using System;
using System.Collections.Generic;
namespace TEngine
{
///
/// 有限状态机。
///
/// 有限状态机持有者类型。
internal sealed class Fsm : FsmBase, IMemory, IFsm where T : class
{
private T _owner;
private readonly Dictionary> _states;
private Dictionary _dataMap;
private FsmState _currentState;
private float _currentStateTime;
private bool _isDestroyed;
///
/// 初始化有限状态机的新实例。
///
public Fsm()
{
_owner = null;
_states = new Dictionary>();
_dataMap = null;
_currentState = null;
_currentStateTime = 0f;
_isDestroyed = true;
}
///
/// 获取有限状态机持有者。
///
public T Owner => _owner;
///
/// 获取有限状态机持有者类型。
///
public override Type OwnerType => typeof(T);
///
/// 获取有限状态机中状态的数量。
///
public override int FsmStateCount => _states.Count;
///
/// 获取有限状态机是否正在运行。
///
public override bool IsRunning => _currentState != null;
///
/// 获取有限状态机是否被销毁。
///
public override bool IsDestroyed => _isDestroyed;
///
/// 获取当前有限状态机状态。
///
public FsmState CurrentState => _currentState;
///
/// 获取当前有限状态机状态名称。
///
public override string CurrentStateName => _currentState?.GetType().FullName;
///
/// 获取当前有限状态机状态持续时间。
///
public override float CurrentStateTime => _currentStateTime;
///
/// 创建有限状态机。
///
/// 有限状态机名称。
/// 有限状态机持有者。
/// 有限状态机状态集合。
/// 创建的有限状态机。
public static Fsm Create(string name, T owner, params FsmState[] states)
{
if (owner == null)
{
throw new GameFrameworkException("FSM owner is invalid.");
}
if (states == null || states.Length < 1)
{
throw new GameFrameworkException("FSM states is invalid.");
}
Fsm fsm = MemoryPool.Acquire>();
fsm.Name = name;
fsm._owner = owner;
fsm._isDestroyed = false;
foreach (FsmState state in states)
{
if (state == null)
{
throw new GameFrameworkException("FSM states is invalid.");
}
Type stateType = state.GetType();
if (fsm._states.ContainsKey(stateType))
{
throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' state '{1}' is already exist.", new TypeNamePair(typeof(T), name), stateType.FullName));
}
fsm._states.Add(stateType, state);
state.OnInit(fsm);
}
return fsm;
}
///
/// 创建有限状态机。
///
/// 有限状态机名称。
/// 有限状态机持有者。
/// 有限状态机状态集合。
/// 创建的有限状态机。
public static Fsm Create(string name, T owner, List> states)
{
if (owner == null)
{
throw new GameFrameworkException("FSM owner is invalid.");
}
if (states == null || states.Count < 1)
{
throw new GameFrameworkException("FSM states is invalid.");
}
Fsm fsm = MemoryPool.Acquire>();
fsm.Name = name;
fsm._owner = owner;
fsm._isDestroyed = false;
foreach (FsmState state in states)
{
if (state == null)
{
throw new GameFrameworkException("FSM states is invalid.");
}
Type stateType = state.GetType();
if (fsm._states.ContainsKey(stateType))
{
throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' state '{1}' is already exist.", new TypeNamePair(typeof(T), name), stateType.FullName));
}
fsm._states.Add(stateType, state);
state.OnInit(fsm);
}
return fsm;
}
///
/// 清理有限状态机。
///
public void Clear()
{
if (_currentState != null)
{
_currentState.OnLeave(this, true);
}
foreach (KeyValuePair> state in _states)
{
state.Value.OnDestroy(this);
}
Name = null;
_owner = null;
_states?.Clear();
_dataMap?.Clear();
_currentState = null;
_currentStateTime = 0f;
_isDestroyed = true;
}
///
/// 开始有限状态机。
///
/// 要开始的有限状态机状态类型。
public void Start() where TState : FsmState
{
if (IsRunning)
{
throw new GameFrameworkException("FSM is running, can not start again.");
}
FsmState state = GetState();
if (state == null)
{
throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' can not start state '{1}' which is not exist.", new TypeNamePair(typeof(T), Name), typeof(TState).FullName));
}
_currentStateTime = 0f;
_currentState = state;
_currentState.OnEnter(this);
}
///
/// 开始有限状态机。
///
/// 要开始的有限状态机状态类型。
public void Start(Type stateType)
{
if (IsRunning)
{
throw new GameFrameworkException("FSM is running, can not start again.");
}
if (stateType == null)
{
throw new GameFrameworkException("State type is invalid.");
}
if (!typeof(FsmState).IsAssignableFrom(stateType))
{
throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName));
}
FsmState state = GetState(stateType);
if (state == null)
{
throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' can not start state '{1}' which is not exist.", new TypeNamePair(typeof(T), Name), stateType.FullName));
}
_currentStateTime = 0f;
_currentState = state;
_currentState.OnEnter(this);
}
///
/// 是否存在有限状态机状态。
///
/// 要检查的有限状态机状态类型。
/// 是否存在有限状态机状态。
public bool HasState() where TState : FsmState
{
return _states.ContainsKey(typeof(TState));
}
///
/// 是否存在有限状态机状态。
///
/// 要检查的有限状态机状态类型。
/// 是否存在有限状态机状态。
public bool HasState(Type stateType)
{
if (stateType == null)
{
throw new GameFrameworkException("State type is invalid.");
}
if (!typeof(FsmState).IsAssignableFrom(stateType))
{
throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName));
}
return _states.ContainsKey(stateType);
}
///
/// 获取有限状态机状态。
///
/// 要获取的有限状态机状态类型。
/// 要获取的有限状态机状态。
public TState GetState() where TState : FsmState
{
FsmState state = null;
if (_states.TryGetValue(typeof(TState), out state))
{
return (TState)state;
}
return null;
}
///
/// 获取有限状态机状态。
///
/// 要获取的有限状态机状态类型。
/// 要获取的有限状态机状态。
public FsmState GetState(Type stateType)
{
if (stateType == null)
{
throw new GameFrameworkException("State type is invalid.");
}
if (!typeof(FsmState).IsAssignableFrom(stateType))
{
throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName));
}
FsmState state = null;
if (_states.TryGetValue(stateType, out state))
{
return state;
}
return null;
}
///
/// 获取有限状态机的所有状态。
///
/// 有限状态机的所有状态。
public FsmState[] GetAllStates()
{
int index = 0;
FsmState[] results = new FsmState[_states.Count];
foreach (KeyValuePair> state in _states)
{
results[index++] = state.Value;
}
return results;
}
///
/// 获取有限状态机的所有状态。
///
/// 有限状态机的所有状态。
public void GetAllStates(List> results)
{
if (results == null)
{
throw new GameFrameworkException("Results is invalid.");
}
results.Clear();
foreach (KeyValuePair> state in _states)
{
results.Add(state.Value);
}
}
///
/// 是否存在有限状态机数据。
///
/// 有限状态机数据名称。
/// 有限状态机数据是否存在。
public bool HasData(string name)
{
if (string.IsNullOrEmpty(name))
{
throw new GameFrameworkException("Data name is invalid.");
}
if (_dataMap == null)
{
return false;
}
return _dataMap.ContainsKey(name);
}
///
/// 获取有限状态机数据。
///
/// 要获取的有限状态机数据的类型。
/// 有限状态机数据名称。
/// 要获取的有限状态机数据。
public TData GetData(string name)
{
return (TData)GetData(name);
}
///
/// 获取有限状态机数据。
///
/// 有限状态机数据名称。
/// 要获取的有限状态机数据。
public object GetData(string name)
{
if (string.IsNullOrEmpty(name))
{
throw new GameFrameworkException("Data name is invalid.");
}
if (_dataMap == null)
{
return null;
}
if (_dataMap.TryGetValue(name, out var data))
{
return data;
}
return null;
}
///
/// 设置有限状态机数据。
///
/// 要设置的有限状态机数据的类型。
/// 有限状态机数据名称。
/// 要设置的有限状态机数据。
public void SetData(string name, TData data)
{
SetData(name, (object)data);
}
///
/// 设置有限状态机数据。
///
/// 有限状态机数据名称。
/// 要设置的有限状态机数据。
public void SetData(string name, object data)
{
if (string.IsNullOrEmpty(name))
{
throw new GameFrameworkException("Data name is invalid.");
}
if (_dataMap == null)
{
_dataMap = new Dictionary(StringComparer.Ordinal);
}
_dataMap[name] = data;
}
///
/// 移除有限状态机数据。
///
/// 有限状态机数据名称。
/// 是否移除有限状态机数据成功。
public bool RemoveData(string name)
{
if (string.IsNullOrEmpty(name))
{
throw new GameFrameworkException("Data name is invalid.");
}
if (_dataMap == null)
{
return false;
}
return _dataMap.Remove(name);
}
///
/// 有限状态机轮询。
///
/// 逻辑流逝时间,以秒为单位。
/// 真实流逝时间,以秒为单位。
internal override void Update(float elapseSeconds, float realElapseSeconds)
{
if (_currentState == null)
{
return;
}
_currentStateTime += elapseSeconds;
_currentState.OnUpdate(this, elapseSeconds, realElapseSeconds);
}
///
/// 关闭并清理有限状态机。
///
internal override void Shutdown()
{
MemoryPool.Release(this);
}
///
/// 切换当前有限状态机状态。
///
/// 要切换到的有限状态机状态类型。
internal void ChangeState() where TState : FsmState
{
ChangeState(typeof(TState));
}
///
/// 切换当前有限状态机状态。
///
/// 要切换到的有限状态机状态类型。
internal void ChangeState(Type stateType)
{
if (_currentState == null)
{
throw new GameFrameworkException("Current state is invalid.");
}
FsmState state = GetState(stateType);
if (state == null)
{
throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' can not change state to '{1}' which is not exist.", new TypeNamePair(typeof(T), Name), stateType.FullName));
}
_currentState.OnLeave(this, false);
_currentStateTime = 0f;
_currentState = state;
_currentState.OnEnter(this);
}
}
}