garbage collection optimizations
parent
01a9211ff4
commit
2f46af30fb
|
@ -83,9 +83,8 @@ namespace MoonTools.ECS
|
||||||
// Returns true if the entity had this component.
|
// Returns true if the entity had this component.
|
||||||
public override bool Remove(int entityID)
|
public override bool Remove(int entityID)
|
||||||
{
|
{
|
||||||
if (entityIDToStorageIndex.ContainsKey(entityID))
|
if (entityIDToStorageIndex.TryGetValue(entityID, out int storageIndex))
|
||||||
{
|
{
|
||||||
var storageIndex = entityIDToStorageIndex[entityID];
|
|
||||||
entityIDToStorageIndex.Remove(entityID);
|
entityIDToStorageIndex.Remove(entityID);
|
||||||
|
|
||||||
var lastElementIndex = nextID - 1;
|
var lastElementIndex = nextID - 1;
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MoonTools.ECS
|
||||||
|
{
|
||||||
|
public class DynamicArray<T> where T : unmanaged
|
||||||
|
{
|
||||||
|
private T[] Array;
|
||||||
|
public int Count { get; private set; }
|
||||||
|
|
||||||
|
public Span<T> ToSpan() => new Span<T>(Array, 0, Count);
|
||||||
|
public ReverseSpanEnumerator<T> GetEnumerator() => new ReverseSpanEnumerator<T>(new Span<T>(Array, 0, Count));
|
||||||
|
|
||||||
|
public DynamicArray(int capacity = 16)
|
||||||
|
{
|
||||||
|
Array = new T[capacity];
|
||||||
|
Count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref T this[int i]
|
||||||
|
{
|
||||||
|
get { return ref Array[i]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(T item)
|
||||||
|
{
|
||||||
|
if (Count >= Array.Length)
|
||||||
|
{
|
||||||
|
global::System.Array.Resize(ref Array, Array.Length * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Array[Count] = item;
|
||||||
|
Count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
Count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,5 +35,15 @@ namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
return !a.Equals(b);
|
return !a.Equals(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static implicit operator int(Entity e)
|
||||||
|
{
|
||||||
|
return e.ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator Entity(int i)
|
||||||
|
{
|
||||||
|
return new Entity(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,13 +62,18 @@ namespace MoonTools.ECS
|
||||||
return RelationDepot.Related<TRelationKind>(a.ID, b.ID);
|
return RelationDepot.Related<TRelationKind>(a.ID, b.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// relations go A->B, so given A, will give all outgoing B relations.
|
protected TRelationKind GetRelationData<TRelationKind>(in Entity a, in Entity b) where TRelationKind : unmanaged
|
||||||
protected IEnumerable<(Entity, TRelationKind)> OutRelations<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
|
{
|
||||||
|
return RelationDepot.Get<TRelationKind>(new Relation(a.ID, b.ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
// relations go A->B, so given A, will give all entities in outgoing relations of this kind.
|
||||||
|
protected ReverseSpanEnumerator<Entity> OutRelations<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
|
||||||
{
|
{
|
||||||
return RelationDepot.OutRelations<TRelationKind>(entity.ID);
|
return RelationDepot.OutRelations<TRelationKind>(entity.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected (Entity, TRelationKind) OutRelationSingleton<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
|
protected Entity OutRelationSingleton<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
|
||||||
{
|
{
|
||||||
return RelationDepot.OutRelationSingleton<TRelationKind>(entity.ID);
|
return RelationDepot.OutRelationSingleton<TRelationKind>(entity.ID);
|
||||||
}
|
}
|
||||||
|
@ -83,13 +88,13 @@ namespace MoonTools.ECS
|
||||||
return RelationDepot.OutRelationCount<TRelationKind>(entity.ID);
|
return RelationDepot.OutRelationCount<TRelationKind>(entity.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Relations go A->B, so given B, will give all incoming A relations.
|
// Relations go A->B, so given B, will give all entities in incoming A relations of this kind.
|
||||||
protected IEnumerable<(Entity, TRelationKind)> InRelations<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
|
protected ReverseSpanEnumerator<Entity> InRelations<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
|
||||||
{
|
{
|
||||||
return RelationDepot.InRelations<TRelationKind>(entity.ID);
|
return RelationDepot.InRelations<TRelationKind>(entity.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected (Entity, TRelationKind) InRelationSingleton<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
|
protected Entity InRelationSingleton<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
|
||||||
{
|
{
|
||||||
return RelationDepot.InRelationSingleton<TRelationKind>(entity.ID);
|
return RelationDepot.InRelationSingleton<TRelationKind>(entity.ID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,13 +62,12 @@ namespace MoonTools.ECS
|
||||||
EntityToRelationTypeIndices[entityId].Remove(relationIndex);
|
EntityToRelationTypeIndices[entityId].Remove(relationIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: should these ints be ID types?
|
public HashSet<int> ComponentTypeIndices(int entityID)
|
||||||
public IEnumerable<int> ComponentTypeIndices(int entityID)
|
|
||||||
{
|
{
|
||||||
return EntityToComponentTypeIndices[entityID];
|
return EntityToComponentTypeIndices[entityID];
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<int> RelationTypeIndices(int entityID)
|
public HashSet<int> RelationTypeIndices(int entityID)
|
||||||
{
|
{
|
||||||
return EntityToRelationTypeIndices[entityID];
|
return EntityToRelationTypeIndices[entityID];
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace MoonTools.ECS
|
||||||
|
{
|
||||||
|
public ref struct ReverseSpanEnumerator<T>
|
||||||
|
{
|
||||||
|
private ReadOnlySpan<T> Span;
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
public ReverseSpanEnumerator<T> GetEnumerator() => this;
|
||||||
|
|
||||||
|
public T Current => Span[index];
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
if (index > 0)
|
||||||
|
{
|
||||||
|
index -= 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public ReverseSpanEnumerator(Span<T> span)
|
||||||
|
{
|
||||||
|
Span = span;
|
||||||
|
index = span.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ReverseSpanEnumerator<T> Empty => new ReverseSpanEnumerator<T>();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
|
@ -13,8 +14,8 @@ namespace MoonTools.ECS
|
||||||
Signature = new FilterSignature(included, excluded);
|
Signature = new FilterSignature(included, excluded);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Entity> Entities => FilterStorage.FilterEntities(Signature);
|
public ReverseSpanEnumerator<Entity> Entities => FilterStorage.FilterEntities(Signature);
|
||||||
public IEnumerable<Entity> EntitiesInRandomOrder => FilterStorage.FilterEntitiesRandom(Signature);
|
public LinearCongruentialEnumerator EntitiesInRandomOrder => FilterStorage.FilterEntitiesRandom(Signature);
|
||||||
public Entity RandomEntity => FilterStorage.FilterRandomEntity(Signature);
|
public Entity RandomEntity => FilterStorage.FilterRandomEntity(Signature);
|
||||||
|
|
||||||
public int Count => FilterStorage.FilterCount(Signature);
|
public int Count => FilterStorage.FilterCount(Signature);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS
|
||||||
|
@ -7,7 +7,7 @@ namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
private EntityStorage EntityStorage;
|
private EntityStorage EntityStorage;
|
||||||
private TypeIndices ComponentTypeIndices;
|
private TypeIndices ComponentTypeIndices;
|
||||||
private Dictionary<FilterSignature, IndexableSet<int>> filterSignatureToEntityIDs = new Dictionary<FilterSignature, IndexableSet<int>>();
|
private Dictionary<FilterSignature, IndexableSet<Entity>> filterSignatureToEntityIDs = new Dictionary<FilterSignature, IndexableSet<Entity>>();
|
||||||
private Dictionary<int, HashSet<FilterSignature>> typeToFilterSignatures = new Dictionary<int, HashSet<FilterSignature>>();
|
private Dictionary<int, HashSet<FilterSignature>> typeToFilterSignatures = new Dictionary<int, HashSet<FilterSignature>>();
|
||||||
|
|
||||||
public FilterStorage(EntityStorage entityStorage, TypeIndices componentTypeIndices)
|
public FilterStorage(EntityStorage entityStorage, TypeIndices componentTypeIndices)
|
||||||
|
@ -21,7 +21,7 @@ namespace MoonTools.ECS
|
||||||
var filterSignature = new FilterSignature(included, excluded);
|
var filterSignature = new FilterSignature(included, excluded);
|
||||||
if (!filterSignatureToEntityIDs.ContainsKey(filterSignature))
|
if (!filterSignatureToEntityIDs.ContainsKey(filterSignature))
|
||||||
{
|
{
|
||||||
filterSignatureToEntityIDs.Add(filterSignature, new IndexableSet<int>());
|
filterSignatureToEntityIDs.Add(filterSignature, new IndexableSet<Entity>());
|
||||||
|
|
||||||
foreach (var type in included)
|
foreach (var type in included)
|
||||||
{
|
{
|
||||||
|
@ -46,20 +46,14 @@ namespace MoonTools.ECS
|
||||||
return new Filter(this, included, excluded);
|
return new Filter(this, included, excluded);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Entity> FilterEntities(FilterSignature filterSignature)
|
public ReverseSpanEnumerator<Entity> FilterEntities(FilterSignature filterSignature)
|
||||||
{
|
{
|
||||||
foreach (var id in filterSignatureToEntityIDs[filterSignature])
|
return filterSignatureToEntityIDs[filterSignature].GetEnumerator();
|
||||||
{
|
|
||||||
yield return new Entity(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Entity> FilterEntitiesRandom(FilterSignature filterSignature)
|
public LinearCongruentialEnumerator FilterEntitiesRandom(FilterSignature filterSignature)
|
||||||
{
|
{
|
||||||
foreach (var index in RandomGenerator.LinearCongruentialGenerator(FilterCount(filterSignature)))
|
return RandomGenerator.LinearCongruentialGenerator(FilterCount(filterSignature));
|
||||||
{
|
|
||||||
yield return new Entity(filterSignatureToEntityIDs[filterSignature][index]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Entity FilterNthEntity(FilterSignature filterSignature, int index)
|
public Entity FilterNthEntity(FilterSignature filterSignature, int index)
|
||||||
|
@ -80,9 +74,9 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
public void Check(int entityID, int componentTypeIndex)
|
public void Check(int entityID, int componentTypeIndex)
|
||||||
{
|
{
|
||||||
if (typeToFilterSignatures.ContainsKey(componentTypeIndex))
|
if (typeToFilterSignatures.TryGetValue(componentTypeIndex, out var filterSignatures))
|
||||||
{
|
{
|
||||||
foreach (var filterSignature in typeToFilterSignatures[componentTypeIndex])
|
foreach (var filterSignature in filterSignatures)
|
||||||
{
|
{
|
||||||
CheckFilter(entityID, filterSignature);
|
CheckFilter(entityID, filterSignature);
|
||||||
}
|
}
|
||||||
|
@ -140,9 +134,9 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
public void RemoveEntity(int entityID, int componentTypeIndex)
|
public void RemoveEntity(int entityID, int componentTypeIndex)
|
||||||
{
|
{
|
||||||
if (typeToFilterSignatures.ContainsKey(componentTypeIndex))
|
if (typeToFilterSignatures.TryGetValue(componentTypeIndex, out var filterSignatures))
|
||||||
{
|
{
|
||||||
foreach (var filterSignature in typeToFilterSignatures[componentTypeIndex])
|
foreach (var filterSignature in filterSignatures)
|
||||||
{
|
{
|
||||||
filterSignatureToEntityIDs[filterSignature].Remove(entityID);
|
filterSignatureToEntityIDs[filterSignature].Remove(entityID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace MoonTools.ECS
|
||||||
private Dictionary<T, int> indices;
|
private Dictionary<T, int> indices;
|
||||||
private T[] array;
|
private T[] array;
|
||||||
public int Count { get; private set; }
|
public int Count { get; private set; }
|
||||||
public Enumerator GetEnumerator() => new Enumerator(this);
|
public ReverseSpanEnumerator<T> GetEnumerator() => new ReverseSpanEnumerator<T>(new Span<T>(array, 0, Count));
|
||||||
|
|
||||||
public IndexableSet(int size = 32)
|
public IndexableSet(int size = 32)
|
||||||
{
|
{
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace MoonTools.ECS
|
||||||
return Lookup<TMessage>().First();
|
return Lookup<TMessage>().First();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<TMessage> WithEntity<TMessage>(int entityID) where TMessage : unmanaged
|
public ReverseSpanEnumerator<TMessage> WithEntity<TMessage>(int entityID) where TMessage : unmanaged
|
||||||
{
|
{
|
||||||
return Lookup<TMessage>().WithEntity(entityID);
|
return Lookup<TMessage>().WithEntity(entityID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,8 @@ namespace MoonTools.ECS
|
||||||
private int count = 0;
|
private int count = 0;
|
||||||
private int capacity = 128;
|
private int capacity = 128;
|
||||||
private TMessage[] messages;
|
private TMessage[] messages;
|
||||||
private Dictionary<int, List<int>> entityToIndices = new Dictionary<int, List<int>>();
|
// duplicating storage here for fast iteration
|
||||||
|
private Dictionary<int, DynamicArray<TMessage>> entityToMessages = new Dictionary<int, DynamicArray<TMessage>>();
|
||||||
|
|
||||||
public MessageStorage()
|
public MessageStorage()
|
||||||
{
|
{
|
||||||
|
@ -34,11 +35,11 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
public void Add(int entityID, in TMessage message)
|
public void Add(int entityID, in TMessage message)
|
||||||
{
|
{
|
||||||
if (!entityToIndices.ContainsKey(entityID))
|
if (!entityToMessages.ContainsKey(entityID))
|
||||||
{
|
{
|
||||||
entityToIndices.Add(entityID, new List<int>());
|
entityToMessages.Add(entityID, new DynamicArray<TMessage>());
|
||||||
}
|
}
|
||||||
entityToIndices[entityID].Add(count);
|
entityToMessages[entityID].Add(message);
|
||||||
|
|
||||||
Add(message);
|
Add(message);
|
||||||
}
|
}
|
||||||
|
@ -58,31 +59,32 @@ namespace MoonTools.ECS
|
||||||
return messages[0];
|
return messages[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<TMessage> WithEntity(int entityID)
|
public ReverseSpanEnumerator<TMessage> WithEntity(int entityID)
|
||||||
{
|
{
|
||||||
if (entityToIndices.ContainsKey(entityID))
|
if (entityToMessages.TryGetValue(entityID, out var messages))
|
||||||
{
|
{
|
||||||
foreach (var index in entityToIndices[entityID])
|
return messages.GetEnumerator();
|
||||||
{
|
}
|
||||||
yield return messages[index];
|
else
|
||||||
}
|
{
|
||||||
|
return ReverseSpanEnumerator<TMessage>.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref readonly TMessage FirstWithEntity(int entityID)
|
public ref readonly TMessage FirstWithEntity(int entityID)
|
||||||
{
|
{
|
||||||
return ref messages[entityToIndices[entityID][0]];
|
return ref entityToMessages[entityID][0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SomeWithEntity(int entityID)
|
public bool SomeWithEntity(int entityID)
|
||||||
{
|
{
|
||||||
return entityToIndices.ContainsKey(entityID) && entityToIndices[entityID].Count > 0;
|
return entityToMessages.ContainsKey(entityID) && entityToMessages[entityID].Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Clear()
|
public override void Clear()
|
||||||
{
|
{
|
||||||
count = 0;
|
count = 0;
|
||||||
foreach (var set in entityToIndices.Values)
|
foreach (var set in entityToMessages.Values)
|
||||||
{
|
{
|
||||||
set.Clear();
|
set.Clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
|
@ -20,7 +20,7 @@ namespace MoonTools.ECS
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A psuedorandom nonrepeating sequence of integers from 0 to n.
|
/// A psuedorandom nonrepeating sequence of integers from 0 to n.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IEnumerable<int> LinearCongruentialGenerator(int n)
|
public static LinearCongruentialEnumerator LinearCongruentialGenerator(int n)
|
||||||
{
|
{
|
||||||
var x = Primes[random.Next(Primes.Length - 1)];
|
var x = Primes[random.Next(Primes.Length - 1)];
|
||||||
while (x % n == 0)
|
while (x % n == 0)
|
||||||
|
@ -29,12 +29,44 @@ namespace MoonTools.ECS
|
||||||
x = Primes[random.Next(Primes.Length - 1)];
|
x = Primes[random.Next(Primes.Length - 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
var start = random.Next(n);
|
return new LinearCongruentialEnumerator(random.Next(n), x, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = start; i < start + n; i++)
|
public struct LinearCongruentialEnumerator
|
||||||
|
{
|
||||||
|
private readonly int start;
|
||||||
|
private readonly int count;
|
||||||
|
private readonly int prime;
|
||||||
|
private int current;
|
||||||
|
|
||||||
|
public LinearCongruentialEnumerator GetEnumerator() => this;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal LinearCongruentialEnumerator(int start, int prime, int count)
|
||||||
|
{
|
||||||
|
current = start;
|
||||||
|
this.start = start;
|
||||||
|
this.prime = prime;
|
||||||
|
this.count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
current += 1;
|
||||||
|
if (current < start + count)
|
||||||
{
|
{
|
||||||
yield return (i * x) % n;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Current
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => (current * prime) % count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,12 +13,6 @@ namespace MoonTools.ECS
|
||||||
B = entityB;
|
B = entityB;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Relation(int idA, int idB)
|
|
||||||
{
|
|
||||||
A = new Entity(idA);
|
|
||||||
B = new Entity(idB);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
{
|
{
|
||||||
return obj is Relation relation && Equals(relation);
|
return obj is Relation relation && Equals(relation);
|
||||||
|
|
|
@ -41,6 +41,11 @@ namespace MoonTools.ECS
|
||||||
Lookup<TRelationKind>().Set(relation, relationData);
|
Lookup<TRelationKind>().Set(relation, relationData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TRelationKind Get<TRelationKind>(Relation relation) where TRelationKind : unmanaged
|
||||||
|
{
|
||||||
|
return Lookup<TRelationKind>().Get(relation);
|
||||||
|
}
|
||||||
|
|
||||||
public (bool, bool) Remove<TRelationKind>(Relation relation) where TRelationKind : unmanaged
|
public (bool, bool) Remove<TRelationKind>(Relation relation) where TRelationKind : unmanaged
|
||||||
{
|
{
|
||||||
return Lookup<TRelationKind>().Remove(relation);
|
return Lookup<TRelationKind>().Remove(relation);
|
||||||
|
@ -61,12 +66,12 @@ namespace MoonTools.ECS
|
||||||
return Lookup<TRelationKind>().Has(new Relation(idA, idB));
|
return Lookup<TRelationKind>().Has(new Relation(idA, idB));
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<(Entity, TRelationKind)> OutRelations<TRelationKind>(int entityID) where TRelationKind : unmanaged
|
public ReverseSpanEnumerator<Entity> OutRelations<TRelationKind>(int entityID) where TRelationKind : unmanaged
|
||||||
{
|
{
|
||||||
return Lookup<TRelationKind>().OutRelations(entityID);
|
return Lookup<TRelationKind>().OutRelations(entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public (Entity, TRelationKind) OutRelationSingleton<TRelationKind>(int entityID) where TRelationKind : unmanaged
|
public Entity OutRelationSingleton<TRelationKind>(int entityID) where TRelationKind : unmanaged
|
||||||
{
|
{
|
||||||
return Lookup<TRelationKind>().OutFirst(entityID);
|
return Lookup<TRelationKind>().OutFirst(entityID);
|
||||||
}
|
}
|
||||||
|
@ -81,12 +86,12 @@ namespace MoonTools.ECS
|
||||||
return Lookup<TRelationKind>().HasOutRelation(entityID);
|
return Lookup<TRelationKind>().HasOutRelation(entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<(Entity, TRelationKind)> InRelations<TRelationKind>(int entityID) where TRelationKind : unmanaged
|
public ReverseSpanEnumerator<Entity> InRelations<TRelationKind>(int entityID) where TRelationKind : unmanaged
|
||||||
{
|
{
|
||||||
return Lookup<TRelationKind>().InRelations(entityID);
|
return Lookup<TRelationKind>().InRelations(entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public (Entity, TRelationKind) InRelationSingleton<TRelationKind>(int entityID) where TRelationKind : unmanaged
|
public Entity InRelationSingleton<TRelationKind>(int entityID) where TRelationKind : unmanaged
|
||||||
{
|
{
|
||||||
return Lookup<TRelationKind>().InFirst(entityID);
|
return Lookup<TRelationKind>().InFirst(entityID);
|
||||||
}
|
}
|
||||||
|
@ -108,6 +113,11 @@ namespace MoonTools.ECS
|
||||||
storages[relationTypeIndex].Set(entityA, entityB, relationData);
|
storages[relationTypeIndex].Set(entityA, entityB, relationData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetStorageIndex(int relationTypeIndex, int entityA, int entityB)
|
||||||
|
{
|
||||||
|
return storages[relationTypeIndex].GetStorageIndex(entityA, entityB);
|
||||||
|
}
|
||||||
|
|
||||||
public unsafe void* Get(int relationTypeIndex, int relationStorageIndex)
|
public unsafe void* Get(int relationTypeIndex, int relationStorageIndex)
|
||||||
{
|
{
|
||||||
return storages[relationTypeIndex].Get(relationStorageIndex);
|
return storages[relationTypeIndex].Get(relationStorageIndex);
|
||||||
|
@ -118,9 +128,9 @@ namespace MoonTools.ECS
|
||||||
storages[relationTypeIndex].UnrelateAll(entityID);
|
storages[relationTypeIndex].UnrelateAll(entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<(int, int)> OutRelationIndices(int entityID, int relationTypeIndex)
|
public ReverseSpanEnumerator<Entity> OutRelations(int entityID, int relationTypeIndex)
|
||||||
{
|
{
|
||||||
return storages[relationTypeIndex].OutRelationIndices(entityID);
|
return storages[relationTypeIndex].OutRelations(entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
|
|
|
@ -6,9 +6,10 @@ namespace MoonTools.ECS
|
||||||
internal abstract class RelationStorage
|
internal abstract class RelationStorage
|
||||||
{
|
{
|
||||||
public abstract unsafe void Set(int entityA, int entityB, void* relationData);
|
public abstract unsafe void Set(int entityA, int entityB, void* relationData);
|
||||||
|
public abstract int GetStorageIndex(int entityA, int entityB);
|
||||||
public abstract unsafe void* Get(int relationStorageIndex);
|
public abstract unsafe void* Get(int relationStorageIndex);
|
||||||
public abstract void UnrelateAll(int entityID);
|
public abstract void UnrelateAll(int entityID);
|
||||||
public abstract IEnumerable<(int, int)> OutRelationIndices(int entityID);
|
public abstract ReverseSpanEnumerator<Entity> OutRelations(int entityID);
|
||||||
public abstract RelationStorage CreateStorage();
|
public abstract RelationStorage CreateStorage();
|
||||||
public abstract void Clear();
|
public abstract void Clear();
|
||||||
}
|
}
|
||||||
|
@ -21,9 +22,9 @@ namespace MoonTools.ECS
|
||||||
private Dictionary<Relation, int> indices = new Dictionary<Relation, int>(16);
|
private Dictionary<Relation, int> indices = new Dictionary<Relation, int>(16);
|
||||||
private Relation[] relations = new Relation[16];
|
private Relation[] relations = new Relation[16];
|
||||||
private TRelation[] relationDatas = new TRelation[16];
|
private TRelation[] relationDatas = new TRelation[16];
|
||||||
private Dictionary<int, IndexableSet<int>> outRelations = new Dictionary<int, IndexableSet<int>>(16);
|
private Dictionary<int, IndexableSet<Entity>> outRelations = new Dictionary<int, IndexableSet<Entity>>(16);
|
||||||
private Dictionary<int, IndexableSet<int>> inRelations = new Dictionary<int, IndexableSet<int>>(16);
|
private Dictionary<int, IndexableSet<Entity>> inRelations = new Dictionary<int, IndexableSet<Entity>>(16);
|
||||||
private Stack<IndexableSet<int>> listPool = new Stack<IndexableSet<int>>();
|
private Stack<IndexableSet<Entity>> listPool = new Stack<IndexableSet<Entity>>();
|
||||||
|
|
||||||
public IEnumerable<(Entity, Entity, TRelation)> All()
|
public IEnumerable<(Entity, Entity, TRelation)> All()
|
||||||
{
|
{
|
||||||
|
@ -36,9 +37,8 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
public void Set(Relation relation, TRelation relationData)
|
public void Set(Relation relation, TRelation relationData)
|
||||||
{
|
{
|
||||||
if (indices.ContainsKey(relation))
|
if (indices.TryGetValue(relation, out var index))
|
||||||
{
|
{
|
||||||
var index = indices[relation];
|
|
||||||
relationDatas[index] = relationData;
|
relationDatas[index] = relationData;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -70,34 +70,37 @@ namespace MoonTools.ECS
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TRelation Get(Relation relation)
|
||||||
|
{
|
||||||
|
return relationDatas[indices[relation]];
|
||||||
|
}
|
||||||
|
|
||||||
public bool Has(Relation relation)
|
public bool Has(Relation relation)
|
||||||
{
|
{
|
||||||
return indices.ContainsKey(relation);
|
return indices.ContainsKey(relation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: creating the new Relation in here is slightly deranged
|
public override ReverseSpanEnumerator<Entity> OutRelations(int entityID)
|
||||||
public IEnumerable<(Entity, TRelation)> OutRelations(int entityID)
|
|
||||||
{
|
{
|
||||||
if (outRelations.ContainsKey(entityID))
|
if (outRelations.TryGetValue(entityID, out var entityOutRelations))
|
||||||
{
|
{
|
||||||
foreach (var id in outRelations[entityID])
|
return entityOutRelations.GetEnumerator();
|
||||||
{
|
}
|
||||||
var relation = new Relation(entityID, id);
|
else
|
||||||
yield return (relation.B, relationDatas[indices[relation]]);
|
{
|
||||||
}
|
return ReverseSpanEnumerator<Entity>.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public (Entity, TRelation) OutFirst(int entityID)
|
public Entity OutFirst(int entityID)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (!outRelations.ContainsKey(entityID))
|
if (!outRelations.ContainsKey(entityID) || outRelations[entityID].Count == 0)
|
||||||
{
|
{
|
||||||
throw new KeyNotFoundException("No out relations to this entity!");
|
throw new KeyNotFoundException("No out relations to this entity!");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
var relation = new Relation(entityID, outRelations[entityID][0]);
|
return outRelations[entityID][0];
|
||||||
return (relation.B, relationDatas[indices[relation]]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasOutRelation(int entityID)
|
public bool HasOutRelation(int entityID)
|
||||||
|
@ -107,32 +110,31 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
public int OutRelationCount(int entityID)
|
public int OutRelationCount(int entityID)
|
||||||
{
|
{
|
||||||
return outRelations.ContainsKey(entityID) ? outRelations[entityID].Count : 0;
|
return outRelations.TryGetValue(entityID, out var entityOutRelations) ? entityOutRelations.Count : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<(Entity, TRelation)> InRelations(int entityID)
|
public ReverseSpanEnumerator<Entity> InRelations(int entityID)
|
||||||
{
|
{
|
||||||
if (inRelations.ContainsKey(entityID))
|
if (inRelations.TryGetValue(entityID, out var entityInRelations))
|
||||||
{
|
{
|
||||||
foreach (var id in inRelations[entityID])
|
return entityInRelations.GetEnumerator();
|
||||||
{
|
}
|
||||||
var relation = new Relation(id, entityID);
|
else
|
||||||
yield return (relation.A, relationDatas[indices[relation]]);
|
{
|
||||||
}
|
return ReverseSpanEnumerator<Entity>.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public (Entity, TRelation) InFirst(int entityID)
|
public Entity InFirst(int entityID)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (!inRelations.ContainsKey(entityID))
|
if (!inRelations.ContainsKey(entityID) || inRelations[entityID].Count == 0)
|
||||||
{
|
{
|
||||||
throw new KeyNotFoundException("No out relations to this entity!");
|
throw new KeyNotFoundException("No out relations to this entity!");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var relation = new Relation(inRelations[entityID][0], entityID);
|
return inRelations[entityID][0];
|
||||||
return (relation.A, relationDatas[indices[relation]]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasInRelation(int entityID)
|
public bool HasInRelation(int entityID)
|
||||||
|
@ -142,7 +144,7 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
public int InRelationCount(int entityID)
|
public int InRelationCount(int entityID)
|
||||||
{
|
{
|
||||||
return inRelations.ContainsKey(entityID) ? inRelations[entityID].Count : 0;
|
return inRelations.TryGetValue(entityID, out var entityInRelations) ? entityInRelations.Count : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public (bool, bool) Remove(Relation relation)
|
public (bool, bool) Remove(Relation relation)
|
||||||
|
@ -150,27 +152,26 @@ namespace MoonTools.ECS
|
||||||
var aEmpty = false;
|
var aEmpty = false;
|
||||||
var bEmpty = false;
|
var bEmpty = false;
|
||||||
|
|
||||||
if (outRelations.ContainsKey(relation.A.ID))
|
if (outRelations.TryGetValue(relation.A.ID, out var entityOutRelations))
|
||||||
{
|
{
|
||||||
outRelations[relation.A.ID].Remove(relation.B.ID);
|
entityOutRelations.Remove(relation.B.ID);
|
||||||
if (outRelations[relation.A.ID].Count == 0)
|
if (outRelations[relation.A.ID].Count == 0)
|
||||||
{
|
{
|
||||||
aEmpty = true;
|
aEmpty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inRelations.ContainsKey(relation.B.ID))
|
if (inRelations.TryGetValue(relation.B.ID, out var entityInRelations))
|
||||||
{
|
{
|
||||||
inRelations[relation.B.ID].Remove(relation.A.ID);
|
entityInRelations.Remove(relation.A.ID);
|
||||||
if (inRelations[relation.B.ID].Count == 0)
|
if (inRelations[relation.B.ID].Count == 0)
|
||||||
{
|
{
|
||||||
bEmpty = true;
|
bEmpty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (indices.ContainsKey(relation))
|
if (indices.TryGetValue(relation, out var index))
|
||||||
{
|
{
|
||||||
var index = indices[relation];
|
|
||||||
var lastElementIndex = count - 1;
|
var lastElementIndex = count - 1;
|
||||||
|
|
||||||
// move an element into the hole
|
// move an element into the hole
|
||||||
|
@ -189,17 +190,17 @@ namespace MoonTools.ECS
|
||||||
return (aEmpty, bEmpty);
|
return (aEmpty, bEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IndexableSet<int> AcquireHashSetFromPool()
|
private IndexableSet<Entity> AcquireHashSetFromPool()
|
||||||
{
|
{
|
||||||
if (listPool.Count == 0)
|
if (listPool.Count == 0)
|
||||||
{
|
{
|
||||||
listPool.Push(new IndexableSet<int>());
|
listPool.Push(new IndexableSet<Entity>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return listPool.Pop();
|
return listPool.Pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReturnHashSetToPool(IndexableSet<int> hashSet)
|
private void ReturnHashSetToPool(IndexableSet<Entity> hashSet)
|
||||||
{
|
{
|
||||||
hashSet.Clear();
|
hashSet.Clear();
|
||||||
listPool.Push(hashSet);
|
listPool.Push(hashSet);
|
||||||
|
@ -212,6 +213,11 @@ namespace MoonTools.ECS
|
||||||
Set(new Relation(entityA, entityB), *((TRelation*) relationData));
|
Set(new Relation(entityA, entityB), *((TRelation*) relationData));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override int GetStorageIndex(int entityA, int entityB)
|
||||||
|
{
|
||||||
|
return indices[new Relation(entityA, entityB)];
|
||||||
|
}
|
||||||
|
|
||||||
public override unsafe void* Get(int relationStorageIndex)
|
public override unsafe void* Get(int relationStorageIndex)
|
||||||
{
|
{
|
||||||
fixed (void* p = &relations[relationStorageIndex])
|
fixed (void* p = &relations[relationStorageIndex])
|
||||||
|
@ -222,41 +228,29 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
public override void UnrelateAll(int entityID)
|
public override void UnrelateAll(int entityID)
|
||||||
{
|
{
|
||||||
if (outRelations.ContainsKey(entityID))
|
if (outRelations.TryGetValue(entityID, out var entityOutRelations))
|
||||||
{
|
{
|
||||||
foreach (var entityB in outRelations[entityID])
|
foreach (var entityB in entityOutRelations)
|
||||||
{
|
{
|
||||||
Remove(new Relation(entityID, entityB));
|
Remove(new Relation(entityID, entityB));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnHashSetToPool(outRelations[entityID]);
|
ReturnHashSetToPool(entityOutRelations);
|
||||||
outRelations.Remove(entityID);
|
outRelations.Remove(entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inRelations.ContainsKey(entityID))
|
if (inRelations.TryGetValue(entityID, out var entityInRelations))
|
||||||
{
|
{
|
||||||
foreach (var entityA in inRelations[entityID])
|
foreach (var entityA in entityInRelations)
|
||||||
{
|
{
|
||||||
Remove(new Relation(entityA, entityID));
|
Remove(new Relation(entityA, entityID));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnHashSetToPool(inRelations[entityID]);
|
ReturnHashSetToPool(entityInRelations);
|
||||||
inRelations.Remove(entityID);
|
inRelations.Remove(entityID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<(int, int)> OutRelationIndices(int entityID)
|
|
||||||
{
|
|
||||||
if (outRelations.ContainsKey(entityID))
|
|
||||||
{
|
|
||||||
foreach (var id in outRelations[entityID])
|
|
||||||
{
|
|
||||||
var relation = new Relation(entityID, id);
|
|
||||||
yield return (id, indices[relation]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override RelationStorage<TRelation> CreateStorage()
|
public override RelationStorage<TRelation> CreateStorage()
|
||||||
{
|
{
|
||||||
return new RelationStorage<TRelation>();
|
return new RelationStorage<TRelation>();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS
|
||||||
|
@ -50,7 +50,7 @@ namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
SnapshotEntityStorage.AddRelationKind(snapshotEntityID, relationTypeIndex);
|
SnapshotEntityStorage.AddRelationKind(snapshotEntityID, relationTypeIndex);
|
||||||
|
|
||||||
foreach (var (otherEntityID, relationStorageIndex) in World.RelationDepot.OutRelationIndices(worldEntity.ID, relationTypeIndex))
|
foreach (var otherEntityID in World.RelationDepot.OutRelations(worldEntity.ID, relationTypeIndex))
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (!World.FilterStorage.CheckSatisfied(otherEntityID, Filter.Signature))
|
if (!World.FilterStorage.CheckSatisfied(otherEntityID, Filter.Signature))
|
||||||
|
@ -58,6 +58,7 @@ namespace MoonTools.ECS
|
||||||
throw new InvalidOperationException($"Snapshot entity {worldEntity.ID} is related to non-snapshot entity {otherEntityID}!");
|
throw new InvalidOperationException($"Snapshot entity {worldEntity.ID} is related to non-snapshot entity {otherEntityID}!");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
var relationStorageIndex = World.RelationDepot.GetStorageIndex(relationTypeIndex, worldEntity, otherEntityID);
|
||||||
var otherSnapshotID = WorldToSnapshotID[otherEntityID];
|
var otherSnapshotID = WorldToSnapshotID[otherEntityID];
|
||||||
SnapshotEntityStorage.AddRelationKind(otherSnapshotID, relationTypeIndex);
|
SnapshotEntityStorage.AddRelationKind(otherSnapshotID, relationTypeIndex);
|
||||||
SnapshotRelationDepot.Set(snapshotEntityID, otherSnapshotID, relationTypeIndex, World.RelationDepot.Get(relationTypeIndex, relationStorageIndex));
|
SnapshotRelationDepot.Set(snapshotEntityID, otherSnapshotID, relationTypeIndex, World.RelationDepot.Get(relationTypeIndex, relationStorageIndex));
|
||||||
|
@ -99,8 +100,9 @@ namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
World.EntityStorage.AddRelationKind(worldID, relationTypeIndex);
|
World.EntityStorage.AddRelationKind(worldID, relationTypeIndex);
|
||||||
|
|
||||||
foreach (var (otherEntityID, relationStorageIndex) in SnapshotRelationDepot.OutRelationIndices(i, relationTypeIndex))
|
foreach (var otherEntityID in SnapshotRelationDepot.OutRelations(i, relationTypeIndex))
|
||||||
{
|
{
|
||||||
|
var relationStorageIndex = SnapshotRelationDepot.GetStorageIndex(relationTypeIndex, i, otherEntityID);
|
||||||
var otherEntityWorldID = SnapshotToWorldID[otherEntityID];
|
var otherEntityWorldID = SnapshotToWorldID[otherEntityID];
|
||||||
World.RelationDepot.Set(worldID, otherEntityWorldID, relationTypeIndex, SnapshotRelationDepot.Get(relationTypeIndex, relationStorageIndex));
|
World.RelationDepot.Set(worldID, otherEntityWorldID, relationTypeIndex, SnapshotRelationDepot.Get(relationTypeIndex, relationStorageIndex));
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace MoonTools.ECS
|
||||||
return MessageDepot.Some<TMessage>();
|
return MessageDepot.Some<TMessage>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IEnumerable<TMessage> ReadMessagesWithEntity<TMessage>(in Entity entity) where TMessage : unmanaged
|
protected ReverseSpanEnumerator<TMessage> ReadMessagesWithEntity<TMessage>(in Entity entity) where TMessage : unmanaged
|
||||||
{
|
{
|
||||||
return MessageDepot.WithEntity<TMessage>(entity.ID);
|
return MessageDepot.WithEntity<TMessage>(entity.ID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS
|
||||||
|
@ -27,7 +27,7 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
public IEnumerable<Type> Types => TypeToIndex.Keys;
|
public Dictionary<Type, int>.KeyCollection Types => TypeToIndex.Keys;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue