diff --git a/src/Builtin/IsMissingRelationNode.cs b/src/Builtin/IsMissingRelationNode.cs new file mode 100644 index 0000000..88664b4 --- /dev/null +++ b/src/Builtin/IsMissingRelationNode.cs @@ -0,0 +1,9 @@ +namespace DCFApixels.DragonECS +{ + [System.Serializable] + [MetaColor(MetaColor.DragonRose)] + [MetaGroup(EcsGraphConsts.PACK_GROUP)] + [MetaDescription(EcsConsts.AUTHOR, "...")] + [MetaID("1C53321A9301DB70DB84A88611F6C36C")] + public struct IsMissingRelationNode : IEcsTagComponent { } +} diff --git a/src/Consts.cs b/src/Consts.cs new file mode 100644 index 0000000..a1cb661 --- /dev/null +++ b/src/Consts.cs @@ -0,0 +1,7 @@ +namespace DCFApixels.DragonECS +{ + public static class EcsGraphConsts + { + public const string PACK_GROUP = "_" + EcsConsts.FRAMEWORK_NAME + "/Graphs"; + } +} diff --git a/src/EcsGraphExtensions.cs b/src/EcsGraphExtensions.cs index 53f3652..3ea2e6a 100644 --- a/src/EcsGraphExtensions.cs +++ b/src/EcsGraphExtensions.cs @@ -5,45 +5,45 @@ namespace DCFApixels.DragonECS { public static class EcsGraphExtensions { - private static EcsGraph[] _worldGraphs = new EcsGraph[4]; + private static EntityGraph[] _worldGraphs = new EntityGraph[4]; - public static EcsGraph CreateGraph(this EcsWorld self, EcsWorld graphWorld) + public static EntityGraph CreateGraph(this EcsWorld self, EcsWorld graphWorld) { int worldID = self.ID; if (_worldGraphs.Length <= worldID) { Array.Resize(ref _worldGraphs, worldID + 4); } - ref EcsGraph graph = ref _worldGraphs[worldID]; + ref EntityGraph graph = ref _worldGraphs[worldID]; if (graph != null) { Throw.UndefinedException(); } - graph = new EcsGraph(self, graphWorld); + graph = new EntityGraph(self, graphWorld); new Destroyer(graph); _worldGraphs[graphWorld.ID] = graph; return graph; } - public static EcsGraph CreateOrGetGraph(this EcsWorld self, EcsWorld graphWorld) + public static EntityGraph CreateOrGetGraph(this EcsWorld self, EcsWorld graphWorld) { int worldID = self.ID; if (_worldGraphs.Length <= worldID) { Array.Resize(ref _worldGraphs, worldID + 4); } - ref EcsGraph graph = ref _worldGraphs[worldID]; + ref EntityGraph graph = ref _worldGraphs[worldID]; if (graph != null) { return graph; } - graph = new EcsGraph(self, graphWorld); + graph = new EntityGraph(self, graphWorld); new Destroyer(graph); _worldGraphs[graphWorld.ID] = graph; return graph; } - public static bool TryGetGraph(this EcsWorld self, out EcsGraph graph) + public static bool TryGetGraph(this EcsWorld self, out EntityGraph graph) { int worldID = self.ID; if (_worldGraphs.Length <= worldID) @@ -54,9 +54,9 @@ namespace DCFApixels.DragonECS return graph != null; } - public static EcsGraph GetGraph(this EcsWorld self) + public static EntityGraph GetGraph(this EcsWorld self) { - if (self.TryGetGraph(out EcsGraph graph)) + if (self.TryGetGraph(out EntityGraph graph)) { return graph; } @@ -66,14 +66,14 @@ namespace DCFApixels.DragonECS public static bool IsGraphWorld(this EcsWorld self) { - if (self.TryGetGraph(out EcsGraph graph)) + if (self.TryGetGraph(out EntityGraph graph)) { return graph.GraphWorld == self; } return false; } - private static void TryDestroy(EcsGraph graph) + private static void TryDestroy(EntityGraph graph) { int worldID = graph.WorldID; if (_worldGraphs.Length <= worldID) @@ -90,8 +90,8 @@ namespace DCFApixels.DragonECS } private class Destroyer : IEcsWorldEventListener { - private EcsGraph _graph; - public Destroyer(EcsGraph graph) + private EntityGraph _graph; + public Destroyer(EntityGraph graph) { _graph = graph; graph.World.AddListener(this); diff --git a/src/EcsGraph.cs b/src/EntityGraph.cs similarity index 77% rename from src/EcsGraph.cs rename to src/EntityGraph.cs index 2fb5134..536d0f2 100644 --- a/src/EcsGraph.cs +++ b/src/EntityGraph.cs @@ -8,7 +8,7 @@ namespace DCFApixels.DragonECS //Graph world //Rel entity //Component - public class EcsGraph + public class EntityGraph { private readonly EcsWorld _world; private readonly EcsWorld _graphWorld; @@ -16,13 +16,13 @@ namespace DCFApixels.DragonECS private readonly GraphWorldHandler _arcWorldHandler; private readonly WorldHandler _loopWorldHandler; - private RelationInfo[] _relEntityInfos; //N * (N - 1) / 2 private readonly SparseMatrix _matrix; - - private bool _isInit = false; + private RelationInfo[] _relEntityInfos; //N * (N - 1) / 2 private int _count; + private bool _isInit = false; + #region Properties internal bool IsInit_Internal { @@ -57,7 +57,7 @@ namespace DCFApixels.DragonECS #endregion #region Constructors/Destroy - internal EcsGraph(EcsWorld world, EcsWorld graphWorld) + internal EntityGraph(EcsWorld world, EcsWorld graphWorld) { _world = world; _graphWorld = graphWorld; @@ -146,6 +146,23 @@ namespace DCFApixels.DragonECS } #endregion + #region MoveRelation + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void MoveRelation(int relEntityID, int newStartEntityID, int newEndEntityID) + { + var startEnd = GetRelationStartEnd(relEntityID); + + //Тут будет не стабильное состояние если TryDel пройдет, а TryAdd - нет + if (_matrix.TryDel(startEnd.start, startEnd.end) == false || + _matrix.TryAdd(newStartEntityID, newEndEntityID, relEntityID) == false) + { + Throw.UndefinedException(); + } + + _relEntityInfos[relEntityID] = new RelationInfo(newStartEntityID, newEndEntityID); + } + #endregion + #region Get [MethodImpl(MethodImplOptions.AggressiveInlining)] public int GetRelation(int startEntityID, int endEntityID) @@ -179,7 +196,11 @@ namespace DCFApixels.DragonECS } #endregion - #region ArcEntityInfo + #region Other + public static implicit operator EntityGraph(SingletonMarker marker) { return marker.Builder.World.GetGraph(); } + #endregion + + #region RelEntityInfo [MethodImpl(MethodImplOptions.AggressiveInlining)] public StartEnd GetRelationStartEnd(int relEntityID) @@ -213,8 +234,8 @@ namespace DCFApixels.DragonECS #region GraphWorldHandler private class GraphWorldHandler : IEcsWorldEventListener { - private readonly EcsGraph _arc; - public GraphWorldHandler(EcsGraph arc) + private readonly EntityGraph _arc; + public GraphWorldHandler(EntityGraph arc) { _arc = arc; _arc.GraphWorld.AddListener(this); @@ -243,38 +264,51 @@ namespace DCFApixels.DragonECS #region WorldHandler private class WorldHandler : IEcsWorldEventListener { - private readonly EcsGraph _arc; - public WorldHandler(EcsGraph arc) + private readonly EntityGraph _graph; + public WorldHandler(EntityGraph arc) { - _arc = arc; - _arc.World.AddListener(this); + _graph = arc; + _graph.World.AddListener(this); } public void Destroy() { - _arc.World.RemoveListener(this); + _graph.World.RemoveListener(this); } #region Callbacks - public void OnReleaseDelEntityBuffer(ReadOnlySpan startEntityBuffer) + public void OnReleaseDelEntityBuffer(ReadOnlySpan delEntities) { - var graph = _arc.GraphWorld.JoinToSubGraph(EcsSubGraphMode.All); - foreach (var e in startEntityBuffer) + EcsSubGraph subGraph; + EcsWorld graphWorld = _graph._graphWorld; + + //subGraph = graphWorld.JoinToSubGraph(EcsSubGraphMode.StartToEnd); + subGraph = graphWorld.JoinToSubGraph(EcsSubGraphMode.All); + foreach (var sourceE in delEntities) { - var span = graph.GetNodes(e); - foreach (var relE in span) + var relEs = subGraph.GetRelations(sourceE); + foreach (var relE in relEs) { - _arc.DelRelation(relE); + //int missingE = graphWorld.NewEntity(); + _graph.DelRelation(relE); } } - _arc._graphWorld.ReleaseDelEntityBufferAll(); + + //subGraph = graphWorld.JoinToSubGraph(EcsSubGraphMode.EndToStart); + //foreach (var sourceE in delEntities) + //{ + // var relEs = subGraph.GetRelations(sourceE); + // foreach (var relE in relEs) + // { + // //int missingE = graphWorld.NewEntity(); + // _graph.DelRelation(relE); + // } + //} + + graphWorld.ReleaseDelEntityBufferAll(); } public void OnWorldDestroy() { } public void OnWorldResize(int startWorldNewSize) { } #endregion } #endregion - - #region Other - public static implicit operator EcsGraph(SingletonMarker marker) { return marker.Builder.World.GetGraph(); } - #endregion } } \ No newline at end of file diff --git a/src/Executors/EcsJoinExecutor.cs b/src/Executors/EcsJoinExecutor.cs deleted file mode 100644 index c43a043..0000000 --- a/src/Executors/EcsJoinExecutor.cs +++ /dev/null @@ -1,45 +0,0 @@ -using DCFApixels.DragonECS.Core; -using System; -using System.Runtime.CompilerServices; - -namespace DCFApixels.DragonECS -{ - public class EcsJoinExecutor : MaskQueryExecutor, IEcsWorldEventListener - { - private long _lastWorldVersion; - - #region Properties - public sealed override long Version - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _lastWorldVersion; - } - public override bool IsCached - { - get { return false; } - } - public override int LastCachedCount - { - get { return 0; } - } - #endregion - - #region Callbacks - protected override void OnInitialize() - { - } - protected override void OnDestroy() - { - } - public void OnWorldResize(int newSize) - { - } - public void OnReleaseDelEntityBuffer(ReadOnlySpan buffer) - { - } - public void OnWorldDestroy() - { - } - #endregion - } -} diff --git a/src/Executors/EcsJoinExecutor.cs.meta b/src/Executors/EcsJoinExecutor.cs.meta deleted file mode 100644 index bb9920d..0000000 --- a/src/Executors/EcsJoinExecutor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2b337a549ff9db3488c9ae26a898f770 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/Executors/EcsJoinToSubGraphExecutor.cs b/src/Executors/EcsJoinToSubGraphExecutor.cs index 9cd7ec6..1dc9789 100644 --- a/src/Executors/EcsJoinToSubGraphExecutor.cs +++ b/src/Executors/EcsJoinToSubGraphExecutor.cs @@ -7,48 +7,61 @@ using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS { + using LinkedList = OnlyAppendHeadLinkedList; public sealed class EcsJoinToSubGraphExecutor : MaskQueryExecutor, IEcsWorldEventListener { - private EntityLinkedList _linkedList; - private Basket[] _baskets; + private EntityGraph _graph; + private EcsMaskIterator _iterator; + + private int[] _filteredAllEntities = new int[32]; + private int _filteredAllEntitiesCount = 0; + private int[] _filteredEntities = null; + private int _filteredEntitiesCount = 0; + + private int[] _currentFilteredEntities = null; + private int _currentFilteredEntitiesCount = 0; + + private long _version; + private WorldStateVersionsChecker _versionsChecker; + + private LinkedList _linkedList; + private LinkedListHead[] _linkedListSourceHeads; + private int[] _startEntities; private int _startEntitiesCount; - private EcsGraph _graph; - - private long _lastWorldVersion; - private int _targetWorldCapacity = -1; - private EcsProfilerMarker _executeMarker = new EcsProfilerMarker("JoinAttach"); - - private EcsMaskIterator _iterator; + private EcsProfilerMarker _executeMarker = new EcsProfilerMarker("Join"); #region Properties public sealed override long Version { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _lastWorldVersion; } + get { return _version; } } - public EcsGraph Graph + public EntityGraph Graph { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _graph; } } - public override bool IsCached + public sealed override bool IsCached { - get { return false; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _versionsChecker.Check(); } } - public override int LastCachedCount + public sealed override int LastCachedCount { - get { return 0; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _filteredAllEntitiesCount; } } #endregion #region OnInitialize/OnDestroy protected override void OnInitialize() { - _linkedList = new EntityLinkedList(World.Capacity); - _baskets = new Basket[World.Capacity]; + _versionsChecker = new WorldStateVersionsChecker(Mask); + _linkedList = new OnlyAppendHeadLinkedList(World.Capacity); + _linkedListSourceHeads = new LinkedListHead[World.Capacity]; World.AddListener(this); _graph = World.GetGraph(); _iterator = Mask.GetIterator(); @@ -60,95 +73,188 @@ namespace DCFApixels.DragonECS #endregion #region Execute - public EcsSubGraph Execute(EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) + private EcsSubGraph Execute_Internal(EcsSubGraphMode mode) { - return ExecuteFor(World.Entities, mode); + _executeMarker.Begin(); + + World.ReleaseDelEntityBufferAllAuto(); + + if (Mask.IsEmpty) + { + _filteredAllEntitiesCount = World.Entities.ToArray(ref _filteredAllEntities); + } + else + { + if (_versionsChecker.CheckAndNext() == false) + { + _filteredAllEntitiesCount = _iterator.IterateTo(World.Entities, ref _filteredAllEntities); + ////Подготовка массивов + //if (_startEntities.Length < _filteredAllEntitiesCount * 2) + //{ + // _startEntities = new int[_filteredAllEntitiesCount * 2]; + //} + } + } + + + //установка текущего массива + _currentFilteredEntities = _filteredAllEntities; + _currentFilteredEntitiesCount = _filteredAllEntitiesCount; + + //Подготовка массивов + if (_targetWorldCapacity < World.Capacity) + { + _targetWorldCapacity = World.Capacity; + _linkedListSourceHeads = new LinkedListHead[_targetWorldCapacity]; + _startEntities = new int[_targetWorldCapacity]; + } + else + { + ArrayUtility.Fill(_linkedListSourceHeads, default); //TODO оптимизировать, сделав не полную отчистку а только по элементов с прошлого раза + } + _startEntitiesCount = 0; + _linkedList.Clear(); + + //Заполнение массивов + if ((mode & EcsSubGraphMode.StartToEnd) != 0) + { + for (int i = 0; i < _filteredAllEntitiesCount; i++) + { + AddStart(_filteredAllEntities[i]); + } + } + if ((mode & EcsSubGraphMode.EndToStart) != 0) + { + for (int i = 0; i < _filteredAllEntitiesCount; i++) + { + AddEnd(_filteredAllEntities[i]); + } + } + + _version++; + + _executeMarker.End(); + return new EcsSubGraph(this); } - public EcsSubGraph ExecuteFor(EcsSpan span, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) + private EcsSubGraph ExecuteFor_Internal(EcsSpan span, EcsSubGraphMode mode) { _executeMarker.Begin(); #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (span.IsNull) { Throw.ArgumentException(""); }//TODO составить текст исключения. - else if (World != span.World) { Throw.ArgumentException(""); } //TODO составить текст исключения. это проверка на то что пользователь использует правильный мир + if (span.IsNull) { _executeMarker.End(); Throw.ArgumentNull(nameof(span)); } + if (span.WorldID != World.ID) { _executeMarker.End(); Throw.Quiery_ArgumentDifferentWorldsException(); } #endif - - //if (_lastWorldVersion != World.Version) + if (_filteredEntities == null) { - //Подготовка массивов - if (_targetWorldCapacity < World.Capacity) - { - _targetWorldCapacity = World.Capacity; - _baskets = new Basket[_targetWorldCapacity]; - _startEntities = new int[_targetWorldCapacity]; - } - else - { - ArrayUtility.Fill(_baskets, default); - } - _startEntitiesCount = 0; - _linkedList.Clear(); - //Конец подготовки массивов - - if ((mode & EcsSubGraphMode.StartToEnd) != 0) - { - if (Mask.IsEmpty) - { - foreach (var relationEntityID in span) { AddStart(relationEntityID); } - } - else - { - foreach (var relationEntityID in _iterator.Iterate(span)) { AddStart(relationEntityID); } - } - } - if ((mode & EcsSubGraphMode.EndToStart) != 0) - { - if (Mask.IsEmpty) - { - foreach (var relationEntityID in span) { AddEnd(relationEntityID); } - } - else - { - foreach (var relationEntityID in _iterator.Iterate(span)) { AddEnd(relationEntityID); } - } - } - - _lastWorldVersion = World.Version; + _filteredEntities = new int[32]; } - //else - //{ - // - //} + _filteredEntitiesCount = _iterator.IterateTo(span, ref _filteredEntities); + + throw new NotImplementedException(); _executeMarker.End(); - return new EcsSubGraph(this, UncheckedCoreUtility.CreateSpan(WorldID, _startEntities, _startEntitiesCount)); } + + public EcsSubGraph Execute(EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) + { + return Execute_Internal(mode); + } + public EcsSubGraph ExecuteFor(EcsSpan span, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) + { + return ExecuteFor_Internal(span, mode); + } + + #region TMP + // public EcsSubGraph Execute(EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) + // { + // return ExecuteFor(World.Entities, mode); + // } + // public EcsSubGraph ExecuteFor(EcsSpan span, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) + // { + // _executeMarker.Begin(); + //#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + // if (span.IsNull) { Throw.ArgumentException(""); }//TODO составить текст исключения. + // else if (World != span.World) { Throw.ArgumentException(""); } //TODO составить текст исключения. это проверка на то что пользователь использует правильный мир + //#endif + // + // //if (_lastWorldVersion != World.Version) + // { + // //Подготовка массивов + // if (_targetWorldCapacity < World.Capacity) + // { + // _targetWorldCapacity = World.Capacity; + // _baskets = new Basket[_targetWorldCapacity]; + // _startEntities = new int[_targetWorldCapacity]; + // } + // else + // { + // ArrayUtility.Fill(_baskets, default); + // } + // _startEntitiesCount = 0; + // _linkedList.Clear(); + // //Конец подготовки массивов + // + // if ((mode & EcsSubGraphMode.StartToEnd) != 0) + // { + // if (Mask.IsEmpty) + // { + // foreach (var relationEntityID in span) { AddStart(relationEntityID); } + // } + // else + // { + // foreach (var relationEntityID in _iterator.Iterate(span)) { AddStart(relationEntityID); } + // } + // } + // if ((mode & EcsSubGraphMode.EndToStart) != 0) + // { + // if (Mask.IsEmpty) + // { + // foreach (var relationEntityID in span) { AddEnd(relationEntityID); } + // } + // else + // { + // foreach (var relationEntityID in _iterator.Iterate(span)) { AddEnd(relationEntityID); } + // } + // } + // + // _lastWorldVersion = World.Version; + // } + // //else + // //{ + // // + // //} + // + // _executeMarker.End(); + // return new EcsSubGraph(this, UncheckedCoreUtility.CreateSpan(WorldID, _startEntities, _startEntitiesCount)); + // } + #endregion + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AddStart(int relationEntityID) { - AddFrom(_graph.GetRelationStart(relationEntityID), relationEntityID); + AddSourceEntity(_graph.GetRelationStart(relationEntityID), relationEntityID); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AddEnd(int relationEntityID) { - AddFrom(_graph.GetRelationEnd(relationEntityID), relationEntityID); + AddSourceEntity(_graph.GetRelationEnd(relationEntityID), relationEntityID); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void AddFrom(int fromEntityID, int relationEntityID) + private void AddSourceEntity(int sourceEntityID, int relationEntityID) { - if (fromEntityID == 0) + if (sourceEntityID == 0) { return; } - ref var basket = ref _baskets[fromEntityID]; - if (basket.index <= 0) + ref var basket = ref _linkedListSourceHeads[sourceEntityID]; + if (basket.head == 0) { - _startEntities[_startEntitiesCount++] = fromEntityID; - basket.index = _linkedList.Add(relationEntityID); + _startEntities[_startEntitiesCount++] = sourceEntityID; + basket.head = _linkedList.NewHead(relationEntityID); } else { - basket.index = _linkedList.InsertBefore(basket.index, relationEntityID); + _linkedList.InsertIntoHead(ref basket.head, relationEntityID); } basket.count++; } @@ -156,21 +262,21 @@ namespace DCFApixels.DragonECS #region Internal result methods [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal EcsSubGraphSpan GetNodes_Internal(int startEntityID) + internal EcsSubGraphSpan GetRelations_Internal(int sourceEntityID) { - Basket basket = _baskets[startEntityID]; - return new EcsSubGraphSpan(_linkedList._nodes, basket.index, basket.count); + LinkedListHead basket = _linkedListSourceHeads[sourceEntityID]; + return new EcsSubGraphSpan(_linkedList._nodes, basket.head, basket.count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal int GetNode_Internal(int startEntityID) + internal int GetRelation_Internal(int sourceEntityID) { - Basket basket = _baskets[startEntityID]; - return basket.count > 0 ? _linkedList.Get(basket.index) : 0; + LinkedListHead basket = _linkedListSourceHeads[sourceEntityID]; + return basket.count > 0 ? _linkedList.Get(basket.head) : 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal int GetNodesCount_Internal(int startEntityID) + internal int GetRelationsCount_Internal(int sourceEntityID) { - return _baskets[startEntityID].count; + return _linkedListSourceHeads[sourceEntityID].count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal int GetCount_Internal() @@ -182,26 +288,37 @@ namespace DCFApixels.DragonECS #region IEcsWorldEventListener void IEcsWorldEventListener.OnWorldResize(int newSize) { - Array.Resize(ref _baskets, newSize); + Array.Resize(ref _linkedListSourceHeads, newSize); } void IEcsWorldEventListener.OnReleaseDelEntityBuffer(ReadOnlySpan buffer) { } void IEcsWorldEventListener.OnWorldDestroy() { } #endregion #region Basket - public struct Basket + private struct LinkedListHead { - public int index; + public LinkedList.NodeIndex head; public int count; public override string ToString() { - return $"i:{index} count:{count}"; + return $"i:{head} count:{count}"; } } #endregion + + #region GetEntites + internal EcsSpan GetSourceEntities() + { + return UncheckedCoreUtility.CreateSpan(WorldID, _startEntities, _startEntitiesCount); + } + internal EcsSpan GetRelEntities() + { + return UncheckedCoreUtility.CreateSpan(WorldID, _currentFilteredEntities, _currentFilteredEntitiesCount); + } + #endregion } - public enum EcsSubGraphMode + public enum EcsSubGraphMode : byte { NONE = 0, StartToEnd = 1 << 0, @@ -209,7 +326,40 @@ namespace DCFApixels.DragonECS All = StartToEnd | EndToStart, } - #region EcsJoinedSpan/EcsJoined + #region EcsSubGraphSpan/EcsSubGraph + public readonly ref struct EcsSubGraph + { + private readonly EcsJoinToSubGraphExecutor _executer; + public EntityGraph Graph + { + get { return _executer.Graph; } + } + internal EcsSubGraph(EcsJoinToSubGraphExecutor executer) + { + _executer = executer; + } + public EcsSpan GetSourceEntities() + { + return _executer.GetSourceEntities(); + } + public EcsSpan GetAllRelEntities() + { + return _executer.GetRelEntities(); + } + public EcsSubGraphSpan GetRelations(int startEntityID) + { + return _executer.GetRelations_Internal(startEntityID); + } + public int GetRelation(int startEntityID) + { + return _executer.GetRelation_Internal(startEntityID); + } + public int GetRelationsCount(int startEntityID) + { + return _executer.GetRelationsCount_Internal(startEntityID); + } + } + public readonly ref struct EcsSubGraphSpan { public static EcsSubGraphSpan Empty @@ -218,8 +368,8 @@ namespace DCFApixels.DragonECS get { return new EcsSubGraphSpan(null, 0, 0); } } - private readonly EntityLinkedList.Node[] _nodes; - private readonly int _startNodeIndex; + private readonly LinkedList.Node[] _nodes; + private readonly LinkedList.NodeIndex _startNodeIndex; private readonly int _count; public int Count { @@ -239,7 +389,7 @@ namespace DCFApixels.DragonECS } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal EcsSubGraphSpan(EntityLinkedList.Node[] nodes, int startNodeIndex, int count) + internal EcsSubGraphSpan(LinkedList.Node[] nodes, LinkedList.NodeIndex startNodeIndex, int count) { _nodes = nodes; _startNodeIndex = startNodeIndex; @@ -252,17 +402,17 @@ namespace DCFApixels.DragonECS } public ref struct Enumerator { - private readonly EntityLinkedList.Node[] _nodes; + private readonly LinkedList.Node[] _nodes; private int _index; private int _count; private int _next; [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Enumerator(EntityLinkedList.Node[] nodes, int startIndex, int count) + internal Enumerator(LinkedList.Node[] nodes, LinkedList.NodeIndex startIndex, int count) { _nodes = nodes; _index = -1; _count = count; - _next = startIndex; + _next = (int)startIndex; } public int Current { @@ -273,100 +423,11 @@ namespace DCFApixels.DragonECS public bool MoveNext() { _index = _next; - _next = _nodes[_next].next; + _next = (int)_nodes[_next].next; return _index > 0 && _count-- > 0; + //return _count-- > 0; } } } - - public readonly ref struct EcsSubGraph - { - private readonly EcsJoinToSubGraphExecutor _executer; - private readonly EcsSpan _startEntities; - public EcsSpan FromEntitiesSpan - { - get { return _startEntities; } - } - public EcsGraph Graph - { - get { return _executer.Graph; } - } - internal EcsSubGraph(EcsJoinToSubGraphExecutor executer, EcsSpan startEntites) - { - _executer = executer; - _startEntities = startEntites; - } - public EcsSubGraphSpan GetNodes(int startEntityID) - { - return _executer.GetNodes_Internal(startEntityID); - } - public int GetNode(int startEntityID) - { - return _executer.GetNode_Internal(startEntityID); - } - public int GetNodesCount(int startEntityID) - { - return _executer.GetNodesCount_Internal(startEntityID); - } - } - #endregion - - - - - - - - - - public static class GraphQueries - { - #region JoinToGraph Empty - public static EcsSubGraph JoinToSubGraph(this TCollection entities, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) - where TCollection : IEntityStorage - { - return entities.ToSpan().JoinToSubGraph(mode); - } - public static EcsSubGraph JoinToSubGraph(this EcsReadonlyGroup group, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) - { - return group.ToSpan().JoinToSubGraph(mode); - } - public static EcsSubGraph JoinToSubGraph(this EcsSpan span, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) - { - EcsWorld world = span.World; - if (world.IsEnableReleaseDelEntBuffer) - { - world.ReleaseDelEntityBufferAll(); - } - world.GetQueryCache(out EcsJoinToSubGraphExecutor executor, out EmptyAspect _); - return executor.ExecuteFor(span, mode); - } - #endregion - - #region JoinToGraph - public static EcsSubGraph JoinToSubGraph(this TCollection entities, out TAspect aspect, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) - where TAspect : EcsAspect, new() - where TCollection : IEntityStorage - { - return entities.ToSpan().JoinToSubGraph(out aspect, mode); - } - public static EcsSubGraph JoinToSubGraph(this EcsReadonlyGroup group, out TAspect aspect, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) - where TAspect : EcsAspect, new() - { - return group.ToSpan().JoinToSubGraph(out aspect, mode); - } - public static EcsSubGraph JoinToSubGraph(this EcsSpan span, out TAspect aspect, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) - where TAspect : EcsAspect, new() - { - EcsWorld world = span.World; - if (world.IsEnableReleaseDelEntBuffer) - { - world.ReleaseDelEntityBufferAll(); - } - world.GetQueryCache(out EcsJoinToSubGraphExecutor executor, out aspect); - return executor.ExecuteFor(span, mode); - } - #endregion - } -} +} \ No newline at end of file diff --git a/src/Executors/GraphQueries.cs b/src/Executors/GraphQueries.cs new file mode 100644 index 0000000..ffa172d --- /dev/null +++ b/src/Executors/GraphQueries.cs @@ -0,0 +1,63 @@ +namespace DCFApixels.DragonECS +{ + public static class GraphQueries + { + #region JoinToGraph Empty + //public static EcsSubGraph JoinToSubGraph(this TCollection entities, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) + // where TCollection : IEntityStorage + //{ + // return entities.ToSpan().JoinToSubGraph(mode); + //} + //public static EcsSubGraph JoinToSubGraph(this EcsReadonlyGroup group, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) + //{ + // return group.ToSpan().JoinToSubGraph(mode); + //} + //public static EcsSubGraph JoinToSubGraph(this EcsSpan span, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) + //{ + // EcsWorld world = span.World; + // if (world.IsEnableReleaseDelEntBuffer) + // { + // world.ReleaseDelEntityBufferAll(); + // } + // world.GetQueryCache(out EcsJoinToSubGraphExecutor executor, out EmptyAspect _); + // return executor.ExecuteFor(span, mode); + //} + #endregion + + #region JoinToGraph + public static EcsSubGraph JoinToSubGraph(this TCollection entities, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) + where TCollection : IEntityStorage + { + if (ReferenceEquals(entities, entities.World)) + { + entities.World.GetQueryCache(out EcsJoinToSubGraphExecutor executor, out EmptyAspect _); + return executor.Execute(mode); + } + return entities.ToSpan().JoinToSubGraph(out EmptyAspect _, mode); + } + + public static EcsSubGraph JoinToSubGraph(this TCollection entities, out TAspect aspect, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) + where TAspect : EcsAspect, new() + where TCollection : IEntityStorage + { + if (ReferenceEquals(entities, entities.World)) + { + entities.World.GetQueryCache(out EcsJoinToSubGraphExecutor executor, out aspect); + return executor.Execute(); + } + return entities.ToSpan().JoinToSubGraph(out aspect, mode); + } + public static EcsSubGraph JoinToSubGraph(this EcsReadonlyGroup group, out TAspect aspect, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) + where TAspect : EcsAspect, new() + { + return group.ToSpan().JoinToSubGraph(out aspect, mode); + } + public static EcsSubGraph JoinToSubGraph(this EcsSpan span, out TAspect aspect, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) + where TAspect : EcsAspect, new() + { + span.World.GetQueryCache(out EcsJoinToSubGraphExecutor executor, out aspect); + return executor.ExecuteFor(span, mode); + } + #endregion + } +} diff --git a/src/Internal/EntityLinkedList.cs b/src/Internal/EntityLinkedList.cs deleted file mode 100644 index 56d7580..0000000 --- a/src/Internal/EntityLinkedList.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace DCFApixels.DragonECS.Graphs.Internal -{ - internal class EntityLinkedList - { - public const int Enter = 0; - - internal Node[] _nodes; - private int _count; - private int _lastNodeIndex; - - #region Properties - public int Count => _count; - public int Capacity => _nodes.Length; - public int Last => _lastNodeIndex; - #endregion - - #region Constructors - public EntityLinkedList(int capacity) - { - _nodes = new Node[capacity * 2 + 10]; - Clear(); - } - #endregion - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Resize(int newCapacity) - { - Array.Resize(ref _nodes, newCapacity * 2 + 10); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Clear() - { - for (int i = 0; i < _nodes.Length; i++) - { - _nodes[i].next = 0; - } - _lastNodeIndex = Enter; - _count = 0; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set(int nodeIndex, int entityID) - { - _nodes[nodeIndex].entityID = entityID; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int Get(int nodeIndex) - { - return _nodes[nodeIndex].entityID; - } - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int InsertBefore(int nodeIndex, int entityID) - { - _nodes[++_count].Set(entityID, nodeIndex); - return _count; - } - - - /// Insert after - /// new node index - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int InsertAfter(int nodeIndex, int entityID) - { - _nodes[++_count].Set(entityID, _nodes[nodeIndex].next); - _nodes[nodeIndex].next = _count; - _lastNodeIndex = nodeIndex + 1; - return _count; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int Add(int entityID) - { - int result = InsertAfter(_lastNodeIndex, entityID); - _lastNodeIndex = _count; - return result; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Enumerator GetEnumerator() - { - return new Enumerator(_nodes); - } - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public EcsJoinedSpan GetSpan(int startNodeIndex, int count) - //{ - // return new EcsJoinedSpan(_nodes, startNodeIndex, count); - //} - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public EcsJoinedSpan GetEmptySpan() - //{ - // return new EcsJoinedSpan(_nodes, 0, 0); - //} - #region Utils - [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)] - public struct Node - { - public static readonly Node Empty = new Node() { entityID = 0, next = -1 }; - public int entityID; - /// next node index - public int next; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set(int entityID, int next) - { - this.entityID = entityID; - this.next = next; - } - public override string ToString() - { - return $"e:{entityID} next:{next}"; - } - } - public struct Enumerator - { - private readonly Node[] _nodes; - private int _index; - private int _next; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Enumerator(Node[] nodes) - { - _nodes = nodes; - _index = -1; - _next = Enter; - } - public int Current - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _nodes[_index].entityID; } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() - { - _index = _next; - _next = _nodes[_next].next; - return _index > 0; - } - } - #endregion - } -} diff --git a/src/Internal/OnlyAppendHeadLinkedList.cs b/src/Internal/OnlyAppendHeadLinkedList.cs new file mode 100644 index 0000000..b8a70ae --- /dev/null +++ b/src/Internal/OnlyAppendHeadLinkedList.cs @@ -0,0 +1,180 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace DCFApixels.DragonECS.Graphs.Internal +{ + internal class OnlyAppendHeadLinkedList + { + public const NodeIndex Enter = 0; + + internal Node[] _nodes; + private int _count; + private NodeIndex _lastNodeIndex; + + #region Properties + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _count; } + } + public int Capacity + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _nodes.Length; } + } + public NodeIndex Last + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _lastNodeIndex; } + } + #endregion + + #region Constructors + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public OnlyAppendHeadLinkedList(int capacity) + { + _nodes = new Node[capacity * 2 + 10]; + Clear(); + } + #endregion + + #region Methods + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void InsertIntoHead(ref NodeIndex headIndex, int entityID) + { + _nodes[++_count].Set(entityID, headIndex); + headIndex = (NodeIndex)_count; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NodeIndex NewHead(int entityID) + { + _nodes[++_count].Set(entityID, 0); + return (NodeIndex)_count; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Get(NodeIndex nodeIndex) + { + return _nodes[(int)nodeIndex].entityID; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _lastNodeIndex = Enter; + _count = 0; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Enumerator GetEnumerator() + { + return new Enumerator(_nodes); + } + #endregion + + #region TMP + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + //public void Resize(int newCapacity) + //{ + // Array.Resize(ref _nodes, newCapacity * 2 + 10); + //} + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + //public void Set(HeadIndex nodeIndex, int entityID) + //{ + // _nodes[(int)nodeIndex].entityID = entityID; + //} + + ///// new node index + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + //public NodeID InsertBefore(NodeID nodeIndex, int entityID) + //{ + // NodeID newNode = (NodeID)(++_count); + // _nodes[(int)newNode] = _nodes[(int)nodeIndex]; + // _nodes[(int)newNode].Set(entityID, nodeIndex); + // return newNode; + //} + ///// new node index + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + //public NodeID InsertAfter(NodeID nodeIndex, int entityID) + //{ + // NodeID newNode = (NodeID)(++_count); + // _nodes[(int)nodeIndex].next = newNode; + // _nodes[(int)newNode].Set(entityID, _nodes[(int)nodeIndex].next); + // _lastNodeIndex = newNode; + // return newNode; + // + // //_nodes[++_count].Set(entityID, _nodes[(int)nodeIndex].next); + // //_nodes[(int)nodeIndex].next = (NodeID)_count; + // //_lastNodeIndex = (NodeID)((int)nodeIndex + 1); + // //return (NodeID)_count; + //} + /// new node index + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + //public NodeID Add(int entityID) + //{ + // var result = InsertAfter(_lastNodeIndex, entityID); + // _lastNodeIndex = (NodeID)_count; + // return result; + //} + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + //public EcsJoinedSpan GetSpan(int startNodeIndex, int count) + //{ + // return new EcsJoinedSpan(_nodes, startNodeIndex, count); + //} + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + //public EcsJoinedSpan GetEmptySpan() + //{ + // return new EcsJoinedSpan(_nodes, 0, 0); + //} + #endregion + + #region Utils + public enum NodeIndex : int { } + + [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)] + public struct Node + { + public static readonly Node Empty = new Node() { entityID = 0, next = (int)Enter }; + + public int entityID; + public NodeIndex next; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Set(int entityID, NodeIndex next) + { + this.entityID = entityID; + this.next = next; + } + public override string ToString() + { + return $"e:{entityID} next:{next}"; + } + } + public struct Enumerator + { + private readonly Node[] _nodes; + private int _index; + private int _next; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Enumerator(Node[] nodes) + { + _nodes = nodes; + _index = -1; + _next = (int)Enter; + } + public int Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _nodes[_index].entityID; } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + _index = _next; + _next = (int)_nodes[_next].next; + return _index > 0; + } + } + #endregion + } +} diff --git a/src/Utils/Exceptions.cs b/src/Utils/Exceptions.cs index a5cd18b..bc3f529 100644 --- a/src/Utils/Exceptions.cs +++ b/src/Utils/Exceptions.cs @@ -19,9 +19,9 @@ namespace DCFApixels.DragonECS.Graphs.Internal } [MethodImpl(MethodImplOptions.NoInlining)] - internal static void ArgumentNull() + internal static void ArgumentNull(string paramName) { - throw new ArgumentNullException(); + throw new ArgumentNullException(paramName); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void ArgumentOutOfRange() @@ -48,6 +48,13 @@ namespace DCFApixels.DragonECS.Graphs.Internal { throw new KeyNotFoundException(); } + + + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void Quiery_ArgumentDifferentWorldsException() + { + throw new ArgumentException("The groups belong to different worlds."); + } } }