core: Vertical Shafts on the shared Core cave planner (L139, v237; 15/16 seeds)

Shaft mode reuses PlanResolvedCavernNetworkV1 with a capped full-height cylinder primitive (shapeKind=1), ledges,
access bores and cross links; 11 VerticalShaftParams fields mapped. Basal law: arrival 2-3 to a walkable terminal
landing; drops/climbs stay reporting tiers. Seed 2 fails shell/seams at the 2-3 arrival mouth (3 variants tried,
stopped per AGENTS.md). Whole view faster than assembler/world in 8/8 cells; near-ready slower in 7/8.
Source/: VoxelForgeCoreAdapter.cpp.

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-11-01 05:34:00 +01:00
1 parent fa4417aad0
commit 318c5cf4f2
31 files changed
+1719 -106

No files matched your search

+89 -6
View File
@@ -1284,7 +1284,8 @@ public:
const std::uint32_t reliefSeed=static_cast<std::uint32_t>(Owner?Owner->Seed:0);
const auto* queryStratum=FindBoundStratumForManagerZ(Z);
const bool plannedTunnelStratum=queryStratum&&queryStratum->Resolved
&&queryStratum->Resolved->generatorKind=="TunnelNetwork"
&&(queryStratum->Resolved->generatorKind=="TunnelNetwork"
||queryStratum->Resolved->generatorKind=="VerticalShafts")
&&queryStratum->Resolved->recipeId=="Core.Caves.PrimitiveField"
&&queryStratum->Resolved->recipeVersion==1;
const auto* routePassageIndices=passageTileScopeMatches
@@ -1617,9 +1618,12 @@ public:
const auto plannedPortalWalkCorridorContains=[&]()
{
if(!queryStratum||!queryStratum->Resolved
||queryStratum->Resolved->generatorKind!="TunnelNetwork"
||(queryStratum->Resolved->generatorKind!="TunnelNetwork"
&&queryStratum->Resolved->generatorKind!="VerticalShafts")
||queryStratum->Resolved->recipeId!="Core.Caves.PrimitiveField"
||queryStratum->Resolved->recipeVersion!=1)return false;
const bool terminalShaftRoute=
queryStratum->Resolved->generatorKind=="VerticalShafts";
const VoxelForgeCore::ResolvedLayoutAnchorV2* first=nullptr;
const VoxelForgeCore::ResolvedLayoutAnchorV2* second=nullptr;
const VoxelForgeCore::ResolvedLayoutAnchorV2* third=nullptr;
@@ -1638,8 +1642,12 @@ public:
}
if(routeCount<6||!first||!second||!third||!lastThree||!lastTwo||!last
||!first->stableId.ends_with("000-arrival")
||!second->stableId.ends_with("000-edge-start")
||!lastTwo->stableId.ends_with("998-departure-inner")
||!second->stableId.ends_with("000-edge-start"))return false;
if(terminalShaftRoute)
{
if(!last->stableId.ends_with("999-basal-terminal"))return false;
}
else if(!lastTwo->stableId.ends_with("998-departure-inner")
||!last->stableId.ends_with("999-departure"))return false;
const double metresPerSubvoxel=1.0/qPerMetre;
const auto position=[&](const VoxelForgeCore::ResolvedLayoutAnchorV2& anchor)
@@ -1677,6 +1685,7 @@ public:
if(nearRouteSegment(*first,*second,PortalWalkLeadMetres,false,0.0)
||nearRouteSegment(*second,*third,PortalWalkLeadMetres,false,
arrivalInnerDistance))return true;
if(terminalShaftRoute)return false;
const auto departureInner=position(*lastTwo),departure=position(*last);
const double departureTailDistance=std::hypot(
departure[0]-departureInner[0],departure[1]-departureInner[1]);
@@ -3835,8 +3844,11 @@ private:
const VoxelForgeCore::ResolvedCavernRoomV1* room=nullptr;
const VoxelForgeCore::ResolvedCavernEdgeV1* edge=nullptr;
bool nativeGraph=false;
std::uint8_t roomShapeKind=0;
std::uint8_t ledgeSide=0;
std::array<std::int64_t,3> boundsMinimumMicrometres{},boundsMaximumMicrometres{};
std::array<double,3> centerMetres{},halfExtentsMetres{};
double ledgeSpacingMetres=0.0,ledgeDepthMetres=0.0;
struct FSegment
{
std::array<double,3> start{},end{},minimum{},maximum{};
@@ -4285,7 +4297,9 @@ private:
||(ResolvedLayout->cavernGraphVocabularyVersion
!=VoxelForgeCore::ResolvedLayoutCavernGraphVocabularyVersionV1
&&ResolvedLayout->cavernGraphVocabularyVersion
!=VoxelForgeCore::ResolvedLayoutCavernGraphVocabularyVersionV2))return;
!=VoxelForgeCore::ResolvedLayoutCavernGraphVocabularyVersionV2
&&ResolvedLayout->cavernGraphVocabularyVersion
!=VoxelForgeCore::ResolvedLayoutCavernGraphVocabularyVersionV3))return;
const auto isNativeGraphStrate=[this](std::int32_t strateIndex)
{
const auto found=std::find_if(ResolvedLayout->strates.begin(),
@@ -4302,6 +4316,10 @@ private:
{
FCavernRuntimeFeature runtime;runtime.room=&room;
runtime.nativeGraph=isNativeGraphStrate(room.strateIndex);
runtime.roomShapeKind=room.shapeKind;
runtime.ledgeSide=room.ledgeSide;
runtime.ledgeSpacingMetres=room.ledgeSpacingMicrometres/1000000.0;
runtime.ledgeDepthMetres=room.ledgeDepthMicrometres/1000000.0;
runtime.boundsMinimumMicrometres=room.boundsMinimumMicrometres;
runtime.boundsMaximumMicrometres=room.boundsMaximumMicrometres;
for(std::size_t axis=0;axis<3;++axis)
@@ -4956,7 +4974,8 @@ private:
ResolvedLayout->strates.end(),[&](const auto& stratum)
{return stratum.strateIndex==passage.lowerStrateIndex;});
if(lowerStratum!=ResolvedLayout->strates.end()
&&lowerStratum->generatorKind=="TunnelNetwork"
&&(lowerStratum->generatorKind=="TunnelNetwork"
||lowerStratum->generatorKind=="VerticalShafts")
&&routeEnd<controls.size())
{
double routeHeight=0.0,distanceSquared=0.0;
@@ -5667,6 +5686,11 @@ public:
FMetricInterval featureVoid;
if(feature.room)
{
// Shaft wall and ledge SDFs are evaluated exactly per sample.
// Until a conservative interval bound for their carved shelves is
// available, keep intersecting boxes Mixed instead of proving a
// potentially false uniform sign.
if(feature.roomShapeKind==1)return {0.0,0.0,false};
double normalizedMinimumSquared=0.0,normalizedMaximumSquared=0.0;
double meanRadius=0.0;
for(std::size_t axis=0;axis<3;++axis)
@@ -7884,6 +7908,64 @@ private:
double edgeFloor=0.0;
if(feature.room)
{
if(feature.roomShapeKind==1)
{
const double radius=feature.halfExtentsMetres[0];
const double bottom=feature.centerMetres[2]-feature.halfExtentsMetres[2];
const double top=feature.centerMetres[2]+feature.halfExtentsMetres[2];
const double radial=std::hypot(point[0]-feature.centerMetres[0],
point[1]-feature.centerMetres[1]);
const double radialQ=radial-radius;
const double verticalQ=std::max(bottom-point[2],point[2]-top);
double shaftDistance=std::min(std::max(radialQ,verticalQ),0.0)
+std::hypot(std::max(radialQ,0.0),std::max(verticalQ,0.0));
if(feature.irregularityAmplitudeVoxels>0.0f)
shaftDistance+=StampValueNoise(
X-feature.centerVoxels[0],Y-feature.centerVoxels[1],
Z-feature.centerVoxels[2],feature.irregularityWavelengthVoxels,
feature.irregularitySeed)
*feature.irregularityAmplitudeVoxels*metresPerVoxel;
// A cardinal ledge faces the walkable backbone. Shelves are
// cut out of the otherwise open cylinder, leaving most of the
// shaft cross-section clear at every interval.
if(feature.ledgeSpacingMetres>0.0&&feature.ledgeDepthMetres>0.0)
{
const long long nearest=static_cast<long long>(std::llround(
(top-point[2])/feature.ledgeSpacingMetres));
const long long maximum=static_cast<long long>(std::floor(
(top-bottom-1000000.0)/feature.ledgeSpacingMetres));
if(nearest>=1&&nearest<=maximum)
{
const double ledgeZ=top-nearest*feature.ledgeSpacingMetres;
constexpr double LedgeThicknessMetres=0.6;
constexpr double LedgeFilletMetres=0.1;
const double dx=point[0]-feature.centerMetres[0];
const double dy=point[1]-feature.centerMetres[1];
const std::array<std::array<double,2>,4> sides={{{1.0,0.0},
{0.0,1.0},{-1.0,0.0},{0.0,-1.0}}};
const auto side=sides[feature.ledgeSide%4];
const double radialLocal=dx*side[0]+dy*side[1];
const double tangentLocal=-dx*side[1]+dy*side[0];
const double halfDepth=feature.ledgeDepthMetres*0.5;
const double halfWidth=radius*0.45;
const double halfThickness=LedgeThicknessMetres*0.5;
const double qx=std::abs(radialLocal-(radius-halfDepth))-halfDepth;
const double qy=std::abs(tangentLocal)-halfWidth;
const double qz=std::abs(point[2]-(ledgeZ-halfThickness))
-halfThickness;
const double outside=std::hypot(std::max(qx,0.0),
std::max(qy,0.0),std::max(qz,0.0));
const double platformDistance=outside
+std::min(std::max(qx,std::max(qy,qz)),0.0)
-LedgeFilletMetres;
shaftDistance=std::max(shaftDistance,-platformDistance);
}
}
featureVoid=shaftDistance;
}
else
{
double normalizedSquared=0.0,meanRadius=0.0;
for(std::size_t axis=0;axis<3;++axis)
{
@@ -7907,6 +7989,7 @@ private:
+feature.floorGradient[1]*(point[1]-feature.centerMetres[1]);
const double width=feature.room->smoothWidthMicrometres/1000000.0;
featureVoid=SmoothMaxMetres(ellipsoid,floor,width);
}
}
else if(feature.edge&&!feature.segments.empty())
{