I don’t normally have to think about serialisation when using Unity, but recently – while working on a node-based graph tool, where the nodes do not inherit from MonoBehaviour – I ran into a situation with two specific (and conflicting) requirements that were causing issues:
- Need to serialise derived types referenced as base types
- Need to serialise Unity object (GameObject, MonoBehaviour) scene references
By default, Unity’s standard serialisation doesn’t handle inheritance particularly well. That means if you have a list of some BaseClass which contains various instances of a DerivedClass, Unity will only save and load the parts of the object that belong to BaseClass.
The one exception to this is if the BaseClass inherits from ScriptableObject. In that case serialisation of inherited types works as expected. However, ScriptableObjects are stored as assets which means they can’t hold references to objects in a scene.
The only method (that I’m aware of) for getting around these conflicting limitations is to use custom serialisation. Thankfully there’s a already a very robust solution available to do just that in the form of Full Serializer which is free and open source (MIT license).
You can find more information about Full Serializer on its GitHub page, including straightforward instructions for installation (basically just chuck the Source folder into your assets directory) and examples of how to use it in your own projects.
Unfortunately, Full Serializer doesn’t actually handle Unity scene references out of the box either. What it does do, however, is provide support for bespoke (de)serialisation of specific types using object converters and processors that you can write to fit your own needs.
I’ve written a converter for Unity objects which you can grab here. It’s pretty heavily commented, but the the basic idea is that Unity object references are actually serialised as integers representing indices into a list of objects that is owned by whoever is doing the (de)serialising.
This list is passed into Full Serializer via the Context field when (de)serialising. This approach is based on a description of a similar solution used in Full Inspector (another tool from the author of Full Serializer). Here’s an example of how it can be used:
In this example an instance of CustomClass is saved to and loaded from a Json string which is in turned serialised by Unity as part of its standard MonoBehaviour serialisation. But you could substitute this for any kind of serialisation method you like (binary, to a file, etc.)
With this solution, serialisation of Unity types is still handled by Unity itself, so you get all the benefits of the existing system while also being able to support specialisations for your own types without losing the power of scene and asset references in the process.