diff --git a/GFramework.Core.Abstractions/state/IStateMachine.cs b/GFramework.Core.Abstractions/state/IStateMachine.cs index f0b6d61..f7ddf1e 100644 --- a/GFramework.Core.Abstractions/state/IStateMachine.cs +++ b/GFramework.Core.Abstractions/state/IStateMachine.cs @@ -1,4 +1,7 @@ -namespace GFramework.Core.Abstractions.state; +using System; +using System.Collections.Generic; + +namespace GFramework.Core.Abstractions.state; /// /// 状态机接口,用于管理状态的注册、切换和验证 @@ -34,4 +37,47 @@ public interface IStateMachine /// /// 要切换到的状态类型,必须实现IState接口 void ChangeTo() where T : IState; + + /// + /// 检查指定类型的状态是否已注册 + /// + /// 要检查的状态类型 + /// 如果状态已注册则返回true,否则返回false + bool IsRegistered() where T : IState; + + /// + /// 获取指定类型的已注册状态实例 + /// + /// 要获取的状态类型 + /// 如果状态存在则返回对应实例,否则返回null + T? GetState() where T : class, IState; + + /// + /// 获取所有已注册状态的类型集合 + /// + /// 包含所有已注册状态类型的枚举器 + IEnumerable GetRegisteredStateTypes(); + + /// + /// 获取上一个状态 + /// + /// 如果历史记录存在则返回上一个状态,否则返回null + IState? GetPreviousState(); + + /// + /// 获取状态历史记录 + /// + /// 状态历史记录的只读副本 + IReadOnlyList GetStateHistory(); + + /// + /// 回退到上一个状态 + /// + /// 如果成功回退则返回true,否则返回false + bool GoBack(); + + /// + /// 清空状态历史记录 + /// + void ClearHistory(); } \ No newline at end of file diff --git a/GFramework.Core.Tests/tests/SyncArchitectureTests.cs b/GFramework.Core.Tests/tests/SyncArchitectureTests.cs index 5fe0ed1..3216d38 100644 --- a/GFramework.Core.Tests/tests/SyncArchitectureTests.cs +++ b/GFramework.Core.Tests/tests/SyncArchitectureTests.cs @@ -1,4 +1,5 @@ -using GFramework.Core.Abstractions.enums; +using System; +using GFramework.Core.Abstractions.enums; using GFramework.Core.architecture; using GFramework.Core.Tests.architecture; using GFramework.Core.Tests.events; diff --git a/GFramework.Core/state/ContextAwareStateMachine.cs b/GFramework.Core/state/ContextAwareStateMachine.cs index 606cc0b..c385502 100644 --- a/GFramework.Core/state/ContextAwareStateMachine.cs +++ b/GFramework.Core/state/ContextAwareStateMachine.cs @@ -61,6 +61,20 @@ public class ContextAwareStateMachine : StateMachine, ISystem /// public virtual void Destroy() { + // 退出当前状态 + if (Current != null) + { + Current.OnExit(null); + Current = null; + } + + // 清理所有状态 + foreach (var state in States.Values.OfType()) + { + state.Dispose(); + } + + States.Clear(); } /// diff --git a/GFramework.Core/state/StateMachine.cs b/GFramework.Core/state/StateMachine.cs index c845340..08e3b24 100644 --- a/GFramework.Core/state/StateMachine.cs +++ b/GFramework.Core/state/StateMachine.cs @@ -5,8 +5,11 @@ namespace GFramework.Core.state; /// /// 状态机实现类,用于管理状态的注册、切换和生命周期 /// -public class StateMachine : IStateMachine +public class StateMachine(int maxHistorySize = 10) : IStateMachine { + private readonly object _lock = new(); + private readonly Stack _stateHistory = new(); + /// /// 存储所有已注册状态的字典,键为状态类型,值为状态实例 /// @@ -15,14 +18,19 @@ public class StateMachine : IStateMachine /// /// 获取当前激活的状态 /// - public IState? Current { get; private set; } + public IState? Current { get; protected set; } /// /// 注册一个状态到状态机中 /// /// 要注册的状态实例 public void Register(IState state) - => States[state.GetType()] = state; + { + lock (_lock) + { + States[state.GetType()] = state; + } + } /// /// 从状态机中注销指定类型的状态 @@ -30,17 +38,28 @@ public class StateMachine : IStateMachine /// 要注销的状态类型 public void Unregister() where T : IState { - var type = typeof(T); - if (!States.TryGetValue(type, out var state)) return; - - // 如果当前状态是要注销的状态,则先执行退出逻辑 - if (Current == state) + lock (_lock) { - Current.OnExit(null); - Current = null; - } + var type = typeof(T); + if (!States.TryGetValue(type, out var state)) return; - States.Remove(type); + // 如果当前状态是要注销的状态,则先执行退出逻辑 + if (Current == state) + { + Current.OnExit(null); + Current = null; + } + + // 从历史记录中移除该状态的所有引用 + var tempStack = new Stack(_stateHistory.Reverse()); + _stateHistory.Clear(); + foreach (var historyState in tempStack.Where(s => s != state)) + { + _stateHistory.Push(historyState); + } + + States.Remove(type); + } } /// @@ -63,10 +82,117 @@ public class StateMachine : IStateMachine /// 当目标状态未注册时抛出 public void ChangeTo() where T : IState { - if (!States.TryGetValue(typeof(T), out var target)) - throw new InvalidOperationException("State not registered."); + lock (_lock) + { + // 检查目标状态是否已注册 + if (!States.TryGetValue(typeof(T), out var target)) + throw new InvalidOperationException("State not registered."); - ChangeInternal(target); + // 验证当前状态是否可以转换到目标状态 + if (Current != null && !Current.CanTransitionTo(target)) + throw new InvalidOperationException( + $"Cannot transition from {Current.GetType().Name} to {typeof(T).Name}"); + + ChangeInternal(target); + } + } + + /// + /// 检查指定类型的状态是否已注册 + /// + /// 要检查的状态类型 + /// 如果状态已注册则返回true,否则返回false + public bool IsRegistered() where T : IState => States.ContainsKey(typeof(T)); + + /// + /// 获取指定类型的已注册状态实例 + /// + /// 要获取的状态类型 + /// 如果状态存在则返回对应实例,否则返回null + public T? GetState() where T : class, IState => States.TryGetValue(typeof(T), out var state) ? state as T : null; + + /// + /// 获取所有已注册状态的类型集合 + /// + /// 包含所有已注册状态类型的枚举器 + public IEnumerable GetRegisteredStateTypes() => States.Keys; + + /// + /// 获取上一个状态 + /// + /// 如果历史记录存在则返回上一个状态,否则返回null + public IState? GetPreviousState() + { + lock (_lock) + { + return _stateHistory.Count > 0 ? _stateHistory.Peek() : null; + } + } + + /// + /// 获取状态历史记录 + /// + /// 状态历史记录的只读副本,从最近到最远排序 + public IReadOnlyList GetStateHistory() + { + lock (_lock) + { + return _stateHistory.ToList().AsReadOnly(); + } + } + + /// + /// 回退到上一个状态 + /// + /// 如果成功回退则返回true,否则返回false + public bool GoBack() + { + lock (_lock) + { + if (_stateHistory.Count == 0) return false; + + var previousState = _stateHistory.Pop(); + + // 检查上一个状态是否仍然注册 + if (!States.ContainsValue(previousState)) + { + // 如果状态已被注销,继续尝试更早的状态 + return GoBack(); + } + + // 回退时不添加到历史记录 + ChangeInternalWithoutHistory(previousState); + return true; + } + } + + /// + /// 清空状态历史记录 + /// + public void ClearHistory() + { + lock (_lock) + { + _stateHistory.Clear(); + } + } + + /// + /// 内部状态切换方法(不记录历史),用于回退操作 + /// + /// 下一个状态实例 + protected virtual void ChangeInternalWithoutHistory(IState next) + { + if (Current == next) return; + + var old = Current; + OnStateChanging(old, next); + + old?.OnExit(next); + Current = next; + Current.OnEnter(old); + + OnStateChanged(old, Current); } /// @@ -75,13 +201,68 @@ public class StateMachine : IStateMachine /// 下一个状态实例 protected virtual void ChangeInternal(IState next) { + // 检查是否为相同状态,避免不必要的切换 if (Current == next) return; - if (Current != null && !Current.CanTransitionTo(next)) return; + + // 验证当前状态是否允许切换到目标状态 + if (Current != null && !Current.CanTransitionTo(next)) + { + OnTransitionRejected(Current, next); + return; + } var old = Current; - old?.OnExit(next); + OnStateChanging(old, next); + // 将当前状态添加到历史记录 + if (Current != null) + { + _stateHistory.Push(Current); + + // 限制历史记录大小 + if (_stateHistory.Count > maxHistorySize) + { + // 移除最旧的记录(栈底元素) + var tempStack = new Stack(_stateHistory.Reverse().Skip(1)); + _stateHistory.Clear(); + foreach (var state in tempStack.Reverse()) + { + _stateHistory.Push(state); + } + } + } + + old?.OnExit(next); Current = next; Current.OnEnter(old); + + OnStateChanged(old, Current); + } + + /// + /// 当状态转换被拒绝时的回调方法 + /// + /// 源状态 + /// 目标状态 + protected virtual void OnTransitionRejected(IState from, IState to) + { + } + + /// + /// 当状态即将发生改变时的回调方法 + /// + /// 源状态 + /// 目标状态 + protected virtual void OnStateChanging(IState? from, IState to) + { + } + + /// + /// 当状态改变完成后的回调方法 + /// + /// 源状态 + /// 目标状态 + protected virtual void OnStateChanged(IState? from, IState? to) + { } } \ No newline at end of file