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:
1 parent
fa4417aad0
commit
318c5cf4f2
31 files changed
+1719
-106
No files matched your search
@@ -5147,6 +5147,7 @@ namespace StandaloneStreamBenchmark
|
||||
}
|
||||
std::uint64_t routePoints=0,routePasses=0,routeWalkPasses=0,routeBindings=0,routeBindingFailures=0;
|
||||
std::uint64_t tunnelNetworkRoutes=0,tunnelNetworkBlockedControls=0;
|
||||
std::uint64_t verticalShaftRoutes=0,verticalShaftBlockedControls=0;
|
||||
for(const auto& stratum:ResolvedLayout->strates)
|
||||
{
|
||||
std::vector<const VoxelForgeCore::ResolvedLayoutAnchorV2*> anchors;
|
||||
@@ -5206,7 +5207,8 @@ namespace StandaloneStreamBenchmark
|
||||
supportMaximumMetres=routeConstraints->supportSearchDepthSubvoxels*qMetres;
|
||||
}
|
||||
}
|
||||
if(stratum.generatorKind=="TunnelNetwork")
|
||||
if(stratum.generatorKind=="TunnelNetwork"
|
||||
||stratum.generatorKind=="VerticalShafts")
|
||||
{
|
||||
std::int64_t floorSupportDepth=0;
|
||||
for(const auto& edge:ResolvedLayout->cavernEdges)
|
||||
@@ -5297,9 +5299,12 @@ namespace StandaloneStreamBenchmark
|
||||
stratum.strateIndex,routeAudit.firstUnsupported[i][0],
|
||||
routeAudit.firstUnsupported[i][1],routeAudit.firstUnsupported[i][2],
|
||||
routeAudit.firstUnsupported[i][3]);
|
||||
if(stratum.generatorKind=="TunnelNetwork")
|
||||
if(stratum.generatorKind=="TunnelNetwork"
|
||||
||stratum.generatorKind=="VerticalShafts")
|
||||
{
|
||||
++tunnelNetworkRoutes;
|
||||
const bool verticalShafts=stratum.generatorKind=="VerticalShafts";
|
||||
if(verticalShafts)++verticalShaftRoutes;
|
||||
else ++tunnelNetworkRoutes;
|
||||
auto controlRoute=route;
|
||||
constexpr double OffBoreControlOffsetMetres=12.0;
|
||||
const std::size_t controlIndex=controlRoute.size()/2;
|
||||
@@ -5319,11 +5324,22 @@ namespace StandaloneStreamBenchmark
|
||||
supportStartMetres,supportStepMetres,supportMaximumMetres,
|
||||
minimumSupportProbes,supportProbeRadiusMetres);
|
||||
const bool detected=control.blocked>0&&!control.passed;
|
||||
tunnelNetworkBlockedControls+=detected;
|
||||
std::printf("[TunnelNetworkBlockedRouteControl] strate=%d mode=off_bore_lateral_deviation_m=%.1f blocked_capsule_samples=%llu result=%s expected=FAIL status=%s\n",
|
||||
stratum.strateIndex,OffBoreControlOffsetMetres,
|
||||
static_cast<unsigned long long>(control.blocked),
|
||||
control.passed?"PASS":"FAIL",detected?"PASS":"FAIL");
|
||||
if(verticalShafts)
|
||||
{
|
||||
verticalShaftBlockedControls+=detected;
|
||||
std::printf("[VerticalShaftsBlockedRouteControl] strate=%d mode=off_bore_lateral_deviation_m=%.1f blocked_capsule_samples=%llu result=%s expected=FAIL status=%s\n",
|
||||
stratum.strateIndex,OffBoreControlOffsetMetres,
|
||||
static_cast<unsigned long long>(control.blocked),
|
||||
control.passed?"PASS":"FAIL",detected?"PASS":"FAIL");
|
||||
}
|
||||
else
|
||||
{
|
||||
tunnelNetworkBlockedControls+=detected;
|
||||
std::printf("[TunnelNetworkBlockedRouteControl] strate=%d mode=off_bore_lateral_deviation_m=%.1f blocked_capsule_samples=%llu result=%s expected=FAIL status=%s\n",
|
||||
stratum.strateIndex,OffBoreControlOffsetMetres,
|
||||
static_cast<unsigned long long>(control.blocked),
|
||||
control.passed?"PASS":"FAIL",detected?"PASS":"FAIL");
|
||||
}
|
||||
}
|
||||
}
|
||||
for(std::size_t passageIndex=0;
|
||||
@@ -5392,8 +5408,9 @@ namespace StandaloneStreamBenchmark
|
||||
&&routePasses>0&&routePasses==routeWalkPasses&&routePasses==routeBindings
|
||||
&&routeBindingFailures==0
|
||||
&&tunnelNetworkRoutes==tunnelNetworkBlockedControls
|
||||
&&verticalShaftRoutes==verticalShaftBlockedControls
|
||||
&&blockedCompiled&&blockedControls==passageCount;
|
||||
std::printf("[ResolvedPassageAuditSummary] interfaces=%llu passed=%llu natural=%llu/%llu strate_routes=%llu route_walkable=%llu route_points=%llu route_bindings=%llu route_binding_failures=%llu tunnel_network_block_controls=%llu/%llu blocked_controls=%llu/%llu status=%s\n",
|
||||
std::printf("[ResolvedPassageAuditSummary] interfaces=%llu passed=%llu natural=%llu/%llu strate_routes=%llu route_walkable=%llu route_points=%llu route_bindings=%llu route_binding_failures=%llu tunnel_network_block_controls=%llu/%llu vertical_shaft_block_controls=%llu/%llu blocked_controls=%llu/%llu status=%s\n",
|
||||
static_cast<unsigned long long>(passageCount),static_cast<unsigned long long>(passagePasses),
|
||||
static_cast<unsigned long long>(naturalPasses),static_cast<unsigned long long>(passageCount),
|
||||
static_cast<unsigned long long>(routePasses),static_cast<unsigned long long>(routeWalkPasses),
|
||||
@@ -5401,6 +5418,8 @@ namespace StandaloneStreamBenchmark
|
||||
static_cast<unsigned long long>(routeBindings),static_cast<unsigned long long>(routeBindingFailures),
|
||||
static_cast<unsigned long long>(tunnelNetworkBlockedControls),
|
||||
static_cast<unsigned long long>(tunnelNetworkRoutes),
|
||||
static_cast<unsigned long long>(verticalShaftBlockedControls),
|
||||
static_cast<unsigned long long>(verticalShaftRoutes),
|
||||
static_cast<unsigned long long>(blockedControls),static_cast<unsigned long long>(passageCount),
|
||||
auditPassed?"PASS":"FAIL");
|
||||
if(!auditPassed)
|
||||
|
||||
@@ -1517,13 +1517,16 @@ namespace StandaloneWorldAssemblyPrototype
|
||||
{
|
||||
using namespace VoxelForgeCore;
|
||||
if(!owner.Manager)
|
||||
{error="Tunnel Network cave planner requires the initialized owner director";return false;}
|
||||
std::vector<const FStrateSlot*> tunnelSlots;
|
||||
{error="native cave planner requires the initialized owner director";return false;}
|
||||
std::vector<std::pair<const FStrateSlot*,bool>> plannerSlots;
|
||||
for(const FStrateSlot& slot:owner.Manager->GetLayout())
|
||||
{
|
||||
if(!slot.Definition
|
||||
||owner.Manager->GetGeneratorTypeForChunk(FIntVector(0,0,slot.TopChunkZ))
|
||||
!=ECaveGeneratorType::TunnelNetwork)continue;
|
||||
if(!slot.Definition)continue;
|
||||
const ECaveGeneratorType generatorType=
|
||||
owner.Manager->GetGeneratorTypeForChunk(FIntVector(0,0,slot.TopChunkZ));
|
||||
const bool tunnelNetwork=generatorType==ECaveGeneratorType::TunnelNetwork;
|
||||
const bool verticalShafts=generatorType==ECaveGeneratorType::VerticalShafts;
|
||||
if(!tunnelNetwork&&!verticalShafts)continue;
|
||||
const bool hasIncomingMouth=std::any_of(layout.passages.begin(),
|
||||
layout.passages.end(),[&](const auto& passage)
|
||||
{return passage.lowerStrateIndex==slot.StrateIndex
|
||||
@@ -1532,24 +1535,27 @@ namespace StandaloneWorldAssemblyPrototype
|
||||
layout.passages.end(),[&](const auto& passage)
|
||||
{return passage.upperStrateIndex==slot.StrateIndex
|
||||
&&passage.lowerStrateIndex>slot.StrateIndex;});
|
||||
// A native planner route requires two mouths. Boundary Tunnel Network
|
||||
// strates keep their legacy field until they have both connections.
|
||||
if(!hasIncomingMouth||!hasOutgoingMouth)continue;
|
||||
// Tunnel Network connects two passages. The basal Vertical Shafts
|
||||
// stratum is terminal: it inherits its arrival from the preceding
|
||||
// strate and intentionally has no departure passage.
|
||||
if((tunnelNetwork&&(!hasIncomingMouth||!hasOutgoingMouth))
|
||||
||(verticalShafts&&(!hasIncomingMouth||hasOutgoingMouth)))continue;
|
||||
auto stratum=std::find_if(layout.strates.begin(),layout.strates.end(),
|
||||
[&](const auto& item){return item.strateIndex==slot.StrateIndex;});
|
||||
if(stratum==layout.strates.end())
|
||||
{error="Tunnel Network strate is missing from the resolved layout";return false;}
|
||||
stratum->generatorKind="TunnelNetwork";
|
||||
stratum->generatorKind=verticalShafts?"VerticalShafts":"TunnelNetwork";
|
||||
stratum->recipeId="Core.Caves.PrimitiveField";
|
||||
stratum->recipeVersion=1;
|
||||
stratum->stableId=layout.worldIdentity+"/strate/"
|
||||
+std::to_string(slot.StrateIndex)+"/generator/TunnelNetwork";
|
||||
+std::to_string(slot.StrateIndex)+"/generator/"
|
||||
+(verticalShafts?"VerticalShafts":"TunnelNetwork");
|
||||
const bool alreadyPlanned=std::any_of(layout.cavernRooms.begin(),
|
||||
layout.cavernRooms.end(),[&](const auto& room)
|
||||
{return room.strateIndex==slot.StrateIndex;})
|
||||
&&std::any_of(layout.cavernEdges.begin(),layout.cavernEdges.end(),
|
||||
[&](const auto& edge){return edge.strateIndex==slot.StrateIndex;});
|
||||
if(!alreadyPlanned)tunnelSlots.push_back(&slot);
|
||||
if(!alreadyPlanned)plannerSlots.emplace_back(&slot,verticalShafts);
|
||||
}
|
||||
if(!layout.finalize(error))return false;
|
||||
const auto toMicrometres=[&](double ownerVoxels)
|
||||
@@ -1562,14 +1568,55 @@ namespace StandaloneWorldAssemblyPrototype
|
||||
return static_cast<std::int32_t>(std::llround(std::clamp(
|
||||
static_cast<double>(value),0.0,1.0)*65536.0));
|
||||
};
|
||||
if(!tunnelSlots.empty())
|
||||
if(!plannerSlots.empty())
|
||||
{
|
||||
std::vector<ResolvedCavernRoomV1> plannedRooms=layout.cavernRooms;
|
||||
std::vector<ResolvedCavernEdgeV1> plannedEdges=layout.cavernEdges;
|
||||
for(const FStrateSlot* slot:tunnelSlots)
|
||||
for(const auto& [slot,verticalShafts]:plannerSlots)
|
||||
{
|
||||
const FStrateGenerationParams& params=slot->Definition->GenerationParams;
|
||||
ResolvedCavernPlannerSettingsV1 settings;
|
||||
if(verticalShafts)
|
||||
{
|
||||
const FVerticalShaftParams& shaft=slot->Definition->VerticalShaftParams;
|
||||
settings.verticalShaftMode=true;
|
||||
settings.roomSpacingMicrometres=std::clamp<std::int64_t>(
|
||||
toMicrometres(shaft.ShaftSpacing),4000000,100000000);
|
||||
settings.minimumRoomRadiusMicrometres=std::max<std::int64_t>(
|
||||
500000,toMicrometres(shaft.ShaftMinRadius));
|
||||
settings.maximumRoomRadiusMicrometres=std::max(
|
||||
settings.minimumRoomRadiusMicrometres,
|
||||
toMicrometres(shaft.ShaftMaxRadius));
|
||||
settings.destinationRadiusMicrometres=std::max(
|
||||
settings.maximumRoomRadiusMicrometres,
|
||||
settings.maximumRoomRadiusMicrometres*135/100);
|
||||
settings.minimumTunnelRadiusMicrometres=std::max<std::int64_t>(0,
|
||||
toMicrometres(shaft.ConnectorRadius));
|
||||
settings.maximumTunnelRadiusMicrometres=
|
||||
settings.minimumTunnelRadiusMicrometres;
|
||||
settings.maximumTunnelLengthMicrometres=std::clamp<std::int64_t>(
|
||||
settings.roomSpacingMicrometres*2,4000000,100000000);
|
||||
settings.smoothWidthMicrometres=1500000;
|
||||
settings.floorSupportDepthMicrometres=2000000;
|
||||
settings.irregularityAmplitudeMicrometres=std::max<std::int64_t>(0,
|
||||
toMicrometres(shaft.SurfaceRoughness));
|
||||
settings.irregularityWavelengthMicrometres=std::max<std::int64_t>(
|
||||
500000,static_cast<std::int64_t>(owner.OwnerVoxelSizeMicrons)*4);
|
||||
settings.roomDensityQ16=toQ16(shaft.ShaftDensity);
|
||||
settings.tunnelDensityQ16=toQ16(shaft.CrossConnectChance);
|
||||
settings.roomShapeVarietyQ16=0;
|
||||
settings.roomHeightRatioQ16=65536;
|
||||
settings.roomFloorCutMinimumQ16=0;
|
||||
settings.roomFloorCutMaximumQ16=0;
|
||||
settings.tunnelHorizontalBiasQ16=65536;
|
||||
settings.originRoomMaximumConnections=32;
|
||||
settings.ledgeSpacingMicrometres=std::max<std::int64_t>(0,
|
||||
toMicrometres(shaft.LedgeSpacing));
|
||||
settings.ledgeDepthMicrometres=std::max<std::int64_t>(0,
|
||||
toMicrometres(shaft.LedgeDepth));
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.roomSpacingMicrometres=std::max<std::int64_t>(4000000,
|
||||
toMicrometres(params.RoomSpacing));
|
||||
settings.minimumRoomRadiusMicrometres=std::max<std::int64_t>(500000,
|
||||
@@ -1607,6 +1654,7 @@ namespace StandaloneWorldAssemblyPrototype
|
||||
settings.tunnelHorizontalBiasQ16=toQ16(params.TunnelHorizontalBias);
|
||||
settings.originRoomMaximumConnections=params.OriginRoomMaxConnections;
|
||||
settings.tunnelsFlowTowardOrigin=params.bTunnelsFlowTowardOrigin;
|
||||
}
|
||||
std::vector<ResolvedCavernRoomV1> rooms;
|
||||
std::vector<ResolvedCavernEdgeV1> edges;
|
||||
if(!PlanResolvedCavernNetworkV1(layout,owner.Seed,slot->StrateIndex,
|
||||
@@ -1629,24 +1677,27 @@ namespace StandaloneWorldAssemblyPrototype
|
||||
constexpr std::int64_t PlayerCenterAboveFloorMicrometres=1130000;
|
||||
for(const FStrateSlot& slot:owner.Manager->GetLayout())
|
||||
{
|
||||
if(!slot.Definition
|
||||
||owner.Manager->GetGeneratorTypeForChunk(FIntVector(0,0,slot.TopChunkZ))
|
||||
!=ECaveGeneratorType::TunnelNetwork)continue;
|
||||
if(!slot.Definition)continue;
|
||||
const ECaveGeneratorType generatorType=
|
||||
owner.Manager->GetGeneratorTypeForChunk(FIntVector(0,0,slot.TopChunkZ));
|
||||
const bool verticalShafts=generatorType==ECaveGeneratorType::VerticalShafts;
|
||||
if(generatorType!=ECaveGeneratorType::TunnelNetwork&&!verticalShafts)continue;
|
||||
auto stratum=std::find_if(layout.strates.begin(),layout.strates.end(),
|
||||
[&](const auto& item){return item.strateIndex==slot.StrateIndex;});
|
||||
if(stratum==layout.strates.end()
|
||||
||!IsNativeCaveFieldStratum(*stratum))continue;
|
||||
const std::string routePrefix="tunnel-network/strate-"
|
||||
const std::string routePrefix=(verticalShafts?"vertical-shafts/strate-"
|
||||
:"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
|
||||
const bool hasPlannedDeparture=!verticalShafts
|
||||
&&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;
|
||||
if(!hasPlannedArrival||(!verticalShafts&&!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
|
||||
@@ -1663,13 +1714,14 @@ namespace StandaloneWorldAssemblyPrototype
|
||||
if(passage.upperStrateIndex==slot.StrateIndex
|
||||
&&passage.lowerStrateIndex>slot.StrateIndex)departure=&passage;
|
||||
}
|
||||
if(!arrival||!departure)
|
||||
{error="Tunnel Network route anchors cannot bind both passage mouths";return false;}
|
||||
if(!arrival||(!verticalShafts&&!departure))
|
||||
{error="native cave route anchors cannot bind their required passage mouths";return false;}
|
||||
const auto appendRoutePoint=[&](std::string id,
|
||||
const std::array<std::int64_t,3>& point)
|
||||
{
|
||||
ResolvedLayoutAnchorV2 anchor;anchor.kind="route_point";
|
||||
anchor.stableId="tunnel-network/route/"+std::move(id);
|
||||
anchor.stableId=(verticalShafts?"vertical-shafts/route/"
|
||||
:"tunnel-network/route/")+std::move(id);
|
||||
anchor.units="1/256 Core voxel";
|
||||
anchor.values={point[0],point[1],point[2]};
|
||||
stratum->anchors.push_back(std::move(anchor));
|
||||
@@ -1684,14 +1736,23 @@ namespace StandaloneWorldAssemblyPrototype
|
||||
appendRoutePoint("000-arrival",start);
|
||||
for(std::size_t edgeIndex=0;edgeIndex<256;++edgeIndex)
|
||||
{
|
||||
const std::string stableId="tunnel-network/strate-"
|
||||
+std::to_string(slot.StrateIndex)+"/route-edge-"
|
||||
const std::string stableId=routePrefix+"route-edge-"
|
||||
+std::to_string(edgeIndex);
|
||||
const auto edge=std::find_if(layout.cavernEdges.begin(),
|
||||
layout.cavernEdges.end(),[&](const auto& value)
|
||||
{return value.strateIndex==slot.StrateIndex
|
||||
&&value.stableId==stableId;});
|
||||
if(edge==layout.cavernEdges.end())break;
|
||||
bool terminalRouteEdge=false;
|
||||
if(verticalShafts)
|
||||
{
|
||||
const std::string nextRouteEdge=routePrefix+"route-edge-"
|
||||
+std::to_string(edgeIndex+1);
|
||||
terminalRouteEdge=std::none_of(layout.cavernEdges.begin(),
|
||||
layout.cavernEdges.end(),[&](const auto& candidate)
|
||||
{return candidate.strateIndex==slot.StrateIndex
|
||||
&&candidate.stableId==nextRouteEdge;});
|
||||
}
|
||||
if(edgeIndex==0)
|
||||
{
|
||||
auto inner=edge->controlPointsMicrometres.front();
|
||||
@@ -1708,18 +1769,20 @@ namespace StandaloneWorldAssemblyPrototype
|
||||
}
|
||||
auto point=edge->controlPointsMicrometres.back();
|
||||
point[2]+=PlayerCenterAboveFloorMicrometres;
|
||||
appendRoutePoint(std::to_string(edgeIndex+1),
|
||||
appendRoutePoint(terminalRouteEdge?"999-basal-terminal"
|
||||
:std::to_string(edgeIndex+1),
|
||||
{toCoreSubvoxels(point[0]),toCoreSubvoxels(point[1]),
|
||||
toCoreSubvoxels(point[2])});
|
||||
}
|
||||
const std::string departureEdgeId="tunnel-network/strate-"
|
||||
+std::to_string(slot.StrateIndex)+"/departure-edge";
|
||||
const auto departureEdge=std::find_if(layout.cavernEdges.begin(),
|
||||
layout.cavernEdges.end(),[&](const auto& value)
|
||||
{return value.strateIndex==slot.StrateIndex
|
||||
&&value.stableId==departureEdgeId;});
|
||||
if(departureEdge!=layout.cavernEdges.end())
|
||||
if(departure)
|
||||
{
|
||||
const std::string departureEdgeId=routePrefix+"departure-edge";
|
||||
const auto departureEdge=std::find_if(layout.cavernEdges.begin(),
|
||||
layout.cavernEdges.end(),[&](const auto& value)
|
||||
{return value.strateIndex==slot.StrateIndex
|
||||
&&value.stableId==departureEdgeId;});
|
||||
if(departureEdge==layout.cavernEdges.end())
|
||||
{error="native cave route lost its planned departure edge";return false;}
|
||||
auto inner=departureEdge->controlPointsMicrometres.front();
|
||||
inner[2]+=PlayerCenterAboveFloorMicrometres;
|
||||
const std::array<std::int64_t,3> innerPoint={
|
||||
@@ -1728,9 +1791,17 @@ namespace StandaloneWorldAssemblyPrototype
|
||||
auto end=departure->upperMouthSubvoxels;
|
||||
if(!sameRoutePoint(innerPoint,end))
|
||||
appendRoutePoint("998-departure-inner",innerPoint);
|
||||
appendRoutePoint("999-departure",departure->upperMouthSubvoxels);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto terminal=std::find_if(layout.cavernRooms.begin(),
|
||||
layout.cavernRooms.end(),[&](const auto& room)
|
||||
{return room.strateIndex==slot.StrateIndex
|
||||
&&room.stableId==routePrefix+"basal-landing/primitive-0";});
|
||||
if(terminal==layout.cavernRooms.end())
|
||||
{error="Vertical Shafts basal route is missing its terminal landing";return false;}
|
||||
}
|
||||
auto end=departure->upperMouthSubvoxels;
|
||||
appendRoutePoint("999-departure",end);
|
||||
}
|
||||
return layout.finalize(error);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user