Skip to content

Commit

Permalink
IndexedComponents: update indexes on EntityBatch changes
Browse files Browse the repository at this point in the history
  • Loading branch information
friflo committed Nov 8, 2024
1 parent dbd3873 commit 6964f48
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 12 deletions.
61 changes: 52 additions & 9 deletions src/ECS/Batch/EntityStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using static System.Diagnostics.DebuggerBrowsableState;
using Browse = System.Diagnostics.DebuggerBrowsableAttribute;

// ReSharper disable SuggestBaseTypeForParameter
// ReSharper disable UseNullPropagation
// ReSharper disable ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
// ReSharper disable once CheckNamespace
Expand All @@ -19,6 +20,8 @@ public partial class EntityStoreBase
#region EntityBatch
[Browse(Never)]
internal int PooledEntityBatchCount => internBase.entityBatches.Count;

private readonly long indexTypesMak = Static.EntitySchema.indexTypes.bitSet.l0;

internal EntityBatch GetBatch(int entityId)
{
Expand Down Expand Up @@ -46,6 +49,15 @@ internal void ApplyBatchTo(EntityBatch batch, int entityId)
newComponentTypes.Add (batch.componentsAdd);
newComponentTypes.Remove(batch.componentsRemove);

// --- stash old component values only if an event handler is set or an indexed component changes
var oldHeapMap = archetype.heapMap;
var indexChanges = ((batch.componentsAdd.bitSet.l0 | batch.componentsRemove.bitSet.l0) & indexTypesMak) != 0;
var sendRemoveEvents = internBase.componentRemoved != null;
var sendAddEvents = internBase.componentAdded != null;
if (sendRemoveEvents || sendAddEvents || indexChanges) {
StashComponentValues(batch, oldHeapMap, compIndex);
}

// --- change archetype
var newArchetype = GetArchetype(newComponentTypes, newTags);
if (newArchetype != archetype) {
Expand All @@ -57,7 +69,21 @@ internal void ApplyBatchTo(EntityBatch batch, int entityId)
var newHeapMap = newArchetype.heapMap;
var components = batch.batchComponents;
foreach (var componentType in batch.componentsAdd) {
newHeapMap[componentType.StructIndex].SetBatchComponent(components, compIndex);
var heap = newHeapMap[componentType.StructIndex];
heap.SetBatchComponent(components, compIndex);
if (componentType.IndexType != null) {
var entity = new Entity((EntityStore)this, entityId, node.revision);
if (oldHeapMap[componentType.StructIndex] == null) {
heap.AddIndex(entity);
} else {
heap.UpdateIndex(entity);
}
}
}
// --- update indexes of removed indexed components
var removedIndexTypes = batch.componentsRemove.bitSet.l0 & indexTypesMak;
if (removedIndexTypes != 0) {
RemoveComponentIndexes(removedIndexTypes, new Entity((EntityStore)this, entityId, node.revision), oldHeapMap);
}

// ----------- Send events for all batch commands. See: SEND_EVENT notes
Expand All @@ -69,16 +95,35 @@ internal void ApplyBatchTo(EntityBatch batch, int entityId)
}
}
// --- send component removed event
if (internBase.componentRemoved != null) {
SendComponentRemoved(batch, entityId, archetype, compIndex);
if (sendRemoveEvents) {
SendComponentRemoved(batch, entityId, archetype);
}
// --- send component added event
if (internBase.componentAdded != null) {
SendComponentAdded (batch, entityId, archetype, compIndex);
if (sendAddEvents) {
SendComponentAdded (batch, entityId, archetype);
}
}

private static void StashComponentValues(EntityBatch batch, StructHeap[] oldHeapMap, int compIndex)
{
var componentsChanged = batch.componentsAdd;
componentsChanged.Add(batch.componentsRemove);
foreach (var componentType in componentsChanged) {
oldHeapMap[componentType.StructIndex]?.StashComponent(compIndex);
}
}

private static void RemoveComponentIndexes(long indexTypes, Entity entity, StructHeap[] oldHeapMap)
{
var indexedComponentsRemove = new ComponentTypes();
indexedComponentsRemove.bitSet.l0 = indexTypes;
foreach (var componentType in indexedComponentsRemove) {
var heap = oldHeapMap[componentType.StructIndex];
heap?.RemoveIndex(entity);
}
}

private void SendComponentAdded(EntityBatch batch, int entityId, Archetype archetype, int compIndex)
private void SendComponentAdded(EntityBatch batch, int entityId, Archetype archetype)
{
var oldHeapMap = archetype.heapMap;
var componentAdded = internBase.componentAdded;
Expand All @@ -91,14 +136,13 @@ private void SendComponentAdded(EntityBatch batch, int entityId, Archetype arche
action = ComponentChangedAction.Add;
} else {
// --- case: archetype contains the component type => archetype remains unchanged
structHeap.StashComponent(compIndex);
action = ComponentChangedAction.Update;
}
componentAdded.Invoke(new ComponentChanged (this, entityId, action, structIndex, structHeap));
}
}

