Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice

Scripting JsonUtility fails to convert 2D arrays to json and also from json

Discussion in '5.4 Beta' started by fermmmm, Feb 24, 2016.

  1. fermmmm

    fermmmm

    Joined:
    Oct 18, 2013
    Posts:
    129
    Are multidimentional 2D arrays not supported in JsonUtility? Didn't find anything in the documentation so I report it as a bug. I want to know if this is going to be fixed. Even the worst Json decoder out there supports 2D arrays.
    You can test the bug running the following code:

    Code (CSharp):
    1.     void Start ()
    2.     {
    3.         int[,] b = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}};
    4.         Debug.Log(JsonUtility.ToJson(b));   // This prints "{}"
    5.  
    6.         string json = "{ \"myArray2D\" : [[321,542], [223,512]] }";
    7.         Debug.Log(JsonUtility.FromJson<MyArrayModel>(json).myArray2D);  // this prints null
    8.     }
    9.  
    10.     public class MyArrayModel
    11.     {
    12.         public List<List<int>> myArray2D;
    13.     }
    Bug report:
    https://fogbugz.unity3d.com/default.asp?773629_e61t12pci1j8kns7

    Edit:
    Other posts I've found with the same issue:
    http://answers.unity3d.com/questions/1118151/jsonutility-nested-array-deserialization.html
    http://answers.unity3d.com/questions/1123326/jsonutility-array-not-supported.html
     
    Last edited: Feb 24, 2016
  2. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,659
    They are not. JsonUtility only supports the same types that the Inspector supports (because they share the same code).
     
  3. fermmmm

    fermmmm

    Joined:
    Oct 18, 2013
    Posts:
    129
    Are going to be supported soon? or this will come when the editor serialization supports more types far in the future?
     
  4. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,659
    They're going to come at the same time as the Editor supporting other types - this isn't necessarily "far" in the future, though, as I need to work on the serializer for various other features people want as well (such as Dictionary support).
     
  5. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    @superpig Super keen for full serialization support. While you guys are at it, how about letting us write our own serializers for different types? Let Unity serialize types as it does normally, but allow us to override it and write out our own data into the serialized result.

    Similar to 'CustomEditor', where you can just rewrite the entire inspector by overriding OnInspectorGUI.

    For example, this is what it might look like for 'Color': (Ignoring the fact that color is already serializable)

    Code (CSharp):
    1. [CustomSerializer(typeof(Color))]
    2. public class ColorSerializer : Serializer
    3. {
    4.     public override void OnSerialize(Writer w, object target)
    5.     {
    6.         Color targetColor = (Color) target;
    7.         w.Write("r", targetColor.r);
    8.         w.Write("g", targetColor.g);
    9.         w.Write("b", targetColor.b);
    10.         w.Write("a", targetColor.a);
    11.     }
    12.  
    13.     public override object OnDeserialize(Reader r)
    14.     {
    15.         return new Color(r.ReadFloat("r"), r.ReadFloat("g"), r.ReadFloat("b"), r.ReadFloat("a"));
    16.     }
    17. }
    This way, we can do lots of cool stuff with the Unity serialization. For example, lets say we are developing Crossy Roads. Lets say I have a 'GameSave' class that has a reference to a scriptableobject of type Character. This character is the character we've got selected in the game. This scriptable object contains all the relevent information about this character, like which prefab to spawn, the characters name, so on.

    I can't 'serialize' GameSave correctly, because this 'reference' doesn't get serialized. But it could be made possible with a custom serializer. For example:

    Code (CSharp):
    1. [CustomSerializer(typeof(GameSave))]
    2. public class GameSaveSerializer : Serializer
    3. {
    4.     public override void OnSerialize(Writer w, object target)
    5.     {
    6.         GameSave targetSave = (GameSave)target;
    7.         w.Write("SelectedCharacter", targetSave.SelectedCharacter.name);
    8.     }
    9.  
    10.     public override object OnDeserialize(Reader r)
    11.     {
    12.         GameSave deserializedSave = new GameSave();
    13.         deserializedSave.SelectedCharacter = Resources.Load<Character>("Characters/" + r.ReadString("SelectedCharacter"));
    14.         return deserializedSave;
    15.     }
    16. }
    Something like this would make the build in JSON Serializer really versatile. I'd use it all the time for save games and other stuff.
     
    mh114 likes this.
  6. fermmmm

    fermmmm

    Joined:
    Oct 18, 2013
    Posts:
    129
    You have to also write how the Unity editor UI shows and let you edit the new serializable data
    Maybe this is not a reality because of all that UI code needed.
     
    Last edited: Feb 25, 2016
  7. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,659
    You can already do that custom serialisation stuff with ISerializationCallbackReceiver.
     
  8. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    We'd be able to support multidim arrays and dictionaries ourselves if we were able to define what the serializer writes and how it reads it, we can't with ISerializationCallbackReceiver right? Unless I am missing something haha.
     
    Last edited: Feb 25, 2016
  9. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    973
    You are indeed missing something! :p
    While native support for dictionaries and multi dimensional arrays would definitely be welcome, you can serialize both with ISerializationCallbackReceiver if you need to do so.

    You just use a backing list or array and fill it with the key-value pairs OnBeforeSerialize. You then populate the dictionary with those KVPs OnAfterDeserialize.

    You could do something similar to get multi-dimensional arrays to serialize. For regular ones, you could store the dimensions and dump the contents in a 1D backing array OnBeforeSerialize, then use the dimensions to populate the multidimensional array OnAfterDeserialize.

    Jagged arrays are a little more annoying but you could do something like defining a System.Serializable struct with a single array of the type you need in it, then serialize a backing array of those structs.

    In all cases, you can use custom inspectors to prettify the result in the inspector, if necessary.
     
  10. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Ah I see, that's pretty sweet!