diff options
author | chai <chaifix@163.com> | 2021-07-27 09:40:26 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2021-07-27 09:40:26 +0800 |
commit | 8bbc03542340b4ea7ca1e2beec2f11ff335851e8 (patch) | |
tree | 15a4bdebe7b8d9448c476e0f67b94a5a50bc2ec5 /Assets/SerializableDictionary | |
parent | 4ceee84cd45e4e3ec40ebd888e41bd47a938c2d5 (diff) |
*mic
Diffstat (limited to 'Assets/SerializableDictionary')
17 files changed, 1091 insertions, 0 deletions
diff --git a/Assets/SerializableDictionary/Editor.meta b/Assets/SerializableDictionary/Editor.meta new file mode 100644 index 00000000..5bfd990a --- /dev/null +++ b/Assets/SerializableDictionary/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 20029ee1c099f4b47afbac48208879b9 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/SerializableDictionary/Editor/SerializableDictionaryPropertyDrawer.cs b/Assets/SerializableDictionary/Editor/SerializableDictionaryPropertyDrawer.cs new file mode 100644 index 00000000..f631a96a --- /dev/null +++ b/Assets/SerializableDictionary/Editor/SerializableDictionaryPropertyDrawer.cs @@ -0,0 +1,565 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using System.Reflection; +using System; + +public class SerializableDictionaryPropertyDrawer : PropertyDrawer +{ + const string KeysFieldName = "m_keys"; + const string ValuesFieldName = "m_values"; + protected const float IndentWidth = 15f; + + static GUIContent s_iconPlus = IconContent ("Toolbar Plus", "Add entry"); + static GUIContent s_iconMinus = IconContent ("Toolbar Minus", "Remove entry"); + static GUIContent s_warningIconConflict = IconContent ("console.warnicon.sml", "Conflicting key, this entry will be lost"); + static GUIContent s_warningIconOther = IconContent ("console.infoicon.sml", "Conflicting key"); + static GUIContent s_warningIconNull = IconContent ("console.warnicon.sml", "Null key, this entry will be lost"); + static GUIStyle s_buttonStyle = GUIStyle.none; + static GUIContent s_tempContent = new GUIContent(); + + + class ConflictState + { + public object conflictKey = null; + public object conflictValue = null; + public int conflictIndex = -1 ; + public int conflictOtherIndex = -1 ; + public bool conflictKeyPropertyExpanded = false; + public bool conflictValuePropertyExpanded = false; + public float conflictLineHeight = 0f; + } + + struct PropertyIdentity + { + public PropertyIdentity(SerializedProperty property) + { + this.instance = property.serializedObject.targetObject; + this.propertyPath = property.propertyPath; + } + + public UnityEngine.Object instance; + public string propertyPath; + } + + static Dictionary<PropertyIdentity, ConflictState> s_conflictStateDict = new Dictionary<PropertyIdentity, ConflictState>(); + + enum Action + { + None, + Add, + Remove + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + label = EditorGUI.BeginProperty(position, label, property); + + Action buttonAction = Action.None; + int buttonActionIndex = 0; + + var keyArrayProperty = property.FindPropertyRelative(KeysFieldName); + var valueArrayProperty = property.FindPropertyRelative(ValuesFieldName); + + ConflictState conflictState = GetConflictState(property); + + if(conflictState.conflictIndex != -1) + { + keyArrayProperty.InsertArrayElementAtIndex(conflictState.conflictIndex); + var keyProperty = keyArrayProperty.GetArrayElementAtIndex(conflictState.conflictIndex); + SetPropertyValue(keyProperty, conflictState.conflictKey); + keyProperty.isExpanded = conflictState.conflictKeyPropertyExpanded; + + valueArrayProperty.InsertArrayElementAtIndex(conflictState.conflictIndex); + var valueProperty = valueArrayProperty.GetArrayElementAtIndex(conflictState.conflictIndex); + SetPropertyValue(valueProperty, conflictState.conflictValue); + valueProperty.isExpanded = conflictState.conflictValuePropertyExpanded; + } + + var buttonWidth = s_buttonStyle.CalcSize(s_iconPlus).x; + + var labelPosition = position; + labelPosition.height = EditorGUIUtility.singleLineHeight; + if (property.isExpanded) + labelPosition.xMax -= s_buttonStyle.CalcSize(s_iconPlus).x; + + EditorGUI.PropertyField(labelPosition, property, label, false); + // property.isExpanded = EditorGUI.Foldout(labelPosition, property.isExpanded, label); + if (property.isExpanded) + { + var buttonPosition = position; + buttonPosition.xMin = buttonPosition.xMax - buttonWidth; + buttonPosition.height = EditorGUIUtility.singleLineHeight; + EditorGUI.BeginDisabledGroup(conflictState.conflictIndex != -1); + if(GUI.Button(buttonPosition, s_iconPlus, s_buttonStyle)) + { + buttonAction = Action.Add; + buttonActionIndex = keyArrayProperty.arraySize; + } + EditorGUI.EndDisabledGroup(); + + EditorGUI.indentLevel++; + var linePosition = position; + linePosition.y += EditorGUIUtility.singleLineHeight; + linePosition.xMax -= buttonWidth; + + foreach(var entry in EnumerateEntries(keyArrayProperty, valueArrayProperty)) + { + var keyProperty = entry.keyProperty; + var valueProperty = entry.valueProperty; + int i = entry.index; + + float lineHeight = DrawKeyValueLine(keyProperty, valueProperty, linePosition, i); + + buttonPosition = linePosition; + buttonPosition.x = linePosition.xMax; + buttonPosition.height = EditorGUIUtility.singleLineHeight; + if(GUI.Button(buttonPosition, s_iconMinus, s_buttonStyle)) + { + buttonAction = Action.Remove; + buttonActionIndex = i; + } + + if(i == conflictState.conflictIndex && conflictState.conflictOtherIndex == -1) + { + var iconPosition = linePosition; + iconPosition.size = s_buttonStyle.CalcSize(s_warningIconNull); + GUI.Label(iconPosition, s_warningIconNull); + } + else if(i == conflictState.conflictIndex) + { + var iconPosition = linePosition; + iconPosition.size = s_buttonStyle.CalcSize(s_warningIconConflict); + GUI.Label(iconPosition, s_warningIconConflict); + } + else if(i == conflictState.conflictOtherIndex) + { + var iconPosition = linePosition; + iconPosition.size = s_buttonStyle.CalcSize(s_warningIconOther); + GUI.Label(iconPosition, s_warningIconOther); + } + + + linePosition.y += lineHeight; + } + + EditorGUI.indentLevel--; + } + + if(buttonAction == Action.Add) + { + keyArrayProperty.InsertArrayElementAtIndex(buttonActionIndex); + valueArrayProperty.InsertArrayElementAtIndex(buttonActionIndex); + } + else if(buttonAction == Action.Remove) + { + DeleteArrayElementAtIndex(keyArrayProperty, buttonActionIndex); + DeleteArrayElementAtIndex(valueArrayProperty, buttonActionIndex); + } + + conflictState.conflictKey = null; + conflictState.conflictValue = null; + conflictState.conflictIndex = -1; + conflictState.conflictOtherIndex = -1; + conflictState.conflictLineHeight = 0f; + conflictState.conflictKeyPropertyExpanded = false; + conflictState.conflictValuePropertyExpanded = false; + + foreach(var entry1 in EnumerateEntries(keyArrayProperty, valueArrayProperty)) + { + var keyProperty1 = entry1.keyProperty; + int i = entry1.index; + object keyProperty1Value = GetPropertyValue(keyProperty1); + + if(keyProperty1Value == null) + { + var valueProperty1 = entry1.valueProperty; + SaveProperty(keyProperty1, valueProperty1, i, -1, conflictState); + DeleteArrayElementAtIndex(valueArrayProperty, i); + DeleteArrayElementAtIndex(keyArrayProperty, i); + + break; + } + + + foreach(var entry2 in EnumerateEntries(keyArrayProperty, valueArrayProperty, i + 1)) + { + var keyProperty2 = entry2.keyProperty; + int j = entry2.index; + object keyProperty2Value = GetPropertyValue(keyProperty2); + + if(ComparePropertyValues(keyProperty1Value, keyProperty2Value)) + { + var valueProperty2 = entry2.valueProperty; + SaveProperty(keyProperty2, valueProperty2, j, i, conflictState); + DeleteArrayElementAtIndex(keyArrayProperty, j); + DeleteArrayElementAtIndex(valueArrayProperty, j); + + goto breakLoops; + } + } + } + breakLoops: + + EditorGUI.EndProperty(); + } + + static float DrawKeyValueLine(SerializedProperty keyProperty, SerializedProperty valueProperty, Rect linePosition, int index) + { + bool keyCanBeExpanded = CanPropertyBeExpanded(keyProperty); + bool valueCanBeExpanded = CanPropertyBeExpanded(valueProperty); + + if(!keyCanBeExpanded && valueCanBeExpanded) + { + return DrawKeyValueLineExpand(keyProperty, valueProperty, linePosition); + } + else + { + var keyLabel = keyCanBeExpanded ? ("Key " + index.ToString()) : ""; + var valueLabel = valueCanBeExpanded ? ("Value " + index.ToString()) : ""; + return DrawKeyValueLineSimple(keyProperty, valueProperty, keyLabel, valueLabel, linePosition); + } + } + + static float DrawKeyValueLineSimple(SerializedProperty keyProperty, SerializedProperty valueProperty, string keyLabel, string valueLabel, Rect linePosition) + { + float labelWidth = EditorGUIUtility.labelWidth; + float labelWidthRelative = labelWidth / linePosition.width; + + float keyPropertyHeight = EditorGUI.GetPropertyHeight(keyProperty); + var keyPosition = linePosition; + keyPosition.height = keyPropertyHeight; + keyPosition.width = labelWidth - IndentWidth; + EditorGUIUtility.labelWidth = keyPosition.width * labelWidthRelative; + EditorGUI.PropertyField(keyPosition, keyProperty, TempContent(keyLabel), true); + + float valuePropertyHeight = EditorGUI.GetPropertyHeight(valueProperty); + var valuePosition = linePosition; + valuePosition.height = valuePropertyHeight; + valuePosition.xMin += labelWidth; + EditorGUIUtility.labelWidth = valuePosition.width * labelWidthRelative; + EditorGUI.indentLevel--; + EditorGUI.PropertyField(valuePosition, valueProperty, TempContent(valueLabel), true); + EditorGUI.indentLevel++; + + EditorGUIUtility.labelWidth = labelWidth; + + return Mathf.Max(keyPropertyHeight, valuePropertyHeight); + } + + static float DrawKeyValueLineExpand(SerializedProperty keyProperty, SerializedProperty valueProperty, Rect linePosition) + { + float labelWidth = EditorGUIUtility.labelWidth; + + float keyPropertyHeight = EditorGUI.GetPropertyHeight(keyProperty); + var keyPosition = linePosition; + keyPosition.height = keyPropertyHeight; + keyPosition.width = labelWidth - IndentWidth; + EditorGUI.PropertyField(keyPosition, keyProperty, GUIContent.none, true); + + float valuePropertyHeight = EditorGUI.GetPropertyHeight(valueProperty); + var valuePosition = linePosition; + valuePosition.height = valuePropertyHeight; + EditorGUI.PropertyField(valuePosition, valueProperty, GUIContent.none, true); + + EditorGUIUtility.labelWidth = labelWidth; + + return Mathf.Max(keyPropertyHeight, valuePropertyHeight); + } + + static bool CanPropertyBeExpanded(SerializedProperty property) + { + switch(property.propertyType) + { + case SerializedPropertyType.Generic: + case SerializedPropertyType.Vector4: + case SerializedPropertyType.Quaternion: + return true; + default: + return false; + } + } + + static void SaveProperty(SerializedProperty keyProperty, SerializedProperty valueProperty, int index, int otherIndex, ConflictState conflictState) + { + conflictState.conflictKey = GetPropertyValue(keyProperty); + conflictState.conflictValue = GetPropertyValue(valueProperty); + float keyPropertyHeight = EditorGUI.GetPropertyHeight(keyProperty); + float valuePropertyHeight = EditorGUI.GetPropertyHeight(valueProperty); + float lineHeight = Mathf.Max(keyPropertyHeight, valuePropertyHeight); + conflictState.conflictLineHeight = lineHeight; + conflictState.conflictIndex = index; + conflictState.conflictOtherIndex = otherIndex; + conflictState.conflictKeyPropertyExpanded = keyProperty.isExpanded; + conflictState.conflictValuePropertyExpanded = valueProperty.isExpanded; + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + float propertyHeight = EditorGUIUtility.singleLineHeight; + + if (property.isExpanded) + { + var keysProperty = property.FindPropertyRelative(KeysFieldName); + var valuesProperty = property.FindPropertyRelative(ValuesFieldName); + + foreach(var entry in EnumerateEntries(keysProperty, valuesProperty)) + { + var keyProperty = entry.keyProperty; + var valueProperty = entry.valueProperty; + float keyPropertyHeight = EditorGUI.GetPropertyHeight(keyProperty); + float valuePropertyHeight = EditorGUI.GetPropertyHeight(valueProperty); + float lineHeight = Mathf.Max(keyPropertyHeight, valuePropertyHeight); + propertyHeight += lineHeight; + } + + ConflictState conflictState = GetConflictState(property); + + if(conflictState.conflictIndex != -1) + { + propertyHeight += conflictState.conflictLineHeight; + } + } + + return propertyHeight; + } + + static ConflictState GetConflictState(SerializedProperty property) + { + ConflictState conflictState; + PropertyIdentity propId = new PropertyIdentity(property); + if(!s_conflictStateDict.TryGetValue(propId, out conflictState)) + { + conflictState = new ConflictState(); + s_conflictStateDict.Add(propId, conflictState); + } + return conflictState; + } + + static Dictionary<SerializedPropertyType, PropertyInfo> s_serializedPropertyValueAccessorsDict; + + static SerializableDictionaryPropertyDrawer() + { + Dictionary<SerializedPropertyType, string> serializedPropertyValueAccessorsNameDict = new Dictionary<SerializedPropertyType, string>() { + { SerializedPropertyType.Integer, "intValue" }, + { SerializedPropertyType.Boolean, "boolValue" }, + { SerializedPropertyType.Float, "floatValue" }, + { SerializedPropertyType.String, "stringValue" }, + { SerializedPropertyType.Color, "colorValue" }, + { SerializedPropertyType.ObjectReference, "objectReferenceValue" }, + { SerializedPropertyType.LayerMask, "intValue" }, + { SerializedPropertyType.Enum, "intValue" }, + { SerializedPropertyType.Vector2, "vector2Value" }, + { SerializedPropertyType.Vector3, "vector3Value" }, + { SerializedPropertyType.Vector4, "vector4Value" }, + { SerializedPropertyType.Rect, "rectValue" }, + { SerializedPropertyType.ArraySize, "intValue" }, + { SerializedPropertyType.Character, "intValue" }, + { SerializedPropertyType.AnimationCurve, "animationCurveValue" }, + { SerializedPropertyType.Bounds, "boundsValue" }, + { SerializedPropertyType.Quaternion, "quaternionValue" }, + }; + Type serializedPropertyType = typeof(SerializedProperty); + + s_serializedPropertyValueAccessorsDict = new Dictionary<SerializedPropertyType, PropertyInfo>(); + BindingFlags flags = BindingFlags.Instance | BindingFlags.Public; + + foreach(var kvp in serializedPropertyValueAccessorsNameDict) + { + PropertyInfo propertyInfo = serializedPropertyType.GetProperty(kvp.Value, flags); + s_serializedPropertyValueAccessorsDict.Add(kvp.Key, propertyInfo); + } + } + + static GUIContent IconContent(string name, string tooltip) + { + var builtinIcon = EditorGUIUtility.IconContent (name); + return new GUIContent(builtinIcon.image, tooltip); + } + + static GUIContent TempContent(string text) + { + s_tempContent.text = text; + return s_tempContent; + } + + static void DeleteArrayElementAtIndex(SerializedProperty arrayProperty, int index) + { + var property = arrayProperty.GetArrayElementAtIndex(index); + // if(arrayProperty.arrayElementType.StartsWith("PPtr<$")) + if(property.propertyType == SerializedPropertyType.ObjectReference) + { + property.objectReferenceValue = null; + } + + arrayProperty.DeleteArrayElementAtIndex(index); + } + + public static object GetPropertyValue(SerializedProperty p) + { + PropertyInfo propertyInfo; + if(s_serializedPropertyValueAccessorsDict.TryGetValue(p.propertyType, out propertyInfo)) + { + return propertyInfo.GetValue(p, null); + } + else + { + if(p.isArray) + return GetPropertyValueArray(p); + else + return GetPropertyValueGeneric(p); + } + } + + static void SetPropertyValue(SerializedProperty p, object v) + { + PropertyInfo propertyInfo; + if(s_serializedPropertyValueAccessorsDict.TryGetValue(p.propertyType, out propertyInfo)) + { + propertyInfo.SetValue(p, v, null); + } + else + { + if(p.isArray) + SetPropertyValueArray(p, v); + else + SetPropertyValueGeneric(p, v); + } + } + + static object GetPropertyValueArray(SerializedProperty property) + { + object[] array = new object[property.arraySize]; + for(int i = 0; i < property.arraySize; i++) + { + SerializedProperty item = property.GetArrayElementAtIndex(i); + array[i] = GetPropertyValue(item); + } + return array; + } + + static object GetPropertyValueGeneric(SerializedProperty property) + { + Dictionary<string, object> dict = new Dictionary<string, object>(); + var iterator = property.Copy(); + if(iterator.Next(true)) + { + var end = property.GetEndProperty(); + do + { + string name = iterator.name; + object value = GetPropertyValue(iterator); + dict.Add(name, value); + } while(iterator.Next(false) && iterator.propertyPath != end.propertyPath); + } + return dict; + } + + static void SetPropertyValueArray(SerializedProperty property, object v) + { + object[] array = (object[]) v; + property.arraySize = array.Length; + for(int i = 0; i < property.arraySize; i++) + { + SerializedProperty item = property.GetArrayElementAtIndex(i); + SetPropertyValue(item, array[i]); + } + } + + static void SetPropertyValueGeneric(SerializedProperty property, object v) + { + Dictionary<string, object> dict = (Dictionary<string, object>) v; + var iterator = property.Copy(); + if(iterator.Next(true)) + { + var end = property.GetEndProperty(); + do + { + string name = iterator.name; + SetPropertyValue(iterator, dict[name]); + } while(iterator.Next(false) && iterator.propertyPath != end.propertyPath); + } + } + + static bool ComparePropertyValues(object value1, object value2) + { + if(value1 is Dictionary<string, object> && value2 is Dictionary<string, object>) + { + var dict1 = (Dictionary<string, object>)value1; + var dict2 = (Dictionary<string, object>)value2; + return CompareDictionaries(dict1, dict2); + } + else + { + return object.Equals(value1, value2); + } + } + + static bool CompareDictionaries(Dictionary<string, object> dict1, Dictionary<string, object> dict2) + { + if(dict1.Count != dict2.Count) + return false; + + foreach(var kvp1 in dict1) + { + var key1 = kvp1.Key; + object value1 = kvp1.Value; + + object value2; + if(!dict2.TryGetValue(key1, out value2)) + return false; + + if(!ComparePropertyValues(value1, value2)) + return false; + } + + return true; + } + + struct EnumerationEntry + { + public SerializedProperty keyProperty; + public SerializedProperty valueProperty; + public int index; + + public EnumerationEntry(SerializedProperty keyProperty, SerializedProperty valueProperty, int index) + { + this.keyProperty = keyProperty; + this.valueProperty = valueProperty; + this.index = index; + } + } + + static IEnumerable<EnumerationEntry> EnumerateEntries(SerializedProperty keyArrayProperty, SerializedProperty valueArrayProperty, int startIndex = 0) + { + if(keyArrayProperty.arraySize > startIndex) + { + int index = startIndex; + var keyProperty = keyArrayProperty.GetArrayElementAtIndex(startIndex); + var valueProperty = valueArrayProperty.GetArrayElementAtIndex(startIndex); + var endProperty = keyArrayProperty.GetEndProperty(); + + do + { + yield return new EnumerationEntry(keyProperty, valueProperty, index); + index++; + } while(keyProperty.Next(false) && valueProperty.Next(false) && !SerializedProperty.EqualContents(keyProperty, endProperty)); + } + } +} + +public class SerializableDictionaryStoragePropertyDrawer : PropertyDrawer +{ + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + property.Next(true); + EditorGUI.PropertyField(position, property, label, true); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + property.Next(true); + return EditorGUI.GetPropertyHeight(property); + } +} diff --git a/Assets/SerializableDictionary/Editor/SerializableDictionaryPropertyDrawer.cs.meta b/Assets/SerializableDictionary/Editor/SerializableDictionaryPropertyDrawer.cs.meta new file mode 100644 index 00000000..e10f405f --- /dev/null +++ b/Assets/SerializableDictionary/Editor/SerializableDictionaryPropertyDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 91da51d02ab9ebc459d80d5965d40d19 +timeCreated: 1492869349 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/SerializableDictionary/Example.meta b/Assets/SerializableDictionary/Example.meta new file mode 100644 index 00000000..5bbdabde --- /dev/null +++ b/Assets/SerializableDictionary/Example.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: ea574807be3814126807ca7b22d13988 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/SerializableDictionary/Example/Editor.meta b/Assets/SerializableDictionary/Example/Editor.meta new file mode 100644 index 00000000..f3048e56 --- /dev/null +++ b/Assets/SerializableDictionary/Example/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: b9e966b834ddb48d0815c494d4f511da +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/SerializableDictionary/Example/Editor/UserSerializableDictionaryPropertyDrawers.cs b/Assets/SerializableDictionary/Example/Editor/UserSerializableDictionaryPropertyDrawers.cs new file mode 100644 index 00000000..5c63f1ea --- /dev/null +++ b/Assets/SerializableDictionary/Example/Editor/UserSerializableDictionaryPropertyDrawers.cs @@ -0,0 +1,12 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +[CustomPropertyDrawer(typeof(StringStringDictionary))] +[CustomPropertyDrawer(typeof(ObjectColorDictionary))] +[CustomPropertyDrawer(typeof(StringColorArrayDictionary))] +public class AnySerializableDictionaryPropertyDrawer : SerializableDictionaryPropertyDrawer {} + +[CustomPropertyDrawer(typeof(ColorArrayStorage))] +public class AnySerializableDictionaryStoragePropertyDrawer: SerializableDictionaryStoragePropertyDrawer {} diff --git a/Assets/SerializableDictionary/Example/Editor/UserSerializableDictionaryPropertyDrawers.cs.meta b/Assets/SerializableDictionary/Example/Editor/UserSerializableDictionaryPropertyDrawers.cs.meta new file mode 100644 index 00000000..0c101e13 --- /dev/null +++ b/Assets/SerializableDictionary/Example/Editor/UserSerializableDictionaryPropertyDrawers.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3089b6c771301cc44ba23b7f8f469e14 +timeCreated: 1493639898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/SerializableDictionary/Example/SerializableDicitonary Example.unity b/Assets/SerializableDictionary/Example/SerializableDicitonary Example.unity new file mode 100644 index 00000000..ce09708d --- /dev/null +++ b/Assets/SerializableDictionary/Example/SerializableDicitonary Example.unity @@ -0,0 +1,251 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} + m_AmbientEquatorColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} + m_AmbientGroundColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &4 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_TemporalCoherenceThreshold: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 10 + m_Resolution: 1 + m_BakeResolution: 50 + m_AtlasSize: 1024 + m_AO: 1 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 0 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 1 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVRFilteringMode: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ShowResolutionOverlay: 1 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 0 +--- !u!196 &5 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666666 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &714127983 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 714127989} + - component: {fileID: 714127988} + - component: {fileID: 714127987} + - component: {fileID: 714127986} + - component: {fileID: 714127985} + - component: {fileID: 714127984} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &714127984 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 714127983} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d5ff00a74ccb984498070d9930a7944c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_stringStringDictionary: + m_keys: + - first key + - second key + - third key + m_values: + - value A + - value B + - value C + m_objectColorDictionary: + m_keys: + - {fileID: 714127983} + - {fileID: 714127984} + m_values: + - {r: 0, g: 0, b: 1, a: 1} + - {r: 1, g: 0, b: 0, a: 1} + m_objectColorArrayDictionary: + m_keys: + - rainbow + - grayscale + m_values: + - data: + - {r: 1, g: 0, b: 0, a: 1} + - {r: 1, g: 0.40000004, b: 0, a: 1} + - {r: 1, g: 0.9333334, b: 0, a: 1} + - {r: 0, g: 1, b: 0, a: 1} + - {r: 0, g: 0.6, b: 1, a: 1} + - {r: 0.26666668, g: 0, b: 1, a: 1} + - {r: 0.6, g: 0, b: 1, a: 1} + - data: + - {r: 0, g: 0, b: 0, a: 0} + - {r: 0.2509804, g: 0.2509804, b: 0.2509804, a: 0.2509804} + - {r: 0.5019608, g: 0.5019608, b: 0.5019608, a: 0.5019608} + - {r: 0.7529412, g: 0.7529412, b: 0.7529412, a: 0.7529412} + - {r: 1, g: 1, b: 1, a: 1} +--- !u!81 &714127985 +AudioListener: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 714127983} + m_Enabled: 1 +--- !u!124 &714127986 +Behaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 714127983} + m_Enabled: 1 +--- !u!92 &714127987 +Behaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 714127983} + m_Enabled: 1 +--- !u!20 &714127988 +Camera: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 714127983} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0.019607844} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 0 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &714127989 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 714127983} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/SerializableDictionary/Example/SerializableDicitonary Example.unity.meta b/Assets/SerializableDictionary/Example/SerializableDicitonary Example.unity.meta new file mode 100644 index 00000000..25ff160d --- /dev/null +++ b/Assets/SerializableDictionary/Example/SerializableDicitonary Example.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 6c0758ade4ba74b7493ce3806fa2f38b +DefaultImporter: + userData: diff --git a/Assets/SerializableDictionary/Example/SerializableDictionaryExample.cs b/Assets/SerializableDictionary/Example/SerializableDictionaryExample.cs new file mode 100644 index 00000000..f47a8923 --- /dev/null +++ b/Assets/SerializableDictionary/Example/SerializableDictionaryExample.cs @@ -0,0 +1,24 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class SerializableDictionaryExample : MonoBehaviour { + // The dictionaries can be accessed throught a property + [SerializeField] + StringStringDictionary m_stringStringDictionary; + public IDictionary<string, string> StringStringDictionary + { + get { return m_stringStringDictionary; } + set { m_stringStringDictionary.CopyFrom (value); } + } + + public ObjectColorDictionary m_objectColorDictionary; + public StringColorArrayDictionary m_objectColorArrayDictionary; + + void Reset () + { + // access by property + StringStringDictionary = new Dictionary<string, string>() { {"first key", "value A"}, {"second key", "value B"}, {"third key", "value C"} }; + m_objectColorDictionary = new ObjectColorDictionary() { {gameObject, Color.blue}, {this, Color.red} }; + } +} diff --git a/Assets/SerializableDictionary/Example/SerializableDictionaryExample.cs.meta b/Assets/SerializableDictionary/Example/SerializableDictionaryExample.cs.meta new file mode 100644 index 00000000..84a0fd47 --- /dev/null +++ b/Assets/SerializableDictionary/Example/SerializableDictionaryExample.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d5ff00a74ccb984498070d9930a7944c +timeCreated: 1492868873 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/SerializableDictionary/Example/UserSerializableDictionaries.cs b/Assets/SerializableDictionary/Example/UserSerializableDictionaries.cs new file mode 100644 index 00000000..b20b24bd --- /dev/null +++ b/Assets/SerializableDictionary/Example/UserSerializableDictionaries.cs @@ -0,0 +1,26 @@ +using System.Collections; +using System.Collections.Generic; +using System; +using UnityEngine; + +[Serializable] +public class StringStringDictionary : SerializableDictionary<string, string> {} + +[Serializable] +public class ObjectColorDictionary : SerializableDictionary<UnityEngine.Object, Color> {} + +[Serializable] +public class ColorArrayStorage : SerializableDictionary.Storage<Color[]> {} + +[Serializable] +public class StringColorArrayDictionary : SerializableDictionary<string, Color[], ColorArrayStorage> {} + +[Serializable] +public class MyClass +{ + public int i; + public string str; +} + +[Serializable] +public class QuaternionMyClassDictionary : SerializableDictionary<Quaternion, MyClass> {}
\ No newline at end of file diff --git a/Assets/SerializableDictionary/Example/UserSerializableDictionaries.cs.meta b/Assets/SerializableDictionary/Example/UserSerializableDictionaries.cs.meta new file mode 100644 index 00000000..0a39089b --- /dev/null +++ b/Assets/SerializableDictionary/Example/UserSerializableDictionaries.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: bd910530dd8f6b5429c65a494644ed09 +timeCreated: 1493639913 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/SerializableDictionary/SerializableDictionary.cs b/Assets/SerializableDictionary/SerializableDictionary.cs new file mode 100644 index 00000000..4614ed7f --- /dev/null +++ b/Assets/SerializableDictionary/SerializableDictionary.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; +using UnityEngine; + +public abstract class SerializableDictionaryBase<TKey, TValue, TValueStorage> : Dictionary<TKey, TValue>, ISerializationCallbackReceiver +{ + [SerializeField] + TKey[] m_keys; + [SerializeField] + TValueStorage[] m_values; + + public SerializableDictionaryBase() + { + } + + public SerializableDictionaryBase(IDictionary<TKey, TValue> dict) : base(dict.Count) + { + foreach (var kvp in dict) + { + this[kvp.Key] = kvp.Value; + } + } + + protected SerializableDictionaryBase(SerializationInfo info, StreamingContext context) : base(info,context){} + + protected abstract void SetValue(TValueStorage[] storage, int i, TValue value); + protected abstract TValue GetValue(TValueStorage[] storage, int i); + + public void CopyFrom(IDictionary<TKey, TValue> dict) + { + this.Clear(); + foreach (var kvp in dict) + { + this[kvp.Key] = kvp.Value; + } + } + + public void OnAfterDeserialize() + { + if(m_keys != null && m_values != null && m_keys.Length == m_values.Length) + { + this.Clear(); + int n = m_keys.Length; + for(int i = 0; i < n; ++i) + { + this[m_keys[i]] = GetValue(m_values, i); + } + + m_keys = null; + m_values = null; + } + + } + + public void OnBeforeSerialize() + { + int n = this.Count; + m_keys = new TKey[n]; + m_values = new TValueStorage[n]; + + int i = 0; + foreach(var kvp in this) + { + m_keys[i] = kvp.Key; + SetValue(m_values, i, kvp.Value); + ++i; + } + } +} + +public class SerializableDictionary<TKey, TValue> : SerializableDictionaryBase<TKey, TValue, TValue> +{ + public SerializableDictionary() + { + } + + public SerializableDictionary(IDictionary<TKey, TValue> dict) : base(dict) + { + } + + protected SerializableDictionary(SerializationInfo info, StreamingContext context) : base(info,context){} + + protected override TValue GetValue(TValue[] storage, int i) + { + return storage[i]; + } + + protected override void SetValue(TValue[] storage, int i, TValue value) + { + storage[i] = value; + } +} + +public static class SerializableDictionary +{ + public class Storage<T> + { + public T data; + } +} + +public class SerializableDictionary<TKey, TValue, TValueStorage> : SerializableDictionaryBase<TKey, TValue, TValueStorage> where TValueStorage : SerializableDictionary.Storage<TValue>, new() +{ + public SerializableDictionary() + { + } + + public SerializableDictionary(IDictionary<TKey, TValue> dict) : base(dict) + { + } + + protected SerializableDictionary(SerializationInfo info, StreamingContext context) : base(info,context){} + + protected override TValue GetValue(TValueStorage[] storage, int i) + { + return storage[i].data; + } + + protected override void SetValue(TValueStorage[] storage, int i, TValue value) + { + storage[i] = new TValueStorage(); + storage[i].data = value; + } +} diff --git a/Assets/SerializableDictionary/SerializableDictionary.cs.meta b/Assets/SerializableDictionary/SerializableDictionary.cs.meta new file mode 100644 index 00000000..cdf58f09 --- /dev/null +++ b/Assets/SerializableDictionary/SerializableDictionary.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e7be1c9624387604fba4005ccf7dbd5a +timeCreated: 1492868176 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/SerializableDictionary/SerializableDictionary.pdf b/Assets/SerializableDictionary/SerializableDictionary.pdf Binary files differnew file mode 100644 index 00000000..cad88c37 --- /dev/null +++ b/Assets/SerializableDictionary/SerializableDictionary.pdf diff --git a/Assets/SerializableDictionary/SerializableDictionary.pdf.meta b/Assets/SerializableDictionary/SerializableDictionary.pdf.meta new file mode 100644 index 00000000..4325a38f --- /dev/null +++ b/Assets/SerializableDictionary/SerializableDictionary.pdf.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8eb73a56b3a6ee64ab2c30cac8878d8f +timeCreated: 1492869030 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: |