Unity has supported polymorphic serialization since 2019. Fields serialized with [SerializeReference] will serialize with polymorphism, and will work when serialized with JsonUtility as well.
Example, using Odin Inspector for drawer support and buttons:
public class TestUnitySerializationComponent : MonoBehaviour
{
#region Inspector Fields
[SerializeReference]
private BaseClass _baseClass;
#endregion
#region Unity Callbacks
[Button("Json Utility", ButtonSizes.Medium)]
public void SerializeWithJsonUtility()
{
var json = JsonUtility.ToJson(_baseClass, true);
string path = GetFilePath();
File.WriteAllText(path, json);
}
private static string GetFilePath()
{
return Application.persistentDataPath + "/Test.txt";
}
#endregion
#region Nested Types
public abstract class BaseClass
{
public int SomeInt;
[SerializeReference]
private NestedBaseClass _nestedClass;
public class NestedBaseClass
{
public int NestedInt;
}
}
public class DerivedClass : BaseClass
{
public float SomeFloat;
public class DerivedNestedClass : NestedBaseClass
{
public float NestedFloat;
}
}
#endregion
}
The Newtonsoft.Json package also supports polymorphism with the correct context settings. Not sure about Unity’s new serialization package. Then other serialization packages like the Odin Serializer support by-reference serialization by default, so no extra work is required.
omg… can’t believe it was that easy. I guess there was so much old info out there I kept going down bad rabbit holes.
Thx spiney199, i’ma go get drunk now.
EDIT: for other people who want to do this then here is some code. no packages required.
[Serializable]
public class Object {
public int ID;
}
[Serializable]
public class Child : Object {
public int ID;
public string name;
}
[Serializable]
public class Savefile {
[SerializeReference] public List<Object> savables;
}
public class Manager
{
public Savefile savefile;
public void Save() {
string folder = Application.streamingAssetsPath + "/Savefile/";
File.WriteAllText(folder + "savefile.json", JsonUtility.ToJson(savefile));
}
public void Load() {
string folder = Application.streamingAssetsPath + "/Savefile/";
savefile = JsonUtility.FromJson<Savefile>(File.ReadAllText(folder + "/savefile.json"));
}
}
Uh, the list of Object needs to be decorated with [SerializeReference] not [SerializeField], otherwise you won’t get the by-reference serialization. That was kind of the single most important part of my post.