Recently I learn about ScriptableObjects and I’m trying to implement a mechanism to survive domain reload during editor play session, when recompiling scripts.
So far, my main game controller was a MonoBehaviou which was initialized on entering play mode. Unfortunately, when the domain is reloaded due to script recompile, all the state in the game controller is lost and basically forces me to re-enter play mode.
My idea is to try to use ScriptableObject to prevent this. My game controller initialization consists of multiple steps to initialize systems and DI container. I imagine, after domain reload I need to re-initialize those systems. However, I think I could store my game state, basically the entities etc. in ScriptableObject state-container, reinitialize my systems, and continue my play session.
Is this feasible? So far I realized I need to have following constraints:
GameController cannot be an Asset - to prevent persisting it’s state within the asset file
Entity State cannot be an Asset - I should store game state only in memory
I have few additional questions:
How to reinitialize my systems after domain reload? I noticed Awake() and Start() are not being called, so it seems I cannot rely on them
How to obtain the reference to my game State after domain reload in MonoBehaviour if it’s only stored in memory?
I don’t think a ScriptableObject is needed in this case. I usually do my initialization in Update instead of in Start or Awake to prevent the initialization issue:
private bool initialized = false; // This will be reset to false after a script reload, because the variable is not serialized
private void Update()
{
if (!initialized)
{
// Initialize parts that are not serializable
initialized = true;
}
}
For the game state you could use a ScriptableObject, but you could also just make sure the game state is serializable.
Just because its an asset doesn’t mean you have to persist is states across Domain loads, you can use properties or manually flag fields in the Scriptable Object as [Nonserializable] and unity won’t save that data when the object is unloaded. Or leave them serializable (so that they are visible in the editor) but then inside OnEnable default out the fields. Of course the data technically does persist across domain loads but the moment its loaded its cleared.
What ScriptableObjects specifically bring to you is a polymorphic way to drag and drop custom classes in the editor, so that you can pre-link up references to classes. Said classes don’t necessarily have to persist their state through serialization.
ScriptableObjects use OnEnable and OnDisable calls. OnEnable is always called when the instance is loaded into memory and before anything can use that instance, and OnDisable is called when the object is unloaded (usually when a scene is unloaded and the asset is no longer being referenced, or when you manually unload it via the Resources class).
You’ll want to use serialization but it sounds like not Unity’s default Serialization. When your state is unloading you can serialize its data and save it in any format you prefer. then when you are loading the data again you can deserialize the data back into the class. you can write an interface that your classes use that manually converts the class’s internal state to and from a serializable object and then serialize said object however you see fit, be it JSONUtility, XML, binary, etc…
Unfortunately I’m using Start&Awake in tandem to have some initialization order enforced to my MonoBehaviours. If I move all the init code to Start I loose this possibility . But thanks for the suggestion!
I wanted to use ScriptableObject because they survive the domain unload by default, the data is stored in unmanaged backing object.
However, I learnt that the delegates are not persisted, so all in all it turns out it’s way more complex to survive editor domain unload, at least in my case.
Meh - don’t do a bunch of boolean checks every frame for the sake of surviving a recompile while in play mode. Or at the very least wrap that logic in a compiler directive so it only does it in the Editor
For those still stumbling onto this thread via Web searches, like me, check out the ISerializationCallbackReceiver interface. It’s another handy tool for getting information to survive Unity’s Domain Reload.