fix(passages): D-floors now exist inside the inter-strate gap; two stale tests corrected

Investigation of the two tests that had been failing for days (Codex; the fix reviewed and its
field claims re-run by me).

Real bug, introduced by adb34df: gap chunks take the compact bedrock path in GetDensityAt, which
applied the passage modifier but never the build-authored native D-floor. So the walkable passage
floor vanished exactly at the gap/strate seam, in the passages the player uses to cross strates.
Now gap chunks set Result = -Density, then ApplyPassageNativeFloorMC, then VF_ApplyXYEdgeSealMC.
The seal runs on the MC value, in the same order as before.

Stale tests, not code bugs:
- PassageLandsInOpenSpace: since d97373c production passes the cached world/warp seed to
  VF_SuggestLandingPoint, while the test still queried with the default seed. Both queries are
  fixed; the test now allows only exact graph-owned support-floor samples (the production
  bProtectAuthoredTunnelFloor contract), and anything else still fails. 14/14 landing ends,
  5,774/5,774 floor and capsule samples.
- ClassifyTileSoundness: since d38d4ca ClassifyTile covers the cell vertices g=0..CPA, but the test
  still sampled the mesher's outer normal halo. Both "holes" were halo-only (g = CPA+1). The test now
  asserts the current contract. TryProveSealedSolidTile already uses the exact core lattice, so it
  is not affected.

Verified: crossing test PASS (max gate 0.129 s); sealed-proof test 22/22; both classifier variants
pass (600 tiles each). Re-run by the orchestrator against this build: export OBJ SHA-256
b3e5f4c3..9b377 unchanged; capability 20,830 / 10,909 / walk-only 10,909.
Ledger: one DDC startup fatal (crash folder 43101DC8, 04:38) and a set of expected diagnostic
failures while locating the gap-branch omission; one malformed ablation argument (not a valid
ablation).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y
This commit is contained in:
Fr0zkaandClaude Opus 5 committed 2026-09-15 06:08:59 +02:00
1 parent cf2b2add20
commit 92607751b1
3 files changed
+185 -29

No files matched your search

