using System.Collections.Generic; using System.Diagnostics; using System.Linq; using UnityEngine; namespace AYellowpaper.SerializedCollections { [System.Serializable] public class SerializedDictionary : Dictionary, ISerializationCallbackReceiver { [SerializeField] internal List> _serializedList = new List>(); #if UNITY_EDITOR internal IKeyable LookupTable { get { if (_lookupTable == null) _lookupTable = new DictionaryLookupTable(this); return _lookupTable; } } private DictionaryLookupTable _lookupTable; #endif public SerializedDictionary() : base() {} public SerializedDictionary(SerializedDictionary serializedDictionary) : base(serializedDictionary) { #if UNITY_EDITOR foreach (var kvp in serializedDictionary._serializedList) _serializedList.Add(new SerializedKeyValuePair(kvp.Key, kvp.Value)); #endif } public SerializedDictionary(IDictionary dictionary) : base(dictionary) { SyncDictionaryToBackingField_Editor(); } public SerializedDictionary(IDictionary dictionary, IEqualityComparer comparer) : base( dictionary, comparer) { SyncDictionaryToBackingField_Editor(); } public SerializedDictionary(IEnumerable> collection) : base(collection) { SyncDictionaryToBackingField_Editor(); } public SerializedDictionary(IEnumerable> collection, IEqualityComparer comparer) : base(collection, comparer) { SyncDictionaryToBackingField_Editor(); } public SerializedDictionary(IEqualityComparer comparer) : base(comparer) { } public SerializedDictionary(int capacity) : base(capacity) { } public SerializedDictionary(int capacity, IEqualityComparer comparer) : base(capacity, comparer) { } [Conditional("UNITY_EDITOR")] private void SyncDictionaryToBackingField_Editor() { foreach (var kvp in this) _serializedList.Add(new SerializedKeyValuePair(kvp.Key, kvp.Value)); } #if UNITY_EDITOR public new TValue this[TKey key] { get => base[key]; set { base[key] = value; for (int i = 0; i < _serializedList.Count; i++) { var kvp = _serializedList[i]; if (!SerializedCollectionsUtility.KeysAreEqual(key, kvp.Key)) continue; kvp.Value = value; _serializedList[i] = kvp; } } } public new void Add(TKey key, TValue value) { base.Add(key, value); _serializedList.Add(new SerializedKeyValuePair(key, value)); } public new void Clear() { base.Clear(); _serializedList.Clear(); } public new bool Remove(TKey key) { if (TryGetValue(key, out var value)) { base.Remove(key); _serializedList.Remove(new SerializedKeyValuePair(key, value)); return true; } return false; } public new bool TryAdd(TKey key, TValue value) { if (base.TryAdd(key, value)) { _serializedList.Add(new SerializedKeyValuePair(key, value)); return true; } return false; } /// /// Only available in Editor. Add a key value pair, even if the key already exists in the dictionary. /// public void AddConflictAllowed(TKey key, TValue value) { if (!ContainsKey(key)) base.Add(key, value); _serializedList.Add(new SerializedKeyValuePair(key, value)); } #endif public void OnAfterDeserialize() { base.Clear(); foreach (var kvp in _serializedList) { #if UNITY_EDITOR if (SerializedCollectionsUtility.IsValidKey(kvp.Key) && !ContainsKey(kvp.Key)) base.Add(kvp.Key, kvp.Value); #else Add(kvp.Key, kvp.Value); #endif } #if UNITY_EDITOR LookupTable.RecalculateOccurences(); #else _serializedList.Clear(); #endif } public void OnBeforeSerialize() { #if UNITY_EDITOR if (UnityEditor.BuildPipeline.isBuildingPlayer) LookupTable.RemoveDuplicates(); #else foreach (var kvp in this) _serializedList.Add(new SerializedKeyValuePair(kvp.Key, kvp.Value)); #endif } } }