0
\$\begingroup\$

**UPDATE: This answer has been solved and this post updated to **

I am creating an inventory system and decided to keep a master list of all the items. The goal is to use Newtonsoft's JSON.net to parse the item list and populate the database of items. The JSON item list looks like:

JSON

{
"Ingredients":
    [

    ],
"Consumables": 
    [
            {
            "ID" : "TP_Small",
            "Icon" : "Sprites/porridge.png",
            "Name" : "Small Tan Pill's Porridge",
            "Consumable" : true,
            "Cooldown": 0,
            "Duration": 3,
            "Effect Description" : "Restores 100 health.",
            "Description" : "A hearty drinkable meal from everyone's favorite hypercellulose gelatin timelord!!!",
            "SFX": "{eb4e9ad8-c6ac-414f-8d5e-c3d012ca6ae6}",
            "Bonuses" : {
                "HP": 100,
                "Stamina": 100,
                "Tolerance": 20,
                "Attack": 4
                }
            }   
    ],

"Concoctions":
    [

    ],
"Equipment": 
    [

    ],
"Abilities" : 
    [

    ]   
}

And this is the structure of the classes we are using to match the JSON:

Classes

[System.Serializable]
public class Items
{
    public List<ItemBase> Ingredients;
    public List<ItemBase>Consumables;
    public List<ItemBase>Concoctions;
    public List<ItemBase>Equipment;
    public List<ItemBase>Abilities;
}

[System.Serializable]
public class ItemBase
{
    public string ID;
    public string Icon;
    public string Name;
    public bool Consumable;
    public int Cooldown;
    public int Duration;
    public string EffectDescription;
    public string Description;
    public string SFX;
    public StatBonus Bonuses;
}

[System.Serializable]
public class StatBonus
{
    public int HP;
    public int Stamina;
    public int Tolerance;
    public int Attack;
 }

The deserialization code:

TextAsset json = Resources.Load<TextAsset>(path);

    itemList = new Items();

    itemList.Abilities = new List<ItemBase>();
    itemList.Concoctions = new List<ItemBase>();
    itemList.Consumables = new List<ItemBase>();
    itemList.Equipment = new List<ItemBase>();
    itemList.Ingredients = new List<ItemBase>();

    itemList = JsonConvert.DeserializeObject<Items>(json.text);

This code now works as intended!

\$\endgroup\$
  • \$\begingroup\$ Follow the advice in the answer: build a dummy structure with these classes in your code, then serialize it to JSON..You'll see the JSON format of the output does not match what you're using as input. Your input never mentions the "id" member. \$\endgroup\$ – DMGregory May 28 at 12:02
  • \$\begingroup\$ How can I modify my class structure to accept an array of ItemBase's even though there is no key for the array entry? I don't understand how I would deserialize my JSON properly. \$\endgroup\$ – Ian Rosenberg May 28 at 12:34
  • 1
    \$\begingroup\$ You would delete the ItemCategory class and instead have Items.Abilities = new List<ItemBase>(); directly. \$\endgroup\$ – DMGregory May 28 at 13:05
  • \$\begingroup\$ Thanks so much! That was EXACTLY what I needed! \$\endgroup\$ – Ian Rosenberg May 28 at 14:11
1
\$\begingroup\$

First, a few minor tweaks that might depend on your JSON library (it looks like you're using the Newtonsoft JSON library, rather than the built-in Unity JsonUtility); I can't say whether your version behaves differently, but for Unity's JSON implementation:

  • The serializer will serialize/deserialize fields, not properties - so you'd have to remove all the { get; set; } auto-property markup to get the fields to be picked up that way

  • Your fields need to be marked public or [SerializeField] - your ItemBase and StatBonus members lack this at the moment.

  • The serializer starts at the level of the members of the root object, rather than treating the root object as a named member of an enclosing object, so you can remove the outermost "Items":{ ... } wrapper and jump straight from the outer {...} into your categories.

Again, feel free to disregard these points if they're unique to Unity's JsonUtility and not reflective of the library you're using.

The more fundamental problem is that your JSON and your class definitions don't agree.

Your JSON corresponds to an Items class with named fields for each category, which is just a list or array of ItemBase:

[System.Serializable]
public class Items
{
    public List<ItemBase> Ingredients;
    public List<ItemBase> Consumables;
    public List<ItemBase> Concoctions;
    public List<ItemBase> Equipment;
    public List<ItemBase> Abilities;
}

Your Items class corresponds to JSON with a type field, and anonymous array/list entries for each category, each one having an id member to contain the list:

{
    "type": [
        {
            "id": [
                {   
                    "ID": "foo",
                    "Icon": "bar",
                    "Name": "baz",
                    "Consumable": false
                }
            ]
        },
        {
            "id": [
                {
                    "ID": "foo",
                    "Icon": "bar",
                    "Name": "baz",
                    "Consumable": false
                }
            ]
        }
    ]
}

A good way to make sure your JSON and internal class definitions match-up: whip up a script that synthetically creates and populates an instance of your class with dummy data, then spits out the JSON that results.

public class JSONTest : MonoBehaviour
{
    [TextArea(5, 50)]
    public string jsonOutput;

    void Start()
    {
        var items = new Items();

        items.type = new List<ItemCategory>();
        var category = new ItemCategory();
        items.type.Add(category);
        category = new ItemCategory();
        items.type.Add(category);

        category.id = new List<ItemBase>();
        category.id.Add(new ItemBase() { ID = "foo", Icon = "bar", Name = "baz", Cooldown = 42, Duration = 7, EffectDescription = "Very Good", Description = "Something" });

        jsonOutput = JsonUtility.ToJson(items, true);
    }
}

Then you can compare the formatting of that result against the JSON you were trying to use, to either adjust your input to match your internal representation, or adjust your internal representation to suit your input.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Yeah, I'm using Newtonsoft JSON library, but your answer would be essentially the same either way, right? \$\endgroup\$ – Ian Rosenberg May 27 at 17:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.