Serialize a list of children of an abstract class in a scriptable object?

So let’s say I have the Building class, which inherits from ScriptableObject. I want to have a way to give an indefinite amount of ‘components’ to objects of the Building type. My approach is to have an abstract class BuildingComponent, which is the parent of all component types such as Employer if the building needs workers or Farm if the building grows food. (e.g. a basic farm that needs workers and grows food would have both of those components, but an automatic farm wouldn’t have the Employer component.)

Right now Building has a list of BuildingComponents, but I want to be able to populate that list when designing a scripted object of it.

I have it as follows:

[CreateAssetMenu]
public class Building : ScriptableObject
{
    [SerializeField]
    List<BuildingComponent> components;
}


[System.Serializable]
public abstract class BuildingComponent
{

}

[System.Serializable]
public class Mine_BuildingComp : BuildingComponent
{
    
}

When creating a Building asset, it’s just blank. It doesn’t show the list in the editor, despite being labeled with [SerializeField] and both BuildingComponent and Mine_BuildingComp being labeled [System.Serializable].

Use SerializeReference. Note that you have to Instantiate the objects yourself, possibly in a inspector UI. I made an example which does it hardcoded. If you want to get fancy about it, consider making your custom property drawer for the list which allow you to manage and instantiate components in that list.

A complete example (without a property drawer) with two subtypes:

using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu]
public class Building : ScriptableObject
{
    [SerializeField]
    [SerializeReference] // <- The missing magic
    List<BuildingComponent> components = new List<BuildingComponent>
    {
        new Mine_BuildingComp(),
        new Lumber_BuildingComp()
    };
}

[System.Serializable]
public abstract class BuildingComponent
{
    public int someID;
}

[System.Serializable]
public class Mine_BuildingComp : BuildingComponent
{
    public string mineName = "Some Mine";
}

[System.Serializable]
public class Lumber_BuildingComp : BuildingComponent
{
    public string lumberName = "Some Lumber";
}

200918-building-serialize.png