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