Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Resolved Undone hierarchy changes are not saved.

Discussion in 'Scripting' started by Tomobodo, Jan 24, 2022.

  1. Tomobodo

    Tomobodo

    Joined:
    Dec 31, 2012
    Posts:
    7
    Hello everyone,

    I'm working on little level editor and I would like to implement a clean undo / redo behaviour but I'm stuck on a strange behaviour. I can't find any toopic on my issue, so, I hope maybe I made a stupid mistake someone could point me on.

    The strange behaviour is as follow :
    1. Add some block on the scene with the code below. Scene appears dirty as it should.
    2. Save the scene. Scene appears clean as it should.
    3. Undo the block adding, scene is marked as dirty as it should, undo seems to work properly, block are removed one by one.
    4. Save the scene. It appears clean.
    5. Reload the scene => the scene is the same as in step 2 instead of step 4. Undo were not saved properly.
    What am I doing wrong ? Triied some Undo.FlushSomething but didn't help, tinkered with EditorGUI.SetDirty but didn't help either.

    So here is the relevant part of the code :

    Code (CSharp):
    1.  
    2. void OnSceneGUI(SceneView sceneView, ...) {
    3. ....
    4.     if (Event.current.type != EventType.MouseDown || Event.current.button != 0)
    5.         return;
    6.            
    7.     Undo.RegisterFullObjectHierarchyUndo(level.gameObject, "Add block");
    8.  
    9.     var createdObject = (GameObject) PrefabUtility.InstantiatePrefab(selectedBlock.gameObject, level.transform);
    10.     createdObject.transform.position = blockGizmo.transform.position;
    11.  
    12.     level.Blocks[(int) blockCoords.x, (int)blockCoords.y, (int)blockCoords.z]  =              createdObject.GetComponent<Block>();
    13.     // updating a grid for game logic, it's a tile based game. I will use the 3d grid to check for allowed moves and so on.
    14.  
    15.     Event.current.Use();
    16. }
    17.  
    This code is executed on the duringSceneGui delegate if that's relevant.

    Thanks in advance.
     
  2. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,114
  3. Tomobodo

    Tomobodo

    Joined:
    Dec 31, 2012
    Posts:
    7
    Hello, thanks for your help

    Using Undo.RegisterCreatedObjectUndo seems to solve the save behaviour, but then when I undo it doesn't undo the change made to the level.Blocks array , that's why I used RegisterFullObjectHierarchyUndo because if I understood the documentation correctly it's supposed to save both the hierarchy AND the change made on the gameobject components.

    My problem seems to be that I have to undo an object creation and a component modification on the same action, but if I call Undo.ResgisterCompleteObjectUndo and Undo.RegisterCreatedObjectUndo, then I'll have to press crl + z two time to undo my action.

    Edit : Actually using Undo.RegisterCreateObjectUndo in cunjunction with Undo.RegisterCompleteObjectUndo seems to work. It seems I was wrong when I thought I'd had to press ctrl + z twice to fully revert my action. Is that the proper way of doing this ? Thanks again.

    Code (CSharp):
    1.  
    2. if (Event.current.type != EventType.MouseDown || Event.current.button != 0) return;
    3.      
    4. Undo.RegisterCompleteObjectUndo(level, "Add block");
    5.      
    6. var createdObject =
    7.                 (GameObject) PrefabUtility.InstantiatePrefab(selectedBlock.gameObject, level.transform);
    8. createdObject.transform.position = blockGizmo.transform.position;
    9.      
    10. level.Blocks[(int) blockCoords.x, (int)blockCoords.y, (int)blockCoords.z] = createdObject.GetComponent<Block>();
    11.  
    12. Undo.RegisterCreatedObjectUndo(createdObject, "Add block");
    13.      
    14. Event.current.Use();
    15.  
     
    Last edited: Jan 24, 2022
  4. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,114
    Glad you got it working! Yeah that is the right way to do it. Unity merges multiple Undo operations done during the same frame into one undoable action by default.

    There's this concept of a current group index which can be incremented manually and unity increments it automatically during events like mouse clicks. So all undoable actions done between this group index being incremented are tied to the same Undo action.
     
    Tomobodo likes this.
  5. Tomobodo

    Tomobodo

    Joined:
    Dec 31, 2012
    Posts:
    7
    That's good to know ! Many thanks for your help !