Some data in scriptable objects doesn't persist when I restart Unity.

I have a Drawing class, which inherits from ScriptableObject, to store a List of Point objects. I want to be able to start the scene, draw a drawing and then save it inside a Drawing object. When playing the game, the drawing would be displayed and the players task would be to add something to the drawing.

Here is a part of my code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Environment
{
    [CreateAssetMenu]
    public class Drawing : ScriptableObject
    {
        public List<Point> points;
        public GameObject objectToDraw;
        public void DrawPoint(Vector3 position, Quaternion rotation)
        {
            points.Add(new Point(position, rotation));
        }

        public void Load()
        {
            foreach (Point point in points)
            {
                Transform drawnObject = Instantiate(objectToDraw).transform;
                drawnObject.position = point.position;
                drawnObject.rotation = point.rotation;
            }
        }

        public void Clear()
        {
            points.Clear();
        }
    }

    [System.Serializable]
    public class Point
    {
        public Vector3 position;
        public Quaternion rotation;
        public Point(Vector3 position, Quaternion rotation)
        {
            this.position = position;
            this.rotation = rotation;
        }
    }
}

All of the behaviour I described works fine, the Drawing persists restaring the scene. The only problem is that when I restart unity, the drawing.points List is empty - all the points are lost.

Is this the normal behaviour of ScriptableObject, which means they can only store references to assets but not Serializable class instances?

No, any serialisable data stored in scriptable objects should persist between editor sessions. I use scriptable objects to store all kinds of wacky nested data. Of course this is predicated on the data actually having been written to disk inside the scriptable object asset, of which is predicated on Unity knowing that data has changed.

You can always see what data has been written out in a scriptable object by opening it in a text editor like notepad++. If it hasn’t been written out, Unity doesn’t have knowledge that the data is changing (what is known as ‘dirtying’ the object).

Though by most accounts, modifying the data of a scriptable object during play mode should be making Unity aware of this. I say by most accounts because I have encountered the odd time when it doesn’t, a behaviour that happens seldom enough I haven’t really pinpointed why.

The easy work around for when this annoying behaviour happens is to manually dirty the object. So for example in your DrawPoint method you could alter it like so:

public void DrawPoint(Vector3 position, Quaternion rotation)
{
    points.Add(new Point(position, rotation));
   
#if UNITY_EDITOR
    UnityEditor.EditorUtility.SetDirty(this);
#endif
}

Of course it’s always better when you don’t have to do this.

2 Likes

Thank you so much, you saved me from having to manually write it in a file and the deserializing it again!