DragonECS/src/Injections/Injector.cs

202 lines
6.3 KiB
C#
Raw Normal View History

2024-04-28 18:36:14 +08:00
using DCFApixels.DragonECS.Internal;
using System;
using System.Collections.Generic;
namespace DCFApixels.DragonECS
{
[MetaName(nameof(Inject))]
2024-02-22 23:48:10 +08:00
[MetaColor(MetaColor.Orange)]
2024-04-29 22:06:19 +08:00
[MetaGroup(EcsConsts.FRAMEWORK_NAME)]
public interface IEcsInject<T> : IEcsProcess
{
void Inject(T obj);
}
2024-02-22 23:48:10 +08:00
[MetaName(nameof(OnInitInjectionComplete))]
[MetaColor(MetaColor.Orange)]
2024-04-29 22:06:19 +08:00
[MetaGroup(EcsConsts.FRAMEWORK_NAME)]
2024-02-22 23:48:10 +08:00
public interface IOnInitInjectionComplete : IEcsProcess
{
void OnInitInjectionComplete();
}
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; } }
private Injector() { }
2024-02-22 23:48:10 +08:00
2024-04-28 18:36:14 +08:00
#region Inject/AddNode
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();
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-03-14 00:24:23 +08:00
branch.Inject(raw);
}
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
#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;
var branch = item.Value;
2024-03-14 00:24:23 +08:00
if (node.Type.IsAssignableFrom(branch.Type))
{
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));
#if !REFLECTION_DISABLED
if (IsCanInstantiated(type))
#endif
{
2024-04-28 18:36:14 +08:00
InitBranch(new InjectionBranch(this, type));
}
return true;
}
2024-02-25 18:33:17 +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>()
{
_instance.TryDeclare<T>();
return _source;
}
2024-02-22 23:48:10 +08:00
public EcsPipeline.Builder Inject<T>(T obj)
{
_initInjections.Add(new InitInject<T>(obj));
2024-02-22 23:48:10 +08:00
return _source;
}
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();
}
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
}
}