using System; using System.Collections.Generic; using MyUtility; using UnityEngine; namespace UndoRedo { public class UR_CommandMgr { private static UR_CommandMgr s_instance; private List m_undoCommands = new List(); private List m_redoCommands = new List(); private UtilityOnDestroyHandler m_sceneDestroyHandler; private long m_commandsStoredBytesLimit = 134217728L; private long m_commandsStoredBytes; public static UR_CommandMgr Instance { get { return (s_instance != null) ? s_instance : (s_instance = new UR_CommandMgr()); } } public bool IsDestroyedOnSceneLoad { get { return m_sceneDestroyHandler != null; } set { if (value) { if (m_sceneDestroyHandler == null) { GameObject gameObject = new GameObject("UR_CommandMgrSceneDestroyHandler"); m_sceneDestroyHandler = gameObject.AddComponent(); UtilityOnDestroyHandler sceneDestroyHandler = m_sceneDestroyHandler; sceneDestroyHandler.m_onDestroy = (Action)Delegate.Combine(sceneDestroyHandler.m_onDestroy, new Action(Reset)); } } else if (m_sceneDestroyHandler != null) { m_sceneDestroyHandler.DestroyWithoutHandling(); m_sceneDestroyHandler = null; } } } public long StoredBytesLimit { get { return m_commandsStoredBytesLimit; } set { m_commandsStoredBytesLimit = value; LimitMemoryUsage(); } } public long StoredBytes { get { return m_commandsStoredBytes; } } public bool IsRedoable { get { return m_redoCommands.Count > 0; } } public bool IsUndoable { get { return m_undoCommands.Count > 0; } } public void Add(UR_ICommand p_cmd, bool p_isAlreadyExecuted) { if (p_cmd != null) { if (!p_isAlreadyExecuted) { p_cmd.Execute(); } if (m_undoCommands.Count > 0) { UR_ICommand uR_ICommand = m_undoCommands[m_undoCommands.Count - 1]; long storedBytes = uR_ICommand.GetStoredBytes(); if (uR_ICommand.CombineWithNext(p_cmd)) { ClearRedoCommands(); m_commandsStoredBytes += uR_ICommand.GetStoredBytes() - storedBytes; LimitMemoryUsage(); return; } } m_undoCommands.Add(p_cmd); ClearRedoCommands(); m_commandsStoredBytes += p_cmd.GetStoredBytes(); LimitMemoryUsage(); } else { Debug.LogError("UR_CommandMgr: Add: p_cmd is null!"); } } public void Execute(UR_ICommand p_cmd) { Add(p_cmd, false); } public bool Redo() { if (IsRedoable) { UR_ICommand uR_ICommand = m_redoCommands[m_redoCommands.Count - 1]; m_redoCommands.RemoveAt(m_redoCommands.Count - 1); m_commandsStoredBytes -= uR_ICommand.GetStoredBytes(); uR_ICommand.Execute(); m_commandsStoredBytes += uR_ICommand.GetStoredBytes(); m_undoCommands.Add(uR_ICommand); return true; } return false; } public bool Undo() { if (IsUndoable) { UR_ICommand uR_ICommand = m_undoCommands[m_undoCommands.Count - 1]; m_undoCommands.RemoveAt(m_undoCommands.Count - 1); m_commandsStoredBytes -= uR_ICommand.GetStoredBytes(); uR_ICommand.Rollback(); m_commandsStoredBytes += uR_ICommand.GetStoredBytes(); m_redoCommands.Add(uR_ICommand); return true; } return false; } public void Reset() { m_undoCommands.Clear(); m_redoCommands.Clear(); m_commandsStoredBytes = 0L; } private void ClearRedoCommands() { for (int i = 0; i < m_redoCommands.Count; i++) { m_commandsStoredBytes -= m_redoCommands[i].GetStoredBytes(); } m_redoCommands.Clear(); } private void LimitMemoryUsage() { while (m_commandsStoredBytes > m_commandsStoredBytesLimit && m_undoCommands.Count > 0) { UR_ICommand uR_ICommand = m_undoCommands[0]; m_undoCommands.RemoveAt(0); m_commandsStoredBytes -= uR_ICommand.GetStoredBytes(); } } } }