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