Search Unity

Putting AssetReference into SerializableDictionary messes the editor up

Discussion in 'Addressables' started by Kerber996, Jun 20, 2019.

  1. Kerber996

    Kerber996

    Joined:
    Nov 9, 2016
    Posts:
    23
    I have created a SerializableDictionary<some enum, AssetReference> and when i click to create one in the editor it makes the editor all crazyyyyyy.

    bugz.PNG


    Code (CSharp):
    1.  
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System.Runtime.Serialization;
    6. using UnityEngine;
    7.  
    8. namespace CaseDK.SerializableDictionary{
    9.  
    10.     public abstract class SerializableDictionaryBase
    11.     {
    12.         public abstract class Storage { }
    13.  
    14.         protected class Dictionary<TKey, TValue> : System.Collections.Generic.Dictionary<TKey, TValue>
    15.         {
    16.             public Dictionary() { }
    17.             public Dictionary(IDictionary<TKey, TValue> dict) : base(dict) { }
    18.             public Dictionary(SerializationInfo info, StreamingContext context) : base(info, context) { }
    19.         }
    20.     }
    21.  
    22.     [Serializable]
    23.     public abstract class SerializableDictionaryBase<TKey, TValue, TValueStorage> : SerializableDictionaryBase, IDictionary<TKey, TValue>, IDictionary, ISerializationCallbackReceiver, IDeserializationCallback, ISerializable
    24.     {
    25.         Dictionary<TKey, TValue> m_dict;
    26.         [SerializeField]
    27.         TKey[] m_keys;
    28.         [SerializeField]
    29.         TValueStorage[] m_values;
    30.  
    31.         public SerializableDictionaryBase()
    32.         {
    33.             m_dict = new Dictionary<TKey, TValue>();
    34.         }
    35.  
    36.         public SerializableDictionaryBase(IDictionary<TKey, TValue> dict)
    37.         {
    38.             m_dict = new Dictionary<TKey, TValue>(dict);
    39.         }
    40.  
    41.         protected abstract void SetValue(TValueStorage[] storage, int i, TValue value);
    42.         protected abstract TValue GetValue(TValueStorage[] storage, int i);
    43.  
    44.         public void CopyFrom(IDictionary<TKey, TValue> dict)
    45.         {
    46.             m_dict.Clear();
    47.             foreach (var kvp in dict)
    48.             {
    49.                 m_dict[kvp.Key] = kvp.Value;
    50.             }
    51.         }
    52.  
    53.         public void OnAfterDeserialize()
    54.         {
    55.             if (m_keys != null && m_values != null && m_keys.Length == m_values.Length)
    56.             {
    57.                 m_dict.Clear();
    58.                 int n = m_keys.Length;
    59.                 for (int i = 0; i < n; ++i)
    60.                 {
    61.                     m_dict[m_keys[i]] = GetValue(m_values, i);
    62.                 }
    63.  
    64.                 m_keys = null;
    65.                 m_values = null;
    66.             }
    67.         }
    68.  
    69.         public void OnBeforeSerialize()
    70.         {
    71.             int n = m_dict.Count;
    72.             m_keys = new TKey[n];
    73.             m_values = new TValueStorage[n];
    74.  
    75.             int i = 0;
    76.             foreach (var kvp in m_dict)
    77.             {
    78.                 m_keys[i] = kvp.Key;
    79.                 SetValue(m_values, i, kvp.Value);
    80.                 ++i;
    81.             }
    82.         }
    83.  
    84.         #region IDictionary<TKey, TValue>
    85.  
    86.         public ICollection<TKey> Keys { get { return ((IDictionary<TKey, TValue>)m_dict).Keys; } }
    87.         public ICollection<TValue> Values { get { return ((IDictionary<TKey, TValue>)m_dict).Values; } }
    88.         public int Count { get { return ((IDictionary<TKey, TValue>)m_dict).Count; } }
    89.         public bool IsReadOnly { get { return ((IDictionary<TKey, TValue>)m_dict).IsReadOnly; } }
    90.  
    91.         public TValue this[TKey key]
    92.         {
    93.             get { return ((IDictionary<TKey, TValue>)m_dict)[key]; }
    94.             set { ((IDictionary<TKey, TValue>)m_dict)[key] = value; }
    95.         }
    96.  
    97.         public void Add(TKey key, TValue value)
    98.         {
    99.             ((IDictionary<TKey, TValue>)m_dict).Add(key, value);
    100.         }
    101.  
    102.         public bool ContainsKey(TKey key)
    103.         {
    104.             return ((IDictionary<TKey, TValue>)m_dict).ContainsKey(key);
    105.         }
    106.  
    107.         public bool Remove(TKey key)
    108.         {
    109.             return ((IDictionary<TKey, TValue>)m_dict).Remove(key);
    110.         }
    111.  
    112.         public bool TryGetValue(TKey key, out TValue value)
    113.         {
    114.             return ((IDictionary<TKey, TValue>)m_dict).TryGetValue(key, out value);
    115.         }
    116.  
    117.         public void Add(KeyValuePair<TKey, TValue> item)
    118.         {
    119.             ((IDictionary<TKey, TValue>)m_dict).Add(item);
    120.         }
    121.  
    122.         public void Clear()
    123.         {
    124.             ((IDictionary<TKey, TValue>)m_dict).Clear();
    125.         }
    126.  
    127.         public bool Contains(KeyValuePair<TKey, TValue> item)
    128.         {
    129.             return ((IDictionary<TKey, TValue>)m_dict).Contains(item);
    130.         }
    131.  
    132.         public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    133.         {
    134.             ((IDictionary<TKey, TValue>)m_dict).CopyTo(array, arrayIndex);
    135.         }
    136.  
    137.         public bool Remove(KeyValuePair<TKey, TValue> item)
    138.         {
    139.             return ((IDictionary<TKey, TValue>)m_dict).Remove(item);
    140.         }
    141.  
    142.         public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    143.         {
    144.             return ((IDictionary<TKey, TValue>)m_dict).GetEnumerator();
    145.         }
    146.  
    147.         IEnumerator IEnumerable.GetEnumerator()
    148.         {
    149.             return ((IDictionary<TKey, TValue>)m_dict).GetEnumerator();
    150.         }
    151.  
    152.         #endregion
    153.  
    154.         #region IDictionary
    155.  
    156.         public bool IsFixedSize { get { return ((IDictionary)m_dict).IsFixedSize; } }
    157.         ICollection IDictionary.Keys { get { return ((IDictionary)m_dict).Keys; } }
    158.         ICollection IDictionary.Values { get { return ((IDictionary)m_dict).Values; } }
    159.         public bool IsSynchronized { get { return ((IDictionary)m_dict).IsSynchronized; } }
    160.         public object SyncRoot { get { return ((IDictionary)m_dict).SyncRoot; } }
    161.  
    162.         public object this[object key]
    163.         {
    164.             get { return ((IDictionary)m_dict)[key]; }
    165.             set { ((IDictionary)m_dict)[key] = value; }
    166.         }
    167.  
    168.         public void Add(object key, object value)
    169.         {
    170.             ((IDictionary)m_dict).Add(key, value);
    171.         }
    172.  
    173.         public bool Contains(object key)
    174.         {
    175.             return ((IDictionary)m_dict).Contains(key);
    176.         }
    177.  
    178.         IDictionaryEnumerator IDictionary.GetEnumerator()
    179.         {
    180.             return ((IDictionary)m_dict).GetEnumerator();
    181.         }
    182.  
    183.         public void Remove(object key)
    184.         {
    185.             ((IDictionary)m_dict).Remove(key);
    186.         }
    187.  
    188.         public void CopyTo(Array array, int index)
    189.         {
    190.             ((IDictionary)m_dict).CopyTo(array, index);
    191.         }
    192.  
    193.         #endregion
    194.  
    195.         #region IDeserializationCallback
    196.  
    197.         public void OnDeserialization(object sender)
    198.         {
    199.             ((IDeserializationCallback)m_dict).OnDeserialization(sender);
    200.         }
    201.  
    202.         #endregion
    203.  
    204.         #region ISerializable
    205.  
    206.         protected SerializableDictionaryBase(SerializationInfo info, StreamingContext context)
    207.         {
    208.             m_dict = new Dictionary<TKey, TValue>(info, context);
    209.         }
    210.  
    211.         public void GetObjectData(SerializationInfo info, StreamingContext context)
    212.         {
    213.             ((ISerializable)m_dict).GetObjectData(info, context);
    214.         }
    215.  
    216.         #endregion
    217.     }
    218.  
    219.     public static class SerializableDictionary
    220.     {
    221.         public class Storage<T> : SerializableDictionaryBase.Storage
    222.         {
    223.             public T data;
    224.         }
    225.     }
    226.  
    227.     public class SerializableDictionary<TKey, TValue> : SerializableDictionaryBase<TKey, TValue, TValue>
    228.     {
    229.         public SerializableDictionary() { }
    230.         public SerializableDictionary(IDictionary<TKey, TValue> dict) : base(dict) { }
    231.         protected SerializableDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { }
    232.  
    233.         protected override TValue GetValue(TValue[] storage, int i)
    234.         {
    235.             return storage[i];
    236.         }
    237.  
    238.         protected override void SetValue(TValue[] storage, int i, TValue value)
    239.         {
    240.             storage[i] = value;
    241.         }
    242.     }
    243.  
    244.     public class SerializableDictionary<TKey, TValue, TValueStorage> : SerializableDictionaryBase<TKey, TValue, TValueStorage> where TValueStorage : SerializableDictionary.Storage<TValue>, new()
    245.     {
    246.         public SerializableDictionary() { }
    247.         public SerializableDictionary(IDictionary<TKey, TValue> dict) : base(dict) { }
    248.         protected SerializableDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { }
    249.  
    250.         protected override TValue GetValue(TValueStorage[] storage, int i)
    251.         {
    252.             return storage[i].data;
    253.         }
    254.  
    255.         protected override void SetValue(TValueStorage[] storage, int i, TValue value)
    256.         {
    257.             storage[i] = new TValueStorage();
    258.             storage[i].data = value;
    259.         }
    260.     }
    261. }
    262.  
    Code (CSharp):
    1.  [System.Serializable]
    2.     public class ATAASDictionary : SerializableDictionary<ApartmentType /*enum*/, AssetReference> { }
    Most of the editor becomes unreadable, and i cant even select the asset or the enum :/
     
  2. unity_bill

    unity_bill

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    Well, we have to do a lot of custom UI to get the AssetReference to draw correctly, including special casing arrays and lists. As this is a custom container, we have no special case for it, and our UI code blows up.

    How do you render your dictionary in the inspector? I wouldn't think it would just draw correctly, unless you have it draw as lists of keys and values.

    Most likely what's needed here is either some custom drawing code in your dictionary's drawer, or more likely, custom code in the asset ref drawer. To pull that off, I think the best bet may be to inherit from AssetReference with something like AssetReferenceDict and then copy our AssetReferenceDrawer code to make your own AssetReferenceDrawerDict.

    Or poke at our drawer code. We have special cased arrays. Since you're using TValueStorage[] m_values under the hood, I'd guess that's what messes things up.