-
-
Save mattdevv/a3275cbd3ada72530d432db79ade6d18 to your computer and use it in GitHub Desktop.
Fixed length array indexable by enum. Includes custom PropertyDrawer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using UnityEngine; | |
| #if UNITY_EDITOR | |
| using UnityEditor; | |
| #endif | |
| [Serializable] | |
| public class EnumArray<E, T> : ISerializationCallbackReceiver where E : Enum | |
| { | |
| public static readonly int s_Length; | |
| [SerializeField] private T[] _values; | |
| public int Length => s_Length; | |
| static EnumArray() | |
| { | |
| var names = Enum.GetNames(typeof(E)); | |
| s_Length = names.Length; | |
| #if UNITY_EDITOR | |
| EnumArrayDrawer.Names[typeof(E)] = names; | |
| if (Enum.GetUnderlyingType(typeof(E)) != typeof(int)) | |
| Debug.LogWarning($"EnumArray should not be used with Enum type {typeof(E)} as it doesn't derive from int"); | |
| var values = Enum.GetValues(typeof(E)) as int[]; | |
| Array.Sort(values, (i0, i1) => i0 - i1); | |
| if (values[0] != 0) Debug.LogWarning($"EnumArray should not be used with Enum type {typeof(E)} as it doesn't start from 0"); | |
| for (int i = 1; i < values.Length; i++) | |
| { | |
| if (values[i] != values[i - 1] + 1) | |
| { | |
| Debug.LogWarning($"EnumArray should not be used with Enum type {typeof(E)} as it contains a gap in enums"); | |
| break; | |
| } | |
| } | |
| #endif | |
| } | |
| public EnumArray() | |
| { | |
| _values = new T[s_Length]; | |
| } | |
| public T this[E e] | |
| { | |
| get => _values[e.GetHashCode()]; | |
| set => _values[e.GetHashCode()] = value; | |
| } | |
| public T this[int i] | |
| { | |
| get => _values[i]; | |
| set => _values[i] = value; | |
| } | |
| public void OnAfterDeserialize() | |
| { | |
| if (_values.Length != s_Length) | |
| Array.Resize(ref _values, s_Length); | |
| } | |
| public void OnBeforeSerialize() { } | |
| } | |
| #if UNITY_EDITOR | |
| [CustomPropertyDrawer(typeof(EnumArray<,>))] | |
| public class EnumArrayDrawer : PropertyDrawer | |
| { | |
| private const float Padding = 4; | |
| private const float Spacing = 2; | |
| private bool open = false; | |
| public static readonly System.Collections.Generic.Dictionary<Type, string[]> Names = new(); | |
| private Type _type; | |
| public override float GetPropertyHeight(SerializedProperty property, GUIContent label) | |
| { | |
| if (_type == null) | |
| _type = fieldInfo.FieldType.GenericTypeArguments[0]; | |
| property.Next(true); | |
| return (EditorGUIUtility.singleLineHeight + Spacing) * ((open ? property.arraySize : 0) + 1) + Padding * 2; | |
| } | |
| public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) | |
| { | |
| if (Event.current.type == EventType.Repaint) | |
| EditorStyles.helpBox.Draw(position, false, false, false, false); | |
| position.height = EditorGUIUtility.singleLineHeight; | |
| position.y += Padding; | |
| position.x += Padding * 4; | |
| position.width -= Padding * 8; | |
| open = EditorGUI.Foldout(position, open, label, EditorStyles.foldout); | |
| position.x -= Padding * 2; | |
| position.width += Padding * 4; | |
| if (!open) | |
| return; | |
| property.Next(true); | |
| var step = EditorGUIUtility.singleLineHeight + Spacing; | |
| var labels = Names[_type]; | |
| for (int i = 0; i < property.arraySize; i++) | |
| { | |
| position.y += step; | |
| label.text = labels[i]; | |
| EditorGUI.PropertyField(position, property.GetArrayElementAtIndex(i), label); | |
| } | |
| } | |
| } | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment