Files
2026-02-21 16:45:37 +08:00

186 lines
3.9 KiB
C#

using System;
using System.Collections.Generic;
using MyUtility;
using UnityEngine;
namespace UndoRedo
{
public class UR_CommandMgr
{
private static UR_CommandMgr s_instance;
private List<UR_ICommand> m_undoCommands = new List<UR_ICommand>();
private List<UR_ICommand> m_redoCommands = new List<UR_ICommand>();
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>();
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();
}
}
}
}