Per-component versioning and change tracking for ECS

Introduce per-component versioning in chunks and world for efficient change detection.
- Add version arrays to chunks and global version to world.
- Update queries and ForEach to mark written components as changed.
- Extend QueryBuilder with WithAllRW/WithPresentRW for write access.
- Expose change tracking API in ChunkView.
- Improve thread safety and debug code.
- Update tests and examples to demonstrate new features.
This commit is contained in:
2025-12-10 19:01:25 +09:00
parent 21e85e0c02
commit 856fa4f07d
11 changed files with 968 additions and 93 deletions

View File

@@ -1,3 +1,4 @@
using Ghost.Core;
namespace Ghost.Entities;
@@ -7,12 +8,37 @@ public unsafe partial struct EntityQuery
public readonly void ForEach<T0>(ForEach<T0> action)
where T0 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
};
var changedCompIDs = stackalloc int[1];
var offsets = stackalloc int[1];
var basePtrs = stackalloc byte*[1];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 1; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -39,6 +65,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 1; index++)
{
basePtrs[index] = pChunkData + offsets[index];
@@ -63,12 +94,39 @@ public unsafe partial struct EntityQuery
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var comp1TypeID = ComponentTypeID<T1>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
comp1TypeID.value,
};
var changedCompIDs = stackalloc int[2];
var offsets = stackalloc int[2];
var basePtrs = stackalloc byte*[2];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 2; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -95,6 +153,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 2; index++)
{
basePtrs[index] = pChunkData + offsets[index];
@@ -121,12 +184,41 @@ public unsafe partial struct EntityQuery
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var comp1TypeID = ComponentTypeID<T1>.value;
var comp2TypeID = ComponentTypeID<T2>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
comp1TypeID.value,
comp2TypeID.value,
};
var changedCompIDs = stackalloc int[3];
var offsets = stackalloc int[3];
var basePtrs = stackalloc byte*[3];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 3; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -153,6 +245,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 3; index++)
{
basePtrs[index] = pChunkData + offsets[index];
@@ -181,12 +278,43 @@ public unsafe partial struct EntityQuery
where T2 : unmanaged, IComponent
where T3 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var comp1TypeID = ComponentTypeID<T1>.value;
var comp2TypeID = ComponentTypeID<T2>.value;
var comp3TypeID = ComponentTypeID<T3>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
comp1TypeID.value,
comp2TypeID.value,
comp3TypeID.value,
};
var changedCompIDs = stackalloc int[4];
var offsets = stackalloc int[4];
var basePtrs = stackalloc byte*[4];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 4; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -213,6 +341,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 4; index++)
{
basePtrs[index] = pChunkData + offsets[index];
@@ -243,12 +376,45 @@ public unsafe partial struct EntityQuery
where T3 : unmanaged, IComponent
where T4 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value, ComponentTypeID<T4>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var comp1TypeID = ComponentTypeID<T1>.value;
var comp2TypeID = ComponentTypeID<T2>.value;
var comp3TypeID = ComponentTypeID<T3>.value;
var comp4TypeID = ComponentTypeID<T4>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
comp1TypeID.value,
comp2TypeID.value,
comp3TypeID.value,
comp4TypeID.value,
};
var changedCompIDs = stackalloc int[5];
var offsets = stackalloc int[5];
var basePtrs = stackalloc byte*[5];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 5; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -275,6 +441,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 5; index++)
{
basePtrs[index] = pChunkData + offsets[index];
@@ -307,12 +478,47 @@ public unsafe partial struct EntityQuery
where T4 : unmanaged, IComponent
where T5 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value, ComponentTypeID<T4>.value, ComponentTypeID<T5>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var comp1TypeID = ComponentTypeID<T1>.value;
var comp2TypeID = ComponentTypeID<T2>.value;
var comp3TypeID = ComponentTypeID<T3>.value;
var comp4TypeID = ComponentTypeID<T4>.value;
var comp5TypeID = ComponentTypeID<T5>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
comp1TypeID.value,
comp2TypeID.value,
comp3TypeID.value,
comp4TypeID.value,
comp5TypeID.value,
};
var changedCompIDs = stackalloc int[6];
var offsets = stackalloc int[6];
var basePtrs = stackalloc byte*[6];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 6; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -339,6 +545,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 6; index++)
{
basePtrs[index] = pChunkData + offsets[index];
@@ -373,12 +584,49 @@ public unsafe partial struct EntityQuery
where T5 : unmanaged, IComponent
where T6 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value, ComponentTypeID<T4>.value, ComponentTypeID<T5>.value, ComponentTypeID<T6>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var comp1TypeID = ComponentTypeID<T1>.value;
var comp2TypeID = ComponentTypeID<T2>.value;
var comp3TypeID = ComponentTypeID<T3>.value;
var comp4TypeID = ComponentTypeID<T4>.value;
var comp5TypeID = ComponentTypeID<T5>.value;
var comp6TypeID = ComponentTypeID<T6>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
comp1TypeID.value,
comp2TypeID.value,
comp3TypeID.value,
comp4TypeID.value,
comp5TypeID.value,
comp6TypeID.value,
};
var changedCompIDs = stackalloc int[7];
var offsets = stackalloc int[7];
var basePtrs = stackalloc byte*[7];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 7; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -405,6 +653,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 7; index++)
{
basePtrs[index] = pChunkData + offsets[index];
@@ -441,12 +694,51 @@ public unsafe partial struct EntityQuery
where T6 : unmanaged, IComponent
where T7 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value, ComponentTypeID<T4>.value, ComponentTypeID<T5>.value, ComponentTypeID<T6>.value, ComponentTypeID<T7>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var comp1TypeID = ComponentTypeID<T1>.value;
var comp2TypeID = ComponentTypeID<T2>.value;
var comp3TypeID = ComponentTypeID<T3>.value;
var comp4TypeID = ComponentTypeID<T4>.value;
var comp5TypeID = ComponentTypeID<T5>.value;
var comp6TypeID = ComponentTypeID<T6>.value;
var comp7TypeID = ComponentTypeID<T7>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
comp1TypeID.value,
comp2TypeID.value,
comp3TypeID.value,
comp4TypeID.value,
comp5TypeID.value,
comp6TypeID.value,
comp7TypeID.value,
};
var changedCompIDs = stackalloc int[8];
var offsets = stackalloc int[8];
var basePtrs = stackalloc byte*[8];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 8; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -473,6 +765,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 8; index++)
{
basePtrs[index] = pChunkData + offsets[index];
@@ -503,12 +800,37 @@ public unsafe partial struct EntityQuery
public readonly void ForEach<T0>(ForEachWithEntity<T0> action)
where T0 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
};
var changedCompIDs = stackalloc int[1];
var offsets = stackalloc int[1];
var basePtrs = stackalloc byte*[1];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 1; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -535,6 +857,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 1; index++)
{
basePtrs[index] = pChunkData + offsets[index];
@@ -560,12 +887,39 @@ public unsafe partial struct EntityQuery
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var comp1TypeID = ComponentTypeID<T1>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
comp1TypeID.value,
};
var changedCompIDs = stackalloc int[2];
var offsets = stackalloc int[2];
var basePtrs = stackalloc byte*[2];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 2; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -592,6 +946,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 2; index++)
{
basePtrs[index] = pChunkData + offsets[index];
@@ -619,12 +978,41 @@ public unsafe partial struct EntityQuery
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var comp1TypeID = ComponentTypeID<T1>.value;
var comp2TypeID = ComponentTypeID<T2>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
comp1TypeID.value,
comp2TypeID.value,
};
var changedCompIDs = stackalloc int[3];
var offsets = stackalloc int[3];
var basePtrs = stackalloc byte*[3];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 3; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -651,6 +1039,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 3; index++)
{
basePtrs[index] = pChunkData + offsets[index];
@@ -680,12 +1073,43 @@ public unsafe partial struct EntityQuery
where T2 : unmanaged, IComponent
where T3 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var comp1TypeID = ComponentTypeID<T1>.value;
var comp2TypeID = ComponentTypeID<T2>.value;
var comp3TypeID = ComponentTypeID<T3>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
comp1TypeID.value,
comp2TypeID.value,
comp3TypeID.value,
};
var changedCompIDs = stackalloc int[4];
var offsets = stackalloc int[4];
var basePtrs = stackalloc byte*[4];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 4; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -712,6 +1136,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 4; index++)
{
basePtrs[index] = pChunkData + offsets[index];
@@ -743,12 +1172,45 @@ public unsafe partial struct EntityQuery
where T3 : unmanaged, IComponent
where T4 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value, ComponentTypeID<T4>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var comp1TypeID = ComponentTypeID<T1>.value;
var comp2TypeID = ComponentTypeID<T2>.value;
var comp3TypeID = ComponentTypeID<T3>.value;
var comp4TypeID = ComponentTypeID<T4>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
comp1TypeID.value,
comp2TypeID.value,
comp3TypeID.value,
comp4TypeID.value,
};
var changedCompIDs = stackalloc int[5];
var offsets = stackalloc int[5];
var basePtrs = stackalloc byte*[5];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 5; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -775,6 +1237,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 5; index++)
{
basePtrs[index] = pChunkData + offsets[index];
@@ -808,12 +1275,47 @@ public unsafe partial struct EntityQuery
where T4 : unmanaged, IComponent
where T5 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value, ComponentTypeID<T4>.value, ComponentTypeID<T5>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var comp1TypeID = ComponentTypeID<T1>.value;
var comp2TypeID = ComponentTypeID<T2>.value;
var comp3TypeID = ComponentTypeID<T3>.value;
var comp4TypeID = ComponentTypeID<T4>.value;
var comp5TypeID = ComponentTypeID<T5>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
comp1TypeID.value,
comp2TypeID.value,
comp3TypeID.value,
comp4TypeID.value,
comp5TypeID.value,
};
var changedCompIDs = stackalloc int[6];
var offsets = stackalloc int[6];
var basePtrs = stackalloc byte*[6];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 6; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -840,6 +1342,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 6; index++)
{
basePtrs[index] = pChunkData + offsets[index];
@@ -875,12 +1382,49 @@ public unsafe partial struct EntityQuery
where T5 : unmanaged, IComponent
where T6 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value, ComponentTypeID<T4>.value, ComponentTypeID<T5>.value, ComponentTypeID<T6>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var comp1TypeID = ComponentTypeID<T1>.value;
var comp2TypeID = ComponentTypeID<T2>.value;
var comp3TypeID = ComponentTypeID<T3>.value;
var comp4TypeID = ComponentTypeID<T4>.value;
var comp5TypeID = ComponentTypeID<T5>.value;
var comp6TypeID = ComponentTypeID<T6>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
comp1TypeID.value,
comp2TypeID.value,
comp3TypeID.value,
comp4TypeID.value,
comp5TypeID.value,
comp6TypeID.value,
};
var changedCompIDs = stackalloc int[7];
var offsets = stackalloc int[7];
var basePtrs = stackalloc byte*[7];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 7; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -907,6 +1451,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 7; index++)
{
basePtrs[index] = pChunkData + offsets[index];
@@ -944,12 +1493,51 @@ public unsafe partial struct EntityQuery
where T6 : unmanaged, IComponent
where T7 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value, ComponentTypeID<T4>.value, ComponentTypeID<T5>.value, ComponentTypeID<T6>.value, ComponentTypeID<T7>.value };
var comp0TypeID = ComponentTypeID<T0>.value;
var comp1TypeID = ComponentTypeID<T1>.value;
var comp2TypeID = ComponentTypeID<T2>.value;
var comp3TypeID = ComponentTypeID<T3>.value;
var comp4TypeID = ComponentTypeID<T4>.value;
var comp5TypeID = ComponentTypeID<T5>.value;
var comp6TypeID = ComponentTypeID<T6>.value;
var comp7TypeID = ComponentTypeID<T7>.value;
var compTypeIDs = stackalloc int[]
{
comp0TypeID.value,
comp1TypeID.value,
comp2TypeID.value,
comp3TypeID.value,
comp4TypeID.value,
comp5TypeID.value,
comp6TypeID.value,
comp7TypeID.value,
};
var changedCompIDs = stackalloc int[8];
var offsets = stackalloc int[8];
var basePtrs = stackalloc byte*[8];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < 8; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -976,6 +1564,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < 8; index++)
{
basePtrs[index] = pChunkData + offsets[index];

View File

@@ -24,12 +24,41 @@ public unsafe partial struct EntityQuery
public readonly void ForEach<<#= generics #>>(<#= delegateTupe #><<#= generics #>> action)
<#= restrictions #>
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version;
var compTypeIDs = stackalloc int[] { <#= AppendGenerics(i, "ComponentTypeID<T{0}>.value") #> };
<# for (var localIndex = 0; localIndex < i; localIndex++) { #>
var comp<#= localIndex #>TypeID = ComponentTypeID<T<#= localIndex #>>.value;
<# } #>
var compTypeIDs = stackalloc int[]
{
<# for (var localIndex = 0; localIndex < i; localIndex++) { #>
comp<#= localIndex #>TypeID.value,
<# } #>
};
var changedCompIDs = stackalloc int[<#= i #>];
var offsets = stackalloc int[<#= i #>];
var basePtrs = stackalloc byte*[<#= i #>];
var changedCompCount = 0;
var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id))
{
for (var i =0; i < <#= i #>; i++)
{
if (id == compTypeIDs[i])
{
ComponentRegister.SetComponentLastWrite(id, globalVersion);
changedCompIDs[changedCompCount] = id;
changedCompCount++;
break;
}
}
}
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
@@ -56,6 +85,11 @@ public unsafe partial struct EntityQuery
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var pChunkData = chunk.GetUnsafePtr();
for (var j = 0; j < changedCompCount; j++)
{
chunk.MarkChanged(changedCompIDs[i], globalVersion);
}
for (var index = 0; index < <#= i #>; index++)
{
basePtrs[index] = pChunkData + offsets[index];

View File

@@ -18,6 +18,20 @@ public ref partial struct QueryBuilder
return this;
}
/// <summary>
/// Adds the specified component type(s) to the 'All' filter of the query and requires read-write access.
/// Targets entities that have all of the specified component types and those component(s) must be enabled.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAllRW<T0>()
where T0 : unmanaged, IComponent
{
_all.Add(ComponentTypeID<T0>.value);
_rw.Add(ComponentTypeID<T0>.value);
return this;
}
/// <summary>
/// Adds the specified component type(s) to the 'Any' filter of the query.
/// Targets entities that have at least one of the specified component types and those component(s) must be enabled.
@@ -83,6 +97,20 @@ public ref partial struct QueryBuilder
return this;
}
/// <summary>
/// Adds the specified component type(s) to the 'Present' filter of the query and requires read-write access.
/// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithPresentRW<T0>()
where T0 : unmanaged, IComponent
{
_present.Add(ComponentTypeID<T0>.value);
_rw.Add(ComponentTypeID<T0>.value);
return this;
}
/// <summary>
/// Adds the specified component type(s) to the 'All' filter of the query.
/// Targets entities that have all of the specified component types and those component(s) must be enabled.
@@ -98,6 +126,23 @@ public ref partial struct QueryBuilder
return this;
}
/// <summary>
/// Adds the specified component type(s) to the 'All' filter of the query and requires read-write access.
/// Targets entities that have all of the specified component types and those component(s) must be enabled.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAllRW<T0, T1>()
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
{
_all.Add(ComponentTypeID<T0>.value);
_rw.Add(ComponentTypeID<T0>.value);
_all.Add(ComponentTypeID<T1>.value);
_rw.Add(ComponentTypeID<T1>.value);
return this;
}
/// <summary>
/// Adds the specified component type(s) to the 'Any' filter of the query.
/// Targets entities that have at least one of the specified component types and those component(s) must be enabled.
@@ -173,6 +218,23 @@ public ref partial struct QueryBuilder
return this;
}
/// <summary>
/// Adds the specified component type(s) to the 'Present' filter of the query and requires read-write access.
/// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithPresentRW<T0, T1>()
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
{
_present.Add(ComponentTypeID<T0>.value);
_rw.Add(ComponentTypeID<T0>.value);
_present.Add(ComponentTypeID<T1>.value);
_rw.Add(ComponentTypeID<T1>.value);
return this;
}
/// <summary>
/// Adds the specified component type(s) to the 'All' filter of the query.
/// Targets entities that have all of the specified component types and those component(s) must be enabled.
@@ -190,6 +252,26 @@ public ref partial struct QueryBuilder
return this;
}
/// <summary>
/// Adds the specified component type(s) to the 'All' filter of the query and requires read-write access.
/// Targets entities that have all of the specified component types and those component(s) must be enabled.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAllRW<T0, T1, T2>()
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
{
_all.Add(ComponentTypeID<T0>.value);
_rw.Add(ComponentTypeID<T0>.value);
_all.Add(ComponentTypeID<T1>.value);
_rw.Add(ComponentTypeID<T1>.value);
_all.Add(ComponentTypeID<T2>.value);
_rw.Add(ComponentTypeID<T2>.value);
return this;
}
/// <summary>
/// Adds the specified component type(s) to the 'Any' filter of the query.
/// Targets entities that have at least one of the specified component types and those component(s) must be enabled.
@@ -275,4 +357,24 @@ public ref partial struct QueryBuilder
return this;
}
/// <summary>
/// Adds the specified component type(s) to the 'Present' filter of the query and requires read-write access.
/// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithPresentRW<T0, T1, T2>()
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
{
_present.Add(ComponentTypeID<T0>.value);
_rw.Add(ComponentTypeID<T0>.value);
_present.Add(ComponentTypeID<T1>.value);
_rw.Add(ComponentTypeID<T1>.value);
_present.Add(ComponentTypeID<T2>.value);
_rw.Add(ComponentTypeID<T2>.value);
return this;
}
}

View File

@@ -31,6 +31,22 @@ public ref partial struct QueryBuilder
return this;
}
/// <summary>
/// Adds the specified component type(s) to the 'All' filter of the query and requires read-write access.
/// Targets entities that have all of the specified component types and those component(s) must be enabled.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAllRW<<#= generics #>>()
<#= restrictions #>
{
<# for (var j = 0; j < i; j++) { #>
_all.Add(ComponentTypeID<T<#= j #>>.value);
_rw.Add(ComponentTypeID<T<#= j #>>.value);
<# } #>
return this;
}
/// <summary>
/// Adds the specified component type(s) to the 'Any' filter of the query.
/// Targets entities that have at least one of the specified component types and those component(s) must be enabled.
@@ -106,5 +122,21 @@ public ref partial struct QueryBuilder
return this;
}
/// <summary>
/// Adds the specified component type(s) to the 'Present' filter of the query and requires read-write access.
/// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithPresentRW<<#= generics #>>()
<#= restrictions #>
{
<# for (var j = 0; j < i; j++) { #>
_present.Add(ComponentTypeID<T<#= j #>>.value);
_rw.Add(ComponentTypeID<T<#= j #>>.value);
<# } #>
return this;
}
<# } #>
}