diff --git a/src/Builtin/EcsArcWorld.cs b/src/Builtin/EcsArcWorld.cs deleted file mode 100644 index 2ddecb1..0000000 --- a/src/Builtin/EcsArcWorld.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace DCFApixels.DragonECS -{ - public abstract class EcsArcWorld : EcsWorld - { - public EcsArcWorld(ConfigContainer config = null) : base(config) { } - public EcsArcWorld(IConfigContainer config = null) : base(config) { } - } - public sealed class EcsLoopArcWorld : EcsArcWorld - where TWorld : EcsWorld - { - public EcsLoopArcWorld(ConfigContainer config = null) : base(config) { } - public EcsLoopArcWorld(IConfigContainer config = null) : base(config) { } - } - public sealed class EcsArcWorld : EcsArcWorld - where TStartWorld : EcsWorld - where TEndWorld : EcsWorld - { - public EcsArcWorld(ConfigContainer config = null) : base(config) { } - public EcsArcWorld(IConfigContainer config = null) : base(config) { } - } -} diff --git a/src/Builtin/EcsArcWorld.cs.meta b/src/Builtin/EcsArcWorld.cs.meta deleted file mode 100644 index 9185047..0000000 --- a/src/Builtin/EcsArcWorld.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 72248d53a53519847b5b360dd02c37c5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/EcsArc.cs b/src/EcsGraph.cs similarity index 57% rename from src/EcsArc.cs rename to src/EcsGraph.cs index ad79295..cd89687 100644 --- a/src/EcsArc.cs +++ b/src/EcsGraph.cs @@ -1,29 +1,24 @@ using DCFApixels.DragonECS.Graphs.Internal; -using DCFApixels.DragonECS.UncheckedCore; using System; using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS { - //Arc - //Arc world + //Graph + //Graph world //Rel entity //Component - public class EcsArc + public class EcsGraph { - private readonly EcsWorld _startWorld; - private readonly EcsWorld _endWorld; - private readonly EcsArcWorld _arcWorld; + private readonly EcsWorld _world; + private readonly EcsWorld _graphWorld; - private readonly StartWorldHandler _startWorldHandler; - private readonly ArcWorldHandler _arcWorldHandler; - private readonly EndWorldHandler _endWorldHandler; - private readonly LoopWorldHandler _loopWorldHandler; + private readonly GraphWorldHandler _arcWorldHandler; + private readonly WorldHandler _loopWorldHandler; private RelationInfo[] _relEntityInfos; //N * (N - 1) / 2 private readonly SparseMatrix _matrix; - private bool _isLoop; private bool _isInit = false; private int _count; @@ -34,30 +29,25 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _isInit; } } - public EcsWorld StartWorld + public EcsWorld World { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _startWorld; } + get { return _world; } } - public EcsWorld EndWorld + public short WorldID { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _endWorld; } + get { return _world.id; } } - public EcsArcWorld ArcWorld + public EcsWorld GraphWorld { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _arcWorld; } + get { return _graphWorld; } } - public short ArcWorldID + public short GraphWorldID { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _arcWorld.id; } - } - public bool IsLoop - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _isLoop; } + get { return _graphWorld.id; } } public int Count { @@ -67,43 +57,23 @@ namespace DCFApixels.DragonECS #endregion #region Constructors/Destroy - internal EcsArc(EcsWorld startWorld, EcsWorld endWorld, EcsArcWorld arcWorld) + internal EcsGraph(EcsWorld world, EcsWorld graphWorld) { - _startWorld = startWorld; - _endWorld = endWorld; - _arcWorld = arcWorld; + _world = world; + _graphWorld = graphWorld; - _isLoop = startWorld == endWorld; + _relEntityInfos = new RelationInfo[_graphWorld.Capacity]; + _matrix = new SparseMatrix(_graphWorld.Capacity); - _relEntityInfos = new RelationInfo[arcWorld.Capacity]; - _matrix = new SparseMatrix(arcWorld.Capacity); - - _arcWorldHandler = new ArcWorldHandler(this); - if (_isLoop) - { - _loopWorldHandler = new LoopWorldHandler(this); - } - else - { - _startWorldHandler = new StartWorldHandler(this); - _endWorldHandler = new EndWorldHandler(this); - } + _arcWorldHandler = new GraphWorldHandler(this); + _loopWorldHandler = new WorldHandler(this); _isInit = true; } public void Destroy() { _arcWorldHandler.Destroy(); - if (_isLoop) - { - _loopWorldHandler.Destroy(); - } - else - { - _startWorldHandler.Destroy(); - _endWorldHandler.Destroy(); - } - + _loopWorldHandler.Destroy(); } #endregion @@ -125,7 +95,7 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] private int NewRelationInternal(int startEntityID, int endEntityID) { - int relEntityID = _arcWorld.NewEntity(); + int relEntityID = _graphWorld.NewEntity(); _matrix.Add(startEntityID, endEntityID, relEntityID); _relEntityInfos[relEntityID] = new RelationInfo(startEntityID, endEntityID); _count++; @@ -158,7 +128,7 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public void DelRelation(int relEntityID) { - _arcWorld.TryDelEntity(relEntityID); + _graphWorld.TryDelEntity(relEntityID); //ClearRelation_Internal(relEntityID); } @@ -213,30 +183,18 @@ namespace DCFApixels.DragonECS } #endregion - #region Other - public EcsArc GetInversetArc() + #region GraphWorldHandler + private class GraphWorldHandler : IEcsWorldEventListener { - return _endWorld.GetArc(_startWorld); - } - public bool TryGetInversetArc(out EcsArc arc) - { - return _endWorld.TryGetArc(_startWorld, out arc); - } - #endregion - - - #region VertexWorldHandler - private class ArcWorldHandler : IEcsWorldEventListener - { - private readonly EcsArc _arc; - public ArcWorldHandler(EcsArc arc) + private readonly EcsGraph _arc; + public GraphWorldHandler(EcsGraph arc) { _arc = arc; - _arc.ArcWorld.AddListener(this); + _arc.GraphWorld.AddListener(this); } public void Destroy() { - _arc.ArcWorld.RemoveListener(this); + _arc.GraphWorld.RemoveListener(this); } #region Callbacks public void OnReleaseDelEntityBuffer(ReadOnlySpan relEntityBuffer) @@ -253,25 +211,25 @@ namespace DCFApixels.DragonECS } #endregion } + #endregion - #region Loop - private class LoopWorldHandler : IEcsWorldEventListener + #region WorldHandler + private class WorldHandler : IEcsWorldEventListener { - private readonly EcsArc _arc; - public LoopWorldHandler(EcsArc arc) + private readonly EcsGraph _arc; + public WorldHandler(EcsGraph arc) { _arc = arc; - _arc.StartWorld.AddListener(this); - //OnWorldResize(_arc.StartWorld.Capacity); + _arc.World.AddListener(this); } public void Destroy() { - _arc.StartWorld.RemoveListener(this); + _arc.World.RemoveListener(this); } #region Callbacks public void OnReleaseDelEntityBuffer(ReadOnlySpan startEntityBuffer) { - var graph = _arc.ArcWorld.GetExecutor>().Execute(); + var graph = _arc.GraphWorld.JoinToSubGraph(EcsSubGraphMode.All); foreach (var e in startEntityBuffer) { var span = graph.GetNodes(e); @@ -280,61 +238,12 @@ namespace DCFApixels.DragonECS _arc.DelRelation(relE); } } - _arc._arcWorld.ReleaseDelEntityBufferAll(); + _arc._graphWorld.ReleaseDelEntityBufferAll(); } public void OnWorldDestroy() { } public void OnWorldResize(int startWorldNewSize) { } #endregion } #endregion - - #region StartEnd - private class StartWorldHandler : IEcsWorldEventListener - { - private readonly EcsArc _arc; - public StartWorldHandler(EcsArc arc) - { - _arc = arc; - _arc.StartWorld.AddListener(this); - //OnWorldResize(_arc.StartWorld.Capacity); - } - public void Destroy() - { - _arc.StartWorld.RemoveListener(this); - } - #region Callbacks - public void OnReleaseDelEntityBuffer(ReadOnlySpan startEntityBuffer) - { - _arc._arcWorld.ReleaseDelEntityBufferAll(); - } - public void OnWorldDestroy() { } - public void OnWorldResize(int startWorldNewSize) { } - #endregion - } - private class EndWorldHandler : IEcsWorldEventListener - { - private readonly EcsArc _arc; - public EndWorldHandler(EcsArc arc) - { - _arc = arc; - _arc.EndWorld.AddListener(this); - //OnWorldResize(_arc.EndWorld.Capacity); - } - public void Destroy() - { - _arc.EndWorld.RemoveListener(this); - } - #region Callbacks - public void OnReleaseDelEntityBuffer(ReadOnlySpan endEntityBuffer) - { - _arc._arcWorld.ReleaseDelEntityBufferAll(); - } - public void OnWorldDestroy() { } - public void OnWorldResize(int endWorldNewSize) { } - #endregion - } - #endregion - - #endregion } } \ No newline at end of file diff --git a/src/EcsGraphExtensions.cs b/src/EcsGraphExtensions.cs new file mode 100644 index 0000000..afb3d39 --- /dev/null +++ b/src/EcsGraphExtensions.cs @@ -0,0 +1,108 @@ +using DCFApixels.DragonECS.Graphs.Internal; +using System; + +namespace DCFApixels.DragonECS +{ + public static class EcsGraphExtensions + { + private static EcsGraph[] _worldGraphs = new EcsGraph[4]; + + public static EcsGraph 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]; + if (graph != null) + { + Throw.UndefinedException(); + } + graph = new EcsGraph(self, graphWorld); + new Destroyer(graph); + _worldGraphs[graphWorld.id] = graph; + return graph; + } + + public static EcsGraph 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]; + if (graph != null) + { + return graph; + } + graph = new EcsGraph(self, graphWorld); + new Destroyer(graph); + _worldGraphs[graphWorld.id] = graph; + return graph; + } + + public static bool TryGetGraph(this EcsWorld self, out EcsGraph graph) + { + int worldID = self.id; + if (_worldGraphs.Length <= worldID) + { + Array.Resize(ref _worldGraphs, worldID + 4); + } + graph = _worldGraphs[worldID]; + return graph != null; + } + + public static EcsGraph GetGraph(this EcsWorld self) + { + if (self.TryGetGraph(out EcsGraph graph)) + { + return graph; + } + Throw.UndefinedException(); + return null; + } + + public static bool IsGraphWorld(this EcsWorld self) + { + if (self.TryGetGraph(out EcsGraph graph)) + { + return graph.GraphWorld == self; + } + return false; + } + + private static void TryDestroy(EcsGraph graph) + { + int worldID = graph.WorldID; + if (_worldGraphs.Length <= worldID) + { + Array.Resize(ref _worldGraphs, worldID + 4); + } + int graphWorldID = graph.GraphWorldID; + if (_worldGraphs.Length <= graphWorldID) + { + Array.Resize(ref _worldGraphs, graphWorldID + 4); + } + _worldGraphs[worldID] = null; + _worldGraphs[graphWorldID] = null; + } + private class Destroyer : IEcsWorldEventListener + { + private EcsGraph _graph; + public Destroyer(EcsGraph graph) + { + _graph = graph; + graph.World.AddListener(this); + graph.GraphWorld.AddListener(this); + } + public void OnReleaseDelEntityBuffer(ReadOnlySpan buffer) { } + public void OnWorldDestroy() + { + TryDestroy(_graph); + } + public void OnWorldResize(int newSize) { } + } + } +} \ No newline at end of file diff --git a/src/EcsWorldGraph.cs b/src/EcsWorldGraph.cs deleted file mode 100644 index aeecc1a..0000000 --- a/src/EcsWorldGraph.cs +++ /dev/null @@ -1,191 +0,0 @@ -using DCFApixels.DragonECS.Graphs.Internal; -using System; - -namespace DCFApixels.DragonECS -{ - public static class EcsWorldGraph - { - private static readonly SparseArray _matrix = new SparseArray(4); - private static EcsArc[] _arcsMapping = new EcsArc[4]; - - #region Register/Unregister - private static EcsArc Register(EcsWorld startWorld, EcsWorld endWorld, EcsArcWorld arcWorld) - { - int startWorldID = startWorld.id; - int endWorldID = endWorld.id; - int arcWorldID = arcWorld.id; - - if (_arcsMapping.Length <= arcWorldID) - { - Array.Resize(ref _arcsMapping, arcWorldID + 4); - } - -#if DEBUG - if (_matrix.Contains(startWorldID, endWorldID)) - { - throw new EcsFrameworkException(); - } -#endif - EcsArc arc = new EcsArc(startWorld, endWorld, arcWorld); - _matrix[startWorldID, endWorldID] = arc; - _arcsMapping[arcWorldID] = arc; - return arc; - } - public static bool IsRegistered(EcsArc arc) - { - return Has(arc.StartWorld.id, arc.EndWorld.id); - } - private static void Unregister(EcsWorld startWorld, EcsWorld endWorld) - { - int startWorldID = startWorld.id; - int endWorldID = endWorld.id; - EcsArc arc = _matrix[startWorldID, endWorldID]; - _arcsMapping[arc.ArcWorld.id] = null; - _matrix.Remove(startWorldID, endWorldID); - arc.Destroy(); - } - #endregion - - #region Get/Has - // private static EcsArc GetOrRigister(EcsWorld startWorld, EcsWorld otherWorld) - // { - //#if DEBUG - // if (!_matrix.Contains(startWorld.id, otherWorld.id)) - // { - // return Register(); - // } - //#endif - // return _matrix[startWorld.id, otherWorld.id]; - // } - private static EcsArc Get(EcsWorld startWorld, EcsWorld otherWorld) - { -#if DEBUG - if (!_matrix.Contains(startWorld.id, otherWorld.id)) - { - throw new EcsFrameworkException(); - } -#endif - return _matrix[startWorld.id, otherWorld.id]; - } - private static bool Has(EcsWorld startWorld, EcsWorld endWorld) - { - return Has(startWorld.id, endWorld.id); - } - private static bool Has(int startWorldID, int endWorldID) - { - return _matrix.Contains(startWorldID, endWorldID); - } - #endregion - - #region Extension - public static bool IsRegistered(this EcsArcWorld self) - { - if (self == null) { Throw.ArgumentNull(); } - int id = self.id; - return id < _arcsMapping.Length && _arcsMapping[self.id] != null; - } - public static EcsArc GetRegisteredArc(this EcsArcWorld self) - { - if (self == null) { Throw.ArgumentNull(); } - int id = self.id; - if (id < _arcsMapping.Length && _arcsMapping[self.id] == null) - { - Throw.UndefinedException(); - } - return _arcsMapping[self.id]; - } - - - public static EcsArc SetLoopArcAuto(this TWorld self, out EcsLoopArcWorld arcWorld, IConfigContainer config = null) - where TWorld : EcsWorld - { - if (self == null) { Throw.ArgumentNull(); } - if (typeof(TWorld) != self.GetType()) - { - EcsDebug.PrintWarning($"{nameof(TWorld)} is not {self.GetType().Name}"); - } - arcWorld = new EcsLoopArcWorld(config); - return Register(self, self, arcWorld); - } - public static EcsArc SetArcAuto(this TStartWorld start, TEndWorld end, out EcsArcWorld arcWorld, IConfigContainer config = null) - where TStartWorld : EcsWorld - where TEndWorld : EcsWorld - { - if (start == null || end == null) { Throw.ArgumentNull(); } - if (typeof(TStartWorld) == typeof(EcsWorld) && typeof(TEndWorld) == typeof(EcsWorld)) - { - EcsDebug.PrintWarning($"{nameof(TStartWorld)} is not {start.GetType().Name} or {nameof(TEndWorld)} is not {end.GetType().Name}"); - } - arcWorld = new EcsArcWorld(config); - return Register(start, end, arcWorld); - } - public static EcsArc SetLoopArcAuto(this TWorld self, IConfigContainer config = null) - where TWorld : EcsWorld - { - return SetLoopArcAuto(self, out _, config); - } - public static EcsArc SetArcAuto(this TStartWorld start, TEndWorld end, IConfigContainer config = null) - where TStartWorld : EcsWorld - where TEndWorld : EcsWorld - { - return SetArcAuto(start, end, out _, config); - } - - public static EcsArc SetLoopArc(this EcsWorld self, EcsArcWorld arc) - { - return SetArc(self, self, arc); - } - public static EcsArc SetArc(this EcsWorld start, EcsWorld end, EcsArcWorld arc) - { - if (start == null || end == null || arc == null) { Throw.ArgumentNull(); } - return Register(start, end, arc); - } - - public static bool HasLoopArc(this EcsWorld self) - { - return HasArc(self, self); - } - public static bool HasArc(this EcsWorld start, EcsWorld end) - { - if (start == null || end == null) { Throw.ArgumentNull(); } - return Has(start, end); - } - - public static EcsArc GetLoopArc(this EcsWorld self) - { - return GetArc(self, self); - } - public static EcsArc GetArc(this EcsWorld start, EcsWorld end) - { - if (start == null || end == null) { Throw.ArgumentNull(); } - return Get(start, end); - } - - public static bool TryGetLoopArc(this EcsWorld self, out EcsArc arc) - { - return TryGetArc(self, self, out arc); - } - public static bool TryGetArc(this EcsWorld start, EcsWorld end, out EcsArc arc) - { - if (start == null || end == null) { Throw.ArgumentNull(); } - bool result = Has(start, end); - arc = result ? Get(start, end) : null; - return result; - } - - public static void DestroyLoopArc(this EcsWorld self) - { - DestroyArcWith(self, self); - } - public static void DestroyArcWith(this EcsWorld start, EcsWorld end) - { - if (start == null || end == null) - { - Throw.ArgumentNull(); - } - Get(start, end).ArcWorld.Destroy(); - Unregister(start, end); - } - #endregion - } -} \ No newline at end of file diff --git a/src/Executors/EcsJoinToGraphExecutor.cs b/src/Executors/EcsJoinToSubGraphExecutor.cs similarity index 54% rename from src/Executors/EcsJoinToGraphExecutor.cs rename to src/Executors/EcsJoinToSubGraphExecutor.cs index 7cf63f7..08bbcf0 100644 --- a/src/Executors/EcsJoinToGraphExecutor.cs +++ b/src/Executors/EcsJoinToSubGraphExecutor.cs @@ -1,20 +1,43 @@ using DCFApixels.DragonECS.Graphs.Internal; using DCFApixels.DragonECS.UncheckedCore; using System; +using System.Collections.Generic; using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS { - public abstract class EcsJoinToGraphExecutor : EcsQueryExecutor, IEcsWorldEventListener + public sealed class EcsJoinToSubGraphExecutor : EcsJoinToSubGraphExecutor + where TAspect : EcsAspect + { + private TAspect _aspect; + + #region Properties + public TAspect Aspect + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _aspect; } + } + protected override EcsAspect AspectRaw + { + get + { + if (_aspect == null) { _aspect = World.GetAspect(); } + return _aspect; + } + } + #endregion + } + public abstract class EcsJoinToSubGraphExecutor : EcsQueryExecutor, IEcsWorldEventListener { private EcsAspect _aspect; - private EcsArcWorld _arcWorld; private EntityLinkedList _linkedList; private Basket[] _baskets; private int[] _startEntities; private int _startEntitiesCount; + private EcsGraph _graph; + private long _lastWorldVersion; private int _targetWorldCapacity = -1; @@ -27,11 +50,6 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _lastWorldVersion; } } - public EcsArcWorld ArcWorld - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _arcWorld; } - } #endregion #region OnInitialize/OnDestroy @@ -40,8 +58,8 @@ namespace DCFApixels.DragonECS _linkedList = new EntityLinkedList(World.Capacity); _baskets = new Basket[World.Capacity]; World.AddListener(this); - _arcWorld = (EcsArcWorld)World; _aspect = AspectRaw; + _graph = World.GetGraph(); } protected override void OnDestroy() { @@ -50,11 +68,11 @@ namespace DCFApixels.DragonECS #endregion #region Execute - public EcsGraph Execute() + public EcsSubGraph Execute(EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) { - return ExecuteFor(World.Entities); + return ExecuteFor(World.Entities, mode); } - public EcsGraph ExecuteFor(EcsSpan span) + public EcsSubGraph ExecuteFor(EcsSpan span, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) { _executeMarker.Begin(); #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS @@ -62,7 +80,7 @@ namespace DCFApixels.DragonECS else if (World != span.World) { Throw.ArgumentException(""); } //TODO составить текст исключения. это проверка на то что пользователь использует правильный мир #endif - if (_lastWorldVersion != World.Version) + //if (_lastWorldVersion != World.Version) { //Подготовка массивов if (_targetWorldCapacity < World.Capacity) @@ -79,50 +97,68 @@ namespace DCFApixels.DragonECS _linkedList.Clear(); //Конец подготовки массивов - EcsArc arc = _arcWorld.GetRegisteredArc(); + if ((mode & EcsSubGraphMode.StartToEnd) != 0) + { + if (_aspect.Mask.IsEmpty) + { + foreach (var relationEntityID in span) { AddStart(relationEntityID); } + } + else + { + var iterator = _aspect.GetIteratorFor(span); + foreach (var relationEntityID in iterator) { AddStart(relationEntityID); } + } + } + if ((mode & EcsSubGraphMode.EndToStart) != 0) + { + if (_aspect.Mask.IsEmpty) + { + foreach (var relationEntityID in span) { AddEnd(relationEntityID); } + } + else + { + var iterator = _aspect.GetIteratorFor(span); + foreach (var relationEntityID in iterator) { AddEnd(relationEntityID); } + } + } - if (_aspect.Mask.IsEmpty) - { - foreach (var relationEntityID in span) - { - int startEntityID = arc.GetRelationStart(relationEntityID); - if (startEntityID == 0) { continue; } - Add(startEntityID, relationEntityID); - } - } - else - { - var iterator = _aspect.GetIteratorFor(span); - foreach (var relationEntityID in iterator) - { - int startEntityID = arc.GetRelationStart(relationEntityID); - if (startEntityID == 0) { continue; } - Add(startEntityID, relationEntityID); - } - } - _lastWorldVersion = World.Version; } - else - { - - } + //else + //{ + // + //} _executeMarker.End(); - return new EcsGraph(this, UncheckedCoreUtility.CreateSpan(WorldID, _startEntities, _startEntitiesCount)); + return new EcsSubGraph(this, UncheckedCoreUtility.CreateSpan(WorldID, _startEntities, _startEntitiesCount)); } - private void Add(int startEntityID, int relationEntityID) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AddStart(int relationEntityID) { - _startEntities[_startEntitiesCount++] = startEntityID; - ref var basket = ref _baskets[startEntityID]; + AddFrom(_graph.GetRelationStart(relationEntityID), relationEntityID); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AddEnd(int relationEntityID) + { + AddFrom(_graph.GetRelationEnd(relationEntityID), relationEntityID); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AddFrom(int fromEntityID, int relationEntityID) + { + if (fromEntityID == 0) + { + return; + } + ref var basket = ref _baskets[fromEntityID]; if (basket.index <= 0) { + _startEntities[_startEntitiesCount++] = fromEntityID; basket.index = _linkedList.Add(relationEntityID); } else { - _linkedList.InsertAfter(basket.index, relationEntityID); + basket.index = _linkedList.InsertBefore(basket.index, relationEntityID); } basket.count++; } @@ -130,10 +166,10 @@ namespace DCFApixels.DragonECS #region Internal result methods [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal EcsGraphSpan GetNodes_Internal(int startEntityID) + internal EcsSubGraphSpan GetNodes_Internal(int startEntityID) { Basket basket = _baskets[startEntityID]; - return new EcsGraphSpan(_linkedList._nodes, basket.index, basket.count); + return new EcsSubGraphSpan(_linkedList._nodes, basket.index, basket.count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal int GetNode_Internal(int startEntityID) @@ -167,42 +203,29 @@ namespace DCFApixels.DragonECS { public int index; public int count; - } - #endregion - } - public sealed class EcsJoinToGraphExecutor : EcsJoinToGraphExecutor - where TAspect : EcsAspect - { - private TAspect _aspect; - - #region Properties - public TAspect Aspect - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _aspect; } - } - protected override EcsAspect AspectRaw - { - get + public override string ToString() { - if (_aspect == null) - { - _aspect = World.GetAspect(); - } - return _aspect; + return $"i:{index} count:{count}"; } } #endregion } - + + public enum EcsSubGraphMode + { + NONE = 0, + StartToEnd = 1 << 0, + EndToStart = 1 << 1, + All = StartToEnd | EndToStart, + } #region EcsJoinedSpan/EcsJoined - public readonly ref struct EcsGraphSpan + public readonly ref struct EcsSubGraphSpan { - public static EcsGraphSpan Empty + public static EcsSubGraphSpan Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return new EcsGraphSpan(null, 0, 0); } + get { return new EcsSubGraphSpan(null, 0, 0); } } private readonly EntityLinkedList.Node[] _nodes; @@ -213,8 +236,20 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _count; } } + private IEnumerable E + { + get + { + List result = new List(); + foreach (var item in this) + { + result.Add(item); + } + return result; + } + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal EcsGraphSpan(EntityLinkedList.Node[] nodes, int startNodeIndex, int count) + internal EcsSubGraphSpan(EntityLinkedList.Node[] nodes, int startNodeIndex, int count) { _nodes = nodes; _startNodeIndex = startNodeIndex; @@ -225,7 +260,7 @@ namespace DCFApixels.DragonECS { return new Enumerator(_nodes, _startNodeIndex, _count); } - public struct Enumerator + public ref struct Enumerator { private readonly EntityLinkedList.Node[] _nodes; private int _index; @@ -254,20 +289,20 @@ namespace DCFApixels.DragonECS } } - public readonly ref struct EcsGraph + public readonly ref struct EcsSubGraph { - private readonly EcsJoinToGraphExecutor _executer; + private readonly EcsJoinToSubGraphExecutor _executer; private readonly EcsSpan _startEntities; public EcsSpan StartEntitiesSpan { get { return _startEntities; } } - internal EcsGraph(EcsJoinToGraphExecutor executer, EcsSpan startEntites) + internal EcsSubGraph(EcsJoinToSubGraphExecutor executer, EcsSpan startEntites) { _executer = executer; _startEntities = startEntites; } - public EcsGraphSpan GetNodes(int startEntityID) + public EcsSubGraphSpan GetNodes(int startEntityID) { return _executer.GetNodes_Internal(startEntityID); } @@ -282,4 +317,64 @@ namespace DCFApixels.DragonECS } #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(); + } + var executor = world.GetExecutor>(); + 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 + 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 + { + return group.ToSpan().JoinToSubGraph(out aspect, mode); + } + public static EcsSubGraph JoinToSubGraph(this EcsSpan span, out TAspect aspect, EcsSubGraphMode mode = EcsSubGraphMode.StartToEnd) + where TAspect : EcsAspect + { + EcsWorld world = span.World; + if (world.IsEnableReleaseDelEntBuffer) + { + world.ReleaseDelEntityBufferAll(); + } + var executor = world.GetExecutor>(); + aspect = executor.Aspect; + return executor.ExecuteFor(span, mode); + } + #endregion + } } diff --git a/src/Internal/EntityLinkedList.cs b/src/Internal/EntityLinkedList.cs index 37b7509..56d7580 100644 --- a/src/Internal/EntityLinkedList.cs +++ b/src/Internal/EntityLinkedList.cs @@ -21,7 +21,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal #region Constructors public EntityLinkedList(int capacity) { - _nodes = new Node[capacity + 10]; + _nodes = new Node[capacity * 2 + 10]; Clear(); } #endregion @@ -29,7 +29,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Resize(int newCapacity) { - Array.Resize(ref _nodes, newCapacity + 10); + Array.Resize(ref _nodes, newCapacity * 2 + 10); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -54,6 +54,15 @@ namespace DCFApixels.DragonECS.Graphs.Internal 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)] @@ -61,13 +70,15 @@ namespace DCFApixels.DragonECS.Graphs.Internal { _nodes[++_count].Set(entityID, _nodes[nodeIndex].next); _nodes[nodeIndex].next = _count; - _lastNodeIndex = _count; + _lastNodeIndex = nodeIndex + 1; return _count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int Add(int entityID) { - return InsertAfter(_lastNodeIndex, entityID); + int result = InsertAfter(_lastNodeIndex, entityID); + _lastNodeIndex = _count; + return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -99,6 +110,10 @@ namespace DCFApixels.DragonECS.Graphs.Internal this.entityID = entityID; this.next = next; } + public override string ToString() + { + return $"e:{entityID} next:{next}"; + } } public struct Enumerator { diff --git a/src/Internal/SparseMatrix.cs b/src/Internal/SparseMatrix.cs index 4d2ba2e..2779cdd 100644 --- a/src/Internal/SparseMatrix.cs +++ b/src/Internal/SparseMatrix.cs @@ -257,28 +257,30 @@ namespace DCFApixels.DragonECS.Graphs.Internal _modBitMask = (newSize - 1) & 0x7FFFFFFF; //newBuckets create and ini - Basket* newBuckets = UnmanagedArrayUtility.New(newSize); + //Basket* newBuckets = UnmanagedArrayUtility.New(newSize); + UnsafeArray newBuckets = new UnsafeArray(newSize); for (int i = 0; i < newSize; i++) { newBuckets[i] = Basket.Empty; } //END newBuckets create and ini - Entry* newEntries = UnmanagedArrayUtility.ResizeAndInit(_entries.ptr, _capacity, newSize); + //Entry* newEntries = UnmanagedArrayUtility.ResizeAndInit(_entries.ptr, _capacity, newSize); + UnsafeArray newEntries = UnsafeArray.Resize(_entries, newSize); for (int i = 0; i < _count; i++) { - if (newEntries[i].key.yHash >= 0) + if (newEntries[i].key.x >= 0) { - int targetBusket = newEntries[i].key.yHash % _capacity; - ref Basket basket = ref _buckets[targetBusket]; - newEntries[i].next = basket.index; + ref Entry entry = ref newEntries[i]; + ref Basket basket = ref newBuckets[entry.key.yHash & _modBitMask]; + entry.next = basket.index; basket.index = i; basket.count++; } } - _buckets = new UnsafeArray(newBuckets, newSize); - _entries = new UnsafeArray(newEntries, newSize); + _buckets = newBuckets; + _entries = newEntries; _capacity = newSize; } @@ -287,7 +289,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal private static int NormalizeCapacity(int capacity) { int result = MIN_CAPACITY; - while (result < capacity) result <<= 1; + while (result < capacity) { result <<= 1; } return result; } #endregion @@ -299,7 +301,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal public int next; // Index of next entry, -1 if last public Key key; public TValue value; - public override string ToString() { return key.x == 0 ? "NULL" : value.ToString(); } + public override string ToString() { return key.x == 0 ? "NULL" : $"{key} {value}"; } } [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)] @@ -320,7 +322,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)] public readonly struct Key : IEquatable { - public static readonly Key Null = new Key(-1, -1); + public static readonly Key Null = new Key(-1, 0); public readonly int x; public readonly int yHash; [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -330,12 +332,29 @@ namespace DCFApixels.DragonECS.Graphs.Internal this.yHash = yHash; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Key FromXY(int x, int y) { return new Key(x, x ^ y ^ BitsUtility.NextXorShiftState(y)); } + public static Key FromXY(int x, int y) + { + unchecked + { + return new Key(x, x ^ y ^ XXX(y)); + } + } + private static int XXX(int x) + { + x *= 3571; + x ^= x << 13; + x ^= x >> 17; + return x; + } public static bool operator ==(Key a, Key b) { return a.x == b.x && a.yHash == b.yHash; } public static bool operator !=(Key a, Key b) { return a.x != b.x || a.yHash != b.yHash; } public override int GetHashCode() { return yHash; } public bool Equals(Key other) { return this == other; } public override bool Equals(object obj) { return obj is Key && Equals((Key)obj); } + public override string ToString() + { + return $"({x}, {yHash})"; + } } #endregion }