diff --git a/src/RelationDepot.cs b/src/RelationDepot.cs index c22493b..7963a6c 100644 --- a/src/RelationDepot.cs +++ b/src/RelationDepot.cs @@ -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 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 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)}"); + } + } + } + } + } + } } } diff --git a/src/RelationStorage.cs b/src/RelationStorage.cs index 166f3c7..50b4e43 100644 --- a/src/RelationStorage.cs +++ b/src/RelationStorage.cs @@ -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 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())); } - 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 OutRelations(int entityID) + public ReverseSpanEnumerator OutRelations(int entityID) { if (outRelations.TryGetValue(entityID, out var entityOutRelations)) { diff --git a/src/World.cs b/src/World.cs index e0400e0..a26f243 100644 --- a/src/World.cs +++ b/src/World.cs @@ -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(in Entity entityA, in Entity entityB) where TRelationKind : unmanaged { var (aEmpty, bEmpty) = RelationDepot.Remove(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); } }