How to handle saving and restoring of runtime objects

Hello,
i am building a simple saving system. So far it is possible to save the state of objects that exists at “Editor Time” and restore their state after scene load. But im having trouble to handle gameobjects that are spawned or destroyed during runtime.
There are basically 3 possible types of those objects that i need to consider.

  1. Objects that exists at edit time but were destroyed during runtime. These must be again destroyed after the scene finishes loading.
  2. Objects that are spawned during runtime…
  3. … and eventually get destroyed.

Those have to be instantiated again if the objects did not got destroyed before saving occured.
Those cannot be tracked by my current system because they either do not exist at scene loading (they were instantiated at runtime) or they do possibly not exist during saving (because they were destroyed) and therefore cannot be found.

I tried to extend my current system by a manager that tries to track the destroyed / instantiated gameobjects at runtime. The manager itself manages data of objects that have to be destroyed / instantiated and is saved to disk pretty much like all the other objects are saved. My problem is that I dont know how to poperly store data that can be used in order to Instantiate(gameobject) after scene load.
My first approach was to store a copy of the gameobject so that i can Instantiate it after the scene loads. This seems not to be possible because GameObject is not System.Serializable.
My next approach was to store the asset path of the prefab asset this object was created from. But I just cannot figure out how to use this approach to restore the objects. I tried using AssetDatabase.LoadAssetAtPath() but this only works in editor. I did not try Resources.Load() because many people say Resources API should be avoided.

Maybe I should completely change how runtime objects are handled by the saving system? Maybe move the responsibility to the destroyer / spawner of the runtime objects?

There’s a bazillion different ways to engineer this as well as a bazillion ways to shortcut what you actually have to save, to simplify the problem. Have you worked through any of the myriad savegame tutorials already out there on Youtube? Not all of them will do all of what you want, but I imagine there’s some interesting discussions to be had.

1 Like

You seem to be trying to break this down into “scene objects” vs “instantiated object” but it might be easier if you look at them as the same thing.

I’d give each object that you want to save/load some sort of identifier on a script e.g. a “Saveable” component, this component could contain the prefab name which can be used for Instantiating when loading.

I’m assuming you’ve got some sort of system already in place to record positions, rotations and other properties.

When you load your scene, if you want to load from the save file, destroy all of the existing scene objects with a “Saveable” component.

Now load up all of your objects from your save file and instantiate them in the scene at the correct position/rotation and assign their specific properties.

When saving, save all of the “Saveable” objects in the scene.

Anything destroyed at runtime would not be saved to the file, so it would not be instantiated when reloading the scene.

I don’t see anything wrong with using Resources.Load for this purpose.

3 Likes

Well to be honest I did not searched too long for tutorials on youtube. But the few I found were pretty basic saving of some values, used 3rd party assets or did not covered what I need. As mentioned i can already save objects or to be more precise arbitrary structs that i can define in monobehaviour scripts attached to gameobjects and track the changes made / restore them. The problem is (or, as of now, partialy were) objects that get destroyed or instantiated during runtime. Which my “base” saving system cannot track by itself because it just takes a snapshot of objects that have a saveable script attached to when saving and right after scene loading for restoring.
Moreover i struggled with how to properly get a reference or the prefab itself serialized in order to respawn the objects later. This problem also occurs in my inventory which uses scriptabe objects that contain a reference to a gameobject and other unity objects that are not system.serializable.
However for the inventory i solved this using a scriptable object acting as a database. I added a simple integer id to my items. This id is then saved and when restoring the inventory is looking into the database using this id to get a scriptable object back. I think I will use a similar approach for gameobjects to instiate them.

@Serinx
Im distinguishing between objects that do get instantiated / destroyed during runtime because they behave a bit different. For example they have to get a unique ID during instantiation, sometimes it is better to also store the parent if the scripts are dependant on hierarchy structure, therefore the parent has to be tracked by the system as well but it might not be a “saveable” by definition. I think it is possible to put everything into 1 saveable class instead of what I am thinking of 3 different classes (uniqueIdentifiable as base class, and saveable / runtime saveable as derived), so i might refactor that part.

That was my first idea to store the path and use it later to restore from assets. As i said did not try using resources API was ready about adressable assets the other day and though of using that but ended up using the database / id approach like described for the inventory.

I think this would cause some problems if im going to destroy every saveable. Take for example a drawer. If there are objects parented just to move relative to its position when animated, etc. Then those will be lost.

Hi Neran28, if found out an effective solution to do so, can you please share that?