Refactor ECS framework and improve performance

Refactored `ArcEntityTest` to use updated `Transform` and `Mesh` components, improving query logic with `GetChunkIterator` and introducing `ForEach` methods for better modularity.

Enhanced `Chunk` and `Archetype` structs with `readonly` properties and memory optimizations. Fixed bugs in memory copy logic and entity relocation.

Improved `EntityManager` with proper disposal handling, added a destructor, and fixed pointer usage in `AddComponent` and `SetComponentData`.

Refactored `EntityQuery` to use `ChunkIterator` and `ChunkView` for better abstraction. Simplified `EntityQueryMask` logic for performance.

Introduced templated `ForEach` methods and `ForEachWithEntity` methods, dynamically generated using T4 templates for scalability.

Added disposal logic for archetypes and queries in `World`. Updated `Program.cs` to include memory debugging setup.

Integrated T4 templates for dynamic code generation and added helper functions for template generation. Updated project file to include templates and generated outputs.

General improvements include enforcing immutability, optimizing memory management, and adding debugging/logging for better traceability.
This commit is contained in:
2025-12-05 00:29:12 +09:00
parent f9db047a5f
commit 224b2b2dd5
15 changed files with 1424 additions and 135 deletions

View File

@@ -0,0 +1,881 @@
using Ghost.Core;
namespace Ghost.Entities;
public unsafe partial struct EntityQuery
{
public readonly void ForEach<T0>(ForEach<T0> action)
where T0 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value };
var offsets = stackalloc int[1];
var basePtrs = stackalloc byte*[1];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 1; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 1; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
action(ref *pComp0);
}
}
}
}
public readonly void ForEach<T0, T1>(ForEach<T0, T1> action)
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value };
var offsets = stackalloc int[2];
var basePtrs = stackalloc byte*[2];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 2; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 2; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
action(ref *pComp0,ref *pComp1);
}
}
}
}
public readonly void ForEach<T0, T1, T2>(ForEach<T0, T1, T2> action)
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value };
var offsets = stackalloc int[3];
var basePtrs = stackalloc byte*[3];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 3; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 3; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
action(ref *pComp0,ref *pComp1,ref *pComp2);
}
}
}
}
public readonly void ForEach<T0, T1, T2, T3>(ForEach<T0, T1, T2, T3> action)
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
where T3 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value };
var offsets = stackalloc int[4];
var basePtrs = stackalloc byte*[4];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 4; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 4; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
action(ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3);
}
}
}
}
public readonly void ForEach<T0, T1, T2, T3, T4>(ForEach<T0, T1, T2, T3, T4> action)
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
where T3 : unmanaged, IComponent
where T4 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value, ComponentTypeID<T4>.value };
var offsets = stackalloc int[5];
var basePtrs = stackalloc byte*[5];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 5; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 5; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
var pComp4 = (T4*)(basePtrs[4] + (sizeof(T4) * entityIndex));
action(ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4);
}
}
}
}
public readonly void ForEach<T0, T1, T2, T3, T4, T5>(ForEach<T0, T1, T2, T3, T4, T5> action)
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
where T3 : unmanaged, IComponent
where T4 : unmanaged, IComponent
where T5 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value, ComponentTypeID<T4>.value, ComponentTypeID<T5>.value };
var offsets = stackalloc int[6];
var basePtrs = stackalloc byte*[6];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 6; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 6; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
var pComp4 = (T4*)(basePtrs[4] + (sizeof(T4) * entityIndex));
var pComp5 = (T5*)(basePtrs[5] + (sizeof(T5) * entityIndex));
action(ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4,ref *pComp5);
}
}
}
}
public readonly void ForEach<T0, T1, T2, T3, T4, T5, T6>(ForEach<T0, T1, T2, T3, T4, T5, T6> action)
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
where T3 : unmanaged, IComponent
where T4 : unmanaged, IComponent
where T5 : unmanaged, IComponent
where T6 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
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 offsets = stackalloc int[7];
var basePtrs = stackalloc byte*[7];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 7; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 7; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
var pComp4 = (T4*)(basePtrs[4] + (sizeof(T4) * entityIndex));
var pComp5 = (T5*)(basePtrs[5] + (sizeof(T5) * entityIndex));
var pComp6 = (T6*)(basePtrs[6] + (sizeof(T6) * entityIndex));
action(ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4,ref *pComp5,ref *pComp6);
}
}
}
}
public readonly void ForEach<T0, T1, T2, T3, T4, T5, T6, T7>(ForEach<T0, T1, T2, T3, T4, T5, T6, T7> action)
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
where T3 : unmanaged, IComponent
where T4 : unmanaged, IComponent
where T5 : unmanaged, IComponent
where T6 : unmanaged, IComponent
where T7 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
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 offsets = stackalloc int[8];
var basePtrs = stackalloc byte*[8];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 8; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 8; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
var pComp4 = (T4*)(basePtrs[4] + (sizeof(T4) * entityIndex));
var pComp5 = (T5*)(basePtrs[5] + (sizeof(T5) * entityIndex));
var pComp6 = (T6*)(basePtrs[6] + (sizeof(T6) * entityIndex));
var pComp7 = (T7*)(basePtrs[7] + (sizeof(T7) * entityIndex));
action(ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4,ref *pComp5,ref *pComp6,ref *pComp7);
}
}
}
}
public readonly void ForEach<T0>(ForEachWithEntity<T0> action)
where T0 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value };
var offsets = stackalloc int[1];
var basePtrs = stackalloc byte*[1];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 1; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 1; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pEntity = (Entity*)(chunk.GetUnsafePtr() + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
action(*pEntity, ref *pComp0);
}
}
}
}
public readonly void ForEach<T0, T1>(ForEachWithEntity<T0, T1> action)
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value };
var offsets = stackalloc int[2];
var basePtrs = stackalloc byte*[2];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 2; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 2; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pEntity = (Entity*)(chunk.GetUnsafePtr() + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
action(*pEntity, ref *pComp0,ref *pComp1);
}
}
}
}
public readonly void ForEach<T0, T1, T2>(ForEachWithEntity<T0, T1, T2> action)
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value };
var offsets = stackalloc int[3];
var basePtrs = stackalloc byte*[3];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 3; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 3; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pEntity = (Entity*)(chunk.GetUnsafePtr() + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
action(*pEntity, ref *pComp0,ref *pComp1,ref *pComp2);
}
}
}
}
public readonly void ForEach<T0, T1, T2, T3>(ForEachWithEntity<T0, T1, T2, T3> action)
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
where T3 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value };
var offsets = stackalloc int[4];
var basePtrs = stackalloc byte*[4];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 4; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 4; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pEntity = (Entity*)(chunk.GetUnsafePtr() + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
action(*pEntity, ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3);
}
}
}
}
public readonly void ForEach<T0, T1, T2, T3, T4>(ForEachWithEntity<T0, T1, T2, T3, T4> action)
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
where T3 : unmanaged, IComponent
where T4 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value, ComponentTypeID<T4>.value };
var offsets = stackalloc int[5];
var basePtrs = stackalloc byte*[5];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 5; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 5; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pEntity = (Entity*)(chunk.GetUnsafePtr() + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
var pComp4 = (T4*)(basePtrs[4] + (sizeof(T4) * entityIndex));
action(*pEntity, ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4);
}
}
}
}
public readonly void ForEach<T0, T1, T2, T3, T4, T5>(ForEachWithEntity<T0, T1, T2, T3, T4, T5> action)
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
where T3 : unmanaged, IComponent
where T4 : unmanaged, IComponent
where T5 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
var compTypeIDs = stackalloc int[] { ComponentTypeID<T0>.value, ComponentTypeID<T1>.value, ComponentTypeID<T2>.value, ComponentTypeID<T3>.value, ComponentTypeID<T4>.value, ComponentTypeID<T5>.value };
var offsets = stackalloc int[6];
var basePtrs = stackalloc byte*[6];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 6; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 6; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pEntity = (Entity*)(chunk.GetUnsafePtr() + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
var pComp4 = (T4*)(basePtrs[4] + (sizeof(T4) * entityIndex));
var pComp5 = (T5*)(basePtrs[5] + (sizeof(T5) * entityIndex));
action(*pEntity, ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4,ref *pComp5);
}
}
}
}
public readonly void ForEach<T0, T1, T2, T3, T4, T5, T6>(ForEachWithEntity<T0, T1, T2, T3, T4, T5, T6> action)
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
where T3 : unmanaged, IComponent
where T4 : unmanaged, IComponent
where T5 : unmanaged, IComponent
where T6 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
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 offsets = stackalloc int[7];
var basePtrs = stackalloc byte*[7];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 7; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 7; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pEntity = (Entity*)(chunk.GetUnsafePtr() + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
var pComp4 = (T4*)(basePtrs[4] + (sizeof(T4) * entityIndex));
var pComp5 = (T5*)(basePtrs[5] + (sizeof(T5) * entityIndex));
var pComp6 = (T6*)(basePtrs[6] + (sizeof(T6) * entityIndex));
action(*pEntity, ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4,ref *pComp5,ref *pComp6);
}
}
}
}
public readonly void ForEach<T0, T1, T2, T3, T4, T5, T6, T7>(ForEachWithEntity<T0, T1, T2, T3, T4, T5, T6, T7> action)
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
where T3 : unmanaged, IComponent
where T4 : unmanaged, IComponent
where T5 : unmanaged, IComponent
where T6 : unmanaged, IComponent
where T7 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
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 offsets = stackalloc int[8];
var basePtrs = stackalloc byte*[8];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < 8; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < 8; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pEntity = (Entity*)(chunk.GetUnsafePtr() + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
var pComp4 = (T4*)(basePtrs[4] + (sizeof(T4) * entityIndex));
var pComp5 = (T5*)(basePtrs[5] + (sizeof(T5) * entityIndex));
var pComp6 = (T6*)(basePtrs[6] + (sizeof(T6) * entityIndex));
var pComp7 = (T7*)(basePtrs[7] + (sizeof(T7) * entityIndex));
action(*pEntity, ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4,ref *pComp5,ref *pComp6,ref *pComp7);
}
}
}
}
}

