fix filter results being out of order on world transfer

pull/5/head
cosmonaut 2023-10-11 15:35:44 -07:00
parent a2a81bf477
commit 3cba3e047c
2 changed files with 64 additions and 5 deletions

View File

@ -20,6 +20,35 @@ namespace MoonTools.ECS
ComponentTypeIndices = componentTypeIndices;
}
private void CopyTypeCache(Dictionary<int, List<FilterSignature>> typeCache)
{
foreach (var type in typeCache.Keys)
{
if (!typeToFilterSignatures.ContainsKey(type))
{
typeToFilterSignatures.Add(type, new List<FilterSignature>());
foreach (var signature in typeCache[type])
{
typeToFilterSignatures[type].Add(signature);
}
}
}
}
public void CreateMissingStorages(FilterStorage other)
{
foreach (var filterSignature in other.filterSignatureToEntityIDs.Keys)
{
if (!filterSignatureToEntityIDs.ContainsKey(filterSignature))
{
filterSignatureToEntityIDs.Add(filterSignature, new IndexableSet<Entity>());
}
}
CopyTypeCache(other.typeToFilterSignatures);
}
public Filter CreateFilter(IndexableSet<int> included, IndexableSet<int> excluded)
{
var filterSignature = new FilterSignature(included, excluded);
@ -174,6 +203,32 @@ namespace MoonTools.ECS
}
}
// Used by TransferEntity
public void AddEntity(FilterSignature signature, int entityID)
{
filterSignatureToEntityIDs[signature].Add(entityID);
}
public void TransferStorage(Dictionary<int, int> worldToTransferID, FilterStorage other)
{
foreach (var (filterSignature, entityIDs) in filterSignatureToEntityIDs)
{
foreach (var entity in entityIDs)
{
if (worldToTransferID.ContainsKey(entity))
{
var otherEntityID = worldToTransferID[entity];
other.AddEntity(filterSignature, otherEntityID);
if (other.addCallbacks.TryGetValue(filterSignature, out var addCallback))
{
addCallback(otherEntityID);
}
}
}
}
}
// used by World.Clear, ignores callbacks
public void Clear()
{

View File

@ -54,14 +54,11 @@ namespace MoonTools.ECS
}
// untyped version for Transfer
// no filter check because filter state is copied directly
internal unsafe void Set(Entity entity, int componentTypeIndex, void* component)
{
ComponentDepot.Set(entity.ID, componentTypeIndex, component);
if (EntityStorage.SetComponent(entity.ID, componentTypeIndex))
{
FilterStorage.Check(entity.ID, componentTypeIndex);
}
EntityStorage.SetComponent(entity.ID, componentTypeIndex);
}
public void Remove<TComponent>(in Entity entity) where TComponent : unmanaged
@ -163,6 +160,10 @@ namespace MoonTools.ECS
other.ComponentDepot.CreateMissingStorages(ComponentDepot);
other.RelationDepot.CreateMissingStorages(RelationDepot);
// FIXME: we could just do this once on startup
// Could have a PrepareTransfer method or something
other.FilterStorage.CreateMissingStorages(FilterStorage);
// destroy all entities matching the filter
foreach (var entity in otherFilter.Entities)
{
@ -176,6 +177,7 @@ 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)
{
@ -211,6 +213,8 @@ namespace MoonTools.ECS
other.Set(otherWorldEntity, componentTypeIndex, ComponentDepot.UntypedGet(entity.ID, componentTypeIndex));
}
}
FilterStorage.TransferStorage(WorldToTransferID, other.FilterStorage);
}
}
}