Home > front end >  How can we avoid corrupting lists when using Unity Undo.RecordObject?
How can we avoid corrupting lists when using Unity Undo.RecordObject?

Time:03-11

It turns out that Undo.RecordObject is not a magic bullet solution for all undo situations. There are some changes to an object that can be accurately reverted thanks to RecordObject, but sometimes some changes lead to a corrupted object upon undo.

Here is an attempt to remedy the situation: enter image description here

CodePudding user response:

Reason

This is because Undo will combine changes together. And it seems like that only the oldest modification is reserved when Unity tries to combine array operations. And it seems like that Unity collapses all operations that change the size of an array because it treats them as the same type of operation.

Undo operations are automatically combined together based on events.

At present, it can be determined that the MouseDown event can automatically split these undo operations, but MouseDrag will not.

Reproduce

Let's see a simple example, these are what Unity is recorded:

  1. Add 3 elements 1, 2, 3 by click.

    • size 0->1
    • size 1->2
    • size 2->3
  2. Remove them by dragging from 3 to 1.

    • size 3->2, array[2] 3->3
    • size 2->1, array[1] 2->2
    • size 1->0, array[0] 1->1
  3. Perform an undo action.

    Here since the operations in step 2 are performed by dragging, they are combined, and Unity only reserves the oldest size modification size 3->2, array[2] 3->3, the action will just do size 2->3, array[2] 3->3, the final result you will get is [0, 0, 3].

  4. By the way in step 2 if you remove elements from 1 to 3, undo will revert to the desired result.

    • size 3->2, array[0] 1->2, array[1] 2->3, array[2] 3->3
    • size 2->1, array[0] 2->3, array[1] 3->3
    • size 1->0, array[0] 3->3

Solution

Here's some approaches to avoid the problem.

  1. Don't record objects in MouseDrag event.

  2. Manually increase undo group index.

     private void RemoveCell(ListObj obj, int index)
     {
         Undo.IncrementCurrentGroup();
         Undo.RecordObject(obj, "remove cell");
         obj.content.Remove(index);
     }
    
  3. Use RegisterCompleteObjectUndo.

  • Related