2025-03-14 16:53:25 +08:00
#if DISABLE_DEBUG
#undef DEBUG
#endif
2025-05-18 10:52:24 +08:00
using DCFApixels.DragonECS.Core.Internal ;
2024-04-28 18:36:14 +08:00
using System ;
2024-02-22 22:16:03 +08:00
using System.Collections.Generic ;
2024-09-08 19:39:43 +08:00
using System.Linq ;
2024-08-20 11:53:23 +08:00
using System.Runtime.CompilerServices ;
2024-02-22 22:16:03 +08:00
namespace DCFApixels.DragonECS
{
2024-08-20 11:53:23 +08:00
public class Injector : IInjector
2024-02-22 22:16:03 +08:00
{
2025-07-14 16:20:11 +08:00
private readonly EcsPipeline _pipeline ;
private readonly Dictionary < Type , InjectionBranch > _branches = new Dictionary < Type , InjectionBranch > ( 32 ) ;
private readonly Dictionary < Type , InjectionNodeBase > _nodes = new Dictionary < Type , InjectionNodeBase > ( 32 ) ;
private ReadOnlySpan < InjectionNodeBase > GetNodes ( Type type )
{
if ( _branches . TryGetValue ( type , out InjectionBranch branch ) )
{
return branch . Nodes ;
}
return Array . Empty < InjectionNodeBase > ( ) ;
}
2024-02-22 22:16:03 +08:00
2025-07-14 16:20:11 +08:00
#region InjectionTempHistory
private StructList < object > _injectionTempHistory = new StructList < object > ( 32 ) ;
private int _injectionTempHistoryReadersCount = 0 ;
private int StartReadHistory_Internal ( )
{
_injectionTempHistoryReadersCount + + ;
return _injectionTempHistory . Count ;
}
private ReadOnlySpan < object > EndReadHistory_Internal ( int startIndex )
{
_injectionTempHistoryReadersCount - - ;
if ( _injectionTempHistoryReadersCount < 0 )
{
Throw . OpeningClosingMethodsBalanceError ( ) ;
}
var result = _injectionTempHistory . AsReadOnlySpan ( ) . Slice ( startIndex ) ;
if ( _injectionTempHistoryReadersCount = = 0 )
{
_injectionTempHistory . Recreate ( ) ;
}
return result ;
}
public readonly struct InjectionHistorySpanReader
{
private readonly Injector _injector ;
private readonly int _startIndex ;
public InjectionHistorySpanReader ( Injector injector )
{
_injector = injector ;
_startIndex = _injector . StartReadHistory_Internal ( ) ;
}
public ReadOnlySpan < object > StopReadAndGetHistorySpan ( )
{
return _injector . EndReadHistory_Internal ( _startIndex ) ;
}
}
public InjectionHistorySpanReader StartReadHistory ( )
{
return new InjectionHistorySpanReader ( this ) ;
}
#endregion
2024-09-08 19:39:43 +08:00
2024-08-20 11:53:23 +08:00
public EcsPipeline Pipelie
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _pipeline ; }
}
2024-04-28 18:36:14 +08:00
2025-07-14 16:20:11 +08:00
public Injector ( EcsPipeline pipeline )
{
_pipeline = pipeline ;
}
2024-02-22 23:48:10 +08:00
2024-08-20 11:53:23 +08:00
#region Inject / Extract / AddNode
2024-02-22 22:16:03 +08:00
public void Inject < T > ( T obj )
{
2024-09-08 19:39:43 +08:00
Type tType = typeof ( T ) ;
Type objType = obj . GetType ( ) ;
if ( _branches . TryGetValue ( objType , out InjectionBranch branch ) = = false )
2024-02-22 22:16:03 +08:00
{
2024-09-08 19:39:43 +08:00
if ( _nodes . ContainsKey ( tType ) = = false )
2024-02-25 02:33:24 +08:00
{
2024-09-08 19:39:43 +08:00
InitNode ( new InjectionNode < T > ( ) ) ;
2024-02-25 02:33:24 +08:00
}
2025-07-14 16:20:11 +08:00
bool hasObjTypeNode = _nodes . ContainsKey ( objType ) ;
if ( hasObjTypeNode = = false & & obj is IInjectionUnit unit )
2024-02-25 02:33:24 +08:00
{
2024-09-08 19:41:09 +08:00
unit . InitInjectionNode ( new InjectionGraph ( this ) ) ;
2025-07-14 16:20:11 +08:00
hasObjTypeNode = _nodes . ContainsKey ( objType ) ;
2024-09-08 19:39:43 +08:00
}
2024-09-07 21:25:21 +08:00
2025-07-14 16:20:11 +08:00
branch = new InjectionBranch ( objType ) ;
2024-09-08 19:39:43 +08:00
InitBranch ( branch ) ;
2025-07-14 16:20:11 +08:00
}
2024-09-08 19:39:43 +08:00
2025-07-14 16:20:11 +08:00
var branchNodes = branch . Nodes ;
for ( int i = 0 ; i < branchNodes . Length ; i + + )
{
branchNodes [ i ] . Inject ( obj ) ;
}
if ( _injectionTempHistoryReadersCount > 0 )
{
_injectionTempHistory . Add ( obj ) ;
}
if ( obj is IInjectionBlock block )
{
block . InjectTo ( this ) ;
2024-02-22 22:16:03 +08:00
}
}
2025-03-13 20:46:51 +08:00
public void ExtractAllTo ( object target )
{
if ( target is IEcsInjectProcess = = false ) { return ; }
foreach ( var node in _nodes )
{
node . Value . ExtractTo ( target ) ;
}
}
2024-08-20 11:53:23 +08:00
public T Extract < T > ( )
{
return ( T ) Extract_Internal ( typeof ( T ) ) ;
}
2024-09-08 19:39:43 +08:00
private object Extract_Internal ( Type type ) //TODO проверить
2024-08-20 11:53:23 +08:00
{
2024-09-08 19:39:43 +08:00
if ( _nodes . TryGetValue ( type , out InjectionNodeBase node ) )
2024-08-20 11:53:23 +08:00
{
2024-09-08 19:39:43 +08:00
return node . CurrentInjectedDependencyRaw ;
2024-08-20 11:53:23 +08:00
}
2025-03-14 21:57:52 +08:00
throw new InjectionException ( $"The injection graph is missing a node for {type.Name} type. To create a node, use the Injector.AddNode<{type.Name}>() method directly in the injector or in the implementation of the IInjectionUnit for {type.Name}." ) ;
2024-08-20 11:53:23 +08:00
}
2025-07-14 16:20:11 +08:00
public bool AddNode < T > ( )
2024-04-28 18:36:14 +08:00
{
2025-07-14 16:20:11 +08:00
if ( _nodes . ContainsKey ( typeof ( T ) ) ) { return false ; }
InitNode ( new InjectionNode < T > ( ) ) ;
return true ;
2024-04-28 18:36:14 +08:00
}
#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 ) ;
}
}
}
#endregion
2025-07-14 16:20:11 +08:00
#region InjectionList
public class InjectionList : IInjector
2024-02-22 22:16:03 +08:00
{
2025-07-14 16:20:11 +08:00
public static readonly InjectionList _Empty_Internal = new InjectionList ( ) ;
2024-09-08 19:39:43 +08:00
2025-07-14 16:20:11 +08:00
private StructList < InjectionBase > _injections = new StructList < InjectionBase > ( 32 ) ;
private StructList < NodeBase > _nodes = new StructList < NodeBase > ( 32 ) ;
private EcsWorld _monoWorld ;
public void AddNode < T > ( )
2024-02-22 22:16:03 +08:00
{
2025-07-14 16:20:11 +08:00
_nodes . Add ( new Node < T > ( ) ) ;
2024-02-22 22:16:03 +08:00
}
2025-07-14 16:20:11 +08:00
public void Inject < T > ( T obj )
{
FindMonoWorld ( obj ) ;
_injections . Add ( new Injection < T > ( obj ) ) ;
}
public void Extract < T > ( ref T obj ) // TODO проверить
2024-09-08 19:39:43 +08:00
{
2025-07-14 16:20:11 +08:00
Type type = typeof ( T ) ;
for ( int i = _injections . Count - 1 ; i > = 0 ; i - - )
2024-09-08 19:39:43 +08:00
{
2025-07-14 16:20:11 +08:00
var item = _injections [ i ] ;
if ( type . IsAssignableFrom ( item . Type ) )
{
obj = ( T ) item . Raw ;
return ;
}
2024-09-08 19:39:43 +08:00
}
2025-07-14 16:20:11 +08:00
Throw . UndefinedException ( ) ;
2024-09-08 19:39:43 +08:00
}
2025-07-14 16:20:11 +08:00
public void MergeWith ( InjectionList other )
2024-02-22 22:16:03 +08:00
{
2025-07-14 16:20:11 +08:00
foreach ( var item in other . _injections )
{
FindMonoWorld ( item ) ;
_injections . Add ( item ) ;
}
foreach ( var item in other . _nodes )
{
_nodes . Add ( item ) ;
}
2024-02-22 22:16:03 +08:00
}
2025-07-14 16:20:11 +08:00
public void InitInjectTo ( Injector injector , EcsPipeline pipeline )
2024-02-22 22:16:03 +08:00
{
2025-07-14 16:20:11 +08:00
#if DEBUG
HashSet < Type > requiredInjectionTypes = new HashSet < Type > ( ) ;
var systems = pipeline . AllSystems ;
var injectType = typeof ( IEcsInject < > ) ;
foreach ( var system in systems )
{
var type = system . GetType ( ) ;
foreach ( var requiredInjectionType in type . GetInterfaces ( ) . Where ( o = > o . IsGenericType & & o . GetGenericTypeDefinition ( ) = = injectType ) . Select ( o = > o . GenericTypeArguments [ 0 ] ) )
{
requiredInjectionTypes . Add ( requiredInjectionType ) ;
}
}
var reader = injector . StartReadHistory ( ) ;
#endif
2024-02-25 18:33:17 +08:00
2025-07-14 16:20:11 +08:00
var initInjectionCallbacks = pipeline . GetProcess < IOnInitInjectionComplete > ( ) ;
foreach ( var system in initInjectionCallbacks )
{
system . OnBeforeInitInjection ( ) ;
}
injector . Inject ( pipeline ) ;
injector . AddNode < object > ( ) ;
InjectTo ( injector , pipeline ) ;
foreach ( var system in initInjectionCallbacks )
{
system . OnInitInjectionComplete ( ) ;
}
#if DEBUG
var injectionHistory = reader . StopReadAndGetHistorySpan ( ) ;
foreach ( var injection in injectionHistory )
{
foreach ( var node in injector . GetNodes ( injection . GetType ( ) ) )
{
requiredInjectionTypes . Remove ( node . Type ) ;
}
}
if ( requiredInjectionTypes . Count > 0 )
{
foreach ( var requiredInjectionType in requiredInjectionTypes )
{
throw new InjectionException ( $"A systems in the pipeline implements IEcsInject<{requiredInjectionType.Name}> interface, but no suitable injection node was found in the Injector. To create a node, use Injector.AddNode<{requiredInjectionType.Name}>() or implement the IInjectionUnit interface for the type being injected." ) ;
}
}
#endif
2024-02-22 22:16:03 +08:00
}
2025-07-14 16:20:11 +08:00
public void InjectTo ( Injector injector , EcsPipeline pipeline )
2024-02-22 22:16:03 +08:00
{
2025-07-14 16:20:11 +08:00
var monoWorldProcess = pipeline . GetProcess < IMonoWorldInject > ( ) ; // TODO Проверить IMonoWorldInject
foreach ( var monoWorldSystem in monoWorldProcess )
{
monoWorldSystem . World = _monoWorld ;
}
foreach ( var item in _nodes )
{
item . AddNodeTo ( injector ) ;
}
foreach ( var item in _injections )
{
item . InjectTo ( injector ) ;
}
2024-02-22 22:16:03 +08:00
}
2025-07-14 16:20:11 +08:00
private void FindMonoWorld ( object obj )
2024-02-22 22:16:03 +08:00
{
2025-01-06 10:48:39 +08:00
if ( obj is EcsWorld objWorld )
2024-12-17 12:22:22 +08:00
{
2025-01-06 10:48:39 +08:00
if ( _monoWorld = = null )
2024-12-17 12:22:22 +08:00
{
_monoWorld = objWorld ;
}
else
{
Type monoWorldType = _monoWorld . GetType ( ) ;
Type objWorldType = objWorld . GetType ( ) ;
if ( monoWorldType ! = objWorldType )
{
2025-01-06 10:48:39 +08:00
if ( objWorldType = = typeof ( EcsWorld ) )
2024-12-17 12:22:22 +08:00
{ // Екземпляр EcsWorld имеет самый больший приоритет.
_monoWorld = objWorld ;
}
2025-01-06 10:48:39 +08:00
if ( objWorldType = = typeof ( EcsDefaultWorld ) & &
2024-12-17 12:22:22 +08:00
monoWorldType ! = typeof ( EcsWorld ) )
{ // Екземпляр EcsDefaultWorld имеет приоритет больше других типов, но меньше приоритета EcsWorld.
_monoWorld = objWorld ;
}
}
}
}
2024-06-24 22:06:02 +08:00
}
2024-02-22 22:16:03 +08:00
2024-09-07 19:07:47 +08:00
void IInjector . Inject < T > ( T obj ) { Inject ( obj ) ; }
T IInjector . Extract < T > ( )
{
T result = default ;
Extract ( ref result ) ;
return result ;
}
2025-07-14 16:20:11 +08:00
private abstract class NodeBase
{
public abstract Type Type { get ; }
public abstract void AddNodeTo ( Injector instance ) ;
}
private sealed class Node < T > : NodeBase
{
public override Type Type { get { return typeof ( T ) ; } }
public override void AddNodeTo ( Injector instance )
{
instance . AddNode < T > ( ) ;
}
}
private abstract class InjectionBase
2024-02-22 22:16:03 +08:00
{
2024-09-07 19:07:47 +08:00
public abstract Type Type { get ; }
public abstract object Raw { get ; }
2024-02-22 22:16:03 +08:00
public abstract void InjectTo ( Injector instance ) ;
}
2025-07-14 16:20:11 +08:00
private sealed class Injection < T > : InjectionBase
2024-02-22 22:16:03 +08:00
{
private T _injectedData ;
2024-09-07 19:07:47 +08:00
public override Type Type { get { return typeof ( T ) ; } }
public override object Raw { get { return _injectedData ; } }
2025-07-14 16:20:11 +08:00
public Injection ( T injectedData )
2024-02-22 22:16:03 +08:00
{
_injectedData = injectedData ;
}
public override void InjectTo ( Injector instance )
{
2025-07-14 16:20:11 +08:00
instance . Inject ( _injectedData ) ;
2024-02-22 22:16:03 +08:00
}
}
}
#endregion
}
2024-09-07 19:07:47 +08:00
}