Parsing JSON to create resource classes

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Hozer

Hello!
I’m building a RPG game where my Items are all resources, for example (pseudocode):

class Item(cost: int, equipped_scene_path: Path, icon: Path)
class MeleeWeapon(damage: int) extends Item
class Shield(defense: int) extends Item
class Consumable(use_count: int) extends Item
class Potion(hp_healed: int) extends Consumable

Now I’m using a .tres file (Right click → New → Resource → Choose class) to create “instances” of these items, which are later parsed and added to an item DB.

Now, as the project is getting more items, I want to use JSON/CSV/SpreadSheet to organize the items, so now I’m testing a JSON similiar to this one:

[
  {
    "CODE": "MACE",
    "NAME": "Mace",
    "CLASS": "MeleeWeapon",
    "COST": 10,
    "ICON_PATH": "res://assets/items/generic_mace/icon.png",
    "BASE_DAMAGE": 20
  },
  {
    "CODE": "SAMPLESWORD",
    "NAME": "Sample Sword",
    "CLASS": "MeleeWeapon",
    "COST": 5,
    "ICON_PATH": "res://assets/items/generic_sword/icon.png",
    "BASE_DAMAGE": 15
  },
  {
    "CODE": "TORCH",
    "NAME": "Torch",
    "CLASS": "Item",
    "COST": 0,
    "ICON_PATH": "res://assets/items/torch/icon.png"
  },
  {
    "CODE": "WOODEN_SHIELD",
    "NAME": "Wooden Shield",
    "CLASS": "Shield",
    "COST": 10,
    "ICON_PATH": "res://assets/items/generic_shield/icon.png",
    "DEFENSE": 15
  }
]

However, I cannot find a way to tell Godot to instance the class in parsed_item[“CLASS”] as the .tres usually does. Do you have any idea of how I should approach this? Or maybe I am making it too complicated for no reason.

:bust_in_silhouette: Reply From: zhyrin

You store items as custom resources in your database, right?
I would create a factory class (see: buidler/factory/abstract factory design pattern) that takes in a single json object like above, and based on CLASS it creates a new resource of the desired type by feeding the rest of the values of the json object as constructor arguments.

Yeah, that’s the way I’m doing it right now, I was hoping someone could come with a reflection wizardry to instance a class based on its String name.

But I’m glad you reinforced the idea of instantiating by hand based on the CLASS attribute.

Hozer | 2023-02-14 19:18

There are centainly ways. If we are talking about built-in types, you can use the ClassDB.
If you want to instance custom scripted types based on a string, you could use a Dictionary that has strings as key and the corresponding GDScripts as values.
But if you want to make the creation process generic, they will have to have the same parameter list for their constructors.

zhyrin | 2023-02-15 20:20

The same way I use ICON_PATH in my example, I could use CLASS_PATH with the path to the class the item uses to instance it, correct?

I’m thinking of maybe going to that approach instead of going for a Factory implementation, this way, whenever I create a class in code and an item with this class, I would just add the correct class_path without needing to adjust the factory (besides for the internal class attributes).

Thanks again for the reply.

Hozer | 2023-02-15 20:35