Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

GameObject Undo?

Discussion in 'Immediate Mode GUI (IMGUI)' started by delinx32, Jun 6, 2015.

  1. delinx32

    delinx32

    Joined:
    Apr 20, 2012
    Posts:
    417
    Should this work? No undo operation gets registered even though I modified underlying terrain data. The docs are a little light on info. Can I register my whole object as an undo operation, or do I have to register every single thing that can change during the operation?

    Code (CSharp):
    1.             if(GUILayout.Button("Smooth Terrain"))
    2.             {
    3.                 Undo.RecordObject(_target, "Smooth Terrain");
    4.                
    5.                 _target.SmoothTerrain();
    6.                
    7.                
    8.             }
    9.  
     
  2. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    After you perform this operation,do you see "Smooth Terrain" listed under Undo ?
     
  3. delinx32

    delinx32

    Joined:
    Apr 20, 2012
    Posts:
    417
    No, nothing is listed. I changed it to just record the terrain data and it worked. The undo operation is kind of slow. I'm guessing that you can't record the whole object all at once.
     
  4. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    What is _target in this case? is it a component or a game object?
     
  5. delinx32

    delinx32

    Joined:
    Apr 20, 2012
    Posts:
    417
    In that case, its the component that the editor is attached to, but I've also tried _target.gameObject and that didn't work either.
     
  6. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    The documentation for Undo is really confusing. I remember we got around these issues, i can look at the code we are using.
     
  7. delinx32

    delinx32

    Joined:
    Apr 20, 2012
    Posts:
    417
    I'm still having issues with this. I wish it was better documented. Now, it seems that my edit action is happening before the object's state is actually recorded.

    In the following code, I want to record the state of the object on the first click (firstPoint.HasValue will be, and is false at that point). Then I proceed to select the cells I want. The issue is that Debug.log("selecting") gets written before another debug.log that I have in my OnBeforeSerialize.

    I must just not understand what/how I'm supposed to be doing it, but the documentation is so light, and google doesn't come up with any helpful posts at all.

    Code (CSharp):
    1.                 if ((((Event.current.type == EventType.MouseDrag)
    2.                       || ((Event.current.type == EventType.MouseDown || Event.current.rawType == EventType.mouseUp) && Event.current.clickCount == 1))
    3.                     )
    4.                     && Event.current.button == 0
    5.                    )
    6.                 {
    7.                     if (!firstPoint.HasValue)
    8.                     {
    9.                         Undo.RecordObject(_target, "Select Cells");
    10.  
    11.                         firstPoint = cellPoint;
    12.                         firstHeight = h;
    13.                         if (wpCell != null)
    14.                             _target.CurrentId = wpCell.id;
    15.                         else
    16.                             _target.CurrentId = _target.MaxId + 1;
    17.  
    18.  
    19.                     }
    20.  
    21.  
    22.                     if (Event.current.rawType == EventType.MouseUp || Math.Abs(diff.X) > 1 || Math.Abs(diff.Y) > 1)
    23.                     {
    24.                         Debug.Log("selecting");
    25.                         _target.SelectCells(firstPoint.Value, firstHeight, h, direction, brushSize, avgFlow, editMode == 1);
    26.                         firstPoint = movePoint;
    27.                         movePoint = cellPoint;
    28.  
    29.                     }
    30.                 }
    31.             }
     
  8. delinx32

    delinx32

    Joined:
    Apr 20, 2012
    Posts:
    417
    Undo.RegisterUndo seems to work where Undo.RecordObject does not. I'm not sure what the difference between the two is.
     
  9. IgorAherne

    IgorAherne

    Joined:
    May 15, 2013
    Posts:
    393
    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:
    Code (CSharp):
    1.  void DragViewingArea() {
    2.             int id = GUIUtility.GetControlID(6, FocusType.Passive);
    3.  
    4.             //prepare for drag:
    5.             if (_currentEvent.type == EventType.MouseDown && _currentEvent.button == 2) {
    6.                 Undo.RegisterCompleteObjectUndo(_fsm, "begin drag FSM viewport on " + _fsm.gameObject.name);
    7.                 Undo.FlushUndoRecordObjects();
    8.              
    9.                 GUIUtility.hotControl = id;
    10.                 _currentEvent.Use();
    11.                 return;
    12.             }
    13.  
    14.             //drag:
    15.             if(_currentEvent.type == EventType.MouseDrag && GUIUtility.hotControl == id) {
    16.                 _fsm._fsmEditorWindow_TableOffset += _currentEvent.delta;
    17.                 _currentEvent.Use();
    18.                 EditorUtility.SetDirty(_fsm); //set dirty everu time as we actually drag
    19.  
    20.                 return;
    21.             }
    22.  
    23.             //finished dragging
    24.             if (_currentEvent.type == EventType.mouseUp  &&  _currentEvent.button == 2  &&  GUIUtility.hotControl == id) {
    25.                 GUIUtility.hotControl = 0;
    26.                 _currentEvent.Use();
    27.                 return;
    28.             }
    29.  
    30.         }
     
    Last edited: Jul 19, 2017