mirror of
https://github.com/DCFApixels/DragonECS-Graphs.git
synced 2025-09-17 19:24:36 +08:00
tmp update
This commit is contained in:
parent
5118e5887d
commit
2f5c172c4e
124
src/Builtin/EcsJoinExecutor.cs
Normal file
124
src/Builtin/EcsJoinExecutor.cs
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public class EcsJoinExecutor<TAspect> : EcsQueryExecutor, IEcsWorldEventListener
|
||||
where TAspect : EcsAspect
|
||||
{
|
||||
private TAspect _aspect;
|
||||
//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
|
||||
public TAspect Aspect => _aspect;
|
||||
internal long ExecuteVersion => _executeVersion;
|
||||
#endregion
|
||||
|
||||
#region OnInitialize/OnDestroy
|
||||
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()
|
||||
{
|
||||
World.RemoveListener(this);
|
||||
}
|
||||
#endregion
|
||||
|
||||
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()
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
*/
|
226
src/EcsEdge.cs
226
src/EcsEdge.cs
@ -1,5 +1,6 @@
|
||||
using DCFApixels.DragonECS.Relations.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
@ -13,68 +14,87 @@ namespace DCFApixels.DragonECS
|
||||
private readonly EcsWorld _otherWorld;
|
||||
private readonly EcsEdgeWorld _edgeWorld;
|
||||
|
||||
private readonly VertexWorldHandler _worldHandler;
|
||||
private readonly VertexWorldHandler _otherWorldHandler;
|
||||
|
||||
private readonly IdsBasket _basket = new IdsBasket(256);
|
||||
private readonly IdsBasket _otherBasket = new IdsBasket(256);
|
||||
private readonly SparseArray64<int> _relationsMatrix = new SparseArray64<int>();
|
||||
|
||||
public readonly ForwardOrientation Forward;
|
||||
public readonly ReverseOrientation Reverse;
|
||||
private ArcTargets[] _arkTargets; //N * (N - 1) / 2
|
||||
|
||||
private RelationTargets[] _relationTargets;
|
||||
private List<WeakReference<EcsJoinGroup>> _groups = new List<WeakReference<EcsJoinGroup>>();
|
||||
private Stack<EcsJoinGroup> _groupsPool = new Stack<EcsJoinGroup>(64);
|
||||
|
||||
#region Properties
|
||||
public EcsWorld World => _world;
|
||||
public EcsWorld OtherWorld => _otherWorld;
|
||||
public EcsEdgeWorld EdgeWorld => _edgeWorld;
|
||||
|
||||
public bool IsLoop => _world == _otherWorld;
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
internal EcsEdge(EcsWorld world, EcsWorld otherWorld, EcsEdgeWorld edgeWorld)
|
||||
{
|
||||
_edgeWorld = edgeWorld;
|
||||
_world = world;
|
||||
_otherWorld = otherWorld;
|
||||
|
||||
_relationTargets = new RelationTargets[edgeWorld.Capacity];
|
||||
_worldHandler = new VertexWorldHandler(this, _world, _basket);
|
||||
_world.AddListener(_worldHandler);
|
||||
if (IsLoop)
|
||||
{
|
||||
_otherWorldHandler = _worldHandler;
|
||||
}
|
||||
else
|
||||
{
|
||||
_otherWorldHandler = new VertexWorldHandler(this, _otherWorld, _otherBasket);
|
||||
_world.AddListener(_otherWorldHandler);
|
||||
}
|
||||
|
||||
_arkTargets = new ArcTargets[edgeWorld.Capacity];
|
||||
|
||||
_edgeWorld.AddListener(worldEventListener: this);
|
||||
_edgeWorld.AddListener(entityEventListener: this);
|
||||
|
||||
Forward = new ForwardOrientation(this);
|
||||
Reverse = new ReverseOrientation(this);
|
||||
}
|
||||
#endregion
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref readonly RelationTargets GetRelationTargets(int arcEntityID)
|
||||
#region Join Groups Pool
|
||||
internal void RegisterGroup(EcsJoinGroup group)
|
||||
{
|
||||
return ref _relationTargets[arcEntityID];
|
||||
_groups.Add(new WeakReference<EcsJoinGroup>(group));
|
||||
}
|
||||
|
||||
#region Methods
|
||||
internal EcsJoinGroup GetFreeGroup()
|
||||
{
|
||||
EcsJoinGroup result = _groupsPool.Count <= 0 ? new EcsJoinGroup(this) : _groupsPool.Pop();
|
||||
result._isReleased = false;
|
||||
return result;
|
||||
}
|
||||
internal void ReleaseGroup(EcsJoinGroup group)
|
||||
{
|
||||
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||
if (group.Edge != this) throw new Exception();
|
||||
#endif
|
||||
group._isReleased = true;
|
||||
group.Clear();
|
||||
_groupsPool.Push(group);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region New/Del
|
||||
private int NewRelation(int entityID, int otherEntityID)
|
||||
public int New(int entityID, int otherEntityID)
|
||||
{
|
||||
|
||||
if (HasRelation(entityID, otherEntityID))
|
||||
if (Has(entityID, otherEntityID))
|
||||
throw new EcsRelationException();
|
||||
int e = _edgeWorld.NewEmptyEntity();
|
||||
int arcEntity = _edgeWorld.NewEntity();
|
||||
_basket.AddToHead(entityID, otherEntityID);
|
||||
_otherBasket.AddToHead(otherEntityID, entityID);
|
||||
_relationsMatrix.Add(entityID, otherEntityID, e);
|
||||
_relationTargets[e] = new RelationTargets(entityID, otherEntityID);
|
||||
return e;
|
||||
_relationsMatrix.Add(entityID, otherEntityID, arcEntity);
|
||||
_arkTargets[arcEntity] = new ArcTargets(entityID, otherEntityID);
|
||||
return arcEntity;
|
||||
}
|
||||
private void BindRelation(int relationEntityID, int entityID, int otherEntityID)
|
||||
{
|
||||
ref var rel = ref _relationTargets[relationEntityID];
|
||||
if (HasRelation(entityID, otherEntityID) || rel.IsEmpty)
|
||||
throw new EcsRelationException();
|
||||
_basket.AddToHead(entityID, otherEntityID);
|
||||
_otherBasket.AddToHead(otherEntityID, entityID);
|
||||
_relationsMatrix.Add(entityID, otherEntityID, relationEntityID);
|
||||
rel = new RelationTargets(entityID, otherEntityID);
|
||||
}
|
||||
private void DelRelation(int entityID, int otherEntityID)
|
||||
public void Del(int entityID, int otherEntityID)
|
||||
{
|
||||
if (!_relationsMatrix.TryGetValue(entityID, otherEntityID, out int e))
|
||||
throw new EcsRelationException();
|
||||
@ -82,28 +102,25 @@ namespace DCFApixels.DragonECS
|
||||
_basket.DelHead(entityID);
|
||||
_otherBasket.Del(entityID);
|
||||
_edgeWorld.DelEntity(e);
|
||||
_relationTargets[e] = RelationTargets.Empty;
|
||||
_arkTargets[e] = ArcTargets.Empty;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Has
|
||||
private bool HasRelation(int entityID, int otherEntityID) => _relationsMatrix.Contains(entityID, otherEntityID);
|
||||
#region Get/Has
|
||||
public bool Has(int entityID, int otherEntityID) => _relationsMatrix.Contains(entityID, otherEntityID);
|
||||
//public bool HasRelationWith(EcsSubject subject, int entityID, int otherEntityID)
|
||||
//{
|
||||
// if (subject.World != _relationWorld)
|
||||
// throw new ArgumentException();
|
||||
// return _source._relationsMatrix.TryGetValue(entityID, otherEntityID, out int entity) && subject.IsMatches(entity);
|
||||
//}
|
||||
#endregion
|
||||
|
||||
#region GetRelation
|
||||
private int GetRelation(int entityID, int otherEntityID)
|
||||
public int Get(int entityID, int otherEntityID)
|
||||
{
|
||||
if (!_relationsMatrix.TryGetValue(entityID, otherEntityID, out int e))
|
||||
throw new EcsRelationException();
|
||||
return e;
|
||||
}
|
||||
private bool TryGetRelation(int entityID, int otherEntityID, out int entity)
|
||||
private bool TryGet(int entityID, int otherEntityID, out int entity)
|
||||
{
|
||||
return _relationsMatrix.TryGetValue(entityID, otherEntityID, out entity);
|
||||
}
|
||||
@ -111,9 +128,7 @@ namespace DCFApixels.DragonECS
|
||||
//{
|
||||
// return _source._relationsMatrix.TryGetValue(entityID, otherEntityID, out entity) && subject.IsMatches(entity);
|
||||
//}
|
||||
#endregion
|
||||
|
||||
#region GetRelations
|
||||
//#region GetRelations
|
||||
//private IdsLinkedList.Span GetRelations(int entityID)
|
||||
//{
|
||||
@ -129,12 +144,31 @@ namespace DCFApixels.DragonECS
|
||||
//#endregion
|
||||
#endregion
|
||||
|
||||
#region Other
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool IsArc(int arcEntityID)
|
||||
{
|
||||
if (arcEntityID <= 0 || arcEntityID >= _arkTargets.Length)
|
||||
return false;
|
||||
return !_arkTargets[arcEntityID].IsEmpty;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ArcTargets GetArcTargets(int arcEntityID)
|
||||
{
|
||||
if (arcEntityID <= 0 || arcEntityID >= _arkTargets.Length)
|
||||
throw new Exception();
|
||||
return _arkTargets[arcEntityID];
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public IdsLinkedList.Span Get(int entityID) => _basket.GetSpanFor(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public IdsLinkedList.LongSpan GetLongs(int entityID) => _basket.GetLongSpanFor(_world, entityID);
|
||||
#endregion
|
||||
|
||||
#region Callbacks
|
||||
void IEcsWorldEventListener.OnWorldResize(int newSize)
|
||||
{
|
||||
Array.Resize(ref _relationTargets, newSize);
|
||||
Array.Resize(ref _arkTargets, newSize);
|
||||
}
|
||||
void IEcsWorldEventListener.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer) { }
|
||||
void IEcsWorldEventListener.OnWorldDestroy() { }
|
||||
@ -142,100 +176,38 @@ namespace DCFApixels.DragonECS
|
||||
void IEcsEntityEventListener.OnNewEntity(int entityID) { }
|
||||
void IEcsEntityEventListener.OnDelEntity(int entityID)
|
||||
{
|
||||
ref RelationTargets rel = ref _relationTargets[entityID];
|
||||
if (_relationsMatrix.Contains(rel.entity, rel.otherEntity))
|
||||
Forward.Del(rel.entity, rel.otherEntity);
|
||||
ref ArcTargets rel = ref _arkTargets[entityID];
|
||||
if (_relationsMatrix.Contains(rel.start, rel.end))
|
||||
Del(rel.start, rel.end);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Orientation
|
||||
public readonly struct ForwardOrientation : IEcsEdgeOrientation
|
||||
#region VertexWorldHandler
|
||||
private class VertexWorldHandler : IEcsEntityEventListener
|
||||
{
|
||||
private readonly EcsEdge _source;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal ForwardOrientation(EcsEdge source) => _source = source;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int New(int entityID, int otherEntityID) => _source.NewRelation(entityID, otherEntityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Bind(int arcEntityID, int entityID, int otherEntityID) => _source.BindRelation(arcEntityID, entityID, otherEntityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Has(int entityID, int otherEntityID) => _source.HasRelation(entityID, otherEntityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int Get(int entityID, int otherEntityID) => _source.GetRelation(entityID, otherEntityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryGet(int entityID, int otherEntityID, out int arcEntityID) => _source.TryGetRelation(entityID, otherEntityID, out arcEntityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public IdsLinkedList.Span Get(int entityID) => _source._basket.GetSpanFor(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public IdsLinkedList.LongSpan GetLongs(int entityID) => _source._basket.GetLongSpanFor(_source._world, entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Del(int entityID, int otherEntityID) => _source.DelRelation(entityID, otherEntityID);
|
||||
}
|
||||
public readonly struct ReverseOrientation : IEcsEdgeOrientation
|
||||
private readonly EcsWorld _world;
|
||||
private readonly IdsBasket _basket;
|
||||
|
||||
public VertexWorldHandler(EcsEdge source, EcsWorld world, IdsBasket basket)
|
||||
{
|
||||
private readonly EcsEdge _source;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal ReverseOrientation(EcsEdge source) => _source = source;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int New(int otherEntityID, int entityID) => _source.NewRelation(entityID, otherEntityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Bind(int arcEntityID, int entityID, int otherEntityID) => _source.BindRelation(arcEntityID, otherEntityID, entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Has(int otherEntityID, int entityID) => _source.HasRelation(entityID, otherEntityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int Get(int otherEntityID, int entityID) => _source.GetRelation(entityID, otherEntityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryGet(int otherEntityID, int entityID, out int arcEntityID) => _source.TryGetRelation(entityID, otherEntityID, out arcEntityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public IdsLinkedList.Span Get(int otherEntityID) => _source._otherBasket.GetSpanFor(otherEntityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public IdsLinkedList.LongSpan GetLongs(int otherEntityID) => _source._otherBasket.GetLongSpanFor(_source._otherWorld, otherEntityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Del(int otherEntityID, int entityID) => _source.DelRelation(entityID, otherEntityID);
|
||||
_source = source;
|
||||
_world = world;
|
||||
_basket = basket;
|
||||
}
|
||||
|
||||
//public readonly ref struct FilterIterator
|
||||
//{
|
||||
// private readonly IdsLinkedList.Span _listSpan;
|
||||
// private readonly EcsMask _mask;
|
||||
// public FilterIterator(EcsWorld world, IdsLinkedList.Span listSpan, EcsMask mask)
|
||||
// {
|
||||
// _listSpan = listSpan;
|
||||
// _mask = mask;
|
||||
// }
|
||||
// public Enumerator GetEnumerator() => new Enumerator(_listSpan, _mask);
|
||||
// public ref struct Enumerator
|
||||
// {
|
||||
// private readonly IdsLinkedList.SpanEnumerator _listEnumerator;
|
||||
// private readonly EcsMask _mask;
|
||||
// public Enumerator(IdsLinkedList.Span listSpan, EcsMask mask)
|
||||
// {
|
||||
// _listEnumerator = listSpan.GetEnumerator();
|
||||
// _mask = mask;
|
||||
// }
|
||||
// public int Current => _listEnumerator.Current;
|
||||
// public bool MoveNext()
|
||||
// {
|
||||
// while (_listEnumerator.MoveNext())
|
||||
// {
|
||||
// int e = _listEnumerator.Current;
|
||||
// ...
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
#endregion
|
||||
}
|
||||
public interface IEcsEdgeOrientation
|
||||
public void OnDelEntity(int entityID)
|
||||
{
|
||||
public int New(int entityID, int otherEntityID);
|
||||
public void Bind(int arcEntityID, int entityID, int otherEntityID);
|
||||
public bool Has(int entityID, int otherEntityID);
|
||||
public int Get(int entityID, int otherEntityID);
|
||||
public bool TryGet(int otherEntityID, int entityID, out int arcEntityID);
|
||||
public IdsLinkedList.Span Get(int entityID);
|
||||
public IdsLinkedList.LongSpan GetLongs(int entityID);
|
||||
public void Del(int entityID, int otherEntityID);
|
||||
var span = _basket.GetSpanFor(entityID);
|
||||
foreach (var arcEntityID in span)
|
||||
{
|
||||
}
|
||||
}
|
||||
public void OnNewEntity(int entityID)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
69
src/EcsJoinGroup.cs
Normal file
69
src/EcsJoinGroup.cs
Normal file
@ -0,0 +1,69 @@
|
||||
using DCFApixels.DragonECS.Relations.Utils;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public class EcsJoinGroup
|
||||
{
|
||||
private EcsEdge _source;
|
||||
|
||||
private int[] _mapping;
|
||||
private int[] _counts;
|
||||
private IdsLinkedList _linkedList;
|
||||
internal bool _isReleased = true;
|
||||
|
||||
#region Properites
|
||||
public EcsEdge Edge => _source;
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constrcutors/Dispose
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static EcsJoinGroup New(EcsEdge edge)
|
||||
{
|
||||
return edge.GetFreeGroup();
|
||||
}
|
||||
internal EcsJoinGroup(EcsEdge edge, int denseCapacity = 64)
|
||||
{
|
||||
_source = edge;
|
||||
_source.RegisterGroup(this);
|
||||
int capacity = edge.World.Capacity;
|
||||
|
||||
_mapping = new int[capacity];
|
||||
_counts = new int[capacity];
|
||||
}
|
||||
public void Dispose() => _source.ReleaseGroup(this);
|
||||
#endregion
|
||||
|
||||
public void Add(int entityFrom, int entityTo)
|
||||
{
|
||||
ref int nodeIndex = ref _mapping[entityFrom];
|
||||
if (nodeIndex <= 0)
|
||||
{
|
||||
nodeIndex = _linkedList.Add(entityTo);
|
||||
_counts[entityFrom] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_linkedList.InsertAfter(nodeIndex, entityTo);
|
||||
_counts[entityFrom]++;
|
||||
}
|
||||
}
|
||||
|
||||
public IdsLinkedList.Span GetEntitiesFor(int entity)
|
||||
{
|
||||
ref var nodeIndex = ref _mapping[entity];
|
||||
if (nodeIndex <= 0)
|
||||
return _linkedList.EmptySpan();
|
||||
else
|
||||
return _linkedList.GetSpan(nodeIndex, _counts[entity]);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_linkedList.Clear();
|
||||
for (int i = 0; i < _mapping.Length; i++)
|
||||
_mapping[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
49
src/Utils/ArcTargets.cs
Normal file
49
src/Utils/ArcTargets.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)]
|
||||
[Serializable]
|
||||
public readonly struct ArcTargets : IEquatable<ArcTargets>
|
||||
{
|
||||
public static readonly ArcTargets Empty = new ArcTargets();
|
||||
|
||||
/// <summary>Start vertex entity ID.</summary>
|
||||
public readonly int start;
|
||||
/// <summary>End vertex entity ID.</summary>
|
||||
public readonly int end;
|
||||
|
||||
#region Properties
|
||||
public bool IsEmpty
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => start == 0 && end == 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal ArcTargets(int startEntity, int endEntity)
|
||||
{
|
||||
start = startEntity;
|
||||
end = endEntity;
|
||||
}
|
||||
|
||||
#region operators
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(ArcTargets a, ArcTargets b) => a.start == b.start && a.end == b.end;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(ArcTargets a, ArcTargets b) => a.start != b.start || a.end != b.end;
|
||||
#endregion
|
||||
|
||||
#region Other
|
||||
public override bool Equals(object obj) => obj is ArcTargets targets && targets == this;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ArcTargets other) => this == other;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override int GetHashCode() => ~start ^ end;
|
||||
public override string ToString() => $"arc({start} -> {end})";
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,4 +1,8 @@
|
||||
namespace DCFApixels.DragonECS.Relations.Utils
|
||||
using System.Runtime.InteropServices;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DCFApixels.DragonECS.Relations.Utils
|
||||
{
|
||||
internal static class ArrayUtility
|
||||
{
|
||||
|
@ -1,83 +0,0 @@
|
||||
#pragma warning disable IDE1006 // Стили именования
|
||||
using DCFApixels.DragonECS.Utils;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)]
|
||||
[Serializable]
|
||||
public readonly struct RelationTargets : IEquatable<RelationTargets>
|
||||
{
|
||||
public static readonly RelationTargets Empty = new RelationTargets();
|
||||
|
||||
public readonly int entity;
|
||||
public readonly int otherEntity;
|
||||
|
||||
#region Properties
|
||||
public int left
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => IsInverted ? otherEntity : entity;
|
||||
}
|
||||
public int right
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => IsInverted ? entity : otherEntity;
|
||||
}
|
||||
|
||||
public bool IsInverted
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => entity > otherEntity; // направление всегда с меньшего к большему
|
||||
}
|
||||
public bool IsEmpty
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => entity == 0 && otherEntity == 0;
|
||||
}
|
||||
|
||||
public RelationTargets Inverted
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => new RelationTargets(otherEntity, entity);
|
||||
}
|
||||
#endregion
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal RelationTargets(int entity, int otherEntity)
|
||||
{
|
||||
this.entity = entity;
|
||||
this.otherEntity = otherEntity;
|
||||
}
|
||||
|
||||
#region operators
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static RelationTargets operator -(RelationTargets a) => a.Inverted;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(RelationTargets a, RelationTargets b) => a.entity == b.entity && a.otherEntity == b.otherEntity;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(RelationTargets a, RelationTargets b) => a.entity != b.entity || a.otherEntity != b.otherEntity;s
|
||||
#endregion
|
||||
|
||||
#region Other
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is RelationTargets targets &&
|
||||
entity == targets.entity &&
|
||||
otherEntity == targets.otherEntity;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(RelationTargets other) => this == other;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override int GetHashCode() => ~entity ^ otherEntity;
|
||||
public override string ToString()
|
||||
{
|
||||
return IsInverted ?
|
||||
$"rel({entity} <- {otherEntity})" :
|
||||
$"rel({entity} -> {otherEntity})";
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
using DCFApixels.DragonECS.Relations.Internal;
|
||||
using DCFApixels.DragonECS.Relations.Utils;
|
||||
using Leopotam.EcsLite;
|
||||
using System;
|
||||
|
||||
namespace DCFApixels.DragonECS.Relations.Internal
|
||||
@ -63,12 +62,12 @@ namespace DCFApixels.DragonECS
|
||||
return WorldGraph.Register(self, otherWorld, edgeWorld);
|
||||
}
|
||||
|
||||
public static void HasEdgeWithSelf(this EcsWorld self) => HasEdgeWith(self, self);
|
||||
public static void HasEdgeWith(this EcsWorld self, EcsWorld otherWorld)
|
||||
public static bool HasEdgeWithSelf(this EcsWorld self) => HasEdgeWith(self, self);
|
||||
public static bool HasEdgeWith(this EcsWorld self, EcsWorld otherWorld)
|
||||
{
|
||||
if (self == null || otherWorld == null)
|
||||
throw new ArgumentNullException();
|
||||
WorldGraph.HasEdge(self, otherWorld);
|
||||
return WorldGraph.HasEdge(self, otherWorld);
|
||||
}
|
||||
|
||||
public static EcsEdge GetEdgeWithSelf(this EcsWorld self) => GetEdgeWith(self, self);
|
||||
|
Loading…
Reference in New Issue
Block a user