Saving several variables in several scriptable objects?

I thought scriptable objects were the greatest thing ever invented in unity until I learned they can’t be saved/serialized. All of the tutorials I’m finding on saving scriptable objects are inputting the values and such within a class for that object that can be serialized, but doesn’t that defeat the purpose of a scriptable object if I have to make a new class for every single object with data I want to save? And going forward in the future, are scriptable objects useless if I want them to contain any information at all that’s meant to change?

Scriptable objects are very commonly misused. Some people use them as a bridge between MonoBehaviours but the intended use case for them was just storing immutable data that you can reference in the Inspector.

So is it correct that they are intended to store only immutable data and should not be used to store any variables that change?

Yes, at least not without knowing exactly what you’re getting yourself into. I know there’s a video floating around that shows them storing mutable data but that video is very incomplete and only shows part of the actual system to make it work properly. So it’s best to just not do it.

1 Like

The contents of a ScriptableObject will never be saved to the user’s disk by Unity.

However, you’re free to make changes to stuff you have inside the ScriptableObject instance during the course of executing the game, and then saving that data yourself using some other means. For example, your “GameplayData” ScriptableObject may have a Serializable structure called “GameplayState” in it. On startup, it will always have the data you provided at build time, which is very reassuring, but you can surely make a copy of the GameplayState that you can then modify and save elsewhere in your game.

Actually saving and loading data in JSON is really a very short learning exercise. It’s not complicated. You take a string of data from a file, and use the JSON tools to convert it into a C# data structure. Or vice versa. Deciding when and how often to save is really a bigger question, once you have the core mechanism down.

To the contrary. Set up correctly, an SO provides BOTH immutable and serializable data.

Just make a struct or class, let’s call it “MyData”. Mark it [Serializable] and add it to an SO as a field. Create an SO asset to edit the immutable values of MyData in the editor.

At runtime, you can save and load an instance of MyData with any means, commonly Json. Ideally MyData is engineered to contain only types compatible with JsonUtility. This is about the only challenge but usually easy to overcome - beginners would tend to “save” a reference to a component but an experienced developer would instead save only the component data (same way as described here using a separate data container class/struct).

Upon game launch and if no save file exists, the runtime will simply use the MyData that was embedded in the project as immutable data. This data is changed at runtime and saved at an appropriate time.

Next time the game launches the save file exists, thus the existing instance of MyData with the immutable values is replaced with the one that was loaded using the values from the last save.

This sort of system will work with both editor and runtime. For a developer editing the immutable values and wanting them to take effect over what’s saved, the dev needs to delete the save file before entering playmode.

The SO is providing a reference to the serializable data in your example. Like they mentioned in their initial post they had already noticed everyone doing that. On a somewhat related note you could create a source generator automating the creation of the POCO.