Last active
December 13, 2024 16:05
-
-
Save a-gruzdev/3edded527e4572318bcba7cb46d08528 to your computer and use it in GitHub Desktop.
Fixed length array associated with any enum and with handy 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; | |
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) * (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 |
Thank you! I took the validation part
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for sharing, I forked this to add validation for the Enum type used and changed the inspector drawer to a foldout since it can take up a lot of space.