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
{
private EntityStorage EntityStorage;
private TypeIndices RelationTypeIndices;
private RelationStorage[] storages = new RelationStorage[256];
public RelationDepot(TypeIndices relationTypeIndices)
public RelationDepot(EntityStorage entityStorage, TypeIndices relationTypeIndices)
{
EntityStorage = entityStorage;
RelationTypeIndices = relationTypeIndices;
}
@ -123,26 +125,11 @@ namespace MoonTools.ECS
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)
{
storages[relationTypeIndex].UnrelateAll(entityID);
}
public ReverseSpanEnumerator<Entity> OutRelations(int entityID, int relationTypeIndex)
{
return storages[relationTypeIndex].OutRelations(entityID);
}
public void Clear()
{
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 unsafe void* Get(int relationStorageIndex);
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 void Clear();
}
@ -38,7 +38,7 @@ namespace MoonTools.ECS
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));
}
@ -91,7 +91,7 @@ namespace MoonTools.ECS
return indices.ContainsKey(relation);
}
public override ReverseSpanEnumerator<Entity> OutRelations(int entityID)
public ReverseSpanEnumerator<Entity> OutRelations(int entityID)
{
if (outRelations.TryGetValue(entityID, out var entityOutRelations))
{

View File

@ -17,7 +17,7 @@ namespace MoonTools.ECS
public World()
{
ComponentDepot = new ComponentDepot(ComponentTypeIndices);
RelationDepot = new RelationDepot(RelationTypeIndices);
RelationDepot = new RelationDepot(EntityStorage, RelationTypeIndices);
FilterStorage = new FilterStorage(EntityStorage, ComponentTypeIndices);
}
@ -79,14 +79,6 @@ namespace MoonTools.ECS
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
{
var (aEmpty, bEmpty) = RelationDepot.Remove<TRelationKind>(entityA, entityB);
@ -177,31 +169,8 @@ namespace MoonTools.ECS
WorldToTransferID.Add(entity.ID, otherWorldEntity.ID);
}
// FIXME: make sure this preserves relation order, should probably do something similar to filter storage
// set relations before components so filters don't freak out
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)}");
}
}
}
}
// transfer relations
RelationDepot.TransferStorage(WorldToTransferID, other.RelationDepot);
// set components
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);
}
}