0

I am trying to create an inventory system using a json file. Basically, I have my json file:

[
    {
    "name":"Potion",
    "id":1,
    "balance":5
    },
    {
    "name":"Neutral Bomb",
    "id":2,
    "balance": 4
    }
]

And I have my c# file:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using LitJson;


public class Item
{
    public string Name  { get; set; }
    public int Id       { get; set; }
    public int Balance  { get; set; }

    public Item(string name1, int id1, int balance1) {
        Name = name1;
        Id = id1;
        Balance = balance1;
    }
}

public class InventoryAttempt : MonoBehaviour
{
    public static void BalanceChange(string filePath, int ID, int change)
    {
        string jsonString = File.ReadAllText(Application.dataPath + filePath);
        List<Item> itemList = JsonMapper.ToObject<List<Item>>(jsonString);
        itemList [ID].Balance += change;
        jsonString = JsonMapper.ToJson (itemList).ToString();
        File.WriteAllText (Application.dataPath + filePath, jsonString);
    }

    void Start()
    {
        BalanceChange ("/Scripts/inventory.json", 1, 1);
    }
}

In my c# file I want to access a single item, lets say the neutral bomb item. How can I go in and edit the balance of the neutral bomb? I want to use the Item ID to tell which object to edit. I want to create a list where each element is one of the items that are stored in the Json file, but I'm not sure how to separate them. What should I do?

