-
-
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 ref T this[E e] | |
{ | |
get => ref _values[e.GetHashCode()]; | |
} | |
public ref T this[int i] | |
{ | |
get => ref _values[i]; | |
} | |
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); | |
// header + top/bottom padding | |
float height = EditorGUIUtility.singleLineHeight + 2 * Padding; | |
if (open) | |
{ | |
int arraySize = property.arraySize; | |
// spacing between array elements | |
height += arraySize * Spacing; | |
// get each array element height | |
for (int i = 0; i < arraySize; i++) | |
height += EditorGUI.GetPropertyHeight(property.GetArrayElementAtIndex(i)); | |
} | |
return height; | |
} | |
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; | |
var style = new GUIStyle(EditorStyles.foldout); | |
style.fontStyle = FontStyle.Bold; | |
open = EditorGUI.Foldout(position, open, label, style); | |
if (!open) | |
return; | |
position.y += EditorGUIUtility.singleLineHeight + Spacing; | |
position.x += Padding * 2; | |
position.width -= Padding * 4; | |
property.Next(true); | |
var labels = Names[_type]; | |
for (int i = 0; i < property.arraySize; i++) | |
{ | |
var serializedElement = property.GetArrayElementAtIndex(i); | |
position.height = EditorGUI.GetPropertyHeight(serializedElement); | |
label.text = labels[i]; | |
GUI.Box(position, GUIContent.none); | |
EditorGUI.PropertyField(position, serializedElement, label, true); | |
position.y += position.height + Spacing; | |
} | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment