流程管理模块

流程管理模块
This commit is contained in:
ALEXTANG
2023-04-05 11:06:06 +08:00
parent ee9fb75407
commit ba7b635bd1
12 changed files with 655 additions and 0 deletions

View File

@@ -0,0 +1,163 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace TEngine.Editor.Inspector
{
[CustomEditor(typeof(ProcedureModule))]
internal sealed class ProcedureModuleInspector : GameFrameworkInspector
{
private SerializedProperty m_AvailableProcedureTypeNames = null;
private SerializedProperty m_EntranceProcedureTypeName = null;
private string[] m_ProcedureTypeNames = null;
private List<string> m_CurrentAvailableProcedureTypeNames = null;
private int m_EntranceProcedureIndex = -1;
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
serializedObject.Update();
ProcedureModule t = (ProcedureModule)target;
if (string.IsNullOrEmpty(m_EntranceProcedureTypeName.stringValue))
{
EditorGUILayout.HelpBox("Entrance procedure is invalid.", MessageType.Error);
}
else if (EditorApplication.isPlaying)
{
EditorGUILayout.LabelField("Current Procedure", t.CurrentProcedure == null ? "None" : t.CurrentProcedure.GetType().ToString());
}
EditorGUI.BeginDisabledGroup(EditorApplication.isPlayingOrWillChangePlaymode);
{
GUILayout.Label("Available Procedures", EditorStyles.boldLabel);
if (m_ProcedureTypeNames.Length > 0)
{
EditorGUILayout.BeginVertical("box");
{
foreach (string procedureTypeName in m_ProcedureTypeNames)
{
bool selected = m_CurrentAvailableProcedureTypeNames.Contains(procedureTypeName);
if (selected != EditorGUILayout.ToggleLeft(procedureTypeName, selected))
{
if (!selected)
{
m_CurrentAvailableProcedureTypeNames.Add(procedureTypeName);
WriteAvailableProcedureTypeNames();
}
else if (procedureTypeName != m_EntranceProcedureTypeName.stringValue)
{
m_CurrentAvailableProcedureTypeNames.Remove(procedureTypeName);
WriteAvailableProcedureTypeNames();
}
}
}
}
EditorGUILayout.EndVertical();
}
else
{
EditorGUILayout.HelpBox("There is no available procedure.", MessageType.Warning);
}
if (m_CurrentAvailableProcedureTypeNames.Count > 0)
{
EditorGUILayout.Separator();
int selectedIndex = EditorGUILayout.Popup("Entrance Procedure", m_EntranceProcedureIndex, m_CurrentAvailableProcedureTypeNames.ToArray());
if (selectedIndex != m_EntranceProcedureIndex)
{
m_EntranceProcedureIndex = selectedIndex;
m_EntranceProcedureTypeName.stringValue = m_CurrentAvailableProcedureTypeNames[selectedIndex];
}
}
else
{
EditorGUILayout.HelpBox("Select available procedures first.", MessageType.Info);
}
}
EditorGUI.EndDisabledGroup();
serializedObject.ApplyModifiedProperties();
Repaint();
}
protected override void OnCompileComplete()
{
base.OnCompileComplete();
RefreshTypeNames();
}
private void OnEnable()
{
m_AvailableProcedureTypeNames = serializedObject.FindProperty("m_AvailableProcedureTypeNames");
m_EntranceProcedureTypeName = serializedObject.FindProperty("m_EntranceProcedureTypeName");
RefreshTypeNames();
}
private void RefreshTypeNames()
{
m_ProcedureTypeNames = Type.GetRuntimeTypeNames(typeof(ProcedureBase));
ReadAvailableProcedureTypeNames();
int oldCount = m_CurrentAvailableProcedureTypeNames.Count;
m_CurrentAvailableProcedureTypeNames = m_CurrentAvailableProcedureTypeNames.Where(x => m_ProcedureTypeNames.Contains(x)).ToList();
if (m_CurrentAvailableProcedureTypeNames.Count != oldCount)
{
WriteAvailableProcedureTypeNames();
}
else if (!string.IsNullOrEmpty(m_EntranceProcedureTypeName.stringValue))
{
m_EntranceProcedureIndex = m_CurrentAvailableProcedureTypeNames.IndexOf(m_EntranceProcedureTypeName.stringValue);
if (m_EntranceProcedureIndex < 0)
{
m_EntranceProcedureTypeName.stringValue = null;
}
}
serializedObject.ApplyModifiedProperties();
}
private void ReadAvailableProcedureTypeNames()
{
m_CurrentAvailableProcedureTypeNames = new List<string>();
int count = m_AvailableProcedureTypeNames.arraySize;
for (int i = 0; i < count; i++)
{
m_CurrentAvailableProcedureTypeNames.Add(m_AvailableProcedureTypeNames.GetArrayElementAtIndex(i).stringValue);
}
}
private void WriteAvailableProcedureTypeNames()
{
m_AvailableProcedureTypeNames.ClearArray();
if (m_CurrentAvailableProcedureTypeNames == null)
{
return;
}
m_CurrentAvailableProcedureTypeNames.Sort();
int count = m_CurrentAvailableProcedureTypeNames.Count;
for (int i = 0; i < count; i++)
{
m_AvailableProcedureTypeNames.InsertArrayElementAtIndex(i);
m_AvailableProcedureTypeNames.GetArrayElementAtIndex(i).stringValue = m_CurrentAvailableProcedureTypeNames[i];
}
if (!string.IsNullOrEmpty(m_EntranceProcedureTypeName.stringValue))
{
m_EntranceProcedureIndex = m_CurrentAvailableProcedureTypeNames.IndexOf(m_EntranceProcedureTypeName.stringValue);
if (m_EntranceProcedureIndex < 0)
{
m_EntranceProcedureTypeName.stringValue = null;
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f8c879b84e1b47bc87f3f0f8b547dfb2
timeCreated: 1680663412

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ed454120d9944420baccd99a443c7fd8
timeCreated: 1680663217

View File

@@ -0,0 +1,73 @@
using System;
namespace TEngine
{
/// <summary>
/// 流程管理器接口。
/// </summary>
public interface IProcedureManager
{
/// <summary>
/// 获取当前流程。
/// </summary>
ProcedureBase CurrentProcedure
{
get;
}
/// <summary>
/// 获取当前流程持续时间。
/// </summary>
float CurrentProcedureTime
{
get;
}
/// <summary>
/// 初始化流程管理器。
/// </summary>
/// <param name="fsmManager">有限状态机管理器。</param>
/// <param name="procedures">流程管理器包含的流程。</param>
void Initialize(IFsmManager fsmManager, params ProcedureBase[] procedures);
/// <summary>
/// 开始流程。
/// </summary>
/// <typeparam name="T">要开始的流程类型。</typeparam>
void StartProcedure<T>() where T : ProcedureBase;
/// <summary>
/// 开始流程。
/// </summary>
/// <param name="procedureType">要开始的流程类型。</param>
void StartProcedure(Type procedureType);
/// <summary>
/// 是否存在流程。
/// </summary>
/// <typeparam name="T">要检查的流程类型。</typeparam>
/// <returns>是否存在流程。</returns>
bool HasProcedure<T>() where T : ProcedureBase;
/// <summary>
/// 是否存在流程。
/// </summary>
/// <param name="procedureType">要检查的流程类型。</param>
/// <returns>是否存在流程。</returns>
bool HasProcedure(Type procedureType);
/// <summary>
/// 获取流程。
/// </summary>
/// <typeparam name="T">要获取的流程类型。</typeparam>
/// <returns>要获取的流程。</returns>
ProcedureBase GetProcedure<T>() where T : ProcedureBase;
/// <summary>
/// 获取流程。
/// </summary>
/// <param name="procedureType">要获取的流程类型。</param>
/// <returns>要获取的流程。</returns>
ProcedureBase GetProcedure(Type procedureType);
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5dd7530db77a4e9dac3f40e30aa05cb0
timeCreated: 1680663217

View File

@@ -0,0 +1,58 @@
using ProcedureOwner = TEngine.IFsm<TEngine.IProcedureManager>;
namespace TEngine
{
/// <summary>
/// 流程基类。
/// </summary>
public abstract class ProcedureBase : FsmState<IProcedureManager>
{
/// <summary>
/// 状态初始化时调用。
/// </summary>
/// <param name="procedureOwner">流程持有者。</param>
protected internal override void OnInit(ProcedureOwner procedureOwner)
{
base.OnInit(procedureOwner);
}
/// <summary>
/// 进入状态时调用。
/// </summary>
/// <param name="procedureOwner">流程持有者。</param>
protected internal override void OnEnter(ProcedureOwner procedureOwner)
{
base.OnEnter(procedureOwner);
}
/// <summary>
/// 状态轮询时调用。
/// </summary>
/// <param name="procedureOwner">流程持有者。</param>
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
protected internal override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
}
/// <summary>
/// 离开状态时调用。
/// </summary>
/// <param name="procedureOwner">流程持有者。</param>
/// <param name="isShutdown">是否是关闭状态机时触发。</param>
protected internal override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown)
{
base.OnLeave(procedureOwner, isShutdown);
}
/// <summary>
/// 状态销毁时调用。
/// </summary>
/// <param name="procedureOwner">流程持有者。</param>
protected internal override void OnDestroy(ProcedureOwner procedureOwner)
{
base.OnDestroy(procedureOwner);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: eb8b31eea6d2468f8a717e780d44844f
timeCreated: 1680663217

View File

@@ -0,0 +1,193 @@
using System;
namespace TEngine
{
/// <summary>
/// 流程管理器。
/// </summary>
internal sealed class ProcedureManager : GameFrameworkModule, IProcedureManager
{
private IFsmManager m_FsmManager;
private IFsm<IProcedureManager> m_ProcedureFsm;
/// <summary>
/// 初始化流程管理器的新实例。
/// </summary>
public ProcedureManager()
{
m_FsmManager = null;
m_ProcedureFsm = null;
}
/// <summary>
/// 获取游戏框架模块优先级。
/// </summary>
/// <remarks>优先级较高的模块会优先轮询,并且关闭操作会后进行。</remarks>
internal override int Priority
{
get { return -2; }
}
/// <summary>
/// 获取当前流程。
/// </summary>
public ProcedureBase CurrentProcedure
{
get
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
return (ProcedureBase)m_ProcedureFsm.CurrentState;
}
}
/// <summary>
/// 获取当前流程持续时间。
/// </summary>
public float CurrentProcedureTime
{
get
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
return m_ProcedureFsm.CurrentStateTime;
}
}
/// <summary>
/// 流程管理器轮询。
/// </summary>
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
internal override void Update(float elapseSeconds, float realElapseSeconds)
{
}
/// <summary>
/// 关闭并清理流程管理器。
/// </summary>
internal override void Shutdown()
{
if (m_FsmManager != null)
{
if (m_ProcedureFsm != null)
{
m_FsmManager.DestroyFsm(m_ProcedureFsm);
m_ProcedureFsm = null;
}
m_FsmManager = null;
}
}
/// <summary>
/// 初始化流程管理器。
/// </summary>
/// <param name="fsmManager">有限状态机管理器。</param>
/// <param name="procedures">流程管理器包含的流程。</param>
public void Initialize(IFsmManager fsmManager, params ProcedureBase[] procedures)
{
if (fsmManager == null)
{
throw new GameFrameworkException("FSM manager is invalid.");
}
m_FsmManager = fsmManager;
m_ProcedureFsm = m_FsmManager.CreateFsm(this, procedures);
}
/// <summary>
/// 开始流程。
/// </summary>
/// <typeparam name="T">要开始的流程类型。</typeparam>
public void StartProcedure<T>() where T : ProcedureBase
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
m_ProcedureFsm.Start<T>();
}
/// <summary>
/// 开始流程。
/// </summary>
/// <param name="procedureType">要开始的流程类型。</param>
public void StartProcedure(Type procedureType)
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
m_ProcedureFsm.Start(procedureType);
}
/// <summary>
/// 是否存在流程。
/// </summary>
/// <typeparam name="T">要检查的流程类型。</typeparam>
/// <returns>是否存在流程。</returns>
public bool HasProcedure<T>() where T : ProcedureBase
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
return m_ProcedureFsm.HasState<T>();
}
/// <summary>
/// 是否存在流程。
/// </summary>
/// <param name="procedureType">要检查的流程类型。</param>
/// <returns>是否存在流程。</returns>
public bool HasProcedure(Type procedureType)
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
return m_ProcedureFsm.HasState(procedureType);
}
/// <summary>
/// 获取流程。
/// </summary>
/// <typeparam name="T">要获取的流程类型。</typeparam>
/// <returns>要获取的流程。</returns>
public ProcedureBase GetProcedure<T>() where T : ProcedureBase
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
return m_ProcedureFsm.GetState<T>();
}
/// <summary>
/// 获取流程。
/// </summary>
/// <param name="procedureType">要获取的流程类型。</param>
/// <returns>要获取的流程。</returns>
public ProcedureBase GetProcedure(Type procedureType)
{
if (m_ProcedureFsm == null)
{
throw new GameFrameworkException("You must initialize procedure first.");
}
return (ProcedureBase)m_ProcedureFsm.GetState(procedureType);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: efb3019410a04559a5d3b39f9435d519
timeCreated: 1680663217

View File

@@ -0,0 +1,144 @@
using System;
using System.Collections;
using UnityEngine;
namespace TEngine
{
/// <summary>
/// 流程管理模块。
/// </summary>
[DisallowMultipleComponent]
public sealed class ProcedureModule : GameFrameworkModuleBase
{
private IProcedureManager m_ProcedureManager = null;
private ProcedureBase m_EntranceProcedure = null;
[SerializeField]
private string[] m_AvailableProcedureTypeNames = null;
[SerializeField]
private string m_EntranceProcedureTypeName = null;
/// <summary>
/// 获取当前流程。
/// </summary>
public ProcedureBase CurrentProcedure
{
get
{
if (m_ProcedureManager == null)
{
return null;
}
return m_ProcedureManager.CurrentProcedure;
}
}
/// <summary>
/// 获取当前流程持续时间。
/// </summary>
public float CurrentProcedureTime
{
get
{
if (m_ProcedureManager == null)
{
return 0f;
}
return m_ProcedureManager.CurrentProcedureTime;
}
}
/// <summary>
/// 游戏框架模块初始化。
/// </summary>
protected override void Awake()
{
base.Awake();
m_ProcedureManager = GameFrameworkEntry.GetModule<IProcedureManager>();
if (m_ProcedureManager == null)
{
Log.Fatal("Procedure manager is invalid.");
}
}
private IEnumerator Start()
{
ProcedureBase[] procedures = new ProcedureBase[m_AvailableProcedureTypeNames.Length];
for (int i = 0; i < m_AvailableProcedureTypeNames.Length; i++)
{
Type procedureType = Utility.Assembly.GetType(m_AvailableProcedureTypeNames[i]);
if (procedureType == null)
{
Log.Error("Can not find procedure type '{0}'.", m_AvailableProcedureTypeNames[i]);
yield break;
}
procedures[i] = (ProcedureBase)Activator.CreateInstance(procedureType);
if (procedures[i] == null)
{
Log.Error("Can not create procedure instance '{0}'.", m_AvailableProcedureTypeNames[i]);
yield break;
}
if (m_EntranceProcedureTypeName == m_AvailableProcedureTypeNames[i])
{
m_EntranceProcedure = procedures[i];
}
}
if (m_EntranceProcedure == null)
{
Log.Error("Entrance procedure is invalid.");
yield break;
}
m_ProcedureManager.Initialize(GameFrameworkEntry.GetModule<IFsmManager>(), procedures);
yield return new WaitForEndOfFrame();
m_ProcedureManager.StartProcedure(m_EntranceProcedure.GetType());
}
/// <summary>
/// 是否存在流程。
/// </summary>
/// <typeparam name="T">要检查的流程类型。</typeparam>
/// <returns>是否存在流程。</returns>
public bool HasProcedure<T>() where T : ProcedureBase
{
return m_ProcedureManager.HasProcedure<T>();
}
/// <summary>
/// 是否存在流程。
/// </summary>
/// <param name="procedureType">要检查的流程类型。</param>
/// <returns>是否存在流程。</returns>
public bool HasProcedure(Type procedureType)
{
return m_ProcedureManager.HasProcedure(procedureType);
}
/// <summary>
/// 获取流程。
/// </summary>
/// <typeparam name="T">要获取的流程类型。</typeparam>
/// <returns>要获取的流程。</returns>
public ProcedureBase GetProcedure<T>() where T : ProcedureBase
{
return m_ProcedureManager.GetProcedure<T>();
}
/// <summary>
/// 获取流程。
/// </summary>
/// <param name="procedureType">要获取的流程类型。</param>
/// <returns>要获取的流程。</returns>
public ProcedureBase GetProcedure(Type procedureType)
{
return m_ProcedureManager.GetProcedure(procedureType);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1587cae710f84819b0056e98344f204d
timeCreated: 1680663317

View File

@@ -33,6 +33,11 @@ public class GameModule:MonoBehaviour
/// 获取资源模块。
/// </summary>
public static ResourceModule Resource { get; private set; }
/// <summary>
/// 流程管理模块。
/// </summary>
public static ProcedureModule Procedure { get; private set; }
/// <summary>
/// 获取配置模块。
@@ -56,6 +61,7 @@ public class GameModule:MonoBehaviour
Fsm = Get<FsmModule>();
ObjectPool = Get<ObjectPoolModule>();
Resource = Get<ResourceModule>();
Procedure = Get<ProcedureModule>();
Setting = Get<SettingModule>();
UI = Get<UIModule>();
}