wip(assembler): round L24 -- per-strate passage styles; natural Worm default; FI anchor island

Core plans inter-strate passages from each upper strate's FStratePassageConfig for every
generator: Straight / Worm (the new natural default: meander, variable radius, rough walls) /
Spiral / Cascading. A naturalness audit (no >8 m flat runs, >=0.20 m wall relief) fails on L23's
smooth tube. FloatingIslands selects Spiral, with a deterministic unique anchor island (ordinal 2)
joined to the bedrock floor by a rock root. The SW arrival no longer stamps flat shelves.
Capsule audits 0 blocked / 0 unsupported / 0 grade failures, all styles. Full-view hashes
deterministic W1/W8/W12, Clang = GCC (reviewer re-run). Evaluator 10, FI geometry 5.
KNOWN: the FI helix renders as a spiral ribbon in open air around the pillar instead of a tunnel
enclosed in rock; fix next round. Unreal edits uncompiled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-20 21:42:21 +02:00
1 parent 71d09a8c52
commit cb9236c265
17 files changed
+922 -122

No files matched your search

+155 -57
View File
@@ -107,6 +107,66 @@ public:
const double floorThicknessVoxels=qPerMetre/Q;
const double playerCenterAboveFloorQ=1.13*qPerMetre;
float composed=density;
const auto composeRouteMouthSupport=[&](std::int32_t strateIndex,
const std::array<std::int64_t,3>& mouth,bool departure)
{
const double mouthDx=qx-static_cast<double>(mouth[0]);
const double mouthDy=qy-static_cast<double>(mouth[1]);
const double routeSupportReach=13.0*qPerMetre;
if(mouthDx*mouthDx+mouthDy*mouthDy>routeSupportReach*routeSupportReach)return;
const auto stratum=std::find_if(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[strateIndex](const auto& value)
{return value.strateIndex==strateIndex;});
if(stratum==ResolvedLayout->strates.end())return;
std::array<const VoxelForgeCore::ResolvedLayoutAnchorV2*,5> route{};
std::size_t routeCount=0;
for(const auto& anchor:stratum->anchors)
if(anchor.kind=="route_point"&&anchor.values.size()>=3)
{
if(departure)
{
if(routeCount<route.size())route[routeCount++]=&anchor;
else
{
std::move(route.begin()+1,route.end(),route.begin());
route.back()=&anchor;
}
}
else if(routeCount<route.size())route[routeCount++]=&anchor;
}
if(routeCount<2)return;
const std::size_t lastSegment=routeCount-1;
const double floorThickness=1000000.0/std::max<std::uint32_t>(1,
ResolvedLayout->coreVoxelSizeMicrometres);
for(std::size_t index=0;index<lastSegment;++index)
{
const auto& a=*route[index];const auto& b=*route[index+1];
const double dx=static_cast<double>(b.values[0]-a.values[0]);
const double dy=static_cast<double>(b.values[1]-a.values[1]);
const double lengthSq=dx*dx+dy*dy;
const double t=lengthSq>0.0?std::clamp(((qx-a.values[0])*dx
+(qy-a.values[1])*dy)/lengthSq,0.0,1.0):0.0;
const double centerX=a.values[0]+t*dx,centerY=a.values[1]+t*dy;
const double centerZ=a.values[2]+t*(static_cast<double>(b.values[2])-a.values[2]);
const double routeRadius=a.values.size()>=4
?a.values[3]+t*(static_cast<double>(b.values[3])-a.values[3]):0.0;
const double halfWidth=std::max(0.75*qPerMetre,routeRadius);
const double horizontalX=qx-centerX,horizontalY=qy-centerY;
if(horizontalX*horizontalX+horizontalY*horizontalY>halfWidth*halfWidth)continue;
const double floorVoxels=(centerZ-1.20*qPerMetre)/Q;
if(Z<floorVoxels-floorThickness||Z>floorVoxels+1.0/Q)continue;
composed=std::min(composed,static_cast<float>(
std::clamp(Z-floorVoxels,-floorThickness,0.0)));
}
};
// Seed the route floor first. The bore carve below reopens any overlap at the
// mouth, then applies its own lower tread, so neither shape blocks the capsule.
for(const auto& passage:ResolvedLayout->passages)
{
composeRouteMouthSupport(passage.upperStrateIndex,passage.upperMouthSubvoxels,true);
// The lower mouth emerges into its native terrain. Keep the passage tread
// support, but do not stamp short, flat route-anchor shelves over that cave mouth.
}
for(const auto& passage:ResolvedLayout->passages)
{
if(passage.controlPoints.size()<2)continue;
@@ -125,16 +185,25 @@ public:
const std::ptrdiff_t lowerMouthIndex=std::clamp<std::ptrdiff_t>(
static_cast<std::ptrdiff_t>(passage.lowerMouthControlIndex),1,lastIndex);
const auto mainEnd=passage.controlPoints.begin()+lowerMouthIndex+1;
const auto carveFound=std::lower_bound(passage.controlPoints.begin(),mainEnd,qz,
// The tube radius is measured from its centerline, while floorProfile is
// one player-center offset away. Search the full vertical radius of the SDF;
// a narrow point window misses earlier turns of a low-pitch helix.
const double carveSearchMargin=std::max(passage.mouthRadiusSubvoxels,
passage.midRadiusSubvoxels)+0.25*qPerMetre;
const auto carveHigh=std::lower_bound(passage.controlPoints.begin(),mainEnd,
qz+carveSearchMargin,
[&](const auto& point,double value){return floorProfile(point)>value;});
const std::ptrdiff_t carveCenter=carveFound-passage.controlPoints.begin();
const std::ptrdiff_t carveBegin=std::max<std::ptrdiff_t>(0,carveCenter-3);
const std::ptrdiff_t carveEnd=std::min<std::ptrdiff_t>(lowerMouthIndex-1,carveCenter+2);
const auto carveLow=std::lower_bound(passage.controlPoints.begin(),mainEnd,
qz-carveSearchMargin,
[&](const auto& point,double value){return floorProfile(point)>value;});
const std::ptrdiff_t carveBegin=std::max<std::ptrdiff_t>(0,
(carveHigh-passage.controlPoints.begin())-1);
const std::ptrdiff_t carveEnd=std::min<std::ptrdiff_t>(lowerMouthIndex-1,
(carveLow-passage.controlPoints.begin())+1);
double bestSignedDistance=std::numeric_limits<double>::infinity();
double bestT=0.0;
std::ptrdiff_t bestIndex=0;
bool hasSupportFloor=false;
double bestSupportFloorVoxels=-std::numeric_limits<double>::infinity();
double bestSupportDensity=0.0;
const auto considerCarveSegment=[&](std::ptrdiff_t index)
{
@@ -164,65 +233,94 @@ public:
for(std::ptrdiff_t index=lowerMouthIndex;index<lastIndex;++index)
considerCarveSegment(index);
if(!std::isfinite(bestSignedDistance))continue;
// Positive density is air; the passage SDF is applied after both owner bands.
composed=std::max(composed,static_cast<float>(-bestSignedDistance/Q));
const auto& nearestA=passage.controlPoints[static_cast<std::size_t>(bestIndex)];
const auto& nearestB=passage.controlPoints[static_cast<std::size_t>(bestIndex+1)];
const double nearestRadius=nearestA.radiusSubvoxels+bestT*(
static_cast<double>(nearestB.radiusSubvoxels)-nearestA.radiusSubvoxels);
const double nearestPlayerCenterZ=nearestA.positionSubvoxels[2]+bestT*(
const double nearestDx=static_cast<double>(nearestB.positionSubvoxels[0])
-nearestA.positionSubvoxels[0];
const double nearestDy=static_cast<double>(nearestB.positionSubvoxels[1])
-nearestA.positionSubvoxels[1];
const double nearestHorizontalSq=nearestDx*nearestDx+nearestDy*nearestDy;
const double supportPathT=nearestHorizontalSq>0.0
?std::clamp(((qx-nearestA.positionSubvoxels[0])*nearestDx
+(qy-nearestA.positionSubvoxels[1])*nearestDy)/nearestHorizontalSq,0.0,1.0)
:bestT;
const double supportPathRadius=nearestA.radiusSubvoxels+supportPathT*(
static_cast<double>(nearestB.radiusSubvoxels)-nearestA.radiusSubvoxels);
const double supportPathPlayerCenterZ=nearestA.positionSubvoxels[2]+supportPathT*(
static_cast<double>(nearestB.positionSubvoxels[2])-nearestA.positionSubvoxels[2])
-nearestRadius+playerCenterAboveFloorQ;
// Only compose a support shelf below the capsule feet. This keeps support
// probes on the matching floor while capsule samples remain air at bends.
if(qz<nearestPlayerCenterZ-0.90*qPerMetre)
-supportPathRadius+playerCenterAboveFloorQ;
const double nearestPlayerCenterZ=supportPathPlayerCenterZ;
const double distanceToCenter=std::max(1.0e-9,bestSignedDistance+nearestRadius);
const double verticalWallAlignment=distanceToCenter>1.0e-9
?std::clamp(-(qz-(nearestA.positionSubvoxels[2]+bestT*(
static_cast<double>(nearestB.positionSubvoxels[2])-nearestA.positionSubvoxels[2])))
/distanceToCenter,0.0,1.0):0.0;
const float relief=VF_FieldSurfaceRelief(static_cast<float>(X),static_cast<float>(Y),
static_cast<float>(Z),static_cast<std::uint32_t>(Owner?Owner->Seed:0));
const double wallReliefWeight=1.0-0.80*verticalWallAlignment;
const double roughSignedDistance=bestSignedDistance
+static_cast<double>(std::clamp(relief,-1.0f,1.0f))*0.24*qPerMetre*wallReliefWeight;
// Positive density is air; rough rock is cut with full side/ceiling detail and
// gentler relief on the gravity-facing wall so the supported tread stays open.
composed=std::max(composed,static_cast<float>(-roughSignedDistance/Q));
// At tight bends, keep the tread tied to the player-center profile selected
// by horizontal path position so vertical probe offsets cannot shift the ramp.
const bool fallbackSupport=qz>=nearestPlayerCenterZ-1.50*qPerMetre;
const double supportThicknessVoxels=fallbackSupport
?qPerMetre/Q:0.5*qPerMetre/Q;
double bestSupportDistanceSquared=std::numeric_limits<double>::infinity();
const auto considerSupportSegment=[&](std::ptrdiff_t index)
{
const double supportCenterQueryQ=qz+playerCenterAboveFloorQ;
const auto supportFound=std::lower_bound(passage.controlPoints.begin(),
mainEnd,supportCenterQueryQ,
[&](const auto& point,double value){return floorProfile(point)>value;});
const std::ptrdiff_t supportCenter=supportFound-passage.controlPoints.begin();
const std::ptrdiff_t supportBegin=std::max<std::ptrdiff_t>(0,supportCenter-3);
const std::ptrdiff_t supportEnd=std::min<std::ptrdiff_t>(lowerMouthIndex-1,supportCenter+2);
const auto considerSupportSegment=[&](std::ptrdiff_t index)
const auto& segmentA=passage.controlPoints[static_cast<std::size_t>(index)];
const auto& segmentB=passage.controlPoints[static_cast<std::size_t>(index+1)];
const double dx=static_cast<double>(segmentB.positionSubvoxels[0])-segmentA.positionSubvoxels[0];
const double dy=static_cast<double>(segmentB.positionSubvoxels[1])-segmentA.positionSubvoxels[1];
const double radiusA=segmentA.radiusSubvoxels;
const double radiusB=segmentB.radiusSubvoxels;
// Keep the tread within the probe band and below the capsule's
// lowest sampled point.
const double floorOffset=0.20;
const double horizontalLengthSq=dx*dx+dy*dy;
const double supportT=horizontalLengthSq>0.0
?std::clamp(((qx-segmentA.positionSubvoxels[0])*dx
+(qy-segmentA.positionSubvoxels[1])*dy)/horizontalLengthSq,0.0,1.0)
:bestT;
const double centerX=segmentA.positionSubvoxels[0]+supportT*dx;
const double centerY=segmentA.positionSubvoxels[1]+supportT*dy;
const double centerZ=segmentA.positionSubvoxels[2]+supportT*(
static_cast<double>(segmentB.positionSubvoxels[2])-segmentA.positionSubvoxels[2]);
const double radius=segmentA.radiusSubvoxels+supportT*(
static_cast<double>(segmentB.radiusSubvoxels)-segmentA.radiusSubvoxels);
const double supportPlayerCenterZ=centerZ-radius+playerCenterAboveFloorQ;
if(fallbackSupport)
{
const auto& segmentA=passage.controlPoints[static_cast<std::size_t>(index)];
const auto& segmentB=passage.controlPoints[static_cast<std::size_t>(index+1)];
const double dx=static_cast<double>(segmentB.positionSubvoxels[0])-segmentA.positionSubvoxels[0];
const double dy=static_cast<double>(segmentB.positionSubvoxels[1])-segmentA.positionSubvoxels[1];
const double horizontalLengthSq=dx*dx+dy*dy;
const double supportT=horizontalLengthSq>0.0
?std::clamp(((qx-segmentA.positionSubvoxels[0])*dx
+(qy-segmentA.positionSubvoxels[1])*dy)/horizontalLengthSq,0.0,1.0)
:bestT;
const double supportCenterX=segmentA.positionSubvoxels[0]+supportT*dx;
const double supportCenterY=segmentA.positionSubvoxels[1]+supportT*dy;
const double supportCenterZ=segmentA.positionSubvoxels[2]+supportT*(
static_cast<double>(segmentB.positionSubvoxels[2])-segmentA.positionSubvoxels[2]);
const double supportRadius=segmentA.radiusSubvoxels+supportT*(
static_cast<double>(segmentB.radiusSubvoxels)-segmentA.radiusSubvoxels);
// Leave a 12 cm settle gap below the capsule feet while staying inside
// the route support probes' search depth.
const double floorQ=supportCenterZ-supportRadius+0.12*qPerMetre;
const double floorVoxels=floorQ/Q;
const double horizontalX=qx-supportCenterX,horizontalY=qy-supportCenterY;
const double horizontalDistance=DeterministicSqrt(horizontalX*horizontalX+horizontalY*horizontalY);
const double supportHalfWidth=std::max(0.0,supportRadius-0.15*qPerMetre);
if(horizontalDistance<=supportHalfWidth&&Z>=floorVoxels-floorThicknessVoxels
&&Z<=floorVoxels+1.0/Q)
{
if(!hasSupportFloor||floorVoxels>bestSupportFloorVoxels)
{
bestSupportFloorVoxels=floorVoxels;hasSupportFloor=true;
bestSupportDensity=std::clamp(Z-floorVoxels,-floorThicknessVoxels,0.0);
}
}
};
for(std::ptrdiff_t index=supportBegin;index<=supportEnd;++index)
considerSupportSegment(index);
for(std::ptrdiff_t index=lowerMouthIndex;index<lastIndex;++index)
considerSupportSegment(index);
}
const double supportProfileError=std::abs(
supportPlayerCenterZ-nearestPlayerCenterZ);
if(supportProfileError>0.06*qPerMetre)return;
}
const double horizontalX=qx-centerX,horizontalY=qy-centerY;
const double horizontalDistance=DeterministicSqrt(horizontalX*horizontalX
+horizontalY*horizontalY);
const double floorQ=centerZ-radius+floorOffset*qPerMetre;
const double floorVoxels=floorQ/Q;
if(Z<floorVoxels-supportThicknessVoxels||Z>floorVoxels+1.0/Q)return;
const double supportHalfWidth=fallbackSupport?radius
:std::max(0.0,radius+2.0*qPerMetre);
if(horizontalDistance>supportHalfWidth)return;
const double supportDistanceSq=horizontalDistance*horizontalDistance
+(Z-floorVoxels)*(Z-floorVoxels);
if(supportDistanceSq>=bestSupportDistanceSquared)return;
bestSupportDistanceSquared=supportDistanceSq;
hasSupportFloor=true;
bestSupportDensity=std::clamp(Z-floorVoxels,
-supportThicknessVoxels,0.0);
};
const std::ptrdiff_t supportBegin=std::max<std::ptrdiff_t>(0,bestIndex-1);
const std::ptrdiff_t supportEnd=std::min<std::ptrdiff_t>(lastIndex-1,bestIndex+1);
for(std::ptrdiff_t index=supportBegin;index<=supportEnd;++index)
considerSupportSegment(index);
if(hasSupportFloor)
composed=std::min(composed,static_cast<float>(bestSupportDensity));
}