using DCFApixels.DragonECS.Internal; using System; using System.Collections.Generic; namespace DCFApixels.DragonECS { [MetaName(nameof(Inject))] [MetaColor(MetaColor.Orange)] public interface IEcsInject : IEcsProcess { void Inject(T obj); } [MetaName(nameof(OnInitInjectionComplete))] [MetaColor(MetaColor.Orange)] public interface IOnInitInjectionComplete : IEcsProcess { void OnInitInjectionComplete(); } public class Injector { private EcsPipeline _pipeline; private Dictionary _branches = new Dictionary(32); private Dictionary _nodes = new Dictionary(32); private bool _isInit = false; private Injector() { } public void Inject(T obj) { Type type = obj.GetType(); if (_branches.TryGetValue(type, out InjectionBranch branch) == false) { if (typeof(T) == type) { InitNode(new InjectionNode(type)); branch = new InjectionBranch(this, type, true); InitBranch(branch); } else { branch = new InjectionBranch(this, type, false); InitBranch(branch); } } branch.Inject(obj); } #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) { var type = item.Key; var branch = item.Value; if (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() { Type type = typeof(T); if (_nodes.ContainsKey(type)) { return false; } InitNode(new InjectionNode(type)); #if !REFLECTION_DISABLED if (IsCanInstantiated(type)) #endif { InitBranch(new InjectionBranch(this, type, true)); } return true; } private bool TryDeclareProperty(CustomInjectionNodeBase injectionProperty) { Type type = injectionProperty.Type; if (_nodes.TryGetValue(type, out InjectionNodeBase oldNode)) { Throw.Exception("Already declared"); } InitNode(injectionProperty); #if !REFLECTION_DISABLED if (IsCanInstantiated(type)) #endif { InitBranch(new InjectionBranch(this, type, true)); } return true; } public class Builder { private EcsPipeline.Builder _source; private Injector _instance; private List _initInjections = new List(16); internal Builder(EcsPipeline.Builder source) { _source = source; _instance = new Injector(); } public EcsPipeline.Builder AddNode() { _instance.TryDeclare(); return _source; } public EcsPipeline.Builder AddCustomNode(CustomInjectionNodeBase injectionProperty) { _instance.TryDeclareProperty(injectionProperty); return _source; } public EcsPipeline.Builder Inject(T obj) { _initInjections.Add(new InitInject(obj)); return _source; } public Injector Build(EcsPipeline pipeline) { _instance.Init(pipeline); foreach (var item in _initInjections) { item.InjectTo(_instance); } foreach (var system in pipeline.GetProcess()) { system.OnInitInjectionComplete(); } return _instance; } private abstract class InitInjectBase { public abstract void InjectTo(Injector instance); } private sealed class InitInject : InitInjectBase { private T _injectedData; public InitInject(T injectedData) { _injectedData = injectedData; } public override void InjectTo(Injector instance) { instance.Inject(_injectedData); } } } #endregion } }