using System; using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif [Serializable] public class EnumArray : 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; public static readonly System.Collections.Generic.Dictionary 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) * (property.arraySize + 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; position.width -= Padding * 2; GUI.Label(position, label, EditorStyles.boldLabel); 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