Prefabs aren't saving with Undo.RecordObject

[85953-unity1.jpg*_|85953]
My Inspector

Undo.RecordObject works as intended and sets the object dirty when I make a change in my custom inspector, but this doesn’t seem to work for prefabs.

using UnityEngine;
using UnityEditor;

//Displays a custom editor for the CollisionDetection script
[CustomEditor(typeof(CollisionDetection))]
[CanEditMultipleObjects]
public class CollisionDetectionEditor : Editor 
{
	CollisionDetection scriptTarget;

	private void OnEnable()
	{
		scriptTarget = target as CollisionDetection;
	}

	public override void OnInspectorGUI()
	{
		DrawDefaultInspector();
		DrawTags();
	}

	//Draws the tags section
	private void DrawTags()
	{
		//Title
		GUILayout.Space(5);
		GUILayout.Label("Tags this projectile will collide with", EditorStyles.boldLabel);

		//Loops through all tags
		for(int i = 0; i < scriptTarget.collidableTags.Count; i++)
		{
			GUILayout.BeginHorizontal();

			EditorGUI.BeginChangeCheck();

			//Editable text field
			string tag = GUILayout.TextField(scriptTarget.collidableTags*.tag, GUILayout.MaxWidth(150), GUILayout.Width(150));*
  •  	//Boolean Field*
    

_ bool instantKill = GUILayout.Toggle(scriptTarget.collidableTags*.instantKill, “Instant Kill”);*_

* if (EditorGUI.EndChangeCheck())*
* {*

* Undo.RecordObject(target, “Changed Collision Tag”);*

_ scriptTarget.collidableTags*.tag = tag;
scriptTarget.collidableTags.instantKill = instantKill;
}*_

* //Remove button*
* if(GUILayout.Button(“Remove”))*
* {*
* scriptTarget.collidableTags.RemoveAt(i);*

* Undo.RecordObject(target, “Removed Collision Tag”);*
* }*

* GUILayout.EndHorizontal();*
* }*

* //Additional buttons*
* if(GUILayout.Button(“Add Tag”))*
* {*
* scriptTarget.collidableTags.Add(new CollisionTag(“New Tag”, false));*

* Undo.RecordObject(target, “Added Collision Tag”);*
* }*

* if(GUILayout.Button(“Clear Tags”))*
* {*
* scriptTarget.collidableTags.Clear();*

* Undo.RecordObject(target, “Cleared Collision Tags”);*

* }*
* }*
}
Inside the EndChangeCheck, it is correctly called when a change happens in the inspector, but not when a change happens on a prefab.
[85954-unity2.jpg|85954]
This new entry will disappear when I close and reopen my project
Does anyone know of an alternate way to set a prefab dirty, so that it correctly saves? Otherwise I have to set the values in Unity’s default list system, which completely negates all the hard work I’ve put into this inspector.
Thanks!

_*

You have to call Undo.RecordObject before your change, not after. In the first case (line 17 in your code above) you do it right. However in line 28, 40 and 48 you call it after you did changes to the object.

The way RecordObject works is that the moment you pass an object to the method Unity creates a snapshot of the current state. Unity automatically checks the list of recorded objects at the end of your custom inspector code and compare the recorded version with the current. If it differs it will create an undo step so the object can be reverted to the recorded state.

Now if you first do changes, then create a snapshot, at the end of your code the state will still be the same and no undo step is created.

So you should do:

        if(GUILayout.Button("Remove"))
        {
            Undo.RecordObject(target, "Removed Collision Tag");
            
            scriptTarget.collidableTags.RemoveAt(i);
        }

This assumes that “CollisionTag” is a [Serializable] custom class that is not derived from UnityEngine.Object (ScriptableObject or MonoBehaviour).

It’s also a bit confusing what “scriptTarget” actually is. If it’s a UnityEngine.Object derived class (like a MonoBehaviour for example) you might want to pass this reference to RecordObject. If scriptTarget is just a downcasted version of “target” this of course wouldn’t change anything but it would make the code more clear, especially since you omitted the declaration and assignment of that variable.

There’s another neat little function that needs to be called in order to make prefab instances save their changes… took me a few hours to figure that out and finally found this:
PrefabUtility.RecordPrefabInstancePropertyModifications

since Unity 2017.4 this is also mentioned on the documentation page of Undo.RecordObject

Please see my answer to this question and see if it helps: UI Text is not being rebuilt/updated in edit mode, when changing text from OnInspectorGUI - Questions & Answers - Unity Discussions

Just wanted to post a link that fixes the bugged implementation of Undo.RecordObject, which still causes problems on 2018.1.