- Home /
Unity editor not saving object changes
I'm currently making a custom inspector script for one of my scripts that allows user input to set a inspector read only variable on the script, with background checking. The script works and sets this variable but after saving the scene, project and restarting unity the variable is now empty.
I've tried force saving the scene and project via script but also this does not work.
The variable script snippet:
public class Object : OWSGBehaviour
{
[ShowOnly, SerializeField] protected string _databaseID = "null";
// Details
/// <summary>
/// Item Database ID (SET ONLY FOR OBJECT DATABASE USE)
/// </summary>
public string DatabaseID
{
get
{
return _databaseID;
}
set
{
_databaseID = value;
}
}
The custom inspector code:
[CustomEditor(typeof(Object), true)]
public class EditorObjectInspectorAdd : Editor {
private static EditorObjectInspectorAddPopup popup;
private static Object myTarget;
static EditorObjectInspectorAdd()
{
EditorObjectInspectorAddPopup.WindowClosed += ReceiveId;
}
public override void OnInspectorGUI()
{
myTarget = (Object)target;
if (GUILayout.Button("Set Database ID"))
{
popup = ScriptableObject.CreateInstance<EditorObjectInspectorAddPopup>();
popup.position = new Rect(Screen.width / 2, Screen.height / 2, 250, 75);
popup.ShowUtility();
}
DrawDefaultInspector();
}
static void ReceiveId(string id)
{
if(myTarget.DatabaseID == "null")
{
myTarget.DatabaseID = id;
}
else
{
Debug.Log("Object Updated from " + myTarget.DatabaseID + " to: " + id);
ObjectDatabaseEditor.UpdateID(myTarget.DatabaseID, id);
myTarget.DatabaseID = id;
}
// Trying to force save changes - no dice
EditorApplication.SaveAssets();
EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo();
}
}
public class EditorObjectInspectorAddPopup : EditorWindow
{
public delegate void OnWindowClose(string id);
public static event OnWindowClose WindowClosed;
bool allowed = false;
string input = "";
string lastInput = "";
void OnGUI()
{
EditorGUILayout.LabelField("Input ID (10 Char max):");
input = EditorGUILayout.TextField(input, EditorStyles.textField);
input = input.Replace(" ", "");
if (input != lastInput)
{
lastInput = input;
allowed = ObjectDatabaseEditor.IsIDavaliable(input);
}
if (allowed)
{
if (GUILayout.Button("Agree!"))
{
if (WindowClosed != null)
WindowClosed(input);
this.Close();
}
} else
{
EditorGUILayout.LabelField("ID is currently taken or not avaliable");
}
}
}
Answer by JoshDangIt · Aug 21, 2016 at 06:17 PM
You'll need to use EditorUtility.SetDirty().
EDIT: In Unity 5.3 onward, you'll want to use Undo.RecordObject(). I'd recommend looking these up in the scripting reference.
Thanks!
For others checking this, once you use Undo, you make your scene aware that there were relevant changes, so it will be marked as dirty, and of course you will be able to undo those changes using the Edit menu.
So I'm facing a similar problem and while Undo.RecordObject seems to help it does not fully fix the issue. I have an editor script that adds scene objects to a list in a custom component on my gameobjects. It used to be that on reload all those changes would be lost, so I record those components now with Undo.RecordObjects(). However, when I reload the scene now the lists do have the right amount of slots in them, but their values are set to none. Anyone know what's causing this?
Okay, after some more messing around I found a solution, posting here in case someone needs it. When adding objects to the scene and referencing these to other scene objects' lists, it is actually sufficient to use EditorUtility.SetDirty on all involved objects (including the newly added object). However, when removing an object and updating the other objects' references, you first have to use Undo.RecordObject on all involved objects and then also set them dirty with EditorUtility.SetDirty. I unfortunately don't know why this is, I came to this result by lots of trial and error. Explanations are welcome, of course!
@Yandalf, wherever you are, thank you for this comment. You've just brought ~3 hours of debugging to an end.
I was running into a similar issue (modifying a List of Vector2 with an editor script, but values added in edit mode would get set to (0,0) when I switched to play mode). I'm genuinely baffled as to why Undo.RecordObject() isn't enough to get those vals to persist, but I guess if this works it works.
Answer by v-ercart · May 22, 2018 at 11:21 PM
I was stuck in a similar place and was messing with serializedObject.ApplyModifiedProperties() and SetDirty for a really long time before I figured out what was happening. I'm using a mix of PropertyFields and directly setting the public properties on my target. Like this:
fontProperty = serializedObject.FindProperty("FontSize");
solutionObj = target as SolutionObject;
EditorGUILayout.PropertyField(fontProperty );
solutionObj.TextLabel = EditorGUILayout.TextField(TextLabel , EditorStyles.textField);
serializedObject.ApplyModifiedProperties();
It turns out the ApplyModifiedProperties() call was overwriting the TextLabel, and trashing the value the TextField had set. I got around this by applying the TextLabel changes AFTER the ApplyModifiedProperties() call. I think this is because the serializedObject copy of the data just gets dumped on top of the actual objects data when they are applied.
Answer by ulisesyo · Mar 12, 2017 at 03:19 PM
It looks like you also need to mark the scene as dirty with
UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty();
Or if you know which scene you are editing, you can use
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(Scene);
I had the same custom editor problem and tried your solution. It worked. But any idea how EditorUtility.SetDirty() could be enough all the last 4 months and suddently it isn't? ^^
Unity changed it. They do not want us to use SetDirty on scene objects. We must use the Undo system or SerializedProperty.
Answer by Bryan-Legend · Oct 29, 2020 at 05:56 PM
In addition to UnityEditor.Undo.RecordObject(this, "Description");
you may need to run UnityEditor.PrefabUtility.RecordPrefabInstancePropertyModifications(this);