can i save a unity scene during runtime?

so i know that unity stores all the information for a level in a .unity file, which seems to be kind of like a json-ish custom format. it seems like the scene file that is saved in the assets folder only reflects the state of the level before you press play, presumably the state of the level is loaded to and from this file into the actual scene while you edit it.

my question is, is there a way to manually save a .unity scene file during runtime? that is, can i save the state of a level while the game is being played?

say i have a game with lots of different levels, and one persistent player object that is loaded into them when they are opened (or for convenience sake say i’m storing persistent data in some donotdestroy object). i want each level to save it’s state whenever you leave it, so that when you reenter it the changes you’ve made can persist. i also want to be able to save the state of all levels, and the player itself, whenever you exit the game.

i know that you can use playerprefs to save individual values, and you can do things like making save files that you load individual values into. i would like to take advantage of unity’s built in level saving instead, even though it will take up more memory and be less performant. what’s the best way to save the at-runtime state of a level into the assets folder as a .unity scene file?

If you’re trying to do this in a live game (not in editor) then I’m pretty sure it’s not possible, thus the reason for save files. Creating scene files in editor is different because you have access to editor scripts which don’t exist in a build. Plus, depending on what platform you build for, you can’t necessarily save to the assets folder as it might not exist (Android comes to mind).

No.

It’s not a custom format, the format is called “yaml” (stands for 'yet another markup language):
https://en.wikipedia.org/wiki/YAML

During runtime, as opposed to editor time while playing? Umm technically yes you can… technically… very very technically.

Is it trivial? Oh heck no! You’d have to write your own custom code to write all the yaml and have a table to lookup all the guids for assets so it’d be useable back in the editor.

Oh… and that’s the other thing. If you output a *.unity scene it wouldn’t be useable in your game at runtime since unity doesn’t really use the *.unity file at runtime. Instead when you compile the game all of your scenes are converted to a different binary format for faster processing at runtime (and smaller storage footprint presumably).

It’d basically be a lot of work for nothing since the resulting *.unity file would still need the Unity Editor to open.

That is unless you also wrote a deserializer for your game as well as the serializer.

So effectively it’s a “no” in that there’s really no good reason to do it (unless you were trying to write some weird modding system).

Yeah, attempting to generate a *.unity file is not how you’d want to do this.

So PlayerPrefs, while some people do use them as a place to “save the game”… it’s really intended for, as the name implies, “player preferences”. For example the chosen resolution, fullscreen/not, volume, quality, etc. This way when the player returns to the game their settings are the same.

The location of playerprefs on windows could give you a clue as to why you might not want to store huge amounts of data there is the fact that in Windows it’s located in the Registry. You really shouldn’t be polluting the registry with massive amounts of data.

…

As for what to do.

Well… you’re going to create a save file. Pick a format you like… could be something like json, or yaml, or xml, or your own custom format.

Next you’re going to want to segregate the data that can change from the data that can’t change. No reason is bloating up a save file with data that isn’t necessary. If they can’t change the ground… why save the ground?

Next you’ll need to decide if you’re going to support only modifying an existing map versus allowing new objects to appear in the map. If new objects can appear you’ll need a way to lookup the objects that can be placed in the world.

We recently did this in a cozy game we called ‘Humaniquarium’ where you get a bonsai planter you could fill with little trinkets. All the trinkets/props were put in an Addressables catalog for 2 reasons because it comes built in with the tools necessary to associate ids (I personally use guids) to with the asset and load only the ones that are necessary at runtime as well as facilitate downloadable expansion packs.

And now you just write some code that cycles through all the objects in the scene that are dynamic and stores the necessary info: transform, computed instance id (not the same as the unity GetInstanceId), the resource id, any asset specific data such as state.

…

Note… none of this is trivial.

But it’s less difficult than attempting to generate a *.unity file at runtime.

I don’t know your exact skill level (I’m suspecting more novice since you don’t know what yaml is), but I’d argue this is definitely in the “expert” territory of things. For simple games you could probably get away with an amateur level design with tight limitations on how effective it is. But it’s definitely not novice.

3 Likes

okay thanks, this is definitely what i was trying to avoid doing haha. i really was hoping to not have to manually enumerate everything that needs to be saved, i might have to rethink how this game is going to be structured if i can’t save the state of a scene

Load/Save steps:

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

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. 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.

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.

2 Likes