This commit is contained in:
DCFApixels 2024-11-17 13:36:14 +08:00
parent 2087573b6e
commit 3da9cb9065
11 changed files with 590 additions and 430 deletions

View File

@ -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 { }
}

7
src/Consts.cs Normal file
View File

@ -0,0 +1,7 @@
namespace DCFApixels.DragonECS
{
public static class EcsGraphConsts
{
public const string PACK_GROUP = "_" + EcsConsts.FRAMEWORK_NAME + "/Graphs";
}
}

View File

@ -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);

View File

@ -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<int> startEntityBuffer)
public void OnReleaseDelEntityBuffer(ReadOnlySpan<int> 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
}
}

View File

@ -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<int> buffer)
{
}
public void OnWorldDestroy()
{
}
#endregion
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 2b337a549ff9db3488c9ae26a898f770
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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<int> 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<TCollection>(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<TCollection, TAspect>(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<TAspect>(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<TAspect>(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
}
}
}

View File

@ -0,0 +1,63 @@
namespace DCFApixels.DragonECS
{
public static class GraphQueries
{
#region JoinToGraph Empty
//public static EcsSubGraph JoinToSubGraph<TCollection>(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<TCollection>(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<TCollection, TAspect>(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<TAspect>(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<TAspect>(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
}
}

View File

@ -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;
}
/// <summary> Insert after</summary>
/// <returns> new node index</returns>
[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;
/// <summary>next node index</summary>
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
}
}

View File

@ -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;
//}
///// <returns> new node index</returns>
//[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;
//}
///// <returns> new node index</returns>
//[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;
//}
/// <returns> new node index</returns>
//[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
}
}

View File

@ -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.");
}
}
}