rename and add new relation lookup methods

filter_relations
cosmonaut 2022-08-09 14:41:31 -07:00
parent 5d3989a620
commit 453426a232
7 changed files with 187 additions and 49 deletions

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace MoonTools.ECS
{
@ -17,6 +18,7 @@ namespace MoonTools.ECS
private HashSet<Type> TypesWithDisabledSerialization = new HashSet<Type>();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void Register<TComponent>() where TComponent : unmanaged
{
if (!storages.ContainsKey(typeof(TComponent)))
@ -33,6 +35,7 @@ namespace MoonTools.ECS
return storages[type];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ComponentStorage<TComponent> Lookup<TComponent>() where TComponent : unmanaged
{
// TODO: is it possible to optimize this?

View File

@ -46,7 +46,7 @@ namespace MoonTools.ECS
#if DEBUG
if (nextID == 0)
{
throw new ArgumentOutOfRangeException("Component storage is empty!");
throw new IndexOutOfRangeException("Component storage is empty!");
}
#endif
return ref components[0];
@ -119,6 +119,12 @@ namespace MoonTools.ECS
public Entity FirstEntity()
{
#if DEBUG
if (nextID == 0)
{
throw new IndexOutOfRangeException("Component storage is empty!");
}
#endif
return new Entity(entityIDs[0]);
}

View File

@ -61,14 +61,46 @@ namespace MoonTools.ECS
return RelationDepot.Related<TRelationKind>(a.ID, b.ID);
}
protected IEnumerable<(Entity, TRelationKind)> RelatedToA<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
// relations go A->B, so given A, will give all outgoing B relations.
protected IEnumerable<(Entity, TRelationKind)> OutRelations<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
{
return RelationDepot.RelatedToA<TRelationKind>(entity.ID);
return RelationDepot.OutRelations<TRelationKind>(entity.ID);
}
protected IEnumerable<(Entity, TRelationKind)> RelatedToB<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
protected (Entity, TRelationKind) OutRelationSingleton<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
{
return RelationDepot.RelatedToB<TRelationKind>(entity.ID);
return RelationDepot.OutRelationSingleton<TRelationKind>(entity.ID);
}
protected bool HasOutRelation<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
{
return RelationDepot.HasOutRelation<TRelationKind>(entity.ID);
}
protected int OutRelationCount<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
{
return RelationDepot.OutRelationCount<TRelationKind>(entity.ID);
}
// Relations go A->B, so given B, will give all incoming A relations.
protected IEnumerable<(Entity, TRelationKind)> InRelations<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
{
return RelationDepot.InRelations<TRelationKind>(entity.ID);
}
protected (Entity, TRelationKind) InRelationSingleton<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
{
return RelationDepot.InRelationSingleton<TRelationKind>(entity.ID);
}
protected bool HasInRelation<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
{
return RelationDepot.HasInRelation<TRelationKind>(entity.ID);
}
protected int InRelationCount<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
{
return RelationDepot.InRelationCount<TRelationKind>(entity.ID);
}
}
}

View File

