Skip to content

Commit

Permalink
IndexedComponents: update indexes when using a CommandBuffer
Browse files Browse the repository at this point in the history
See: #5
  • Loading branch information
friflo committed Nov 11, 2024
1 parent ef8b680 commit f713eca
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/ECS/Base/Types/ComponentType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ internal override StructHeap CreateHeap() {

internal override ComponentCommands CreateComponentCommands()
{
return new ComponentCommands<T>(StructIndex) {
return new ComponentCommands<T>(StructIndex, IndexType) {
componentCommands = new ComponentCommand<T>[8]
};
}
Expand Down
46 changes: 34 additions & 12 deletions src/ECS/CommandBuffer/Commands/ComponentCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ internal abstract class ComponentCommands : IComponentStash
{
[Browse(Never)] internal int commandCount; // 4
[Browse(Never)] internal readonly int structIndex; // 4
[Browse(Never)] internal readonly long indexMask; // 8


public abstract IComponent GetStashDebug();
Expand All @@ -24,8 +25,11 @@ internal abstract class ComponentCommands : IComponentStash
internal abstract void ExecuteCommands (Playback playback);
internal abstract void SendCommandEvents (Playback playback);

internal ComponentCommands(int structIndex) {
internal ComponentCommands(int structIndex, Type indexType) {
this.structIndex = structIndex;
if (indexType != null) {
indexMask = 1L << structIndex;
}
}
}

Expand All @@ -39,7 +43,7 @@ internal sealed class ComponentCommands<T> : ComponentCommands, IComponentStash<
[Browse(Never)] private T stashValue;


internal ComponentCommands(int structIndex) : base(structIndex) { }
internal ComponentCommands(int structIndex, Type indexType) : base(structIndex, indexType) { }

public override IComponent GetStashDebug() => stashValue;
public ref T GetStashRef() => ref stashValue;
Expand All @@ -58,25 +62,25 @@ internal override void UpdateComponentTypes(Playback playback, bool storeOldComp
// --- set new entity component types for Add/Remove commands
foreach (ref var command in commands)
{
var entityId = command.entityId;
ref var node = ref nodes[entityId];
var archetype = node.archetype;
if (archetype == null) {
throw EntityNotFound(command.ToString());
}
if ((archetype.componentTypes.bitSet.l0 & indexMask) != 0) {
RemoveIndexedComponent(playback, node, entityId);
}
if (command.change == Update) {
continue;
}
var entityId = command.entityId;
#if NET6_0_OR_GREATER
ref var changeIndex = ref System.Runtime.InteropServices.CollectionsMarshal.GetValueRefOrAddDefault(indexes, entityId, out exists);
#else
exists = indexes.TryGetValue(entityId, out var changeIndex);
#endif
ref var node = ref nodes[entityId];
var archetype = node.archetype;
if (archetype == null) {
throw EntityNotFound(command.ToString());
}
if (storeOldComponent) {
var heap = archetype.heapMap[index];
if (heap != null) {
command.oldComponent = ((StructHeap<T>)heap).components[node.compIndex];
}
StoreComponent(ref command, node);
}
if (!exists) {
changeIndex = playback.entityChangesCount++;
Expand All @@ -99,6 +103,21 @@ internal override void UpdateComponentTypes(Playback playback, bool storeOldComp
}
}

private void RemoveIndexedComponent(Playback playback, in EntityNode node, int entityId)
{
var heap = (StructHeap<T>)node.archetype.heapMap[structIndex];
heap.componentStash = heap.components[node.compIndex];
heap.RemoveIndex(new Entity(playback.store, entityId, node.revision));
}

private void StoreComponent(ref ComponentCommand<T> command, in EntityNode node)
{
var heap = node.archetype.heapMap[structIndex];
if (heap != null) {
command.oldComponent = ((StructHeap<T>)heap).components[node.compIndex];
}
}

private static InvalidOperationException EntityNotFound(string command) {
return new InvalidOperationException($"Playback - entity not found. command: {command}");
}
Expand All @@ -123,6 +142,9 @@ internal override void ExecuteCommands(Playback playback)
continue;
}
((StructHeap<T>)heap).components[node.compIndex] = command.component;
if (StructInfo<T>.HasIndex) {
heap.AddIndex(new Entity(playback.store, command.entityId, node.revision));
}
}
}

Expand Down
47 changes: 45 additions & 2 deletions src/Tests/ECS/Index/Test_IndexedComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
using Friflo.Engine.ECS;
using Friflo.Engine.ECS.Serialize;
using NUnit.Framework;
using Tests.ECS.Index;
using static NUnit.Framework.Assert;

// ReSharper disable MethodHasAsyncOverload
// ReSharper disable HeuristicUnreachableCode
// ReSharper disable InconsistentNaming
namespace Tests.ECS.Serialize {
namespace Tests.ECS.Index {

public static class Test_IndexedComponent
{
Expand Down Expand Up @@ -174,6 +173,50 @@ public static void Test_IndexedComponent_CreateEntityBatch()
AreEqual(1, store.GetEntitiesWithComponentValue<IndexedInt,int>(60).Count);
AreEqual(1, store.GetAllIndexedComponentValues<IndexedInt,int>().Count);
}

[Test]
public static void Test_IndexedComponent_CommandBuffer()
{
var store = new EntityStore();
store.CreateEntity(1);


var ecb = store.GetCommandBuffer();
ecb.ReuseBuffer = true;
ecb.AddComponent(1, new IndexedInt { value = 70 });
ecb.Playback();

AreEqual(1, store.GetEntitiesWithComponentValue<IndexedInt,int>(70).Count);
AreEqual(1, store.GetAllIndexedComponentValues<IndexedInt,int>().Count);

ecb.AddComponent(1, new IndexedInt { value = 71 });
ecb.Playback();

AreEqual(0, store.GetEntitiesWithComponentValue<IndexedInt,int>(70).Count);
AreEqual(1, store.GetEntitiesWithComponentValue<IndexedInt,int>(71).Count);
AreEqual(1, store.GetAllIndexedComponentValues<IndexedInt,int>().Count);

ecb.SetComponent(1, new IndexedInt { value = 72 });
ecb.Playback();

AreEqual(0, store.GetEntitiesWithComponentValue<IndexedInt,int>(71).Count);
AreEqual(1, store.GetEntitiesWithComponentValue<IndexedInt,int>(72).Count);
AreEqual(1, store.GetAllIndexedComponentValues<IndexedInt,int>().Count);

ecb.RemoveComponent<IndexedInt>(1);
ecb.RemoveComponent<IndexedInt>(1);
ecb.Playback();

AreEqual(0, store.GetEntitiesWithComponentValue<IndexedInt,int>(72).Count);
AreEqual(0, store.GetAllIndexedComponentValues<IndexedInt,int>().Count);

ecb.RemoveComponent<IndexedInt>(1);
ecb.Playback();

AreEqual(0, store.GetEntitiesWithComponentValue<IndexedInt,int>(72).Count);
AreEqual(0, store.GetAllIndexedComponentValues<IndexedInt,int>().Count);
}

}

}

0 comments on commit f713eca

Please sign in to comment.