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("");
}
//TODO PrintJson не возможно будет добавлено когда-то
//TODO PrintJson возможно будет добавлено когда-то
}
public sealed class DefaultDebugService : DebugService
{

View File

@ -66,7 +66,6 @@ namespace DCFApixels.DragonECS
return AutoToString(self, typeof(T), isWriteName);
}
//TODO сделать специальный вывод в виде названий констант для Enum-ов
private static string AutoToString(object target, Type type, bool isWriteName)
{
#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 HashSet<Type> _uniqueSystemsSet = new HashSet<Type>();
#region Properties
//private ReadOnlySpan<SystemNode> SystemRecords
//{
@ -107,10 +109,14 @@ namespace DCFApixels.DragonECS
{
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)
{
_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);
int newIndex;
if (_freeNodesCount <= 0)
@ -175,10 +181,7 @@ namespace DCFApixels.DragonECS
_defaultAddParams = oldDefaultAddParams;
}
if (module is IInjectionUnit injectionUnit)
{
Injector.Inject(injectionUnit);
}
Injector.Inject(module);
return this;
}
#endregion
@ -251,6 +254,8 @@ namespace DCFApixels.DragonECS
}
public Builder Remove<TSystem>()
{
_uniqueSystemsSet.Remove(typeof(TSystem));
if (_systemNodesCount <= 1)
{
if (_systemNodesCount == 1 && _systemNodes[0].system is TSystem)
@ -293,9 +298,6 @@ namespace DCFApixels.DragonECS
_layerLists.Add(BASIC_LAYER, basicLayerList);
}
//ERROR Уникальные системы ломают работу подсчета систем
HashSet<Type> uniqueSystemsSet = new HashSet<Type>();
int allSystemsLength = 0;
foreach (var item in _layerLists)
{
@ -320,10 +322,12 @@ namespace DCFApixels.DragonECS
{
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);
}
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)
{
//TODO добавить оишбку если порядок совпадающих слоев не совпадает
HashSet<string> seen = new HashSet<string>();
List<string> result = new List<string>();
List<string> listA = _layers;
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)
{
seen.Add(item);

View File

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

View File

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

View File

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

View File

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

View File

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