View File

@@ -0,0 +1,127 @@
<#@ template language="C#" #>
<#@ output extension="gen.cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ include file="Helpers.ttinclude" #>
using Ghost.Core;
namespace Ghost.Entities;
public unsafe partial struct EntityQuery
{
<# for (var i = 1; i <= Amount; i++)
{
var generics = AppendGenerics(i);
var compGenerics = AppendGenericRefParameters(i);
var restrictions = AppendGenericRestrictionsMultiline(i, "unmanaged, IComponent", 2);
#>
public readonly void ForEach<<#= generics #>>(ForEach<<#= generics #>> action)
<#= restrictions #>
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
var compTypeIDs = stackalloc int[] { <#= AppendGenerics(i, "ComponentTypeID<T{0}>.value") #> };
var offsets = stackalloc int[<#= i #>];
var basePtrs = stackalloc byte*[<#= i #>];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < <#= i #>; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < <#= i #>; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
<# for (var localIndex = 0; localIndex < i; localIndex++) { #>
var pComp<#= localIndex #> = (T<#= localIndex #>*)(basePtrs[<#= localIndex #>] + (sizeof(T<#= localIndex #>) * entityIndex));
<# } #>
action(<#= AppendRefParameters(i, "*pComp{0}") #>);
}
}
}
}
<# } #>
<# for (var i = 1; i <= Amount; i++)
{
var generics = AppendGenerics(i);
var compGenerics = AppendGenericRefParameters(i);
var restrictions = AppendGenericRestrictionsMultiline(i, "unmanaged, IComponent", 2);
#>
public readonly void ForEach<<#= generics #>>(ForEachWithEntity<<#= generics #>> action)
<#= restrictions #>
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
var compTypeIDs = stackalloc int[] { <#= AppendGenerics(i, "ComponentTypeID<T{0}>.value") #> };
var offsets = stackalloc int[<#= i #>];
var basePtrs = stackalloc byte*[<#= i #>];
foreach (var archetypeID in _matchingArchetypes)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
var hasAllComponents = true;
for (var index = 0; index < <#= i #>; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
{
hasAllComponents = false;
break;
}
}
if (!hasAllComponents)
{
continue;
}
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
for (var index = 0; index < <#= i #>; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
{
var pEntity = (Entity*)(chunk.GetUnsafePtr() + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
<# for (var localIndex = 0; localIndex < i; localIndex++) { #>
var pComp<#= localIndex #> = (T<#= localIndex #>*)(basePtrs[<#= localIndex #>] + (sizeof(T<#= localIndex #>) * entityIndex));
<# } #>
action(*pEntity, <#= AppendRefParameters(i, "*pComp{0}") #>);
}
}
}
}
<# } #>
}

View File

@@ -0,0 +1,21 @@
namespace Ghost.Entities;
public delegate void ForEach<T0>(ref T0 t0Component);
public delegate void ForEach<T0, T1>(ref T0 t0Component,ref T1 t1Component);
public delegate void ForEach<T0, T1, T2>(ref T0 t0Component,ref T1 t1Component,ref T2 t2Component);
public delegate void ForEach<T0, T1, T2, T3>(ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component);
public delegate void ForEach<T0, T1, T2, T3, T4>(ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component);
public delegate void ForEach<T0, T1, T2, T3, T4, T5>(ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component,ref T5 t5Component);
public delegate void ForEach<T0, T1, T2, T3, T4, T5, T6>(ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component,ref T5 t5Component,ref T6 t6Component);
public delegate void ForEach<T0, T1, T2, T3, T4, T5, T6, T7>(ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component,ref T5 t5Component,ref T6 t6Component,ref T7 t7Component);
public delegate void ForEachWithEntity<T0>(Entity entity, ref T0 t0Component);
public delegate void ForEachWithEntity<T0, T1>(Entity entity, ref T0 t0Component,ref T1 t1Component);
public delegate void ForEachWithEntity<T0, T1, T2>(Entity entity, ref T0 t0Component,ref T1 t1Component,ref T2 t2Component);
public delegate void ForEachWithEntity<T0, T1, T2, T3>(Entity entity, ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component);
public delegate void ForEachWithEntity<T0, T1, T2, T3, T4>(Entity entity, ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component);
public delegate void ForEachWithEntity<T0, T1, T2, T3, T4, T5>(Entity entity, ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component,ref T5 t5Component);
public delegate void ForEachWithEntity<T0, T1, T2, T3, T4, T5, T6>(Entity entity, ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component,ref T5 t5Component,ref T6 t6Component);
public delegate void ForEachWithEntity<T0, T1, T2, T3, T4, T5, T6, T7>(Entity entity, ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component,ref T5 t5Component,ref T6 t6Component,ref T7 t7Component);

View File

@@ -0,0 +1,24 @@
<#@ template language="C#" #>
<#@ output extension="gen.cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ include file="Helpers.ttinclude" #>
namespace Ghost.Entities;
<# for (var i = 1; i <= Amount; i++)
{
var generics = AppendGenerics(i);
var compGenerics = AppendGenericRefParameters(i);
#>
public delegate void ForEach<<#= generics #>>(<#= compGenerics #>);
<# } #>
<# for (var i = 1; i <= Amount; i++)
{
var generics = AppendGenerics(i);
var compGenerics = AppendGenericRefParameters(i);
#>
public delegate void ForEachWithEntity<<#= generics #>>(Entity entity, <#= compGenerics #>);
<# } #>

View File

@@ -0,0 +1,149 @@
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#+
public int Amount = 8;
public int ExtensionAmount = 3;
public string Indent(StringBuilder sb, int spaces)
{
var indent = new string(' ', spaces);
return sb.ToString().Replace("\n", "\n" + indent);
}
string AppendGenerics(int amount, string template)
{
var sb = new StringBuilder();
for (var i = 0; i < amount; i++)
{
if (i > 0) sb.Append(", ");
sb.Append(string.Format(template, i));
}
return sb.ToString();
}
string AppendGenerics(int amount)
{
return AppendGenerics(amount, "T{0}");
}
public StringBuilder AppendGenericRefParameters(int amount)
{
var sb = new StringBuilder();
for (var localIndex = 0; localIndex < amount; localIndex++)
{
sb.Append($"ref T{localIndex} t{localIndex}Component,");
}
sb.Length--;
return sb;
}
public StringBuilder AppendRefParameters(int amount, string template)
{
var sb = new StringBuilder();
for (var localIndex = 0; localIndex < amount; localIndex++)
{
sb.Append($"ref {string.Format(template, localIndex)},");
}
sb.Length--;
return sb;
}
public StringBuilder AppendGenericRestrictions(int amount, string Ttemplate, string template)
{
var sb = new StringBuilder();
for (var localIndex = 0; localIndex < amount; localIndex++)
{
sb.Append($"where {Ttemplate}{localIndex} : {template}");
if (localIndex < amount - 1)
{
sb.Append(' ');
}
}
return sb;
}
public StringBuilder AppendGenericRestrictions(int amount, string template)
{
return AppendGenericRestrictions(amount, "T", template);
}
public StringBuilder AppendGenericRestrictionsMultiline(int amount, string Ttemplate, string template, int indentation)
{
var sb = new StringBuilder();
var spaces = new string(' ', indentation * 4);
for (var localIndex = 0; localIndex < amount; localIndex++)
{
sb.Append($"{spaces}where {Ttemplate}{localIndex} : {template}");
if (localIndex < amount - 1)
{
sb.AppendLine();
}
}
return sb;
}
public StringBuilder AppendGenericRestrictionsMultiline(int amount, string template, int indentation)
{
return AppendGenericRestrictionsMultiline(amount, "T", template, indentation);
}
public StringBuilder TryGetComponentPools(int amount)
{
var sb = new StringBuilder();
for (var localIndex = 0; localIndex < amount; localIndex++)
{
sb.Append($"_componentStorage.TryGetPool<T{localIndex}>(out var pool{localIndex})");
if (localIndex < amount - 1)
{
sb.Append(" && ");
}
}
return sb;
}
public StringBuilder HasEntity(int amount)
{
var sb = new StringBuilder();
for (var localIndex = 1; localIndex < amount; localIndex++)
{
sb.Append($"pool{localIndex}.Has(entity)");
if (localIndex < amount - 1)
{
sb.Append(" && ");
}
}
return sb;
}
public StringBuilder GetComponent(int amount)
{
var sb = new StringBuilder();
for (var localIndex = 0; localIndex < amount; localIndex++)
{
sb.Append($"pool{localIndex}.GetRef(entity)");
if (localIndex < amount - 1)
{
sb.Append(", ");
}
}
return sb;
}
public StringBuilder GetComponentRef(int amount)
{
var sb = new StringBuilder();
for (var localIndex = 0; localIndex < amount; localIndex++)
{
sb.Append($"ref pool{localIndex}.GetRef(entity)");
if (localIndex < amount - 1)
{
sb.Append(", ");
}
}
return sb;
}
#>