wip(L25, side branch): FI helix enclosed in a 13 m rock root; support never created in open air

Fixes the L24 ribbon (owner request). NOT merged: the open-air support gate leaves ~4,000 unsupported
samples on every SurfaceWorld-recipe passage style (TN -> SW), a walkability regression. L26 fixes that
on this branch. See Linux25/REPORT.md.

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-21 00:38:57 +02:00
1 parent cb9236c265
commit ef789aaa00
14 files changed
+662 -110

No files matched your search

+27
View File
@@ -1983,6 +1983,33 @@ cutaway views. Both affect captures only, not generated geometry.
[`Standalone/Research/WorldAssemblerM3/Linux24/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux24/REPORT.md)
records the evidence and owner-facing caveats.
### 8.43 Enclosed FloatingIslands helix and native-solid passage support — World Assembler L25
L24's support tread was composited into the passage field without requiring native solid terrain at
the support sample. A 6 m root could not contain the resolved helix either: the centreline reaches
5.562 m from the anchor axis and the mouth bore is 4.5 m. With the old root radius, the tread could
therefore read as a free-floating spiral outside the rock. This was not a unit conversion error.
The shared passage composer now emits route-mouth support, tread, and fallback support only where
the pre-passage native density is solid. The open-air audit samples each support footprint at 0.25 m
spacing and two depths, including route-mouth shelves; its L24 ungated-support control must report a
violation. The FI anchor root is now a relief-bearing 13.25 m nominal rock column. Across five
heights its measured radius is 12.0–13.375 m. Taking the maximum 5.562 m centreline radius and the
full 4.5 m mouth bore at every height gives a conservative minimum wall of 1.938 m, exceeding the
previous 1.5 m reserve. The authored mid-bore remains 3 m. The helix is selected from its route-bound
root point and joins the lower route before the tunnel hands off through the shared SW ceiling.
The configured FI Spiral passes the capsule/support/grade audit with zero blocked, unsupported, or
grade-failure samples; the L23 smooth-wall control fails naturalness and the L24 ungated-support
control fails the open-air audit. The other style overrides also pass the open-air audit, but their
capsule results are recorded individually in the L25 report because some overrides are not
walkable after floating support is suppressed. Evaluator version is 12, FI geometry version is 7,
and resolved-layout schema V3 remains unchanged. The L25 report records measurements, hashes,
captures, style results, and the single Unreal adapter version edit.
[`Standalone/Research/WorldAssemblerM3/Linux25/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux25/REPORT.md)
records the evidence and caveats.
## 9. Multiplayer model (listen-server first, dedicated-friendly)
> **Status: transport is DESIGN ONLY — nothing is networked in-tree yet** (no `Replicated`/`HasAuthority`/RPCs; a
+13
View File
@@ -1181,6 +1181,19 @@ The shared evaluator is version 10, the FI recipe geometry is version 5, and res
V3 is unchanged. See ARCHITECTURE §8.42 and
[`Standalone/Research/WorldAssemblerM3/Linux24/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux24/REPORT.md).
### 3.26 Enclosed FloatingIslands helix and open-air support gate — World Assembler L25
| Symbol | Canonical file | Role |
|---|---|---|
| `ApplyResolvedStratePassageCarves` | `Standalone/Core/src/ShapeWorldInternal.h` | Emits route-mouth support, tread and fallback support only over pre-passage native solid density, shared by every passage style. |
| `auditPassageOpenAir` / `--audit-resolved-layout-passages` | `Standalone/Source/StreamBenchmarkPipeline.h` | Samples the support footprint at 0.25 m spacing and two depths; compares against L24 ungated support as a required negative control. |
| Anchor root dimensions and relief | `Standalone/Core/src/FloatingIslandsInternal.h` | Raises the FI anchor root from a 6 m cylinder to a nominal 13.25 m relief-bearing rock column sized around the 3 m helix and 4.5 m mouth. |
| Passage route and root measures | `Standalone/Core/src/ResolvedLayoutInternal.h`, `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h` | Binds the Spiral to the root and reports measured centreline/root clearance. |
The shared evaluator is version 12 and FI geometry version is 7; resolved-layout schema V3 is
unchanged. See ARCHITECTURE §8.43 and
[`Standalone/Research/WorldAssemblerM3/Linux25/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux25/REPORT.md).
## 4. The density pipeline (most-edited hot path)
### 4.1 `GetDensityWithParams` (TunnelNetwork) — VoxelGenerator.cpp:3749
@@ -485,7 +485,7 @@ bool BuildFloatingIslandStratumPlan(const UVoxelStrateManager* StrateManager,
IslandPlan.topChunkZ = Slot.TopChunkZ;
IslandPlan.bottomChunkZ = Slot.BottomChunkZ;
auto& Recipe = IslandPlan.manifest.recipe;
Recipe.geometryVersion = 5;
Recipe.geometryVersion = 7;
Recipe.layoutChunkWidthSubvoxels = LayoutChunkWidthSubvoxels;
Recipe.seed = static_cast<std::uint32_t>(StrateManager->GetWorldSeed());
Recipe.ownerVoxelSizeMicrons = static_cast<std::uint32_t>(std::llround(OwnerVoxelSizeCm * 10000.0));
@@ -249,8 +249,8 @@ namespace VoxelForgeCore
// L'assembleur v1 encode coordonnees et scalaires en 1/256 de voxel, independamment des tuiles.
inline constexpr std::int64_t WorldAssemblySubvoxelsPerVoxel = 256;
inline constexpr std::uint32_t WorldAssemblySchemaVersion = 2;
// Version 10 adds per-strate passage styles and rough wall relief to resolved passages.
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 10;
// Version 12 gates passage supports on native rock and anchors the FI spiral inside a measured root.
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 12;
enum class FieldChannel : std::uint32_t
{
@@ -281,7 +281,7 @@ namespace floating_island_detail
? recipe.ownerVoxelSizeMicrons / ScaleGcd : 0;
const std::uint32_t ExpectedDenominator = ScaleGcd > 0
? recipe.coreVoxelSizeMicrons / ScaleGcd : 0;
if (recipe.schemaVersion != 1 || recipe.geometryVersion < 1 || recipe.geometryVersion > 5
if (recipe.schemaVersion != 1 || recipe.geometryVersion < 1 || recipe.geometryVersion > 7
|| (recipe.geometryVersion == 1
&& (recipe.crustDepthBonusQ16 != 0 || recipe.rootDepthRatioQ16 != 0))
|| recipe.unitsPerVoxel != Q
@@ -756,7 +756,9 @@ namespace floating_island_detail
if (recipe.geometryVersion >= 5 && island.ordinal == recipe.anchorIslandOrdinal
&& recipe.anchorRootBottomZSubvoxels < island.bottomZSubvoxels)
{
const double rootTop = static_cast<double>(island.bottomZSubvoxels);
// The central buttress must meet the island crust underside. IslandBottom
// also includes the four shorter root lobes and sits below that surface.
const double rootTop = static_cast<double>(IslandCrustBottom(recipe, island));
const double rootBottom = static_cast<double>(recipe.anchorRootBottomZSubvoxels);
const double depth = std::max(1.0, rootTop - rootBottom);
const double blend = std::clamp(static_cast<double>(recipe.anchorRootRadiusSubvoxels)
@@ -1330,7 +1332,7 @@ std::optional<FloatingIslandManifestV1> FloatingIslandManifestV1::FromJson(
manifest.recipe.anchorRootBottomZSubvoxels)
||!floating_island_detail::ReadInteger(recipeValue.Get("anchor_mouth_offset_q"),
manifest.recipe.anchorMouthOffsetSubvoxels))
{error="floating-island geometry version 5 is missing a passage-rooted anchor field";return std::nullopt;}
{error="floating-island geometry version 7 is missing a passage-rooted anchor field";return std::nullopt;}
}
if (!floating_island_detail::ReadU32(root.Get("schema_version"), schema)
|| !floating_island_detail::ReadHash(root.Get("content_hash"), manifestHash)
+42 -9
View File
@@ -550,6 +550,14 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
const auto routeAnchor=[](const ResolvedLayoutStratumV2& s,bool departure,
std::array<std::int64_t,3>& out)
{
if(departure)
for(const auto& a:s.anchors)
if(a.kind=="passage_anchor"&&a.values.size()>=10)
{out={a.values[7],a.values[8],a.values[9]};return true;}
if(!departure)
for(const auto& a:s.anchors)
if(a.kind=="passage_arrival"&&a.values.size()>=3)
{out={a.values[0],a.values[1],a.values[2]};return true;}
const ResolvedLayoutAnchorV2* selected=nullptr;
for(const auto& a:s.anchors)
if(a.kind=="route_point"&&a.values.size()>=3)
@@ -597,8 +605,9 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
// Leave room for the capsule and bounded wall relief at the floor/wall seam.
const std::int64_t mouthRadius=std::max<std::int64_t>(static_cast<std::int64_t>(std::llround(1.5*qPerMetre)),
cfg?cfg->mouthRadiusSubvoxels:0);
const std::int64_t midRadius=std::max<std::int64_t>(mouthRadius,
cfg?cfg->midRadiusSubvoxels:0);
const std::int64_t midRadius=std::max<std::int64_t>(
static_cast<std::int64_t>(std::llround(1.5*qPerMetre)),
cfg?cfg->midRadiusSubvoxels:mouthRadius);
const std::int64_t reachMinimum=cfg?std::max<std::int64_t>(0,cfg->reachMinimumSubvoxels):8*qPerMetre;
const std::int64_t reachMaximum=cfg?std::max<std::int64_t>(reachMinimum,cfg->reachMaximumSubvoxels):24*qPerMetre;
const std::uint32_t style=cfg?std::min<std::uint32_t>(cfg->style,3u):1u;
@@ -624,7 +633,9 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
for(const auto& anchor:upper.anchors)
if(anchor.kind=="passage_anchor"&&anchor.values.size()>=7)
{passageAnchor=&anchor;break;}
const bool anchoredSpiral=style==2&&passageAnchor!=nullptr;
const bool anchoredIslandPassage=passageAnchor!=nullptr
&&upper.generatorKind=="FloatingIslands";
const bool anchoredSpiral=style==2&&anchoredIslandPassage;
if(!hasUpperRoute||!hasLowerRoute)
{
const auto xy=PassageRandomXY(PassageSeed(seed,upper.strateIndex,lower.strateIndex,
@@ -652,7 +663,10 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
std::array<std::int64_t,2> upperTangent{},lowerTangent{};
const bool hasUpperTangent=hasUpperRoute
&&routeTangent(upper,true,upperTangent);
const bool hasLowerTangent=hasLowerRoute
const bool hasPassageArrival=std::any_of(lower.anchors.begin(),lower.anchors.end(),
[](const auto& anchor){return anchor.kind=="passage_arrival"
&&anchor.values.size()>=3;});
const bool hasLowerTangent=hasLowerRoute&&!hasPassageArrival
&&routeTangent(lower,false,lowerTangent);
const std::int64_t outerRingRadius=std::max<std::int64_t>(1,
@@ -671,6 +685,8 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
std::max<std::int64_t>(0,cfg?cfg->cascadeLedgeSubvoxels:0)
*static_cast<std::int64_t>(cfg?cfg->cascadeSteps:4)),
mouthRadius+2*qPerMetre,outerRingRadius);
if(anchoredIslandPassage)
ringRadius=std::min(ringRadius,mouthRadius+qPerMetre/2);
std::uint32_t phase=static_cast<std::uint32_t>(PassageSeed(seed,
upper.strateIndex,lower.strateIndex,connection,0x50484153u)%16);
if(hasUpperRoute)
@@ -700,7 +716,7 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
+clockwiseTangentY*upperTangent[1]>=0.0;
}
const int direction=clockwise?1:-1;
constexpr std::int64_t TargetGradeQ16=12500; // leave margin below the 15-degree contract.
constexpr std::int64_t TargetGradeQ16=12500; // leave margin below the 15-degree helix contract.
const std::int64_t wormRadialWobble=std::min<std::int64_t>(
std::max<std::int64_t>(0,wander/3),2*qPerMetre);
const std::int64_t wormCenterWobble=std::min<std::int64_t>(
@@ -716,10 +732,14 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
const double loop=static_cast<double>(loopIndex);
const double phaseA=loop*0.6180339887498948+0.37;
const double phaseB=loop*0.4142135623730950+1.11;
const double jitterX=static_cast<double>(wormCenterWobble)*std::sin(phaseB);
const double jitterY=static_cast<double>(wormCenterWobble)*std::cos(phaseB);
radius+=static_cast<double>(wormRadialWobble)
*std::sin(angle+phaseA);
centerX=static_cast<double>(wormCenterWobble)*std::sin(phaseB);
centerY=static_cast<double>(wormCenterWobble)*std::cos(phaseB);
centerX=jitterX+(anchoredIslandPassage&&passageAnchor
?static_cast<double>(passageAnchor->values[0]):0.0);
centerY=jitterY+(anchoredIslandPassage&&passageAnchor
?static_cast<double>(passageAnchor->values[1]):0.0);
}
else if(pathStyle==3u)
{
@@ -730,6 +750,11 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
cfg->cascadeLedgeSubvoxels):0));
radius-=ledge*(0.5-0.5*std::cos(angle*steps));
}
if(pathStyle!=1u&&anchoredIslandPassage&&passageAnchor)
{
centerX=static_cast<double>(passageAnchor->values[0]);
centerY=static_cast<double>(passageAnchor->values[1]);
}
return std::array<std::int64_t,2>{
static_cast<std::int64_t>(std::llround(centerX+radius*directions[directionIndex][0]/65536.0)),
static_cast<std::int64_t>(std::llround(centerY+radius*directions[directionIndex][1]/65536.0))};
@@ -748,7 +773,11 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
const std::int64_t anchorY=passageAnchor->values[1];
const std::int64_t rootRadius=passageAnchor->values[2];
const std::int64_t rootBottom=passageAnchor->values[5];
helixBedrockZ=rootBottom!=0?rootBottom:contentZQ(upper.bedrock.topMicrometres);
const std::int64_t bedrockTop=rootBottom!=0?rootBottom
:contentZQ(upper.bedrock.topMicrometres);
// Passage route heights are player-center positions. End one capsule
// half-height above the bedrock top so the final ramp step is walkable.
helixBedrockZ=bedrockTop+qPerMetre;
const std::int64_t helixRadius=spiralRadius;
if(rootRadius<helixRadius+midRadius+qPerMetre/4
||std::hypot(static_cast<double>(upperMouth[0]-anchorX),
@@ -796,6 +825,8 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
helixEndIndex=xy.size()-1;
hasAnchorHelix=helixEndIndex>0;
}
const std::int64_t routeGradeQ16=hasAnchorHelix
&&lower.generatorKind=="SurfaceWorld"?8000:TargetGradeQ16;
const std::array<std::int64_t,2> firstRing=ringPoint(phase);
if(hasAnchorHelix&&pathStyle==1u)
{
@@ -843,12 +874,14 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
const std::size_t start=hasAnchorHelix?helixEndIndex:0;
for(std::size_t i=start+1;i<xy.size();++i)
total+=distanceQ(xy[i][0]-xy[i-1][0],xy[i][1]-xy[i-1][1]);
if(!hasLowerTangent&&!xy.empty())
total+=distanceQ(lowerMouth[0]-xy.back()[0],lowerMouth[1]-xy.back()[1]);
return total;
};
while(loops<256)
{
totalHorizontal=measurePath();
if(totalHorizontal*static_cast<std::uint64_t>(TargetGradeQ16)
if(totalHorizontal*static_cast<std::uint64_t>(routeGradeQ16)
>=static_cast<std::uint64_t>(verticalDistance)*65536ull)break;
for(int step=1;step<=16;++step)
{
+50 -41
View File
@@ -110,6 +110,9 @@ public:
const auto composeRouteMouthSupport=[&](std::int32_t strateIndex,
const std::array<std::int64_t,3>& mouth,bool departure)
{
// Support is allowed to reinforce native solid terrain only. Without this
// guard the route-point tread stamps a floating shelf into an open stratum.
if(!(density<0.0f))return;
const double mouthDx=qx-static_cast<double>(mouth[0]);
const double mouthDy=qy-static_cast<double>(mouth[1]);
const double routeSupportReach=13.0*qPerMetre;
@@ -159,26 +162,26 @@ public:
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.
// Keep the native surface route connected to the entrance. Passage carving
// then removes only the parts that overlap the tunnel, whose own tread owns
// the interior ramp.
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.
}
composeRouteMouthSupport(passage.upperStrateIndex,
passage.upperMouthSubvoxels,true);
for(const auto& passage:ResolvedLayout->passages)
{
if(passage.controlPoints.size()<2)continue;
const double placementRadiusQ=static_cast<double>(passage.placementRadiusSubvoxels)
+static_cast<double>(passage.midRadiusSubvoxels);
if(qx*qx+qy*qy>placementRadiusQ*placementRadiusQ)continue;
if(qx*qx+qy*qy>placementRadiusQ*placementRadiusQ)
continue;
const double firstFloorQ=passage.controlPoints.front().positionSubvoxels[2]
-passage.controlPoints.front().radiusSubvoxels+playerCenterAboveFloorQ;
const double lastFloorQ=passage.controlPoints.back().positionSubvoxels[2]
-passage.controlPoints.back().radiusSubvoxels+playerCenterAboveFloorQ;
if(qz>firstFloorQ+2.0*passage.mouthRadiusSubvoxels
||qz<lastFloorQ-2.0*passage.mouthRadiusSubvoxels)continue;
||qz<lastFloorQ-2.0*passage.mouthRadiusSubvoxels)
continue;
const auto floorProfile=[&](const auto& point)
{return point.positionSubvoxels[2]-point.radiusSubvoxels+playerCenterAboveFloorQ;};
const std::ptrdiff_t lastIndex=static_cast<std::ptrdiff_t>(passage.controlPoints.size())-1;
@@ -237,21 +240,6 @@ public:
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 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])
-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*(
@@ -265,11 +253,6 @@ public:
// 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)
{
@@ -293,21 +276,28 @@ public:
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 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 supportPlayerCenterZ=centerZ-radius+playerCenterAboveFloorQ;
const double supportQueryDepth=supportPlayerCenterZ-qz;
// Support belongs just below the avatar's foot plane. Queries within
// the capsule body, or a neighbouring coil's overlapping bore, must
// not turn that tread into a ceiling or mid-air shelf.
if(supportQueryDepth<0.93*qPerMetre||supportQueryDepth>1.30*qPerMetre)return;
const bool fallbackSupport=qz>=supportPlayerCenterZ-1.50*qPerMetre;
const double supportThicknessVoxels=fallbackSupport
?qPerMetre/Q:0.5*qPerMetre/Q;
const double floorQ=centerZ-radius+floorOffset*qPerMetre;
const double floorVoxels=floorQ/Q;
// Keep the supported ramp to a comfortable walking width. Extending a
// full bore-radius shelf across overlapping helix coils can block the
// capsule on the neighbouring turn.
const bool lowerMouthBodyOverlap=index>=lowerMouthIndex-2
&&supportQueryDepth<0.98*qPerMetre;
const double supportHalfWidth=std::min(radius,
(lowerMouthBodyOverlap?0.90:1.25)*qPerMetre);
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);
@@ -317,11 +307,30 @@ public:
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);
std::ptrdiff_t supportCenterIndex=bestIndex;
if(bestIndex<lowerMouthIndex)
{
// A helix can have multiple centerlines at one XY. Select the tread
// whose floor is just below this density query, not the closest wall.
const double supportProfileTarget=qz+0.93*qPerMetre;
const auto supportProfile=std::lower_bound(passage.controlPoints.begin(),mainEnd,
supportProfileTarget,[&](const auto& point,double value)
{return floorProfile(point)>value;});
const std::ptrdiff_t profileIndex=std::clamp<std::ptrdiff_t>(
supportProfile-passage.controlPoints.begin(),0,lowerMouthIndex);
// At floor height the nearest 3D centerline can belong to the next
// coil below. The descending floor profile identifies the coil that
// owns this tread, even when it is more than eight control points away.
supportCenterIndex=profileIndex;
}
const std::ptrdiff_t supportBegin=std::max<std::ptrdiff_t>(0,supportCenterIndex-1);
const std::ptrdiff_t supportEnd=std::min<std::ptrdiff_t>(lastIndex-1,
supportCenterIndex+1);
for(std::ptrdiff_t index=supportBegin;index<=supportEnd;++index)
considerSupportSegment(index);
if(hasSupportFloor)
// Keep route treads inside the native rock envelope. Carving may reopen the
// floor above this point, but a support cannot create a new surface in air.
if(hasSupportFloor&&density<0.0f)
composed=std::min(composed,static_cast<float>(bestSupportDensity));
}
return composed;
@@ -0,0 +1,86 @@
# World Assembler L25 — FI helix inside the root
**The ribbon came from two causes.** The shared passage compositor stamped route-mouth tread/support into native air, and the L24 6 m root could not contain this route: its measured centerline reached 5.562 m from the root axis and the mouth bore is 4.5 m. That leaves a nominal `6 - 5.562 - 4.5 = -4.062 m` wall allowance. The axis and units were correct; the support pass ignored surrounding rock, and the root was too small.
L25 gates shared route-mouth support on negative pre-passage density, so it can reinforce existing rock but cannot create a shelf in air. The FI anchor root is now a relief-bearing 13.25 m nominal rock column. I chose a sturdier column with the existing uneven relief over a thin cylinder; it remains column-shaped from outside. The authored spiral stays centered on the root axis.
## Root and passage measurements
Axis `(9.800, 4.571) m`; helix centerline radius `2.999–5.562 m`; bore radius `4.5 m` at the mouth and `3.0 m` through the middle. The conservative wall estimate uses the largest path offset and mouth bore at every height.
| Height (m) | Solid radius min / mean / max (m) |
|---:|---:|
| -68.209 | 12.000 / 12.129 / 12.375 |
| -80.643 | 12.125 / 12.254 / 12.500 |
| -93.595 | 12.500 / 12.672 / 12.875 |
| -106.548 | 12.875 / 13.012 / 13.250 |
| -118.982 | 13.000 / 13.168 / 13.375 |
Minimum measured wall allowance is `1.938 m`, above the existing `1.5 m` reserve.
## Audits
The authored FI Spiral passed on Clang and GCC: 61,173 capsule samples, `blocked=0`, 5,318 support samples, `unsupported=0`, `grade_failures=0`; both route bindings pass, and walkability is 1,135/1,135. Strict layout validation accepted with zero issues; malformed controls were rejected 9/9.
The open-air audit sampled 813,632 passage support points at 0.25 m spacing: `violations=0`, including 11,520 route-support samples. Its L24 ungated-support negative control found 1,438 violations. Naturalness passed with a 0 m flat run and 0.767 m wall-relief peak-to-peak; the L23 smooth-wall negative control was detected at 0 m relief. The capsule, open-air, and naturalness results match between Clang and GCC.
All four style overrides in both recipes passed the open-air audit (zero violations; the L24 control was detected each time). The capsule sweep has failures outside the authored FI Spiral: FI styles 0/1/3 have 7/13/6 blocked samples; SurfaceWorld styles 0/1/2/3 have 4,255/4,071/3,948/4,117 unsupported samples after the safe support gate. Their blocked/grade counts are zero. These are alternate-style walkability failures, not open-air emissions; the canonical FI Spiral and composed SurfaceWorld route pass. The individual logs are `Saved/Linux/linux25-style-*.log`.
L13 parity passed on both compilers: FI 8/8 page pairs, 14 higher-LOD pairs, 782,026 exact-query samples, zero mismatches; SurfaceWorld 5 page pairs, 9 native-only pairs, 14 higher-LOD pairs, 910,651 exact-query samples, zero mismatches. Both had one passing edit pair. L9 uniform-block proofs had zero violations: SurfaceWorld checked 26,977 blocks / 35,906,387 samples; FI used its expected 21,504 fallbacks/unknowns and checked no blocks.
The 24 m crossing passed both compilers and recipes. FI processed 314 moving tiles and SurfaceWorld 432; compiler hashes match per recipe. Crossing whole-view density/mesh/payload/topology hashes (FI 2,370 tiles; SurfaceWorld 2,553):
- FI: `c284b42ced276f4c / f6a90d0027d8d6fe / fdec2a7f61215a1e / 60a99d7c20700cd6`
- SurfaceWorld: `cee18b39a9271559 / c1713be06b92bd8e / fd7954350ebfacfc / c58b075a1b7f2895`
## Determinism and SurfaceWorld
The exact LOD0–8 hash matrix passed at W1/W8/W12 for Clang and GCC: 2,370 whole-view tiles, 960 full-detail tiles, all nine LOD rows and exact-query hashes identical across workers and compilers. Hash vectors are density/mesh/payload/topology:
| Recipe | Whole view (2,370 tiles) | Full detail (960 tiles) | Exact-query density / detail / collision |
|---|---|---|---|
| SurfaceWorld | `8d494f8f843171b2 / 37d21941f6d9cce8 / 47248393fa2f3322 / 36d03d874daef4ae` | `ace56c8f205238ad / a9c603a1248de6b8 / ea55f1f4fcc6a894 / 5ea7bc78a1b678ae` | `c949c4df2ce6f9d9 / 114c501e2d830d94 / e6011d3a248d4849` |
| Floating Islands | `6f0095c01b066744 / efea60f7a9c1d675 / 849c1829e1dcddd5 / 4f7cc65dc1adc234` | `d18e722b37a2479e / 0e410a8e80a3e7f7 / 0751926f0c67d8a4 / f01208bc2f7841ec` | `7b7c50ac24ccadcc / efcba20c0c70c415 / e604823a249029bf` |
Re-run command, with `N=1,8,12`, both compiler binaries, and both recipes:
```sh
timeout 1800s taskset -c 0-11 env LP_NUM_THREADS=12 prlimit --as=6442450944 -- Standalone/bin/linux/VoxelForgeCoreHeadless-linux25-<clang|gcc> --world-assembler-prototype --stream-benchmark --stream-pipeline --stream-hash --force-generate --clip-radius=3 --max-clip-level=8 --far-horizon-lod8-step=0 --workers=N --recipe=<surface-world|floating-islands> Standalone/data/owner_world.json
```
SurfaceWorld away from the passage was directly compared with L23 in L24 and matched at 960 full-detail tiles: `66ac781666579e3e / 914873894a0e38c4 / ec8b03ade039cd56 / a2b621b0321d43dc`. L25 changes only passage/root generation and the shared passage composition region; it does not change the away-from-passage SurfaceWorld field. The L25 full-view hashes above cover a different tile selection from that away-only comparison.
## Captures
The four final captures are 1920×1080 JPEGs under `captures/`, each below 300 KB:
- `fi-pillar-exterior.jpg` (43 KB): wide exterior; thick relief-bearing root, no outside ribbon.
- `fi-pillar-cutaway.jpg` (53 KB): vertical cutaway exposing the helix and central rock.
- `fi-helix-inside.jpg` (37 KB): headlamp on, 90° FOV, camera `(11.495, 7.047, -87.858) m` at resolved route point 200, about 2 m above the tread, aimed down the route tangent. The tight turn leaves a close, wall-heavy view; the cutaway is clearer for the full spiral.
- `sw-arrival-mouth.jpg` (55 KB): headlamp on, 80° FOV, camera `(9.800, 4.571, -133.000) m`, 5.5 m below the lower mouth, looking up into the SW arrival.
## Changes, invariants, and run history
Core evaluator version is 12; FI geometry version is 7; resolved-layout schema V3 is unchanged. Source changes are in the Core passage planner/compositor, FI root geometry, and the standalone audit/hash reporting. `ARCHITECTURE.md` §8.43 and `CODEMAP.md` §3.26 document the change. The only Unreal edit is the adapter's FI geometry-version assignment (`geometryVersion = 7`); Unreal was unavailable, so that adapter edit was not compiled here.
L3 FP-contract preamble/self-test, L4 `FLazy`, L7 shared cache, L9/L12 proofs, L11 readiness/crash fix, L13 route binding, L18/L19 shared ceiling, L21/L22 layout and bands, L23/L24 passages, ARCHITECTURE §8.10, and CLAUDE.md async rules remain intact. No commit, push, or stash was made.
Failed or retried runs:
- The first scene export omitted `--render-distance-chunks=0`; it expanded to 593,068 tiles / about 640 MB and was stopped before 15 minutes, then its partial export was removed. A render-distance-48 retry returned 844 plane-dominated tiles / 31 MB and was discarded. Clipmap-only (195 tiles) and focused 27-tile detail exports succeeded.
- Two extra GCC audit invocations exited 2 because the headless binary needs the owner JSON as a positional path; the corrected invocation with `Standalone/data/owner_world.json` passed. The requested six-worker/compiler/recipe hash matrix itself passed.
- Early interior camera trials missed the resolved helix centerline and showed wall-only frames; the final interior frame uses a point extracted from the current resolved layout. No build or audit exceeded 30 minutes, and no step was left stuck for 15 minutes.
## Orchestrator review (Claude) — side branch, not merged yet
- The FI helix fix is confirmed by my capture review: `fi-pillar-exterior.jpg` shows a solid relief-bearing
column with no outside ribbon, and `fi-pillar-cutaway.jpg` shows the helix inside it.
- **Regression that blocks merge:** the support gate makes non-FI passages unwalkable. With the SurfaceWorld
recipe (the owner world's TunnelNetwork strate above SurfaceWorld), every style has ~4,000 unsupported
capsule samples (L24: 0). FI styles 0/1/3 have blocked samples. The owner world's real TN→SW passage is
affected, so a player can fall through it.
- Kept on side branch `wip/l25-helix`; `assembler/world` stays at L24 (`cb9236c`) until L26 makes every style
in both recipes pass with 0 blocked / 0 unsupported / 0 open-air violations.
- Design decision (owner delegated decisions to me, 2026-10-21): passages are tunnels in rock. The planner keeps
the path inside solid ground where possible; unavoidable open-air crossings get a natural, grounded rock
bridge (thick, relief, connected to rock on both ends), never a floating tread.
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

+352 -41
View File
@@ -453,6 +453,9 @@ namespace StandaloneStreamBenchmark
std::array<std::array<double,4>,8> firstUnsupported{};
std::array<std::array<bool,5>,8> firstSupportMasks{};
std::size_t firstBlockedCount=0,firstUnsupportedCount=0;
std::array<double,4> firstDeepUnsupported{};
std::array<bool,5> firstDeepSupportMask{};
bool hasDeepUnsupported=false;
bool passed=false;
};
const double coreMetres=static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0;
@@ -547,6 +550,13 @@ namespace StandaloneStreamBenchmark
if(supportedProbes<minimumSupportProbes)
{
++audit.unsupported;
if(!audit.hasDeepUnsupported&&footZ<-80.0)
{
audit.hasDeepUnsupported=true;
audit.firstDeepUnsupported={firstUnsupportedX,firstUnsupportedY,
footZ,lastUnsupportedDensity};
audit.firstDeepSupportMask=supportMask;
}
if(audit.firstUnsupportedCount<audit.firstUnsupported.size())
{
const std::size_t sample=audit.firstUnsupportedCount++;
@@ -658,6 +668,267 @@ namespace StandaloneStreamBenchmark
[index](const auto& s){return s.strateIndex==index;});
return it==ResolvedLayout->strates.end()?nullptr:&*it;
};
const auto controlSnapshot=CoreSnapshot.withoutResolvedLayoutPassages();
VoxelForgeCore::World blockedWorld(controlSnapshot);
std::string blockedCompileError;
const bool blockedCompiled=controlSnapshot
&&blockedWorld.compile(ShapeRequest,Scheduler,blockedCompileError);
if(!blockedCompiled)
{
Streamer.Stop();
std::fprintf(stderr,"[ResolvedPassageBlockedControl] compile_failed=%s\n",
blockedCompileError.c_str());
return 10;
}
struct FPassageOpenAirAudit
{
std::uint64_t supportSamples=0,violations=0,legacyViolations=0;
std::uint64_t routeSupportSamples=0,routeSupportViolations=0;
std::array<std::array<double,4>,8> firstViolations{};
std::size_t firstViolationCount=0;
};
constexpr double PassageSupportAuditSpacingMetres=0.25;
constexpr std::array<double,2> PassageSupportAuditDepthsMetres{{0.125,0.375}};
constexpr std::array<std::array<double,2>,16> PassageSupportAuditDirections{{
{{1.0000000000000000,0.0000000000000000}},
{{0.9238795325112867,0.3826834323650898}},
{{0.7071067811865476,0.7071067811865476}},
{{0.3826834323650898,0.9238795325112867}},
{{0.0000000000000000,1.0000000000000000}},
{{-0.3826834323650898,0.9238795325112867}},
{{-0.7071067811865476,0.7071067811865476}},
{{-0.9238795325112867,0.3826834323650898}},
{{-1.0000000000000000,0.0000000000000000}},
{{-0.9238795325112867,-0.3826834323650898}},
{{-0.7071067811865476,-0.7071067811865476}},
{{-0.3826834323650898,-0.9238795325112867}},
{{0.0000000000000000,-1.0000000000000000}},
{{0.3826834323650898,-0.9238795325112867}},
{{0.7071067811865476,-0.7071067811865476}},
{{0.9238795325112867,-0.3826834323650898}}}};
const auto auditPassageOpenAir=[&](const VoxelForgeCore::World& Field,
const VoxelForgeCore::World& Native,
const VoxelForgeCore::ResolvedLayoutPassageV1& passage)
{
FPassageOpenAirAudit audit;
const auto inspect=[&](double xMetres,double yMetres,double floorMetres,
double depthMetres,double supportThicknessMetres,bool routeSupport=false)
{
if(depthMetres<=0.0||depthMetres>supportThicknessMetres+1.0e-6)return;
++audit.supportSamples;
audit.routeSupportSamples+=routeSupport;
const VoxelForgeCore::Vec3d sample{xMetres/coreMetres,yMetres/coreMetres,
(floorMetres-depthMetres)/coreMetres};
const float nativeDensity=Native.densityAt(sample);
const float passageDensity=Field.densityAt(sample);
const float legacySupportDensity=std::min(nativeDensity,
static_cast<float>(-depthMetres/coreMetres));
if(nativeDensity>=0.0f&&legacySupportDensity<0.0f)
++audit.legacyViolations;
if(nativeDensity>=0.0f&&passageDensity<0.0f)
{
audit.routeSupportViolations+=routeSupport;
if(audit.firstViolationCount<audit.firstViolations.size())
audit.firstViolations[audit.firstViolationCount++]={xMetres,yMetres,
floorMetres-depthMetres,passageDensity};
++audit.violations;
}
};
const auto inspectFloorDisc=[&](double xMetres,double yMetres,double floorMetres,
double supportRadiusMetres,double depthMetres,double supportThicknessMetres,
bool routeSupport=false)
{
const std::size_t radialSteps=static_cast<std::size_t>(std::ceil(
supportRadiusMetres/PassageSupportAuditSpacingMetres));
for(std::size_t radialStep=0;radialStep<=radialSteps;++radialStep)
{
const double radial=std::min(supportRadiusMetres,
radialStep*PassageSupportAuditSpacingMetres);
for(const auto& direction:PassageSupportAuditDirections)
inspect(xMetres+direction[0]*radial,yMetres+direction[1]*radial,
floorMetres,depthMetres,supportThicknessMetres,routeSupport);
}
};
for(std::size_t segment=1;segment<passage.controlPoints.size();++segment)
{
const auto& a=passage.controlPoints[segment-1];
const auto& b=passage.controlPoints[segment];
const double ax=qToMetres(a.positionSubvoxels[0]);
const double ay=qToMetres(a.positionSubvoxels[1]);
const double az=qToMetres(a.positionSubvoxels[2]);
const double bx=qToMetres(b.positionSubvoxels[0]);
const double by=qToMetres(b.positionSubvoxels[1]);
const double bz=qToMetres(b.positionSubvoxels[2]);
const double length=std::sqrt((bx-ax)*(bx-ax)+(by-ay)*(by-ay)+(bz-az)*(bz-az));
const std::size_t intervals=std::max<std::size_t>(1,static_cast<std::size_t>(
std::ceil(length/PassageSupportAuditSpacingMetres)));
for(std::size_t sample=0;sample<=intervals;++sample)
{
if(segment>1&&sample==0)continue;
const double t=static_cast<double>(sample)/intervals;
const double centerX=ax+(bx-ax)*t,centerY=ay+(by-ay)*t;
const double centerZ=az+(bz-az)*t;
const double radius=qToMetres(a.radiusSubvoxels)
+(qToMetres(b.radiusSubvoxels)-qToMetres(a.radiusSubvoxels))*t;
const double floorZ=centerZ-radius+0.20;
for(const double depth:PassageSupportAuditDepthsMetres)
inspectFloorDisc(centerX,centerY,floorZ,radius,depth,1.0);
}
}
const auto upperStratum=std::find_if(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[&](const auto& value)
{return value.strateIndex==passage.upperStrateIndex;});
if(upperStratum!=ResolvedLayout->strates.end())
{
std::array<const VoxelForgeCore::ResolvedLayoutAnchorV2*,5> route{};
std::size_t routeCount=0;
for(const auto& anchor:upperStratum->anchors)
if(anchor.kind=="route_point"&&anchor.values.size()>=3)
{
if(routeCount<route.size())route[routeCount++]=&anchor;
else
{
std::move(route.begin()+1,route.end(),route.begin());
route.back()=&anchor;
}
}
const double mouthX=qToMetres(passage.upperMouthSubvoxels[0]);
const double mouthY=qToMetres(passage.upperMouthSubvoxels[1]);
constexpr double RouteSupportReachMetres=13.0;
constexpr double RouteFloorOffsetMetres=1.20;
constexpr double RouteSupportThicknessMetres=1.0;
constexpr double RouteSupportDepthStepMetres=0.125;
for(std::size_t segment=1;segment<routeCount;++segment)
{
const auto& a=*route[segment-1];
const auto& b=*route[segment];
const double ax=qToMetres(a.values[0]),ay=qToMetres(a.values[1]);
const double az=qToMetres(a.values[2]);
const double bx=qToMetres(b.values[0]),by=qToMetres(b.values[1]);
const double bz=qToMetres(b.values[2]);
const double dx=bx-ax,dy=by-ay,dz=bz-az;
const double length=std::sqrt(dx*dx+dy*dy+dz*dz);
const std::size_t intervals=std::max<std::size_t>(1,
static_cast<std::size_t>(std::ceil(length
/PassageSupportAuditSpacingMetres)));
const double routeRadius=a.values.size()>=4
?std::max(0.75,qToMetres(a.values[3])):0.75;
for(std::size_t sample=0;sample<=intervals;++sample)
{
if(segment>1&&sample==0)continue;
const double t=static_cast<double>(sample)/intervals;
const double centerX=ax+dx*t,centerY=ay+dy*t;
const double centerZ=az+dz*t;
for(std::size_t radialStep=0;radialStep<=static_cast<std::size_t>(
std::ceil(routeRadius/PassageSupportAuditSpacingMetres));++radialStep)
{
const double radial=std::min(routeRadius,
radialStep*PassageSupportAuditSpacingMetres);
for(const auto& direction:PassageSupportAuditDirections)
{
const double x=centerX+direction[0]*radial;
const double y=centerY+direction[1]*radial;
if(std::hypot(x-mouthX,y-mouthY)>RouteSupportReachMetres)continue;
const double floorZ=centerZ-RouteFloorOffsetMetres;
for(double depth=RouteSupportDepthStepMetres;
depth<=RouteSupportThicknessMetres+1.0e-6;
depth+=RouteSupportDepthStepMetres)
inspect(x,y,floorZ,depth,RouteSupportThicknessMetres,true);
}
}
}
}
}
return audit;
};
if(Assembly)
for(const auto& stratum:ResolvedLayout->strates)
{
if(stratum.generatorKind!="FloatingIslands")continue;
const auto anchor=std::find_if(stratum.anchors.begin(),stratum.anchors.end(),
[](const auto& value){return value.kind=="passage_anchor"&&value.values.size()>=7;});
const auto islandPlan=std::find_if(Assembly->floatingIslands.begin(),
Assembly->floatingIslands.end(),[&](const auto& value)
{return value.strateIndex==stratum.strateIndex;});
if(anchor==stratum.anchors.end()||islandPlan==Assembly->floatingIslands.end())continue;
const auto ordinal=islandPlan->manifest.recipe.anchorIslandOrdinal;
if(ordinal>=islandPlan->manifest.plan.islands.size())continue;
const auto& anchorIsland=islandPlan->manifest.plan.islands[ordinal];
const double axisX=qToMetres(anchor->values[0]);
const double axisY=qToMetres(anchor->values[1]);
const double rootBottom=qToMetres(anchor->values[5]);
const auto& islandRecipe=islandPlan->manifest.recipe;
const std::int64_t crustRatioQ16=islandRecipe.thicknessRatioQ16
+islandRecipe.crustDepthBonusQ16;
const std::int64_t crustDepthQ=(anchorIsland.radiusSubvoxels*crustRatioQ16
+32768)/65536;
const double rootTop=qToMetres(anchorIsland.topZSubvoxels-crustDepthQ);
const double nominalRootRadius=qToMetres(anchor->values[2]);
double helixMinimumRadius=std::numeric_limits<double>::infinity();
double helixMaximumRadius=0.0;
for(const auto& passage:ResolvedLayout->passages)
if(passage.upperStrateIndex==stratum.strateIndex)
for(const auto& point:passage.controlPoints)
{
const double z=qToMetres(point.positionSubvoxels[2]);
if(z<rootBottom||z>rootTop)continue;
const double radial=std::hypot(
qToMetres(point.positionSubvoxels[0]-anchor->values[0]),
qToMetres(point.positionSubvoxels[1]-anchor->values[1]));
helixMinimumRadius=std::min(helixMinimumRadius,radial);
helixMaximumRadius=std::max(helixMaximumRadius,radial);
}
if(!std::isfinite(helixMinimumRadius))continue;
double minimumMeasuredRootRadius=std::numeric_limits<double>::infinity();
std::uint64_t rootRaySamples=0;
constexpr std::array<double,5> RootHeightFractions{{0.01,0.25,0.5,0.75,0.99}};
for(const double fraction:RootHeightFractions)
{
const double z=rootTop+(rootBottom-rootTop)*fraction;
double minimumRadius=std::numeric_limits<double>::infinity();
double maximumRadius=0.0,meanRadius=0.0;
constexpr std::size_t DirectionCount=32;
constexpr double RayStepMetres=0.125;
const std::size_t raySteps=static_cast<std::size_t>(std::ceil(
(nominalRootRadius+2.0)/RayStepMetres));
for(std::size_t direction=0;direction<DirectionCount;++direction)
{
const double angle=2.0*3.14159265358979323846*direction/DirectionCount;
double radius=0.0;
for(std::size_t step=0;step<=raySteps;++step)
{
const double probeRadius=step*RayStepMetres;
const VoxelForgeCore::Vec3d probe{
(axisX+probeRadius*std::cos(angle))/coreMetres,
(axisY+probeRadius*std::sin(angle))/coreMetres,z/coreMetres};
if(blockedWorld.densityAt(probe)>=0.0f)break;
radius=probeRadius;
}
minimumRadius=std::min(minimumRadius,radius);
maximumRadius=std::max(maximumRadius,radius);
meanRadius+=radius;
++rootRaySamples;
}
meanRadius/=DirectionCount;
minimumMeasuredRootRadius=std::min(minimumMeasuredRootRadius,minimumRadius);
std::printf("[PassageRootRadiusMeasure] strate=%d z_m=%.3f solid_radius_min_m=%.3f mean_m=%.3f max_m=%.3f nominal_root_m=%.3f rays=%zu\n",
stratum.strateIndex,z,minimumRadius,meanRadius,maximumRadius,
nominalRootRadius,DirectionCount);
}
const auto firstRootPassage=std::find_if(ResolvedLayout->passages.begin(),
ResolvedLayout->passages.end(),[&](const auto& passage)
{return passage.upperStrateIndex==stratum.strateIndex;});
const double mouthBoreRadius=firstRootPassage==ResolvedLayout->passages.end()?0.0
:qToMetres(firstRootPassage->mouthRadiusSubvoxels);
const double midBoreRadius=firstRootPassage==ResolvedLayout->passages.end()?0.0
:qToMetres(firstRootPassage->midRadiusSubvoxels);
const double maximumBoreRadius=std::max(mouthBoreRadius,midBoreRadius);
std::printf("[PassageRootMeasure] strate=%d axis_m=(%.3f,%.3f) helix_centerline_radius_min_m=%.3f max_m=%.3f mouth_bore_radius_m=%.3f mid_bore_radius_m=%.3f nominal_root_m=%.3f measured_min_root_m=%.3f minimum_wall_m=%.3f samples=%llu\n",
stratum.strateIndex,axisX,axisY,helixMinimumRadius,helixMaximumRadius,
mouthBoreRadius,midBoreRadius,nominalRootRadius,minimumMeasuredRootRadius,
minimumMeasuredRootRadius-helixMaximumRadius-maximumBoreRadius,
static_cast<unsigned long long>(rootRaySamples));
}
const auto mouthInContent=[&](std::int32_t index,const std::array<std::int64_t,3>& mouth)
{
const auto* stratum=findStratum(index);if(!stratum)return false;
@@ -667,6 +938,8 @@ namespace StandaloneStreamBenchmark
return zUm>=stratum->content.bottomMicrometres&&zUm<stratum->content.topMicrometres;
};
std::uint64_t passageCount=0,passagePasses=0,blockedControls=0,naturalPasses=0;
std::uint64_t openAirViolations=0,openAirLegacyViolations=0,openAirSamples=0;
std::uint64_t openAirAudits=0;
for(const auto& passage:ResolvedLayout->passages)
{
std::vector<std::array<double,3>> path;path.reserve(passage.controlPoints.size());
@@ -680,6 +953,11 @@ namespace StandaloneStreamBenchmark
}
const FWalkAudit passageAudit=auditPlayerPath(Shape,path,0.125,0.125,0.25,3,0.45);
const FPassageNaturalnessAudit naturalAudit=auditPassageNaturalness(Shape,passage);
const FPassageOpenAirAudit openAirAudit=auditPassageOpenAir(Shape,blockedWorld,passage);
openAirSamples+=openAirAudit.supportSamples;
openAirViolations+=openAirAudit.violations;
openAirLegacyViolations+=openAirAudit.legacyViolations;
++openAirAudits;
const auto radialSquared=[](const std::array<std::int64_t,3>& p)
{return p[0]*p[0]+p[1]*p[1];};
const bool mouthsInRadius=radialSquared(passage.upperMouthSubvoxels)
@@ -706,15 +984,32 @@ namespace StandaloneStreamBenchmark
static_cast<unsigned long long>(naturalAudit.wallSamples),
static_cast<unsigned long long>(naturalAudit.missingWallSamples),
naturalAudit.passed?"PASS":"FAIL");
std::printf("[PassageOpenAirAudit] id=%s support_samples=%llu violations=%llu l24_ungated_violations=%llu route_support_samples=%llu route_support_violations=%llu spacing_m=%.3f status=%s\n",
passage.stableId.c_str(),static_cast<unsigned long long>(openAirAudit.supportSamples),
static_cast<unsigned long long>(openAirAudit.violations),
static_cast<unsigned long long>(openAirAudit.legacyViolations),
static_cast<unsigned long long>(openAirAudit.routeSupportSamples),
static_cast<unsigned long long>(openAirAudit.routeSupportViolations),
PassageSupportAuditSpacingMetres,
openAirAudit.violations==0?"PASS":"FAIL");
for(std::size_t i=0;i<openAirAudit.firstViolationCount;++i)
std::printf("[PassageOpenAirAuditSample] id=%s kind=unsupported_support xyz_m=(%.3f,%.3f,%.3f) density=%.6f\n",
passage.stableId.c_str(),openAirAudit.firstViolations[i][0],
openAirAudit.firstViolations[i][1],openAirAudit.firstViolations[i][2],
openAirAudit.firstViolations[i][3]);
for(std::size_t i=0;i<passageAudit.firstBlockedCount;++i)
{
const auto& sample=passageAudit.firstBlocked[i];
std::printf("[ResolvedPassageAuditSample] id=%s kind=blocked xyz_m=(%.3f,%.3f,%.3f) density=%.6f\n",
passage.stableId.c_str(),passageAudit.firstBlocked[i][0],passageAudit.firstBlocked[i][1],
passageAudit.firstBlocked[i][2],passageAudit.firstBlocked[i][3]);
passage.stableId.c_str(),sample[0],sample[1],sample[2],sample[3]);
}
for(std::size_t i=0;i<passageAudit.firstUnsupportedCount;++i)
{
std::printf("[ResolvedPassageAuditSample] id=%s kind=unsupported xyz_m=(%.3f,%.3f,%.3f) density=%.6f\n",
passage.stableId.c_str(),passageAudit.firstUnsupported[i][0],
passageAudit.firstUnsupported[i][1],passageAudit.firstUnsupported[i][2],
passageAudit.firstUnsupported[i][3]);
}
}
std::uint64_t routePoints=0,routePasses=0,routeWalkPasses=0,routeBindings=0,routeBindingFailures=0;
struct FRouteAuditInput
@@ -798,15 +1093,28 @@ namespace StandaloneStreamBenchmark
{return a[0]==b[0]&&a[1]==b[1]&&a[2]==b[2];};
if(passage.upperStrateIndex==stratum.strateIndex)
{
const std::array<std::int64_t,3> departure{{anchors.back()->values[0],
anchors.back()->values[1],anchors.back()->values[2]}};
const auto rootedMouth=std::find_if(stratum.anchors.begin(),
stratum.anchors.end(),[](const auto& anchor)
{return anchor.kind=="passage_anchor"&&anchor.values.size()>=10;});
const std::array<std::int64_t,3> departure=
rootedMouth!=stratum.anchors.end()
?std::array<std::int64_t,3>{{rootedMouth->values[7],
rootedMouth->values[8],rootedMouth->values[9]}}
:std::array<std::int64_t,3>{{anchors.back()->values[0],
anchors.back()->values[1],anchors.back()->values[2]}};
binding&=equalPosition(passage.upperMouthSubvoxels,
departure);
}
if(passage.lowerStrateIndex==stratum.strateIndex)
{
const std::array<std::int64_t,3> arrival{{anchors.front()->values[0],
anchors.front()->values[1],anchors.front()->values[2]}};
const auto passageArrival=std::find_if(stratum.anchors.begin(),
stratum.anchors.end(),[](const auto& anchor)
{return anchor.kind=="passage_arrival"&&anchor.values.size()>=3;});
const std::array<std::int64_t,3> arrival=passageArrival!=stratum.anchors.end()
?std::array<std::int64_t,3>{{passageArrival->values[0],
passageArrival->values[1],passageArrival->values[2]}}
:std::array<std::int64_t,3>{{anchors.front()->values[0],
anchors.front()->values[1],anchors.front()->values[2]}};
binding&=equalPosition(passage.lowerMouthSubvoxels,
arrival);
}
@@ -831,43 +1139,45 @@ namespace StandaloneStreamBenchmark
routeAudit.firstUnsupported[i][1],routeAudit.firstUnsupported[i][2],
routeAudit.firstUnsupported[i][3]);
}
const auto controlSnapshot=CoreSnapshot.withoutResolvedLayoutPassages();
VoxelForgeCore::World blockedWorld(controlSnapshot);
std::string blockedCompileError;
const bool blockedCompiled=controlSnapshot
&&blockedWorld.compile(ShapeRequest,Scheduler,blockedCompileError);
if(blockedCompiled)
for(const auto& passage:ResolvedLayout->passages)
for(const auto& passage:ResolvedLayout->passages)
{
std::vector<std::array<double,3>> path;path.reserve(passage.controlPoints.size());
for(const auto& point:passage.controlPoints)
{
std::vector<std::array<double,3>> path;path.reserve(passage.controlPoints.size());
for(const auto& point:passage.controlPoints)
{
const double playerZ=static_cast<double>(point.positionSubvoxels[2]
-point.radiusSubvoxels)+1.13*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel
*1000000.0/World.CoreVoxelSizeMicrons;
path.push_back({qToMetres(point.positionSubvoxels[0])/coreMetres,
qToMetres(point.positionSubvoxels[1])/coreMetres,playerZ/256.0});
}
const FWalkAudit blockedAudit=auditPlayerPath(blockedWorld,path,
0.125,0.125,0.25,3,0.45);
blockedControls+=blockedAudit.blocked>0&&!blockedAudit.passed;
std::printf("[ResolvedPassageBlockedControl] id=%s blocked_capsule_samples=%llu detected=%s\n",
passage.stableId.c_str(),static_cast<unsigned long long>(blockedAudit.blocked),
blockedAudit.blocked>0&&!blockedAudit.passed?"true":"false");
}
else
std::fprintf(stderr,"[ResolvedPassageBlockedControl] compile_failed=%s\n",blockedCompileError.c_str());
if(blockedCompiled)
for(const auto& input:routeAuditInputs)
{
const FWalkAudit controlRoute=auditPlayerPath(blockedWorld,input.path,
input.supportStart,input.supportStep,input.supportMaximum,
input.minimumSupportProbes,input.supportProbeRadius);
std::printf("[ResolvedStrateRouteBlockedControl] strate=%d blocked=%llu unsupported=%llu status=%s\n",
input.strateIndex,static_cast<unsigned long long>(controlRoute.blocked),
static_cast<unsigned long long>(controlRoute.unsupported),
controlRoute.passed?"PASS":"FAIL");
const double playerZ=static_cast<double>(point.positionSubvoxels[2]
-point.radiusSubvoxels)+1.13*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel
*1000000.0/World.CoreVoxelSizeMicrons;
path.push_back({qToMetres(point.positionSubvoxels[0])/coreMetres,
qToMetres(point.positionSubvoxels[1])/coreMetres,playerZ/256.0});
}
const FWalkAudit blockedAudit=auditPlayerPath(blockedWorld,path,
0.125,0.125,0.25,3,0.45);
blockedControls+=blockedAudit.blocked>0&&!blockedAudit.passed;
std::printf("[ResolvedPassageBlockedControl] id=%s blocked_capsule_samples=%llu detected=%s\n",
passage.stableId.c_str(),static_cast<unsigned long long>(blockedAudit.blocked),
blockedAudit.blocked>0&&!blockedAudit.passed?"true":"false");
}
for(const auto& input:routeAuditInputs)
{
const FWalkAudit controlRoute=auditPlayerPath(blockedWorld,input.path,
input.supportStart,input.supportStep,input.supportMaximum,
input.minimumSupportProbes,input.supportProbeRadius);
std::printf("[ResolvedStrateRouteBlockedControl] strate=%d blocked=%llu unsupported=%llu status=%s\n",
input.strateIndex,static_cast<unsigned long long>(controlRoute.blocked),
static_cast<unsigned long long>(controlRoute.unsupported),
controlRoute.passed?"PASS":"FAIL");
}
const bool l24OpenAirControlDetected=openAirLegacyViolations>0;
std::printf("[PassageOpenAirNegativeControl] source=L24_ungated_support unsupported_samples=%llu detected=%s\n",
static_cast<unsigned long long>(openAirLegacyViolations),
l24OpenAirControlDetected?"true":"false");
std::printf("[PassageOpenAirAuditSummary] interfaces=%llu samples=%llu violations=%llu l24_negative_control=%s status=%s\n",
static_cast<unsigned long long>(openAirAudits),
static_cast<unsigned long long>(openAirSamples),
static_cast<unsigned long long>(openAirViolations),
l24OpenAirControlDetected?"DETECTED":"MISSED",
openAirAudits==passageCount&&openAirViolations==0&&l24OpenAirControlDetected
?"PASS":"FAIL");
const bool l23SmoothWallDetected=!looksNatural(0.0,0.0);
std::printf("[PassageNaturalnessNegativeControl] source=L23_smooth_unrelieved_wall relief_p2p_m=0.000 threshold_m=%.3f detected=%s\n",
MinimumWallReliefMetres,l23SmoothWallDetected?"true":"false");
@@ -877,6 +1187,7 @@ namespace StandaloneStreamBenchmark
MinimumWallReliefMetres,naturalPasses==passageCount&&l23SmoothWallDetected?"PASS":"FAIL");
const bool auditPassed=passageCount>0&&passagePasses==passageCount
&&naturalPasses==passageCount&&l23SmoothWallDetected
&&openAirAudits==passageCount&&openAirViolations==0&&l24OpenAirControlDetected
&&routePasses>0&&routePasses==routeWalkPasses&&routePasses==routeBindings
&&routeBindingFailures==0
&&blockedCompiled&&blockedControls==passageCount;
+84 -13
View File
@@ -540,7 +540,7 @@ namespace StandaloneWorldAssemblyPrototype
FIntVector(0,0,islandSlot->TopChunkZ));
const FStratePassageConfig& passage=islandSlot->Definition->PassageConfig;
recipe.seed=static_cast<std::uint32_t>(owner.Seed);
recipe.geometryVersion=5;
recipe.geometryVersion=7;
recipe.ownerVoxelSizeMicrons=owner.OwnerVoxelSizeMicrons;
recipe.coreVoxelSizeMicrons=owner.CoreVoxelSizeMicrons;
recipe.ownerToCoreScaleNumerator=owner.OwnerVoxelSizeMicrons/static_cast<std::uint32_t>(divisor);
@@ -573,17 +573,22 @@ namespace StandaloneWorldAssemblyPrototype
recipe.anchorPlacementRadiusSubvoxels=ownerVoxelsToCoreQ(passage.DistanceMax);
const std::int64_t spiralRadius=ownerVoxelsToCoreQ(passage.SpiralRadius);
const std::int64_t mouthBore=std::max(ownerVoxelsToCoreQ(passage.MouthRadius),
ownerVoxelsToCoreQ(12.0));
ownerVoxelsToCoreQ(36.0));
const std::int64_t bore=std::max(ownerVoxelsToCoreQ(passage.MidRadius),
ownerVoxelsToCoreQ(12.0));
const std::int64_t wallReserve=ownerVoxelsToCoreQ(12.0);
// Put the mouth near the island rim, with enough island and root around the
// first coil to read as a cave entrance instead of a hole in open air.
recipe.anchorMouthOffsetSubvoxels=spiralRadius+mouthBore+ownerVoxelsToCoreQ(4.0);
const std::int64_t excursion=std::max(ownerVoxelsToCoreQ(passage.Wander),spiralRadius);
recipe.anchorRootRadiusSubvoxels=excursion+bore+wallReserve;
ownerVoxelsToCoreQ(24.0));
const std::int64_t wallReserve=ownerVoxelsToCoreQ(20.0);
// Retain a 4.5-metre mouth for capsule clearance while keeping the long
// ramp at three metres to leave more rock around the first coil.
recipe.anchorMouthOffsetSubvoxels=ownerVoxelsToCoreQ(40.0);
const std::int64_t supportOverhang=ownerVoxelsToCoreQ(16.0);
const std::int64_t rootTaperReserve=ownerVoxelsToCoreQ(10.0);
const std::int64_t mouthEnvelope=recipe.anchorMouthOffsetSubvoxels+mouthBore;
const std::int64_t treadEnvelope=spiralRadius+bore+supportOverhang;
recipe.anchorRootRadiusSubvoxels=std::max(mouthEnvelope,treadEnvelope)
+wallReserve+rootTaperReserve;
recipe.anchorIslandMinimumRadiusSubvoxels=std::max(recipe.minimumRadiusSubvoxels,
recipe.anchorMouthOffsetSubvoxels+mouthBore+ownerVoxelsToCoreQ(4.0));
std::max(recipe.anchorMouthOffsetSubvoxels+mouthBore+ownerVoxelsToCoreQ(4.0),
recipe.anchorRootRadiusSubvoxels+wallReserve));
recipe.anchorRootBottomZSubvoxels=recipe.layoutMinimumZSubvoxels
+recipe.boundarySealSubvoxels;
@@ -713,6 +718,39 @@ namespace StandaloneWorldAssemblyPrototype
[&](const auto& p){return p.strateIndex==slot.StrateIndex;});
if(it!=assembly.floatingIslands.end())
{
std::size_t passageMouthRouteIndex=it->manifest.plan.route.empty()?0
:it->manifest.plan.route.size()-1;
std::size_t resolvedRoutePointCount=it->manifest.plan.route.size();
if(it->manifest.recipe.geometryVersion>=5
&&!it->manifest.plan.route.empty()
&&it->manifest.recipe.anchorIslandOrdinal<it->manifest.plan.islands.size())
{
const auto& rootedIsland=it->manifest.plan.islands[
it->manifest.recipe.anchorIslandOrdinal];
const double qPerMetre=static_cast<double>(
VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)*1000000.0
/owner.CoreVoxelSizeMicrons;
const double thresholdQ=static_cast<double>(
it->manifest.recipe.anchorMouthOffsetSubvoxels)+qPerMetre;
for(std::size_t reverse=it->manifest.plan.route.size();reverse>1;--reverse)
{
const std::size_t index=reverse-1;
const auto& point=it->manifest.plan.route[index].positionSubvoxels;
const double dx=static_cast<double>(point[0]-rootedIsland.centerSubvoxels[0]);
const double dy=static_cast<double>(point[1]-rootedIsland.centerSubvoxels[1]);
if(std::hypot(dx,dy)>thresholdQ)
{
passageMouthRouteIndex=std::min(index+1,
it->manifest.plan.route.size()-1);
break;
}
}
// Stop the island surface route immediately before it enters
// the outer coil. The helical passage owns the walkable path
// from its mouth inward.
resolvedRoutePointCount=passageMouthRouteIndex>1
?passageMouthRouteIndex-1:passageMouthRouteIndex;
}
const auto recipeBottom=fixedToMicrons(it->manifest.recipe.layoutMinimumZSubvoxels);
const auto recipeTop=fixedToMicrons(it->manifest.recipe.layoutMaximumZSubvoxels);
if(recipeBottom!=bottom||recipeTop!=top)
@@ -737,10 +775,17 @@ namespace StandaloneWorldAssemblyPrototype
it->manifest.recipe.anchorPlacementRadiusSubvoxels,
it->manifest.recipe.anchorRootBottomZSubvoxels,
a.radiusSubvoxels};
if(!it->manifest.plan.route.empty())
{
const auto& routeMouth=it->manifest.plan.route[
passageMouthRouteIndex].positionSubvoxels;
passageAnchor.values.insert(passageAnchor.values.end(),
{routeMouth[0],routeMouth[1],routeMouth[2]});
}
s.anchors.push_back(std::move(passageAnchor));
}
}
for(std::size_t n=0;n<it->manifest.plan.route.size();++n)
for(std::size_t n=0;n<resolvedRoutePointCount;++n)
{
const auto& p=it->manifest.plan.route[n];ResolvedLayoutAnchorV2 anchor;
anchor.kind="route_point";anchor.stableId="route/"+std::to_string(n);
@@ -788,6 +833,32 @@ namespace StandaloneWorldAssemblyPrototype
{const auto& p=plan->route[n];ResolvedLayoutAnchorV2 a;a.kind="route_point";a.stableId="route/"+std::to_string(n);
a.units="1/256 Core voxel";a.values={p.positionSubvoxels[0],p.positionSubvoxels[1],p.positionSubvoxels[2],p.radiusSubvoxels};
s.anchors.push_back(std::move(a));}
const auto upperAnchorStratum=std::find_if(out.strates.begin(),out.strates.end(),
[](const auto& candidate)
{return candidate.generatorKind=="FloatingIslands"
&&std::any_of(candidate.anchors.begin(),candidate.anchors.end(),
[](const auto& anchor){return anchor.kind=="passage_anchor"
&&anchor.values.size()>=7;});});
if(upperAnchorStratum!=out.strates.end())
{
const auto rootAnchor=std::find_if(upperAnchorStratum->anchors.begin(),
upperAnchorStratum->anchors.end(),[](const auto& anchor)
{return anchor.kind=="passage_anchor"&&anchor.values.size()>=7;});
const std::int64_t arrivalZMicrometres=top-seal-1250000;
if(rootAnchor!=upperAnchorStratum->anchors.end()
&&arrivalZMicrometres>=bottom+seal&&arrivalZMicrometres<top-seal)
{
ResolvedLayoutAnchorV2 arrival;arrival.kind="passage_arrival";
arrival.stableId="passage-arrival/from-strate/"
+std::to_string(upperAnchorStratum->strateIndex);
arrival.units="1/256 Core voxel";
arrival.values={rootAnchor->values[0],rootAnchor->values[1],
static_cast<std::int64_t>(std::llround(
static_cast<double>(arrivalZMicrometres)
*WorldAssemblySubvoxelsPerVoxel/owner.CoreVoxelSizeMicrons))};
s.anchors.push_back(std::move(arrival));
}
}
}
out.strates.push_back(std::move(s));
}
@@ -803,9 +874,9 @@ namespace StandaloneWorldAssemblyPrototype
config.connections=authored.Connections;
config.style=static_cast<std::uint32_t>(authored.Style);
config.mouthRadiusSubvoxels=std::max(ownerVoxelsToCoreQ(authored.MouthRadius),
ownerVoxelsToCoreQ(12.0));
ownerVoxelsToCoreQ(36.0));
config.midRadiusSubvoxels=std::max(ownerVoxelsToCoreQ(authored.MidRadius),
ownerVoxelsToCoreQ(12.0));
ownerVoxelsToCoreQ(24.0));
config.reachMinimumSubvoxels=ownerVoxelsToCoreQ(authored.ReachMin);
config.reachMaximumSubvoxels=ownerVoxelsToCoreQ(authored.ReachMax);
config.distanceMinimumSubvoxels=ownerVoxelsToCoreQ(authored.DistanceMin);