Compare commits

...

10 Commits

Author SHA1 Message Date
DCFApixels
7fa63ef7e3 Merge branch 'dev' into next_version 2025-07-15 14:37:35 +08:00
DCFApixels
007ef493a8 up version to 0.9.16 2025-07-15 13:57:53 +08:00
DCFApixels
e4dc76e037 update 2025-07-14 21:10:57 +08:00
DCFApixels
cfc1ffe9a6 impl EcsPipeline.Builder.MergeWith 2025-07-14 20:55:09 +08:00
DCFApixels
0c7f743f1e Squashed commit of the following:
commit 5f92f544f39679f8bcc508c17b5572ae789e7ab8
Author: DCFApixels <99481254+DCFApixels@users.noreply.github.com>
Date:   Mon Jul 14 16:19:58 2025 +0800

    Update LayersMap.cs

commit 27e7fddb40f697c5a5b21d140267e2c49e1f46f6
Author: DCFApixels <99481254+DCFApixels@users.noreply.github.com>
Date:   Mon Jul 14 16:13:49 2025 +0800

    update

commit f118605bea25abe11b196074fdd6c6baeb9124ba
Author: DCFApixels <99481254+DCFApixels@users.noreply.github.com>
Date:   Mon Jul 14 15:49:52 2025 +0800

    update pipeline building, rework/refactoring injector

commit 52af6142d0
Author: DCFApixels <99481254+DCFApixels@users.noreply.github.com>
Date:   Sat Jul 12 01:32:51 2025 +0800

    Update EcsPipeline.Builder.cs

commit b3571e3ed8
Author: DCFApixels <99481254+DCFApixels@users.noreply.github.com>
Date:   Sat Jul 12 01:28:24 2025 +0800

    update

commit ab50dcb7e3
Author: DCFApixels <99481254+DCFApixels@users.noreply.github.com>
Date:   Fri Jul 11 23:37:48 2025 +0800

    update

commit c23aa1b223
Author: DCFApixels <99481254+DCFApixels@users.noreply.github.com>
Date:   Fri Jul 11 17:38:45 2025 +0800

    update StructList
2025-07-14 16:20:11 +08:00
DCFApixels
4db3b1c32d up version to 0.9.15 2025-06-04 19:19:49 +08:00
DCFApixels
9a88fff7a7 remove static EcsAspect.GetMask 2025-06-04 18:45:24 +08:00
DCFApixels
68118dc581 add static EcsAspect.GetMask 2025-06-03 23:13:28 +08:00
DCFApixels
a016763824 Update entlong.cs 2025-06-03 09:49:08 +08:00
DCFApixels
5031853e91 update entlong.TryUnpack 2025-06-03 00:22:56 +08:00
15 changed files with 507 additions and 274 deletions

View File

@ -10,7 +10,7 @@
<RootNamespace>DCFApixels.DragonECS</RootNamespace> <RootNamespace>DCFApixels.DragonECS</RootNamespace>
<Title>DragonECS</Title> <Title>DragonECS</Title>
<Version>0.9.14</Version> <Version>0.9.16</Version>
<Authors>DCFApixels</Authors> <Authors>DCFApixels</Authors>
<Description>ECS Framework for Game Engines with C# and .Net Platform</Description> <Description>ECS Framework for Game Engines with C# and .Net Platform</Description>
<Copyright>DCFApixels</Copyright> <Copyright>DCFApixels</Copyright>

View File

@ -8,7 +8,7 @@
"displayName": "DragonECS", "displayName": "DragonECS",
"description": "C# Entity Component System Framework", "description": "C# Entity Component System Framework",
"unity": "2020.3", "unity": "2020.3",
"version": "0.9.14", "version": "0.9.16",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/DCFApixels/DragonECS.git" "url": "https://github.com/DCFApixels/DragonECS.git"

View File

