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.Graphs.Internal;
using DCFApixels.DragonECS.UncheckedCore;
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
//Arc //Graph
//Arc world //Graph world
//Rel entity //Rel entity
//Component //Component
public class EcsArc public class EcsGraph
{ {
private readonly EcsWorld _startWorld; private readonly EcsWorld _world;
private readonly EcsWorld _endWorld; private readonly EcsWorld _graphWorld;
private readonly EcsArcWorld _arcWorld;
private readonly StartWorldHandler _startWorldHandler; private readonly GraphWorldHandler _arcWorldHandler;
private readonly ArcWorldHandler _arcWorldHandler; private readonly WorldHandler _loopWorldHandler;
private readonly EndWorldHandler _endWorldHandler;
private readonly LoopWorldHandler _loopWorldHandler;
private RelationInfo[] _relEntityInfos; //N * (N - 1) / 2 private RelationInfo[] _relEntityInfos; //N * (N - 1) / 2
private readonly SparseMatrix _matrix; private readonly SparseMatrix _matrix;
private bool _isLoop;
private bool _isInit = false; private bool _isInit = false;
private int _count; private int _count;
@ -34,30 +29,25 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _isInit; } get { return _isInit; }
} }
public EcsWorld StartWorld public EcsWorld World
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _startWorld; } get { return _world; }
} }
public EcsWorld EndWorld public short WorldID
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _endWorld; } get { return _world.id; }
} }
public EcsArcWorld ArcWorld public EcsWorld GraphWorld
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _arcWorld; } get { return _graphWorld; }
} }
public short ArcWorldID public short GraphWorldID
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _arcWorld.id; } get { return _graphWorld.id; }
}
public bool IsLoop
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _isLoop; }
} }
public int Count public int Count
{ {
@ -67,43 +57,23 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Constructors/Destroy #region Constructors/Destroy
internal EcsArc(EcsWorld startWorld, EcsWorld endWorld, EcsArcWorld arcWorld) internal EcsGraph(EcsWorld world, EcsWorld graphWorld)
{ {
_startWorld = startWorld; _world = world;
_endWorld = endWorld; _graphWorld = graphWorld;
_arcWorld = arcWorld;
_isLoop = startWorld == endWorld; _relEntityInfos = new RelationInfo[_graphWorld.Capacity];
_matrix = new SparseMatrix(_graphWorld.Capacity);
_relEntityInfos = new RelationInfo[arcWorld.Capacity]; _arcWorldHandler = new GraphWorldHandler(this);
_matrix = new SparseMatrix(arcWorld.Capacity); _loopWorldHandler = new WorldHandler(this);
_arcWorldHandler = new ArcWorldHandler(this);
if (_isLoop)
{
_loopWorldHandler = new LoopWorldHandler(this);
}
else
{
_startWorldHandler = new StartWorldHandler(this);
_endWorldHandler = new EndWorldHandler(this);
}
_isInit = true; _isInit = true;
} }
public void Destroy() public void Destroy()
{ {
_arcWorldHandler.Destroy(); _arcWorldHandler.Destroy();
if (_isLoop) _loopWorldHandler.Destroy();
{
_loopWorldHandler.Destroy();
}
else
{
_startWorldHandler.Destroy();
_endWorldHandler.Destroy();
}
} }
#endregion #endregion
@ -125,7 +95,7 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private int NewRelationInternal(int startEntityID, int endEntityID) private int NewRelationInternal(int startEntityID, int endEntityID)
{ {
int relEntityID = _arcWorld.NewEntity(); int relEntityID = _graphWorld.NewEntity();
_matrix.Add(startEntityID, endEntityID, relEntityID); _matrix.Add(startEntityID, endEntityID, relEntityID);
_relEntityInfos[relEntityID] = new RelationInfo(startEntityID, endEntityID); _relEntityInfos[relEntityID] = new RelationInfo(startEntityID, endEntityID);
_count++; _count++;
@ -158,7 +128,7 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void DelRelation(int relEntityID) public void DelRelation(int relEntityID)
{ {
_arcWorld.TryDelEntity(relEntityID); _graphWorld.TryDelEntity(relEntityID);
//ClearRelation_Internal(relEntityID); //ClearRelation_Internal(relEntityID);
} }
@ -213,30 +183,18 @@ namespace DCFApixels.DragonECS
} }
#endregion #endregion
#region Other #region GraphWorldHandler
public EcsArc GetInversetArc() private class GraphWorldHandler : IEcsWorldEventListener
{ {
return _endWorld.GetArc(_startWorld); private readonly EcsGraph _arc;
} public GraphWorldHandler(EcsGraph arc)
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)
{ {
_arc = arc; _arc = arc;
_arc.ArcWorld.AddListener(this); _arc.GraphWorld.AddListener(this);
} }
public void Destroy() public void Destroy()
{ {
_arc.ArcWorld.RemoveListener(this); _arc.GraphWorld.RemoveListener(this);
} }
#region Callbacks #region Callbacks
public void OnReleaseDelEntityBuffer(ReadOnlySpan<int> relEntityBuffer) public void OnReleaseDelEntityBuffer(ReadOnlySpan<int> relEntityBuffer)
@ -253,25 +211,25 @@ namespace DCFApixels.DragonECS
} }
#endregion #endregion
} }
#endregion
#region Loop #region WorldHandler
private class LoopWorldHandler : IEcsWorldEventListener private class WorldHandler : IEcsWorldEventListener
{ {
private readonly EcsArc _arc; private readonly EcsGraph _arc;
public LoopWorldHandler(EcsArc arc) public WorldHandler(EcsGraph arc)
{ {
_arc = arc; _arc = arc;
_arc.StartWorld.AddListener(this); _arc.World.AddListener(this);
//OnWorldResize(_arc.StartWorld.Capacity);
} }
public void Destroy() public void Destroy()
{ {
_arc.StartWorld.RemoveListener(this); _arc.World.RemoveListener(this);
} }
#region Callbacks #region Callbacks
public void OnReleaseDelEntityBuffer(ReadOnlySpan<int> startEntityBuffer) 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) foreach (var e in startEntityBuffer)
{ {
var span = graph.GetNodes(e); var span = graph.GetNodes(e);
@ -280,61 +238,12 @@ namespace DCFApixels.DragonECS
_arc.DelRelation(relE); _arc.DelRelation(relE);
} }
} }
_arc._arcWorld.ReleaseDelEntityBufferAll(); _arc._graphWorld.ReleaseDelEntityBufferAll();
} }
public void OnWorldDestroy() { } public void OnWorldDestroy() { }
public void OnWorldResize(int startWorldNewSize) { } public void OnWorldResize(int startWorldNewSize) { }
#endregion #endregion
} }
#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.Graphs.Internal;
using DCFApixels.DragonECS.UncheckedCore; using DCFApixels.DragonECS.UncheckedCore;
using System; using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS 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 EcsAspect _aspect;
private EcsArcWorld _arcWorld;
private EntityLinkedList _linkedList; private EntityLinkedList _linkedList;
private Basket[] _baskets; private Basket[] _baskets;
private int[] _startEntities; private int[] _startEntities;
private int _startEntitiesCount; private int _startEntitiesCount;
private EcsGraph _graph;
private long _lastWorldVersion; private long _lastWorldVersion;
private int _targetWorldCapacity = -1; private int _targetWorldCapacity = -1;
@ -27,11 +50,6 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _lastWorldVersion; } get { return _lastWorldVersion; }
} }
public EcsArcWorld ArcWorld
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _arcWorld; }
}
#endregion #endregion
#region OnInitialize/OnDestroy #region OnInitialize/OnDestroy
@ -40,8 +58,8 @@ namespace DCFApixels.DragonECS
_linkedList = new EntityLinkedList(World.Capacity); _linkedList = new EntityLinkedList(World.Capacity);
_baskets = new Basket[World.Capacity]; _baskets = new Basket[World.Capacity];
World.AddListener(this); World.AddListener(this);
_arcWorld = (EcsArcWorld)World;
_aspect = AspectRaw; _aspect = AspectRaw;
_graph = World.GetGraph();
} }
protected override void OnDestroy() protected override void OnDestroy()
{ {
@ -50,11 +68,11 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Execute #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(); _executeMarker.Begin();
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
@ -62,7 +80,7 @@ namespace DCFApixels.DragonECS
else if (World != span.World) { Throw.ArgumentException(""); } //TODO составить текст исключения. это проверка на то что пользователь использует правильный мир else if (World != span.World) { Throw.ArgumentException(""); } //TODO составить текст исключения. это проверка на то что пользователь использует правильный мир
#endif #endif
if (_lastWorldVersion != World.Version) //if (_lastWorldVersion != World.Version)
{ {
//Подготовка массивов //Подготовка массивов
if (_targetWorldCapacity < World.Capacity) if (_targetWorldCapacity < World.Capacity)
@ -79,50 +97,68 @@ namespace DCFApixels.DragonECS
_linkedList.Clear(); _linkedList.Clear();
//Конец подготовки массивов //Конец подготовки массивов
EcsArc arc = _arcWorld.GetRegisteredArc(); if ((mode & EcsSubGraphMode.StartToEnd) != 0)
if (_aspect.Mask.IsEmpty)
{ {
foreach (var relationEntityID in span) if (_aspect.Mask.IsEmpty)
{ {
int startEntityID = arc.GetRelationStart(relationEntityID); foreach (var relationEntityID in span) { AddStart(relationEntityID); }
if (startEntityID == 0) { continue; } }
Add(startEntityID, relationEntityID); else
{
var iterator = _aspect.GetIteratorFor(span);
foreach (var relationEntityID in iterator) { AddStart(relationEntityID); }
} }
} }
else if ((mode & EcsSubGraphMode.EndToStart) != 0)
{ {
var iterator = _aspect.GetIteratorFor(span); if (_aspect.Mask.IsEmpty)
foreach (var relationEntityID in iterator)
{ {
int startEntityID = arc.GetRelationStart(relationEntityID); foreach (var relationEntityID in span) { AddEnd(relationEntityID); }
if (startEntityID == 0) { continue; } }
Add(startEntityID, relationEntityID); else
{
var iterator = _aspect.GetIteratorFor(span);
foreach (var relationEntityID in iterator) { AddEnd(relationEntityID); }
} }
} }
_lastWorldVersion = World.Version; _lastWorldVersion = World.Version;
} }
else //else
{ //{
//
} //}
_executeMarker.End(); _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; AddFrom(_graph.GetRelationStart(relationEntityID), relationEntityID);
ref var basket = ref _baskets[startEntityID]; }
[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) if (basket.index <= 0)
{ {
_startEntities[_startEntitiesCount++] = fromEntityID;
basket.index = _linkedList.Add(relationEntityID); basket.index = _linkedList.Add(relationEntityID);
} }
else else
{ {
_linkedList.InsertAfter(basket.index, relationEntityID); basket.index = _linkedList.InsertBefore(basket.index, relationEntityID);
} }
basket.count++; basket.count++;
} }
@ -130,10 +166,10 @@ namespace DCFApixels.DragonECS
#region Internal result methods #region Internal result methods
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsGraphSpan GetNodes_Internal(int startEntityID) internal EcsSubGraphSpan GetNodes_Internal(int startEntityID)
{ {
Basket basket = _baskets[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)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal int GetNode_Internal(int startEntityID) internal int GetNode_Internal(int startEntityID)
@ -167,42 +203,29 @@ namespace DCFApixels.DragonECS
{ {
public int index; public int index;
public int count; public int count;
} public override string ToString()
#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
{ {
if (_aspect == null) return $"i:{index} count:{count}";
{
_aspect = World.GetAspect<TAspect>();
}
return _aspect;
} }
} }
#endregion #endregion
} }
public enum EcsSubGraphMode
{
NONE = 0,
StartToEnd = 1 << 0,
EndToStart = 1 << 1,
All = StartToEnd | EndToStart,
}
#region EcsJoinedSpan/EcsJoined #region EcsJoinedSpan/EcsJoined
public readonly ref struct EcsGraphSpan public readonly ref struct EcsSubGraphSpan
{ {
public static EcsGraphSpan Empty public static EcsSubGraphSpan Empty
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return new EcsGraphSpan(null, 0, 0); } get { return new EcsSubGraphSpan(null, 0, 0); }
} }
private readonly EntityLinkedList.Node[] _nodes; private readonly EntityLinkedList.Node[] _nodes;
@ -213,8 +236,20 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _count; } 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)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsGraphSpan(EntityLinkedList.Node[] nodes, int startNodeIndex, int count) internal EcsSubGraphSpan(EntityLinkedList.Node[] nodes, int startNodeIndex, int count)
{ {
_nodes = nodes; _nodes = nodes;
_startNodeIndex = startNodeIndex; _startNodeIndex = startNodeIndex;
@ -225,7 +260,7 @@ namespace DCFApixels.DragonECS
{ {
return new Enumerator(_nodes, _startNodeIndex, _count); return new Enumerator(_nodes, _startNodeIndex, _count);
} }
public struct Enumerator public ref struct Enumerator
{ {
private readonly EntityLinkedList.Node[] _nodes; private readonly EntityLinkedList.Node[] _nodes;
private int _index; 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; private readonly EcsSpan _startEntities;
public EcsSpan StartEntitiesSpan public EcsSpan StartEntitiesSpan
{ {
get { return _startEntities; } get { return _startEntities; }
} }
internal EcsGraph(EcsJoinToGraphExecutor executer, EcsSpan startEntites) internal EcsSubGraph(EcsJoinToSubGraphExecutor executer, EcsSpan startEntites)
{ {
_executer = executer; _executer = executer;
_startEntities = startEntites; _startEntities = startEntites;
} }
public EcsGraphSpan GetNodes(int startEntityID) public EcsSubGraphSpan GetNodes(int startEntityID)
{ {
return _executer.GetNodes_Internal(startEntityID); return _executer.GetNodes_Internal(startEntityID);
} }
@ -282,4 +317,64 @@ namespace DCFApixels.DragonECS
} }
#endregion #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 #region Constructors
public EntityLinkedList(int capacity) public EntityLinkedList(int capacity)
{ {
_nodes = new Node[capacity + 10]; _nodes = new Node[capacity * 2 + 10];
Clear(); Clear();
} }
#endregion #endregion
@ -29,7 +29,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Resize(int newCapacity) public void Resize(int newCapacity)
{ {
Array.Resize(ref _nodes, newCapacity + 10); Array.Resize(ref _nodes, newCapacity * 2 + 10);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -54,6 +54,15 @@ namespace DCFApixels.DragonECS.Graphs.Internal
return _nodes[nodeIndex].entityID; 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> /// <summary> Insert after</summary>
/// <returns> new node index</returns> /// <returns> new node index</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -61,13 +70,15 @@ namespace DCFApixels.DragonECS.Graphs.Internal
{ {
_nodes[++_count].Set(entityID, _nodes[nodeIndex].next); _nodes[++_count].Set(entityID, _nodes[nodeIndex].next);
_nodes[nodeIndex].next = _count; _nodes[nodeIndex].next = _count;
_lastNodeIndex = _count; _lastNodeIndex = nodeIndex + 1;
return _count; return _count;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Add(int entityID) public int Add(int entityID)
{ {
return InsertAfter(_lastNodeIndex, entityID); int result = InsertAfter(_lastNodeIndex, entityID);
_lastNodeIndex = _count;
return result;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -99,6 +110,10 @@ namespace DCFApixels.DragonECS.Graphs.Internal
this.entityID = entityID; this.entityID = entityID;
this.next = next; this.next = next;
} }
public override string ToString()
{
return $"e:{entityID} next:{next}";
}
} }
public struct Enumerator public struct Enumerator
{ {

View File

@ -257,28 +257,30 @@ namespace DCFApixels.DragonECS.Graphs.Internal
_modBitMask = (newSize - 1) & 0x7FFFFFFF; _modBitMask = (newSize - 1) & 0x7FFFFFFF;
//newBuckets create and ini //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++) for (int i = 0; i < newSize; i++)
{ {
newBuckets[i] = Basket.Empty; newBuckets[i] = Basket.Empty;
} }
//END newBuckets create and ini //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++) 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 Entry entry = ref newEntries[i];
ref Basket basket = ref _buckets[targetBusket]; ref Basket basket = ref newBuckets[entry.key.yHash & _modBitMask];
newEntries[i].next = basket.index; entry.next = basket.index;
basket.index = i; basket.index = i;
basket.count++; basket.count++;
} }
} }
_buckets = new UnsafeArray<Basket>(newBuckets, newSize); _buckets = newBuckets;
_entries = new UnsafeArray<Entry>(newEntries, newSize); _entries = newEntries;
_capacity = newSize; _capacity = newSize;
} }
@ -287,7 +289,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal
private static int NormalizeCapacity(int capacity) private static int NormalizeCapacity(int capacity)
{ {
int result = MIN_CAPACITY; int result = MIN_CAPACITY;
while (result < capacity) result <<= 1; while (result < capacity) { result <<= 1; }
return result; return result;
} }
#endregion #endregion
@ -299,7 +301,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal
public int next; // Index of next entry, -1 if last public int next; // Index of next entry, -1 if last
public Key key; public Key key;
public TValue value; 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)] [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)]
@ -320,7 +322,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)] [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)]
public readonly struct Key : IEquatable<Key> 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 x;
public readonly int yHash; public readonly int yHash;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -330,12 +332,29 @@ namespace DCFApixels.DragonECS.Graphs.Internal
this.yHash = yHash; this.yHash = yHash;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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 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 override int GetHashCode() { return yHash; }
public bool Equals(Key other) { return this == other; } public bool Equals(Key other) { return this == other; }
public override bool Equals(object obj) { return obj is Key && Equals((Key)obj); } public override bool Equals(object obj) { return obj is Key && Equals((Key)obj); }
public override string ToString()
{
return $"({x}, {yHash})";
}
} }
#endregion #endregion
} }