private void SendComponentRemoved(EntityBatch batch, int entityId, Archetype archetype, int compIndex)
private void SendComponentRemoved(EntityBatch batch, int entityId, Archetype archetype)
{
var oldHeapMap = archetype.heapMap;
var componentRemoved = internBase.componentRemoved;
Expand All @@ -109,7 +153,6 @@ private void SendComponentRemoved(EntityBatch batch, int entityId, Archetype arc
if (oldHeap == null) {
continue;
}
oldHeap.StashComponent(compIndex);
componentRemoved.Invoke(new ComponentChanged (this, entityId, ComponentChangedAction.Remove, structIndex, oldHeap));
}
}
Expand Down
31 changes: 28 additions & 3 deletions src/Tests/ECS/Arch/Test_Batch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,17 @@ public static void Test_Batch_ApplyTo()
{
var store = new EntityStore(PidType.RandomPids);
var batch = new EntityBatch();
batch.Add (new Position());
batch.Add (new Position(2,2,2));
batch.AddTag<TestTag>();

var entity1 = store.CreateEntity();
var entity2 = store.CreateEntity();
var entity1 = store.CreateEntity(1);
var entity2 = store.CreateEntity(2);
entity1.AddComponent(new Position(1,1,1));
store.OnComponentAdded += changed => {
if (changed.Entity.Id == 1) {
AreEqual(new Position(1,1,1), changed.OldComponent<Position>());
}
};
batch.ApplyTo(entity1)
.ApplyTo(entity2);
AreEqual(0, store.Info.PooledEntityBatchCount);
Expand Down Expand Up @@ -295,6 +301,25 @@ public static void Test_Batch_EntityBatch_Perf()
AreEqual(0, store.Info.PooledEntityBatchCount);
}

[Test]
public static void Test_Batch_ApplyTo_Perf()
{
var count = 10; // 50_000_000 ~ #PC: 3278 ms
var store = new EntityStore();
var batch = new EntityBatch();
batch.Add(new Position());
batch.Add(new Rotation());
batch.Add(new Scale3());

var sw = new Stopwatch();
sw.Start();
var entity1 = store.CreateEntity(1);
for (int n = 0; n < count; n++) {
batch.ApplyTo(entity1);
}
Console.WriteLine($"Test_Batch_ApplyTo_Perf() - duration: {sw.ElapsedMilliseconds} ms");
}

[Test]
public static void Test_Batch_obsolete() {
var store = new EntityStore(PidType.RandomPids);
Expand Down
28 changes: 28 additions & 0 deletions src/Tests/ECS/Serialize/Test_SerializeIndexedComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,34 @@ public static void Test_IndexedComponent_Remove()
AreEqual(0, store.GetEntitiesWithComponentValue<IndexedInt,int>(40).Count);
AreEqual(0, store.GetAllIndexedComponentValues<IndexedInt,int>().Count);
}

[Test]
public static void Test_IndexedComponent_ApplyTo()
{
var store = new EntityStore(PidType.RandomPids);
var batch = new EntityBatch();
batch.Add (new IndexedInt { value = 50 });

var entity1 = store.CreateEntity(1);
batch.ApplyTo(entity1);
AreEqual(1, store.GetEntitiesWithComponentValue<IndexedInt,int>(50).Count);
AreEqual(1, store.GetAllIndexedComponentValues<IndexedInt,int>().Count);

batch = new EntityBatch();
batch.Add (new IndexedInt { value = 51 });
batch.ApplyTo(entity1);
AreEqual(1, store.GetEntitiesWithComponentValue<IndexedInt,int>(51).Count);
AreEqual(0, store.GetEntitiesWithComponentValue<IndexedInt,int>(50).Count);
AreEqual(1, store.GetAllIndexedComponentValues<IndexedInt,int>().Count);

batch = new EntityBatch();
batch.Remove<IndexedInt>();
batch.ApplyTo(entity1);
AreEqual(0, store.GetEntitiesWithComponentValue<IndexedInt,int>(51).Count);
AreEqual(0, store.GetAllIndexedComponentValues<IndexedInt,int>().Count);

batch.ApplyTo(entity1);
}
}

}

0 comments on commit 6964f48

Please sign in to comment.