com.alicizax.unity/Runtime/Base/Module/ModuleSystem.cs
2025-03-24 13:16:51 +08:00

343 lines
12 KiB
C#

using System;
using System.Buffers;
using System.Collections.Generic;
namespace AlicizaX
{
public static class ModuleSystem
{
internal const int DesignModuleCount = 32;
private static readonly Dictionary<Type, IModule> _moduleMaps = new Dictionary<Type, IModule>(DesignModuleCount);
private static readonly GameFrameworkLinkedList<IModule> _modules = new GameFrameworkLinkedList<IModule>();
private static readonly GameFrameworkLinkedList<IModuleUpdate> _updateModules = new GameFrameworkLinkedList<IModuleUpdate>();
private static readonly IModuleUpdate[] _updateExecuteArray = new IModuleUpdate[DesignModuleCount];
private static readonly GameFrameworkLinkedList<IModuleLateUpdate> _lateUpdateModules = new GameFrameworkLinkedList<IModuleLateUpdate>();
private static readonly IModuleLateUpdate[] _lateUpdateExecuteArray = new IModuleLateUpdate[DesignModuleCount];
private static readonly GameFrameworkLinkedList<IModuleFixedUpdate> _fixedUpdateModules = new GameFrameworkLinkedList<IModuleFixedUpdate>();
private static readonly IModuleFixedUpdate[] _fixedUpdateExecuteArray = new IModuleFixedUpdate[DesignModuleCount];
private static readonly GameFrameworkLinkedList<IModuleDrawGizmos> _gizmosUpdateModules = new GameFrameworkLinkedList<IModuleDrawGizmos>();
private static readonly IModuleDrawGizmos[] _gizmosUpdateExecuteArray = new IModuleDrawGizmos[DesignModuleCount];
private static readonly GameFrameworkLinkedList<IModuleGUI> _guiUpdateModules = new GameFrameworkLinkedList<IModuleGUI>();
private static readonly IModuleGUI[] _guiUpdateExecuteArray = new IModuleGUI[DesignModuleCount];
private static bool _isExecuteListDirty;
private static bool _isLateExecuteListDirty;
private static bool _isFixedExecuteListDirty;
private static bool _isGizmosExecuteListDirty;
private static bool _isGUIExecuteListDirty;
internal static void Dispose()
{
_updateModules.Clear();
Array.Clear(_updateExecuteArray, 0, _updateExecuteArray.Length);
_lateUpdateModules.Clear();
Array.Clear(_lateUpdateExecuteArray, 0, _lateUpdateExecuteArray.Length);
_fixedUpdateModules.Clear();
Array.Clear(_fixedUpdateExecuteArray, 0, _fixedUpdateExecuteArray.Length);
_gizmosUpdateModules.Clear();
Array.Clear(_gizmosUpdateExecuteArray, 0, _gizmosUpdateExecuteArray.Length);
_guiUpdateModules.Clear();
Array.Clear(_guiUpdateExecuteArray, 0, _guiUpdateExecuteArray.Length);
for (LinkedListNode<IModule> current = _modules.Last; current != null; current = current.Previous)
{
current.Value.Dispose();
}
_modules.Clear();
_moduleMaps.Clear();
}
#region Public Manager
public static T RegisterManager<T>() where T : AManager, new()
{
T manager = new T();
if (manager is IModuleAwake awakeManager)
{
awakeManager.Awake();
}
AddManager(manager);
return manager;
}
private static void AddManager(AManager manager)
{
Type type = manager.GetType();
_moduleMaps[type] = manager;
_modules.AddLast(manager);
manager.Register();
CheckSystemLife(manager);
}
#endregion
#region Public System
public static T RegisterModule<T>(Type implType)
{
return (T)RegisterModule(typeof(T), implType);
}
public static IModule RegisterModule(Type interfaceType, Type implType)
{
if (!interfaceType.IsInterface)
{
throw new GameFrameworkException(Utility.Text.Format("You must register module by interface, but '{0}' is not.", interfaceType.FullName));
}
if (!implType.IsClass || implType.IsInterface || implType.IsAbstract)
{
throw new GameFrameworkException(Utility.Text.Format("You must register module by Class and not Interface and Abstract, but '{0}' is not.", implType.FullName));
}
if (!typeof(IModule).IsAssignableFrom(interfaceType))
{
throw new GameFrameworkException(Utility.Text.Format("You must register module by Class and not Interface and Abstract, but '{0}' is not.", implType.FullName));
}
if (GetModule(interfaceType) != null)
{
Log.Error("Already Register {0}", interfaceType.FullName);
return default;
}
return SetModuleInstance(interfaceType, implType);
}
public static T GetModule<T>() where T : class
{
Type interfaceType = typeof(T);
if (!interfaceType.IsInterface)
{
throw new GameFrameworkException(Utility.Text.Format("You must get module by interface, but '{0}' is not.", interfaceType.FullName));
}
return GetModule(interfaceType) as T;
}
public static IModule GetModule(Type moduleType)
{
if (_moduleMaps.TryGetValue(moduleType, out var ret))
{
return ret;
}
return default;
}
private static IModule SetModuleInstance(Type interfaceType, Type implType)
{
IModule module = (IModule)Activator.CreateInstance(implType);
_moduleMaps[interfaceType] = module;
_modules.AddLast(module);
if (module is IModuleAwake awakeSystem)
{
awakeSystem.Awake();
}
CheckSystemLife(module);
return module;
}
#endregion
private static void CheckSystemLife(IModule module)
{
if (module is IModuleUpdate updateSystem)
{
BindSystemLife<IModuleUpdate>(updateSystem, _updateModules, ref _isExecuteListDirty);
}
if (module is IModuleLateUpdate lateUpdate)
{
BindSystemLife<IModuleLateUpdate>(lateUpdate, _lateUpdateModules, ref _isLateExecuteListDirty);
}
if (module is IModuleFixedUpdate fixedUpdate)
{
BindSystemLife<IModuleFixedUpdate>(fixedUpdate, _fixedUpdateModules, ref _isFixedExecuteListDirty);
}
if (module is IModuleDrawGizmos drawGizmosUpdate)
{
BindSystemLife<IModuleDrawGizmos>(drawGizmosUpdate, _gizmosUpdateModules, ref _isGizmosExecuteListDirty);
}
if (module is IModuleGUI guiUpdate)
{
BindSystemLife<IModuleGUI>(guiUpdate, _guiUpdateModules, ref _isGUIExecuteListDirty);
}
}
internal static void BindSystemLife<T>(T system, GameFrameworkLinkedList<T> updateModule, ref bool executeDirty) where T : IExecuteSystem
{
LinkedListNode<T> currentUpdate = updateModule.First;
while (currentUpdate != null)
{
if (system.Priority > currentUpdate.Value.Priority)
{
break;
}
currentUpdate = currentUpdate.Next;
}
if (currentUpdate != null)
{
updateModule.AddBefore(currentUpdate, system);
}
else
{
updateModule.AddLast(system);
}
executeDirty = true;
}
#region BuildExecuteList
private static void BuildExecuteList()
{
if (_isExecuteListDirty)
{
_isExecuteListDirty = false;
Array.Clear(_updateExecuteArray, 0, _updateExecuteArray.Length);
int index = 0;
foreach (var module in _updateModules)
{
_updateExecuteArray[index++] = module;
}
}
}
private static void BuildLateExecuteList()
{
if (_isLateExecuteListDirty)
{
_isLateExecuteListDirty = false;
Array.Clear(_lateUpdateExecuteArray, 0, _lateUpdateExecuteArray.Length);
int index = 0;
foreach (var module in _lateUpdateModules)
{
_lateUpdateExecuteArray[index++] = module;
}
}
}
private static void BuildFixedExecuteList()
{
if (_isFixedExecuteListDirty)
{
_isFixedExecuteListDirty = false;
Array.Clear(_fixedUpdateExecuteArray, 0, _fixedUpdateExecuteArray.Length);
int index = 0;
foreach (var module in _fixedUpdateModules)
{
_fixedUpdateExecuteArray[index++] = module;
}
}
}
private static void BuildGizmosExecuteList()
{
if (_isGizmosExecuteListDirty)
{
_isGizmosExecuteListDirty = false;
Array.Clear(_gizmosUpdateExecuteArray, 0, _gizmosUpdateExecuteArray.Length);
int index = 0;
foreach (var module in _gizmosUpdateModules)
{
_gizmosUpdateExecuteArray[index++] = module;
}
}
}
private static void BuildGUIExecuteList()
{
if (_isGUIExecuteListDirty)
{
_isGUIExecuteListDirty = false;
Array.Clear(_guiUpdateExecuteArray, 0, _guiUpdateExecuteArray.Length);
int index = 0;
foreach (var module in _guiUpdateModules)
{
_guiUpdateExecuteArray[index++] = module;
}
}
}
#endregion
#region RunExecuteList
internal static void UpdateExecuteList(float elapseSeconds, float realElapseSeconds)
{
BuildExecuteList();
int executeCount = _updateExecuteArray.Length;
for (int i = 0; i < executeCount; i++)
{
_updateExecuteArray[i]?.Update(elapseSeconds, realElapseSeconds);
}
}
internal static void UpdateLateExecuteList()
{
BuildLateExecuteList();
int executeCount = _lateUpdateExecuteArray.Length;
for (int i = 0; i < executeCount; i++)
{
_lateUpdateExecuteArray[i]?.LateUpdate();
}
}
internal static void UpdateFixedExecuteList()
{
BuildFixedExecuteList();
int executeCount = _fixedUpdateExecuteArray.Length;
for (int i = 0; i < executeCount; i++)
{
_fixedUpdateExecuteArray[i]?.FixedUpdate();
}
}
internal static void UpdateGizmosExecuteList()
{
BuildGizmosExecuteList();
int executeCount = _gizmosUpdateExecuteArray.Length;
for (int i = 0; i < executeCount; i++)
{
_gizmosUpdateExecuteArray[i]?.DrawGizmos();
}
}
internal static void UpdateGUIExecuteList()
{
BuildGUIExecuteList();
int executeCount = _guiUpdateExecuteArray.Length;
for (int i = 0; i < executeCount; i++)
{
_guiUpdateExecuteArray[i]?.OnGUI();
}
}
#endregion
}
}