ScriptableObject asset problem! The changes won't saved to disk!

I create an instance of ScriptableObject onto my disk as an .asset file.

Then I planned to use that file at runtime so I create a public variable in one of my component as that ScriptableObject type so the slot would show up in the inspector. I then drag my .asset file to that slot and I can use its value as soon as I enter play mode and I see changes immediately applied to my .asset file by clicking on the file in my asset tree and I see the Inspector showing the changed value that my script changes.

However, the actual data on disk haven’t change yet! I tried opening that file on my disk (I use ā€˜Force Text’ serialization so I can read it) and the value in that file is not like in the inspector! I can enter play mode and exit as many time as I wanted and the value is saved across plays but never to my file in disk. The real problem starts when I closed unity and open again, the value has gone because it was never saved to disk.

If I push Ctrl+D to duplicate the file, the Inspector of new file will show the value on disk of original file, not the updated ones in the inspector. Supporting the evidence that the value on disk is not getting updated.

BUT one way that I got it to finally update is, I changed one of the field that show up in .asset inspector by hand in editor mode. Then the moment I close Unity the file will be updated! I wondered why when I used the script to change values (adding Note objects to the list, as seen below) the file refuse to update when I close unity and simply discarding changes? (Of course the ideal solution is I want it to save immediately, not when closing unity.)

Can someone help me so I can update changes to disk?

Here is my class hierarchy. I got it to save when closing Unity by, for example, changing the ā€˜bpm’ number to something else in the .asset file inspector and close Unity.

public class Simfile : ScriptableObject {

	public string songName;
	public string artist;
	public string noteCharter;
	public AudioClip musicFile;
	public int bpm;
	public float offset;
	
	[SerializeField] Chart easyChart;
	[SerializeField] Chart normalChart;
	[SerializeField] Chart expertChart;
.
.
.

[System.Serializable]
public class Chart
{

	Note focusedNote = null;

	[SerializeField] int laneCount;
	[SerializeField] int noteCount;
	[SerializeField] public List<Note> notes;
.
.
.

[System.Serializable]
public class Note {
	[SerializeField] float position;
	[SerializeField] float absolutePosition;
	[SerializeField] int specialNote;
	[SerializeField] int lane;
	[SerializeField] float nextLinkAbsolutePosition;
	[SerializeField] int nextLinkLane;
	[SerializeField] float prevLinkAbsolutePosition;
	[SerializeField] int prevLinkLane;
.
.
.

Thank you

If you want to save that asset you have to call AssetDatabase.Refresh(); first, then you have to mark the object that you load from the .asset file as dirty EditorUtility.SetDirty(object loaded from .asset file); and then call AssetDatabase.SaveAssets(); :slight_smile:

17 Likes

Great answer @albal , this worked for me.

I’m struggling with this issue for days and still can’t figure out how to do it.
I tried putting the code in Awake() for each SO. This has a nasty effect: if there are 10 SO’s it asks to save 100 times!! Oh, and upon restarting Unity the assets are empty, not of ScriptableObject type - as if no code was written at all.
So where to put this code?

Very helpful. Thanks!!!

I think just setting it dirty is enough ( worked for me )

2 Likes

Wait, WHERE do you save this? How do you detect changes? Is there like an OnValueChanged() or something?

Oh this baffled me for days. All I needed was SetDirty.
MrLucid, you would do this in the same script that is updating your SO’s. If you’re changing an SO field value ā€œby handā€ in the editor, it’s not an issue, your changes will persist, unless you’re in play mode, in which case… well stop playing and then change the value.

SetDirty is not longer an option, and I can’t try this fix.

How is SetDirty no longer an option?

I’m on Unity 2019.4, and SetDirty() has been deprecated from the ScriptableObject API. We might be able to use EditorUtility.SetDirty(someObject) instead.

1 Like

Ah, I thought you were talking about EditorUtility.SetDirty. I had forgotten about the existence of the version on ScriptableObject. Yes, you want to use EditorUtility.SetDirty in these instances.

1 Like

IT Only work for unity editor not in mobile device