2023-03-29 16:43:06 +08:00
using System ;
using System.Collections.Generic ;
using System.Reflection ;
namespace DCFApixels.DragonECS
{
2023-04-05 09:14:42 +08:00
internal static class DummyInstance < T >
{
public static T intsance = ( T ) Activator . CreateInstance ( typeof ( T ) ) ;
}
2023-03-29 16:43:06 +08:00
internal class AutoInjectionMap
{
2023-03-30 05:33:55 +08:00
private readonly EcsPipeline _source ;
2023-03-29 16:43:06 +08:00
private Dictionary < Type , List < FiledRecord > > _systems ;
2023-04-05 09:14:42 +08:00
private HashSet < Type > _notInjected ;
private Type dummyInstance = typeof ( DummyInstance < > ) ;
private bool _isDummyInjected = false ;
2023-03-29 16:43:06 +08:00
2023-03-30 05:33:55 +08:00
public AutoInjectionMap ( EcsPipeline source )
2023-03-29 16:43:06 +08:00
{
_source = source ;
var allsystems = _source . AllSystems ;
_systems = new Dictionary < Type , List < FiledRecord > > ( ) ;
2023-04-05 09:14:42 +08:00
_notInjected = new HashSet < Type > ( ) ;
2023-03-29 16:43:06 +08:00
foreach ( var system in allsystems )
{
Type systemType = system . GetType ( ) ;
foreach ( var field in systemType . GetFields ( BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic ) )
{
2023-05-07 00:50:23 +08:00
EcsInjectAttribute autoInjectAttribute = field . GetCustomAttribute < EcsInjectAttribute > ( ) ;
2023-04-05 09:14:42 +08:00
if ( autoInjectAttribute ! = null )
2023-03-29 16:43:06 +08:00
{
Type fieldType = field . FieldType ;
List < FiledRecord > list ;
if ( ! _systems . TryGetValue ( fieldType , out list ) )
{
list = new List < FiledRecord > ( ) ;
_systems . Add ( fieldType , list ) ;
}
2023-04-05 09:14:42 +08:00
list . Add ( new FiledRecord ( system , field , autoInjectAttribute ) ) ;
2023-03-29 16:43:06 +08:00
}
}
}
2023-04-05 09:14:42 +08:00
foreach ( var item in _systems . Keys )
{
_notInjected . Add ( item ) ;
}
2023-03-29 16:43:06 +08:00
}
public void Inject ( object obj )
{
2023-04-05 09:14:42 +08:00
_notInjected . Remove ( obj . GetType ( ) ) ;
2023-03-29 16:43:06 +08:00
Type objectType = obj . GetType ( ) ;
if ( _systems . TryGetValue ( objectType , out List < FiledRecord > list ) )
{
foreach ( var item in list )
{
item . field . SetValue ( item . target , obj ) ;
}
}
}
2023-04-05 09:14:42 +08:00
public void InjectDummy ( )
{
if ( _isDummyInjected )
return ;
_isDummyInjected = true ;
foreach ( var notInjectedItem in _notInjected )
{
foreach ( var systemRecord in _systems [ notInjectedItem ] )
{
if ( systemRecord . attribute . notNullDummyType = = null )
continue ;
if ( systemRecord . field . GetValue ( systemRecord . target ) ! = null )
continue ;
if ( systemRecord . field . FieldType . IsAssignableFrom ( systemRecord . attribute . notNullDummyType ) = = false )
{
EcsDebug . Print ( EcsConsts . DEBUG_ERROR_TAG , $"The {systemRecord.attribute.notNullDummyType} dummy cannot be assigned to the {systemRecord.field.FieldType.Name} field" ) ;
continue ;
}
systemRecord . field . SetValue ( systemRecord . target ,
dummyInstance . MakeGenericType ( systemRecord . attribute . notNullDummyType ) . GetField ( "intsance" , BindingFlags . Static | BindingFlags . Public ) . GetValue ( null ) ) ;
}
}
_notInjected . Clear ( ) ;
_notInjected = null ;
}
2023-03-29 16:43:06 +08:00
private readonly struct FiledRecord
{
public readonly IEcsSystem target ;
public readonly FieldInfo field ;
2023-05-07 00:50:23 +08:00
public readonly EcsInjectAttribute attribute ;
public FiledRecord ( IEcsSystem target , FieldInfo field , EcsInjectAttribute attribute )
2023-03-29 16:43:06 +08:00
{
this . target = target ;
this . field = field ;
2023-04-05 09:14:42 +08:00
this . attribute = attribute ;
2023-03-29 16:43:06 +08:00
}
}
}
[DebugHide, DebugColor(DebugColor.Gray)]
2023-05-07 00:50:23 +08:00
public class AutoInjectSystem : IEcsPreInitProcess , IEcsPreInject , IEcsPreInitInjectProcess
2023-03-29 16:43:06 +08:00
{
2023-03-30 05:33:55 +08:00
private EcsPipeline _pipeline ;
2023-03-29 16:43:06 +08:00
private List < object > _injectQueue = new List < object > ( ) ;
private AutoInjectionMap _autoInjectionMap ;
2023-04-05 09:14:42 +08:00
private bool _isPreInjectionComplete = false ;
2023-03-29 16:43:06 +08:00
public void PreInject ( object obj )
{
2023-03-30 05:33:55 +08:00
if ( _pipeline = = null )
2023-03-29 16:43:06 +08:00
{
_injectQueue . Add ( obj ) ;
return ;
}
AutoInject ( obj ) ;
}
2023-03-30 05:33:55 +08:00
public void PreInit ( EcsPipeline pipeline )
2023-03-29 16:43:06 +08:00
{
2023-03-30 05:33:55 +08:00
_pipeline = pipeline ;
_autoInjectionMap = new AutoInjectionMap ( _pipeline ) ;
2023-03-29 16:43:06 +08:00
foreach ( var obj in _injectQueue )
{
AutoInject ( obj ) ;
}
_injectQueue . Clear ( ) ;
_injectQueue = null ;
2023-04-05 09:14:42 +08:00
if ( _isPreInjectionComplete )
{
_autoInjectionMap . InjectDummy ( ) ;
}
2023-03-29 16:43:06 +08:00
}
private void AutoInject ( object obj )
{
_autoInjectionMap . Inject ( obj ) ;
}
2023-04-05 09:14:42 +08:00
public void OnPreInitInjectionBefore ( ) { }
public void OnPreInitInjectionAfter ( )
{
_isPreInjectionComplete = true ;
if ( _autoInjectionMap ! = null )
{
_autoInjectionMap . InjectDummy ( ) ;
}
}
2023-03-29 16:43:06 +08:00
}
}