Best practice for refactoring enum in ScriptableObject?

Hi all,
I find refactoring enum when it is used in ScriptableObject can be very annoying. Say I have a piece of code like this.

public enum NPCType
{
    Frog,
    Dog,
    Cat
};
public class NPC : ScriptableObject
{
    public NPCType npcTypes;
    public float speed;
}

If I add another animal between Dog and Cat,

public enum NPCType
{
    Frog,
    Dog,
    Mouse,
    Cat
};

All my pre-existed cat objects will turn into mouse. I know I can just append mouse after cat but I think there should be a better way to do this.

Any advice?

Cheers!

Enums are just serialized as a value iirc so you should be able to just specify those values. Try

public enum NPCType
{
    Frog = 0,
    Dog = 1,
    Mouse = 3,
    Cat = 2
}

Thanks! That worked!

Normally, you want to use compiler features of enum types to full potential

public enum NPCType {
  Frog = 0,
  Dog,
  Mouse,
  Cat, // you can also keep this comma so that you can reorder them freely in the future
}

This is contrary to what you wanted, but in general, you want to make your enum handling code order-insensitive.
If you depend on the exact values, this is not a smart choice, and you will likely run into trouble in the long run.

The point of an enum value is usually not to represent critical information such as order, but to opaquely enumerate sequential constants and make arbitrary magic indices appear as text.

If you really want to represent critical information, then do what WarmedxMints suggested, but when you really think about it, what’s the point of doing it in this case? The difference is only an illusion, and you’ll only fool yourself later.

public enum NPCType {
    Frog = 0,
    Dog = 1,
    Mouse = 3,
    Cat = 2
}

is the exact same thing as

public enum NPCType {
    Frog = 0,
    Dog,
    Cat,
    Mouse
}

The only difference (apart from the clutter) is that you’ve tricked your eyes into some false sense of order, which has no effect on your code whatsoever.

The way you use enum values as ‘critical’ data is to correlate this ordering with some other mechanism, maybe some kind of priority etc. I.e. if you reorder data in this enum above

public enum NPCType {
    Frog = 0, // this is only to make it more readable for your future self
    Mouse,
    Dog,
    Cat
}

Your code shouldn’t fall apart, but should instead treat Mouse as somehow more important than Cat IF the order should be relevant at all, and most likely it’s just an ID, the exact value of which shouldn’t matter during runtime, as long as 3 always maps to all things Cat, and 2 always maps to all things Dog etc.
So what you’re doing is a code smell.

1 Like

To put it short, the way you’re consuming enum is not a good practice in itself, because you’re defeating the purpose of an enum if you’re tying up your code with the values themselves, instead of consuming only the names. This way you’re working around the enum, and should probably use something else, like const or readonly values.

1 Like

I think using an enum this way makes sense when displayed with scriptable object.
In my case i have an “Animation” enum : Attack1,Attack2,InstantCast1,InstantCast2, etc…
Later in development i had to add “Attack3”, i did not want it to appear at the end of the list obviously.
So i decided to manually handle the value of each enum instead :

    public enum Animation {
        Attack1 = 0,
        Attack2 = 1,
        Attack3 = 4,
        InstantCast1 = 2,
        InstantCast2 = 3,
    }

That way the enum is still displayed sorted as i want in the scriptable object, and i just have to be carefull when adding a new one, which is not supposed to happend a lot and seems like a very little drawback to me.
Thanks for the insights anyway =)