@ -30,7 +30,7 @@ namespace DCFApixels.DragonECS
} }
public interface IEcsAspect public interface IEcsAspect
{ {
EcsMask Mask { get; set; } EcsMask Mask { get; }
} }
#region IEcsAspectExtensions tmp #region IEcsAspectExtensions tmp
@ -143,7 +143,6 @@ namespace DCFApixels.DragonECS
public EcsMask Mask public EcsMask Mask
{ {
get { return _mask; } get { return _mask; }
set { }
} }
public EcsWorld World public EcsWorld World
{ {

View File

@ -34,10 +34,10 @@ namespace DCFApixels.DragonECS
private int _freeNodesCount = 0; private int _freeNodesCount = 0;
private readonly Dictionary<string, LayerSystemsList> _layerLists = new Dictionary<string, LayerSystemsList>(8); private readonly Dictionary<string, LayerSystemsList> _layerLists = new Dictionary<string, LayerSystemsList>(8);
private readonly List<InitDeclaredRunner> _initDeclaredRunners = new List<InitDeclaredRunner>(4); private readonly StructList<InitDeclaredRunner> _initDeclaredRunners = new StructList<InitDeclaredRunner>(4);
public readonly LayersMap Layers; public readonly LayersMap Layers;
public readonly Injector.Builder Injector; public readonly InitInjectionList Injections;
public readonly Configurator Configs; public readonly Configurator Configs;
private AddParams _defaultAddParams = new AddParams(BASIC_LAYER, 0, false); private AddParams _defaultAddParams = new AddParams(BASIC_LAYER, 0, false);
@ -57,11 +57,12 @@ namespace DCFApixels.DragonECS
if (config == null) { config = new ConfigContainer(); } if (config == null) { config = new ConfigContainer(); }
Configs = new Configurator(config, this); Configs = new Configurator(config, this);
Injector = new Injector.Builder(this); var injectorBuilder = new Injector.InjectionList();
Injector.AddNode<object>(); Injections = new InitInjectionList(injectorBuilder, this);
Injector.AddNode<EcsWorld>(); Injections.AddNode<object>();
Injector.AddNode<EcsAspect>(); Injections.AddNode<EcsWorld>();
Injector.AddNode<EcsPipeline>(); Injections.AddNode<EcsAspect>();
Injections.AddNode<EcsPipeline>();
var graph = new DependencyGraph<string>(BASIC_LAYER); var graph = new DependencyGraph<string>(BASIC_LAYER);
Layers = new LayersMap(graph, this, PRE_BEGIN_LAYER, BEGIN_LAYER, BASIC_LAYER, END_LAYER, POST_END_LAYER); Layers = new LayersMap(graph, this, PRE_BEGIN_LAYER, BEGIN_LAYER, BASIC_LAYER, END_LAYER, POST_END_LAYER);
@ -201,7 +202,7 @@ namespace DCFApixels.DragonECS
_defaultAddParams = oldDefaultAddParams; _defaultAddParams = oldDefaultAddParams;
} }
Injector.Inject(module); Injections.Inject(module);
return this; return this;
} }
#endregion #endregion
@ -234,22 +235,21 @@ namespace DCFApixels.DragonECS
} }
private void MergeWith(Builder other) private void MergeWith(Builder other)
{ {
throw new NotImplementedException(); Injections.MergeWith(other.Injections);
//Injector.Add(other.Injector); foreach (var declaredRunners in other._initDeclaredRunners)
//foreach (var declaredRunners in other._initDeclaredRunners) {
//{ _initDeclaredRunners.Add(declaredRunners);
// _initDeclaredRunners.Add(declaredRunners); }
//} foreach (var config in other.Configs.Instance.GetAllConfigs())
//foreach (var config in other.Configs.Instance.GetAllConfigs()) {
//{ Configs.Instance.Set(config.Key, config.Value);
// Configs.Instance.Set(config.Key, config.Value); }
//} Layers.MergeWith(other.Layers);
//Layers.MergeWith(other.Layers);
// foreach (ref readonly SystemNode otherRecord in new LinkedListCountIterator<SystemNode>(_systemNodes, _systemNodesCount, _startIndex))
//foreach (ref readonly SystemNode otherRecord in new LinkedListCountIterator<SystemNode>(_systemNodes, _systemNodesCount, _startIndex)) {
//{ AddNode_Internal(otherRecord.system, otherRecord.layerName, otherRecord.sortOrder, otherRecord.isUnique);
// AddNode_Internal(otherRecord.system, otherRecord.layerName, otherRecord.sortOrder, otherRecord.isUnique); }
//}
} }
#endregion #endregion
@ -368,7 +368,7 @@ namespace DCFApixels.DragonECS
} }
} }
EcsPipeline pipeline = new EcsPipeline(Configs.Instance.GetContainer(), Injector, allSystems); EcsPipeline pipeline = new EcsPipeline((ReadOnlySpan<IEcsProcess>)allSystems, Configs.Instance.GetContainer(), Injections.Instance);
foreach (var item in _initDeclaredRunners) foreach (var item in _initDeclaredRunners)
{ {
item.Declare(pipeline); item.Declare(pipeline);
@ -394,8 +394,46 @@ namespace DCFApixels.DragonECS
} }
#endregion #endregion
#region InitInjector
public readonly struct InitInjectionList
{
private readonly Builder _pipelineBuilder;
public readonly Injector.InjectionList Instance;
public InitInjectionList(Injector.InjectionList instance, Builder pipelineBuilder)
{
Instance = instance;
_pipelineBuilder = pipelineBuilder;
}
public Builder AddNode<T>()
{
Instance.AddNode<T>();
return _pipelineBuilder;
}
public Builder Inject<T>(T obj)
{
Instance.Inject(obj);
return _pipelineBuilder;
}
public Builder Extract<T>(ref T obj)
{
Instance.Extract(ref obj);
return _pipelineBuilder;
}
public Builder Merge(Injector.InjectionList other)
{
Instance.MergeWith(other);
return _pipelineBuilder;
}
public Builder MergeWith(InitInjectionList other)
{
Instance.MergeWith(other.Instance);
return _pipelineBuilder;
}
}
#endregion
#region Configurator #region Configurator
public class Configurator public readonly struct Configurator
{ {
private readonly IConfigContainerWriter _configs; private readonly IConfigContainerWriter _configs;
private readonly Builder _builder; private readonly Builder _builder;
@ -564,6 +602,8 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Obsolete #region Obsolete
[Obsolete("Use " + nameof(Injections))]
public readonly InitInjectionList Injector;
[Obsolete("Use LayersMap")] [Obsolete("Use LayersMap")]
public class LayerList : LayersMap public class LayerList : LayersMap
{ {

View File

@ -78,11 +78,25 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Constructors #region Constructors
private EcsPipeline(IConfigContainer configs, Injector.Builder injectorBuilder, IEcsProcess[] systems) public EcsPipeline(ReadOnlySpan<IEcsProcess> systems, IConfigContainer configs = null, Injector.InjectionList injectionList = null) :
this(systems.ToArray(), configs, injectionList)
{ }
public EcsPipeline(IEnumerable<IEcsProcess> systems, IConfigContainer configs = null, Injector.InjectionList injectionList = null) :
this(systems.ToArray(), configs, injectionList)
{ }
private EcsPipeline(IEcsProcess[] systems, IConfigContainer configs, Injector.InjectionList injectionList)
{ {
if (configs == null)
{
configs = new ConfigContainer();
}
if (injectionList == null)
{
injectionList = Injector.InjectionList._Empty_Internal;
}
_configs = configs; _configs = configs;
_allSystems = systems; _allSystems = systems;
injectorBuilder.Inject(this);
var members = GetProcess<IEcsPipelineMember>(); var members = GetProcess<IEcsPipelineMember>();
for (int i = 0; i < members.Length; i++) for (int i = 0; i < members.Length; i++)
@ -90,7 +104,8 @@ namespace DCFApixels.DragonECS
members[i].Pipeline = this; members[i].Pipeline = this;
} }
_injector = injectorBuilder.Build(this); _injector = new Injector(this);
injectionList.InitInjectTo(_injector, this);
} }
~EcsPipeline() ~EcsPipeline()
{ {

View File

@ -114,7 +114,7 @@ namespace DCFApixels.DragonECS
} }
public ReadOnlySpan<WorldComponentPoolAbstract> GetAllWorldComponents() public ReadOnlySpan<WorldComponentPoolAbstract> GetAllWorldComponents()
{ {
return _worldComponentPools.ToReadOnlySpan(); return _worldComponentPools.AsReadOnlySpan();
} }
public abstract class WorldComponentPoolAbstract public abstract class WorldComponentPoolAbstract
{ {

View File

@ -10,7 +10,7 @@ namespace DCFApixels.DragonECS
public static EcsPipeline.Builder Inject<T>(this EcsPipeline.Builder self, T data) public static EcsPipeline.Builder Inject<T>(this EcsPipeline.Builder self, T data)
{ {
if (data == null) { Throw.ArgumentNull(); } if (data == null) { Throw.ArgumentNull(); }
self.Injector.Inject(data); self.Injections.Inject(data);
if (data is IEcsModule module) if (data is IEcsModule module)
{ {
self.AddModule(module); self.AddModule(module);

View File

@ -8,11 +8,8 @@ namespace DCFApixels.DragonECS.Core.Internal
{ {
internal class InjectionBranch internal class InjectionBranch
{ {
private readonly Injector _source;
private readonly Type _type; private readonly Type _type;
private InjectionNodeBase[] _nodes = new InjectionNodeBase[4]; private StructList<InjectionNodeBase> _nodes = new StructList<InjectionNodeBase>(4);
private int _nodesCount = 0;
public Type Type public Type Type
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -21,45 +18,15 @@ namespace DCFApixels.DragonECS.Core.Internal
public ReadOnlySpan<InjectionNodeBase> Nodes public ReadOnlySpan<InjectionNodeBase> Nodes
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return new ReadOnlySpan<InjectionNodeBase>(_nodes, 0, _nodesCount); } get { return _nodes.AsReadOnlySpan(); }
} }
public InjectionBranch(Injector source, Type type) public InjectionBranch(Type type)
{ {
_source = source;
_type = type; _type = type;
} }
public void Inject(object obj)
{
for (int i = 0; i < _nodesCount; i++)
{
_nodes[i].Inject(obj);
}
if (obj is IInjectionBlock block)
{
block.InjectTo(_source);
}
}
public void AddNode(InjectionNodeBase node) public void AddNode(InjectionNodeBase node)
{ {
if (_nodesCount >= _nodes.Length) _nodes.Add(node);
{
Array.Resize(ref _nodes, (_nodes.Length << 1) + 1);
}
_nodes[_nodesCount++] = node;
}
public void Trim()
{
if (_nodesCount <= 0)
{
_nodes = Array.Empty<InjectionNodeBase>();
return;
}
InjectionNodeBase[] newNodes = new InjectionNodeBase[_nodesCount];
for (int i = 0; i < newNodes.Length; i++)
{
newNodes[i] = _nodes[i];
}
} }
} }
} }

View File

@ -60,8 +60,6 @@ namespace DCFApixels.DragonECS.Core.Internal
} }
private void ExtractTo_Internal(object target) private void ExtractTo_Internal(object target)
{ {
var type = target.GetType();
var intrfs = type.GetInterfaces();
if (target is IEcsInject<T> intrf) if (target is IEcsInject<T> intrf)
{ {
intrf.Inject(_currentInjectedDependency); intrf.Inject(_currentInjectedDependency);

View File

@ -11,14 +11,59 @@ namespace DCFApixels.DragonECS
{ {
public class Injector : IInjector public class Injector : IInjector
{ {
private EcsPipeline _pipeline; private readonly EcsPipeline _pipeline;
private Dictionary<Type, InjectionBranch> _branches = new Dictionary<Type, InjectionBranch>(32); private readonly Dictionary<Type, InjectionBranch> _branches = new Dictionary<Type, InjectionBranch>(32);
private Dictionary<Type, InjectionNodeBase> _nodes = new Dictionary<Type, InjectionNodeBase>(32); private readonly Dictionary<Type, InjectionNodeBase> _nodes = new Dictionary<Type, InjectionNodeBase>(32);
private bool _isInit = false; private ReadOnlySpan<InjectionNodeBase> GetNodes(Type type)
{
if(_branches.TryGetValue(type, out InjectionBranch branch))
{
return branch.Nodes;
}
return Array.Empty<InjectionNodeBase>();
}
#if DEBUG #region InjectionTempHistory
private HashSet<Type> _requiredInjectionTypes = new HashSet<Type>(); private StructList<object> _injectionTempHistory = new StructList<object>(32);
#endif 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
public EcsPipeline Pipelie public EcsPipeline Pipelie
{ {
@ -26,12 +71,14 @@ namespace DCFApixels.DragonECS
get { return _pipeline; } get { return _pipeline; }
} }
private Injector() { } public Injector(EcsPipeline pipeline)
{
_pipeline = pipeline;
}
#region Inject/Extract/AddNode #region Inject/Extract/AddNode
public void Inject<T>(T obj) public void Inject<T>(T obj)
{ {
object raw = obj;
Type tType = typeof(T); Type tType = typeof(T);
Type objType = obj.GetType(); Type objType = obj.GetType();
if (_branches.TryGetValue(objType, out InjectionBranch branch) == false) if (_branches.TryGetValue(objType, out InjectionBranch branch) == false)
@ -40,31 +87,32 @@ namespace DCFApixels.DragonECS
{ {
InitNode(new InjectionNode<T>()); InitNode(new InjectionNode<T>());
} }
bool hasNode = _nodes.ContainsKey(objType); bool hasObjTypeNode = _nodes.ContainsKey(objType);
if (hasNode == false && obj is IInjectionUnit unit) if (hasObjTypeNode == false && obj is IInjectionUnit unit)
{ {
unit.InitInjectionNode(new InjectionGraph(this)); unit.InitInjectionNode(new InjectionGraph(this));
hasNode = _nodes.ContainsKey(objType); hasObjTypeNode = _nodes.ContainsKey(objType);
} }
branch = new InjectionBranch(this, objType); branch = new InjectionBranch(objType);
InitBranch(branch); InitBranch(branch);
}
#if DEBUG
foreach (var requiredInjectionType in _requiredInjectionTypes) var branchNodes = branch.Nodes;
for (int i = 0; i < branchNodes.Length; i++)
{ {
if (requiredInjectionType.IsAssignableFrom(objType)) branchNodes[i].Inject(obj);
}
if (_injectionTempHistoryReadersCount > 0)
{ {
if (_nodes.ContainsKey(requiredInjectionType) == false) _injectionTempHistory.Add(obj);
}
if (obj is IInjectionBlock block)
{ {
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 type {objType.Name}."); block.InjectTo(this);
} }
} }
}
#endif
}
branch.Inject(raw);
}
public void ExtractAllTo(object target) public void ExtractAllTo(object target)
{ {
if (target is IEcsInjectProcess == false) { return; } if (target is IEcsInjectProcess == false) { return; }
@ -86,12 +134,11 @@ namespace DCFApixels.DragonECS
} }
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}."); 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}.");
} }
public void AddNode<T>() public bool AddNode<T>()
{
if (_nodes.ContainsKey(typeof(T)) == false)
{ {
if (_nodes.ContainsKey(typeof(T))) { return false; }
InitNode(new InjectionNode<T>()); InitNode(new InjectionNode<T>());
} return true;
} }
#endregion #endregion
@ -126,71 +173,121 @@ namespace DCFApixels.DragonECS
} }
} }
} }
private bool IsCanInstantiated(Type type)
{
return !type.IsAbstract && !type.IsInterface;
}
#endregion #endregion
#region Build #region InjectionList
private void Init(EcsPipeline pipeline) public class InjectionList : IInjector
{ {
if (_isInit) { Throw.Exception("Already initialized"); } public static readonly InjectionList _Empty_Internal = new InjectionList();
_pipeline = pipeline; private StructList<InjectionBase> _injections = new StructList<InjectionBase>(32);
foreach (var pair in _nodes) private StructList<NodeBase> _nodes = new StructList<NodeBase>(32);
private EcsWorld _monoWorld;
public void AddNode<T>()
{ {
pair.Value.Init(pipeline); _nodes.Add(new Node<T>());
} }
_isInit = true; public void Inject<T>(T obj)
{
FindMonoWorld(obj);
_injections.Add(new Injection<T>(obj));
}
public void Extract<T>(ref T obj) // TODO проверить
{
Type type = typeof(T);
for (int i = _injections.Count - 1; i >= 0; i--)
{
var item = _injections[i];
if (type.IsAssignableFrom(item.Type))
{
obj = (T)item.Raw;
return;
}
}
Throw.UndefinedException();
}
public void MergeWith(InjectionList other)
{
foreach (var item in other._injections)
{
FindMonoWorld(item);
_injections.Add(item);
}
foreach (var item in other._nodes)
{
_nodes.Add(item);
}
}
public void InitInjectTo(Injector injector, EcsPipeline pipeline)
{
#if DEBUG #if DEBUG
var systems = _pipeline.AllSystems; HashSet<Type> requiredInjectionTypes = new HashSet<Type>();
var systems = pipeline.AllSystems;
var injectType = typeof(IEcsInject<>); var injectType = typeof(IEcsInject<>);
foreach (var system in systems) foreach (var system in systems)
{ {
var type = system.GetType(); var type = system.GetType();
foreach (var requiredInjectionType in type.GetInterfaces().Where(o => o.IsGenericType && o.GetGenericTypeDefinition() == injectType).Select(o => o.GenericTypeArguments[0])) foreach (var requiredInjectionType in type.GetInterfaces().Where(o => o.IsGenericType && o.GetGenericTypeDefinition() == injectType).Select(o => o.GenericTypeArguments[0]))
{ {
_requiredInjectionTypes.Add(requiredInjectionType); requiredInjectionTypes.Add(requiredInjectionType);
} }
} }
var reader = injector.StartReadHistory();
#endif #endif
}
private bool TryDeclare<T>()
var initInjectionCallbacks = pipeline.GetProcess<IOnInitInjectionComplete>();
foreach (var system in initInjectionCallbacks)
{ {
Type type = typeof(T); system.OnBeforeInitInjection();
if (_nodes.ContainsKey(type))
{
return false;
}
InitNode(new InjectionNode<T>());
#if !REFLECTION_DISABLED
if (IsCanInstantiated(type))
#endif
{
InitBranch(new InjectionBranch(this, type));
}
return true;
} }
public class Builder : IInjector injector.Inject(pipeline);
injector.AddNode<object>();
InjectTo(injector, pipeline);
foreach (var system in initInjectionCallbacks)
{ {
private EcsPipeline.Builder _source; system.OnInitInjectionComplete();
private Injector _instance;
private List<InitInjectBase> _initInjections = new List<InitInjectBase>(16);
private EcsWorld _monoWorld;
internal Builder(EcsPipeline.Builder source)
{
_source = source;
_instance = new Injector();
} }
public EcsPipeline.Builder AddNode<T>()
#if DEBUG
var injectionHistory = reader.StopReadAndGetHistorySpan();
foreach (var injection in injectionHistory)
{ {
_instance.TryDeclare<T>(); foreach (var node in injector.GetNodes(injection.GetType()))
return _source; {
requiredInjectionTypes.Remove(node.Type);
} }
public EcsPipeline.Builder Inject<T>(T obj) }
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
}
public void InjectTo(Injector injector, EcsPipeline pipeline)
{
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);
}
}
private void FindMonoWorld(object obj)
{ {
if (obj is EcsWorld objWorld) if (obj is EcsWorld objWorld)
{ {
@ -216,55 +313,6 @@ namespace DCFApixels.DragonECS
} }
} }
} }
_initInjections.Add(new InitInject<T>(obj));
return _source;
}
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 (type.IsAssignableFrom(item.Type))
{
obj = (T)item.Raw;
return _source;
}
}
Throw.UndefinedException();
return default;
}
public Injector Build(EcsPipeline pipeline)
{
var monoWorldProcess = pipeline.GetProcess<IMonoWorldInject>(); // TODO Проверить IMonoWorldInject
foreach (var monoWorldSystem in monoWorldProcess)
{
monoWorldSystem.World = _monoWorld;
}
var initInjectionCallbacks = pipeline.GetProcess<IOnInitInjectionComplete>();
foreach (var system in initInjectionCallbacks)
{
system.OnBeforeInitInjection();
}
_instance.Init(pipeline);
foreach (var item in _initInjections)
{
item.InjectTo(_instance);
}
foreach (var system in initInjectionCallbacks)
{
system.OnInitInjectionComplete();
}
return _instance;
}
public void Add(Builder other)
{
foreach (var item in other._initInjections)
{
_initInjections.Add(item);
}
} }
void IInjector.Inject<T>(T obj) { Inject(obj); } void IInjector.Inject<T>(T obj) { Inject(obj); }
@ -275,24 +323,38 @@ namespace DCFApixels.DragonECS
return result; return result;
} }
private abstract class InitInjectBase 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
{ {
public abstract Type Type { get; } public abstract Type Type { get; }
public abstract object Raw { get; } public abstract object Raw { get; }
public abstract void InjectTo(Injector instance); public abstract void InjectTo(Injector instance);
} }
private sealed class InitInject<T> : InitInjectBase private sealed class Injection<T> : InjectionBase
{ {
private T _injectedData; private T _injectedData;
public override Type Type { get { return typeof(T); } } public override Type Type { get { return typeof(T); } }
public override object Raw { get { return _injectedData; } } public override object Raw { get { return _injectedData; } }
public InitInject(T injectedData) public Injection(T injectedData)
{ {
_injectedData = injectedData; _injectedData = injectedData;
} }
public override void InjectTo(Injector instance) public override void InjectTo(Injector instance)
{ {
instance.Inject<T>(_injectedData); instance.Inject(_injectedData);
} }
} }
} }

