329 lines
11 KiB
C#
329 lines
11 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>();
|
|
|
|
// Update systems
|
|
private static readonly GameFrameworkLinkedList<IModuleUpdate> _updateModules = new GameFrameworkLinkedList<IModuleUpdate>();
|
|
private static readonly IModuleUpdate[] _updateExecuteArray = new IModuleUpdate[DesignModuleCount];
|
|
private static int _updateExecuteCount;
|
|
|
|
// LateUpdate systems
|
|
private static readonly GameFrameworkLinkedList<IModuleLateUpdate> _lateUpdateModules = new GameFrameworkLinkedList<IModuleLateUpdate>();
|
|
private static readonly IModuleLateUpdate[] _lateUpdateExecuteArray = new IModuleLateUpdate[DesignModuleCount];
|
|
private static int _lateUpdateExecuteCount;
|
|
|
|
// FixedUpdate systems
|
|
private static readonly GameFrameworkLinkedList<IModuleFixedUpdate> _fixedUpdateModules = new GameFrameworkLinkedList<IModuleFixedUpdate>();
|
|
private static readonly IModuleFixedUpdate[] _fixedUpdateExecuteArray = new IModuleFixedUpdate[DesignModuleCount];
|
|
private static int _fixedUpdateExecuteCount;
|
|
|
|
// Gizmos systems
|
|
private static readonly GameFrameworkLinkedList<IModuleDrawGizmos> _gizmosUpdateModules = new GameFrameworkLinkedList<IModuleDrawGizmos>();
|
|
private static readonly IModuleDrawGizmos[] _gizmosUpdateExecuteArray = new IModuleDrawGizmos[DesignModuleCount];
|
|
private static int _gizmosExecuteCount;
|
|
|
|
// GUI systems
|
|
private static readonly GameFrameworkLinkedList<IModuleGUI> _guiUpdateModules = new GameFrameworkLinkedList<IModuleGUI>();
|
|
private static readonly IModuleGUI[] _guiUpdateExecuteArray = new IModuleGUI[DesignModuleCount];
|
|
private static int _guiExecuteCount;
|
|
|
|
// Dirty flags
|
|
private static bool _isExecuteListDirty;
|
|
private static bool _isLateExecuteListDirty;
|
|
private static bool _isFixedExecuteListDirty;
|
|
private static bool _isGizmosExecuteListDirty;
|
|
private static bool _isGUIExecuteListDirty;
|
|
|
|
internal static void Dispose()
|
|
{
|
|
// Clear all modules and execute arrays
|
|
_updateModules.Clear();
|
|
Array.Clear(_updateExecuteArray, 0, _updateExecuteArray.Length);
|
|
_updateExecuteCount = 0;
|
|
|
|
_lateUpdateModules.Clear();
|
|
Array.Clear(_lateUpdateExecuteArray, 0, _lateUpdateExecuteArray.Length);
|
|
_lateUpdateExecuteCount = 0;
|
|
|
|
_fixedUpdateModules.Clear();
|
|
Array.Clear(_fixedUpdateExecuteArray, 0, _fixedUpdateExecuteArray.Length);
|
|
_fixedUpdateExecuteCount = 0;
|
|
|
|
_gizmosUpdateModules.Clear();
|
|
Array.Clear(_gizmosUpdateExecuteArray, 0, _gizmosUpdateExecuteArray.Length);
|
|
_gizmosExecuteCount = 0;
|
|
|
|
_guiUpdateModules.Clear();
|
|
Array.Clear(_guiUpdateExecuteArray, 0, _guiUpdateExecuteArray.Length);
|
|
_guiExecuteCount = 0;
|
|
|
|
// Dispose all modules
|
|
for (var 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, TImple>() where T : IModule where TImple : class, T, new()
|
|
{
|
|
Type interfaceType = typeof(T);
|
|
Type implType = typeof(TImple);
|
|
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("Module must implement IModule.", interfaceType.FullName));
|
|
}
|
|
|
|
if (GetModule(interfaceType) != null)
|
|
{
|
|
Log.Error("Already Register {0}", interfaceType.FullName);
|
|
return default;
|
|
}
|
|
|
|
TImple impl = new TImple();
|
|
return (T)SetModuleInstance(interfaceType, impl);
|
|
}
|
|
|
|
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)
|
|
{
|
|
return _moduleMaps.TryGetValue(moduleType, out var ret) ? ret : default;
|
|
}
|
|
|
|
private static IModule SetModuleInstance<TImpl>(Type interfaceType, TImpl impl) where TImpl : class, IModule
|
|
{
|
|
_moduleMaps[interfaceType] = impl;
|
|
_modules.AddLast(impl);
|
|
|
|
if (impl is IModuleAwake awakeSystem)
|
|
{
|
|
awakeSystem.Awake();
|
|
}
|
|
|
|
CheckSystemLife(impl);
|
|
return impl;
|
|
}
|
|
|
|
#endregion
|
|
|
|
private static void CheckSystemLife(IModule module)
|
|
{
|
|
if (module is IModuleUpdate updateSystem)
|
|
{
|
|
BindSystemLife(updateSystem, _updateModules, ref _isExecuteListDirty);
|
|
}
|
|
|
|
if (module is IModuleLateUpdate lateUpdate)
|
|
{
|
|
BindSystemLife(lateUpdate, _lateUpdateModules, ref _isLateExecuteListDirty);
|
|
}
|
|
|
|
if (module is IModuleFixedUpdate fixedUpdate)
|
|
{
|
|
BindSystemLife(fixedUpdate, _fixedUpdateModules, ref _isFixedExecuteListDirty);
|
|
}
|
|
|
|
if (module is IModuleDrawGizmos drawGizmosUpdate)
|
|
{
|
|
BindSystemLife(drawGizmosUpdate, _gizmosUpdateModules, ref _isGizmosExecuteListDirty);
|
|
}
|
|
|
|
if (module is IModuleGUI guiUpdate)
|
|
{
|
|
BindSystemLife(guiUpdate, _guiUpdateModules, ref _isGUIExecuteListDirty);
|
|
}
|
|
}
|
|
|
|
private static void BindSystemLife<T>(T system, GameFrameworkLinkedList<T> updateModule, ref bool executeDirty) where T : IExecuteSystem
|
|
{
|
|
var current = updateModule.First;
|
|
while (current != null && system.Priority <= current.Value.Priority)
|
|
{
|
|
current = current.Next;
|
|
}
|
|
|
|
if (current != null)
|
|
{
|
|
updateModule.AddBefore(current, system);
|
|
}
|
|
else
|
|
{
|
|
updateModule.AddLast(system);
|
|
}
|
|
|
|
executeDirty = true;
|
|
}
|
|
|
|
#region BuildExecuteList
|
|
|
|
private static void BuildExecuteList()
|
|
{
|
|
if (!_isExecuteListDirty) return;
|
|
_isExecuteListDirty = false;
|
|
_updateExecuteCount = 0;
|
|
foreach (var module in _updateModules)
|
|
{
|
|
if (_updateExecuteCount >= _updateExecuteArray.Length) break;
|
|
_updateExecuteArray[_updateExecuteCount++] = module;
|
|
}
|
|
}
|
|
|
|
private static void BuildLateExecuteList()
|
|
{
|
|
if (!_isLateExecuteListDirty) return;
|
|
_isLateExecuteListDirty = false;
|
|
_lateUpdateExecuteCount = 0;
|
|
foreach (var module in _lateUpdateModules)
|
|
{
|
|
if (_lateUpdateExecuteCount >= _lateUpdateExecuteArray.Length) break;
|
|
_lateUpdateExecuteArray[_lateUpdateExecuteCount++] = module;
|
|
}
|
|
}
|
|
|
|
private static void BuildFixedExecuteList()
|
|
{
|
|
if (!_isFixedExecuteListDirty) return;
|
|
_isFixedExecuteListDirty = false;
|
|
_fixedUpdateExecuteCount = 0;
|
|
foreach (var module in _fixedUpdateModules)
|
|
{
|
|
if (_fixedUpdateExecuteCount >= _fixedUpdateExecuteArray.Length) break;
|
|
_fixedUpdateExecuteArray[_fixedUpdateExecuteCount++] = module;
|
|
}
|
|
}
|
|
|
|
private static void BuildGizmosExecuteList()
|
|
{
|
|
if (!_isGizmosExecuteListDirty) return;
|
|
_isGizmosExecuteListDirty = false;
|
|
_gizmosExecuteCount = 0;
|
|
foreach (var module in _gizmosUpdateModules)
|
|
{
|
|
if (_gizmosExecuteCount >= _gizmosUpdateExecuteArray.Length) break;
|
|
_gizmosUpdateExecuteArray[_gizmosExecuteCount++] = module;
|
|
}
|
|
}
|
|
|
|
private static void BuildGUIExecuteList()
|
|
{
|
|
if (!_isGUIExecuteListDirty) return;
|
|
_isGUIExecuteListDirty = false;
|
|
_guiExecuteCount = 0;
|
|
foreach (var module in _guiUpdateModules)
|
|
{
|
|
if (_guiExecuteCount >= _guiUpdateExecuteArray.Length) break;
|
|
_guiUpdateExecuteArray[_guiExecuteCount++] = module;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RunExecuteList
|
|
|
|
internal static void UpdateExecuteList(float elapseSeconds, float realElapseSeconds)
|
|
{
|
|
BuildExecuteList();
|
|
for (int i = 0; i < _updateExecuteCount; i++)
|
|
{
|
|
_updateExecuteArray[i].Update(elapseSeconds, realElapseSeconds);
|
|
}
|
|
}
|
|
|
|
internal static void UpdateLateExecuteList()
|
|
{
|
|
BuildLateExecuteList();
|
|
for (int i = 0; i < _lateUpdateExecuteCount; i++)
|
|
{
|
|
_lateUpdateExecuteArray[i].LateUpdate();
|
|
}
|
|
}
|
|
|
|
internal static void UpdateFixedExecuteList()
|
|
{
|
|
BuildFixedExecuteList();
|
|
for (int i = 0; i < _fixedUpdateExecuteCount; i++)
|
|
{
|
|
_fixedUpdateExecuteArray[i].FixedUpdate();
|
|
}
|
|
}
|
|
|
|
internal static void UpdateGizmosExecuteList()
|
|
{
|
|
BuildGizmosExecuteList();
|
|
for (int i = 0; i < _gizmosExecuteCount; i++)
|
|
{
|
|
_gizmosUpdateExecuteArray[i].DrawGizmos();
|
|
}
|
|
}
|
|
|
|
internal static void UpdateGUIExecuteList()
|
|
{
|
|
BuildGUIExecuteList();
|
|
for (int i = 0; i < _guiExecuteCount; i++)
|
|
{
|
|
_guiUpdateExecuteArray[i].OnGUI();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|