core: cave planner holds for 16 seeds; mouth joints planned from the resolved mouth (L135, v236)

Mouth floor/profile carried into the first/last edges (fixes seeds 1 and 2); fixed a Q16/Q32 scale bug in the mouth
clearance scorer; shortest grade-safe handles; bounded cave AABBs and hoisted edge-BVH normalisation. Seeds 0-15 pass
all composed audits and negative controls; fast tier, Clang/GCC W1/W8/W12 green. Near-ready still +3.9..+13.7% vs
assembler/world (Surface World +3.9..+8.2% with no caves). Not for merge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-31 23:39:01 +01:00
1 parent a3c8e3687d
commit 2d89023933
25 files changed
+2516 -235

No files matched your search

+124 -37
View File
@@ -3176,13 +3176,15 @@ namespace StandaloneStreamBenchmark
const auto passageUpperMouthFloorDepth=[&](
const VoxelForgeCore::ResolvedLayoutPassageV1& passage)
{
const double controlZ=qToMetres(
passage.controlPoints.front().positionSubvoxels[2]);
const double authoredMouthDepth=std::max(0.0,controlZ
-qToMetres(passage.upperMouthSubvoxels[2])+1.13);
const auto upperStratum=std::find_if(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[&](const auto& stratum)
{return stratum.strateIndex==passage.upperStrateIndex;});
const double mouthCenterHeight=upperStratum!=ResolvedLayout->strates.end()
&&upperStratum->generatorKind=="SurfaceWorld"?0.98:1.13;
const double controlZ=qToMetres(
passage.controlPoints.front().positionSubvoxels[2]);
const double authoredMouthDepth=std::max(0.0,controlZ
-qToMetres(passage.upperMouthSubvoxels[2])+mouthCenterHeight);
if(upperStratum==ResolvedLayout->strates.end()
||(upperStratum->generatorKind!="FloatingIslands"
&&upperStratum->generatorKind!="TunnelNetwork"))
@@ -3202,7 +3204,8 @@ namespace StandaloneStreamBenchmark
||distanceSquared>std::pow(
qToMetres(passage.controlPoints.front().radiusSubvoxels)+2.0,2.0))
return authoredMouthDepth;
const double routeAlignedDepth=std::max(0.0,controlZ-routeHeight+1.13);
const double routeAlignedDepth=std::max(0.0,
controlZ-routeHeight+mouthCenterHeight);
return std::max(authoredMouthDepth,routeAlignedDepth);
};
const auto passageSplineControls=[&](
@@ -3349,61 +3352,124 @@ namespace StandaloneStreamBenchmark
};
std::vector<double> allPassageBodyFloorDepths;
std::vector<std::vector<FPassageAuditRoutePoint>> allPassageSmoothRoutes;
struct FUpperMouthFloorBlend
struct FMouthFloorBlend
{
std::vector<std::array<double,3>> receivingRoute;
double mouthX=0.0,mouthY=0.0,mouthFloor=0.0;
double tangentX=0.0,tangentY=0.0;
};
std::vector<FUpperMouthFloorBlend> allUpperMouthFloorBlends;
struct FPassageFloorBlends
{
FMouthFloorBlend upper,lower;
};
std::vector<FPassageFloorBlends> allPassageFloorBlends;
allPassageBodyFloorDepths.reserve(ResolvedLayout->passages.size());
allPassageSmoothRoutes.reserve(ResolvedLayout->passages.size());
allUpperMouthFloorBlends.reserve(ResolvedLayout->passages.size());
allPassageFloorBlends.reserve(ResolvedLayout->passages.size());
for(const auto& passage:ResolvedLayout->passages)
{
const double bodyDepth=passageBodyFloorDepth(passage);
allPassageBodyFloorDepths.push_back(bodyDepth);
allPassageSmoothRoutes.push_back(passageSmoothRoute(passage,bodyDepth));
FUpperMouthFloorBlend blend;
FPassageFloorBlends blends;
const auto controls=passageSplineControls(passage);
const auto floorProfile=passageSplineFloorProfile(passage);
const std::size_t routeEnd=std::clamp<std::size_t>(
passage.lowerMouthControlIndex,1,passage.controlPoints.size()-1);
const auto segments=VoxelForgeCore::PassageSpline::BuildSegments(
controls,routeEnd,8.0,1.0,floorProfile,0.100);
const auto upperStratum=std::find_if(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[&](const auto& stratum)
{return stratum.strateIndex==passage.upperStrateIndex;});
if(upperStratum!=ResolvedLayout->strates.end()
&&upperStratum->generatorKind=="FloatingIslands")
&&(upperStratum->generatorKind=="FloatingIslands"
||upperStratum->generatorKind=="TunnelNetwork"))
{
for(const auto& anchor:upperStratum->anchors)
if(anchor.kind=="route_point"&&anchor.values.size()>=3)
blend.receivingRoute.push_back({
blends.upper.receivingRoute.push_back({
qToMetres(anchor.values[0]),qToMetres(anchor.values[1]),
qToMetres(anchor.values[2])});
const auto controls=passageSplineControls(passage);
const auto floorProfile=passageSplineFloorProfile(passage);
const std::size_t routeEnd=std::clamp<std::size_t>(
passage.lowerMouthControlIndex,1,passage.controlPoints.size()-1);
const auto segments=VoxelForgeCore::PassageSpline::BuildSegments(
controls,routeEnd,8.0,1.0,floorProfile,0.100);
if(upperStratum->generatorKind=="TunnelNetwork"
&&blends.upper.receivingRoute.size()>2)
blends.upper.receivingRoute.erase(
blends.upper.receivingRoute.begin(),
blends.upper.receivingRoute.end()-2);
if(!segments.empty())
{
blend.mouthX=segments.front().a[0];
blend.mouthY=segments.front().a[1];
blend.mouthFloor=floorProfile.front();
blend.tangentX=segments.front().b[0]-segments.front().a[0];
blend.tangentY=segments.front().b[1]-segments.front().a[1];
blends.upper.mouthX=controls.front()[0];
blends.upper.mouthY=controls.front()[1];
blends.upper.mouthFloor=floorProfile.front();
blends.upper.tangentX=segments.front().b[0]-segments.front().a[0];
blends.upper.tangentY=segments.front().b[1]-segments.front().a[1];
}
if(upperStratum->generatorKind=="TunnelNetwork")
for(const auto& edge:ResolvedLayout->cavernEdges)
if(edge.startAnchorStableId==passage.stableId+"/upper-mouth"
&&edge.controlPointsMicrometres.size()>=2)
{
blends.upper.tangentX=
(edge.controlPointsMicrometres[0][0]
-edge.controlPointsMicrometres[1][0])/1000000.0;
blends.upper.tangentY=
(edge.controlPointsMicrometres[0][1]
-edge.controlPointsMicrometres[1][1])/1000000.0;
}
}
allUpperMouthFloorBlends.push_back(std::move(blend));
const auto lowerStratum=std::find_if(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[&](const auto& stratum)
{return stratum.strateIndex==passage.lowerStrateIndex;});
if(lowerStratum!=ResolvedLayout->strates.end()
&&lowerStratum->generatorKind=="TunnelNetwork"
&&!controls.empty()&&routeEnd<controls.size())
{
for(const auto& anchor:lowerStratum->anchors)
if(anchor.kind=="route_point"&&anchor.values.size()>=3)
blends.lower.receivingRoute.push_back({
qToMetres(anchor.values[0]),qToMetres(anchor.values[1]),
qToMetres(anchor.values[2])});
if(blends.lower.receivingRoute.size()>2)
blends.lower.receivingRoute.resize(2);
blends.lower.mouthX=controls[routeEnd][0];
blends.lower.mouthY=controls[routeEnd][1];
blends.lower.mouthFloor=floorProfile[routeEnd];
if(!segments.empty())
{
blends.lower.tangentX=controls[routeEnd][0]
-controls[routeEnd-1][0];
blends.lower.tangentY=controls[routeEnd][1]
-controls[routeEnd-1][1];
}
for(const auto& edge:ResolvedLayout->cavernEdges)
if(edge.startAnchorStableId==passage.stableId+"/lower-mouth"
&&edge.controlPointsMicrometres.size()>=2)
{
blends.lower.tangentX=
(edge.controlPointsMicrometres[1][0]
-edge.controlPointsMicrometres[0][0])/1000000.0;
blends.lower.tangentY=
(edge.controlPointsMicrometres[1][1]
-edge.controlPointsMicrometres[0][1])/1000000.0;
}
}
allPassageFloorBlends.push_back(std::move(blends));
}
const auto passageFloorAtXY=[&](std::size_t passageIndex,double x,double y,
double plannedFloor)
{
if(passageIndex>=allUpperMouthFloorBlends.size())return plannedFloor;
const auto& blend=allUpperMouthFloorBlends[passageIndex];
if(passageIndex>=allPassageFloorBlends.size())return plannedFloor;
const auto& blends=allPassageFloorBlends[passageIndex];
double floor=plannedFloor;
floor=VoxelForgeCore::PassageSpline::BlendUpperMouthFloorAtXY(
blends.upper.receivingRoute,x,y,floor,blends.upper.mouthX,
blends.upper.mouthY,blends.upper.mouthFloor,
blends.upper.tangentX,blends.upper.tangentY,
VoxelForgeCore::PassageSpline::UpperMouthFloorBlendRadiusMetres,1.13);
return VoxelForgeCore::PassageSpline::BlendUpperMouthFloorAtXY(
blend.receivingRoute,x,y,plannedFloor,blend.mouthX,blend.mouthY,
blend.mouthFloor,
blend.tangentX,blend.tangentY,
VoxelForgeCore::PassageSpline::UpperMouthFloorBlendRadiusMetres,
1.13);
blends.lower.receivingRoute,x,y,floor,blends.lower.mouthX,
blends.lower.mouthY,blends.lower.mouthFloor,
-blends.lower.tangentX,-blends.lower.tangentY,
VoxelForgeCore::PassageSpline::UpperMouthFloorBlendRadiusMetres,1.13);
};
const auto interpolatePassageRoute=[](
const std::vector<FPassageAuditRoutePoint>& route,double distance)
@@ -4361,7 +4427,8 @@ namespace StandaloneStreamBenchmark
// The probes sit 0.18 m inside the authored radius. Add that
// radius back to the signed wall distance so radius-carried ribs
// remain visible; the cubic detrend removes the smooth mouth flare.
radii.push_back(sampleRadius+0.5*(left+right));
const double measuredRadius=sampleRadius+0.5*(left+right);
radii.push_back(measuredRadius);
++audit.samples;
}
if(radii.size()<static_cast<std::size_t>(WindowLengthMetres/
@@ -4494,6 +4561,18 @@ namespace StandaloneStreamBenchmark
constexpr double PassageShellAuditSpacingMetres=0.25;
constexpr std::array<double,2> PassageShellAuditDepthsMetres{{0.125,0.375}};
constexpr float PassageShellDensityTolerance=1.0e-6f;
std::vector<bool> surfaceLandingPassages(ResolvedLayout->passages.size(),false);
for(std::size_t passageIndex=0;passageIndex<ResolvedLayout->passages.size();
++passageIndex)
{
const auto& passage=ResolvedLayout->passages[passageIndex];
const auto upper=std::find_if(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[&](const auto& stratum)
{return stratum.strateIndex==passage.upperStrateIndex;});
surfaceLandingPassages[passageIndex]=upper!=ResolvedLayout->strates.end()
&&upper->generatorKind=="SurfaceWorld"
&&upper->lowerInterfaceCapabilities.surfaceToTunnelLandingSupport;
}
const auto expectedPassageShellAt=[&](double xMetres,double yMetres,
double zMetres)
{
@@ -4639,7 +4718,17 @@ namespace StandaloneStreamBenchmark
const double floorBlend=std::clamp(floorDistance/0.25,0.0,1.0);
const double smoothFloorBlend=floorBlend*floorBlend
*(3.0-2.0*floorBlend);
const double thickness=0.75*smoothFade*smoothFloorBlend;
double thickness=0.75*smoothFade*smoothFloorBlend;
if(candidatePassage<surfaceLandingPassages.size()
&&surfaceLandingPassages[candidatePassage])
{
const double landingFade=std::clamp(1.0-along/8.0,
0.0,1.0);
const double smoothLandingFade=landingFade*landingFade
*(3.0-2.0*landingFade);
thickness=std::max(thickness,
0.50*smoothLandingFade*smoothFloorBlend);
}
const double shellDistance=std::max(-flatDistance,
flatDistance-thickness);
minimumShellDistance=std::min(minimumShellDistance,
@@ -5137,11 +5226,9 @@ namespace StandaloneStreamBenchmark
{
if(stratum.generatorKind!="TunnelNetwork")
return equalPosition(authored,mouth);
auto expected=mouth;
expected[2]+=static_cast<std::int64_t>(std::llround(
1130000.0*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel
/World.CoreVoxelSizeMicrons));
return equalPosition(authored,expected);
// Passage mouths already encode the player center 1.13 m above
// their floor, matching the route-point convention directly.
return equalPosition(authored,mouth);
};
for(const auto& passage:ResolvedLayout->passages)
{
+4 -1
View File
@@ -1580,10 +1580,13 @@ private:
static_cast<unsigned long long>(D.islandSharedCacheConflictReplacements),
static_cast<double>(D.islandSharedCacheLockWaitNanoseconds)/1000.0);
if(D.passageComposerProfiled)
std::printf("[PassageComposerTile] key=(%d,%d,%d,lod%d) worker_ms=%.3f samples=%llu native_field_calls=%llu features=%llu route_candidates=%llu boundary_band_queries=%llu queries=%llu passage_iterations=%llu carve_segment_visits=%llu relief_field_calls=%llu sweep_segments=%llu sweep_pairs=%llu sweep_prepare_ms=%.3f sweep_outside_pairs=%llu sweep_shell_support_skips=%llu sweep_min_updates=%llu sweep_base_samples=%llu sweep_detail_samples=%llu sweep_grid_samples=%llu sweep_no_influence_samples=%llu sweep_lookups=%llu sweep_cache_hits=%llu sweep_base_hits=%llu sweep_outside_hits=%llu sweep_missing=%llu\n",
std::printf("[PassageComposerTile] key=(%d,%d,%d,lod%d) worker_ms=%.3f samples=%llu field_calls=%llu native_cave_samples=%llu room_candidates=%llu edge_candidates=%llu features=%llu route_candidates=%llu boundary_band_queries=%llu queries=%llu passage_iterations=%llu carve_segment_visits=%llu relief_field_calls=%llu sweep_segments=%llu sweep_pairs=%llu sweep_prepare_ms=%.3f sweep_outside_pairs=%llu sweep_shell_support_skips=%llu sweep_min_updates=%llu sweep_base_samples=%llu sweep_detail_samples=%llu sweep_grid_samples=%llu sweep_no_influence_samples=%llu sweep_lookups=%llu sweep_cache_hits=%llu sweep_base_hits=%llu sweep_outside_hits=%llu sweep_missing=%llu\n",
Event.Key.Coord.X,Event.Key.Coord.Y,Event.Key.Coord.Z,Event.Key.Level,
Event.WorkerMilliseconds,static_cast<unsigned long long>(Event.DensitySamples),
static_cast<unsigned long long>(D.fieldCalls),
static_cast<unsigned long long>(D.nativeCaveFieldSamples),
static_cast<unsigned long long>(D.cavernRoomCandidates),
static_cast<unsigned long long>(D.cavernEdgeCandidates),
static_cast<unsigned long long>(D.passageTileFeatureCount),
static_cast<unsigned long long>(D.passageTileRouteSegmentCandidates),
static_cast<unsigned long long>(D.resolvedBoundaryBandQueries),
+466 -8
View File
@@ -11,9 +11,11 @@
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <functional>
#include <iterator>
#include <limits>
#include <numeric>
#include <queue>
#include <string>
#include <vector>
@@ -283,6 +285,330 @@ namespace StandaloneWorldAssemblyPrototype
}
}
}
std::uint64_t terrainPathCount=0,terrainGridSamples=0;
std::int32_t terrainGridStepQ=0;
const auto appendTerrainFallback=[&](std::int32_t stepQ)
{
if(!fallbackSearch
||!((arrivalRadiusSubvoxels>0)!=(departureRadiusSubvoxels>0)))
return;
{
// A bounded one-mouth world can have no walkable straight chord even
// when a contour route exists. Link real ground columns only when their
// grade meets the same limit, then use the ordinary capsule and support
// sweep to accept or reject each resulting path.
struct FGroundNode
{
std::int64_t ground=0;
bool supportReachable=false;
};
struct FQueueEntry
{
std::uint64_t cost=0;
std::size_t index=0;
bool operator>(const FQueueEntry& other) const
{return cost>other.cost||(cost==other.cost&&index>other.index);}
};
constexpr std::array<std::array<std::int64_t,2>,5> supportOffsets{{
{{0,0}},{{ProbeRadiusQ,0}},{{-ProbeRadiusQ,0}},
{{0,ProbeRadiusQ}},{{0,-ProbeRadiusQ}}}};
constexpr std::int64_t SupportStepQ=WorldAssemblySubvoxelsPerVoxel/4;
const std::int64_t routeBaseLiftQ=constraints.minimumClearanceSubvoxels/4;
const auto hasRouteSupportAt=[&](std::int64_t centerX,std::int64_t centerY,
std::int64_t footZ)
{
std::uint32_t reachable=0;
for(const auto& offset:supportOffsets)
{
for(std::int64_t depth=SupportStepQ;depth<=SupportDepthQ;
depth+=SupportStepQ)
{
if(finalField.point(centerX+offset[0],centerY+offset[1],
footZ-depth).densitySubvoxels<0)
{++reachable;break;}
}
}
return reachable>=constraints.minimumSupportProbes;
};
const auto tryTerrainPaths=[&](std::int32_t terrainStepQ)
{
terrainPathCount=0;terrainGridSamples=0;terrainGridStepQ=0;
const std::int64_t boundedRadius=std::max(arrivalRadiusSubvoxels,
departureRadiusSubvoxels);
const std::int32_t boundRadiusVoxels=static_cast<std::int32_t>(
(boundedRadius+WorldAssemblySubvoxelsPerVoxel-1)
/WorldAssemblySubvoxelsPerVoxel);
const std::int32_t searchRadiusVoxels=std::clamp(
boundRadiusVoxels+64,64,256);
const std::int64_t searchRadiusQ=static_cast<std::int64_t>(
searchRadiusVoxels)*WorldAssemblySubvoxelsPerVoxel;
const std::int32_t radiusSteps=static_cast<std::int32_t>(
searchRadiusQ/terrainStepQ);
const std::int32_t dimension=radiusSteps*2+1;
const std::size_t nodeCount=static_cast<std::size_t>(dimension)*dimension;
const auto indexOf=[dimension](std::int32_t x,std::int32_t y)
{return static_cast<std::size_t>(y)*dimension+x;};
std::vector<FGroundNode> grid(nodeCount);
const auto safeGroundAt=[&](std::int64_t centerX,std::int64_t centerY)
{
constexpr std::int64_t FootprintStepQ=WorldAssemblySubvoxelsPerVoxel/2;
std::int64_t highestGround=std::numeric_limits<std::int64_t>::min();
for(std::int64_t oy=-PlayerRadiusQ;oy<=PlayerRadiusQ;
oy+=FootprintStepQ)
for(std::int64_t ox=-PlayerRadiusQ;ox<=PlayerRadiusQ;
ox+=FootprintStepQ)
{
if(ox*ox+oy*oy>PlayerRadiusQ*PlayerRadiusQ)continue;
highestGround=std::max(highestGround,finalField.point(
centerX+ox,centerY+oy,0).groundHeightSubvoxels);
}
return FGroundNode{highestGround,
hasRouteSupportAt(centerX,centerY,
highestGround+routeBaseLiftQ)};
};
for(std::int32_t gy=0;gy<dimension;++gy)
for(std::int32_t gx=0;gx<dimension;++gx)
{
const std::int64_t xQ=static_cast<std::int64_t>(gx-radiusSteps)
*terrainStepQ;
const std::int64_t yQ=static_cast<std::int64_t>(gy-radiusSteps)
*terrainStepQ;
grid[indexOf(gx,gy)]=safeGroundAt(xQ,yQ);
++terrainGridSamples;
}
for(std::size_t directionIndex=0;directionIndex<1;++directionIndex)
{
std::vector<std::uint64_t> costs(nodeCount,
std::numeric_limits<std::uint64_t>::max());
std::vector<std::size_t> parent(nodeCount,nodeCount);
std::priority_queue<FQueueEntry,std::vector<FQueueEntry>,
std::greater<FQueueEntry>> open;
std::vector<std::int8_t> edgeSupportCache(nodeCount*4,-1);
for(std::int32_t gy=0;gy<dimension;++gy)
for(std::int32_t gx=0;gx<dimension;++gx)
{
if(gx!=0&&gy!=0&&gx!=dimension-1&&gy!=dimension-1)continue;
const std::size_t start=indexOf(gx,gy);
if(!grid[start].supportReachable)continue;
costs[start]=0;
open.push({0,start});
}
if(open.empty())continue;
std::size_t goal=nodeCount;
std::uint64_t goalCost=std::numeric_limits<std::uint64_t>::max();
std::uint64_t goalDistanceSquared=std::numeric_limits<std::uint64_t>::max();
while(!open.empty())
{
const FQueueEntry current=open.top();open.pop();
if(current.cost!=costs[current.index])continue;
if(goalCost!=std::numeric_limits<std::uint64_t>::max()
&&current.cost>goalCost)break;
const std::int32_t gx=static_cast<std::int32_t>(current.index%dimension);
const std::int32_t gy=static_cast<std::int32_t>(current.index/dimension);
if(parent[current.index]!=nodeCount)
{
const std::int64_t xQ=static_cast<std::int64_t>(gx-radiusSteps)
*terrainStepQ;
const std::int64_t yQ=static_cast<std::int64_t>(gy-radiusSteps)
*terrainStepQ;
const std::uint64_t distanceSquared=static_cast<std::uint64_t>(
xQ*xQ+yQ*yQ);
if(distanceSquared<=static_cast<std::uint64_t>(
boundedRadius*boundedRadius)
&&(current.cost<goalCost||(current.cost==goalCost
&&distanceSquared<goalDistanceSquared)))
{goal=current.index;goalCost=current.cost;
goalDistanceSquared=distanceSquared;}
}
for(std::int32_t oy=-1;oy<=1;++oy)
for(std::int32_t ox=-1;ox<=1;++ox)
{
if(ox==0&&oy==0)continue;
const std::int32_t nx=gx+ox,ny=gy+oy;
if(nx<0||ny<0||nx>=dimension||ny>=dimension)continue;
const std::size_t next=indexOf(nx,ny);
if(!grid[next].supportReachable)continue;
const std::int64_t horizontalQ=static_cast<std::int64_t>(
std::llround(terrainStepQ*std::hypot(static_cast<double>(ox),
static_cast<double>(oy))));
const std::int64_t riseQ=std::abs(grid[next].ground
-grid[current.index].ground);
if(horizontalQ<=0||riseQ*65536>horizontalQ*GradeQ16)continue;
const std::int32_t edgeDx=nx-gx,edgeDy=ny-gy;
std::int32_t baseX=gx,baseY=gy,edgeDirection=0;
if(edgeDx==0)
{baseY=std::min(gy,ny);edgeDirection=1;}
else if(edgeDy==0)
{baseX=std::min(gx,nx);edgeDirection=0;}
else if(edgeDx==edgeDy)
{baseX=std::min(gx,nx);baseY=std::min(gy,ny);edgeDirection=2;}
else
{baseX=std::max(gx,nx);baseY=std::min(gy,ny);edgeDirection=3;}
const std::size_t edgeCacheIndex=indexOf(baseX,baseY)*4
+static_cast<std::size_t>(edgeDirection);
if(edgeSupportCache[edgeCacheIndex]<0)
{
const std::uint64_t intervals=std::max<std::uint64_t>(2,
(static_cast<std::uint64_t>(horizontalQ)
+WorldAssemblySubvoxelsPerVoxel/8-1)
/(WorldAssemblySubvoxelsPerVoxel/8));
bool supported=true;
const std::int64_t fromX=static_cast<std::int64_t>(
gx-radiusSteps)*terrainStepQ;
const std::int64_t fromY=static_cast<std::int64_t>(
gy-radiusSteps)*terrainStepQ;
const std::int64_t toX=static_cast<std::int64_t>(
nx-radiusSteps)*terrainStepQ;
const std::int64_t toY=static_cast<std::int64_t>(
ny-radiusSteps)*terrainStepQ;
for(std::uint64_t sample=1;sample<intervals;++sample)
{
const std::int64_t x=fromX+(toX-fromX)
*static_cast<std::int64_t>(sample)
/static_cast<std::int64_t>(intervals);
const std::int64_t y=fromY+(toY-fromY)
*static_cast<std::int64_t>(sample)
/static_cast<std::int64_t>(intervals);
const std::int64_t footZ=grid[current.index].ground
+(grid[next].ground-grid[current.index].ground)
*static_cast<std::int64_t>(sample)
/static_cast<std::int64_t>(intervals)
+routeBaseLiftQ;
if(!hasRouteSupportAt(x,y,footZ))
{supported=false;break;}
}
edgeSupportCache[edgeCacheIndex]=supported?1:0;
}
if(edgeSupportCache[edgeCacheIndex]==0)continue;
const std::uint64_t edgeCost=static_cast<std::uint64_t>(
horizontalQ+riseQ*4);
if(current.cost>std::numeric_limits<std::uint64_t>::max()-edgeCost)
continue;
const std::uint64_t nextCost=current.cost+edgeCost;
if(nextCost>=costs[next])continue;
costs[next]=nextCost;parent[next]=current.index;
open.push({nextCost,next});
}
}
if(goal==nodeCount)continue;
std::vector<std::size_t> path;
for(std::size_t cursor=goal;cursor!=nodeCount;cursor=parent[cursor])
{
path.push_back(cursor);
if(parent[cursor]==nodeCount)break;
if(path.size()>nodeCount)break;
}
if(path.size()<2||parent[path.back()]!=nodeCount)continue;
std::reverse(path.begin(),path.end());
if(arrivalRadiusSubvoxels>0)
std::reverse(path.begin(),path.end());
Candidate candidate;
candidate.centerX=static_cast<std::int32_t>(
(static_cast<std::int32_t>(path.front()%dimension)-radiusSteps)
*terrainStepQ);
candidate.centerY=static_cast<std::int32_t>(
(static_cast<std::int32_t>(path.front()/dimension)-radiusSteps)
*terrainStepQ);
candidate.direction=static_cast<std::int32_t>(directionIndex);
candidate.score=static_cast<std::int64_t>(goalCost/path.size());
candidate.endpointProximityCost=goalDistanceSquared
*(arrivalRadiusSubvoxels>0?16ull:1ull);
candidate.points.reserve(path.size());
bool gradePass=true;
for(std::size_t pointIndex=0;pointIndex<path.size();++pointIndex)
{
const std::size_t index=path[pointIndex];
const std::int32_t gx=static_cast<std::int32_t>(index%dimension);
const std::int32_t gy=static_cast<std::int32_t>(index/dimension);
const std::int64_t xQ=static_cast<std::int64_t>(gx-radiusSteps)
*terrainStepQ;
const std::int64_t yQ=static_cast<std::int64_t>(gy-radiusSteps)
*terrainStepQ;
WorldAssemblyRoutePointV1 point;
point.positionSubvoxels={xQ,yQ,
grid[index].ground+routeBaseLiftQ+HalfHeightQ};
point.radiusSubvoxels=RouteRadiusQ;
point.stableFeatureId=WorldAssemblyFeatureId(recipe.seed,
xQ,yQ,
0x52550000u+static_cast<std::uint32_t>(pointIndex));
if(pointIndex>0)
{
const auto& previous=candidate.points.back().positionSubvoxels;
const std::int64_t dx=point.positionSubvoxels[0]-previous[0];
const std::int64_t dy=point.positionSubvoxels[1]-previous[1];
const std::int64_t dz=std::abs(point.positionSubvoxels[2]-previous[2]);
const std::int64_t run=static_cast<std::int64_t>(std::llround(
std::hypot(static_cast<double>(dx),static_cast<double>(dy))));
if(run<=0||dz*65536>run*GradeQ16)gradePass=false;
}
candidate.points.push_back(point);
}
if(!gradePass)continue;
++terrainPathCount;
const std::array<std::array<std::int64_t,2>,8> lateralNudges{{
{{-ProbeRadiusQ,-ProbeRadiusQ}},{{-ProbeRadiusQ,0}},
{{0,-ProbeRadiusQ}},{{ProbeRadiusQ,-ProbeRadiusQ}},
{{-ProbeRadiusQ,ProbeRadiusQ}},{{0,ProbeRadiusQ}},
{{ProbeRadiusQ,0}},{{ProbeRadiusQ,ProbeRadiusQ}}}};
for(std::size_t nudgeIndex=0;nudgeIndex<lateralNudges.size();++nudgeIndex)
{
Candidate shifted=candidate;
shifted.direction=candidate.direction*9
+static_cast<std::int32_t>(nudgeIndex+1);
shifted.score+=static_cast<std::int64_t>(nudgeIndex+1);
bool shiftedGradePass=true;
for(std::size_t pointIndex=0;pointIndex<shifted.points.size();++pointIndex)
{
const std::int64_t tQ16=shifted.points.size()>1
?static_cast<std::int64_t>(pointIndex)*65536
/static_cast<std::int64_t>(shifted.points.size()-1):0;
const std::int64_t t2Q16=tQ16*tQ16/65536;
const std::int64_t oneMinusQ16=65536-tQ16;
const std::int64_t oneMinus2Q16=
oneMinusQ16*oneMinusQ16/65536;
const std::int64_t weightQ16=std::min<std::int64_t>(65536,
16*t2Q16*oneMinus2Q16/65536);
auto& point=shifted.points[pointIndex];
point.positionSubvoxels[0]+=lateralNudges[nudgeIndex][0]
*weightQ16/65536;
point.positionSubvoxels[1]+=lateralNudges[nudgeIndex][1]
*weightQ16/65536;
const auto ground=safeGroundAt(point.positionSubvoxels[0],
point.positionSubvoxels[1]);
if(!ground.supportReachable)shiftedGradePass=false;
point.positionSubvoxels[2]=ground.ground+routeBaseLiftQ
+HalfHeightQ;
point.stableFeatureId=WorldAssemblyFeatureId(recipe.seed,
point.positionSubvoxels[0],point.positionSubvoxels[1],
0x52550000u+static_cast<std::uint32_t>(
(nudgeIndex+1)*0x10000u+pointIndex));
if(pointIndex==0)continue;
const auto& previous=shifted.points[pointIndex-1]
.positionSubvoxels;
const std::int64_t dx=point.positionSubvoxels[0]-previous[0];
const std::int64_t dy=point.positionSubvoxels[1]-previous[1];
const std::int64_t dz=std::abs(point.positionSubvoxels[2]-previous[2]);
const std::int64_t run=static_cast<std::int64_t>(std::llround(
std::hypot(static_cast<double>(dx),static_cast<double>(dy))));
if(run<=0||dz*65536>run*GradeQ16)shiftedGradePass=false;
}
if(!shiftedGradePass)continue;
candidates.push_back(std::move(shifted));
++terrainPathCount;
}
candidates.push_back(std::move(candidate));
}
if(terrainPathCount>0)terrainGridStepQ=terrainStepQ;
};
tryTerrainPaths(stepQ);
tested+=terrainPathCount;
std::printf("[WorldAssemblerRouteTerrainSearch] grid_step_m=%.3f grid_samples=%llu candidate_paths=%llu grade_limit_deg=15.000 status=%s\n",
terrainGridStepQ*coreVoxelMetres/WorldAssemblySubvoxelsPerVoxel,
static_cast<unsigned long long>(terrainGridSamples),
static_cast<unsigned long long>(terrainPathCount),
terrainPathCount>0?"FOUND":"EMPTY");
}
};
if(gradeRejected>0||placementRejected>0)
{
const double metresPerSubvoxel=static_cast<double>(coreVoxelSizeMicrons)
@@ -318,8 +644,33 @@ namespace StandaloneWorldAssemblyPrototype
});
std::uint64_t sweepAttempt=0,repairAttempt=0;
VoxelForgeCore::WorldAssemblyRouteAuditResult lastAudit{};
for(auto& candidate:candidates)
std::size_t candidateCursor=0;
constexpr std::array<std::int32_t,4> TerrainFallbackSteps{{1024,512,256,128}};
std::size_t terrainFallbackStep=0;
for(;;)
{
if(candidateCursor>=candidates.size())
{
if(terrainFallbackStep<TerrainFallbackSteps.size()&&fallbackSearch
&&((arrivalRadiusSubvoxels>0)!=(departureRadiusSubvoxels>0)))
{
const std::size_t firstTerrainCandidate=candidates.size();
appendTerrainFallback(TerrainFallbackSteps[terrainFallbackStep++]);
std::stable_sort(candidates.begin()+firstTerrainCandidate,
candidates.end(),[](const Candidate& a,const Candidate& b)
{
if(a.endpointProximityCost!=b.endpointProximityCost)
return a.endpointProximityCost<b.endpointProximityCost;
if(a.score!=b.score)return a.score<b.score;
if(a.centerY!=b.centerY)return a.centerY<b.centerY;
if(a.centerX!=b.centerX)return a.centerX<b.centerX;
return a.direction<b.direction;
});
continue;
}
break;
}
auto& candidate=candidates[candidateCursor++];
stratum.route=candidate.points;
std::int64_t liftQ=0;
constexpr std::int64_t RepairStepQ=64;
@@ -349,6 +700,42 @@ namespace StandaloneWorldAssemblyPrototype
static_cast<long long>(candidate.score));
return true;
}
if(liftQ==0&&audit.blockedCapsuleSamples==0
&&audit.unsupportedCenterSamples>0)
{
constexpr std::int64_t SupportAlignmentStepQ=16;
const std::int64_t lowerLimit=std::max<std::int64_t>(0,
audit.minimumClearanceSubvoxels
-constraints.minimumClearanceSubvoxels);
for(std::int64_t lowerQ=SupportAlignmentStepQ;
lowerQ<=lowerLimit;lowerQ+=SupportAlignmentStepQ)
{
for(std::size_t pointIndex=0;pointIndex<stratum.route.size();++pointIndex)
stratum.route[pointIndex].positionSubvoxels[2]
=candidate.points[pointIndex].positionSubvoxels[2]-lowerQ;
const auto loweredAudit=AuditHeightfieldRoute(candidateField);
lastAudit=loweredAudit;++repairAttempt;
if(loweredAudit.passed)
{
std::printf("[WorldAssemblerRouteRepaired] uniform_lower_q=%lld support_limit_q=%lld\n",
static_cast<long long>(lowerQ),
static_cast<long long>(lowerLimit));
const double metresPerSubvoxel=coreVoxelMetres
/WorldAssemblySubvoxelsPerVoxel;
std::printf("[WorldAssemblerRouteAccepted] arrival_xy_m=(%.3f,%.3f) departure_xy_m=(%.3f,%.3f) endpoint_proximity_cost=%llu average_grade_q16=%lld\n",
candidate.points.front().positionSubvoxels[0]*metresPerSubvoxel,
candidate.points.front().positionSubvoxels[1]*metresPerSubvoxel,
candidate.points.back().positionSubvoxels[0]*metresPerSubvoxel,
candidate.points.back().positionSubvoxels[1]*metresPerSubvoxel,
static_cast<unsigned long long>(candidate.endpointProximityCost),
static_cast<long long>(candidate.score));
return true;
}
if(loweredAudit.blockedCapsuleSamples>0
||loweredAudit.minimumClearanceSubvoxels
<constraints.minimumClearanceSubvoxels)break;
}
}
if(audit.blockedCapsuleSamples==0||liftQ>=MaximumRepairLiftQ)break;
const std::int64_t needed=std::max<std::int64_t>(1,
constraints.minimumClearanceSubvoxels-audit.minimumClearanceSubvoxels);
@@ -358,6 +745,62 @@ namespace StandaloneWorldAssemblyPrototype
liftQ=nextLift;
++repairAttempt;
}
if(lastAudit.unsupportedCenterSamples>0&&sweepAttempt<5)
{
const Heightfield2D diagnosticField(recipe,stratum);
const std::int64_t sampleSpacing=std::min<std::int64_t>(
constraints.sweepSpacingSubvoxels,
WorldAssemblySubvoxelsPerVoxel/2);
const std::int64_t supportSpacing=std::min<std::int64_t>(sampleSpacing,
WorldAssemblySubvoxelsPerVoxel/4);
constexpr std::array<std::array<std::int64_t,2>,5> supportOffsets{{
{{0,0}},{{ProbeRadiusQ,0}},{{-ProbeRadiusQ,0}},
{{0,ProbeRadiusQ}},{{0,-ProbeRadiusQ}}}};
for(std::size_t segment=1;segment<stratum.route.size();++segment)
{
const auto& from=stratum.route[segment-1].positionSubvoxels;
const auto& to=stratum.route[segment].positionSubvoxels;
const std::int64_t dx=to[0]-from[0],dy=to[1]-from[1],dz=to[2]-from[2];
const std::uint64_t length=std::max<std::uint64_t>(1,
static_cast<std::uint64_t>(std::llround(std::sqrt(
static_cast<double>(dx*dx+dy*dy+dz*dz)))));
const std::uint64_t intervals=std::max<std::uint64_t>(1,
(length+sampleSpacing-1)/sampleSpacing);
for(std::uint64_t step=segment==1?0:1;step<=intervals;++step)
{
const auto interpolate=[&](std::size_t axis)
{return from[axis]+(to[axis]-from[axis])
*static_cast<std::int64_t>(step)/static_cast<std::int64_t>(intervals);};
const std::int64_t x=interpolate(0),y=interpolate(1),z=interpolate(2);
const std::int64_t footZ=z-PlayerHeightQ/2;
std::array<std::int64_t,5> reachedDepth{};
for(std::size_t probe=0;probe<supportOffsets.size();++probe)
for(std::int64_t depth=supportSpacing;
depth<=constraints.supportSearchDepthSubvoxels;
depth+=supportSpacing)
{
if(diagnosticField.point(x+supportOffsets[probe][0],
y+supportOffsets[probe][1],footZ-depth)
.densitySubvoxels<0)
{reachedDepth[probe]=depth;break;}
}
const auto supported=static_cast<std::uint32_t>(std::count_if(
reachedDepth.begin(),reachedDepth.end(),[](auto depth){return depth>0;}));
if(supported>=constraints.minimumSupportProbes)continue;
const double metresPerSubvoxel=coreVoxelMetres
/WorldAssemblySubvoxelsPerVoxel;
std::printf("[WorldAssemblerRouteSupportSample] ordinal=%llu x_m=%.3f y_m=%.3f center_z_m=%.3f supported=%u/5 depths_q=(%lld,%lld,%lld,%lld,%lld)\n",
static_cast<unsigned long long>(sweepAttempt),x*metresPerSubvoxel,
y*metresPerSubvoxel,z*metresPerSubvoxel,supported,
static_cast<long long>(reachedDepth[0]),
static_cast<long long>(reachedDepth[1]),
static_cast<long long>(reachedDepth[2]),
static_cast<long long>(reachedDepth[3]),
static_cast<long long>(reachedDepth[4]));
segment=stratum.route.size();break;
}
}
}
if(sweepAttempt<3)
std::printf("[WorldAssemblerRouteCandidateRejected] ordinal=%llu blocked=%llu unsupported=%llu grade_failures=%llu minimum_clearance_q=%lld\n",
static_cast<unsigned long long>(sweepAttempt),
@@ -1183,6 +1626,7 @@ namespace StandaloneWorldAssemblyPrototype
static_cast<double>(micrometres)*WorldAssemblySubvoxelsPerVoxel
/layout.coreVoxelSizeMicrometres));
};
constexpr std::int64_t PlayerCenterAboveFloorMicrometres=1130000;
for(const FStrateSlot& slot:owner.Manager->GetLayout())
{
if(!slot.Definition
@@ -1192,10 +1636,24 @@ namespace StandaloneWorldAssemblyPrototype
[&](const auto& item){return item.strateIndex==slot.StrateIndex;});
if(stratum==layout.strates.end()
||!IsNativeCaveFieldStratum(*stratum))continue;
const bool hasRoutePoints=std::count_if(stratum->anchors.begin(),
const std::string routePrefix="tunnel-network/strate-"
+std::to_string(slot.StrateIndex)+"/";
const bool hasPlannedArrival=std::any_of(layout.cavernEdges.begin(),
layout.cavernEdges.end(),[&](const auto& edge)
{return edge.strateIndex==slot.StrateIndex
&&edge.stableId==routePrefix+"route-edge-0";});
const bool hasPlannedDeparture=std::any_of(layout.cavernEdges.begin(),
layout.cavernEdges.end(),[&](const auto& edge)
{return edge.strateIndex==slot.StrateIndex
&&edge.stableId==routePrefix+"departure-edge";});
if(!hasPlannedArrival||!hasPlannedDeparture)continue;
// Route-point anchors also drive the passage-mouth floor blend. The
// native cave planner replaces the legacy finite-strate route, so
// retaining its old anchors would join the passage floor to a route
// that is no longer present in the composed cave field.
stratum->anchors.erase(std::remove_if(stratum->anchors.begin(),
stratum->anchors.end(),[](const auto& anchor)
{return anchor.kind=="route_point"&&anchor.values.size()>=3;})>=2;
if(hasRoutePoints)continue;
{return anchor.kind=="route_point";}),stratum->anchors.end());
const ResolvedLayoutPassageV1* arrival=nullptr;
const ResolvedLayoutPassageV1* departure=nullptr;
for(const auto& passage:layout.passages)
@@ -1222,9 +1680,7 @@ namespace StandaloneWorldAssemblyPrototype
if(std::abs(a[axis]-b[axis])>2)return false;
return true;
};
constexpr std::int64_t PlayerCenterAboveFloorMicrometres=1130000;
auto start=arrival->lowerMouthSubvoxels;
start[2]+=toCoreSubvoxels(PlayerCenterAboveFloorMicrometres);
appendRoutePoint("000-arrival",start);
for(std::size_t edgeIndex=0;edgeIndex<256;++edgeIndex)
{
@@ -1239,6 +1695,10 @@ namespace StandaloneWorldAssemblyPrototype
if(edgeIndex==0)
{
auto inner=edge->controlPointsMicrometres.front();
// Keep the exact authored mouth anchor and use the planner
// edge's floor height for the first cave-side walking point.
// Passage composition uses these same two points to blend the
// floor profile into the native cave route.
inner[2]+=PlayerCenterAboveFloorMicrometres;
const std::array<std::int64_t,3> point={
toCoreSubvoxels(inner[0]),toCoreSubvoxels(inner[1]),
@@ -1266,12 +1726,10 @@ namespace StandaloneWorldAssemblyPrototype
toCoreSubvoxels(inner[0]),toCoreSubvoxels(inner[1]),
toCoreSubvoxels(inner[2])};
auto end=departure->upperMouthSubvoxels;
end[2]+=toCoreSubvoxels(PlayerCenterAboveFloorMicrometres);
if(!sameRoutePoint(innerPoint,end))
appendRoutePoint("998-departure-inner",innerPoint);
}
auto end=departure->upperMouthSubvoxels;
end[2]+=toCoreSubvoxels(PlayerCenterAboveFloorMicrometres);
appendRoutePoint("999-departure",end);
}
return layout.finalize(error);