Save/Load gameobjects with references to prefabs/Scriptable objects

I need to save a gameobject and load it later. The gameobject can have references to prefabs and scriptableobjects. The solution i need has to work in editor and in build!
Right now i am maintaining a database with key (string, prefab/so reference), so i save the name of a prefab/so as string and at loading i use the database to get the reference. But i don’t like this solution since it requires to maintain the database.
I am wondering if there are better and cleaner solution for this.
Any recommendation welcome :slight_smile:

Ultimately your only option is to create some kind of indirect reference via an ID or something else with which to restore the reference later.

There’s currently no built in way to save a reference to any UnityEngine.Object and load it later.

How about adressables?

Only an option if you pre-cache an asset’s guid, as that can’t be retrieved at runtime.

The cleanest solution is always to save the barest minimum of information necessary to recreate the state of the game, or specifically the parts you care about.

Alternately you can get save helper products off the Unity Asset Store to help you do more stuff.

As far as referring to extant assets, I always use the actual Resources.Load<T>(); name of the object so I can get it back easily.

Keep in mind that anything you don’t fully save needs to handle changes to the referenced item. For instance, if you’re a wizard and pick up a sword and save that game, the savegame might say “you get a sword and you’re a wizard.” Later on if you change your game so that wizards cannot wield swords, consider how you will load older savegames.

Anyway, there just isn’t one solution, but I always feel the happiest with things that save the least amount of data necessary to restore.

Load/Save steps:

An excellent discussion of loading/saving in Unity3D by Xarbrough:

And another excellent set of notes and considerations by karliss_coldwild:

Loading/Saving ScriptableObjects by a proxy identifier such as name:

When loading, you can never re-create a MonoBehaviour or ScriptableObject instance directly from JSON. Save data needs to be all entirely plain C# data with no Unity objects in it.

The reason is they are hybrid C# and native engine objects, and when the JSON package calls new to make one, it cannot make the native engine portion of the object, so you end up with a defective “dead” Unity object.

Instead you must first create the MonoBehaviour using AddComponent() on a GameObject instance, or use ScriptableObject.CreateInstance() to make your SO, then use the appropriate JSON “populate object” call to fill in its public fields.

If you want to use PlayerPrefs to save your game, it’s always better to use a JSON-based wrapper such as this one I forked from a fellow named Brett M Johnson on github:

Do not use the binary formatter/serializer: it is insecure, it cannot be made secure, and it makes debugging very difficult, plus it actually will NOT prevent people from modifying your save data on their computers.

A good summary / survey of the problem space:

This isn’t about your question on saving references, what everyone said above is correct, but about a common issue with saved data that you should keep in mind, similar to Kurt’s wizard example

Handling old save files is important. Always include a save system version in your save data.

For example, say version 1 stores the player’s level. Later, you switch to version 2, which stores experience instead. You write a script to convert old saves. Then you update again to version 3 and need another conversion. But now you can’t tell what a saved number means because you don’t know which version created it.

By saving the version number, you’ll always know which conversion script to run and avoid breaking old saves.