forked from Misaki/GhostEngine
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.
61 lines
1.7 KiB
C#
61 lines
1.7 KiB
C#
namespace Ghost.Entities;
|
|
|
|
public unsafe class EntityQueryy<T1, T2>
|
|
where T1 : unmanaged, IComponent
|
|
where T2 : unmanaged, IComponent
|
|
{
|
|
// The Cache Struct
|
|
struct ArchetypeCache
|
|
{
|
|
public Archetype Archetype;
|
|
public int Offset1; // Offset for T0
|
|
public int Offset2; // Offset for T2
|
|
}
|
|
|
|
private List<ArchetypeCache> _cache = new();
|
|
|
|
internal void AddMatchingArchetype(Archetype archetype)
|
|
{
|
|
// We look up the offsets ONCE when the archetype is registered
|
|
int off1 = archetype.GetOffset(ComponentTypeID<T1>.value);
|
|
int off2 = archetype.GetOffset(ComponentTypeID<T2>.value);
|
|
|
|
_cache.Add(new ArchetypeCache
|
|
{
|
|
Archetype = archetype,
|
|
Offset1 = off1,
|
|
Offset2 = off2
|
|
});
|
|
}
|
|
|
|
// The Optimized Iteration Loop
|
|
public void ForEach(delegate*<ref T1, ref T2, void> action)
|
|
{
|
|
foreach (var cache in _cache)
|
|
{
|
|
var archetype = cache.Archetype;
|
|
var offset1 = cache.Offset1;
|
|
var offset2 = cache.Offset2;
|
|
|
|
// Iterate Chunks
|
|
for (int i = 0; i < archetype.ChunkCount; i++)
|
|
{
|
|
var chunk = archetype.GetChunkReference(i);
|
|
var chunkPtr = chunk.GetUnsafePtr();
|
|
var count = chunk.Count;
|
|
|
|
// POINTER MATH ONLY - NO LOOKUPS
|
|
// We use the pre-calculated integer offsets
|
|
T1* ptr1 = (T1*)(chunkPtr + offset1);
|
|
T2* ptr2 = (T2*)(chunkPtr + offset2);
|
|
|
|
// The hot loop
|
|
for (int k = 0; k < count; k++)
|
|
{
|
|
action(ref ptr1[k], ref ptr2[k]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|