Undo.RecordObject isn't working.

I am using Undo.RegisterUndo method to register undoable actions but in Unity 5.x it says it’s obsolete and asks me to use Undo.RecordObject instead. But the problem is RecordObject method does not work while RegisterUndo does. What am I missing here?

What I’m doing : I’m customizing Transform’s inspector window and I pass a cast Transform object to Undo.RecordObject method.

I found this post by complete accident:

quoting it in case it’s deleted:

Undo.RegisterCompleteObjectUndo(Object objectToUndo, string name) will record a copy of the full state of the object that it will keep, unlike Undo.RecordObject(Object objectToUndo, string name) that will only keep a
copy of the state until the end of the
frame to compute a diff.
.
By the way, I just got the following
error that drove me to find more on
this method:

Generating diff of this object for
undo because the type tree changed.
This happens if you have used
Undo.RecordObject when changing the
script property. Please use
Undo.RegisterCompleteObjectUndo
So RegisterCompleteObjectUndo seems important in complex situations were a diff is not possible.

Couple of words from myself:

Undo.RegisterCompleteObjectUndo seems to work with Event and editor-GUI as well every time. And RecordObject seemed only to work sometimes (only worked occasionally)

Additionally, if you are working with Event in editor script, and actually have code that Use()s the GUI event, chances are the event might not get through to unity’s undo system.
You might need to call Undo.FlushUndoRecordObjects(); after RegisterCompleteObjectUndo()

.

Don’t forget to use EditorUtility.SetDirty() on the object, AFTER you’ve recoreded into Undo

Here is an example, allowing me to offset 2D viewport up/down left/right:

void DragViewingArea() {
            int id = GUIUtility.GetControlID(6, FocusType.Passive);
 
            //prepare for drag:
            if (_currentEvent.type == EventType.MouseDown && _currentEvent.button == 2) {
                Undo.RegisterCompleteObjectUndo(_fsm, "begin drag FSM viewport on " + _fsm.gameObject.name);
                Undo.FlushUndoRecordObjects();
             
                GUIUtility.hotControl = id;
                _currentEvent.Use();
                return;
            }
 
            //drag:
            if(_currentEvent.type == EventType.MouseDrag && GUIUtility.hotControl == id) {
                _fsm._fsmEditorWindow_TableOffset += _currentEvent.delta;
                _currentEvent.Use();
                EditorUtility.SetDirty(_fsm); //set dirty as soon as we actually drag
 
                return;
            }
 
            //finished dragging
            if (_currentEvent.type == EventType.mouseUp  &&  _currentEvent.button == 2  &&  GUIUtility.hotControl == id) {
                GUIUtility.hotControl = 0;
                _currentEvent.Use();
                return;
            }
 
        }

You have to make sure to call Undo.FlushUndoRecordObjects() to make sure changes made after calling RecordObject are pushed onto the Undo stack.

I have the same issue and it seems to happen with changes on my 1024 X 1024 terrain vs. 50 X 50. Also, Undo.FlushUndoRecordObjects() is automatically done; so, not sure why I would need to explicitly call that. I tried but it didn’t help anyway. The RegisterUndo does work though. I suspect a bug in RecordObject and will continue to use the deprecated method until I hear otherwise.

In your example, you have:

 private void ResetPosition(Object[] objs)
 {
     for(int i = 0; i < objs.Length; i++)
     {
         Transform tr = (Transform)objs*;*

Undo.RecordObject(tr, “Transform Change”);
tr.position = Vector3.zero;
}
}
Don’t record the change on the Transform, instead record it on the GameObject:
private void ResetPosition(Object[] objs)
{
for(int i = 0; i < objs.Length; i++)
{
Transform tr = (Transform)objs*;*
Undo.RecordObject(tr.gameObject, “Transform Change”);
tr.position = Vector3.zero;
}
}
This is not explained in the docs, but the examples hint at it. Another source:
_*http://answers.unity3d.com/answers/1007419/view.html*_

I had a somewhat related problem, where the undo wasn’t working in a specific object.
It was an editor-only object (had hideflags) but I needed it to update on an undo operation.
In my case, it turned out that I forgot to add SerializeField on the fields (or make them public), so the undo wasn’t registering the fields.

I carefully read the official introduciton for Undo usage (Unity - Scripting API: Undo), and finally understood its implicit rules.

If you want to record the modification of the transform, you have to use :

Undo.RecordObject (gameObject.transform, “name”)

NOT below:

Undo.RecordObject (gameObject, “name”)

In a word, you have to clarify exactly what the thing you want to record. In this case, it’s a transform, not a gameObject itself.

I had Undo.RecordObject() not working as well and sometimes it worked, sometimes not. I didn’t want to just replace it with RegisterCompleteObjectUndo(), so after investigation I found it didn’t work with prefab instances and worked fine with usual instances. Official documentations states about that. It says we need to call PrefabUtility.RecordPrefabInstancePropertyModifications() after Undo.RecordObject(). I created a little example scaffolding just for reference if someone or me will be looking for Undo problems.

#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;

public class SomeComponent : MonoBehaviour
{
    [SerializeField] private int _even;
    [SerializeField] private int _odd;

#if UNITY_EDITOR
    private void OnValidate()
    {
        bool isUndoRecorded = false;

        if (_even % 2 != 0)
        {
            RecordUndoIfNeeded(ref isUndoRecorded);
            ++_even;
        }

        if (_odd % 2 != 1)
        {
            RecordUndoIfNeeded(ref isUndoRecorded);
            ++_odd;
        }

        if (isUndoRecorded)
        {
            if (PrefabUtility.IsPartOfPrefabInstance(this))
            {
                // This case covers prefab instances in standard scenes and in prefab preview stage
                // scenes. Also it covers prefab variant assets editing (with no preview scene)
                // PrefabUtility.IsPartOfNonAssetPrefabInstance() excludes prefab variant assets,
                // so above check can be replaced by this call and process prefab variant assets
                // through EditorUtility.SetDirty()
                PrefabUtility.RecordPrefabInstancePropertyModifications(this);
            }
            else if (PrefabUtility.IsPartOfPrefabAsset(this))
            {
                // This case covers base prefab assets editing (with no preview scene)
                // To process prefab variant assets by this case change
                // PrefabUtility.IsPartOfPrefabInstance() to
                // PrefabUtility.IsPartOfNonAssetPrefabInstance()
                // but I guess it makes no sence
                EditorUtility.SetDirty(this);
            }
        }
    }
    
    private void RecordUndoIfNeeded(ref bool isUndoRecorded)
    {
        if(isUndoRecorded)
            return;
        isUndoRecorded = true;
        Undo.RecordObject(this, typeof(SomeComponent) + " change");
    }
#endif
}

I remember having this problem …
sometimes, we use the undo.recordobject on a specific object …
What saved me from many headaches was to understand what kind of action I wanted to apply.

if I applied it on some movement I used the object + transform.
If I used only vector3, I serialized vector3 or the list to look for …

I don’t understand why it works in such a way.
but in theory, it should apply to any action on the object.

Anyway, if you can put the script where it doesn’t work, I could help you!