Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Join us on March 30, 2023, between 5 am & 1 pm EST, in the Performance Profiling Dev Blitz Day 2023 - Q&A forum and Discord where you can connect with our teams behind the Memory and CPU Profilers.
    Dismiss Notice

[Released] Serializable Dictionary Lite - Now allowing custom editor for key field

Discussion in 'Assets and Asset Store' started by Rotary-Heart, Feb 19, 2018.

  1. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
  2. tonygiang

    tonygiang

    Joined:
    Jun 13, 2017
    Posts:
    53
    There is a problem with OpenUPM not recognizing a valid git tag for SDL.

    Edit: I think I found the issue. upm which uses npm underneath only recognizes SemVer syntax. That means 3 numbers in the version string only.
     
    Last edited: Oct 29, 2021
  3. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
    Good catch, I didn't realize that it had an issue. It has been fixed now.
     
  4. minad2017

    minad2017

    Joined:
    Dec 1, 2016
    Posts:
    50
    hi.
    I'm using the Lite version of Unity 2020.3.10f1.

    When I use the "StringColorArrayDictionary", the name is not visible to the inspector.
    It only becomes visible again when I hover the mouse pointer over it.
    I recently went from Unity 2019 to 2020, and I remember that it was not a problem in 2019.
    Is there any way to fix this?
     

    Attached Files:

    • 1.jpg
      1.jpg
      File size:
      19.5 KB
      Views:
      196
  5. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
    Can you send a small reproducible package? I'm having trouble replicating this
     
  6. tonygiang

    tonygiang

    Joined:
    Jun 13, 2017
    Posts:
    53
    Hey, just a heads up about the documentation of this package that you may want to consider updating: I think users should be aware that starting from Unity 2020, subclassing
    SerializableDictionaryBase
    to a non-generic class is now a completely optional step. Unity 2020+ can now serialize generic classes. So users of this package can now just do this:

    Code (CSharp):
    1. public SerializableDictionaryBase<string, UnityEvent<string>> StringEvents
    2.     = new SerializableDictionaryBase<string, UnityEvent<string>>();
    Yes, Unity 2020+ even handles nested generics. The above field looks like this in Inspector:

     
  7. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
    While that is true, I've received a couple of support tickets while using a direct generic declaration. Here's a thread I made about it https://forum.unity.com/threads/generic-reference-is-ignoring-default-values-case-1376739.1189978/
     
  8. sunwooz

    sunwooz

    Joined:
    Nov 9, 2012
    Posts:
    10
    Is there a complete example using a simple Dictionary with key of string and value of class? I'm pretty new to Unity and I'm having a hard time getting the dictionary to show up in the editor.

    Code (CSharp):
    1.  
    2. using RotaryHeart.Lib.SerializableDictionary;
    3.  
    4. [Serializable]
    5. public class MyDictionary : SerializableDictionaryBase<string, List<ItemEffect>> { }
    6.  
    7. [SerializeField]
    8. public MyDictionary itemEffects;
    9.  
    10. public class ItemEffect
    11. {
    12.     [SerializeField]
    13.     public string resource { get; set; }
    14.     [SerializeField]
    15.     public int amount { get; set; }
    16. }
    17.  
    Should this be enough to get it to work?
    Maybe I need to instantiate the dictionary to get it to show?
    Any help would be appreciated
     
  9. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
    Hello,

    You are really close to having it good to go! You can check the advanced dictionary from the documentation if you want more information, but what you are missing is a wrapper class for your List<ItemEffect> value. Unity cannot serialize multi-dimension array. You also need to mark your class as Serializable and you may not be able to use properties as SerializeFields without an additional attribute (Depends on Unity version and a couple of other stuff).

    Check the code changes below, this should fix your issues.

    Code (CSharp):
    1. using RotaryHeart.Lib.SerializableDictionary;
    2.  
    3. [Serializable]
    4. public class MyDictionary : SerializableDictionaryBase<string, ValueWrapper> { }
    5.  
    6. [SerializeField]
    7. public MyDictionary itemEffects;
    8.  
    9. [Serializable]
    10. public class ItemEffect
    11. {
    12.     [SerializeField]
    13.     public string resource;
    14.     [SerializeField]
    15.     public int amount;
    16. }
    17.  
    18. [Serializable]
    19. public class ValueWrapper
    20. {
    21.     public List<ItemEffect> values;
    22. }
     
  10. sunwooz

    sunwooz

    Joined:
    Nov 9, 2012
    Posts:
    10
    Thank you for your quick reply!

    I see the Dictionary now in the editor, but can't seem to modify the values. Do I need to do something extra to be able to modify the values?

    upload_2022-6-7_17-45-17.png
     
  11. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
    Did you make all the changes provided above? You seem to be missing the Serializable attribute.
     
  12. sunwooz

    sunwooz

    Joined:
    Nov 9, 2012
    Posts:
    10
    You're right. I was missing the Serializable on the ItemEffect class

    Now I can add elements to the array, but I can't seem to add the resource/amount for each array element.

    upload_2022-6-7_18-35-44.png

    I tried adding SerializeField inside the value wrapper, but that didn't work.. hmm.

    Thanks for your patience!
     
  13. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
    Did you change your properties to be fields as posted on the code above? You might need to read this Serialization for more details about Unity limitations.
     
  14. sunwooz

    sunwooz

    Joined:
    Nov 9, 2012
    Posts:
    10
    Thank you for the link!

    I was able to get it to work by changing this in the ItemEffect class.

    Code (CSharp):
    1.  
    2. [Serializable]
    3.     public class ItemEffect
    4.     {
    5.         [SerializeField]
    6.         public string resource {
    7.             get => m_backing;
    8.             private set => m_backing = value;
    9.         }
    10.         [SerializeField] private string m_backing;
    11.         [SerializeField]
    12.         public int amount {
    13.             get => m_backing2;
    14.             private set => m_backing2 = value;
    15.         }
    16.         [SerializeField] private int m_backing2;
    17.     }
    18.  
    I honestly have no idea what an explicit backing field really means, I think I have a guess at it, but this seems to work.
     
  15. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
    Version 2.6.9.6 has been submitted to the asset store for review. This version includes:
    • Added logic to allow TooltipAttribute to show
     
  16. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
    Great News! Version 2.6.9.6 is now live on the store!
     
  17. helloroy

    helloroy

    Joined:
    Jun 23, 2016
    Posts:
    33
    Hello, Pro version said "V3 has many modifications made to the system to allow for better data management with less than half of the memory usage of V2.", it's about Unity Editor or compiled game?

    And I want to say thanks that this asset is even better than Odin's Dictionary serialization, and both can work together, Amazing!
     
  18. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
    Hello!

    I'm glad to know that you like the asset. As for your question, it's about both. There are many difference in how both systems handle their data, but the main point is that the lite has overhead that is not related to a dictionary. You can see it if you serialize your data into a json object. Also lite dictionary cannot be serialized using with BinaryFormatter.

    Here's a quick example that shows how both of them handle the data, note that both of them are using the exact same data (use a json beutifier to see it better)
    Code (CSharp):
    1. Lite dictionary-----------------------------
    2. Json data: {"test":{"reorderableList":{"canAdd":true,"canRemove":true,"draggable":true,"expandable":true,"multipleSelection":true,"isExpanded":false,"label":{"m_Text":"Keys","m_Image":{"instanceID":0},"m_Tooltip":""},"headerHeight":18.0,"footerHeight":13.0,"slideEasing":0.15000000596046449,"verticalSpacing":2.0,"showDefaultBackground":true,"elementDisplayType":0,"elementNameProperty":"","elementNameOverride":"","elementIcon":{"instanceID":0}},"reqReferences":{"instanceID":0},"isExpanded":false,"_keyValues":[0,1,2,3,4,5],"_keys":[0,1,2,3,4,5],"_values":[1,2,3,4,5,6]},"test2":{"reorderableList":{"canAdd":true,"canRemove":true,"draggable":true,"expandable":true,"multipleSelection":true,"isExpanded":false,"label":{"m_Text":"Keys","m_Image":{"instanceID":0},"m_Tooltip":""},"headerHeight":18.0,"footerHeight":13.0,"slideEasing":0.15000000596046449,"verticalSpacing":2.0,"showDefaultBackground":true,"elementDisplayType":0,"elementNameProperty":"","elementNameOverride":"","elementIcon":{"instanceID":0}},"reqReferences":{"instanceID":13814},"isExpanded":false,"_keyValues":[{"val":2147483647},{"val":2147483647},{"val":2147483647},{"val":2147483647},{"val":2147483647},{"val":2147483647}],"_keys":[{"val":2147483647},{"val":2147483647},{"val":2147483647},{"val":2147483647},{"val":2147483647},{"val":2147483647}],"_values":[1,2,3,4,5,6]}}
    3. Json size: 1332
    4. System.Runtime.Serialization.SerializationException: Type 'RotaryHeart.Lib.SerializableDictionary.DrawableDictionary'
    5.  
    6. Pro dictionary-----------------------------
    7. Json data: {"test":{"m_val":7,"m_keys":[0,1,2,3,4,5],"m_values":[1,2,3,4,5,6]},"test2":{"m_val":7,"m_keys":[{"val":2147483647},{"val":2147483647},{"val":2147483647},{"val":2147483647},{"val":2147483647},{"val":2147483647}],"m_values":[1,2,3,4,5,6]}}
    8. Json size: 238
    9. BinaryFormatter size: 5833
    Here's the code used for this example:
    Code (CSharp):
    1. public class NewBehaviourScript : MonoBehaviour
    2. {
    3.     public enum MyEnum
    4.     {
    5.         EnumValue1, EnumValue2, EnumValue3, EnumValue4, EnumValue5, EnumValue6
    6.     }
    7.  
    8.     [System.Serializable]
    9.     public class GenericHolder
    10.     {
    11.         public int val;
    12.     }
    13.    
    14.     [System.Serializable]
    15.     public class LiteHolder
    16.     {
    17.         [System.Serializable]
    18.         public class MyDictionary : SerializableDictionaryBase<MyEnum, int> { }
    19.    
    20.         [System.Serializable]
    21.         public class MyDictionary2 : SerializableDictionaryBase<GenericHolder, int> { }
    22.  
    23.         public MyDictionary test;
    24.         public MyDictionary2 test2;
    25.     }
    26.    
    27.     [System.Serializable]
    28.     public class ProHolder
    29.     {
    30.         [System.Serializable]
    31.         public class MyDictionary : SerializableDictionary<MyEnum, int> { }
    32.    
    33.         [System.Serializable]
    34.         public class MyDictionary2 : SerializableDictionary<GenericHolder, int> { }
    35.  
    36.         public MyDictionary test;
    37.         public MyDictionary2 test2;
    38.     }
    39.  
    40.     public LiteHolder dictionaryLite;
    41.     public ProHolder dictionaryPro;
    42.  
    43.     [ContextMenu("Serialize")]
    44.     public void Serialize()
    45.     {
    46.         Debug.Log("Lite dictionary-----------------------------");
    47.         SerializeObject(dictionaryLite);
    48.         Debug.Log("Pro dictionary-----------------------------");
    49.         SerializeObject(dictionaryPro);
    50.     }
    51.  
    52.     public void SerializeObject(object obj)
    53.     {
    54.         var data = JsonUtility.ToJson(obj);
    55.         Debug.Log($"Json data: {data}");
    56.         Debug.Log($"Json size: {data.Length}");
    57.        
    58.         try
    59.         {
    60.             using (Stream s = new MemoryStream())
    61.             {
    62.                 BinaryFormatter formatter = new BinaryFormatter();
    63.                 formatter.Serialize(s, obj);
    64.                 Debug.Log($"BinaryFormatter size: {s.Length}");
    65.             }
    66.         }
    67.         catch (System.Exception e)
    68.         {
    69.             Debug.LogError(e);
    70.         }
    71.     }
    72. }
    And the data stored on both of them (As you can see it is using the exact same data):
    upload_2022-12-21_20-27-51.png upload_2022-12-21_20-29-31.png
     
    Stexe likes this.
  19. unity_2F92679DC87B10556DB6

    unity_2F92679DC87B10556DB6

    Joined:
    Jan 18, 2023
    Posts:
    4
    Hey, I've been using this on a project. When I try to build, it gives me a ton of errors directed to the Serialized dictionary folder. Should I be able to build using this package?

    upload_2023-2-7_17-32-7.png
     
  20. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
    Hello, yes you definitely can. Note that the folder that is throwing you errors is an editor folder, it shouldn't be included in the build. I have a couple of questions for you

    Are you using any custom build pipeline?
    What Unity version are you using?
    What platform are you build?
     
  21. unity_2F92679DC87B10556DB6

    unity_2F92679DC87B10556DB6

    Joined:
    Jan 18, 2023
    Posts:
    4
    Hey, thanks for responding so quickly :D

    So, I'm not using a custom build pipeline, my version is 2021.3.8f1, and I'm building for Windows.
    I didn't know you could exclude folders and files from a build, wow.
    When I imported the package, the folder went into the Assets folder instead of the Packages folder, would that be the issue? Or should I just try to exclude the editor folder from build?
     
    Last edited: Feb 8, 2023
  22. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
    I cannot replicate your issue, I was able to make a build without problems using the same Unity version.

    What version of the asset are you using?
    Can you try replicating it in an empty project?
     
  23. unity_2F92679DC87B10556DB6

    unity_2F92679DC87B10556DB6

    Joined:
    Jan 18, 2023
    Posts:
    4
  24. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
    I see the issue. You've added an asmdef to the asset folder, note that if you do that and not add one to the editor folder when you compile it will try to include the editor file. You'll need to add an asmdef to the editor folder and mark it editor only. Take a look at the RotaryHeart.Editor.asmdef file in Rotary Heart/Shared/Editor for an example
     
  25. unity_2F92679DC87B10556DB6

    unity_2F92679DC87B10556DB6

    Joined:
    Jan 18, 2023
    Posts:
    4
  26. Agent40

    Agent40

    Joined:
    Oct 31, 2020
    Posts:
    3
    Hey, your serialized dictionary has been an amazing help but there seems to be an issue with using it alongside SerializedProperty. I couldn't find anything about there being any issues with it but from the looks of things the propertyheight isn't being calculated properly. upload_2023-3-19_22-27-22.png
    upload_2023-3-19_22-27-53.png
    upload_2023-3-19_22-28-22.png

    It works completely fine by itself but as soon as a SerializedProperty is involved, it breaks completely and refuses to even show in play mode.

    upload_2023-3-19_22-31-3.png

    Update: it works while empty now but as soon as it's filled with any type of data, it can no longer be expanded and is visually skewed
     
    Last edited: Mar 19, 2023
  27. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
    Can you upload a repro script. I'm failing to replicate the issue, also what Unity version are you using?
     
  28. Agent40

    Agent40

    Joined:
    Oct 31, 2020
    Posts:
    3
  29. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
    I couldn't test your scripts since it had some errors, but seems like what you are trying to do will give you problems with many drawers since you are creating many new
    SerialiedObjects
    . What you can do instead is use CreateEditor and draw that editor in your window:

    Code (CSharp):
    1. protected Editor snapshotEditor;
    2.  
    3. void OnEnable()
    4. {
    5.     var snapshot = ScriptableObject.CreateInstance<SnapshotEditor>();
    6.     snapshotEditor = Editor.CreateEditor(snapshot);
    7. }
    8.  
    9. void OnDestroy()
    10. {
    11.     DestroyImmediate(snapshotEditor);
    12. }
    13.  
    14. void OnGUI()
    15. {
    16.     snapshotEditor.OnInspectorGUI();
    17. }
     
  30. Agent40

    Agent40

    Joined:
    Oct 31, 2020
    Posts:
    3
    Sorry there was 1 redundant line, it should work now. Editor cannot be utilised in EditorWindow so are you specifying to create an Editor for SnapshotEditor so that it works within SnapshotEditorWindow?
     
  31. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    798
    No, you can use that code in your editor window and it will draw the appropriate inspector in your window.

    upload_2023-3-21_22-2-54.png