So I’m having trouble understanding exactly how Undo works in custom editor windows. Here is the progress I’ve made:
I’ve discovered that although I can register undo events for objects that change, the undo command will not always revert those changes. For example, any serialized field of a member that belongs to an instance of a class does not seem to revert.
EDIT: The first post was pseudocode off of the top of my head. I’ve rebuilt this to provide as a compilable example:
using System;
using UnityEngine;
using UnityEditor;
public class FooWindow : EditorWindow {
[SerializeField]
Foo fooClass;
[MenuItem("Window/Test Editor")]
static void ShowEditor(){
FooWindow editor = EditorWindow.GetWindow<FooWindow>();
editor.title = "Test Editor";
editor.Init();
}
void Init(){
fooClass = CreateInstance<Foo>();
}
void OnGUI(){
EditorGUI.BeginChangeCheck();
bool toggle = GUILayout.Toggle(fooClass.SClass.Bar, "Bar");
if(EditorGUI.EndChangeCheck()){
Debug.LogWarning("Saved");
Undo.RecordObject(fooClass, "Set bar");
fooClass.SClass.Bar = toggle;
EditorUtility.SetDirty(fooClass);
}
}
}
using UnityEngine;
using UnityEditor;
using System.Collections;
public class Foo : Editor {
[SerializeField]
SerializedClass sClass;
public SerializedClass SClass {
get { return sClass; }
set { sClass = value; }
}
public Foo(){
sClass = new SerializedClass();
}
}
using UnityEngine;
using System.Collections;
[System.Serializable]
public class SerializedClass {
[SerializeField]
bool bar = false;
public bool Bar {
get { return bar; }
set { bar = value; }
}
}
This will record the undo action, but will not revert it. Instead, If I move the undo code into the Foo class and then create another serialized variable within the Foo class and change that value, which I then would force the SerializedClass’s Bar variable to, it will correctly undo the change. EDIT: I put together a small example here and am able to get both a boolean and an int array tracked through undo.
using System;
using UnityEngine;
using UnityEditor;
public class FooWindow : EditorWindow {
[SerializeField]
Foo fooClass;
[MenuItem("Window/Test Editor")]
static void ShowEditor(){
FooWindow editor = EditorWindow.GetWindow<FooWindow>();
editor.title = "Test Editor";
editor.Init();
}
void Init(){
GameObject go = new GameObject();
SerializedClass sClass = go.AddComponent<SerializedClass>();
fooClass = ScriptableObject.CreateInstance<Foo>();
fooClass.Init(sClass);
}
void OnGUI(){
fooClass.UpdateValues();
}
}
using UnityEngine;
using UnityEditor;
using System.Collections;
public class Foo : Editor {
SerializedClass sClass;
public SerializedClass SClass {
get { return sClass; }
set { sClass = value; }
}
public void Init(SerializedClass newSClass){
sClass = newSClass;
}
public void UpdateValues(){
EditorGUI.BeginChangeCheck();
bool toggle = GUILayout.Toggle(sClass.Bar, "Bar");
if(EditorGUI.EndChangeCheck()){
Debug.LogWarning("Saved");
Undo.RecordObject(sClass, "Set bar");
sClass.Bar = toggle;
EditorUtility.SetDirty(sClass);
}
if(GUILayout.Button("Array")){
Debug.LogWarning("adding...");
Undo.RecordObject(sClass, "Add Int");
int[] intArray = sClass.IntArray;
System.Array.Resize<int>(ref intArray, sClass.IntArray.Length + 1);
sClass.IntArray = intArray;
EditorUtility.SetDirty(sClass);
}
}
}
using UnityEngine;
using UnityEditor;
using System.Collections;
public class SerializedClass : MonoBehaviour {
[SerializeField]
bool bar = false;
public bool Bar {
get { return bar; }
set { bar = value; }
}
[SerializeField]
int[] intArray = new int[0];
public int[] IntArray{
get { return intArray; }
set { intArray = value; }
}
}
So, there is something about the Undo class that I don’t understand. Why doesn’t it restore properties of serialized values within a class? EDIT: in setting up this example I was able to get the int array working. But a similar setup doesn’t work in my project. So there is something about what will actually be recorded and what won’t that I’m not understanding. So my question is: how exactly does Undo.RecordObject() determine whether it will record and restore a change with the undo command?