mirror of
https://github.com/DCFApixels/DragonECS-Graphs.git
synced 2025-09-18 03:34:35 +08:00
update
This commit is contained in:
parent
74c5f8e8c5
commit
df5b50257f
@ -173,7 +173,7 @@ namespace DCFApixels.DragonECS
|
|||||||
return !_relEntityInfos[relEntityID].IsNull;
|
return !_relEntityInfos[relEntityID].IsNull;
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public StartEnd GetRelationInfo(int relEntityID)
|
public StartEnd GetRelationStartEnd(int relEntityID)
|
||||||
{
|
{
|
||||||
if (relEntityID <= 0 || relEntityID >= _relEntityInfos.Length)
|
if (relEntityID <= 0 || relEntityID >= _relEntityInfos.Length)
|
||||||
{
|
{
|
||||||
@ -182,14 +182,22 @@ namespace DCFApixels.DragonECS
|
|||||||
return new StartEnd(_relEntityInfos[relEntityID]);
|
return new StartEnd(_relEntityInfos[relEntityID]);
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public int GetRelStart(int relEntityID)
|
public int GetRelationStart(int relEntityID)
|
||||||
{
|
{
|
||||||
return GetRelationInfo(relEntityID).start;
|
if (relEntityID <= 0 || relEntityID >= _relEntityInfos.Length)
|
||||||
|
{
|
||||||
|
Throw.UndefinedException();
|
||||||
|
}
|
||||||
|
return _relEntityInfos[relEntityID].start;
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public int GetRelEnd(int relEntityID)
|
public int GetRelationEnd(int relEntityID)
|
||||||
{
|
{
|
||||||
return GetRelationInfo(relEntityID).end;
|
if (relEntityID <= 0 || relEntityID >= _relEntityInfos.Length)
|
||||||
|
{
|
||||||
|
Throw.UndefinedException();
|
||||||
|
}
|
||||||
|
return _relEntityInfos[relEntityID].end;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -80,23 +80,17 @@ namespace DCFApixels.DragonECS
|
|||||||
#region Extension
|
#region Extension
|
||||||
public static bool IsRegistered(this EcsArcWorld self)
|
public static bool IsRegistered(this EcsArcWorld self)
|
||||||
{
|
{
|
||||||
if (self == null)
|
if (self == null) { Throw.ArgumentNull(); }
|
||||||
{
|
|
||||||
Throw.ArgumentNull();
|
|
||||||
}
|
|
||||||
int id = self.id;
|
int id = self.id;
|
||||||
return id < _arcsMapping.Length && _arcsMapping[self.id] != null;
|
return id < _arcsMapping.Length && _arcsMapping[self.id] != null;
|
||||||
}
|
}
|
||||||
public static EcsArc GetRegisteredArc(this EcsArcWorld self)
|
public static EcsArc GetRegisteredArc(this EcsArcWorld self)
|
||||||
{
|
{
|
||||||
if (self == null)
|
if (self == null) { Throw.ArgumentNull(); }
|
||||||
{
|
|
||||||
Throw.ArgumentNull();
|
|
||||||
}
|
|
||||||
int id = self.id;
|
int id = self.id;
|
||||||
if (id < _arcsMapping.Length && _arcsMapping[self.id] == null)
|
if (id < _arcsMapping.Length && _arcsMapping[self.id] == null)
|
||||||
{
|
{
|
||||||
throw new Exception();
|
Throw.UndefinedException();
|
||||||
}
|
}
|
||||||
return _arcsMapping[self.id];
|
return _arcsMapping[self.id];
|
||||||
}
|
}
|
||||||
@ -105,10 +99,7 @@ namespace DCFApixels.DragonECS
|
|||||||
public static EcsArc SetLoopArcAuto<TWorld>(this TWorld self, out EcsLoopArcWorld<TWorld> arcWorld, IConfigContainer config = null)
|
public static EcsArc SetLoopArcAuto<TWorld>(this TWorld self, out EcsLoopArcWorld<TWorld> arcWorld, IConfigContainer config = null)
|
||||||
where TWorld : EcsWorld
|
where TWorld : EcsWorld
|
||||||
{
|
{
|
||||||
if (self == null)
|
if (self == null) { Throw.ArgumentNull(); }
|
||||||
{
|
|
||||||
Throw.ArgumentNull();
|
|
||||||
}
|
|
||||||
if (typeof(TWorld) != self.GetType())
|
if (typeof(TWorld) != self.GetType())
|
||||||
{
|
{
|
||||||
EcsDebug.PrintWarning($"{nameof(TWorld)} is not {self.GetType().Name}");
|
EcsDebug.PrintWarning($"{nameof(TWorld)} is not {self.GetType().Name}");
|
||||||
@ -120,10 +111,7 @@ namespace DCFApixels.DragonECS
|
|||||||
where TStartWorld : EcsWorld
|
where TStartWorld : EcsWorld
|
||||||
where TEndWorld : EcsWorld
|
where TEndWorld : EcsWorld
|
||||||
{
|
{
|
||||||
if (start == null || end == null)
|
if (start == null || end == null) { Throw.ArgumentNull(); }
|
||||||
{
|
|
||||||
Throw.ArgumentNull();
|
|
||||||
}
|
|
||||||
if (typeof(TStartWorld) == typeof(EcsWorld) && typeof(TEndWorld) == typeof(EcsWorld))
|
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}");
|
EcsDebug.PrintWarning($"{nameof(TStartWorld)} is not {start.GetType().Name} or {nameof(TEndWorld)} is not {end.GetType().Name}");
|
||||||
@ -143,49 +131,52 @@ namespace DCFApixels.DragonECS
|
|||||||
return SetArcAuto(start, end, out _, config);
|
return SetArcAuto(start, end, out _, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EcsArc SetLoopArc(this EcsWorld self, EcsArcWorld arc) => SetArc(self, self, arc);
|
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)
|
public static EcsArc SetArc(this EcsWorld start, EcsWorld end, EcsArcWorld arc)
|
||||||
{
|
{
|
||||||
if (start == null || end == null || arc == null)
|
if (start == null || end == null || arc == null) { Throw.ArgumentNull(); }
|
||||||
{
|
|
||||||
Throw.ArgumentNull();
|
|
||||||
}
|
|
||||||
return Register(start, end, arc);
|
return Register(start, end, arc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool HasLoopArc(this EcsWorld self) => HasArc(self, self);
|
public static bool HasLoopArc(this EcsWorld self)
|
||||||
|
{
|
||||||
|
return HasArc(self, self);
|
||||||
|
}
|
||||||
public static bool HasArc(this EcsWorld start, EcsWorld end)
|
public static bool HasArc(this EcsWorld start, EcsWorld end)
|
||||||
{
|
{
|
||||||
if (start == null || end == null)
|
if (start == null || end == null) { Throw.ArgumentNull(); }
|
||||||
{
|
|
||||||
Throw.ArgumentNull();
|
|
||||||
}
|
|
||||||
return Has(start, end);
|
return Has(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EcsArc GetLoopArc(this EcsWorld self) => GetArc(self, self);
|
public static EcsArc GetLoopArc(this EcsWorld self)
|
||||||
|
{
|
||||||
|
return GetArc(self, self);
|
||||||
|
}
|
||||||
public static EcsArc GetArc(this EcsWorld start, EcsWorld end)
|
public static EcsArc GetArc(this EcsWorld start, EcsWorld end)
|
||||||
{
|
{
|
||||||
if (start == null || end == null)
|
if (start == null || end == null) { Throw.ArgumentNull(); }
|
||||||
{
|
|
||||||
Throw.ArgumentNull();
|
|
||||||
}
|
|
||||||
return Get(start, end);
|
return Get(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryGetLoopArc(this EcsWorld self, out EcsArc arc) => TryGetArc(self, self, out arc);
|
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)
|
public static bool TryGetArc(this EcsWorld start, EcsWorld end, out EcsArc arc)
|
||||||
{
|
{
|
||||||
if (start == null || end == null)
|
if (start == null || end == null) { Throw.ArgumentNull(); }
|
||||||
{
|
|
||||||
Throw.ArgumentNull();
|
|
||||||
}
|
|
||||||
bool result = Has(start, end);
|
bool result = Has(start, end);
|
||||||
arc = result ? Get(start, end) : null;
|
arc = result ? Get(start, end) : null;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DestroyLoopArc(this EcsWorld self) => DestroyArcWith(self, self);
|
public static void DestroyLoopArc(this EcsWorld self)
|
||||||
|
{
|
||||||
|
DestroyArcWith(self, self);
|
||||||
|
}
|
||||||
public static void DestroyArcWith(this EcsWorld start, EcsWorld end)
|
public static void DestroyArcWith(this EcsWorld start, EcsWorld end)
|
||||||
{
|
{
|
||||||
if (start == null || end == null)
|
if (start == null || end == null)
|
||||||
|
@ -1,124 +1,40 @@
|
|||||||
/*
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
public class EcsJoinExecutor<TAspect> : EcsQueryExecutor, IEcsWorldEventListener
|
public class EcsJoinExecutor : EcsQueryExecutor, IEcsWorldEventListener
|
||||||
where TAspect : EcsAspect
|
|
||||||
{
|
{
|
||||||
private TAspect _aspect;
|
private long _lastWorldVersion;
|
||||||
//internal EcsGroup _filteredGroup;
|
|
||||||
|
|
||||||
private IdsLinkedList _linkedBasket;
|
|
||||||
private int[] _mapping;
|
|
||||||
private int[] _counts;
|
|
||||||
|
|
||||||
private long _executeVersion;
|
|
||||||
|
|
||||||
private int _targetWorldCapacity = -1;
|
|
||||||
private EcsProfilerMarker _executeMarker = new EcsProfilerMarker("JoinAttach");
|
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
public TAspect Aspect => _aspect;
|
public sealed override long Version
|
||||||
internal long ExecuteVersion => _executeVersion;
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => _lastWorldVersion;
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region OnInitialize/OnDestroy
|
#region Callbacks
|
||||||
protected override void OnInitialize()
|
protected override void OnInitialize()
|
||||||
{
|
{
|
||||||
_linkedBasket = new IdsLinkedList(128);
|
|
||||||
World.AddListener(this);
|
|
||||||
_mapping = new int[World.Capacity];
|
|
||||||
_counts = new int[World.Capacity];
|
|
||||||
}
|
}
|
||||||
protected override void OnDestroy()
|
protected override void OnDestroy()
|
||||||
{
|
{
|
||||||
World.RemoveListener(this);
|
|
||||||
}
|
}
|
||||||
#endregion
|
public void OnWorldResize(int newSize)
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
_linkedBasket.Clear();
|
|
||||||
ArrayUtility.Fill(_mapping, 0, 0, _mapping.Length);
|
|
||||||
ArrayUtility.Fill(_counts, 0, 0, _counts.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IdsLinkedList.Span GetEntitiesFor(int entity)
|
|
||||||
{
|
|
||||||
ref var nodeIndex = ref _mapping[entity];
|
|
||||||
if (nodeIndex <= 0)
|
|
||||||
return _linkedBasket.EmptySpan();
|
|
||||||
else
|
|
||||||
return _linkedBasket.GetSpan(nodeIndex, _counts[entity]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Execute
|
|
||||||
public EcsJoinAttachResult<TAspect> Execute() => ExecuteFor(World.Entities);
|
|
||||||
public EcsJoinAttachResult<TAspect> ExecuteFor(EcsReadonlyGroup sourceGroup)
|
|
||||||
{
|
|
||||||
_executeMarker.Begin();
|
|
||||||
var world = _aspect.World;
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
|
||||||
if (sourceGroup.IsNull) throw new ArgumentNullException();//TODO составить текст исключения.
|
|
||||||
#endif
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
|
||||||
else
|
|
||||||
if (World != sourceGroup.World) throw new ArgumentException();//TODO составить текст исключения. это проверка на то что пользователь использует правильный мир
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//Подготовка массивов
|
|
||||||
if (_targetWorldCapacity < World.Capacity)
|
|
||||||
{
|
|
||||||
_targetWorldCapacity = World.Capacity;
|
|
||||||
_mapping = new int[_targetWorldCapacity];
|
|
||||||
_counts = new int[_targetWorldCapacity];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ArrayUtility.Fill(_counts, 0);
|
|
||||||
ArrayUtility.Fill(_mapping, 0);
|
|
||||||
}
|
|
||||||
_linkedBasket.Clear();
|
|
||||||
//Конец подготовки массивов
|
|
||||||
|
|
||||||
EcsEdge edge = World.GetEdgeWithSelf();
|
|
||||||
|
|
||||||
var iterator = new EcsAspectIterator(_aspect, sourceGroup);
|
|
||||||
foreach (var arcEntityID in iterator)
|
|
||||||
{
|
|
||||||
var rel = edge.GetRelationTargets(arcEntityID);
|
|
||||||
|
|
||||||
|
|
||||||
int sorceEntityID = rel.entity;
|
|
||||||
//if (!CheckMaskInternal(targetWorldWhereQuery.query.mask, attachTargetID)) continue; //TODO проверить что все работает //исчключить все аттачи, цели которых не входят в targetWorldWhereQuery
|
|
||||||
|
|
||||||
ref int nodeIndex = ref _mapping[sorceEntityID];
|
|
||||||
if (nodeIndex <= 0)
|
|
||||||
nodeIndex = _linkedBasket.Add(arcEntityID);
|
|
||||||
else
|
|
||||||
_linkedBasket.InsertAfter(nodeIndex, arcEntityID);
|
|
||||||
_counts[sorceEntityID]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
_executeVersion++;
|
|
||||||
_executeMarker.End();
|
|
||||||
|
|
||||||
return new EcsJoinAttachResult<TAspect>(_aspect, this, _executeVersion);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region IEcsWorldEventListener
|
|
||||||
void IEcsWorldEventListener.OnWorldResize(int newSize)
|
|
||||||
{
|
|
||||||
Array.Resize(ref _mapping, newSize);
|
|
||||||
Array.Resize(ref _counts, newSize);
|
|
||||||
}
|
|
||||||
void IEcsWorldEventListener.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
void IEcsWorldEventListener.OnWorldDestroy()
|
public void OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public void OnWorldDestroy()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
264
src/Executors/EcsJoinToGraphExecutor.cs
Normal file
264
src/Executors/EcsJoinToGraphExecutor.cs
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
using DCFApixels.DragonECS.Graphs.Internal;
|
||||||
|
using DCFApixels.DragonECS.UncheckedCore;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS
|
||||||
|
{
|
||||||
|
public abstract class EcsJoinToGraphExecutor : EcsQueryExecutor, IEcsWorldEventListener
|
||||||
|
{
|
||||||
|
private EcsAspect _aspect;
|
||||||
|
private EcsArcWorld _arcWorld;
|
||||||
|
|
||||||
|
private EntityLinkedList _linkedList;
|
||||||
|
private Basket[] _baskets;
|
||||||
|
private int[] _startEntities;
|
||||||
|
private int _startEntitiesCount;
|
||||||
|
|
||||||
|
private long _lastWorldVersion;
|
||||||
|
|
||||||
|
private int _targetWorldCapacity = -1;
|
||||||
|
private EcsProfilerMarker _executeMarker = new EcsProfilerMarker("JoinAttach");
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
protected abstract EcsAspect AspectRaw { get; }
|
||||||
|
public sealed override long Version
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get { return _lastWorldVersion; }
|
||||||
|
}
|
||||||
|
public EcsArcWorld ArcWorld
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get { return _arcWorld; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region OnInitialize/OnDestroy
|
||||||
|
protected override void OnInitialize()
|
||||||
|
{
|
||||||
|
_linkedList = new EntityLinkedList(World.Capacity);
|
||||||
|
_baskets = new Basket[World.Capacity];
|
||||||
|
World.AddListener(this);
|
||||||
|
_arcWorld = (EcsArcWorld)World;
|
||||||
|
}
|
||||||
|
protected override void OnDestroy()
|
||||||
|
{
|
||||||
|
World.RemoveListener(this);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Execute
|
||||||
|
public EcsGraph Execute()
|
||||||
|
{
|
||||||
|
return ExecuteFor(World.Entities);
|
||||||
|
}
|
||||||
|
public EcsGraph ExecuteFor(EcsSpan span)
|
||||||
|
{
|
||||||
|
_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();
|
||||||
|
//Конец подготовки массивов
|
||||||
|
|
||||||
|
EcsArc arc = _arcWorld.GetRegisteredArc();
|
||||||
|
|
||||||
|
var iterator = _aspect.GetIteratorFor(span);
|
||||||
|
foreach (var relationEntityID in iterator)
|
||||||
|
{
|
||||||
|
int startEntityID = arc.GetRelationStart(relationEntityID);
|
||||||
|
if(startEntityID == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_startEntities[_startEntitiesCount++] = startEntityID;
|
||||||
|
|
||||||
|
ref var basket = ref _baskets[startEntityID];
|
||||||
|
if (basket.index <= 0)
|
||||||
|
{
|
||||||
|
basket.index = _linkedList.Add(relationEntityID);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_linkedList.InsertAfter(basket.index, relationEntityID);
|
||||||
|
}
|
||||||
|
basket.count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastWorldVersion = World.Version;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_executeMarker.End();
|
||||||
|
return new EcsGraph(this, UncheckedCoreUtility.CreateSpan(WorldID, _startEntities, _startEntitiesCount));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Internal result methods
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal EcsGraphSpan GetNodes_Internal(int startEntityID)
|
||||||
|
{
|
||||||
|
Basket basket = _baskets[startEntityID];
|
||||||
|
return new EcsGraphSpan(_linkedList._nodes, basket.index, basket.count);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal int GetNode_Internal(int startEntityID)
|
||||||
|
{
|
||||||
|
Basket basket = _baskets[startEntityID];
|
||||||
|
return basket.count > 0 ? _linkedList.Get(basket.index) : 0;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal int GetNodesCount_Internal(int startEntityID)
|
||||||
|
{
|
||||||
|
return _baskets[startEntityID].count;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal int GetCount_Internal()
|
||||||
|
{
|
||||||
|
return _linkedList.Count;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IEcsWorldEventListener
|
||||||
|
void IEcsWorldEventListener.OnWorldResize(int newSize)
|
||||||
|
{
|
||||||
|
Array.Resize(ref _baskets, newSize);
|
||||||
|
}
|
||||||
|
void IEcsWorldEventListener.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer) { }
|
||||||
|
void IEcsWorldEventListener.OnWorldDestroy() { }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Basket
|
||||||
|
public struct Basket
|
||||||
|
{
|
||||||
|
public int index;
|
||||||
|
public int count;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
public sealed class EcsJoinExecutor<TAspect> : EcsJoinToGraphExecutor
|
||||||
|
where TAspect : EcsAspect
|
||||||
|
{
|
||||||
|
private TAspect _aspect;
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
public TAspect Aspect
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get { return _aspect; }
|
||||||
|
}
|
||||||
|
protected override EcsAspect AspectRaw
|
||||||
|
{
|
||||||
|
get { return _aspect; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region EcsJoinedSpan/EcsJoined
|
||||||
|
public readonly ref struct EcsGraphSpan
|
||||||
|
{
|
||||||
|
public static EcsGraphSpan Empty
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get { return new EcsGraphSpan(null, 0, 0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly EntityLinkedList.Node[] _nodes;
|
||||||
|
private readonly int _startNodeIndex;
|
||||||
|
private readonly int _count;
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get { return _count; }
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal EcsGraphSpan(EntityLinkedList.Node[] nodes, int startNodeIndex, int count)
|
||||||
|
{
|
||||||
|
_nodes = nodes;
|
||||||
|
_startNodeIndex = startNodeIndex;
|
||||||
|
_count = count;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Enumerator GetEnumerator()
|
||||||
|
{
|
||||||
|
return new Enumerator(_nodes, _startNodeIndex, _count);
|
||||||
|
}
|
||||||
|
public struct Enumerator
|
||||||
|
{
|
||||||
|
private readonly EntityLinkedList.Node[] _nodes;
|
||||||
|
private int _index;
|
||||||
|
private int _count;
|
||||||
|
private int _next;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal Enumerator(EntityLinkedList.Node[] nodes, int startIndex, int count)
|
||||||
|
{
|
||||||
|
_nodes = nodes;
|
||||||
|
_index = -1;
|
||||||
|
_count = count;
|
||||||
|
_next = startIndex;
|
||||||
|
}
|
||||||
|
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 && _count-- > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly ref struct EcsGraph
|
||||||
|
{
|
||||||
|
private readonly EcsJoinToGraphExecutor _executer;
|
||||||
|
private readonly EcsSpan _startEntities;
|
||||||
|
public EcsSpan StartEntitiesSpan
|
||||||
|
{
|
||||||
|
get { return _startEntities; }
|
||||||
|
}
|
||||||
|
internal EcsGraph(EcsJoinToGraphExecutor executer, EcsSpan startEntites)
|
||||||
|
{
|
||||||
|
_executer = executer;
|
||||||
|
_startEntities = startEntites;
|
||||||
|
}
|
||||||
|
public EcsGraphSpan 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
|
||||||
|
}
|
130
src/Internal/EntityLinkedList.cs
Normal file
130
src/Internal/EntityLinkedList.cs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
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 + 10];
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Resize(int newCapacity)
|
||||||
|
{
|
||||||
|
Array.Resize(ref _nodes, newCapacity + 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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 = _count;
|
||||||
|
return _count;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public int Add(int entityID)
|
||||||
|
{
|
||||||
|
return InsertAfter(_lastNodeIndex, entityID);
|
||||||
|
}
|
||||||
|
|
||||||
|
[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 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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user