Save prefab changes made in Prefab Mode from custom editor

Hello,

I’m doing a custom inspector for my MonoBehaviour class “RoomInfo” attached on a prefab. The goal is to help the designers to choose where to place the exits of the room:

    public class RoomInfo : MonoBehaviour
    {
        [SerializeField, Range(1, 10)]
        private int XTile = 1;

        [SerializeField, Range(1, 7)]
        private int YTile = 1;

        [SerializeField, HideInInspector]
        private List<Vector2Int> Exits_Up = new List<Vector2Int>();

        [SerializeField, HideInInspector]
        private List<Vector2Int> Exits_Down = new List<Vector2Int>();

        [SerializeField, HideInInspector]
        private List<Vector2Int> Exits_Right = new List<Vector2Int>();

        [SerializeField, HideInInspector]
        private List<Vector2Int> Exits_Left = new List<Vector2Int>();
}

In the inspector, I just get the 4 serialized lists and in the OnSceneGUI method I update the lists of exits when clicking on a handle cube placeholder:

[CustomEditor(typeof(RoomInfo), true)]
public class RoomInspector : Editor
{
    private RoomInfo room = null;

    private bool needUpdate = false;
    private bool editExits = false;

    private SerializedProperty upExitsProperty;
    private SerializedProperty downExitsProperty;
    private SerializedProperty rightExitsProperty;
    private SerializedProperty leftExitsProperty;

    private float buttonSize = 2.0f;

    private void Awake()
    {
        room = target as RoomInfo;

        upExitsProperty = serializedObject.FindProperty("Exits_Up");
        downExitsProperty = serializedObject.FindProperty("Exits_Down");
        rightExitsProperty = serializedObject.FindProperty("Exits_Right");
        leftExitsProperty = serializedObject.FindProperty("Exits_Left");
    }

    public void OnSceneGUI()
    {
        serializedObject.Update();

        Handles.matrix = Matrix4x4.TRS(new Vector3(0.0f, 0.0f, 4.0f), Quaternion.identity, new Vector3(ProceduralGeneration.XTileSize, buttonSize, 20.0f));

        for (int i = 0; i < room.XTileNb; i++) // Down
        {
            Vector3 pos = new Vector3(i + 0.5f, -0.5f, -0.5f);
            Vector2Int coordinates = new Vector2Int(i, 0);

            int index = -1;
            bool contain = Contains(downExitsProperty, coordinates, ref index);

            if (contain)
                Handles.color = new Color(0.0f, 1.0f, 0.0f, 0.8f);
            else
                Handles.color = new Color(1.0f, 0.0f, 0.0f, 0.8f);

            if (Handles.Button(pos, Quaternion.identity, 1.0f, 1.0f, Handles.CubeHandleCap))
            {
                if (contain)
                    Remove(downExitsProperty, index);
                else
                    Add(downExitsProperty, coordinates);

                needUpdate = true;
                Repaint();
            }
        }
        ...
        //Repeated 3 times for up, left and right of the room
    }

    private bool Contains(SerializedProperty list, Vector2Int val, ref int index)
    {
        for (int i = 0; i < list.arraySize; i++)
        {
            if (list.GetArrayElementAtIndex(i).vector2IntValue == val)
            {
                index = i;
                return true;
            }
        }

        index = -1;
        return false;
    }

    private void Add(SerializedProperty list, Vector2Int val)
    {
        int size = list.arraySize;
        list.InsertArrayElementAtIndex(size);
        list.GetArrayElementAtIndex(size).vector2IntValue = val;
    }

    private void Remove(SerializedProperty list, int index)
    {
        list.DeleteArrayElementAtIndex(index);
    }

In the Prefab Mode the serialized values for XTile & YTile are correctly changed, I can exit Prefab Mode and re-open the prefab, the changes are applied. Now for the serialized lists, I can see that the changes are effective (The color of the handles change) but after exiting Prefab Mode and re-open the prefab, the handles are all back to red so no changes have been saved. I don’t know what’s wrong, since I’m directly editing in Prefab Mode I don’t think I need to call method from PrefabUtility right? Any help is appreciated! :slight_smile:

I know this is an old thread, but I was recently looking for this answer and it took me a bit to figure it out more or less on my own, so I am sure others are as well.
Here is what I got as a solution.

[CustomEditor(typeof(Item),true)]//change this to reflect your class type
public class ItemCustomInspector : Editor
{
	public override void OnInspectorGUI()
	{
		Item itemScript = (Item)target;//change this to reflect your class type
		


		PrefabUtility.RecordPrefabInstancePropertyModifications(itemScript);

		if (PrefabUtility.HasPrefabInstanceAnyOverrides(itemScript.gameObject, false))//changes made
		{
			EditorGUILayout.LabelField("Prefab has been changed in inspector", EditorStyles.boldLabel);
			if (GUILayout.Button("Apply Prefab Changes"))
			{
				Debug.Log("Applying changes");
				PrefabUtility.ApplyPrefabInstance(itemScript.gameObject, InteractionMode.UserAction);
			}
			if (GUILayout.Button("Revert Prefab Changes"))
			{
				Debug.Log("Reverting changes");
				PrefabUtility.RevertPrefabInstance(itemScript.gameObject, InteractionMode.UserAction);
			}
		}
	}
}