View File

@ -31,5 +31,9 @@ namespace DCFApixels.DragonECS.Core.Internal
{ {
return self.GetCustomAttribute<T>(inherit) != null; return self.GetCustomAttribute<T>(inherit) != null;
} }
public static bool IsCanInstantiated(this Type type)
{
return !type.IsAbstract && !type.IsInterface;
}
} }
} }

View File

@ -12,8 +12,12 @@ namespace DCFApixels.DragonECS.Core.Internal
[DebuggerDisplay("Count: {Count}")] [DebuggerDisplay("Count: {Count}")]
internal struct StructList<T> internal struct StructList<T>
{ {
internal readonly static bool _IsManaged = RuntimeHelpers.IsReferenceOrContainsReferences<T>();
internal T[] _items; internal T[] _items;
internal int _count; internal int _count;
#region Properties
public int Count public int Count
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -30,6 +34,11 @@ namespace DCFApixels.DragonECS.Core.Internal
Array.Resize(ref _items, value); Array.Resize(ref _items, value);
} }
} }
public bool IsNull
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _items == null; }
}
public T this[int index] public T this[int index]
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -49,13 +58,16 @@ namespace DCFApixels.DragonECS.Core.Internal
_items[index] = value; _items[index] = value;
} }
} }
#endregion
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public StructList(int capacity) public StructList(int capacity)
{ {
_items = new T[ArrayUtility.NextPow2(capacity)]; _items = new T[ArrayUtility.NextPow2(capacity)];
_count = 0; _count = 0;
} }
#endregion
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(T item) public void Add(T item)
@ -64,6 +76,11 @@ namespace DCFApixels.DragonECS.Core.Internal
{ {
Array.Resize(ref _items, _items.Length << 1); Array.Resize(ref _items, _items.Length << 1);
} }
AddFixed(item);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddFixed(T item)
{
_items[_count++] = item; _items[_count++] = item;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -72,6 +89,11 @@ namespace DCFApixels.DragonECS.Core.Internal
return Array.IndexOf(_items, item, 0, _count); return Array.IndexOf(_items, item, 0, _count);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Contains(T item)
{
return _count != 0 && IndexOf(item) >= 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SwapAt(int idnex1, int idnex2) public void SwapAt(int idnex1, int idnex2)
{ {
T tmp = _items[idnex1]; T tmp = _items[idnex1];
@ -93,8 +115,11 @@ namespace DCFApixels.DragonECS.Core.Internal
if (index < 0 || index >= _count) { Throw.ArgumentOutOfRange(); } if (index < 0 || index >= _count) { Throw.ArgumentOutOfRange(); }
#endif #endif
_items[index] = _items[--_count]; _items[index] = _items[--_count];
if (_IsManaged)
{
_items[_count] = default; _items[_count] = default;
} }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveAtWithOrder(int index) public void RemoveAtWithOrder(int index)
{ {
@ -128,6 +153,56 @@ namespace DCFApixels.DragonECS.Core.Internal
} }
return false; return false;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Peek()
{
#if DEBUG
if (_count <= 0) { Throw.EmptyStack(); }
#endif
return _items[_count - 1];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPeek(out T result)
{
if (_count <= 0)
{
result = default;
return false;
}
result = _items[_count - 1];
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Pop()
{
#if DEBUG
if (_count <= 0) { Throw.EmptyStack(); }
#endif
T result = _items[--_count];
if (_IsManaged)
{
_items[_count] = default;
}
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPop(out T result)
{
if (_count <= 0)
{
result = default;
return false;
}
result = _items[--_count];
if (_IsManaged)
{
_items[_count] = default;
}
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FastClear() public void FastClear()
{ {
@ -136,19 +211,31 @@ namespace DCFApixels.DragonECS.Core.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear() public void Clear()
{ {
for (int i = 0; i < _count; i++) if (_IsManaged)
{ {
_items[i] = default; Array.Clear(_items, 0, _count);
} }
_count = 0; _count = 0;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Recreate()
{
_items = new T[_items.Length];
_count = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Recreate(int newSize)
{
_items = new T[ArrayUtility.NextPow2(newSize)];
_count = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<T>.Enumerator GetEnumerator() public ReadOnlySpan<T>.Enumerator GetEnumerator()
{ {
return new ReadOnlySpan<T>(_items, 0, _count).GetEnumerator(); return new ReadOnlySpan<T>(_items, 0, _count).GetEnumerator();
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<T> ToReadOnlySpan() public ReadOnlySpan<T> AsReadOnlySpan()
{ {
return new ReadOnlySpan<T>(_items, 0, _count); return new ReadOnlySpan<T>(_items, 0, _count);
} }
@ -157,5 +244,13 @@ namespace DCFApixels.DragonECS.Core.Internal
{ {
return _items.Take(_count); return _items.Take(_count);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T[] ToArray()
{
if (_count <= 0) { return Array.Empty<T>(); }
T[] result = new T[_count];
Array.Copy(_items, result, _count);
return result;
}
} }
} }

View File

@ -141,8 +141,17 @@ namespace DCFApixels.DragonECS.Core.Internal
{ {
throw new ArgumentException("The groups belong to different worlds."); throw new ArgumentException("The groups belong to different worlds.");
} }
[MethodImpl(MethodImplOptions.NoInlining)]
internal static void ArgumentDifferentWorldsException()
{
throw new ArgumentException("The groups belong to different worlds.");
}
[MethodImpl(MethodImplOptions.NoInlining)]
internal static void EmptyStack()
{
throw new InvalidOperationException("Invalid Operation Empty Stack.");
}
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
internal static void ArgumentNull() internal static void ArgumentNull()
{ {

View File

@ -19,7 +19,7 @@ namespace DCFApixels.DragonECS.Core
private readonly IDependencyGraph<string> _graph; private readonly IDependencyGraph<string> _graph;
private readonly EcsPipeline.Builder _pipelineBuilder; private readonly EcsPipeline.Builder _pipelineBuilder;
private readonly string _preBeginLayer; //private readonly string _preBeginLayer;
#region Properties #region Properties
public EcsPipeline.Builder Back public EcsPipeline.Builder Back
@ -209,21 +209,21 @@ namespace DCFApixels.DragonECS.Core
{ {
var enumerator = other.GetEnumerator(); var enumerator = other.GetEnumerator();
string prev = null; string prev = null;
if (_preBeginLayer != null) //if (_preBeginLayer != null)
{ //{
while (enumerator.MoveNext()) // while (enumerator.MoveNext())
{ // {
var layer = enumerator.Current; // var layer = enumerator.Current;
if (layer == _preBeginLayer) { break; } // if (layer == _preBeginLayer) { break; }
//
Add(layer); // Add(layer);
if (prev != null) // if (prev != null)
{ // {
Move(prev).Before(layer); // Move(prev).Before(layer);
} // }
prev = layer; // prev = layer;
} // }
} //}
while (enumerator.MoveNext()) while (enumerator.MoveNext())
{ {
var layer = enumerator.Current; var layer = enumerator.Current;

View File

@ -136,7 +136,7 @@ namespace DCFApixels.DragonECS
} }
#endregion #endregion
#region Unpacking #region Unpacking Try
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryGetID(out int id) public bool TryGetID(out int id)
{ {
@ -156,6 +156,90 @@ namespace DCFApixels.DragonECS
return IsAlive; return IsAlive;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(out int id)
{
id = _id;
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(out int id, out EcsWorld world)
{
world = GetWorld_Internal();
id = _id;
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(out int id, out short gen, out EcsWorld world)
{
world = GetWorld_Internal();
gen = _gen;
id = _id;
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(out int id, out short worldID)
{
worldID = _world;
id = _id;
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(out int id, out short gen, out short worldID)
{
worldID = _world;
gen = _gen;
id = _id;
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(EcsWorld world, out int id)
{
if (world.ID != _world) { Throw.ArgumentDifferentWorldsException(); }
id = _id;
return world.IsAlive(_id, _gen);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(EcsWorld world, out int id, out short gen)
{
if (world.ID != _world) { Throw.ArgumentDifferentWorldsException(); }
gen = _gen;
id = _id;
return world.IsAlive(_id, _gen);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(EcsMask mask, out int id)
{
if (mask.WorldID != _world) { Throw.ArgumentDifferentWorldsException(); }
id = _id;
return mask.World.IsAlive(_id, _gen) && mask.World.IsMatchesMask(mask, _id);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(EcsMask mask, out int id, out short gen)
{
if (mask.WorldID != _world) { Throw.ArgumentDifferentWorldsException(); }
gen = _gen;
id = _id;
return mask.World.IsAlive(_id, _gen) && mask.World.IsMatchesMask(mask, _id);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(EcsAspect aspect, out int id)
{
if (aspect.World.ID != _world) { Throw.ArgumentDifferentWorldsException(); }
id = _id;
return aspect.World.IsAlive(_id, _gen) && aspect.IsMatches(_id);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(EcsAspect aspect, out int id, out short gen)
{
if (aspect.World.ID != _world) { Throw.ArgumentDifferentWorldsException(); }
gen = _gen;
id = _id;
return aspect.World.IsAlive(_id, _gen) && aspect.IsMatches(_id);
}
#endregion
#region Unpacking/Deconstruct
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Unpack(out int id) public void Unpack(out int id)
{ {
@ -238,46 +322,13 @@ namespace DCFApixels.DragonECS
gen = _gen; gen = _gen;
id = _id; id = _id;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(out int id) public void Deconstruct(out int id, out short gen, out short worldID) { Unpack(out id, out gen, out worldID); }
{
id = _id;
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(out int id, out EcsWorld world) public void Deconstruct(out int id, out EcsWorld world) { Unpack(out id, out world); }
{
world = GetWorld_Internal();
id = _id;
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(out int id, out short gen, out EcsWorld world)
{
world = GetWorld_Internal();
gen = _gen;
id = _id;
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(out int id, out short worldID)
{
worldID = _world;
id = _id;
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(out int id, out short gen, out short worldID)
{
worldID = _world;
gen = _gen;
id = _id;
return IsAlive;
}
#endregion #endregion
#region Unpacking #region Unpacking Unchecked
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetIDUnchecked() public int GetIDUnchecked()
{ {
@ -352,13 +403,6 @@ namespace DCFApixels.DragonECS
public static explicit operator int(entlong a) { return a.ID; } public static explicit operator int(entlong a) { return a.ID; }
#endregion #endregion
#region Deconstruct
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Deconstruct(out int id, out short gen, out short worldID) { Unpack(out id, out gen, out worldID); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Deconstruct(out int id, out EcsWorld world) { Unpack(out id, out world); }
#endregion
#region Other #region Other
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private EcsWorld GetWorld_Internal() private EcsWorld GetWorld_Internal()