@ -80,6 +80,11 @@ namespace MoonTools.ECS
}
}
public void Clear()
{
Count = 0;
}
public void Save(IndexableSetState<T> state)
{
ReadOnlySpan<byte> arrayBytes = MemoryMarshal.Cast<T, byte>(array);

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace MoonTools.ECS
{
@ -15,6 +16,7 @@ namespace MoonTools.ECS
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private RelationStorage<TRelationKind> Lookup<TRelationKind>() where TRelationKind : unmanaged
{
Register<TRelationKind>();
@ -31,6 +33,11 @@ namespace MoonTools.ECS
Lookup<TRelationKind>().Remove(relation);
}
public void UnrelateAll<TRelationKind>(int entityID) where TRelationKind : unmanaged
{
Lookup<TRelationKind>().UnrelateAll(entityID);
}
// FIXME: optimize this
public void OnEntityDestroy(int entityID)
{
@ -50,14 +57,44 @@ namespace MoonTools.ECS
return Lookup<TRelationKind>().Has(new Relation(idA, idB));
}
public IEnumerable<(Entity, TRelationKind)> RelatedToA<TRelationKind>(int entityID) where TRelationKind : unmanaged
public IEnumerable<(Entity, TRelationKind)> OutRelations<TRelationKind>(int entityID) where TRelationKind : unmanaged
{
return Lookup<TRelationKind>().RelatedToA(entityID);
return Lookup<TRelationKind>().OutRelations(entityID);
}
public IEnumerable<(Entity, TRelationKind)> RelatedToB<TRelationKind>(int entityID) where TRelationKind : unmanaged
public (Entity, TRelationKind) OutRelationSingleton<TRelationKind>(int entityID) where TRelationKind : unmanaged
{
return Lookup<TRelationKind>().RelatedToB(entityID);
return Lookup<TRelationKind>().OutFirst(entityID);
}
public int OutRelationCount<TRelationKind>(int entityID) where TRelationKind : unmanaged
{
return Lookup<TRelationKind>().OutRelationCount(entityID);
}
public bool HasOutRelation<TRelationKind>(int entityID) where TRelationKind : unmanaged
{
return Lookup<TRelationKind>().HasOutRelation(entityID);
}
public IEnumerable<(Entity, TRelationKind)> InRelations<TRelationKind>(int entityID) where TRelationKind : unmanaged
{
return Lookup<TRelationKind>().InRelations(entityID);
}
public (Entity, TRelationKind) InRelationSingleton<TRelationKind>(int entityID) where TRelationKind : unmanaged
{
return Lookup<TRelationKind>().InFirst(entityID);
}
public bool HasInRelation<TRelationKind>(int entityID) where TRelationKind : unmanaged
{
return Lookup<TRelationKind>().HasInRelation(entityID);
}
public int InRelationCount<TRelationKind>(int entityID) where TRelationKind : unmanaged
{
return Lookup<TRelationKind>().InRelationCount(entityID);
}
public void Save(RelationDepotState state)

View File

@ -20,9 +20,9 @@ namespace MoonTools.ECS
private Dictionary<Relation, int> indices = new Dictionary<Relation, int>(16);
private Relation[] relations = new Relation[16];
private TRelation[] relationDatas = new TRelation[16];
private Dictionary<int, HashSet<int>> entitiesRelatedToA = new Dictionary<int, HashSet<int>>(16);
private Dictionary<int, HashSet<int>> entitiesRelatedToB = new Dictionary<int, HashSet<int>>(16);
private Stack<HashSet<int>> listPool = new Stack<HashSet<int>>();
private Dictionary<int, IndexableSet<int>> outRelations = new Dictionary<int, IndexableSet<int>>(16);
private Dictionary<int, IndexableSet<int>> inRelations = new Dictionary<int, IndexableSet<int>>(16);
private Stack<IndexableSet<int>> listPool = new Stack<IndexableSet<int>>();
public IEnumerable<(Entity, Entity, TRelation)> All()
{
@ -45,17 +45,17 @@ namespace MoonTools.ECS
var idA = relation.A.ID;
var idB = relation.B.ID;
if (!entitiesRelatedToA.ContainsKey(idA))
if (!outRelations.ContainsKey(idA))
{
entitiesRelatedToA[idA] = AcquireHashSetFromPool();
outRelations[idA] = AcquireHashSetFromPool();
}
entitiesRelatedToA[idA].Add(idB);
outRelations[idA].Add(idB);
if (!entitiesRelatedToB.ContainsKey(idB))
if (!inRelations.ContainsKey(idB))
{
entitiesRelatedToB[idB] = AcquireHashSetFromPool();
inRelations[idB] = AcquireHashSetFromPool();
}
entitiesRelatedToB[idB].Add(idA);
inRelations[idB].Add(idA);
if (count >= relationDatas.Length)
{
@ -74,12 +74,12 @@ namespace MoonTools.ECS
return indices.ContainsKey(relation);
}
// FIXME: is there a more descriptive name for these?
public IEnumerable<(Entity, TRelation)> RelatedToA(int entityID)
// FIXME: creating the new Relation in here is slightly deranged
public IEnumerable<(Entity, TRelation)> OutRelations(int entityID)
{
if (entitiesRelatedToA.ContainsKey(entityID))
if (outRelations.ContainsKey(entityID))
{
foreach (var id in entitiesRelatedToA[entityID])
foreach (var id in outRelations[entityID])
{
var relation = new Relation(entityID, id);
yield return (relation.B, relationDatas[indices[relation]]);
@ -87,11 +87,33 @@ namespace MoonTools.ECS
}
}
public IEnumerable<(Entity, TRelation)> RelatedToB(int entityID)
public (Entity, TRelation) OutFirst(int entityID)
{
if (entitiesRelatedToB.ContainsKey(entityID))
#if DEBUG
if (!outRelations.ContainsKey(entityID))
{
foreach (var id in entitiesRelatedToB[entityID])
throw new KeyNotFoundException("No out relations to this entity!");
}
#endif
var relation = new Relation(entityID, outRelations[entityID][0]);
return (relation.B, relationDatas[indices[relation]]);
}
public bool HasOutRelation(int entityID)
{
return outRelations.ContainsKey(entityID) && outRelations[entityID].Count > 0;
}
public int OutRelationCount(int entityID)
{
return outRelations.ContainsKey(entityID) ? outRelations[entityID].Count : 0;
}
public IEnumerable<(Entity, TRelation)> InRelations(int entityID)
{
if (inRelations.ContainsKey(entityID))
{
foreach (var id in inRelations[entityID])
{
var relation = new Relation(id, entityID);
yield return (relation.A, relationDatas[indices[relation]]);
@ -99,16 +121,39 @@ namespace MoonTools.ECS
}
}
public (Entity, TRelation) InFirst(int entityID)
{
#if DEBUG
if (!inRelations.ContainsKey(entityID))
{
throw new KeyNotFoundException("No out relations to this entity!");
}
#endif
var relation = new Relation(inRelations[entityID][0], entityID);
return (relation.A, relationDatas[indices[relation]]);
}
public bool HasInRelation(int entityID)
{
return inRelations.ContainsKey(entityID) && inRelations[entityID].Count > 0;
}
public int InRelationCount(int entityID)
{
return inRelations.ContainsKey(entityID) ? inRelations[entityID].Count : 0;
}
public bool Remove(Relation relation)
{
if (entitiesRelatedToA.ContainsKey(relation.A.ID))
if (outRelations.ContainsKey(relation.A.ID))
{
entitiesRelatedToA[relation.A.ID].Remove(relation.B.ID);
outRelations[relation.A.ID].Remove(relation.B.ID);
}
if (entitiesRelatedToB.ContainsKey(relation.B.ID))
if (inRelations.ContainsKey(relation.B.ID))
{
entitiesRelatedToB[relation.B.ID].Remove(relation.A.ID);
inRelations[relation.B.ID].Remove(relation.A.ID);
}
if (indices.ContainsKey(relation))
@ -133,42 +178,47 @@ namespace MoonTools.ECS
return false;
}
public override void OnEntityDestroy(int entityID)
public void UnrelateAll(int entityID)
{
if (entitiesRelatedToA.ContainsKey(entityID))
if (outRelations.ContainsKey(entityID))
{
foreach (var entityB in entitiesRelatedToA[entityID])
foreach (var entityB in outRelations[entityID])
{
Remove(new Relation(entityID, entityB));
}
ReturnHashSetToPool(entitiesRelatedToA[entityID]);
entitiesRelatedToA.Remove(entityID);
ReturnHashSetToPool(outRelations[entityID]);
outRelations.Remove(entityID);
}
if (entitiesRelatedToB.ContainsKey(entityID))
if (inRelations.ContainsKey(entityID))
{
foreach (var entityA in entitiesRelatedToB[entityID])
foreach (var entityA in inRelations[entityID])
{
Remove(new Relation(entityA, entityID));
}
ReturnHashSetToPool(entitiesRelatedToB[entityID]);
entitiesRelatedToB.Remove(entityID);
ReturnHashSetToPool(inRelations[entityID]);
inRelations.Remove(entityID);
}
}
private HashSet<int> AcquireHashSetFromPool()
public override void OnEntityDestroy(int entityID)
{
UnrelateAll(entityID);
}
private IndexableSet<int> AcquireHashSetFromPool()
{
if (listPool.Count == 0)
{
listPool.Push(new HashSet<int>());
listPool.Push(new IndexableSet<int>());
}
return listPool.Pop();
}
private void ReturnHashSetToPool(HashSet<int> hashSet)
private void ReturnHashSetToPool(IndexableSet<int> hashSet)
{
hashSet.Clear();
listPool.Push(hashSet);
@ -206,24 +256,24 @@ namespace MoonTools.ECS
state.RelationDatas.CopyTo(MemoryMarshal.Cast<TRelation, byte>(relationDatas));
indices.Clear();
entitiesRelatedToA.Clear();
entitiesRelatedToB.Clear();
outRelations.Clear();
inRelations.Clear();
for (var i = 0; i < state.Count; i += 1)
{
var relation = relations[i];
indices[relation] = i;
if (!entitiesRelatedToA.ContainsKey(relation.A.ID))
if (!outRelations.ContainsKey(relation.A.ID))
{
entitiesRelatedToA[relation.A.ID] = AcquireHashSetFromPool();
outRelations[relation.A.ID] = AcquireHashSetFromPool();
}
entitiesRelatedToA[relation.A.ID].Add(relation.B.ID);
outRelations[relation.A.ID].Add(relation.B.ID);
if (!entitiesRelatedToB.ContainsKey(relation.B.ID))
if (!inRelations.ContainsKey(relation.B.ID))
{
entitiesRelatedToB[relation.B.ID] = AcquireHashSetFromPool();
inRelations[relation.B.ID] = AcquireHashSetFromPool();
}
entitiesRelatedToB[relation.B.ID].Add(relation.A.ID);
inRelations[relation.B.ID].Add(relation.A.ID);
}
count = state.Count;

View File

@ -78,6 +78,11 @@ namespace MoonTools.ECS
RelationDepot.Remove<TRelationKind>(new Relation(entityA, entityB));
}
protected void UnrelateAll<TRelationKind>(in Entity entity) where TRelationKind : unmanaged
{
RelationDepot.UnrelateAll<TRelationKind>(entity.ID);
}
// FIXME: this is insanely inefficient
protected void Destroy(in Entity entity)
{