using System; using UnityEngine; using UnityEngine.SceneManagement; using UnityObject = UnityEngine.Object; #if UNITY_EDITOR using UnityEditor; using UnityEditor.SceneManagement; #endif namespace Unity.XR.CoreUtils { /// /// Represents a series of object actions as a single undo-operation. /// /// /// UndoBlock methods work in both Edit mode and Play mode. In Play mode undo-operations are disabled. /// This class mirrors the normal functions you find in the class and collapses them into one operation /// when the block is complete. /// /// /// Proper usage of this class is: /// /// using (var undoBlock = new UndoBlock("Desired Undo Message")) /// { /// undoBlock.yourCodeToUndo() /// } /// /// public class UndoBlock : IDisposable { int m_UndoGroup; bool m_DisposedValue; // To detect redundant calls of Dispose #if UNITY_EDITOR string m_UndoLabel; bool m_Dirty; bool m_TestMode; #endif /// /// Initialize a new UndoBlock. /// /// The label to apply to the undo group created within this undo block. /// Whether this is part of a test run. public UndoBlock(string undoLabel, bool testMode = false) { #if UNITY_EDITOR m_Dirty = false; m_TestMode = testMode; if (!Application.isPlaying && !m_TestMode) { Undo.IncrementCurrentGroup(); m_UndoGroup = Undo.GetCurrentGroup(); Undo.SetCurrentGroupName(undoLabel); m_UndoLabel = undoLabel; } else m_UndoGroup = -1; #else m_UndoGroup = -1; #endif } /// /// Register undo operations for a newly created object. /// /// The object that was created. public void RegisterCreatedObject(UnityObject objectToUndo) { #if UNITY_EDITOR if (!Application.isPlaying && !m_TestMode) { Undo.RegisterCreatedObjectUndo(objectToUndo, m_UndoLabel); m_Dirty = true; } #endif } /// /// Records any changes done on the object after the RecordObject function. /// /// The reference to the object that you will be modifying. public void RecordObject(UnityObject objectToUndo) { #if UNITY_EDITOR if (!Application.isPlaying && !m_TestMode) Undo.RecordObject(objectToUndo, m_UndoLabel); #endif } /// /// Sets the parent transform of an object and records an undo operation. /// /// The Transform component whose parent is to be changed. /// The parent Transform to be assigned. public void SetTransformParent(Transform transform, Transform newParent) { #if UNITY_EDITOR if (!Application.isPlaying && !m_TestMode) Undo.SetTransformParent(transform, newParent, m_UndoLabel); else transform.parent = newParent; #else transform.parent = newParent; #endif } /// /// Adds a component to the game object and registers an undo operation for this action. /// /// The game object you want to add the component to. /// The type of component you want to add. /// The new component. public T AddComponent(GameObject gameObject) where T : Component { #if UNITY_EDITOR if (!Application.isPlaying && !m_TestMode) { m_Dirty = true; return Undo.AddComponent(gameObject); } #endif return gameObject.AddComponent(); } /// /// Dispose of this object. /// /// Whether to cleanup this object's state. protected virtual void Dispose(bool disposing) { if (!m_DisposedValue) { if (disposing && m_UndoGroup > -1) { #if UNITY_EDITOR if (!Application.isPlaying && !m_TestMode) { Undo.CollapseUndoOperations(m_UndoGroup); if (m_Dirty) { EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene()); } } m_Dirty = false; #endif } m_DisposedValue = true; } } /// /// This code added to correctly implement the disposable pattern. /// public void Dispose() { // Do not change this code. Put cleanup code in Dispose(bool disposing) above. Dispose(true); } } }