Support enableable components and query enhancements

- Upgraded `Misaki.HighPerformance.LowLevel` to v1.2.8.
- Added `IEquatable` to `Handle<T>` and `Identifier<T>`.
- Improved `Result` extensions with `[CallerArgumentExpression]`.
- Introduced `SetEnabled` in `EntityManager` to toggle components.
- Refactored `Chunk` and `Archetype` for enableable components.
- Added `EntityQueryMask` for filtering enabled/disabled components.
- Enhanced `QueryBuilder` with new filtering methods (`WithAll`, etc.).
- Improved `EntityQuery.ForEach` with entity validation.
This commit is contained in:
2025-12-05 22:38:11 +09:00
parent 224b2b2dd5
commit 30c1d99959
16 changed files with 1203 additions and 448 deletions

View File

@@ -10,13 +10,19 @@ namespace Ghost.Entities;
public unsafe partial struct EntityQuery
{
<# for (var f = 0; f < 2; f++)
{
var isForEachWithEntity = f != 0;
#>
<# for (var i = 1; i <= Amount; i++)
{
var generics = AppendGenerics(i);
var compGenerics = AppendGenericRefParameters(i);
var restrictions = AppendGenericRestrictionsMultiline(i, "unmanaged, IComponent", 2);
var delegateTupe = isForEachWithEntity ? "ForEachWithEntity" : "ForEach";
#>
public readonly void ForEach<<#= generics #>>(ForEach<<#= generics #>> action)
public readonly void ForEach<<#= generics #>>(<#= delegateTupe #><<#= generics #>> action)
<#= restrictions #>
{
var world = World.GetWorld(_worldID).GetValueOrThrow(ResultStatus.Success);
@@ -25,18 +31,20 @@ public unsafe partial struct EntityQuery
var offsets = stackalloc int[<#= i #>];
var basePtrs = stackalloc byte*[<#= i #>];
foreach (var archetypeID in _matchingArchetypes)
for (var i = 0; i < _matchingArchetypes.Count; i++)
{
ref var archetype = ref world.GetArchetypeReference(archetypeID);
ref var archetype = ref world.GetArchetypeReference(_matchingArchetypes[i]);
var hasAllComponents = true;
for (var index = 0; index < <#= i #>; index++)
{
offsets[index] = archetype.GetOffset(compTypeIDs[index]);
if (offsets[index] == -1)
var layoutResult = archetype.GetLayout(compTypeIDs[index]);
if (layoutResult.Status != ResultStatus.Success)
{
hasAllComponents = false;
break;
}
offsets[index] = layoutResult.Value.offset;
}
if (!hasAllComponents)
@@ -47,81 +55,35 @@ public unsafe partial struct EntityQuery
for (var chunkIndex = 0; chunkIndex < archetype.ChunkCount; chunkIndex++)
{
ref var chunk = ref archetype.GetChunkReference(chunkIndex);
var count = chunk.Count;
var pChunkData = chunk.GetUnsafePtr();
for (var index = 0; index < <#= i #>; index++)
{
basePtrs[index] = chunk.GetUnsafePtr() + offsets[index];
basePtrs[index] = pChunkData + offsets[index];
}
for (var entityIndex = 0; entityIndex < count; entityIndex++)
for (var entityIndex = 0; entityIndex < chunk.Count; entityIndex++)
{
if (!IsEntityValid(pChunkData, entityIndex, in archetype, in _mask))
{
continue;
}
<# 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));
<# } #>
<# if (isForEachWithEntity) { #>
var pEntity = (Entity*)(pChunkData + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
action(*pEntity, <#= AppendRefParameters(i, "*pComp{0}") #>);
<# } else { #>
action(<#= AppendRefParameters(i, "*pComp{0}") #>);
<# } #>
}
}
}
}
<# } #>
<# } #>
}