transfer relations in order

pull/5/head
cosmonaut 2023-10-12 12:27:13 -07:00
parent 3cba3e047c
commit 2aa8fc87e7
3 changed files with 38 additions and 53 deletions

View File

@ -6,11 +6,13 @@ namespace MoonTools.ECS
{ {
internal class RelationDepot internal class RelationDepot
{ {
private EntityStorage EntityStorage;
private TypeIndices RelationTypeIndices; private TypeIndices RelationTypeIndices;
private RelationStorage[] storages = new RelationStorage[256]; private RelationStorage[] storages = new RelationStorage[256];
public RelationDepot(TypeIndices relationTypeIndices) public RelationDepot(EntityStorage entityStorage, TypeIndices relationTypeIndices)
{ {
EntityStorage = entityStorage;
RelationTypeIndices = relationTypeIndices; RelationTypeIndices = relationTypeIndices;
} }
@ -123,26 +125,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)
{
return storages[relationTypeIndex].Get(relationStorageIndex);
}
public void UnrelateAll(int entityID, int relationTypeIndex) public void UnrelateAll(int entityID, int relationTypeIndex)
{ {
storages[relationTypeIndex].UnrelateAll(entityID); storages[relationTypeIndex].UnrelateAll(entityID);
} }
public ReverseSpanEnumerator<Entity> OutRelations(int entityID, int relationTypeIndex)
{
return storages[relationTypeIndex].OutRelations(entityID);
}
public void Clear() public void Clear()
{ {
for (var i = 0; i < storages.Length; i += 1) for (var i = 0; i < storages.Length; i += 1)
@ -174,5 +161,33 @@ namespace MoonTools.ECS
} }
} }
} }
public unsafe void TransferStorage(Dictionary<int, int> worldToTransferID, RelationDepot other)
{
for (var i = 0; i < storages.Length; i += 1)
{
if (storages[i] != null)
{
foreach (var (a, b) in storages[i].All())
{
if (worldToTransferID.TryGetValue(a, out var otherA))
{
if (worldToTransferID.TryGetValue(b, out var otherB))
{
var storageIndex = storages[i].GetStorageIndex(a, b);
var relationData = storages[i].Get(storageIndex);
other.Set(otherA, otherB, i, relationData);
other.EntityStorage.AddRelationKind(otherA, i);
other.EntityStorage.AddRelationKind(otherB, i);
}
else
{
throw new InvalidOperationException($"Missing transfer entity! {EntityStorage.Tag(a.ID)} related to {EntityStorage.Tag(b.ID)}");
}
}
}
}
}
}
} }
} }

View File

@ -12,7 +12,7 @@ namespace MoonTools.ECS
public abstract int GetStorageIndex(int entityA, int entityB); 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 ReverseSpanEnumerator<Entity> OutRelations(int entityID); public abstract ReverseSpanEnumerator<(Entity, Entity)> All();
public abstract RelationStorage CreateStorage(); public abstract RelationStorage CreateStorage();
public abstract void Clear(); public abstract void Clear();
} }
@ -38,7 +38,7 @@ namespace MoonTools.ECS
relationDatas = (TRelation*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<TRelation>())); relationDatas = (TRelation*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<TRelation>()));
} }
public ReverseSpanEnumerator<(Entity, Entity)> All() public override ReverseSpanEnumerator<(Entity, Entity)> All()
{ {
return new ReverseSpanEnumerator<(Entity, Entity)>(new Span<(Entity, Entity)>(relations, count)); return new ReverseSpanEnumerator<(Entity, Entity)>(new Span<(Entity, Entity)>(relations, count));
} }
@ -91,7 +91,7 @@ namespace MoonTools.ECS
return indices.ContainsKey(relation); return indices.ContainsKey(relation);
} }
public override ReverseSpanEnumerator<Entity> OutRelations(int entityID) public ReverseSpanEnumerator<Entity> OutRelations(int entityID)
{ {
if (outRelations.TryGetValue(entityID, out var entityOutRelations)) if (outRelations.TryGetValue(entityID, out var entityOutRelations))
{ {

View File

@ -17,7 +17,7 @@ namespace MoonTools.ECS
public World() public World()
{ {
ComponentDepot = new ComponentDepot(ComponentTypeIndices); ComponentDepot = new ComponentDepot(ComponentTypeIndices);
RelationDepot = new RelationDepot(RelationTypeIndices); RelationDepot = new RelationDepot(EntityStorage, RelationTypeIndices);
FilterStorage = new FilterStorage(EntityStorage, ComponentTypeIndices); FilterStorage = new FilterStorage(EntityStorage, ComponentTypeIndices);
} }
@ -79,14 +79,6 @@ namespace MoonTools.ECS
EntityStorage.AddRelationKind(entityB.ID, relationTypeIndex); EntityStorage.AddRelationKind(entityB.ID, relationTypeIndex);
} }
// untyped version for Transfer
internal unsafe void Relate(Entity entityA, Entity entityB, int relationTypeIndex, void* relationData)
{
RelationDepot.Set(entityA, entityB, relationTypeIndex, relationData);
EntityStorage.AddRelationKind(entityA.ID, relationTypeIndex);
EntityStorage.AddRelationKind(entityB.ID, relationTypeIndex);
}
public void Unrelate<TRelationKind>(in Entity entityA, in Entity entityB) where TRelationKind : unmanaged public void Unrelate<TRelationKind>(in Entity entityA, in Entity entityB) where TRelationKind : unmanaged
{ {
var (aEmpty, bEmpty) = RelationDepot.Remove<TRelationKind>(entityA, entityB); var (aEmpty, bEmpty) = RelationDepot.Remove<TRelationKind>(entityA, entityB);
@ -177,31 +169,8 @@ namespace MoonTools.ECS
WorldToTransferID.Add(entity.ID, otherWorldEntity.ID); WorldToTransferID.Add(entity.ID, otherWorldEntity.ID);
} }
// FIXME: make sure this preserves relation order, should probably do something similar to filter storage // transfer relations
// set relations before components so filters don't freak out RelationDepot.TransferStorage(WorldToTransferID, other.RelationDepot);
foreach (var entity in filter.Entities)
{
var otherWorldEntityA = WorldToTransferID[entity.ID];
foreach (var relationTypeIndex in EntityStorage.RelationTypeIndices(entity.ID))
{
foreach (var entityB in RelationDepot.OutRelations(entity.ID, relationTypeIndex))
{
var storageIndex = RelationDepot.GetStorageIndex(relationTypeIndex, entity.ID, entityB);
int otherWorldEntityB;
if (WorldToTransferID.TryGetValue(entityB, out otherWorldEntityB))
{
other.Relate(otherWorldEntityA, otherWorldEntityB, relationTypeIndex, RelationDepot.Get(relationTypeIndex, storageIndex));
}
else
{
// related entity is not in the filter
throw new Exception($"Missing transfer entity! {EntityStorage.Tag(entity.ID)} related to {EntityStorage.Tag(entityB.ID)}");
}
}
}
}
// set components // set components
foreach (var entity in filter.Entities) foreach (var entity in filter.Entities)
@ -214,6 +183,7 @@ namespace MoonTools.ECS
} }
} }
// transfer filters last so callbacks trigger correctly
FilterStorage.TransferStorage(WorldToTransferID, other.FilterStorage); FilterStorage.TransferStorage(WorldToTransferID, other.FilterStorage);
} }
} }