This commit is contained in:
Mikhail 2024-03-18 02:45:25 +08:00
parent f16e5e353c
commit 285649c47c
8 changed files with 369 additions and 446 deletions

View File

@ -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<TWorld> : EcsArcWorld
where TWorld : EcsWorld
{
public EcsLoopArcWorld(ConfigContainer config = null) : base(config) { }
public EcsLoopArcWorld(IConfigContainer config = null) : base(config) { }
}
public sealed class EcsArcWorld<TStartWorld, TEndWorld> : EcsArcWorld
where TStartWorld : EcsWorld
where TEndWorld : EcsWorld
{
public EcsArcWorld(ConfigContainer config = null) : base(config) { }
public EcsArcWorld(IConfigContainer config = null) : base(config) { }
}
}

View File

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

View File

@ -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<int> 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<int> startEntityBuffer)
{
var graph = _arc.ArcWorld.GetExecutor<EcsJoinToGraphExecutor<EmptyAspect>>().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<int> 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<int> endEntityBuffer)
{
_arc._arcWorld.ReleaseDelEntityBufferAll();
}
public void OnWorldDestroy() { }
public void OnWorldResize(int endWorldNewSize) { }
#endregion
}
#endregion
#endregion
}
}

108
src/EcsGraphExtensions.cs Normal file
View File

@ -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<int> buffer) { }
public void OnWorldDestroy()
{
TryDestroy(_graph);
}
public void OnWorldResize(int newSize) { }
}
}
}

View File

@ -1,191 +0,0 @@
using DCFApixels.DragonECS.Graphs.Internal;
using System;
namespace DCFApixels.DragonECS
{
public static class EcsWorldGraph
{
private static readonly SparseArray<EcsArc> _matrix = new SparseArray<EcsArc>(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<TWorld>(this TWorld self, out EcsLoopArcWorld<TWorld> 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<TWorld>(config);
return Register(self, self, arcWorld);
}
public static EcsArc SetArcAuto<TStartWorld, TEndWorld>(this TStartWorld start, TEndWorld end, out EcsArcWorld<TStartWorld, TEndWorld> 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<TStartWorld, TEndWorld>(config);
return Register(start, end, arcWorld);
}
public static EcsArc SetLoopArcAuto<TWorld>(this TWorld self, IConfigContainer config = null)
where TWorld : EcsWorld
{
return SetLoopArcAuto(self, out _, config);
}
public static EcsArc SetArcAuto<TStartWorld, TEndWorld>(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
}
}

View File

@ -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<TAspect> : 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<TAspect>(); }
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<TAspect> : 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<TAspect>();
}
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<int> E
{
get
{
List<int> result = new List<int>();
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<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();
}
var executor = world.GetExecutor<EcsJoinToSubGraphExecutor<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
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
{
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
{
EcsWorld world = span.World;
if (world.IsEnableReleaseDelEntBuffer)
{
world.ReleaseDelEntityBufferAll();
}
var executor = world.GetExecutor<EcsJoinToSubGraphExecutor<TAspect>>();
aspect = executor.Aspect;
return executor.ExecuteFor(span, mode);
}
#endregion
}
}

View File

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

View File

@ -257,28 +257,30 @@ namespace DCFApixels.DragonECS.Graphs.Internal
_modBitMask = (newSize - 1) & 0x7FFFFFFF;
//newBuckets create and ini
Basket* newBuckets = UnmanagedArrayUtility.New<Basket>(newSize);
//Basket* newBuckets = UnmanagedArrayUtility.New<Basket>(newSize);
UnsafeArray<Basket> newBuckets = new UnsafeArray<Basket>(newSize);
for (int i = 0; i < newSize; i++)
{
newBuckets[i] = Basket.Empty;
}
//END newBuckets create and ini
Entry* newEntries = UnmanagedArrayUtility.ResizeAndInit<Entry>(_entries.ptr, _capacity, newSize);
//Entry* newEntries = UnmanagedArrayUtility.ResizeAndInit<Entry>(_entries.ptr, _capacity, newSize);
UnsafeArray<Entry> newEntries = UnsafeArray<Entry>.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<Basket>(newBuckets, newSize);
_entries = new UnsafeArray<Entry>(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<Key>
{
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
}