fix(morphology): BuildChunkCache under-bounds room/tunnel collection when Min > Max
Third instance of the same class, and the worst one -- found by the Sol-High
read-only audit (VF-05) and verified against the code before acting.
MaxInfluence, RoomZBuffer and EvaluateSDF's Margin all derive from
MaxRoomRadius / TunnelMaxRadius, while the radii are Lerp(Min, Max, hash), which
yields up to max(Min, Max). A room able to reach a chunk can therefore sit in a
cell the collect region never visited.
Worse than the two fixed earlier today because:
- it is TunnelNetwork, the largest archetype;
- BuildChunkCache is called by BOTH density paths (FRoomGraphSource calls it
rather than transcribing it), so this was never an op-stack bug -- it is in
the shipped original code and always has been;
- the failure mode is a window-invariance break (ARCHITECTURE 8.4): whether a
room exists depends on which chunk you queried from, which in multiplayer
means two peers generate different geometry from the same seed.
Four bound sites now use RoomRadiusEnvelope / TunnelRadiusEnvelope; the two
duplicated copies of the formula still compute the identical expression. No
Lerp, placement, hash or bStore line changed -- with correctly ordered params
max(Min,Max) == Max, so this is bit-identical. A no-op at correct values is the
acceptance signal.
Also adds a reviewer's header to AUDIT-2026-08-CODEX.md marking which findings I
verified (VF-05 confirmed, VF-02 premise confirmed, VF-03 evidence overstated --
its cited fixture corroboration does not exist) and which are unverified leads.
Not built -- Jahni builds.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -124,9 +124,13 @@ void VoxelCaveMorphology::BuildChunkCache(
|
||||
// MaxInfluence = how far a room body / tunnel TUBE reaches PERPENDICULAR to its
|
||||
// anchor — NOT its length. A room or tunnel whose anchor lies within MaxInfluence
|
||||
// of a box can touch a voxel inside that box.
|
||||
// Envelope conservatif / conservative bound: Lerp accepts inverted endpoints,
|
||||
// so max(Min, Max) covers either radius without changing the authored roll.
|
||||
const float RoomRadiusEnvelope = FMath::Max(Params.MinRoomRadius, Params.MaxRoomRadius);
|
||||
const float TunnelRadiusEnvelope = FMath::Max(Params.TunnelMinRadius, Params.TunnelMaxRadius);
|
||||
const float MaxInfluence = FMath::Max(
|
||||
Params.MaxRoomRadius,
|
||||
Params.TunnelWarpStrength + Params.TunnelMaxRadius
|
||||
RoomRadiusEnvelope,
|
||||
Params.TunnelWarpStrength + TunnelRadiusEnvelope
|
||||
) + Params.SDFBlendRadius;
|
||||
|
||||
const float MaxTunnelLen = FMath::Max(Params.MaxTunnelLength, 0.0f);
|
||||
@@ -165,10 +169,10 @@ void VoxelCaveMorphology::BuildChunkCache(
|
||||
// Vertical range for room CENTER placement.
|
||||
//=========================================================================
|
||||
// Buffer = seal thickness + max room half-height.
|
||||
// This guarantees the tallest possible room (MaxRoomRadius * RoomHeightRatio)
|
||||
// This guarantees the tallest possible room (RoomRadiusEnvelope * RoomHeightRatio)
|
||||
// fits entirely within the seal boundary — no room gets its ceiling or floor
|
||||
// cut flat by the seal. Smaller rooms have proportionally more margin.
|
||||
const float RoomZBuffer = Params.MaxRoomRadius * Params.RoomHeightRatio;
|
||||
const float RoomZBuffer = RoomRadiusEnvelope * Params.RoomHeightRatio;
|
||||
const float StrateMinZ = Params.StrateBottomWorldZ + Params.BoundarySealThickness + RoomZBuffer;
|
||||
const float StrateMaxZ = Params.StrateTopWorldZ - Params.BoundarySealThickness - RoomZBuffer;
|
||||
const float StrateRangeZ = StrateMaxZ - StrateMinZ;
|
||||
@@ -868,9 +872,11 @@ float VoxelCaveMorphology::EvaluateSDF(
|
||||
const FStrateGenerationParams& Params,
|
||||
uint32 Seed, int32 StrateIndex)
|
||||
{
|
||||
const float RoomRadiusEnvelope = FMath::Max(Params.MinRoomRadius, Params.MaxRoomRadius);
|
||||
const float TunnelRadiusEnvelope = FMath::Max(Params.TunnelMinRadius, Params.TunnelMaxRadius);
|
||||
const float Margin = FMath::Max(
|
||||
Params.MaxRoomRadius,
|
||||
Params.TunnelWarpStrength + Params.TunnelMaxRadius
|
||||
RoomRadiusEnvelope,
|
||||
Params.TunnelWarpStrength + TunnelRadiusEnvelope
|
||||
) + Params.SDFBlendRadius;
|
||||
|
||||
FChunkSDFCache TempCache;
|
||||
|
||||
Reference in New Issue
Block a user