Editing and Undo for non-unity properties

How can handle undo for non-unity, not unity serialized properties?

Imagine I was making a .ini editor in unity using a custom EditorWindow. I read the ini file, for each [section] I make a Dictionary and for each key=value make an entry in a Dictionary themselves are in a Dictionary>.

In OnGui for each section I call EditorGUILayout.Folder and within each section I call EditorGUILayout.TextField for each key/value pair.

This all works. I can load an .ini file and I see all the fields. But, a bunch of things don’t work and I’m really confused about what Unity expects.

  1. My data gets lost on every single call to OnGUI??? In other words I have something like this

    class MyWindow : EditorWindow
    {
      Dictionary<string, Dictionary<string, string> > m_sections;
    
      void OnGUI()
      {
        if (m_sections == null)
        {
          Debug.Log("new m_sections");   // This gets called constantly!!! WTF?!?!
          m_sections = new Dictionary<string, Dictionary<string, string>>();
        }
        ...
      }
    }
    
  2. How do I handle Undo?

I tried making class MyData that inherits from UnityEngine.Object and putting my Dictionary> instead it as a public field. That way I could call Undo.RecordObject. I can’t imagine that will work but since I can’t get past #1 above I have no idea.

To handle temporary data inside the editor that isn’t lost when you close you editor windows, change the scene, change playmode or when scripts recompile you want to use a ScriptableObject. It’s important to set the hideFlags to DontSave otherwise Unity would try to save it along with the scene. It would even mark the scene as dirty (modified) if you don’t set the hideflags.

You usually want to use a singleton like pattern for this ScriptableObject. However keep in mind that static variables are also wiped when scripts are recompiled. So you have to use Resources.FindObjectsOfTypeAll to search for an existing (serialized) instance. Something like this:

public class DataObject : ScriptableObject
{
    private static DataObject m_Instance = null;
    public static DataObject Instance
    {
        get
        {
            if (m_Instance == null)
            {
                var tmp = Resources.FindObjectsOfTypeAll<DataObject>();
                if (tmp.Length > 0)
                    m_Instance = tmp[0];
                else
                    m_Instance = ScriptableObject.CreateInstance<DataObject>();
                m_Instance.hideFlags = HideFlags.DontSave;
            }
            return m_Instance;
        }
    }

    public string someSerializedData = "Hello World";
}

Keep in mind that ScriptableObjects need it’s own file where the file name matches the class name, just like MonoBehaviour scripts.

It’s important to either always use the singleton property or get the reference in OnEnable and store it in a variable:

// in your editor window
DataObject data;
void OnEnable()
{
    data = DataObject.Instance;
}
void OnGUI()
{
    data.someSerializedData = GUILayout.TextField(data.someSerializedData);
}

Note: Unity also serialized private members of editor classes unless you put a NonSerialized attribute on it. So in this case here the reference to our DataObject instance which is stored in the “data” variable will survive playmode changes while the window is open.

Hey There,

UnityEditor data does not serialize in any way at all.

Everything is temporary (editor stuff)

Whenever you view a editor class (inspector/window) you are looking at a brand new object. As soon as you close that window or change your selection (ie changing the inspector window) that editor window is tossed out with all that data that you think it saved. If you make a public bool it will stick around until you leave the window but if you come back it’s a brand new window.

You are going to have to save the data yourself. What that comes down to is saving the data as XML or json (or whatever). You can then take this data and save it to EditorPrefs, a TextFile, a ScriptableObject, or the Userdata of the script itself. The choice is yours but each one has it’s own advantages. If you are going simple just save your data to EditorPrefs (keep note this only saves on your computer).

The More You Know!

Unity uses a powerful library that is built into C# to make all these classes. It’s called Reflection and the class they use is called Activator. This basically just makes a class on the fly just based on a type.