diagnostics(opstack): separate disabled-slot bail causes

The old Not Op Stack counter fired before slot attribution, so interior disabled strates and boundary encounters produced the same number. Split the instrumentation into sole-slot, boundary-tile, unresolved-layout, and late-recheck counters while preserving every ClassifyTile condition, return point, and verdict.
This commit is contained in:
2026-08-17 00:39:47 +02:00
parent 8295f6e76b
commit 1e02c6314f
4 changed files with 43 additions and 6 deletions
+33 -2
View File
@@ -2809,7 +2809,33 @@ EVoxelTileClass UVoxelGenerator::ClassifyTile(const FIntVector& OriginVoxels, in
// même endroit, que `GetDensityAt`.
if (!StrateManager->UsesOperatorStackForChunk(CC))
{
INC_DWORD_STAT(STAT_VoxelForgeCaveBailNotOpStack);
// Attribution DIAGNOSTIQUE uniquement : l'ancien compteur mélangeait une
// strate cave entièrement désactivée avec une tuile de frontière qui avait
// rencontré un slot désactivé avant la garde « slot différent » ci-dessous.
// On résout les bornes APRÈS l'échec du même prédicat ; elles ne changent ni
// la condition, ni le point de retour, ni le verdict.
// Diagnostic attribution only: the old counter mixed a wholly disabled cave
// slot with a boundary tile that met a disabled slot before the different-slot
// guard below. Resolve bounds only after the same predicate fails; classification
// control flow and return value stay unchanged.
int32 FailedTopCZ = 0, FailedBotCZ = 0;
if (!StrateManager->GetStrateChunkZBounds(ChunkZ, FailedTopCZ, FailedBotCZ))
{
INC_DWORD_STAT(STAT_VoxelForgeCaveBailNotOpStackNoLayout);
}
else
{
const int32 TileMinCZ = FloorDivC(MinZ, CHUNK_SIZE);
const int32 TileMaxCZ = FloorDivC(MaxZ, CHUNK_SIZE);
if (TileMinCZ >= FailedBotCZ && TileMaxCZ <= FailedTopCZ)
{
INC_DWORD_STAT(STAT_VoxelForgeCaveBailNotOpStackSoleSlot);
}
else
{
INC_DWORD_STAT(STAT_VoxelForgeCaveBailNotOpStackBoundaryTile);
}
}
return EVoxelTileClass::Mixed;
}
@@ -2929,7 +2955,12 @@ EVoxelTileClass UVoxelGenerator::ClassifyTile(const FIntVector& OriginVoxels, in
// déclenché la tentative : un seul chunk hors pile invaliderait le verdict.
if (!StrateManager->UsesOperatorStackForChunk(CC))
{
INC_DWORD_STAT(STAT_VoxelForgeCaveBailNotOpStack);
// Le passage Z précédent a déjà accepté l'unique slot cave. Avec le layout actuel
// (prédicat indépendant de X/Y), ce recheck est redondant ; un hit nomme donc
// précisément cette garde tardive au lieu d'être agrégé aux opt-ins désactivés.
// The prior Z pass already accepted the sole cave slot. With the current X/Y-
// independent predicate this recheck is redundant, so attribute it separately.
INC_DWORD_STAT(STAT_VoxelForgeCaveBailNotOpStackRecheck);
return EVoxelTileClass::Mixed;
}
+4 -1
View File
@@ -10,7 +10,10 @@ DEFINE_STAT(STAT_VoxelForgeTilesSkippedAllAir);
DEFINE_STAT(STAT_VoxelForgeTilesMeshed);
DEFINE_STAT(STAT_VoxelForgeTilesOpStackSolid);
DEFINE_STAT(STAT_VoxelForgeTilesOpStackAir);
DEFINE_STAT(STAT_VoxelForgeCaveBailNotOpStack);
DEFINE_STAT(STAT_VoxelForgeCaveBailNotOpStackSoleSlot);
DEFINE_STAT(STAT_VoxelForgeCaveBailNotOpStackBoundaryTile);
DEFINE_STAT(STAT_VoxelForgeCaveBailNotOpStackNoLayout);
DEFINE_STAT(STAT_VoxelForgeCaveBailNotOpStackRecheck);
DEFINE_STAT(STAT_VoxelForgeCaveBailMixedContent);
DEFINE_STAT(STAT_VoxelForgeCaveBailParams);
DEFINE_STAT(STAT_VoxelForgeCaveBailStackVerdict);
+4 -1
View File
@@ -14,7 +14,10 @@ DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Tiles Skipped All Air"), STAT_VoxelForge
DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Tiles Meshed"), STAT_VoxelForgeTilesMeshed, STATGROUP_VoxelForge, VOXELFORGE_API);
DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Tiles Operator Stack Solid"), STAT_VoxelForgeTilesOpStackSolid, STATGROUP_VoxelForge, VOXELFORGE_API);
DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Tiles Operator Stack Air"), STAT_VoxelForgeTilesOpStackAir, STATGROUP_VoxelForge, VOXELFORGE_API);
DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Cave Bail Not Op Stack"), STAT_VoxelForgeCaveBailNotOpStack, STATGROUP_VoxelForge, VOXELFORGE_API);
DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Cave Bail Not Op Stack Sole Slot"), STAT_VoxelForgeCaveBailNotOpStackSoleSlot, STATGROUP_VoxelForge, VOXELFORGE_API);
DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Cave Bail Not Op Stack Boundary Tile"), STAT_VoxelForgeCaveBailNotOpStackBoundaryTile, STATGROUP_VoxelForge, VOXELFORGE_API);
DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Cave Bail Not Op Stack No Layout"), STAT_VoxelForgeCaveBailNotOpStackNoLayout, STATGROUP_VoxelForge, VOXELFORGE_API);
DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Cave Bail Not Op Stack Recheck"), STAT_VoxelForgeCaveBailNotOpStackRecheck, STATGROUP_VoxelForge, VOXELFORGE_API);
DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Cave Bail Mixed Content"), STAT_VoxelForgeCaveBailMixedContent, STATGROUP_VoxelForge, VOXELFORGE_API);
DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Cave Bail Params"), STAT_VoxelForgeCaveBailParams, STATGROUP_VoxelForge, VOXELFORGE_API);
DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Cave Bail Stack Verdict"), STAT_VoxelForgeCaveBailStackVerdict, STATGROUP_VoxelForge, VOXELFORGE_API);