Prevent Custom ScriptableObject Asset persisting changes after exiting play mode

Problem
I have a problem whereby changes that are made to a custom asset (composed of ScriptableObhects) in play mode remain in the editor after I exit play mode.
The asset properties will only reset to their original, pre-play, values after a restart of unity.

More information:
I have created a custom graph asset to create quests for an RPG game.
The graph, its nodes and the quest objects are implemented as ScriptableObjects.
Each graph and its constituent nodes and quests are then stored as an asset in the project.

To use the graph I attach it to an actor in the scene. When the player interacts with the actor a quest is updated. This is visible in the inspector for that quest. Unfortunately, when I exit play mode, the updates made during play remain in the editor.

If I exit Unity and restart then the quest will revert to its original value.

The behaviour I expect is that changes I make in play mode are automatically reset once I exit. Are there manual steps that must betaken on ScrtiptableObjects or even property drawers that can restore this behaviour?

Many thanks in advance for any help.

Instantiate the asset so you’re working with a runtime copy instead of the original.

2 Likes

Cheers!

Turns out the situation is made a little more complicated as the object I need to clone is a graph whose nodes are also ScriptableObjects and Instantiate only creates a shallow clone in this case.

I am able to get around this by creating a clone method on the graph which will manually traverse all nodes and create instances of all the constituent nodes.

Many thanks for the response, this has helped me greatly.

Happy to help!

Wow, I’m having the exact opposite issue. I want the data within my ScriptableObjects to stay persistent as I’m entering and exiting play-mode, but when I exit play-mode, their data reverts back what they had just before I entered play-mode.

Is it a ScriptableObject in memory or a ScriptableObject asset (file in project)? What version of Unity are you using? Have you disabled domain reloading? If it’s an asset, are you sure you’re changing the asset and not an in-memory instance?

It’s an in-memory ScriptableObject that we’re filling it out based on a json file instead of built in serialization. We want to be able to make it as easy as possible for the User to edit it by hand, and we don’t want it to be affected by changes in the Unity Version. So, it’s not part of the AssetDatabase.

I’m on Unity 2019.4.

And, I haven’t looked into domain reloading yet, but I get the feeling that it might mess with the current project because we’re automating something that enters and exits play mode multiple times and we’re counting on most items getting reset when we exit play mode.

I am starting to think that the reason why it gets reset is because it’s an in-memory only ScriptableObject that isn’t saved in the AssetDatabase. The amount of data we need to pull back is small enough that I have one more thing to try before I start writing code that will insert copy of the ScriptableObject into the AssetDatabase.

You’re right. It’s in memory, so it’s not retained when you leave play mode. With ScriptableObject asset files, it’s more the fact that it’s an asset file than being a ScriptableObject that makes it persist through play mode changes. There’s nothing particularly magical about ScriptableObjects. They’re essentially just regular objects that Unity can serialize. (A few little things Unity does, but that’s the gist.)

If it’s small enough, what about deserializing it from JSON at runtime? You don’t even need a ScriptableObject for that.

Well, there sort of is… even if you mark a field as private in a ScriptableObject,

private bool Initialized;

As long as you remain in the editor, that value will persist between play / stop cycles of the editor.

This is VERY counter-intuitive for most people, and can cause all kinds of weird bugs.

To get around this, always flag stuff you do NOT want serialized with NonSerializedAttribute.

In the end, I just used the EditorPrefs to assign an int to keep track of my progress. My old design had quite a few items that could be changed during runtime, but when my client said that they only wanted a way to select a file to run, well, it really cut down on the amount of items that needed to be kept track of. So, now, I prime the value to zero before entering Play Mode for the first time (during said run), at the start of a pass, I grab the value from the EditorPrefs. At the end of a run, I update the value in the EditorPrefs to the index of the next pass. While outside of play mode, I check the index to see if there are any more passes to run or if I should just delete the GameObject that’s been executing the automation code.