diff --git a/src/Common/IdsBasket.cs b/src/Common/IdsBasket.cs index edd665c..28c2a28 100644 --- a/src/Common/IdsBasket.cs +++ b/src/Common/IdsBasket.cs @@ -1,11 +1,10 @@ -using DCFApixels.DragonECS.Relations.Utils; -using System; +using System; using System.Diagnostics; -namespace DCFApixels.DragonECS +namespace DCFApixels.DragonECS.Relations.Utils { [DebuggerTypeProxy(typeof(DebuggerProxy))] - public class IdsBasket + internal class IdsBasket { private IdsLinkedList _headList = new IdsLinkedList(4); private IdsLinkedList _valueList = new IdsLinkedList(4); @@ -83,6 +82,14 @@ namespace DCFApixels.DragonECS else return _headList.GetSpan(head.startNodeIndex, head.count); } + public IdsLinkedList.LongSpan GetLongSpanFor(EcsWorld world, int value) + { + ref var head = ref _headMapping[value]; + if (head.startNodeIndex <= 0) + return _headList.EmptyLongSpan(world); + else + return _headList.GetLongSpan(world, head.startNodeIndex, head.count); + } private struct SpanInfo { diff --git a/src/EcsEdge.cs b/src/EcsEdge.cs index 60a0483..031db23 100644 --- a/src/EcsEdge.cs +++ b/src/EcsEdge.cs @@ -1,5 +1,7 @@ using DCFApixels.DragonECS.Relations.Utils; using System; +using System.Collections; +using System.Collections.Generic; using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS @@ -158,9 +160,10 @@ namespace DCFApixels.DragonECS public void BindRelation(int relationEntityID, int entityID, int otherEntityID) => _source.BindRelation(relationEntityID, entityID, otherEntityID); public bool HasRelation(int entityID, int otherEntityID) => _source.HasRelation(entityID, otherEntityID); public int GetRelation(int entityID, int otherEntityID) => _source.GetRelation(entityID, otherEntityID); - public void DelRelation(int entityID, int otherEntityID) => _source.DelRelation(entityID, otherEntityID); public bool TryGetRelation(int entityID, int otherEntityID, out int relationEntityID) => _source.TryGetRelation(entityID, otherEntityID, out relationEntityID); public IdsLinkedList.Span GetRelations(int entityID) => _source._basket.GetSpanFor(entityID); + public IdsLinkedList.LongSpan GetLongRelations(int entityID) => _source._basket.GetLongSpanFor(_source._world, entityID); + public void DelRelation(int entityID, int otherEntityID) => _source.DelRelation(entityID, otherEntityID); } public readonly struct ReverseOrientation { @@ -170,16 +173,43 @@ namespace DCFApixels.DragonECS public void BindRelation(int relationEntityID, int entityID, int otherEntityID) => _source.BindRelation(relationEntityID, otherEntityID, entityID); public bool HasRelation(int otherEntityID, int entityID) => _source.HasRelation(entityID, otherEntityID); public int GetRelation(int otherEntityID, int entityID) => _source.GetRelation(entityID, otherEntityID); - public void DelRelation(int otherEntityID, int entityID) => _source.DelRelation(entityID, otherEntityID); public bool TryGetRelation(int otherEntityID, int entityID, out int relationEntityID) => _source.TryGetRelation(entityID, otherEntityID, out relationEntityID); public IdsLinkedList.Span GetRelations(int otherEntityID) => _source._otherBasket.GetSpanFor(otherEntityID); + public IdsLinkedList.LongSpan GetLongRelations(int otherEntityID) => _source._otherBasket.GetLongSpanFor(_source._otherWorld, otherEntityID); + public void DelRelation(int otherEntityID, int entityID) => _source.DelRelation(entityID, otherEntityID); } - public struct RelationsSpan - { - private readonly IdsBasket _basket; - private readonly EcsAspect _aspect; - } + //public readonly ref struct FilterIterator + //{ + // private readonly IdsLinkedList.Span _listSpan; + // private readonly EcsMask _mask; + // public FilterIterator(EcsWorld world, IdsLinkedList.Span listSpan, EcsMask mask) + // { + // _listSpan = listSpan; + // _mask = mask; + // } + // public Enumerator GetEnumerator() => new Enumerator(_listSpan, _mask); + // public ref struct Enumerator + // { + // private readonly IdsLinkedList.SpanEnumerator _listEnumerator; + // private readonly EcsMask _mask; + // public Enumerator(IdsLinkedList.Span listSpan, EcsMask mask) + // { + // _listEnumerator = listSpan.GetEnumerator(); + // _mask = mask; + // } + // public int Current => _listEnumerator.Current; + // public bool MoveNext() + // { + // while (_listEnumerator.MoveNext()) + // { + // int e = _listEnumerator.Current; + // ... + // } + // return false; + // } + // } + //} #endregion } } diff --git a/src/Utils/IdsLinkedList.cs b/src/Utils/IdsLinkedList.cs index ec25759..93cc45d 100644 --- a/src/Utils/IdsLinkedList.cs +++ b/src/Utils/IdsLinkedList.cs @@ -130,16 +130,107 @@ namespace DCFApixels.DragonECS.Relations.Utils public int Add(int id) => InsertAfter(_lastNodeIndex, id); public ref readonly Node GetNode(int nodeIndex) => ref _nodes[nodeIndex]; + #region Span/Enumerator + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public SpanEnumerator GetEnumerator() => new SpanEnumerator(_nodes, _nodes[Head].next, _count); public Span GetSpan(int startNodeIndex, int count) => new Span(this, startNodeIndex, count); public Span EmptySpan() => new Span(this, 0, 0); - #region IEnumerable - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public LongSpan GetLongs(EcsWorld world) => new LongSpan(world, this, _nodes[Head].next, _count); + public LongSpan GetLongSpan(EcsWorld world, int startNodeIndex, int count) => new LongSpan(world, this, startNodeIndex, count); + public LongSpan EmptyLongSpan(EcsWorld world) => new LongSpan(world, this, 0, 0); + + public readonly ref struct Span + { + private readonly IdsLinkedList _source; + private readonly int _startNodeIndex; + private readonly int _count; + public Span(IdsLinkedList source, int startNodeIndex, int count) + { + _source = source; + _startNodeIndex = startNodeIndex; + _count = count; + } + public SpanEnumerator GetEnumerator() => new SpanEnumerator(_source._nodes, _startNodeIndex, _count); + } + public struct SpanEnumerator : IEnumerator + { + private readonly Node[] _nodes; + private int _count; + private int _index; + private int _next; + public SpanEnumerator(Node[] nodes, int startIndex, int count) + { + _nodes = nodes; + _index = -1; + _count = count; + _next = startIndex; + } + public int Current => _nodes[_index].value; + object IEnumerator.Current => Current; + public bool MoveNext() + { + _index = _next; + _next = _nodes[_next].next; + return _index > 0 && _count-- > 0; + } + void IDisposable.Dispose() { } + void IEnumerator.Reset() + { + _index = -1; + _next = Head; + } + } + public readonly ref struct LongSpan + { + private readonly EcsWorld _world; + private readonly IdsLinkedList _source; + private readonly int _startNodeIndex; + private readonly int _count; + public LongSpan(EcsWorld world, IdsLinkedList source, int startNodeIndex, int count) + { + _world = world; + _source = source; + _startNodeIndex = startNodeIndex; + _count = count; + } + public LongSpanEnumerator GetEnumerator() => new LongSpanEnumerator(_world, _source._nodes, _startNodeIndex, _count); + } + public struct LongSpanEnumerator : IEnumerator + { + private EcsWorld _world; + private readonly Node[] _nodes; + private int _count; + private int _index; + private int _next; + public LongSpanEnumerator(EcsWorld world, Node[] nodes, int startIndex, int count) + { + _world = world; + _nodes = nodes; + _index = -1; + _count = count; + _next = startIndex; + } + public entlong Current => _world.GetEntityLong(_nodes[_index].value); + object IEnumerator.Current => Current; + public bool MoveNext() + { + _index = _next; + _next = _nodes[_next].next; + return _index > 0 && _count-- > 0; + } + void IDisposable.Dispose() { } + void IEnumerator.Reset() + { + _index = -1; + _next = Head; + } + } #endregion - #region Utils Node/Enumerator/Span + #region Node [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)] public struct Node { @@ -157,52 +248,6 @@ namespace DCFApixels.DragonECS.Relations.Utils } public override string ToString() => $"node({prev}<>{next} v:{value})"; } - - #region Span/Enumerator - public readonly ref struct Span - { - private readonly IdsLinkedList _source; - private readonly int _startNodeIndex; - private readonly int _count; - public Span(IdsLinkedList source, int startNodeIndex, int count) - { - _source = source; - _startNodeIndex = startNodeIndex; - _count = count; - } - public SpanEnumerator GetEnumerator() => new SpanEnumerator(_source._nodes, _startNodeIndex, _count); - } - public struct SpanEnumerator : IEnumerator - { - private readonly Node[] _nodes; - private int _index; - private int _count; - private int _next; - public SpanEnumerator(Node[] nodes, int startIndex, int count) - { - _nodes = nodes; - _index = -1; - _count = count; - _next = startIndex; - } - public int Current => _nodes[_index].value; - public bool MoveNext() - { - _index = _next; - _next = _nodes[_next].next; - return _index > 0 && _count-- > 0; - } - - object IEnumerator.Current => Current; - void IDisposable.Dispose() { } - void IEnumerator.Reset() - { - _index = -1; - _next = Head; - } - } - #endregion - #endregion #region Debug diff --git a/src/WorldGraph.cs b/src/WorldGraph.cs index ab0566e..72d6476 100644 --- a/src/WorldGraph.cs +++ b/src/WorldGraph.cs @@ -17,6 +17,7 @@ namespace DCFApixels.DragonECS #endif EcsEdge edge = new EcsEdge(world, otherWorld, edgeWorld); _matrix[worldID, otherWorldID] = edge; + _matrix[otherWorldID, worldID] = edge; return edge; } internal static void Unregister(EcsWorld world, EcsWorld otherWorld) @@ -25,6 +26,7 @@ namespace DCFApixels.DragonECS int otherWorldID = otherWorld.id; //var manager = _matrix[worldID, otherWorldID]; _matrix.Remove(worldID, otherWorldID); + _matrix.Remove(otherWorldID, worldID); } internal static EcsEdge Get(EcsWorld world, EcsWorld otherWorld) @@ -64,8 +66,8 @@ namespace DCFApixels.DragonECS WorldGraph.HasEdge(self, otherWorld); } - public static EcsEdge GetEdgeWithSelf(this EcsWorld self) => GetRelationWith(self, self); - public static EcsEdge GetRelationWith(this EcsWorld self, EcsWorld otherWorld) + public static EcsEdge GetEdgeWithSelf(this EcsWorld self) => GetEdgeWith(self, self); + public static EcsEdge GetEdgeWith(this EcsWorld self, EcsWorld otherWorld) { if (self == null || otherWorld == null) throw new ArgumentNullException();