wip: opt-in landing-pad contract + Core.Liminal.Field v2 pads (L145)

Layers may publish certified arrival/departure pads; the passage planner binds endpoints and tangents to them;
no-pad layouts serialize unchanged (owner canonical hashes match v227). Pads removed the endpoint grade failures;
seeds 0-4 passed at a 45 m margin, but seed 5 still has 289 blocked passage-capsule samples ~29 m before the
departure pad, where the composed field stays solid (-0.162) inside the tube over native ground (-3.6). Ripple
audit now keeps true route distance across masked gaps (with a synthetic control).

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 12:19:30 +01:00
1 parent a45ba9bb10
commit 7d654ff861
14 files changed
+1228 -66

No files matched your search

@@ -599,6 +599,7 @@ namespace VoxelForgeCore
inline constexpr std::string_view CoreLiminalFieldRecipeIdV1 = "Core.Liminal.Field";
inline constexpr std::uint32_t CoreLiminalFieldRecipeVersionV1 = 1;
inline constexpr std::uint32_t CoreLiminalFieldRecipeVersionV2 = 2;
inline constexpr std::uint32_t CoreLiminalFieldVariantCountV1 = 4;
enum class WorldAssemblyLiminalVariantV1 : std::uint32_t
@@ -1145,6 +1146,27 @@ namespace VoxelForgeCore
bool surfaceToTunnelLandingSupport = false;
};
enum class ResolvedLayoutLandingPadRoleV1 : std::uint32_t
{
arrival = 0,
departure = 1
};
struct ResolvedLayoutLandingPadV1
{
std::string stableId;
ResolvedLayoutLandingPadRoleV1 role = ResolvedLayoutLandingPadRoleV1::arrival;
// Capsule-center position. floorHeightSubvoxels is the supported floor below it.
std::array<std::int64_t, 3> positionSubvoxels{};
std::int64_t floorHeightSubvoxels = 0;
// Unit horizontal travel direction, signed Q16, oriented into the layer route.
std::array<std::int32_t, 2> approachDirectionQ16{};
// Certified horizontal free radius around the capsule center and support below the floor.
std::int64_t clearanceSubvoxels = 0;
std::int64_t supportDepthSubvoxels = 0;
bool certifiedWalkableWithSupport = false;
};
struct ResolvedLayoutStratumV2
{
std::string stableId;
@@ -1174,6 +1196,7 @@ namespace VoxelForgeCore
std::int64_t managerChunkWidthMicrometres = 0;
std::int64_t dispatchChunkWidthMicrometres = 0;
std::vector<ResolvedLayoutAnchorV2> anchors;
std::vector<ResolvedLayoutLandingPadV1> landingPads;
ResolvedLayoutStratePassageCapabilitiesV1 passageCapabilities;
ResolvedLayoutInterfaceCapabilitiesV1 lowerInterfaceCapabilities;
};
@@ -1316,6 +1339,12 @@ namespace VoxelForgeCore
VFCORE_API bool PlanCoreLiminalFieldV1(
WorldAssemblyRecipeV1& recipe, WorldAssemblyStratumPlanV1& stratum,
const ResolvedLayoutSnapshotV3& layout, std::string& error);
VFCORE_API bool PrepareCoreLiminalLandingPadsV2(
WorldAssemblyRecipeV1& recipe, WorldAssemblyStratumPlanV1& stratum,
ResolvedLayoutSnapshotV3& layout, std::string& error);
VFCORE_API bool PlanCoreLiminalFieldV2(
WorldAssemblyRecipeV1& recipe, WorldAssemblyStratumPlanV1& stratum,
const ResolvedLayoutSnapshotV3& layout, std::string& error);
struct ResolvedLayoutStampPlacementAuditV1
{
+121 -7
View File
@@ -613,7 +613,28 @@ namespace
for(std::size_t v=0;v<anchor.values.size();++v){if(v)out<<',';out<<anchor.values[v];}
out<<"]}";
}
out<<"]}";
out<<']';
if(!x.landingPads.empty())
{
out<<",\"landing_pads\":[";
for(std::size_t p=0;p<x.landingPads.size();++p)
{
if(p)out<<',';const auto& pad=x.landingPads[p];
out<<"{\"stable_id\":"<<LayoutEscape(pad.stableId)
<<",\"role\":"<<static_cast<std::uint32_t>(pad.role)
<<",\"position_q\":["<<pad.positionSubvoxels[0]<<','
<<pad.positionSubvoxels[1]<<','<<pad.positionSubvoxels[2]
<<"],\"floor_q\":"<<pad.floorHeightSubvoxels
<<",\"approach_q16\":["<<pad.approachDirectionQ16[0]<<','
<<pad.approachDirectionQ16[1]<<']'
<<",\"clearance_q\":"<<pad.clearanceSubvoxels
<<",\"support_depth_q\":"<<pad.supportDepthSubvoxels
<<",\"certified\":"
<<(pad.certifiedWalkableWithSupport?"true":"false")<<'}';
}
out<<']';
}
out<<'}';
}
out<<"],\"passages\":[";
for(std::size_t i=0;i<s.passages.size();++i)
@@ -957,6 +978,9 @@ bool ResolvedLayoutSnapshotV3::finalize(std::string& error)
for(std::size_t i=0;i<strates.size();++i)
{
auto& x=strates[i];x.order=static_cast<std::int32_t>(i);
std::stable_sort(x.landingPads.begin(),x.landingPads.end(),[](const auto& a,const auto& b)
{return a.role!=b.role?static_cast<std::uint32_t>(a.role)
<static_cast<std::uint32_t>(b.role):a.stableId<b.stableId;});
if(x.stableId.empty())x.stableId=worldIdentity+"/strate/"+std::to_string(x.strateIndex);
if(x.content.kind.empty())x.content.kind="content";
if(x.ceiling.kind.empty())x.ceiling.kind="ceiling";
@@ -1017,9 +1041,40 @@ bool ResolvedLayoutSnapshotV3::validate(ResolvedLayoutValidationModeV3 mode,
const auto add=[&](std::string code,std::string detail)
{issues.push_back({std::move(code),std::move(detail)});};
const bool strict=mode==ResolvedLayoutValidationModeV3::strict;
const std::int64_t playerCenterAboveFloorQ=static_cast<std::int64_t>(std::llround(
1.13*WorldAssemblySubvoxelsPerVoxel*1000000.0/coreVoxelSizeMicrometres));
for(std::size_t i=0;i<strates.size();++i)
{
const auto& s=strates[i];
std::vector<std::string> landingPadIds;
for(const auto& pad:s.landingPads)
{
if(pad.stableId.empty()
||std::find(landingPadIds.begin(),landingPadIds.end(),pad.stableId)
!=landingPadIds.end())
add("landing_pad_identity",s.stableId+" has an empty or duplicate landing-pad ID");
else landingPadIds.push_back(pad.stableId);
const auto role=static_cast<std::uint32_t>(pad.role);
const std::int64_t directionX=pad.approachDirectionQ16[0];
const std::int64_t directionY=pad.approachDirectionQ16[1];
const std::int64_t directionLengthSquared=directionX*directionX+directionY*directionY;
constexpr std::int64_t UnitQ16Squared=1ll<<32;
const bool unitDirection=directionLengthSquared>=UnitQ16Squared*98/100
&&directionLengthSquared<=UnitQ16Squared*102/100;
const std::int64_t floorMicrometres=pad.floorHeightSubvoxels
*static_cast<std::int64_t>(coreVoxelSizeMicrometres)
/WorldAssemblySubvoxelsPerVoxel;
if(role>static_cast<std::uint32_t>(ResolvedLayoutLandingPadRoleV1::departure)
||pad.positionSubvoxels[2]
!=pad.floorHeightSubvoxels+playerCenterAboveFloorQ
||!s.content.presentInCurrentField
||floorMicrometres<s.content.bottomMicrometres
||floorMicrometres>=s.content.topMicrometres
||!unitDirection||pad.clearanceSubvoxels<=0
||pad.supportDepthSubvoxels<=0
||!pad.certifiedWalkableWithSupport)
add("landing_pad_contract",s.stableId+" publishes an uncertified or malformed landing pad");
}
const std::int64_t effectiveTransitionWidth=LayoutTransitionLimit(s);
if(s.interiorTopMicrometres<=s.interiorBottomMicrometres)
add("invalid_interior",s.stableId+" has non-positive content height");
@@ -1643,6 +1698,22 @@ std::optional<ResolvedLayoutSnapshotV3> ResolvedLayoutSnapshotV3::FromJson(
for(const auto& a:v.Get("anchors").AsArray())
{ResolvedLayoutAnchorV2 p;p.kind=LayoutString(a,"kind");p.stableId=LayoutString(a,"stable_id");p.units=LayoutString(a,"units");
for(const auto& value:a.Get("values").AsArray())p.values.push_back(value.Integer());x.anchors.push_back(std::move(p));}
for(const auto& value:v.Get("landing_pads").AsArray())
{
ResolvedLayoutLandingPadV1 pad;pad.stableId=LayoutString(value,"stable_id");
pad.role=static_cast<ResolvedLayoutLandingPadRoleV1>(LayoutInt(value,"role"));
const auto& position=value.Get("position_q").AsArray();
for(std::size_t axis=0;axis<3&&axis<position.size();++axis)
pad.positionSubvoxels[axis]=position[axis].Integer();
pad.floorHeightSubvoxels=LayoutInt(value,"floor_q");
const auto& approach=value.Get("approach_q16").AsArray();
for(std::size_t axis=0;axis<2&&axis<approach.size();++axis)
pad.approachDirectionQ16[axis]=static_cast<std::int32_t>(approach[axis].Integer());
pad.clearanceSubvoxels=LayoutInt(value,"clearance_q");
pad.supportDepthSubvoxels=LayoutInt(value,"support_depth_q");
pad.certifiedWalkableWithSupport=LayoutBool(value,"certified");
x.landingPads.push_back(std::move(pad));
}
s.strates.push_back(std::move(x));
}
for(const auto& v:root.Get("passages").AsArray())
@@ -2566,6 +2637,17 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
{return c.upperStrateIndex==strate;});
return it==configs.end()?nullptr:&*it;
};
const auto landingPadFor=[](const ResolvedLayoutStratumV2& stratum,
ResolvedLayoutLandingPadRoleV1 role,std::uint32_t ordinal)
->const ResolvedLayoutLandingPadV1*
{
std::vector<const ResolvedLayoutLandingPadV1*> candidates;
for(const auto& pad:stratum.landingPads)
if(pad.role==role)candidates.push_back(&pad);
std::sort(candidates.begin(),candidates.end(),[](const auto* a,const auto* b)
{return a->stableId<b->stableId;});
return ordinal<candidates.size()?candidates[ordinal]:nullptr;
};
const auto routeAnchor=[](const ResolvedLayoutStratumV2& s,bool departure,
std::array<std::int64_t,3>& out)
{
@@ -2662,9 +2744,37 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
passage.upperStrateIndex=upper.strateIndex;passage.lowerStrateIndex=lower.strateIndex;
passage.placementRadiusSubvoxels=placementRadius;
passage.mouthRadiusSubvoxels=mouthRadius;passage.midRadiusSubvoxels=midRadius;
const auto* upperDeparturePad=landingPadFor(upper,
ResolvedLayoutLandingPadRoleV1::departure,connection);
const auto* lowerArrivalPad=landingPadFor(lower,
ResolvedLayoutLandingPadRoleV1::arrival,connection);
const auto validateLandingPad=[&](const ResolvedLayoutLandingPadV1* pad,
std::string_view side)
{
if(!pad)return true;
const std::int64_t requiredClearance=mouthRadius
+static_cast<std::int64_t>(std::llround(0.34*qPerMetre));
if(!pad->certifiedWalkableWithSupport||pad->clearanceSubvoxels<requiredClearance
||pad->supportDepthSubvoxels<static_cast<std::int64_t>(std::llround(0.50*qPerMetre))
||!radialWithin(pad->positionSubvoxels,placementRadius)
||pad->positionSubvoxels[2]
!=pad->floorHeightSubvoxels+playerCenterAboveFloorQ)
{
error=passage.stableId+" "+std::string(side)
+" landing pad is uncertified, unsupported, too tight, or outside PassageConfig.DistanceMax";
return false;
}
return true;
};
if(!validateLandingPad(upperDeparturePad,"departure")
||!validateLandingPad(lowerArrivalPad,"arrival"))return false;
std::array<std::int64_t,3> upperMouth{},lowerMouth{};
const bool hasUpperRoute=connection==0&&routeAnchor(upper,true,upperMouth);
const bool hasLowerRoute=connection==0&&routeAnchor(lower,false,lowerMouth);
const bool hasUpperRoute=upperDeparturePad
?(upperMouth=upperDeparturePad->positionSubvoxels,true)
:connection==0&&routeAnchor(upper,true,upperMouth);
const bool hasLowerRoute=lowerArrivalPad
?(lowerMouth=lowerArrivalPad->positionSubvoxels,true)
:connection==0&&routeAnchor(lower,false,lowerMouth);
const bool surfaceGroundDeparture=hasUpperRoute&&upperIsSurfaceWorld;
const ResolvedLayoutAnchorV2* passageAnchor=nullptr;
if(connection==0)
@@ -2713,13 +2823,17 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
constexpr std::int64_t LandingExtensionQ=8;
std::array<std::int64_t,2> upperTangent{},lowerTangent{};
const bool hasUpperTangent=hasUpperRoute
&&routeTangent(upper,true,upperTangent);
const bool hasUpperTangent=upperDeparturePad
?(upperTangent={upperDeparturePad->approachDirectionQ16[0],
upperDeparturePad->approachDirectionQ16[1]},true)
:hasUpperRoute&&routeTangent(upper,true,upperTangent);
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 bool hasLowerTangent=lowerArrivalPad
?(lowerTangent={lowerArrivalPad->approachDirectionQ16[0],
lowerArrivalPad->approachDirectionQ16[1]},true)
:hasLowerRoute&&!hasPassageArrival&&routeTangent(lower,false,lowerTangent);
const bool profiledSurfaceJoin=hasLowerTangent
&&std::any_of(lower.anchors.begin(),lower.anchors.end(),
[](const auto& anchor){return anchor.kind=="heightfield_profile"
+398 -1
View File
@@ -542,7 +542,8 @@ namespace world_assembly_detail
const auto& liminal = stratum.liminalField;
if (liminal.version != 0)
{
if (liminal.version != CoreLiminalFieldRecipeVersionV1
if ((liminal.version != CoreLiminalFieldRecipeVersionV1
&& liminal.version != CoreLiminalFieldRecipeVersionV2)
|| static_cast<std::uint32_t>(liminal.variant) >= CoreLiminalFieldVariantCountV1
|| liminal.seed != effectiveRecipe.seed
|| liminal.variant != SelectCoreLiminalFieldVariantV1(liminal.seed)
@@ -2719,6 +2720,402 @@ bool PlanCoreLiminalFieldV1(WorldAssemblyRecipeV1& recipe,
return true;
}
std::array<std::array<std::int64_t,2>,6> CoreLiminalRouteXYV2(
std::int64_t startX,std::int64_t startY,std::int64_t finishX,
std::int64_t finishY,std::int64_t qPerMetre)
{
return {{{{startX,startY}},{{-40*qPerMetre,40*qPerMetre}},
{{-40*qPerMetre,-40*qPerMetre}},{{40*qPerMetre,-40*qPerMetre}},
{{40*qPerMetre,40*qPerMetre}},{{finishX,finishY}}}};
}
std::vector<WorldAssemblyRoutePointV1> BuildCoreLiminalRouteV2(
const WorldAssemblySurfaceProfileV1& profile,
const ResolvedLayoutLandingPadV1& arrivalPad,
const ResolvedLayoutLandingPadV1& departurePad,
const WorldAssemblyLiminalVariantDefinitionV1& definition,
std::uint32_t seed,std::int32_t strateIndex,std::int64_t coreMicrons,
std::int64_t qPerMetre,
std::uint64_t& totalHorizontal,std::string& error)
{
error.clear();totalHorizontal=0;
const auto groundHeightAt=[&](std::int64_t x,std::int64_t y)
{
if(profile.kind==WorldAssemblySurfaceProfileKindV1::flatField)
return profile.h0Subvoxels;
const std::int64_t turnX=world_assembly_detail::SurfaceProfileTurnAtCoordinate(
x,profile.wavelengthXSubvoxels,profile.phaseXTurnsQ32);
const std::int64_t turnY=world_assembly_detail::SurfaceProfileTurnAtCoordinate(
y,profile.wavelengthYSubvoxels,profile.phaseYTurnsQ32);
return profile.h0Subvoxels
+world_assembly_detail::MulQ30(profile.amplitudeXSubvoxels,
world_assembly_detail::CosineQ30(turnX))
+world_assembly_detail::MulQ30(profile.amplitudeYSubvoxels,
world_assembly_detail::CosineQ30(turnY));
};
const auto horizontalLengthQ=[](std::int64_t dx,std::int64_t dy)
{return world_assembly_detail::IntegerSqrt(static_cast<std::uint64_t>(dx*dx+dy*dy));};
const auto micrometresToQ=[&](std::int64_t micrometres)
{return (micrometres*WorldAssemblySubvoxelsPerVoxel+coreMicrons/2)/coreMicrons;};
const auto routeXY=CoreLiminalRouteXYV2(arrivalPad.positionSubvoxels[0],
arrivalPad.positionSubvoxels[1],departurePad.positionSubvoxels[0],
departurePad.positionSubvoxels[1],qPerMetre);
std::vector<WorldAssemblyRoutePointV1> route;
const std::int64_t pointSpacing=12*qPerMetre;
const std::int64_t routeRadius=std::max<std::int64_t>(
micrometresToQ(definition.routeHalfWidthMicrometres),micrometresToQ(500000));
const auto routeId=[&](std::size_t ordinal)
{
std::uint64_t id=14695981039346656037ull;
const auto add=[&](std::uint64_t value,std::uint32_t bytes)
{for(std::uint32_t byte=0;byte<bytes;++byte)
{id^=static_cast<std::uint8_t>(value>>(byte*8));id*=1099511628211ull;}};
add(seed,4);add(static_cast<std::uint32_t>(strateIndex),4);add(ordinal,4);
return id?id:1;
};
const auto appendRoutePoint=[&](std::int64_t x,std::int64_t y)
{
WorldAssemblyRoutePointV1 point;
point.positionSubvoxels={x,y,groundHeightAt(x,y)};
point.radiusSubvoxels=routeRadius;
point.stableFeatureId=routeId(route.size());
route.push_back(point);
};
const auto interpolate=[](std::int64_t start,std::int64_t delta,
std::uint64_t step,std::uint64_t steps)
{
const std::int64_t numerator=delta*static_cast<std::int64_t>(step);
const std::int64_t divisor=static_cast<std::int64_t>(steps);
return start+(numerator>=0?(numerator+divisor/2)/divisor
:(numerator-divisor/2)/divisor);
};
appendRoutePoint(routeXY.front()[0],routeXY.front()[1]);
for(std::size_t segment=1;segment<routeXY.size();++segment)
{
const std::int64_t dx=routeXY[segment][0]-routeXY[segment-1][0];
const std::int64_t dy=routeXY[segment][1]-routeXY[segment-1][1];
const std::uint64_t length=horizontalLengthQ(dx,dy);
if(length==0){error="Core.Liminal.Field v2 route contains a zero-horizontal segment";return {};}
totalHorizontal+=length;
const std::uint64_t steps=std::max<std::uint64_t>(1,
(length+static_cast<std::uint64_t>(pointSpacing)-1)
/static_cast<std::uint64_t>(pointSpacing));
for(std::uint64_t step=1;step<=steps;++step)
appendRoutePoint(interpolate(routeXY[segment-1][0],dx,step,steps),
interpolate(routeXY[segment-1][1],dy,step,steps));
}
if(route.size()<2||totalHorizontal<300*static_cast<std::uint64_t>(qPerMetre)
||route.front().positionSubvoxels[2]!=arrivalPad.floorHeightSubvoxels
||route.back().positionSubvoxels[2]!=departurePad.floorHeightSubvoxels)
{error="Core.Liminal.Field v2 pad-to-pad route is incomplete or too short";return {};}
return route;
}
bool PrepareCoreLiminalLandingPadsV2(WorldAssemblyRecipeV1& recipe,
WorldAssemblyStratumPlanV1& stratum,ResolvedLayoutSnapshotV3& layout,
std::string& error)
{
error.clear();
if(layout.coreVoxelSizeMicrometres==0||stratum.strateIndex<0
||stratum.topChunkZ<stratum.bottomChunkZ)
{error="Core.Liminal.Field v2 needs a finite stratum and resolved Core voxel size";return false;}
auto resolved=std::find_if(layout.strates.begin(),layout.strates.end(),
[&](const auto& value){return value.strateIndex==stratum.strateIndex
&&value.generatorKind=="SurfaceWorld";});
if(resolved==layout.strates.end()||!resolved->content.presentInCurrentField)
{error="Core.Liminal.Field v2 must target a resolved SurfaceWorld content band";return false;}
constexpr std::int64_t Q=WorldAssemblySubvoxelsPerVoxel;
const std::int64_t coreMicrons=layout.coreVoxelSizeMicrometres;
const auto micrometresToQ=[&](std::int64_t micrometres)
{
const std::int64_t numerator=micrometres*Q;
return numerator>=0?(numerator+coreMicrons/2)/coreMicrons
:(numerator-coreMicrons/2)/coreMicrons;
};
const std::int64_t qPerMetre=micrometresToQ(1000000);
if(qPerMetre<=0){error="Core.Liminal.Field v2 could not resolve fixed-scale metres";return false;}
const std::uint32_t seed=recipe.seed;
const WorldAssemblyLiminalVariantV1 variant=SelectCoreLiminalFieldVariantV1(seed);
const auto& definition=CoreLiminalFieldVariantsV1[static_cast<std::size_t>(variant)];
const std::int64_t bottom=static_cast<std::int64_t>(stratum.bottomChunkZ)
*recipe.layoutChunkWidthSubvoxels;
const std::int64_t top=(static_cast<std::int64_t>(stratum.topChunkZ)+1)
*recipe.layoutChunkWidthSubvoxels;
const std::int64_t contentBottom=micrometresToQ(resolved->content.bottomMicrometres);
const std::int64_t profileRelief=variant==WorldAssemblyLiminalVariantV1::repeatingHills
?2*micrometresToQ(definition.hillAmplitudeMicrometres):0;
const std::int64_t deckSweepRadius=static_cast<std::int64_t>(std::ceil(std::hypot(
static_cast<double>(definition.routeHalfWidthMicrometres+250000),
static_cast<double>(definition.routeHalfThicknessMicrometres+250000))));
const std::int64_t floorClearance=definition.routeHalfThicknessMicrometres
+deckSweepRadius+250000;
// Keep the field above the lower tunnel's mouth transition so the routed
// departure has a clean open section before it reaches the cave wall.
constexpr std::int64_t MinimumFieldGroundMarginMicrometres=20000000;
const std::int64_t fieldGroundMargin=std::max(floorClearance,
MinimumFieldGroundMarginMicrometres);
const std::int64_t floorHeight=contentBottom+profileRelief
+micrometresToQ(fieldGroundMargin);
if(floorHeight<=bottom||top<=floorHeight+8*qPerMetre)
{error="Core.Liminal.Field v2 has no room for its supported field and cap";return false;}
WorldAssemblySurfaceProfileV1 profile;
profile.version=1;
profile.kind=definition.surfaceKind;
profile.h0Subvoxels=floorHeight;
if(profile.kind==WorldAssemblySurfaceProfileKindV1::periodicHills)
{
profile.amplitudeXSubvoxels=micrometresToQ(definition.hillAmplitudeMicrometres);
profile.amplitudeYSubvoxels=profile.amplitudeXSubvoxels;
profile.wavelengthXSubvoxels=micrometresToQ(definition.hillWavelengthMicrometres);
profile.wavelengthYSubvoxels=profile.wavelengthXSubvoxels;
ResolveWorldAssemblySurfaceProfilePhasesV1(profile,seed);
}
if(!world_assembly_detail::ValidateSurfaceProfile(profile,seed,error))return false;
stratum.hasRecipeOverride=true;
stratum.recipeOverride=recipe;
stratum.recipeOverride.surfaceProfile=profile;
stratum.recipeOverride.contentHash=0;
stratum.surfaceProfile=profile;
stratum.capHeightSubvoxels=top-4*qPerMetre;
stratum.capUndulationSubvoxels=0;
stratum.capDetailAmplitudeSubvoxels=0;
stratum.capRidgeAmplitudeSubvoxels=0;
stratum.waterEnabled=false;
stratum.waterSurfaceSubvoxels=0;
const auto groundHeightAt=[&](std::int64_t x,std::int64_t y)
{
if(profile.kind==WorldAssemblySurfaceProfileKindV1::flatField)
return profile.h0Subvoxels;
const std::int64_t turnX=world_assembly_detail::SurfaceProfileTurnAtCoordinate(
x,profile.wavelengthXSubvoxels,profile.phaseXTurnsQ32);
const std::int64_t turnY=world_assembly_detail::SurfaceProfileTurnAtCoordinate(
y,profile.wavelengthYSubvoxels,profile.phaseYTurnsQ32);
return profile.h0Subvoxels
+world_assembly_detail::MulQ30(profile.amplitudeXSubvoxels,
world_assembly_detail::CosineQ30(turnX))
+world_assembly_detail::MulQ30(profile.amplitudeYSubvoxels,
world_assembly_detail::CosineQ30(turnY));
};
const auto routeXY=CoreLiminalRouteXYV2(-12*qPerMetre,0,12*qPerMetre,0,qPerMetre);
const auto squareRoot=[](std::uint64_t value)
{return world_assembly_detail::IntegerSqrt(value);};
const auto directionQ16=[&](std::int64_t dx,std::int64_t dy)
{
const std::uint64_t length=squareRoot(static_cast<std::uint64_t>(dx*dx+dy*dy));
if(length==0)return std::array<std::int32_t,2>{{0,0}};
const auto rounded=[&](std::int64_t value)
{return value>=0?(value+static_cast<std::int64_t>(length/2))
/static_cast<std::int64_t>(length)
:(value-static_cast<std::int64_t>(length/2))
/static_cast<std::int64_t>(length);};
return std::array<std::int32_t,2>{{
static_cast<std::int32_t>(rounded(dx*65536)),
static_cast<std::int32_t>(rounded(dy*65536))}};
};
const auto arrivalDirection=directionQ16(routeXY[1][0]-routeXY[0][0],
routeXY[1][1]-routeXY[0][1]);
const auto departureDirection=directionQ16(routeXY.back()[0]-routeXY[routeXY.size()-2][0],
routeXY.back()[1]-routeXY[routeXY.size()-2][1]);
const std::int64_t playerCenterAboveFloor=micrometresToQ(1130000);
const std::int64_t landingClearance=micrometresToQ(6000000);
const std::int64_t supportDepth=micrometresToQ(2000000);
const auto makePad=[&](std::string id,ResolvedLayoutLandingPadRoleV1 role,
const std::array<std::int64_t,2>& xy,const std::array<std::int32_t,2>& direction)
{
ResolvedLayoutLandingPadV1 pad;
pad.stableId=std::move(id);pad.role=role;
pad.floorHeightSubvoxels=groundHeightAt(xy[0],xy[1]);
pad.positionSubvoxels={xy[0],xy[1],pad.floorHeightSubvoxels+playerCenterAboveFloor};
pad.approachDirectionQ16=direction;
pad.clearanceSubvoxels=landingClearance;
pad.supportDepthSubvoxels=supportDepth;
pad.certifiedWalkableWithSupport=true;
return pad;
};
resolved->recipeId=std::string(CoreLiminalFieldRecipeIdV1);
resolved->recipeVersion=CoreLiminalFieldRecipeVersionV2;
resolved->landingPads.clear();
resolved->landingPads.push_back(makePad("core/liminal-field/landing/arrival/000",
ResolvedLayoutLandingPadRoleV1::arrival,routeXY.front(),arrivalDirection));
resolved->landingPads.push_back(makePad("core/liminal-field/landing/departure/000",
ResolvedLayoutLandingPadRoleV1::departure,routeXY.back(),departureDirection));
std::uint64_t routeLength=0;
stratum.route=BuildCoreLiminalRouteV2(profile,resolved->landingPads[0],
resolved->landingPads[1],definition,seed,stratum.strateIndex,coreMicrons,
qPerMetre,routeLength,error);
if(!error.empty())return false;
stratum.routeConstraints={1,micrometresToQ(340000),micrometresToQ(1760000),
17560,micrometresToQ(125000),micrometresToQ(250000),
micrometresToQ(1000000),micrometresToQ(120000),3};
resolved->anchors.erase(std::remove_if(resolved->anchors.begin(),resolved->anchors.end(),
[](const auto& anchor){return anchor.kind=="route_point"
||anchor.kind=="liminal_route_point"||anchor.kind=="liminal_variant"
||anchor.kind=="heightfield_profile";}),resolved->anchors.end());
ResolvedLayoutAnchorV2 profileAnchor;
profileAnchor.kind="heightfield_profile";
profileAnchor.stableId="heightfield-profile/liminal/"
+std::to_string(static_cast<std::uint32_t>(profile.kind));
profileAnchor.units="profile kind enum";
profileAnchor.values={1,static_cast<std::int64_t>(profile.kind)};
resolved->anchors.push_back(std::move(profileAnchor));
std::uint64_t routeAnchorDistance=0,lastRouteAnchorDistance=0;
for(std::size_t pointIndex=0;pointIndex<stratum.route.size();++pointIndex)
{
if(pointIndex>0)
{
const auto& previous=stratum.route[pointIndex-1].positionSubvoxels;
const auto& current=stratum.route[pointIndex].positionSubvoxels;
const auto dx=static_cast<std::uint64_t>(current[0]-previous[0]);
const auto dy=static_cast<std::uint64_t>(current[1]-previous[1]);
routeAnchorDistance+=world_assembly_detail::IntegerSqrt(dx*dx+dy*dy);
}
const bool first=pointIndex==0;
const bool last=pointIndex+1==stratum.route.size();
const bool spaced=routeAnchorDistance-lastRouteAnchorDistance
>=static_cast<std::uint64_t>(8*qPerMetre);
if(!first&&!last&&!spaced)continue;
const auto& point=stratum.route[pointIndex];
ResolvedLayoutAnchorV2 routeAnchor;
routeAnchor.kind="route_point";
routeAnchor.stableId="route/"+std::to_string(pointIndex);
routeAnchor.units="1/256 Core voxel";
routeAnchor.values={point.positionSubvoxels[0],point.positionSubvoxels[1],
point.positionSubvoxels[2]+playerCenterAboveFloor,point.radiusSubvoxels};
resolved->anchors.push_back(std::move(routeAnchor));
lastRouteAnchorDistance=routeAnchorDistance;
}
if(!layout.finalize(error))return false;
const auto reportPad=[&](const ResolvedLayoutLandingPadV1& pad)
{
std::printf("[ResolvedLandingPad] strate=%d id=%s role=%s position_m=(%.3f,%.3f,%.3f) "
"floor_m=%.3f approach_q16=(%d,%d) clearance_m=%.3f support_m=%.3f "
"certified_walkable_with_support=true status=PASS\n",stratum.strateIndex,
pad.stableId.c_str(),pad.role==ResolvedLayoutLandingPadRoleV1::arrival?"arrival":"departure",
pad.positionSubvoxels[0]/static_cast<double>(qPerMetre),
pad.positionSubvoxels[1]/static_cast<double>(qPerMetre),
pad.positionSubvoxels[2]/static_cast<double>(qPerMetre),
pad.floorHeightSubvoxels/static_cast<double>(qPerMetre),
pad.approachDirectionQ16[0],pad.approachDirectionQ16[1],
pad.clearanceSubvoxels/static_cast<double>(qPerMetre),
pad.supportDepthSubvoxels/static_cast<double>(qPerMetre));
};
reportPad(resolved->landingPads[0]);reportPad(resolved->landingPads[1]);
std::printf("[LiminalPadRoute] points=%zu path_length_m=%.3f spacing_max_m=4.000 "
"profile_ground_following=true status=PASS\n",stratum.route.size(),
routeLength/static_cast<double>(qPerMetre));
return true;
}
bool PlanCoreLiminalFieldV2(WorldAssemblyRecipeV1& recipe,
WorldAssemblyStratumPlanV1& stratum,const ResolvedLayoutSnapshotV3& layout,
std::string& error)
{
error.clear();
if(layout.coreVoxelSizeMicrometres==0||stratum.strateIndex<0
||stratum.topChunkZ<stratum.bottomChunkZ)
{error="Core.Liminal.Field v2 needs a finite stratum and resolved Core voxel size";return false;}
const auto resolved=std::find_if(layout.strates.begin(),layout.strates.end(),
[&](const auto& value){return value.strateIndex==stratum.strateIndex
&&value.recipeId==CoreLiminalFieldRecipeIdV1
&&value.recipeVersion==CoreLiminalFieldRecipeVersionV2;});
if(resolved==layout.strates.end()||!resolved->content.presentInCurrentField
||stratum.surfaceProfile.version!=1)
{error="Core.Liminal.Field v2 needs its prepared profile and resolved landing pads";return false;}
const ResolvedLayoutLandingPadV1* arrivalPad=nullptr;
const ResolvedLayoutLandingPadV1* departurePad=nullptr;
for(const auto& pad:resolved->landingPads)
{
if(pad.role==ResolvedLayoutLandingPadRoleV1::arrival)
{if(arrivalPad){error="Core.Liminal.Field v2 has multiple arrival pads";return false;}arrivalPad=&pad;}
if(pad.role==ResolvedLayoutLandingPadRoleV1::departure)
{if(departurePad){error="Core.Liminal.Field v2 has multiple departure pads";return false;}departurePad=&pad;}
}
if(!arrivalPad||!departurePad||!arrivalPad->certifiedWalkableWithSupport
||!departurePad->certifiedWalkableWithSupport)
{error="Core.Liminal.Field v2 requires certified arrival and departure pads";return false;}
const ResolvedLayoutPassageV1* arrival=nullptr;
const ResolvedLayoutPassageV1* departure=nullptr;
for(const auto& passage:layout.passages)
{
if(passage.lowerStrateIndex==stratum.strateIndex)
{if(arrival){error="Core.Liminal.Field v2 requires one arrival passage";return false;}arrival=&passage;}
if(passage.upperStrateIndex==stratum.strateIndex)
{if(departure){error="Core.Liminal.Field v2 requires one departure passage";return false;}departure=&passage;}
}
if(!arrival||!departure||arrival->lowerMouthSubvoxels!=arrivalPad->positionSubvoxels
||departure->upperMouthSubvoxels!=departurePad->positionSubvoxels)
{error="Core.Liminal.Field v2 passage mouths are not bound to the certified layer pads";return false;}
constexpr std::int64_t Q=WorldAssemblySubvoxelsPerVoxel;
const std::int64_t coreMicrons=layout.coreVoxelSizeMicrometres;
const auto micrometresToQ=[&](std::int64_t micrometres)
{
const std::int64_t numerator=micrometres*Q;
return numerator>=0?(numerator+coreMicrons/2)/coreMicrons
:(numerator-coreMicrons/2)/coreMicrons;
};
const std::int64_t qPerMetre=micrometresToQ(1000000);
const std::int64_t playerCenterAboveFloor=micrometresToQ(1130000);
if(qPerMetre<=0||arrivalPad->positionSubvoxels[2]
!=arrivalPad->floorHeightSubvoxels+playerCenterAboveFloor
||departurePad->positionSubvoxels[2]
!=departurePad->floorHeightSubvoxels+playerCenterAboveFloor)
{error="Core.Liminal.Field v2 pad floor and capsule-center heights differ";return false;}
const std::uint32_t seed=recipe.seed;
const WorldAssemblyLiminalVariantV1 variant=SelectCoreLiminalFieldVariantV1(seed);
const auto& definition=CoreLiminalFieldVariantsV1[static_cast<std::size_t>(variant)];
const auto& profile=stratum.surfaceProfile;
std::uint64_t totalHorizontal=0;
std::vector<WorldAssemblyRoutePointV1> route=BuildCoreLiminalRouteV2(profile,
*arrivalPad,*departurePad,definition,seed,stratum.strateIndex,coreMicrons,
qPerMetre,totalHorizontal,error);
if(!error.empty())return false;
if(route.size()!=stratum.route.size())
{error="Core.Liminal.Field v2 route differs from the path used to certify its pads";return false;}
for(std::size_t index=0;index<route.size();++index)
if(route[index].stableFeatureId!=stratum.route[index].stableFeatureId
||route[index].positionSubvoxels!=stratum.route[index].positionSubvoxels
||route[index].radiusSubvoxels!=stratum.route[index].radiusSubvoxels)
{error="Core.Liminal.Field v2 route differs from the path used to certify its pads";return false;}
WorldAssemblyLiminalFieldPlanV1 liminal;
liminal.version=CoreLiminalFieldRecipeVersionV2;
liminal.variant=variant;liminal.seed=seed;
liminal.arrivalMouthSubvoxels=arrivalPad->positionSubvoxels;
liminal.departureMouthSubvoxels=departurePad->positionSubvoxels;
liminal.floorHeightSubvoxels=profile.h0Subvoxels;
liminal.routeHalfWidthSubvoxels=micrometresToQ(definition.routeHalfWidthMicrometres);
liminal.routeHalfThicknessSubvoxels=micrometresToQ(definition.routeHalfThicknessMicrometres);
liminal.routeOffsetSubvoxels=150*qPerMetre;
liminal.supportSpacingSubvoxels=micrometresToQ(definition.supportSpacingMicrometres);
liminal.supportRadiusSubvoxels=micrometresToQ(definition.supportRadiusMicrometres);
liminal.mouthFloorOffsetSubvoxels=playerCenterAboveFloor;
stratum.route=std::move(route);
stratum.routeConstraints={1,micrometresToQ(340000),micrometresToQ(1760000),
17560,micrometresToQ(125000),micrometresToQ(250000),
micrometresToQ(1000000),micrometresToQ(120000),3};
stratum.liminalField=liminal;
std::string validationError;
if(!world_assembly_detail::ValidateSurfaceProfile(stratum.surfaceProfile,seed,validationError)
||!world_assembly_detail::ValidateStratum(stratum,recipe,validationError))
{error=validationError.empty()?"Core.Liminal.Field v2 produced an invalid plan":validationError;return false;}
std::printf("[CoreLiminalFieldPlan] recipe=%.*s version=%u variant=%.*s seed=%u "
"arrival_pad=%s departure_pad=%s route_points=%zu path_length_m=%.3f "
"profile_ground_following=true route_grade_limit_deg=15.000 status=PASS\n",
static_cast<int>(CoreLiminalFieldRecipeIdV1.size()),CoreLiminalFieldRecipeIdV1.data(),
liminal.version,static_cast<int>(definition.name.size()),definition.name.data(),seed,
arrivalPad->stableId.c_str(),departurePad->stableId.c_str(),stratum.route.size(),
totalHorizontal/static_cast<double>(qPerMetre));
return true;
}
std::string WorldAssemblyManifest::ToJson() const
{
std::string error;