Search Unity

JSON .NET for Unity

Discussion in 'Assets and Asset Store' started by Dustin-Horne, Sep 13, 2013.

  1. bdovaz

    bdovaz

    Joined:
    Dec 10, 2011
    Posts:
    1,053
    @Dustin-Horne I'm getting this error building for Android with IL2CPP (I suppose that it's a stripping problem):

    Can it be the same problem that @mihakinova had? In my data model I have some "ICollection" and "IDictionary" types.

    Is there any solution to keep those types that doesn't involve any "hacking" like your last reply? Some other solution that involves link.xml or similar
     
  2. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Unfortunately it's not yet possible. But, could you do me a favor? It's been hard getting someone to do that can reproduce it. I need you to add the namespace "System.Collections.Generic" to the link.xml file and submit a bug report. In speaking with Unity, this is a bug and it shouldn't be stripping those constructors if that's in the link.xml but it is.
     
  3. bdovaz

    bdovaz

    Joined:
    Dec 10, 2011
    Posts:
    1,053
    But this should happen on any IL2CPP platform isn't it (Android, iOS, WebGL...)? It should be easy to make a repro project with the minimum code.

    I will see if I can do it but why don't you have sent it yet? It should crash always.
     
  4. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    It's inconsistent to reproduce, and it sometimes happens on one platform and not the others. It actually seems to happen most often on iOS. I've asked a few people to report it but I don't think any have yet.
     
  5. Sharlatan

    Sharlatan

    Joined:
    Jul 23, 2013
    Posts:
    111
    Hey Dustin

    First, let me thank you for all the work you've done on this!

    I have some questions you can hopefully help me out with since I'm considering switching to JSON.NET for Unity:

    • Are you still planning to support the product for the foreseeable future even though it's now free?
    • You mentioned that you don't fully support .NET 4.6 yet. Does that mean there are still some minor problems or are it major problems I'd have to expect when using 4.6?
    • Do you have some kind of road map when you're roughly planning to support 4.6?
    Thanks a lot and have a nice day!
     
  6. bdovaz

    bdovaz

    Joined:
    Dec 10, 2011
    Posts:
    1,053
    I have some questions too.

    Now that it's free why don't you contribute with PRs to the original json .net GitHub project? There are many nuget libraries that depend on that library and that require .net 4.6 that I would like to use on Unity.

    Now I'm afraid that if I use them it will not work on AOT plarforms because original json .net will not work.
     
  7. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Yes, I will be supporting it fully at least through the end of this year, after which I will need to see. The repository is now on GitHub and it's a Google controlled account, so my continued support will depend on what level of contributorship they allow me to maintain. I imagine though that I'll still be a contributor for the foreseeable future after the end of this year.

    For .NET 4.6, I actually have a build that supports it. I have some additional testing to do and I'll be pushing it to the GitHub repository as well as adding some additional documentation. The issue is that I can't push the 4.6 build to the asset store as it'll break all 3.5 users. The Unity assembly mapper doesn't let me specify a framework version when mapping dll's to platforms which prevents me from being able to ship both .NET 3.5 and 4.6 compatible assemblies with the bundled asset package.
     
  8. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    While the official JSON .NET is fantastic, the author has stated he's not interested in official Unity compatibility which was the reason for the port to begin with. Even if I were to create PRs, they would be extraordinarily complex in order to support both Unity and the standard platforms and they'd never be accepted and merged into the official source.

    I did at one point consider forking the official project and maintaining the up to date version with mine, however it made some substantial changes such as removing support for BSON which some of my customers currently use. This keeps versioning out of sync and is the reason it's an entirely separate repository. In addition, the repository for my port is now owned and operated by Google and I'm just a contributor.
     
  9. bdovaz

    bdovaz

    Joined:
    Dec 10, 2011
    Posts:
    1,053
    I don't understand why he is not interested. Even Microsoft depends on json .net library for asp net core. Also .net core it's cross platform and they are supporting many platforms if they add some aot platform they will face this problem.
     
  10. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    That would be a question for James Newton King. However, I believe the reason was that he didn't want to write a bunch of special rules / code for niche products. Even if Unity is widely used, it's still a specific product and not a whole platform like Mono, .NET, etc.

    That being said, I'm betting that within a year or so Unity will fully support .NET Core (just speculation) and it'll all be moot anyway because you'll be able to use the official release.
     
  11. bdovaz

    bdovaz

    Joined:
    Dec 10, 2011
    Posts:
    1,053
    I hope that we will get to that.

    Thanks.
     
  12. Sharlatan

    Sharlatan

    Joined:
    Jul 23, 2013
    Posts:
    111
    Thank you so much for getting back to me so fast! Your support is amazing :)

    Will you announce it in this thread when you push the 4.6 version on GitHub or should I just check regularly on GitHub?
    Really looking forward to it!

    Have a nice day!
     
  13. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    I'll announce it here, but if you want to try out what I've got so far, drop me an email (email address is in the readme and documentation) and I'll send it over. It's specifically for .NET 4.6 with IL2CPP builds so it's 4.6 with support for the 4.x types like BigInteger and it's AOT compatible.
     
  14. Sharlatan

    Sharlatan

    Joined:
    Jul 23, 2013
    Posts:
    111
    Thank you very much, I'll write you an e-mail tomorrow or in the next few days! Much appreciated!

    Also (asking here and not in the mail because it might interest others): You specifically mention IL2CPP. Does it also work on platforms that don't support IL2CPP yet? Like Windows desktop? Thanks again!
     
  15. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Yes, the il2cpp build will work with desktop as well.
     
  16. --Den--

    --Den--

    Joined:
    Sep 7, 2015
    Posts:
    6
    Hi @Dustin-Horne ,
    I'm getting this error (Android IL2CPP)

    [NativeObservable] Error deserializing native observable:
    System.NotSupportedException: /Applications/Unity/Unity.app/Contents/il2cpp/libil2cpp/icalls/mscorlib/System.Reflection.Emit/DynamicMethod.cpp(19) : Unsupported internal call for IL2CPP: DynamicMethod::create_dynamic_method - System.Reflection.Emit is not supported.
    at System.Reflection.Emit.DynamicMethod.CreateDynMethod () [0x00000] in <filename unknown>:0
    at System.Reflection.Emit.DynamicMethod.CreateDelegate (System.Type delegateType) [0x00000] in <filename unknown>:0
    at Newtonsoft.Json.Utilities.DynamicReflectionDelegateFactory.CreateDefaultConstructor[T] (System.Type MethodParameter) [0x00000] in <filename unknown>:0
    at Newtonsoft.Json.Serialization.DefaultContractResolver.InitializeContract (Newtonsoft.Json.Serialization.JsonContract MethodParameter) [0x00000] in <filename unknown>:0
    at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateObjectContract (System.Type MethodParameter) [0x00000] in <filename unknown>:0
    at Newtonsoft.Json.Serialization.DefaultCont

    Any ideas how to fix it?
     
  17. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Something is weird there. "System.Reflection.Emit is not supported." I wonder if there's a DLL mapping issue. Emit is not used on AOT platforms (anything IL2CPP or Android with .NET). Is this using the latest version from the asset store? And what Unity version?
     
  18. --Den--

    --Den--

    Joined:
    Sep 7, 2015
    Posts:
    6
    Fixed. Define AOT was missed.
     
    Dustin-Horne likes this.
  19. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    You must be building from source or using an old version?
     
  20. --Den--

    --Den--

    Joined:
    Sep 7, 2015
    Posts:
    6
    From source and new version. I'm building through not unity's default build system, that's why AOT was missed.
     
  21. bilal-arikan

    bilal-arikan

    Joined:
    Jul 26, 2013
    Posts:
    8
    Hi Everyone,
    I have a problem while Deserializing Json to an Object on Android platform, I am sending data to Firebase and getting data from there, I cant paste error message as a text because in Unity Editor there is no problem (Perfectly Working),

    I spent 3 days but I did not find the solution, I think it is a Bug on Android platforms




    //My object to serialize and deserialize
    Code (CSharp):
    1.  
    2. public Dictionary<Point, PassedSubChapter> PassedSubChapterScores = new Dictionary<Point ,PassedSubChapter>();
    3.  
    MyClasses to Serialize and Deserialize:
    Code (CSharp):
    1.     [Serializable]
    2.     public struct PassedSubChapter // I tried even with "class"
    3.     {
    4.         public int Star;
    5.         public int Score;
    6.         public float Time;
    7.         public int RewardXp;
    8.     }
    9.  
    10. public class Point : IEquatable<Point>
    11. {
    12.     [Newtonsoft.Json.JsonConstructor]
    13.     public Point()
    14.     {
    15.         X = 0;
    16.         Y = 0;
    17.     }
    18.  
    19.     public Point(int x, int y)
    20.     {
    21.         X = x;
    22.         Y = y;
    23.     }
    24.  
    25.     public int X;
    26.     public int Y;
    27.  
    28.     public override string ToString()
    29.     {
    30.         return X.ToString("00") + Y.ToString("00");
    31.     }
    32.  
    33.     public bool Equals(Point other)
    34.     {
    35.         return X == other.X && Y == other.Y;
    36.     }
    37.  
    38.     public override int GetHashCode()
    39.     {
    40.         return X.GetHashCode() ^ Y.GetHashCode();
    41.     }
    42. }
    SerializerSettings that i am using
    Code (CSharp):
    1.        
    2. // for Key/Values on Dictionary
    3. static JsonSerializerSettings sett = new JsonSerializerSettings() {
    4.             ContractResolver = new DictionaryAsArrayResolver(),
    5.             NullValueHandling = NullValueHandling.Ignore
    6.         };
    7.  
    8. //While serializing
    9. return JsonConvert.SerializeObject(o, pretty ? Formatting.Indented : Formatting.None,sett);
    10.  
    11. //While Deserializing
    12. return (T)JsonConvert.DeserializeObject(json, typeof(T),sett);
    // Json Data from Firebase
    Code (CSharp):
    1. ...
    2. "PassedSubChapterScores" : [ {
    3.       "Key" : {
    4.         "X" : 1,
    5.         "Y" : 1
    6.       },
    7.       "Value" : {
    8.         "RewardXp" : 0,
    9.         "Score" : 50,
    10.         "Star" : 1,
    11.         "Time" : 10.8166695
    12.       }
    13.     }, {
    14.       "Key" : {
    15.         "X" : 1,
    16.         "Y" : 2
    17.       },
    18.       "Value" : {
    19.         "RewardXp" : 0,
    20.         "Score" : 50,
    21.         "Star" : 2,
    22.         "Time" : 33.9166145
    23.       }
    24.     } ]
    25. ...
     
  22. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    This is cleaner:
    return JsonConvert.DeserializeObject<T>(json, sett);
    instead of
    return (T)JsonConvert.DeserializeObject(json, typeof(T),sett);

    That being said... the only collection I see is your Dictionary. It is the same problem that's been mentioned before... that Unity is stripping the constructor off that Dictionary (or something related) and causing it to fail deserialization. You'll have to possibly simplify the data and see if you can figure out which constructor is being stripped.
     
  23. bilal-arikan

    bilal-arikan

    Joined:
    Jul 26, 2013
    Posts:
    8
    on Unity Editor, it is serializing and deserializing custom dictionaries perfectly but on Android platform it gives an error on top images. (I didnt tried on ios and windows) If you do not have any other solution, it looks like the only way to change class structure :(
     
  24. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    The problem isn't your class structure. The problem is that Unit is stripping a constructor off of something when it does the IL2CPP build.
     
  25. bilal-arikan

    bilal-arikan

    Joined:
    Jul 26, 2013
    Posts:
    8
    Finally 4. day and I solved,
    @Dustin-Horne , Thank you for your answer in a short time
    My mistake: I was always trying different solutions alone, when I tried mixing different solutions it solved
    Solutions from:
    https://stackoverflow.com/questions...ary-as-key-value-list-from-datacontractjsonse
    https://stackoverflow.com/questions...ialize-dictionary-as-array-of-key-value-pairs

    I have changed this code ...
    Code (CSharp):
    1.         static JsonSerializerSettings sett = new JsonSerializerSettings() {
    2.             ContractResolver = new DictionaryAsArrayResolver(),
    3.             NullValueHandling = NullValueHandling.Ignore,
    4.             MissingMemberHandling = MissingMemberHandling.Ignore,
    5.         };
    6.  
    to this...
    Code (CSharp):
    1.         static JsonSerializerSettings sett = new JsonSerializerSettings() {
    2.             ContractResolver = new DictionaryAsArrayResolver(),
    3.             Converters = { new JsonGenericDictionaryOrArrayConverter() },
    4.             NullValueHandling = NullValueHandling.Ignore,
    5.             MissingMemberHandling = MissingMemberHandling.Ignore,
    6.         };
    Code (CSharp):
    1. public class JsonGenericDictionaryOrArrayConverter : JsonConverter
    2.     {
    3.         public override bool CanConvert(Type objectType)
    4.         {
    5.             return objectType.GetDictionaryKeyValueTypes().Count() == 1;
    6.         }
    7.  
    8.         public override bool CanWrite { get { return false; } }
    9.  
    10.         object ReadJsonGeneric<TKey, TValue>(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    11.         {
    12.             var tokenType = reader.TokenType;
    13.  
    14.             var dict = existingValue as IDictionary<TKey, TValue>;
    15.             if (dict == null)
    16.             {
    17.                 var contract = serializer.ContractResolver.ResolveContract(objectType);
    18.                 dict = (IDictionary<TKey, TValue>)contract.DefaultCreator();
    19.             }
    20.  
    21.             if (tokenType == JsonToken.StartArray)
    22.             {
    23.                 var pairs = new JsonSerializer().Deserialize<KeyValuePair<TKey, TValue>[]>(reader);
    24.                 if (pairs == null)
    25.                     return existingValue;
    26.                 foreach (var pair in pairs)
    27.                     dict.Add(pair);
    28.             }
    29.             else if (tokenType == JsonToken.StartObject)
    30.             {
    31.                 // Using "Populate()" avoids infinite recursion.
    32.                 // https://github.com/JamesNK/Newtonsoft.Json/blob/ee170dc5510bb3ffd35fc1b0d986f34e33c51ab9/Src/Newtonsoft.Json/Converters/CustomCreationConverter.cs
    33.                 serializer.Populate(reader, dict);
    34.             }
    35.             return dict;
    36.         }
    37.  
    38.         public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    39.         {
    40.             var keyValueTypes = objectType.GetDictionaryKeyValueTypes().Single(); // Throws an exception if not exactly one.
    41.  
    42.             var method = GetType().GetMethod("ReadJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
    43.             var genericMethod = method.MakeGenericMethod(new[] { keyValueTypes.Key, keyValueTypes.Value });
    44.             return genericMethod.Invoke(this, new object[] { reader, objectType, existingValue, serializer });
    45.         }
    46.  
    47.         public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    48.         {
    49.             throw new NotImplementedException();
    50.         }
    51.     }
     
  26. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Woo... that looks really complicated.. It shouldn't need that complex of a solution, but if it's preventing Unity from stripping it should be fine.

    You probably could have simplified by creating just a custom Converter and using it and inside the converter deserializing to a List<KeyValuePair<TKey, TValue>> and then converting that to a Dictionary.
     
  27. strongbox3d

    strongbox3d

    Joined:
    May 8, 2012
    Posts:
    860
    Hello Dustin-Horne,

    I have been using your asset for a long time now in my Xbox One game and it has never failed me. I just started to need to use a list<> in the class I am serializing and de-serializing, and it doesn't seen to be working. How one go about saving a list<> from the System.Collections.Generic library?

    Regards,
    Carlos
     
    TooManySugar likes this.
  28. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    It should work without issue but sometimes there is odd behavior on Xbox. What error are you running into? Is this IL2CPP?
     
  29. strongbox3d

    strongbox3d

    Joined:
    May 8, 2012
    Posts:
    860
    I get not error but the data in the List<int> is not getting saved. I have a class containing all the data I need to save, including Vector3, Quaternions, int, float, etc. Now I added a List<> with a couple of integers, and when I test the game that data is not saved?

    I wonder:

    You told me to do this for Vector3 to get saved:

    [JsonConverter(typeof(Vector3Converter))]
    public Vector3 playerPos = new Vector3(561.5f, 3.887f, 472.7f);

    This vector get saved. Do I need something like that in order to save lists?

    [something here]
    List<int> myList = new List<int>();

    Please let me know if I could be doing something wrong, cose I don't understand. Otherwise, is there a documentation for the asset? I bought it a long time ago.

    Regards,
    Carlos
     
  30. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    You shouldn't need to. Also, the Vector3Converter (and a couple others) are automatically used on Xbox one because of bugs Unity never fixed with deserializing structs.

    Could you show me what your class looks like with the List<int> on it?
     
  31. strongbox3d

    strongbox3d

    Joined:
    May 8, 2012
    Posts:
    860
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections.Generic;
    3. using Newtonsoft.Json;
    4.  
    5. public class ContentToSave
    6. {
    7.     #region VARIABLES
    8.  
    9.     public int isNewGame = 1;
    10.  
    11.     [JsonConverter(typeof(Vector3Converter))]
    12.     public Vector3 playerPos = new Vector3(561.5f, 3.887f, 472.7f);
    13.  
    14.     [JsonConverter(typeof(QuaternionConverter))]
    15.     public Quaternion playerRot = Quaternion.identity;
    16.     public int playerLevel = 1;
    17.     public int playerStrength = 100;
    18.     public float lungCapacity = 30.0f;
    19.     public int playerLungRank = 0;
    20.  
    21.     public int savedFins = 0;//---------------------//
    22.     public int savedGun = 0;//------------------------//
    23.     public int savedMask = 0;
    24.     public int savedCamo = 0;
    25.     public int savedGearType = 0;
    26.  
    27.     public int Fin1 = 6;//The number 6 is the current color from the list of colors which contains 6 colors
    28.     public int Fin2 = 6;
    29.     public int Fin3 = 6;
    30.     public int Fin4 = 6;
    31.  
    32.     public int Gun1 = 6;
    33.     public int Gun2 = 6;
    34.     public int Gun3 = 6;
    35.     public int Gun4 = 6;
    36.  
    37.     public int Mask1 = 6;
    38.     public int Mask2 = 6;
    39.     public int Mask3 = 6;
    40.     public int Mask4 = 6;
    41.  
    42.     public int wetSuitColor = 6;
    43.  
    44.     //Fish Amount
    45.     public int totalFishAmount = 0;
    46.     public int barracudaAmount = 0;
    47.  
    48.     //Lungs Capacity
    49.     public int pointsNeeded = 100;
    50.     public int totalHitPoints = 0;
    51.  
    52.     //From Game Settings
    53.     public int currentSelected = 0;
    54.     public float currAimSens = 0.5f;//0.02f
    55.     public int aimInvertedInt = 0;
    56.     public int camHInvertedInt = 0;
    57.     public int camVInvertedInt = 0;
    58.     public int instrOnInt = 1;//instructions off or on 0 = off and 1 = on
    59.  
    60.     //Missions Related
    61.     public List<int> mission0States = new List<int>() { 0, 0 };//First int in list: Activation State 0 = inactive, 1 = active. Second int in list: Completion State 0 = not completed, 1 = completed
    62.     #endregion
    63.  
    64.    
    65.     //---------------------------LOAD VALUES-------------------------------------
    66.     public void LoadValues()
    67.     {
    68.         isNewGame = SaveLoadManager.classContainingData.isNewGame;
    69.  
    70.         playerPos = SaveLoadManager.classContainingData.playerPos;
    71.         playerRot = SaveLoadManager.classContainingData.playerRot;
    72.         playerLevel = SaveLoadManager.classContainingData.playerLevel;
    73.         playerStrength = SaveLoadManager.classContainingData.playerStrength;
    74.         lungCapacity = SaveLoadManager.classContainingData.lungCapacity;
    75.         playerLungRank = SaveLoadManager.classContainingData.playerLungRank;
    76.  
    77.         savedFins = SaveLoadManager.classContainingData.savedFins;//-/////////////////////////////
    78.         savedGun = SaveLoadManager.classContainingData.savedGun;//-////////////////////////////////
    79.         savedMask = SaveLoadManager.classContainingData.savedMask;
    80.         savedCamo = SaveLoadManager.classContainingData.savedCamo;
    81.         savedGearType = SaveLoadManager.classContainingData.savedGearType;
    82.  
    83.         Fin1 = SaveLoadManager.classContainingData.Fin1;
    84.         Fin2 = SaveLoadManager.classContainingData.Fin2;
    85.         Fin3 = SaveLoadManager.classContainingData.Fin3;
    86.         Fin4 = SaveLoadManager.classContainingData.Fin4;
    87.  
    88.         Gun1 = SaveLoadManager.classContainingData.Gun1;
    89.         Gun2 = SaveLoadManager.classContainingData.Gun2;
    90.         Gun3 = SaveLoadManager.classContainingData.Gun3;
    91.         Gun4 = SaveLoadManager.classContainingData.Gun4;
    92.  
    93.         Mask1 = SaveLoadManager.classContainingData.Mask1;
    94.         Mask2 = SaveLoadManager.classContainingData.Mask2;
    95.         Mask3 = SaveLoadManager.classContainingData.Mask3;
    96.         Mask4 = SaveLoadManager.classContainingData.Mask4;
    97.  
    98.         wetSuitColor = SaveLoadManager.classContainingData.wetSuitColor;
    99.  
    100.         //Fish Amounts
    101.         totalFishAmount = SaveLoadManager.classContainingData.totalFishAmount;
    102.         barracudaAmount = SaveLoadManager.classContainingData.barracudaAmount;
    103.         pointsNeeded = SaveLoadManager.classContainingData.pointsNeeded;
    104.         totalHitPoints = SaveLoadManager.classContainingData.totalHitPoints;
    105.  
    106.         //From Game Settings
    107.         currentSelected = SaveLoadManager.classContainingData.currentSelected;
    108.         currAimSens = SaveLoadManager.classContainingData.currAimSens;
    109.         aimInvertedInt = SaveLoadManager.classContainingData.aimInvertedInt;
    110.         camHInvertedInt = SaveLoadManager.classContainingData.camHInvertedInt;
    111.         camVInvertedInt = SaveLoadManager.classContainingData.camVInvertedInt;
    112.         instrOnInt = SaveLoadManager.classContainingData.instrOnInt;
    113.  
    114.         //Missions Related
    115.         mission0States = SaveLoadManager.classContainingData.mission0States;
    116.  
    117.  
    118.     }
    119.  
    120.     //-------------------------RESET CLASS---------------------------------------
    121.     public void ResetValues()
    122.     {
    123.         isNewGame = 1;
    124.  
    125.         playerPos = new Vector3(561.5f, 3.887f, 472.7f);
    126.         playerRot = Quaternion.identity;
    127.         playerLevel = 1;
    128.         playerStrength = 100;
    129.         lungCapacity = 30.0f;
    130.         playerLungRank = 0;
    131.  
    132.         savedFins = 0;
    133.         savedGun = 0;
    134.         savedMask = 0;
    135.         savedCamo = 0;
    136.         savedGearType = 0;
    137.  
    138.         Fin1 = 6;
    139.         Fin2 = 6;
    140.         Fin3 = 6;
    141.         Fin4 = 6;
    142.  
    143.         Gun1 = 6;
    144.         Gun2 = 6;
    145.         Gun3 = 6;
    146.         Gun4 = 6;
    147.  
    148.         Mask1 = 6;
    149.         Mask2 = 6;
    150.         Mask3 = 6;
    151.         Mask4 = 6;
    152.  
    153.         wetSuitColor = 6;
    154.  
    155.         //Fish Amount
    156.         totalFishAmount = 0;
    157.         barracudaAmount = 0;
    158.  
    159.         //Lungs Capacity
    160.         pointsNeeded = 100;
    161.         totalHitPoints = 0;
    162.  
    163.         //From Game Settings
    164.         currentSelected = 0;
    165.         currAimSens = 0.5f;//0.02f
    166.         aimInvertedInt = 0;
    167.         camHInvertedInt = 0;
    168.         camVInvertedInt = 0;
    169.         instrOnInt = 1;
    170.  
    171.         //Missions Related
    172.         for(int i = 0; i < mission0States.Count; i++)
    173.         {
    174.             mission0States[i] = 0;//First int in list: Activation State 0 = inactive, 1 = active. Second int in list: Completion State 0 = not completed, 1 = completed
    175.         }
    176.     }
    177. }
     
  32. strongbox3d

    strongbox3d

    Joined:
    May 8, 2012
    Posts:
    860
    This class only hold the variables and some methods that are called from the classes that udpate the values of such variables. It is in the line 61
     
    Last edited: Feb 15, 2018
  33. Schazzwozzer

    Schazzwozzer

    Joined:
    Jul 27, 2012
    Posts:
    18
    Hello,

    I'm switching my project over from binary serialization to JSON and am finding that, when using ISerializable, deserializing strings will throw InvalidCastExceptions. It seems to be the same issue described here: https://github.com/JamesNK/Newtonsoft.Json/issues/656

    As per the link, it seems like it's an issue unique to Mono, so does this seem like a bug you'd address in your package? Also, as I'm not terribly savvy with serialization, should my workaround (temporary or not) just be to wrap the string in some object/struct?

    Here's a script that can be dropped into an empty Unity project with your plugin to reproduce the exception.
    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System.IO;
    6. using System.Runtime.Serialization;
    7. using Newtonsoft.Json;
    8.  
    9. public sealed class StringDeserializationTest : MonoBehaviour {
    10.     private TestObject testObject;
    11.     private static string filePath;
    12.     private static string fileName = "Test Object.json";
    13.  
    14.     [Serializable]
    15.     public class TestObject : ISerializable {
    16.         public string Name;
    17.  
    18.         public TestObject( string name ) {
    19.             this.Name = name;
    20.         }
    21.  
    22.         // Constructor for deserialization
    23.         protected TestObject( SerializationInfo info, StreamingContext context ) {
    24.             this.Name = info.GetString( "name" );
    25.         }
    26.  
    27.         public void GetObjectData( SerializationInfo info, StreamingContext context ) {
    28.             info.AddValue( "name", Name );
    29.         }
    30.     }
    31.  
    32.     private void Start() {
    33.         testObject = new TestObject( "Foo" );
    34.         filePath = Path.Combine( Application.dataPath, "Resources/" );
    35.  
    36.         Serialize();
    37.         Deserialize();
    38.     }
    39.  
    40.     public void Serialize() {
    41.         using( StreamWriter output = File.CreateText( Path.Combine( filePath, fileName ) ) )
    42.         {
    43.             JsonSerializer serializer = new JsonSerializer();
    44.             serializer.Serialize( output, testObject );
    45.             Debug.Log( "Test Object saved to file (" + Path.Combine( filePath, fileName ) + ")" );
    46.         }
    47.     }
    48.  
    49.     public void Deserialize() {
    50.         testObject = JsonConvert.DeserializeObject<TestObject>( File.ReadAllText( Path.Combine( filePath, fileName ) ));
    51.         Debug.Log( "Test Object loaded from file." );
    52.     }
    53. }
    Thanks in advance!
     
  34. Schazzwozzer

    Schazzwozzer

    Joined:
    Jul 27, 2012
    Posts:
    18
    Quick update. For some reason, I'd assumed that my issue was limited to strings, but it seems to occur for any primitive value type deserialized via an ISerializable constructor. I found a workaround, but boy is it ugly. Instead of, for instance, this.Integer = info.GetIn32( "integer" ), one can use:

    Code (CSharp):
    1. using Newtonsoft.Json.Linq;
    2. this.Integer = (int)((JValue)info.GetValue( "integer", typeof( JValue ))).Value;
    EDIT: Wouldn't ya know, minutes after posting this, I thought I'd try switching to the "Experimental" .NET 4.6 scripting runtime, and that did it. The exceptions went away. So, uh, I guess that's the solution? That's the solution I'm rolling with, anyway!
     
    Last edited: Feb 28, 2018
  35. Maisey

    Maisey

    Joined:
    Feb 17, 2014
    Posts:
    302
    Hello again @Dustin-Horne !

    I'm having some trouble, I need to keep the $type data in my JSON, but the MongoDB I'm communicating with doesn't support the "$" as a key in JSON (or I'm missing something). Do you have a suggestion for a workaround for this? Can I somehow rename the $type and let the (de)serializer know about my change?

    Thanks!
     
  36. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Sorry I'm slow, have had family in town. I'll take a look at this and see if I can figure out what's going on and what/if there is a workaround for it. In the meantime, I'm still have testing ongoing for the .NET 4.6 build so ping me if you want it and I'll see what I can do.

    This sounds like a limitation of MongoDB? I think MongoDB also uses its own $type key internally (it's fairly standard) to store the type of the BSON object (which it uses internally as its storage engine). As a result, I'm not sure you'll be able to use the $type key for objects stored on MongoDB.
     
  37. Maisey

    Maisey

    Joined:
    Feb 17, 2014
    Posts:
    302
    Yes, that seems to be the issue. You don't know if a way to serialize my data and use a custom key instead of using "$type"?

    Thanks!
     
  38. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    There is not. The property name is a const value located in JsonTypeReflector. If you wanted, you could pull the solution yourself off of GitHub, change the type name to something like $objectType and recompile it. The file is in:
    Serialization\JsonTypeReflector
    and the property is:
    TypePropertyName
     
  39. Maisey

    Maisey

    Joined:
    Feb 17, 2014
    Posts:
    302
    Thanks a lot, exactly what I needed! Out of curiosity, is $type the standard in JSON generally or is that something that has been chosen for Newtonsoft.Json lib explicitly?
     
    Dustin-Horne likes this.
  40. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    I'm not entirely sure on its origins to be honest, but several libraries use it. It's definitely not unique to Json .net.
     
  41. SureSight

    SureSight

    Joined:
    Aug 2, 2013
    Posts:
    65
    I'm having some issues saving a complex object in BSON.
    I tried defining a custom JsonConverter without any luck.
    The properties JournalCharacters and PlayerInventory are ignored

    Code (CSharp):
    1. public class GameSave
    2. {
    3.   public const string CurrentFileVersion = "1.0";
    4.   public const string QuickSaveFileName = "Quick Save";
    5.  
    6.   public string FileVersion { get; set; }
    7.   public string FileName { get; set; }
    8.   public DateTime FileDate { get; set; }
    9.   public Vector3 PlayerPosition { get; set; }
    10.   public Quaternion PlayerRotation { get; set; }
    11.   public PlayerJournalCharacter[] JournalCharacters { get; set; }
    12.   public PlayerInventory PlayerInventory { get; set; }
    13. }
    The code that does the serialisation is below
    Code (CSharp):
    1. using (FileStream fileStream = File.Open(filePath, FileMode.OpenOrCreate))
    2.       {
    3.         using (BsonWriter bsonWriter = new BsonWriter(fileStream))
    4.         {
    5.           new JsonSerializer().Serialize(bsonWriter, gameSave);
    6.         }
    7. }
    What am I doing wrong?
     
    Last edited: Mar 9, 2018
  42. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    What problems are you actually having?
     
  43. SureSight

    SureSight

    Joined:
    Aug 2, 2013
    Posts:
    65
    The properties below are completely ignored by the serilizer

    public PlayerJournalCharacter[] JournalCharacters { get; set; }
    public PlayerInventory PlayerInventory { get; set; }
     
  44. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Can you show (with code tags please) what those classes look like?
     
  45. SureSight

    SureSight

    Joined:
    Aug 2, 2013
    Posts:
    65
    Of course.

    Code (CSharp):
    1.  
    2. [JsonObject(MemberSerialization.OptOut)]
    3. public class PlayerJournal
    4. {
    5.   public IList<PlayerJournalCharacter> JournalCharacters { get; set; }
    6. }
    7.  
    8. [JsonObject(MemberSerialization.OptOut)]
    9. public class PlayerJournalCharacter
    10. {
    11.   public CharacterClass CharacterClass { get; private set; } //enum
    12.   public RelationshipRank RelationshipRank { get; private set; }  //enum
    13. }
    Code (CSharp):
    1.  
    2. [JsonObject(MemberSerialization.OptOut)]
    3. public class PlayerInventory
    4. {
    5.   public PlayerInventoryItem EquippedItem { get; set; }
    6.  
    7.   public IList<PlayerInventoryItem> items = new List<PlayerInventoryItem>();
    8. }
    9.  
    10. [JsonObject(MemberSerialization.OptOut)]
    11. public class PlayerInventoryItem
    12. {
    13.   public InventoryItemType Type { get; set; }  //enum
    14.   public bool IsConsumed { get; set; }
    15. }
     
    Last edited: Mar 9, 2018
  46. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Could you try something for me quickly? Change those properties from "IList" to just "List" since you're not using any type name handling. Also, ditch the [JsonObject] attributes. I just want to start clean and make sure it works, then we can tackle the customizations.
     
  47. SureSight

    SureSight

    Joined:
    Aug 2, 2013
    Posts:
    65
    I did as you asked and then I added better exception handling. I found that the JsonSerializer.Serialize() was failing part way through the file save and aborting.
    The failure occurred before it got to the custom classes and that's why it appeared to be ignoring them.

    Oddly the error is caused by the Vector3 and Quaternion properties on the GameSave object.
    The documentation says that custom converters already exist for these classes.
    Error messages below:

    I am using Unity 5.5 with JSON.NET 2.0.1. Is this a known bug?
     
    Last edited: Mar 11, 2018
  48. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Ahh missed those. The major issue is that JsonConverters are for json and they don't run for bson. You'll need to create an instance of JsonSerializerSettings and set the ReferenceLoopHandling property to .Ignore. I believe this is honored for bson Serialization.
     
  49. mihakinova

    mihakinova

    Joined:
    Jan 6, 2015
    Posts:
    85
    @Dustin-Horne I'm in the process of updating my project to Unity 2018.1 and I ran into an issue.

    With the upgrade, I also raised .NET to 4.x.

    Now, json.net crashes with the following exception:
    Code (CSharp):
    1. [Exception] ExecutionEngineException: Attempting to call method 'System.Reflection.MonoProperty::GetterAdapterFrame' for which no ahead of time (AOT) code was generated.
    2.     System.Reflection.MonoProperty+GetterAdapter.Invoke (System.Object _this) (at <00000000000000000000000000000000>:0)
    3.     System.Reflection.MonoProperty.GetValue (System.Object obj, System.Object[] index) (at <00000000000000000000000000000000>:0)
    4.     Newtonsoft.Json.Utilities.ReflectionUtils.GetMemberValue (System.Reflection.MemberInfo member, System.Object target) (at <00000000000000000000000000000000>:0)
    5.     Newtonsoft.Json.Serialization.ReflectionValueProvider.GetValue (System.Object target) (at <00000000000000000000000000000000>:0)
    6.     Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues (Newtonsoft.Json.JsonWriter writer, System.Object value, Newtonsoft.Json.Serialization.JsonContainerContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonProperty property, Newtonsoft.Json.Serialization.JsonContract& memberContract, System.Object& memberValue) (at <00000000000000000000000000000000>:0)
    7.     Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject (Newtonsoft.Json.JsonWriter writer, System.Object value, Newtonsoft.Json.Serialization.JsonObjectContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract collectionContract, Newtonsoft.Json.Serialization.JsonProperty containerProperty) (at <00000000000000000000000000000000>:0)
    8.     Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize (Newtonsoft.Json.JsonWriter jsonWriter, System.Object value, System.Type objectType) (at <00000000000000000000000000000000>:0)
    9.     Newtonsoft.Json.JsonSerializer.SerializeInternal (Newtonsoft.Json.JsonWriter jsonWriter, System.Object value, System.Type objectType) (at <00000000000000000000000000000000>:0)
    10.     Newtonsoft.Json.JsonConvert.SerializeObjectInternal (System.Object value, System.Type type, Newtonsoft.Json.JsonSerializer jsonSerializer) (at <00000000000000000000000000000000>:0)
    Any ideas?
     
  50. SureSight

    SureSight

    Joined:
    Aug 2, 2013
    Posts:
    65
    Forgive me, but I can't seem to make that work either.

    BSON seems to only be an option using the JsonSerializer.Serialize() method, but there is no way to pass JsonSerializerSettings parameter to that method.

    I even tried updating the JsonConvert.DefaultSettings as the documentation suggested, but I get the same error.

    Code (CSharp):
    1. JsonConvert.DefaultSettings = () => new JsonSerializerSettings
    2.       {
    3.         ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    4.       };
    5.  
    6. using (FileStream fileStream = File.Open(filePath, FileMode.OpenOrCreate))
    7.       {
    8.         using (BsonWriter bsonWriter = new BsonWriter(fileStream))
    9.         {
    10.           new JsonSerializer().Serialize(bsonWriter, gameSave);
    11.         }
    12.       }
    Do you have a suggested fix or should I give and just use some custom classes of my own to save to/from BSON? For example, GameSaveVector3