I am trying to serialize the SmartEnum class provided by ardalis at his repo GitHub - ardalis/SmartEnum: A base class for quickly and easily creating strongly typed enum replacements in C#. in Unity.
What I am trying to achieve: Similar functionality to the c# enum where the serialized value has a property drawer with a drop down of available options. When de-serialized the reference of the object needs to be reassigned to the correct value.
The syntax for defining a SmartEnum is as follows:
using Ardalis.SmartEnum;
public sealed class TestEnum : SmartEnum<TestEnum>
{
public static readonly TestEnum One = new TestEnum(nameof(One), 1);
public static readonly TestEnum Two = new TestEnum(nameof(Two), 2);
public static readonly TestEnum Three = new TestEnum(nameof(Three), 3);
private TestEnum(string name, int value) : base(name, value)
{
}
}
You would then define an enum field as such:
TestEnum myTestEnum = TestEnum.One;
In order to achieve this I have created a new class that extends SmartEnum and implements ISerializationCallbackReceiver.
I have gotten quite far but have been struggling with the deserialization. So before I give up entirely I’m wondering if its even possible since you can’t normally serialize static fields. I am using reflection to get a list of the name values of all of the SmartEnums declared statically then serializing a string which is what the property drawer modifies. On deserialization I try to update the original ref and ideally swap it to the memory location of a different statically declared instance. This is where it all falls flat as I cannot access/change the reference that was originally assigned to with TestEnum myTestEnum = TestEnum.One;.
Here is what I have so far
public class UnitySmartEnum<T> : SmartEnum<T>, ISerializationCallbackReceiver where T : SmartEnum<T,int>
{
public UnitySmartEnum(string name,int value) : base(name,value) { }
//Custom serialization
[SerializeField]
List<string> options;
[SerializeField]
string value;
public void OnBeforeSerialize()
{
value = Name;
options = GetType()
.GetFields(BindingFlags.Public | BindingFlags.Static)
.Where(f => f.FieldType == typeof(T))
.Select(fieldInfo => fieldInfo.GetValue(null))
.Cast<UnitySmartEnum<T>>()
.Select(e => e.Name)
.ToList();
}
public void OnAfterDeserialize()
{
var listOptions = GetType()
.GetFields(BindingFlags.Public | BindingFlags.Static)
.Where(f => f.FieldType == typeof(T))
.Select(fieldInfo => fieldInfo.GetValue(null))
.Cast<UnitySmartEnum<T>>();
var tryGetSelectedValue = listOptions.Where(option => option.Name == value).FirstOrDefault();
//reassignment is where it all goes wrong since the original instance is static and readonly, I want to change the instance that the reference points to I left this here even though it doesn't work so you can see my last ditch attempts to make it work
if (tryGetSelectedValue != null)
{
var me = this;
Reassign(ref me,ref tryGetSelectedValue);
}
else
{
var me = this;
tryGetSelectedValue = listOptions.FirstOrDefault();
Reassign(ref me,ref tryGetSelectedValue);
}
}
public static void Reassign(ref UnitySmartEnum<T> a, ref UnitySmartEnum<T> b)
{
a = b;
}
}
[CustomPropertyDrawer(typeof(RPGEvents))]
public class EnumPropertyDrawer : PropertyDrawer
{
List<string> options = new List<string>();
int selectedIndex = 0;
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
SerializedProperty enumNames = property.FindPropertyRelative("options");
SerializedProperty name = property.FindPropertyRelative("value");
int i = 0;
options.Clear();
foreach (SerializedProperty item in enumNames)
{
options.Add(item.stringValue);
if (item.stringValue == name.stringValue)
{
selectedIndex = i;
}
i++;
}
var container = new VisualElement();
var nameField = new DropdownField("Enum Value",options,selectedIndex);
nameField.RegisterValueChangedCallback((e) =>
{
name.stringValue = e.newValue;
property.serializedObject.ApplyModifiedProperties();
});
container.Add(nameField);
return container;
}
}
I’ve never worked with Unity’s serialization or property drawers before so there might be obvious mistakes.