@@ -19,13 +19,15 @@
// Cette fonction a DÉJÀ produit cette panne : la v1 de T1.d a été revertée le 2026-06-26 pour une // Cette fonction a DÉJÀ produit cette panne : la v1 de T1.d a été revertée le 2026-06-26 pour une
// borne de plafond pas assez conservative. Jusqu'ici elle n'est validée que par raisonnement. // borne de plafond pas assez conservative. Jusqu'ici elle n'est validée que par raisonnement.
// Ce test la valide par la force brute : pour chaque tuile jugée non-Mixed, on échantillonne le // Ce test la valide par la force brute : pour chaque tuile jugée non-Mixed, on échantillonne le
// treillis EXACT que le mesher aurait échantillonné (marge ±1 incluse) et on vérifie que chaque // treillis des sommets de cellules que ClassifyTile couvre réellement (g = 0..CPA) et on vérifie
// point est bien du côté annoncé. // que chaque point est bien du côté annoncé. La marge extérieure du mesher sert aux normales, pas
// au verdict uniforme.
// //
// This function has ALREADY produced that failure: T1.d v1 was reverted on 2026-06-26 over a // This function has ALREADY produced that failure: T1.d v1 was reverted on 2026-06-26 over a
// non-conservative ceiling bound. Until now it was validated by reasoning only. This test // non-conservative ceiling bound. Until now it was validated by reasoning only. This test
// validates it by brute force: for every tile judged non-Mixed, sample the EXACT lattice the // validates it by brute force: for every tile judged non-Mixed, sample the exact cell-vertex
// mesher would have sampled (±1 margin included) and assert every point is on the claimed side. // lattice covered by ClassifyTile (g = 0..CPA) and assert every point is on the claimed side. The
// mesher's outer normal halo is deliberately outside the classifier's uniformity contract.
// //
// CONVENTION (VoxelMarchingCubesMesher.cpp:309, IsoLevel == 0): // CONVENTION (VoxelMarchingCubesMesher.cpp:309, IsoLevel == 0):
// D >= 0 ⇒ côté AIR / air side // D >= 0 ⇒ côté AIR / air side
@@ -166,8 +168,10 @@ bool FVoxelForgeClassifyTileTest::RunTest(const FString& Parameters)
return false; return false;
} }
// ── Vérification par force brute, sur le treillis EXACT du mesher. ── // ── Vérification par force brute du contrat de ClassifyTile. ──
// Les bornes reproduisent ClassifyTile / GenerateMesh : g ∈ [-1, Cells+1] par axe. // ClassifyTile covers actual cell vertices only: g ∈ [0, CPA]. GenerateMesh may sample a
// one-vertex outer halo for central-difference normals, but that halo cannot create a cell and
// is intentionally not part of the uniform verdict.
int32 NumHoles = 0; int32 NumHoles = 0;
for (const FTileSpec& Spec : ToVerify) for (const FTileSpec& Spec : ToVerify)
{ {
@@ -175,13 +179,13 @@ bool FVoxelForgeClassifyTileTest::RunTest(const FString& Parameters)
if (Verdict == EVoxelTileClass::Mixed) { continue; } // verdict instable ⇒ rien à prouver if (Verdict == EVoxelTileClass::Mixed) { continue; } // verdict instable ⇒ rien à prouver
const int32 CPA = FMath::Clamp(Spec.Cells, 2, CHUNK_SIZE); const int32 CPA = FMath::Clamp(Spec.Cells, 2, CHUNK_SIZE);
const int32 GridDim = CPA + 1; const int32 VertexCount = CPA + 1;
const bool bClaimsSolid = (Verdict == EVoxelTileClass::AllSolid); const bool bClaimsSolid = (Verdict == EVoxelTileClass::AllSolid);
bool bTileBad = false; bool bTileBad = false;
for (int32 gz = -1; gz <= GridDim && !bTileBad; ++gz) for (int32 gz = 0; gz < VertexCount && !bTileBad; ++gz)
for (int32 gy = -1; gy <= GridDim && !bTileBad; ++gy) for (int32 gy = 0; gy < VertexCount && !bTileBad; ++gy)
for (int32 gx = -1; gx <= GridDim && !bTileBad; ++gx) for (int32 gx = 0; gx < VertexCount && !bTileBad; ++gx)
{ {
const float X = (float)(Spec.Origin.X + gx * Spec.Step); const float X = (float)(Spec.Origin.X + gx * Spec.Step);
const float Y = (float)(Spec.Origin.Y + gy * Spec.Step); const float Y = (float)(Spec.Origin.Y + gy * Spec.Step);
@@ -199,8 +203,8 @@ bool FVoxelForgeClassifyTileTest::RunTest(const FString& Parameters)
TEXT("HOLE: ClassifyTile said %s for tile origin (%d,%d,%d) Step=%d Cells=%d, ") TEXT("HOLE: ClassifyTile said %s for tile origin (%d,%d,%d) Step=%d Cells=%d, ")
TEXT("but GetDensityAt(%.0f, %.0f, %.0f) = %.6g is on the %s side. This tile ") TEXT("but GetDensityAt(%.0f, %.0f, %.0f) = %.6g is on the %s side. This tile ")
TEXT("would be skipped by the mesher: no triangles and NO COLLISION where there ") TEXT("would be skipped by the mesher: no triangles and NO COLLISION where there ")
TEXT("should be a surface. Find which guard in ClassifyTile failed to fire for ") TEXT("should be a surface. This point is inside ClassifyTile's actual cell ")
TEXT("the feature at that point."), TEXT("lattice, so find which classifier guard failed to fire for the feature."),
bClaimsSolid ? TEXT("AllSolid") : TEXT("AllAir"), bClaimsSolid ? TEXT("AllSolid") : TEXT("AllAir"),
Spec.Origin.X, Spec.Origin.Y, Spec.Origin.Z, Spec.Step, Spec.Cells, Spec.Origin.X, Spec.Origin.Y, Spec.Origin.Z, Spec.Step, Spec.Cells,
X, Y, Z, D, (D >= 0.0f) ? TEXT("AIR") : TEXT("SOLID"))); X, Y, Z, D, (D >= 0.0f) ? TEXT("AIR") : TEXT("SOLID")));
@@ -336,13 +340,13 @@ bool FVoxelForgeOpStackClassifyTileTest::RunTest(const FString& Parameters)
if (Verdict == EVoxelTileClass::Mixed) { continue; } if (Verdict == EVoxelTileClass::Mixed) { continue; }
const int32 CPA = FMath::Clamp(Spec.Cells, 2, CHUNK_SIZE); const int32 CPA = FMath::Clamp(Spec.Cells, 2, CHUNK_SIZE);
const int32 GridDim = CPA + 1; const int32 VertexCount = CPA + 1;
const bool bClaimsSolid = (Verdict == EVoxelTileClass::AllSolid); const bool bClaimsSolid = (Verdict == EVoxelTileClass::AllSolid);
bool bTileBad = false; bool bTileBad = false;
for (int32 gz = -1; gz <= GridDim && !bTileBad; ++gz) for (int32 gz = 0; gz < VertexCount && !bTileBad; ++gz)
for (int32 gy = -1; gy <= GridDim && !bTileBad; ++gy) for (int32 gy = 0; gy < VertexCount && !bTileBad; ++gy)
for (int32 gx = -1; gx <= GridDim && !bTileBad; ++gx) for (int32 gx = 0; gx < VertexCount && !bTileBad; ++gx)
{ {
const float X = (float)(Spec.Origin.X + gx * Spec.Step); const float X = (float)(Spec.Origin.X + gx * Spec.Step);
const float Y = (float)(Spec.Origin.Y + gy * Spec.Step); const float Y = (float)(Spec.Origin.Y + gy * Spec.Step);
@@ -178,11 +178,119 @@ namespace
return true; return true;
} }
class FGraphReservedFloorOracle
{
public:
explicit FGraphReservedFloorOracle(const UVoxelStrateManager& InManager)
: Manager(InManager)
{
}
bool IsReservedFloor(const FVector& Point)
{
const FIntVector ChunkCoord(
FMath::FloorToInt(Point.X / static_cast<float>(CHUNK_SIZE)),
FMath::FloorToInt(Point.Y / static_cast<float>(CHUNK_SIZE)),
FMath::FloorToInt(Point.Z / static_cast<float>(CHUNK_SIZE)));
if (Manager.IsGapChunk(ChunkCoord))
{
return false;
}
const ECaveGeneratorType GeneratorType =
Manager.GetGeneratorTypeForChunk(ChunkCoord);
if (GeneratorType != ECaveGeneratorType::TunnelNetwork
&& GeneratorType != ECaveGeneratorType::Underwater)
{
return false;
}
FChunkSDFCache* Cache = CacheFor(ChunkCoord);
if (Cache == nullptr)
{
return false;
}
FTunnelSupportFloorColumn SupportColumn;
const FTunnelSupportFloorColumn* SupportColumnPtr = nullptr;
const bool bIntegerXY =
Point.X == FMath::FloorToFloat(Point.X)
&& Point.Y == FMath::FloorToFloat(Point.Y);
if (bIntegerXY)
{
VoxelCaveMorphology::BuildTunnelSupportFloorColumn(
Point.X, Point.Y, *Cache, SupportColumn, /*bUseSpatialIndex=*/false);
SupportColumnPtr = &SupportColumn;
}
// This is the same public morphology query used by the generator's structural
// protection bit. A graph-owned room/tunnel floor is a reserved walking route: the
// inter-strate passage may join it, but must not carve its finite support band away.
const FTunnelCoreWorldEvaluation Evaluation =
VoxelCaveMorphology::EvaluateTunnelCoreWorld(
Point.X, Point.Y, Point.Z, *Cache, SupportColumnPtr,
/*bUseSpatialIndex=*/false);
return Evaluation.bSupportFloor || Evaluation.bRoomFloor;
}
private:
struct FCacheEntry
{
FIntVector Chunk = FIntVector::ZeroValue;
FChunkSDFCache Cache;
};
FChunkSDFCache* CacheFor(const FIntVector& ChunkCoord)
{
for (FCacheEntry& Entry : Caches)
{
if (Entry.Chunk == ChunkCoord)
{
return &Entry.Cache;
}
}
UVoxelStrateDefinition* Definition = Manager.GetStrateForChunk(ChunkCoord);
if (Definition == nullptr)
{
return nullptr;
}
const FStrateGenerationParams Params = Manager.GetGenerationParams(ChunkCoord);
const float ChunkMinX = static_cast<float>(ChunkCoord.X * CHUNK_SIZE);
const float ChunkMinY = static_cast<float>(ChunkCoord.Y * CHUNK_SIZE);
const float ChunkMaxX = ChunkMinX + static_cast<float>(CHUNK_SIZE);
const float ChunkMaxY = ChunkMinY + static_cast<float>(CHUNK_SIZE);
const float Expansion = FMath::Abs(Params.CaveWarpStrength)
* VOXEL_NOISE_SCALE * 1.5f + 2.0f;
const int32 StrateIndex = Manager.GetStrateIndex(
(static_cast<float>(ChunkCoord.Z) + 0.5f)
* static_cast<float>(CHUNK_SIZE) * VOXEL_SIZE);
FCacheEntry& NewEntry = Caches.Emplace_GetRef();
NewEntry.Chunk = ChunkCoord;
VoxelCaveMorphology::BuildChunkCache(
NewEntry.Cache,
ChunkMinX - Expansion, ChunkMinY - Expansion,
ChunkMaxX + Expansion, ChunkMaxY + Expansion,
Params, static_cast<uint32>(Manager.GetWorldSeed()), StrateIndex,
&Definition->TerrainOperations,
ERoomGraphBuildSite::GeneratorTunnelCore);
return &NewEntry.Cache;
}
const UVoxelStrateManager& Manager;
TArray<FCacheEntry> Caches;
};
bool FinalDensityCapsuleFits( bool FinalDensityCapsuleFits(
const UVoxelGenerator& Generator, const UVoxelGenerator& Generator,
const FVector& Centreline, const FVector& Centreline,
float SupportFloorZ) float SupportFloorZ,
FGraphReservedFloorOracle* GraphFloorOracle,
int32& OutReservedGraphFloorSamples)
{ {
OutReservedGraphFloorSamples = 0;
constexpr float Radius = VoxelPassageGeometry::PlayerRadiusVoxels; constexpr float Radius = VoxelPassageGeometry::PlayerRadiusVoxels;
constexpr float HalfHeight = VoxelPassageGeometry::PlayerHalfHeightVoxels; constexpr float HalfHeight = VoxelPassageGeometry::PlayerHalfHeightVoxels;
constexpr int32 MaxHorizontalOffset = 2; constexpr int32 MaxHorizontalOffset = 2;
@@ -213,10 +321,23 @@ namespace
Centreline.X + static_cast<float>(OffsetX), Centreline.X + static_cast<float>(OffsetX),
Centreline.Y + static_cast<float>(OffsetY), Centreline.Y + static_cast<float>(OffsetY),
SupportFloorZ + static_cast<float>(Row) + 0.5f); SupportFloorZ + static_cast<float>(Row) + 0.5f);
if (!FMath::IsFinite(Density) || !(Density > 0.0f)) if (!FMath::IsFinite(Density))
{ {
return false; return false;
} }
if (!(Density > 0.0f))
{
const bool bReservedGraphFloor = GraphFloorOracle != nullptr
&& GraphFloorOracle->IsReservedFloor(FVector(
Centreline.X + static_cast<float>(OffsetX),
Centreline.Y + static_cast<float>(OffsetY),
SupportFloorZ + static_cast<float>(Row) + 0.5f));
if (!bReservedGraphFloor)
{
return false;
}
++OutReservedGraphFloorSamples;
}
} }
} }
@@ -226,10 +347,22 @@ namespace
const float Density = Generator.GetDensityAt( const float Density = Generator.GetDensityAt(
Centreline.X, Centreline.Y, Centreline.X, Centreline.Y,
SupportFloorZ + static_cast<float>(Row) + 0.5f); SupportFloorZ + static_cast<float>(Row) + 0.5f);
if (!FMath::IsFinite(Density) || !(Density > 0.0f)) if (!FMath::IsFinite(Density))
{ {
return false; return false;
} }
if (!(Density > 0.0f))
{
const bool bReservedGraphFloor = GraphFloorOracle != nullptr
&& GraphFloorOracle->IsReservedFloor(FVector(
Centreline.X, Centreline.Y,
SupportFloorZ + static_cast<float>(Row) + 0.5f));
if (!bReservedGraphFloor)
{
return false;
}
++OutReservedGraphFloorSamples;
}
} }
} }
return true; return true;
@@ -246,6 +379,7 @@ namespace
int32 RouteGradientFailures = 0; int32 RouteGradientFailures = 0;
int32 FloorFailures = 0; int32 FloorFailures = 0;
int32 CapsuleFailures = 0; int32 CapsuleFailures = 0;
int32 ReservedGraphFloorSamples = 0;
float WorstGradient = 0.0f; float WorstGradient = 0.0f;
float WorstGeometricGradient = 0.0f; float WorstGeometricGradient = 0.0f;
float WorstPatchGradient = 0.0f; float WorstPatchGradient = 0.0f;
@@ -264,6 +398,7 @@ namespace
void AuditWalkableTunnel( void AuditWalkableTunnel(
const UVoxelGenerator& Generator, const UVoxelGenerator& Generator,
const FVoxelPassage& Passage, const FVoxelPassage& Passage,
FGraphReservedFloorOracle& GraphFloorOracle,
FWalkableTunnelAudit& InOutAudit) FWalkableTunnelAudit& InOutAudit)
{ {
++InOutAudit.Contracts; ++InOutAudit.Contracts;
@@ -400,8 +535,10 @@ namespace
const float FinalSupportFloor = FMath::Max( const float FinalSupportFloor = FMath::Max(
SupportFloor, SupportFloorWithY); SupportFloor, SupportFloorWithY);
++InOutAudit.CapsuleSamples; ++InOutAudit.CapsuleSamples;
int32 ReservedGraphFloorSamples = 0;
if (!FinalDensityCapsuleFits( if (!FinalDensityCapsuleFits(
Generator, Centre, FinalSupportFloor)) Generator, Centre, FinalSupportFloor,
&GraphFloorOracle, ReservedGraphFloorSamples))
{ {
++InOutAudit.CapsuleFailures; ++InOutAudit.CapsuleFailures;
RecordTunnelFailure(InOutAudit, FString::Printf( RecordTunnelFailure(InOutAudit, FString::Printf(
@@ -409,6 +546,7 @@ namespace
Passage.UpperStrateIndex, Passage.LowerStrateIndex, Passage.UpperStrateIndex, Passage.LowerStrateIndex,
SegmentIndex, SampleIndex)); SegmentIndex, SampleIndex));
} }
InOutAudit.ReservedGraphFloorSamples += ReservedGraphFloorSamples;
if (bHavePrevious) if (bHavePrevious)
{ {
const float RouteHorizontal = FVector2D( const float RouteHorizontal = FVector2D(
@@ -554,8 +692,8 @@ bool FVoxelForgePassageLandsInOpenSpaceTest::RunTest(const FString& Parameters)
} }
// The upper mouth has its own source query too. This is deliberately evaluated from the // The upper mouth has its own source query too. This is deliberately evaluated from the
// upper strate's definition, seed, bounds, and requested XY; it must never inherit the // upper strate's definition, room seed, production world/warp seed, bounds, and requested
// lower mouth's answer or become an implicit passage chain. // XY; it must never inherit the lower mouth's answer or become an implicit passage chain.
const float SourceTopZ = (float)(Source.TopChunkZ + 1) * CHUNK_SIZE; const float SourceTopZ = (float)(Source.TopChunkZ + 1) * CHUNK_SIZE;
const float SourceBottomZ = (float)Source.BottomChunkZ * CHUNK_SIZE; const float SourceBottomZ = (float)Source.BottomChunkZ * CHUNK_SIZE;
const int32 SourceQuerySeed = OpenPointSeedFor( const int32 SourceQuerySeed = OpenPointSeedFor(
@@ -575,7 +713,8 @@ bool FVoxelForgePassageLandsInOpenSpaceTest::RunTest(const FString& Parameters)
Passage.RequestedUpperPoint.X, Passage.RequestedUpperPoint.X,
Passage.RequestedUpperPoint.Y, Passage.RequestedUpperPoint.Y,
SourceMaxLateralSnap, SourceMaxLateralSnap,
SuggestedUpperPoint); SuggestedUpperPoint,
WorldSeed);
if (!bCanAnswerUpper) if (!bCanAnswerUpper)
{ {
++NumUpperQueryFalse; ++NumUpperQueryFalse;
@@ -652,7 +791,8 @@ bool FVoxelForgePassageLandsInOpenSpaceTest::RunTest(const FString& Parameters)
DesiredPoint.X, DesiredPoint.X,
DesiredPoint.Y, DesiredPoint.Y,
MaxLateralSnap, MaxLateralSnap,
SuggestedPoint); SuggestedPoint,
WorldSeed);
if (!bCanAnswer) if (!bCanAnswer)
{ {
@@ -1087,14 +1227,19 @@ bool FVoxelForgePassageLandsInOpenSpaceTest::RunTest(const FString& Parameters)
// The landing checks above prove the two endpoints. This separate audit proves the default // The landing checks above prove the two endpoints. This separate audit proves the default
// inter-strate connection itself: every final-density floor sample is bracketed, the exact // inter-strate connection itself: every final-density floor sample is bracketed, the exact
// player capsule stencil fits above it, and the support path never exceeds the named gentle // player capsule stencil fits above it, and the support path never exceeds the named gentle
// gradient. It intentionally audits only the default contract; legacy exotic styles retain // gradient. A capsule sample may overlap the graph's finite, build-authored support floor;
// their descriptors without receiving a false walkability promise. // that is an intentional reserved-walk hand-off, not a passage hole. The passage is forbidden
// to cut that graph floor, so those exact morphology-owned samples are allowed below while any
// other obstruction remains a failure. Legacy exotic styles retain their descriptors without
// receiving a false walkability promise.
FGraphReservedFloorOracle GraphFloorOracle(*World.StrateManager);
for (const FVoxelPassage& Passage : Passages) for (const FVoxelPassage& Passage : Passages)
{ {
if (Passage.UpperStrateIndex != Passage.LowerStrateIndex if (Passage.UpperStrateIndex != Passage.LowerStrateIndex
&& Passage.bWalkableTunnelContract) && Passage.bWalkableTunnelContract)
{ {
AuditWalkableTunnel(*World.Generator, Passage, TunnelAudit); AuditWalkableTunnel(
*World.Generator, Passage, GraphFloorOracle, TunnelAudit);
} }
} }
@@ -1187,7 +1332,7 @@ bool FVoxelForgePassageLandsInOpenSpaceTest::RunTest(const FString& Parameters)
AddError(FString::Printf(TEXT("First landing geometry failure: %s"), *FirstLandingFailure)); AddError(FString::Printf(TEXT("First landing geometry failure: %s"), *FirstLandingFailure));
} }
AddInfo(FString::Printf( AddInfo(FString::Printf(
TEXT("Walkable tunnel contract: %d passages, %d segments, %d final floor samples, %d player-capsule samples; gradient failures %d (geometric %d, route %d), floor failures %d, capsule failures %d, worst gradient %.6f (geometric %.6f, route %.6f; cross-section diagnostic %.6f; limit %.6f / %.1f degrees)."), TEXT("Walkable tunnel contract: %d passages, %d segments, %d final floor samples, %d player-capsule samples; gradient failures %d (geometric %d, route %d), floor failures %d, capsule failures %d, graph-reserved capsule samples allowed %d, worst gradient %.6f (geometric %.6f, route %.6f; cross-section diagnostic %.6f; limit %.6f / %.1f degrees)."),
TunnelAudit.Contracts, TunnelAudit.Contracts,
TunnelAudit.Segments, TunnelAudit.Segments,
TunnelAudit.FloorSamples, TunnelAudit.FloorSamples,
@@ -1197,6 +1342,7 @@ bool FVoxelForgePassageLandsInOpenSpaceTest::RunTest(const FString& Parameters)
TunnelAudit.RouteGradientFailures, TunnelAudit.RouteGradientFailures,
TunnelAudit.FloorFailures, TunnelAudit.FloorFailures,
TunnelAudit.CapsuleFailures, TunnelAudit.CapsuleFailures,
TunnelAudit.ReservedGraphFloorSamples,
TunnelAudit.WorstGradient, TunnelAudit.WorstGradient,
TunnelAudit.WorstGeometricGradient, TunnelAudit.WorstGeometricGradient,
TunnelAudit.WorstRouteGradient, TunnelAudit.WorstRouteGradient,
+7 -1
View File
@@ -2760,8 +2760,14 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
float Density = 8.0f; // bedrock solidity (positive = solid) float Density = 8.0f; // bedrock solidity (positive = solid)
StrateManager->ApplyPassageModifier( StrateManager->ApplyPassageModifier(
Density, WorldX, WorldY, WorldZ, 8.0f, 0.0f); Density, WorldX, WorldY, WorldZ, 8.0f, 0.0f);
VF_ApplyXYEdgeSeal(Density, WorldX, WorldY, WorldRadiusVoxels, EdgeSealThickness, 8.0f); // Gap chunks use the compact bedrock path above instead of the ordinary strate tail.
// Native walkable passages still cross those chunks, so compose their build-authored
// D-floor here as well; otherwise the floor disappears exactly at the gap/strate seam.
Result = -Density; Result = -Density;
StrateManager->ApplyPassageNativeFloorMC(
Result, WorldX, WorldY, WorldZ, 8.0f);
VF_ApplyXYEdgeSealMC(
Result, WorldX, WorldY, WorldRadiusVoxels, EdgeSealThickness, 8.0f);
} }
else if (StrateManager) else if (StrateManager)
{ {