In the last post, I went over the inventory and item system, and mentioned that unity can’t actually serialize types.

However, we can create a class that will let us serialize types in a way that makes it easy to work with, but actually uses ints behind the scenes.

Since I am only using this for types that derive from Item, you will have to modify this a bit to work for your use case.

Implementation

[System.Serializable]
public class ItemTypeReference
{
    public static List<(Type type, string name, string fullName)> types = new();

    static ItemTypeReference()
    {
        types.Add((typeof(Item), typeof(Item).Name));
        // Get all subclasses of Item
        foreach (var type in Assembly.GetAssembly(typeof(Item)).GetTypes())
        {
            if (type.IsSubclassOf(typeof(Item)))
            {
                types.Add((type, type.Name));
            }
        }
    }
}

Here we create a static field on the type itself, which stores a List of tuples containing a type and a name that will be shown in the inspector. In the static constructor we populate this with all classes that inherit from Item using Assembly.GetTypes().

// class ItemTypeReference
public int index;
public ItemTypeReference(Type type)
{
    index = types.FindIndex(t => t.type == type);
}

The index field is what brings this all together and makes it work. Instead of trying to serialize a type directly which we can’t do, we serialize an index into the types array and we use that to get an actual type.

I’ve added in a constructor that takes a Type and automatically assigns index to the appropriate value. (I’m using Linq for conciseness)

However, opening the inspector and seeing an int field is of no use, so we need to add a custom property drawer.

#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(ItemTypeReference))]
public class ItemTypeReferenceDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        var prop = property.FindPropertyRelative("index");
        prop.intValue = EditorGUI.Popup(position, prop.intValue, ItemTypeReference.types.Select(t => t.name).ToArray());
    }
}
#endif

This gives us a simple popup which lets us select any of the types that derive from Item.

Popup

Finally, so that we don’t have to use ItemTypeReference.types[index].type everytime, let’s add a getter field systemType.

public Type systemType { get { return ItemTypeReference.types[index].type; } }

Now, if we have a ItemTypeReference, we can simply do ItemTypeReference.systemType to give us the actual type, that way we never have to deal with the int outside of the implementation.