MissingMethodException: Method not found: 'Default constructor not found...ctor() of Item'.
System.Activator.CreateInstance (System.Type type, Boolean nonPublic) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System/Activator.cs:368)
System.Activator.CreateInstance (System.Type type) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System/Activator.cs:254)
LitJson.JsonMapper.ReadValue (System.Type inst_type, LitJson.JsonReader reader)
LitJson.JsonMapper.ReadValue (System.Type inst_type, LitJson.JsonReader reader)
LitJson.JsonMapper.ToObject[List`1] (System.String json)
InventoryAttempt.BalanceChange (System.String filePath, Int32 ID, Int32 change) (at Assets/Scripts/InventoryAttempt.cs:26)
InventoryAttempt.Start () (at Assets/Scripts/InventoryAttempt.cs:34)
Miles Kim
  • 47
  • 9
  • Possible duplicate of [How do I edit JSON values in c# with LitJson in Unity3D?](http://stackoverflow.com/questions/42165004/how-do-i-edit-json-values-in-c-sharp-with-litjson-in-unity3d) – Fredrik Schön Feb 11 '17 at 07:32

2 Answers2

1

First of all, the variable names in your Json does not match the ones in your Item class. The ones in your Item class are capitalized.

Use Unity's JsonUtility.

Secondly, get the JsonHelper class from this post. It allows Unity's JsonUtility to serialize and deserialize Json Array.

Do not generate Json by hand in the future since you will run into problems like this. Use the Json class and a simple function to do that. For example, this:

void generateJson()
{
    Item[] item = new Item[2];

    item[0] = new Item();
    item[0].Name = "Potion";
    item[0].Id = 1;
    item[0].Balance = 5;

    item[1] = new Item();
    item[1].Name = "Neutral Bomb";
    item[1].Id = 2;
    item[1].Balance = 4;

    string value = JsonHelper.ToJson(item, true);
    Debug.Log(value);
}

Will generate this:

{
    "Items": [
        {
            "Name": "Potion",
            "Id": 1,
            "Balance": 5
        },
        {
            "Name": "Neutral Bomb",
            "Id": 2,
            "Balance": 4
        }
    ]
}

No error. That is valid json.

Solution:

InventoryAttempt class:

public class InventoryAttempt
{
    public static void BalanceChange(string filePath, int ID, int change)
    {
        //Load Data
        string jsonString = File.ReadAllText(Application.dataPath + filePath);

        Item[] item = JsonHelper.FromJson<Item>(jsonString);

        //Loop through the Json Data Array
        for (int i = 0; i < item.Length; i++)
        {
            //Check if Id matches
            if (item[i].Id == ID)
            {
                Debug.Log("Found!");
                //Increment Change value?
                item[i].Balance += change;
                break; //Exit loop
            }
        }

        //Convert to Json
        string newJsonString = JsonHelper.ToJson(item);

        //Save
        File.WriteAllText(Application.dataPath + filePath, newJsonString);
    }
}

Your Item class Item.

[Serializable]
public class Item
{
    public string Name;
    public int Id;
    public int Balance;

    public Item()
    {

    }

    public Item(string name1, int id1, int balance1)
    {
        Name = name1;
        Id = id1;
        Balance = balance1;
    }
}

Test script:

public class Test : MonoBehaviour
{
    // Use this for initialization
    void Start()
    {
        InventoryAttempt.BalanceChange("/Scripts/inventory.json", 1, 1);
    }
}

Note:

I removed get/set property stuff. Please remove these as they must be removed for this to work. Also, [Serializable] is added to the top of the Item class. Please add that as-well. I suggest you copy and replace the classes directly before making the "it doesn't work" comment under the question...

Community
  • 1
  • 1
Programmer
  • 121,791
  • 22
  • 236
  • 328
0

First things first your json does not seem to be a valid array (not the missing [ and ].

[
    {
        "name":"Potion"
        "id":1,
        "balance":7
    },
    {
        "name":"Neutral Bomb",
        "id":2,
        "balance": 4
    }
]

Also, I would follow naming conventions and start the properties with an Upper Case characters.

public class Item
{
    public string Name  { get; set; }
    public int Id       { get; set; }
    public int Balance  { get; set; }

    public Item()
    {
    }

    public Item(string name1, int id1, int balance1)
    {
        Name = name1;
        Id = id1;
        Balance = balance1;
    }
}

The code below should give you want you want, but depending on the scope of your project could be very inefficient. You may want to consider caching the jsonString and/or the deserialization result. You may also want to use FirstOrDefault and use a null check if its expected the ID may not exist.

public class InventoryAttempt : MonoBehaviour
{
    public static Item JsonToItem(string filePath, int itemID)
    {
        string jsonString = File.ReadAllText(Application.dataPath + filePath);
        return JsonMapper.ToObject<List<Item>>(jsonString).First(x => x.Id == itemID);
    }

    void Start()
    {
        var item = JsonToItem("/Scripts/inventory.json", 1);
    }
}
Shane Ray
  • 1,449
  • 1
  • 13
  • 18
  • The .First thing wont work. It shows up red and doesn't work. Any idea why that is? – Miles Kim Feb 10 '17 at 19:30
  • I changed the script based mostly on what you said, but without the .First() because it created a bunch of errors. What do I do to make this code work? – Miles Kim Feb 10 '17 at 20:01
  • For First() you are likely just missing the `using System.Linq` statement. – Shane Ray Feb 10 '17 at 20:06
  • I also updated the `First()` statement in the code above. Should be something like `.First(x => x.Id == itemID)`. – Shane Ray Feb 10 '17 at 20:09
  • Will this allow me to edit the item and then put it back into the json file? – Miles Kim Feb 10 '17 at 20:20
  • I tried what you said, but it still gives me the error. I pasted the error at the bottom of my question. Any idea why that is? Is ToObject>() even a possible function? – Miles Kim Feb 10 '17 at 20:34
  • I do not see the error at the bottom of your question. – Shane Ray Feb 10 '17 at 21:02
  • You're right, I must not have finished the edit. My bad. – Miles Kim Feb 10 '17 at 21:31
  • I put it there now – Miles Kim Feb 10 '17 at 21:31
  • You are missing the default parameterless constructor for the class `Item`. – Shane Ray Feb 10 '17 at 21:33
  • I updated my post to show the `Item` class with a parameterless constructor. – Shane Ray Feb 10 '17 at 21:40
  • InvalidOperationException: Operation is not valid due to the current state of the object System.Linq.Enumerable.First[Item] (IEnumerable`1 source, System.Func`2 predicate, Fallback fallback) System.Linq.Enumerable.First[Item] (IEnumerable`1 source, System.Func`2 predicate) InventoryAttempt.JsonToItem (System.String filePath, Int32 itemID) (at Assets/Scripts/InventoryAttempt.cs:38) InventoryAttempt.Start () (at Assets/Scripts/InventoryAttempt.cs:42) – Miles Kim Feb 10 '17 at 21:52
  • I am done for the day. If you are still stuck tomorrow, let me know. I can whip up a sample application for you. – Shane Ray Feb 10 '17 at 23:11