using System; using System.Buffers; using System.Collections.Generic; namespace AlicizaX { public static class ModuleSystem { internal const int DesignModuleCount = 32; private static readonly Dictionary _moduleMaps = new Dictionary(DesignModuleCount); private static readonly GameFrameworkLinkedList _modules = new GameFrameworkLinkedList(); // Update systems private static readonly GameFrameworkLinkedList _updateModules = new GameFrameworkLinkedList(); private static readonly IModuleUpdate[] _updateExecuteArray = new IModuleUpdate[DesignModuleCount]; private static int _updateExecuteCount; // LateUpdate systems private static readonly GameFrameworkLinkedList _lateUpdateModules = new GameFrameworkLinkedList(); private static readonly IModuleLateUpdate[] _lateUpdateExecuteArray = new IModuleLateUpdate[DesignModuleCount]; private static int _lateUpdateExecuteCount; // FixedUpdate systems private static readonly GameFrameworkLinkedList _fixedUpdateModules = new GameFrameworkLinkedList(); private static readonly IModuleFixedUpdate[] _fixedUpdateExecuteArray = new IModuleFixedUpdate[DesignModuleCount]; private static int _fixedUpdateExecuteCount; // Gizmos systems private static readonly GameFrameworkLinkedList _gizmosUpdateModules = new GameFrameworkLinkedList(); private static readonly IModuleDrawGizmos[] _gizmosUpdateExecuteArray = new IModuleDrawGizmos[DesignModuleCount]; private static int _gizmosExecuteCount; // GUI systems private static readonly GameFrameworkLinkedList _guiUpdateModules = new GameFrameworkLinkedList(); 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() 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() 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() 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(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 system, GameFrameworkLinkedList 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 } }