Resolve TODO

This commit is contained in:
Mikhail 2024-09-08 19:39:43 +08:00
parent 693a0615e0
commit 5591a3f5b1
8 changed files with 114 additions and 79 deletions

View File

@ -196,7 +196,7 @@ namespace DCFApixels.DragonECS
{ {
self.Print(""); self.Print("");
} }
//TODO PrintJson не возможно будет добавлено когда-то //TODO PrintJson возможно будет добавлено когда-то
} }
public sealed class DefaultDebugService : DebugService public sealed class DefaultDebugService : DebugService
{ {

View File

@ -66,7 +66,6 @@ namespace DCFApixels.DragonECS
return AutoToString(self, typeof(T), isWriteName); return AutoToString(self, typeof(T), isWriteName);
} }
//TODO сделать специальный вывод в виде названий констант для Enum-ов
private static string AutoToString(object target, Type type, bool isWriteName) private static string AutoToString(object target, Type type, bool isWriteName)
{ {
#if (DEBUG && !DISABLE_DEBUG) || !REFLECTION_DISABLED //в дебажных утилитах REFLECTION_DISABLED только в релизном билде работает #if (DEBUG && !DISABLE_DEBUG) || !REFLECTION_DISABLED //в дебажных утилитах REFLECTION_DISABLED только в релизном билде работает

View File

@ -39,6 +39,8 @@ namespace DCFApixels.DragonECS
private AddParams _defaultAddParams = new AddParams(BASIC_LAYER, 0, false); private AddParams _defaultAddParams = new AddParams(BASIC_LAYER, 0, false);
private HashSet<Type> _uniqueSystemsSet = new HashSet<Type>();
#region Properties #region Properties
//private ReadOnlySpan<SystemNode> SystemRecords //private ReadOnlySpan<SystemNode> SystemRecords
//{ //{
@ -107,10 +109,14 @@ namespace DCFApixels.DragonECS
{ {
InsertAfterNode_Internal(_endIndex, system, layer, sortOrder, isUnique); InsertAfterNode_Internal(_endIndex, system, layer, sortOrder, isUnique);
} }
int _DEBUG_COUNTER = 0;
private void InsertAfterNode_Internal(int insertAfterIndex, IEcsProcess system, string layer, int sortOrder, bool isUnique) private void InsertAfterNode_Internal(int insertAfterIndex, IEcsProcess system, string layer, int sortOrder, bool isUnique)
{ {
_DEBUG_COUNTER++; //TODO нужно потестить
if (isUnique && _uniqueSystemsSet.Add(system.GetType()) == false)
{
EcsDebug.PrintWarning($"The pipeline already contains a unique instance of {system.GetType().Name}");
}
SystemNode record = new SystemNode(system, layer, sortOrder, isUnique); SystemNode record = new SystemNode(system, layer, sortOrder, isUnique);
int newIndex; int newIndex;
if (_freeNodesCount <= 0) if (_freeNodesCount <= 0)
@ -175,10 +181,7 @@ namespace DCFApixels.DragonECS
_defaultAddParams = oldDefaultAddParams; _defaultAddParams = oldDefaultAddParams;
} }
if (module is IInjectionUnit injectionUnit) Injector.Inject(module);
{
Injector.Inject(injectionUnit);
}
return this; return this;
} }
#endregion #endregion
@ -251,6 +254,8 @@ namespace DCFApixels.DragonECS
} }
public Builder Remove<TSystem>() public Builder Remove<TSystem>()
{ {
_uniqueSystemsSet.Remove(typeof(TSystem));
if (_systemNodesCount <= 1) if (_systemNodesCount <= 1)
{ {
if (_systemNodesCount == 1 && _systemNodes[0].system is TSystem) if (_systemNodesCount == 1 && _systemNodes[0].system is TSystem)
@ -293,9 +298,6 @@ namespace DCFApixels.DragonECS
_layerLists.Add(BASIC_LAYER, basicLayerList); _layerLists.Add(BASIC_LAYER, basicLayerList);
} }
//ERROR Уникальные системы ломают работу подсчета систем
HashSet<Type> uniqueSystemsSet = new HashSet<Type>();
int allSystemsLength = 0; int allSystemsLength = 0;
foreach (var item in _layerLists) foreach (var item in _layerLists)
{ {
@ -320,10 +322,12 @@ namespace DCFApixels.DragonECS
{ {
list = basicLayerList; list = basicLayerList;
} }
if (node.isUnique == false || uniqueSystemsSet.Add(node.system.GetType()))
{
list.Add(node.system, node.sortOrder, node.isUnique); list.Add(node.system, node.sortOrder, node.isUnique);
}
//if (node.isUnique == false || uniqueSystemsSet.Add(node.system.GetType()))
//{
// list.Add(node.system, node.sortOrder, node.isUnique);
//}
} }
@ -525,15 +529,32 @@ namespace DCFApixels.DragonECS
} }
return InsertAfter(targetLayer, movingLayers); return InsertAfter(targetLayer, movingLayers);
} }
private static bool AreMatchingOrderIdentical(IReadOnlyList<string> listA, IReadOnlyList<string> listB)
{
int indexA = 0;
foreach (string itemB in listB)
{
if (indexA < listA.Count && listA[indexA] == itemB)
{
indexA++;
}
}
return indexA == listA.Count;
}
public void MergeWith(IReadOnlyList<string> other) public void MergeWith(IReadOnlyList<string> other)
{ {
//TODO добавить оишбку если порядок совпадающих слоев не совпадает
HashSet<string> seen = new HashSet<string>();
List<string> result = new List<string>();
List<string> listA = _layers; List<string> listA = _layers;
IReadOnlyList<string> listB = other; IReadOnlyList<string> listB = other;
if (AreMatchingOrderIdentical(listA, listB) == false)
{
Throw.Exception("Для слияния списков слоев, нужно чтобы названия слоев, присутствующие в обоих списках, появлялись в одном и том же порядке в обоих списках");
}
HashSet<string> seen = new HashSet<string>();
List<string> result = new List<string>();
foreach (string item in listA) foreach (string item in listA)
{ {
seen.Add(item); seen.Add(item);

View File

@ -224,6 +224,7 @@ namespace DCFApixels.DragonECS
#endregion #endregion
} }
#region EcsModule
public interface IEcsModule public interface IEcsModule
{ {
void Import(EcsPipeline.Builder b); void Import(EcsPipeline.Builder b);
@ -237,6 +238,7 @@ namespace DCFApixels.DragonECS
void IInjectionUnit.InitInjectionNode(InjectionNodes nodes) { nodes.AddNode<T>(); } void IInjectionUnit.InitInjectionNode(InjectionNodes nodes) { nodes.AddNode<T>(); }
public EcsModule() { if (GetType() != typeof(T)) { Throw.UndefinedException(); } } public EcsModule() { if (GetType() != typeof(T)) { Throw.UndefinedException(); } }
} }
#endregion
#region Extensions #region Extensions
public static partial class EcsPipelineExtensions public static partial class EcsPipelineExtensions

View File

@ -7,20 +7,18 @@ namespace DCFApixels.DragonECS.Internal
{ {
private readonly Injector _source; private readonly Injector _source;
private readonly Type _type; private readonly Type _type;
private InjectionNodeBase[] _nodes = new InjectionNodeBase[2]; private InjectionNodeBase[] _nodes = new InjectionNodeBase[4];
private int _nodesCount = 0; private int _nodesCount = 0;
private object _currentInjectedDependency;
public Type Type public Type Type
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _type; } get { return _type; }
} }
public object CurrentInjectedDependency public ReadOnlySpan<InjectionNodeBase> Nodes
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _currentInjectedDependency; } get { return new ReadOnlySpan<InjectionNodeBase>(_nodes, 0, _nodesCount); }
} }
public InjectionBranch(Injector source, Type type) public InjectionBranch(Injector source, Type type)
{ {
@ -29,7 +27,6 @@ namespace DCFApixels.DragonECS.Internal
} }
public void Inject(object obj) public void Inject(object obj)
{ {
_currentInjectedDependency = obj;
for (int i = 0; i < _nodesCount; i++) for (int i = 0; i < _nodesCount; i++)
{ {
_nodes[i].Inject(obj); _nodes[i].Inject(obj);

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
@ -9,6 +10,7 @@ namespace DCFApixels.DragonECS
{ {
get { return _type; } get { return _type; }
} }
public abstract object CurrentInjectedDependencyRaw { get; }
protected InjectionNodeBase(Type type) protected InjectionNodeBase(Type type)
{ {
_type = type; _type = type;
@ -22,7 +24,18 @@ namespace DCFApixels.DragonECS.Internal
internal sealed class InjectionNode<T> : InjectionNodeBase internal sealed class InjectionNode<T> : InjectionNodeBase
{ {
private EcsProcess<IEcsInject<T>> _process; private EcsProcess<IEcsInject<T>> _process;
public InjectionNode(Type type) : base(type) { } private T _currentInjectedDependency;
public sealed override object CurrentInjectedDependencyRaw
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _currentInjectedDependency; }
}
public T CurrentInjectedDependency
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _currentInjectedDependency; }
}
public InjectionNode() : base(typeof(T)) { }
public sealed override void Init(EcsPipeline pipeline) public sealed override void Init(EcsPipeline pipeline)
{ {
_process = pipeline.GetProcess<IEcsInject<T>>(); _process = pipeline.GetProcess<IEcsInject<T>>();
@ -30,6 +43,7 @@ namespace DCFApixels.DragonECS.Internal
public sealed override void Inject(object raw) public sealed override void Inject(object raw)
{ {
T obj = (T)raw; T obj = (T)raw;
_currentInjectedDependency = obj;
for (int i = 0; i < _process.Length; i++) for (int i = 0; i < _process.Length; i++)
{ {
_process[i].Inject(obj); _process[i].Inject(obj);

View File

@ -1,6 +1,7 @@
using DCFApixels.DragonECS.Internal; using DCFApixels.DragonECS.Internal;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
@ -12,6 +13,10 @@ namespace DCFApixels.DragonECS
private Dictionary<Type, InjectionNodeBase> _nodes = new Dictionary<Type, InjectionNodeBase>(32); private Dictionary<Type, InjectionNodeBase> _nodes = new Dictionary<Type, InjectionNodeBase>(32);
private bool _isInit = false; private bool _isInit = false;
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
private HashSet<Type> _requiredInjectionTypes = new HashSet<Type>();
#endif
public EcsPipeline Pipelie public EcsPipeline Pipelie
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -24,70 +29,56 @@ namespace DCFApixels.DragonECS
public void Inject<T>(T obj) public void Inject<T>(T obj)
{ {
object raw = obj; object raw = obj;
Type type = obj.GetType(); Type tType = typeof(T);
if (_branches.TryGetValue(type, out InjectionBranch branch) == false) Type objType = obj.GetType();
if (_branches.TryGetValue(objType, out InjectionBranch branch) == false)
{ {
if (typeof(T) == type) if (_nodes.ContainsKey(tType) == false)
{ {
if (_nodes.ContainsKey(type) == false) InitNode(new InjectionNode<T>());
{
InitNode(new InjectionNode<T>(type));
} }
branch = new InjectionBranch(this, type); bool hasNode = _nodes.ContainsKey(objType);
InitBranch(branch);
}
else
{
bool hasNode = _nodes.ContainsKey(type);
if (hasNode == false && obj is IInjectionUnit unit) if (hasNode == false && obj is IInjectionUnit unit)
{ {
unit.InitInjectionNode(new InjectionNodes(this)); unit.InitInjectionNode(new InjectionNodes(this));
hasNode = _nodes.ContainsKey(type); hasNode = _nodes.ContainsKey(objType);
} }
if (hasNode)
{
branch = new InjectionBranch(this, type);
InitBranch(branch);
}
else
{
//TODO переработать это исключение
// идея следующая, в режиме дебага с помощью рефлекшена собрать информацию о системах в которых есть IEcsInject, собрать все типы которые принимают системы,
// потом при инициирующих инъекциях проверить что во все собранные типы были заинжектены. Если нет, то только тогда бросать исключение.
// Исключения можно заранее определять и собирать, а бросать на моменте. Например тут создать исключение, и если инхекции небыло то бросить его.
// Дополнительно обернуть все в #if DEBUG
//Другой вариант, тут добавить дополнительную проверку, если среди систем есть системы с IEcsInject<T> где T это obj.GetType() то бросить исключение branch = new InjectionBranch(this, objType);
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}."); InitBranch(branch);
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
foreach (var requiredInjectionType in _requiredInjectionTypes)
{
if (requiredInjectionType.IsAssignableFrom(objType))
{
if (_nodes.ContainsKey(requiredInjectionType) == false)
{
throw new EcsInjectionException($"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 type {objType.Name}.");
} }
} }
} }
#endif
}
branch.Inject(raw); branch.Inject(raw);
} }
public T Extract<T>() public T Extract<T>()
{ {
return (T)Extract_Internal(typeof(T)); return (T)Extract_Internal(typeof(T));
} }
private object Extract_Internal(Type type) private object Extract_Internal(Type type)//TODO проверить
{ {
if (_branches.TryGetValue(type, out InjectionBranch branch)) if (_nodes.TryGetValue(type, out InjectionNodeBase node))
{ {
return branch.CurrentInjectedDependency; return node.CurrentInjectedDependencyRaw;
} }
return null; throw new EcsInjectionException($"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}.");
//if (_nodes.ContainsKey(type))
//{
// return null;
//}
//throw new EcsInjectionException($"The injection graph is missing a node for {type.Name} type. To create a node, use the AddNode<{type.Name}>() method directly in the injector or in the implementation of the IInjectionUnit for {type.Name}.");
} }
public void AddNode<T>() public void AddNode<T>()
{ {
Type type = typeof(T); if (_nodes.ContainsKey(typeof(T)) == false)
if (_nodes.ContainsKey(type) == false)
{ {
InitNode(new InjectionNode<T>(type)); InitNode(new InjectionNode<T>());
} }
} }
#endregion #endregion
@ -132,16 +123,27 @@ namespace DCFApixels.DragonECS
#region Build #region Build
private void Init(EcsPipeline pipeline) private void Init(EcsPipeline pipeline)
{ {
if (_isInit) if (_isInit) { Throw.Exception("Already initialized"); }
{
throw new Exception("Already initialized");
}
_pipeline = pipeline; _pipeline = pipeline;
foreach (var node in _nodes.Values) foreach (var pair in _nodes)
{ {
node.Init(pipeline); pair.Value.Init(pipeline);
} }
_isInit = true; _isInit = true;
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
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);
}
}
#endif
} }
private bool TryDeclare<T>() private bool TryDeclare<T>()
{ {
@ -150,7 +152,7 @@ namespace DCFApixels.DragonECS
{ {
return false; return false;
} }
InitNode(new InjectionNode<T>(type)); InitNode(new InjectionNode<T>());
#if !REFLECTION_DISABLED #if !REFLECTION_DISABLED
if (IsCanInstantiated(type)) if (IsCanInstantiated(type))
#endif #endif
@ -180,13 +182,13 @@ namespace DCFApixels.DragonECS
_initInjections.Add(new InitInject<T>(obj)); _initInjections.Add(new InitInject<T>(obj));
return _source; return _source;
} }
public EcsPipeline.Builder Extract<T>(ref T obj) public EcsPipeline.Builder Extract<T>(ref T obj)//TODO проверить
{ {
Type type = typeof(T); Type type = typeof(T);
for (int i = _initInjections.Count - 1; i >= 0; i--) for (int i = _initInjections.Count - 1; i >= 0; i--)
{ {
var item = _initInjections[i]; var item = _initInjections[i];
if (item.Type.IsAssignableFrom(type)) if (type.IsAssignableFrom(item.Type))
{ {
obj = (T)item.Raw; obj = (T)item.Raw;
return _source; return _source;

View File

@ -39,6 +39,6 @@
} }
public interface IInjectionUnit public interface IInjectionUnit
{ {
void InitInjectionNode(InjectionNodes nodes); void InitInjectionNode(InjectionNodes graph);
} }
} }