2024-04-28 18:36:14 +08:00
using DCFApixels.DragonECS.Internal ;
using System ;
2024-02-22 22:16:03 +08:00
using System.Collections.Generic ;
namespace DCFApixels.DragonECS
{
[MetaName(nameof(Inject))]
2024-02-22 23:48:10 +08:00
[MetaColor(MetaColor.Orange)]
2024-02-22 22:16:03 +08:00
public interface IEcsInject < T > : IEcsProcess
{
void Inject ( T obj ) ;
}
2024-02-22 23:48:10 +08:00
[MetaName(nameof(OnInitInjectionComplete))]
[MetaColor(MetaColor.Orange)]
public interface IOnInitInjectionComplete : IEcsProcess
{
void OnInitInjectionComplete ( ) ;
}
2024-02-22 22:16:03 +08:00
public class Injector
{
private EcsPipeline _pipeline ;
private Dictionary < Type , InjectionBranch > _branches = new Dictionary < Type , InjectionBranch > ( 32 ) ;
private Dictionary < Type , InjectionNodeBase > _nodes = new Dictionary < Type , InjectionNodeBase > ( 32 ) ;
private bool _isInit = false ;
2024-04-28 18:36:14 +08:00
public EcsPipeline Pipelie { get { return _pipeline ; } }
2024-02-22 22:16:03 +08:00
private Injector ( ) { }
2024-02-22 23:48:10 +08:00
2024-04-28 18:36:14 +08:00
#region Inject / AddNode
2024-02-22 22:16:03 +08:00
public void Inject < T > ( T obj )
{
2024-03-14 00:24:23 +08:00
object raw = obj ;
2024-02-25 02:33:24 +08:00
Type type = obj . GetType ( ) ;
2024-02-22 22:16:03 +08:00
if ( _branches . TryGetValue ( type , out InjectionBranch branch ) = = false )
{
2024-02-25 02:33:24 +08:00
if ( typeof ( T ) = = type )
{
2024-04-28 18:36:14 +08:00
if ( _nodes . ContainsKey ( type ) = = false )
{
InitNode ( new InjectionNode < T > ( type ) ) ;
}
branch = new InjectionBranch ( this , type ) ;
2024-02-25 02:33:24 +08:00
InitBranch ( branch ) ;
}
else
{
2024-04-28 18:36:14 +08:00
bool hasNode = _nodes . ContainsKey ( type ) ;
if ( hasNode = = false & & obj is IInjectionUnit unit )
{
unit . OnInitInjectionBranch ( new InjectionBranchIniter ( this ) ) ;
hasNode = _nodes . ContainsKey ( type ) ;
}
if ( hasNode )
{
branch = new InjectionBranch ( this , type ) ;
InitBranch ( branch ) ;
}
else
{
throw new EcsInjectionException ( $"To create an injection branch, no injection node of {type.Name} was found. To create a node, use the AddNode<{type.Name}>() method directly in the injector or in the implementation of the IInjectionUnit for {type.Name}." ) ;
}
2024-02-25 02:33:24 +08:00
}
2024-02-22 22:16:03 +08:00
}
2024-03-14 00:24:23 +08:00
branch . Inject ( raw ) ;
2024-02-22 22:16:03 +08:00
}
2024-04-28 18:36:14 +08:00
public void AddNode < T > ( )
{
Type type = typeof ( T ) ;
if ( _nodes . ContainsKey ( type ) = = false )
{
InitNode ( new InjectionNode < T > ( type ) ) ;
}
}
#endregion
2024-02-22 22:16:03 +08:00
#region Internal
private void InitBranch ( InjectionBranch branch )
{
_branches . Add ( branch . Type , branch ) ;
foreach ( var item in _nodes )
{
var type = item . Key ;
var node = item . Value ;
if ( type . IsAssignableFrom ( branch . Type ) )
{
branch . AddNode ( node ) ;
}
}
}
private void InitNode ( InjectionNodeBase node )
{
if ( _pipeline ! = null )
{
node . Init ( _pipeline ) ;
}
_nodes . Add ( node . Type , node ) ;
foreach ( var item in _branches )
{
2024-04-28 18:36:14 +08:00
//var type = item.Key;
2024-02-22 22:16:03 +08:00
var branch = item . Value ;
2024-03-14 00:24:23 +08:00
if ( node . Type . IsAssignableFrom ( branch . Type ) )
2024-02-22 22:16:03 +08:00
{
branch . AddNode ( node ) ;
}
}
}
private bool IsCanInstantiated ( Type type )
{
return ! type . IsAbstract & & ! type . IsInterface ;
}
#endregion
#region Build
private void Init ( EcsPipeline pipeline )
{
if ( _isInit )
{
throw new Exception ( "Already initialized" ) ;
}
_pipeline = pipeline ;
foreach ( var node in _nodes . Values )
{
node . Init ( pipeline ) ;
}
_isInit = true ;
}
private bool TryDeclare < T > ( )
{
Type type = typeof ( T ) ;
if ( _nodes . ContainsKey ( type ) )
{
return false ;
}
InitNode ( new InjectionNode < T > ( type ) ) ;
2024-02-23 18:34:40 +08:00
#if ! REFLECTION_DISABLED
2024-02-22 22:16:03 +08:00
if ( IsCanInstantiated ( type ) )
2024-02-23 18:34:40 +08:00
#endif
2024-02-22 22:16:03 +08:00
{
2024-04-28 18:36:14 +08:00
InitBranch ( new InjectionBranch ( this , type ) ) ;
2024-02-22 22:16:03 +08:00
}
return true ;
}
2024-02-25 18:33:17 +08:00
2024-02-22 22:16:03 +08:00
public class Builder
{
private EcsPipeline . Builder _source ;
private Injector _instance ;
private List < InitInjectBase > _initInjections = new List < InitInjectBase > ( 16 ) ;
internal Builder ( EcsPipeline . Builder source )
{
_source = source ;
_instance = new Injector ( ) ;
}
2024-02-26 10:37:58 +08:00
public EcsPipeline . Builder AddNode < T > ( )
2024-02-22 22:16:03 +08:00
{
_instance . TryDeclare < T > ( ) ;
return _source ;
}
2024-02-22 23:48:10 +08:00
public EcsPipeline . Builder Inject < T > ( T obj )
2024-02-22 22:16:03 +08:00
{
_initInjections . Add ( new InitInject < T > ( obj ) ) ;
2024-02-22 23:48:10 +08:00
return _source ;
2024-02-22 22:16:03 +08:00
}
public Injector Build ( EcsPipeline pipeline )
{
_instance . Init ( pipeline ) ;
foreach ( var item in _initInjections )
{
item . InjectTo ( _instance ) ;
}
2024-02-22 23:48:10 +08:00
foreach ( var system in pipeline . GetProcess < IOnInitInjectionComplete > ( ) )
{
system . OnInitInjectionComplete ( ) ;
}
2024-02-22 22:16:03 +08:00
return _instance ;
}
private abstract class InitInjectBase
{
public abstract void InjectTo ( Injector instance ) ;
}
private sealed class InitInject < T > : InitInjectBase
{
private T _injectedData ;
public InitInject ( T injectedData )
{
_injectedData = injectedData ;
}
public override void InjectTo ( Injector instance )
{
instance . Inject < T > ( _injectedData ) ;
}
}
}
#endregion
}
}
2024-02-23 18:34:40 +08:00