Search Unity

Deserializing Scriptable objects with Json Utility Issue

Discussion in 'Scripting' started by Tsucasa, Jun 2, 2018.

  1. Tsucasa

    Tsucasa

    Joined:
    Nov 11, 2017
    Posts:
    3
    Hi All

    I have been really stuck trying to get this working so am hoping someone in here can help.

    I have a scriptable object called JobManager and I've created 5 objects using it, the Scriptable object is very simple and only contains 2 integers see below:
    Code (CSharp):
    1. [Serializable]
    2. public class JobManager : ScriptableObject {
    3.  
    4.     public int jobNumber;
    5.     public int jobStatus;
    6.  
    7. }
    My save function seems to create a valid Json see attached File (save.txt) so I'm happy with my save function, however my Load function seems to be causing me grief!!
    I have tried all sorts to get it to work but no joy, the most recent was this site, the code I use for loading is below:
    Code (CSharp):
    1.     public static JobManager[] Load()
    2.     {
    3.         if (FileCheck())
    4.         {
    5.             string jsonData = File.ReadAllText(Application.persistentDataPath + "/save.txt");
    6.             Debug.Log(JsonHelper.FromJson<JobManager>(jsonData));
    7.             JobManager[] jobs = JsonHelper.FromJson<JobManager>(jsonData);
    8.             return jobs;
    9.         }
    10.         else
    11.         {
    12.             Debug.LogError("Save file not found");
    13.             return null;
    14.         }
    15.     }
    16. }
    17.  
    18. public static class JsonHelper
    19. {
    20.     public static T[] FromJson<T>(string json)
    21.     {
    22.         Wrapper<T> wrapper = JsonUtility.FromJson<Wrapper<T>>(json);
    23.         return wrapper.Items;
    24.     }
    25.  
    26.     [Serializable]
    27.     private class Wrapper<T>
    28.     {
    29.         public T[] Items;
    30.     }
    31. }
    The Result of this code is jobs is always null, Ideally I'd like for the jobs to be populated with whats in save.txt but that doesn't seem to happen.

    Thanks
     

    Attached Files:

    • save.txt
      File size:
      163 bytes
      Views:
      619
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,528
    Where's your save script?

    I ask, because your save.txt looks like this:
    Code (csharp):
    1. {"array": [{"jobNumber":1,"jobStatus":1},{"jobNumber":2,"jobStatus":0},{"jobNumber":3,"jobStatus":0},{"jobNumber":4,"jobStatus":0},{"jobNumber":5,"jobStatus":0}] }
    Note that the base json object has one property named 'array' to which the array of objects is attached.

    But your JsonHelper has Wrapper<T> written as this:
    Code (csharp):
    1.  
    2.     [Serializable]
    3.     private class Wrapper<T>
    4.     {
    5.         public T[] Items;
    6.     }
    7.  
    Note, the array is named 'Items', not 'array'.

    Lastly, I'm wondering how you're serializing this into save.txt, because ScriptableObject's don't serialize that way with JsonUtility. They're serialized by reference (which is not a good thing for your use) because JsonUtility just uses the built in unity serializer which treats all UnityEngine.Objects by ref and not as data.

    Furthermore, if you change the name from array to Items, you'll get null for each object in the array. Because again, that's not how the JsonUtility deals with unity objects. It won't instantiate them like that.
     
  3. Tsucasa

    Tsucasa

    Joined:
    Nov 11, 2017
    Posts:
    3

    Hi lordofduct

    Thanks for your reply, I was first using a wrapper as you have mentioned how ever i was only getting the Instance ID which meant I didn't have the required information so I changed the save function to this:

    Code (CSharp):
    1.     public static void Save()
    2.     {
    3.  
    4.         JobManager[] jobs = Resources.LoadAll<JobManager>("Jobs");    
    5.  
    6.         string data = "";
    7.  
    8.         data = "{";
    9.         data += "\"array\": [";
    10.         for (int i = 0; i < jobs.Length; i++)
    11.         {
    12.             data += JsonUtility.ToJson(jobs[i]);
    13.             //Add a comma after every element except for the last one
    14.             if (i < jobs.Length - 1) data += ",";
    15.         }
    16.         data += "] }";
    17.  
    18.         File.WriteAllText(Application.persistentDataPath + "/save.txt", data);
    19.     }
    The reason for this is that's how i understood it needed to be from the site provided in my first post.
     
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,528
    So yeah. First and foremost your generated wrapper has a property name mismatch since you name it 'array' in save, but expect 'Items' in the Load.

    But as I previously stated, you're still going to have a problem with the fact that JsonUtility just doesn't work with unity objects in the manner you want.

    If you want to treat a unity object as its data you are going to need to tokenize that data into its own NON-unity object.

    ...

    question, is there a reason that 'JobManager' is a ScriptableObject anyways? Do you need them to be assets for a reason?
     
  5. Tsucasa

    Tsucasa

    Joined:
    Nov 11, 2017
    Posts:
    3
    Thanks for the first correction (didn't realize that would be an issue).

    With regards to why its a scriptable object is because it makes them easier and quicker to create with out as much code to create, also when i read about scriptable objects this sounded like a good scenario for them, but maybe I just misunderstood the point of Scriptable objects.

    Thanks