ScriptableObject does not save custom class data from custom inspector
Asked Answered
P

1

1

I’m having trouble getting a scriptable object to retain data. Currently it resets on each domain reload (every time I change some code in my project and every editor restart). I have tried all the usual things (below) but nothing seems to work.

The object being inspected:

public class GameTagTree : ScriptableObject
{
    [SerializeField] 
    GameTag root = new GameTag("root", "root", 0, null);

    // Has simple add function that adds a tag to the above root as a child
}

Gametag class - simplified:

[System.Serializable]
public class GameTag : IComparable<GameTag>
{
    [SerializeField] string fullName;
    [SerializeField] string partName;
    [SerializeField] int uid;
    [SerializeField] GameTag parent;
    [System.NonSerialized] List<GameTag> children;

    public GameTag(string partName, string fullName, int id, GameTag parent)
    {
        this.partName = partName;
        this.fullName = fullName;
        this.uid = id;
        this.parent = parent;
        children = new List<GameTag>();
    }
}

My current editor:

[CustomEditor(typeof(GameTagTree))]
public class GameTagTreeEditor : Editor
{   
    const string gameTagTreePath = "Assets/0 Main/Tags/GameTagTree.asset";
    string newTagName;
    GameTagTree tree;

    public override void OnInspectorGUI()
    {
        newTagName = "some.random.tag ";
        GameTagTree targetTree = (GameTagTree)target;

        if (GUILayout.Button("Add tag"))
        {
            targetTree.AddTag(newTagName);

            EditorUtility.SetDirty(targetTree);
            EditorUtility.SetDirty(target);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }

        List<GameTag> tags = new List<GameTag>();
        targetTree.GetRoot().GetChildrenRecursive(ref tags);

        for (int i = 0; i < tags.Count; i++)
        {
            EditorGUILayout.LabelField(tags[i].Uid + " - " + tags[i].FullName);
        }
   }
}

From looking through documentation, I was able to fnd that AssetDatabase.SaveAssets(); definitely works (i.e. it shows that it is saving the ScriptableObject asset) but somehow on any recompilation of the editor the object just resets to default values and all added tags are gone.

I tried using AssetDatabase to get the scriptableObject asset but this does the same as GameTagTree targetTree = (GameTagTree)target; above.

I suspect it has something to do with using the custom class not derived from UnityEngine.Object or nesting a list<GameTag> - but I’ve run out of ideas on how to fix.

I tried using SerializedProperty but didn’t have any luck because SerializedProperty does not support objects not derived from UnityEngine.Object.

public override void OnInspectorGUI()
{
    serializedObject.Update();

    SerializedProperty sp = rootProp.Copy(); // copy so we don't iterate the original

    if (sp.isArray)
    {
        sp.Next(true); // skip generic field
        sp.Next(true); // advance to array size field

        // Get the array size
        int arrayLength = sp.intValue;
        sp.Next(true); // advance to first array index

        // Write values to list
        List<string> values = new List<string>(arrayLength);

        for (int i = 0; i < arrayLength; i++)
        {
            // copy the value to the list
            // Doesnt work for `GameTag`, even when using the object field in the property
            values.Add(sp.stringValue); 

            // advance without drilling into children
            if (i < arrayLength - 1) // TODO is this lastIndex thing needed?
                sp.Next(false);
        }

        // iterate over the list displaying the contents
        for (int i = 0; i < values.Count; i++)
            EditorGUILayout.LabelField(i + " = " + values[i]);

        serializedObject.ApplyModifiedProperties();
    }
}

After running through many forums which do not seem to have the answer I’ve tried putting a minimal replication above of the problem. Any suggestions on where to look appreciated.

Peking answered 10/8, 2023 at 2:45 Comment(0)
O
0

Your List<GameTag> children property has attribute [NonSerialized], so its data is never being saved. Remove the attribute and it will work. You don’t even need a custom inspector for this.

Oxime answered 10/8, 2023 at 6:33 Comment(1)

I realized I put this in because I kept getting an error of serialization depth going over 10, but then realized this is because I am assigning the children var in every tag so it infinitely keeps making tag children. Took that out and too the [NonSerialized] tag and all is well. Thank you.

Peking

© 2022 - 2025 — McMap. All rights reserved.