We are all used to Unity idioms of displaying values from our scripts in the inspector. This is one of those great things about Unity - we don't have to fiddle with .init
files, we can apply values to a prefab and have them automatically applied to all instances unless the instances have overridden it etc. We learned all these workflows intuitively, but at some point it's important to realize this intuitive understanding may not be perfect.
Today's lesson focuses on enums. Let's say you have a script with the following contents:
using UnityEngine;
public class EnumsSerialization : MonoBehaviour {
public enum PossibleValues {
Value0, Value1, Value2
}
public PossibleValues myValue;
void Start() {
if(myValue == PossibleValues.Value1) Debug.Log("OK");
else Debug.Log("Failed!");
}
}
Simply, we have an enum inside our class, we declare a public field of that type and do some work on startup based on the assigned value. Let's drag that script to an empty object and create a prefab from it. We will assume the different prefabs in our project will have different values assigned to this variable, and the work they do on startup will differ based on this value. Let's set the value to Value1 on the prefab itself and run the scene. We are expecting an OK
message and we get it.
So far so good. However, what happens if we or a team member want to add another enum value at the end? We simply add it and it will continue to work.
What if we want to add an enum value in the middle of these existing values? Let's say that we wanted to make the code more sensible, and we wanted the new option to appear at the beginning of the list of values. The code will look like this:
public enum PossibleValues {
Default, Value0, Value1, Value2
}
Seems innocent enough. However, all the values on our prefabs using this script have now been changed, and will show a different value - a value moved for one to the right. If we run the scene now without any changes to the prefab, we will observe the Failed
message, and all we did was add some code. Worse, there is no indication that something like this may happen because we don't intuitively expect it.
So, why did this happen and how to solve it?
This happens because enums are serialized as ints, each enum as a corresponding int value, by default starting from zero. When the assembly reload happens (here recompilation after we have changed our code) the value of PossibleValues.Default
got the int value of 0, PossibleValues.Value0
got the value of 1 etc. as it would always in C# by default. The problem is our prefabs hold values saved on disk as ints, and not the meaningful values of enums. Our prefab had the value of 1 saved, which now corresponds to PossibleValues.Value0
and the meaning of that value is now changed.
This leads to a conclusion: when enums are added, all prefabs that have an int value same or greater than the int value of the added element will be affected. This also has a positive side effect: enums are safe to rename (e.g. using the Ctrl + R + R rename tool in Visual Studio).
There are ways to avoid getting into this situation with people on your team who are not aware of this, in part.
public enum PossibleValues {
Default = -1, Value0 = 0, Value1 = 1, Value2 = 2
}
By assigning values to our enums we prevent the insertion in the middle from taking the default values and causing these problems. We presume the coworkers on the project will conclude that inserting values in the middle corresponds to a new int and will assign it. Unfortunately, if they start creating new enums they may not know or remember to use this technique, and also it is one more thing to remember. For me, it is simply easier to remember not to put the new enum values in the middle.
This article has been written on Unity 5.5.
If you're finding this article helpful, consider our asset Dialogical on the Unity Asset store for your game dialogues.