wip: Core.Liminal.Field v1 recipe, 4 seed-selected variants between fixed mouths (L144, fails mouth joins)

Plans and draws flat field+monolith, repeating hills, road over cloud floor and pillar grid in a 3-strata fixture,
binding passage/0-1 and 1-2 as fixed endpoints. Composed W1 probes: 3/4 seeds fail one passage interface, 4/4 fail the
liminal walk audit near the mouths (support itself passes). Stopped per AGENTS.md. Same mouth-ownership failure
class as FI (L133/L140) and VS seed 2 (L139).

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 11:17:45 +01:00
1 parent a4e214561f
commit a45ba9bb10
18 files changed
+1547 -43

No files matched your search

@@ -597,6 +597,61 @@ namespace VoxelForgeCore
}
}
inline constexpr std::string_view CoreLiminalFieldRecipeIdV1 = "Core.Liminal.Field";
inline constexpr std::uint32_t CoreLiminalFieldRecipeVersionV1 = 1;
inline constexpr std::uint32_t CoreLiminalFieldVariantCountV1 = 4;
enum class WorldAssemblyLiminalVariantV1 : std::uint32_t
{
flatFieldMonolith = 0,
repeatingHills = 1,
roadOverCloudFloor = 2,
pillarGrid = 3
};
struct WorldAssemblyLiminalVariantDefinitionV1
{
WorldAssemblyLiminalVariantV1 variant = WorldAssemblyLiminalVariantV1::flatFieldMonolith;
std::string_view name;
WorldAssemblySurfaceProfileKindV1 surfaceKind = WorldAssemblySurfaceProfileKindV1::flatField;
std::int64_t hillAmplitudeMicrometres = 0;
std::int64_t hillWavelengthMicrometres = 0;
std::int64_t routeHalfWidthMicrometres = 0;
std::int64_t routeHalfThicknessMicrometres = 0;
std::int64_t supportSpacingMicrometres = 0;
std::int64_t supportRadiusMicrometres = 0;
std::int64_t monolithRadiusMicrometres = 0;
std::int64_t monolithHeightMicrometres = 0;
std::uint32_t pillarRows = 0;
std::uint32_t pillarColumns = 0;
std::int64_t pillarSpacingMicrometres = 0;
std::int64_t pillarRadiusMicrometres = 0;
std::int64_t pillarHeightMicrometres = 0;
};
inline constexpr std::array<WorldAssemblyLiminalVariantDefinitionV1,
CoreLiminalFieldVariantCountV1> CoreLiminalFieldVariantsV1{{
{WorldAssemblyLiminalVariantV1::flatFieldMonolith, "flatField-monolith",
WorldAssemblySurfaceProfileKindV1::flatField, 0, 0, 1750000, 500000,
36000000, 550000, 1600000, 26000000, 0, 0, 0, 0, 0},
{WorldAssemblyLiminalVariantV1::repeatingHills, "periodicHills",
WorldAssemblySurfaceProfileKindV1::periodicHills, 2200000, 80000000,
1750000, 500000, 36000000, 550000, 0, 0, 0, 0, 0, 0, 0},
{WorldAssemblyLiminalVariantV1::roadOverCloudFloor, "road-over-cloud-floor",
WorldAssemblySurfaceProfileKindV1::flatField, 0, 0, 2000000, 500000,
24000000, 550000, 0, 0, 0, 0, 0, 0, 0},
{WorldAssemblyLiminalVariantV1::pillarGrid, "pillar-grid",
WorldAssemblySurfaceProfileKindV1::flatField, 0, 0, 1750000, 500000,
36000000, 550000, 0, 0, 15, 15, 76000000, 5500000, 40000000}
}};
inline constexpr WorldAssemblyLiminalVariantV1 SelectCoreLiminalFieldVariantV1(
std::uint32_t seed) noexcept
{
return static_cast<WorldAssemblyLiminalVariantV1>(
seed % CoreLiminalFieldVariantCountV1);
}
struct WorldAssemblyRecipeV1
{
std::uint32_t schemaVersion = WorldAssemblySchemaVersion;
@@ -654,6 +709,23 @@ namespace VoxelForgeCore
std::array<std::int64_t, 4> parametersSubvoxels{};
};
struct WorldAssemblyLiminalFieldPlanV1
{
std::uint32_t version = 0;
WorldAssemblyLiminalVariantV1 variant = WorldAssemblyLiminalVariantV1::flatFieldMonolith;
std::uint32_t seed = 0;
std::array<std::int64_t, 3> arrivalMouthSubvoxels{};
std::array<std::int64_t, 3> departureMouthSubvoxels{};
// Fixed distance from each passage player-center anchor to its walk surface.
std::int64_t mouthFloorOffsetSubvoxels = 0;
std::int64_t floorHeightSubvoxels = 0;
std::int64_t routeHalfWidthSubvoxels = 0;
std::int64_t routeHalfThicknessSubvoxels = 0;
std::int64_t routeOffsetSubvoxels = 0;
std::int64_t supportSpacingSubvoxels = 0;
std::int64_t supportRadiusSubvoxels = 0;
};
struct WorldAssemblyStratumPlanV1
{
std::int32_t strateIndex = -1;
@@ -678,6 +750,7 @@ namespace VoxelForgeCore
std::vector<WorldAssemblyFeatureV1> features;
WorldAssemblyRouteConstraintsV1 routeConstraints;
std::vector<WorldAssemblyRoutePointV1> route;
WorldAssemblyLiminalFieldPlanV1 liminalField;
std::uint64_t contentHash = 0;
};
@@ -893,6 +966,7 @@ namespace VoxelForgeCore
inline constexpr std::uint32_t ResolvedLayoutStampVocabularyVersionV3 = 3;
inline constexpr std::uint32_t ResolvedLayoutStampVocabularyVersionV4 = 4;
inline constexpr std::uint32_t ResolvedLayoutStampVocabularyVersionV5 = 5;
inline constexpr std::uint32_t ResolvedLayoutStampVocabularyVersionV6 = 6;
inline constexpr std::uint32_t ResolvedLayoutCavernGraphVocabularyVersionV1 = 1;
inline constexpr std::uint32_t ResolvedLayoutOreVeinVocabularyVersionV1 = 1;
enum class ResolvedLayoutValidationModeV3 : std::uint8_t { compatibility, strict };
@@ -920,6 +994,7 @@ namespace VoxelForgeCore
// Present only for fillSweptDeckSegment; defines its directed centerline.
std::array<std::array<std::int64_t, 3>, 2> sweepEndpointsMicrometres{};
// V5 permits one continuous swept deck to carry its complete sampled centerline.
// V6 also permits a path whose X coordinates are not strictly increasing.
// Empty retains the V4 single-segment interpretation.
std::vector<std::array<std::int64_t, 3>> sweepPathMicrometres;
std::int64_t placementRadiusMicrometres = 0;
@@ -1238,6 +1313,9 @@ namespace VoxelForgeCore
ResolvedLayoutSnapshotV3& layout, std::int32_t seed,
const std::vector<ResolvedLayoutPassageConfigV1>& configs,
std::string& error);
VFCORE_API bool PlanCoreLiminalFieldV1(
WorldAssemblyRecipeV1& recipe, WorldAssemblyStratumPlanV1& stratum,
const ResolvedLayoutSnapshotV3& layout, std::string& error);
struct ResolvedLayoutStampPlacementAuditV1
{
+94 -10
View File
@@ -249,6 +249,71 @@ namespace
/WorldAssemblySubvoxelsPerVoxel));
return result;
};
const bool liminalRouteStamp=strate->recipeId==CoreLiminalFieldRecipeIdV1
&&stamp.stableId.starts_with("core/liminal-field/route/")
&&(stamp.kind==ResolvedSdfStampKindV1::fillSweptDeckSegment
||stamp.kind==ResolvedSdfStampKindV1::fillPillar);
if(liminalRouteStamp)
{
const auto variant=std::find_if(strate->anchors.begin(),strate->anchors.end(),
[](const auto& anchor){return anchor.kind=="liminal_variant"
&&anchor.values.size()>=6;});
std::vector<const ResolvedLayoutAnchorV2*> points;
for(const auto& anchor:strate->anchors)
if(anchor.kind=="liminal_route_point"&&anchor.values.size()>=4)
points.push_back(&anchor);
if(variant==strate->anchors.end()||points.size()<2)
{if(reason)*reason="Core.Liminal.Field route stamp has no versioned fixed-mouth route";return false;}
const auto routePoint=[&](const ResolvedLayoutAnchorV2& anchor)
{
std::array<std::int64_t,3> q={anchor.values[0],anchor.values[1],anchor.values[2]};
return qToMicrometres(q);
};
const std::int64_t halfThickness=static_cast<std::int64_t>(std::llround(
static_cast<double>(variant->values[5])*coreMicrometres
/WorldAssemblySubvoxelsPerVoxel));
if(stamp.kind==ResolvedSdfStampKindV1::fillSweptDeckSegment)
{
const auto first=routePoint(*points.front());
const auto last=routePoint(*points.back());
if(stamp.sweepPathMicrometres.size()<2
||stamp.sweepPathMicrometres.front()[0]!=first[0]
||stamp.sweepPathMicrometres.front()[1]!=first[1]
||stamp.sweepPathMicrometres.front()[2]!=first[2]-halfThickness
||stamp.sweepPathMicrometres.back()[0]!=last[0]
||stamp.sweepPathMicrometres.back()[1]!=last[1]
||stamp.sweepPathMicrometres.back()[2]!=last[2]-halfThickness)
{if(reason)*reason="Core.Liminal.Field deck does not terminate at its fixed passage mouths";return false;}
return true;
}
const auto deck=std::find_if(layout.stamps.begin(),layout.stamps.end(),
[&](const auto& existing){return existing.strateIndex==stamp.strateIndex
&&existing.stableId=="core/liminal-field/route/deck/000"
&&existing.kind==ResolvedSdfStampKindV1::fillSweptDeckSegment;});
if(deck==layout.stamps.end()||deck->sweepPathMicrometres.size()<2)
{if(reason)*reason="Core.Liminal.Field support has no previously resolved route deck";return false;}
double distance=std::numeric_limits<double>::infinity();
for(std::size_t i=1;i<deck->sweepPathMicrometres.size();++i)
{
const auto& a=deck->sweepPathMicrometres[i-1];
const auto& b=deck->sweepPathMicrometres[i];
const double dx=static_cast<double>(b[0]-a[0]);
const double dy=static_cast<double>(b[1]-a[1]);
const double lengthSquared=dx*dx+dy*dy;
const double t=lengthSquared>0.0?std::clamp(
((stamp.positionMicrometres[0]-a[0])*dx
+(stamp.positionMicrometres[1]-a[1])*dy)/lengthSquared,
0.0,1.0):0.0;
const double offsetX=stamp.positionMicrometres[0]-(a[0]+t*dx);
const double offsetY=stamp.positionMicrometres[1]-(a[1]+t*dy);
distance=std::min(distance,std::hypot(offsetX,offsetY));
}
const double corridorRadius=deck->halfExtentsMicrometres[1]
+stamp.halfExtentsMicrometres[0]+RouteClearanceMicrometres;
if(distance>corridorRadius)
{if(reason)*reason="Core.Liminal.Field route stamp is outside its versioned route corridor";return false;}
return true;
}
for(const auto& passage:layout.passages)
{
if(passage.upperStrateIndex!=stamp.strateIndex
@@ -1158,8 +1223,9 @@ bool ResolvedLayoutSnapshotV3::validate(ResolvedLayoutValidationModeV3 mode,
&&stampVocabularyVersion!=ResolvedLayoutStampVocabularyVersionV2
&&stampVocabularyVersion!=ResolvedLayoutStampVocabularyVersionV3
&&stampVocabularyVersion!=ResolvedLayoutStampVocabularyVersionV4
&&stampVocabularyVersion!=ResolvedLayoutStampVocabularyVersionV5)
add("stamp_vocabulary_version","resolved stamps require supported vocabulary version 1 through 5");
&&stampVocabularyVersion!=ResolvedLayoutStampVocabularyVersionV5
&&stampVocabularyVersion!=ResolvedLayoutStampVocabularyVersionV6)
add("stamp_vocabulary_version","resolved stamps require supported vocabulary version 1 through 6");
std::vector<std::string> stampIds;
for(const auto& stamp:stamps)
{
@@ -1217,11 +1283,15 @@ bool ResolvedLayoutSnapshotV3::validate(ResolvedLayoutValidationModeV3 mode,
validPath=validPath&&coordinate>=-1000000000000ll
&&coordinate<=1000000000000ll;
if(pointIndex>0)
validPath=validPath
&&stamp.sweepPathMicrometres[pointIndex-1][0]<point[0];
{
const auto& previous=stamp.sweepPathMicrometres[pointIndex-1];
validPath=validPath&&previous!=point
&&(stampVocabularyVersion>=ResolvedLayoutStampVocabularyVersionV6
||previous[0]<point[0]);
}
}
if(!validPath)add("stamp_sweep_path",stamp.stableId
+" has an invalid V5 path or non-increasing longitudinal axis");
+" has an invalid swept-deck path for its vocabulary version");
}
}
if(motif)
@@ -1749,10 +1819,20 @@ bool ResolveResolvedLayoutStampsV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
const bool hasContinuousSweptDeck=std::any_of(ordered.begin(),ordered.end(),[](const auto& request)
{return request.kind==ResolvedSdfStampKindV1::fillSweptDeckSegment
&&!request.sweepPathMicrometres.empty();});
const bool hasNonMonotoneSweptDeck=std::any_of(ordered.begin(),ordered.end(),[](const auto& request)
{
if(request.kind!=ResolvedSdfStampKindV1::fillSweptDeckSegment
||request.sweepPathMicrometres.empty())return false;
for(std::size_t i=1;i<request.sweepPathMicrometres.size();++i)
if(request.sweepPathMicrometres[i-1][0]>=request.sweepPathMicrometres[i][0])
return true;
return false;
});
const bool hasSweptDeck=std::any_of(ordered.begin(),ordered.end(),[](const auto& request)
{return request.kind==ResolvedSdfStampKindV1::fillSweptDeckSegment;});
candidate.stampVocabularyVersion=hasContinuousSweptDeck
?ResolvedLayoutStampVocabularyVersionV5
?(hasNonMonotoneSweptDeck?ResolvedLayoutStampVocabularyVersionV6
:ResolvedLayoutStampVocabularyVersionV5)
:hasSweptDeck?ResolvedLayoutStampVocabularyVersionV4
:ResolvedLayoutStampVocabularyVersionV1;
candidate.stamps.clear();candidate.stamps.reserve(ordered.size());
@@ -1818,8 +1898,8 @@ bool ResolveResolvedLayoutStampsV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
for(const auto coordinate:point)
if(coordinate<-1000000000000ll||coordinate>1000000000000ll)
{error="stamp request "+request.stableId+" has an unbounded path point";return false;}
if(pointIndex>0&&request.sweepPathMicrometres[pointIndex-1][0]>=point[0])
{error="stamp request "+request.stableId+" path X coordinates must increase strictly";return false;}
if(pointIndex>0&&request.sweepPathMicrometres[pointIndex-1]==point)
{error="stamp request "+request.stableId+" path contains a zero-length segment";return false;}
}
}
@@ -1836,6 +1916,7 @@ bool ResolveResolvedLayoutStampsV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
return static_cast<std::int64_t>(bits%span)-radius;
};
bool placed=false;
std::string lastPlacementFailure;
for(std::uint32_t attempt=0;attempt<(request.placementRadiusMicrometres==0?1u:512u);++attempt)
{
ResolvedLayoutStampV1 stamp;stamp.stableId=request.stableId;
@@ -1919,11 +2000,14 @@ bool ResolveResolvedLayoutStampsV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
stamp.boundsMaximumMicrometres[axis]=stamp.positionMicrometres[axis]+extents[axis];
}
}
if(!LayoutStampSafe(candidate,stamp))continue;
std::string safetyReason;
if(!LayoutStampSafe(candidate,stamp,&safetyReason))
{lastPlacementFailure=std::move(safetyReason);continue;}
candidate.stamps.push_back(std::move(stamp));placed=true;break;
}
if(!placed)
{error="stamp request "+request.stableId+" has no deterministic passage-safe content placement";return false;}
{error="stamp request "+request.stableId+" has no deterministic passage-safe content placement"
+(lastPlacementFailure.empty()?std::string{}:": "+lastPlacementFailure);return false;}
}
if(!candidate.finalize(error))return false;
std::vector<ResolvedLayoutIssueV2> issues;std::string strictError;
+28 -6
View File
@@ -1523,6 +1523,8 @@ public:
&nativeLatticeFloorSupport);
}
const auto* bound=FindBoundStratumForManagerZ(Z);
const bool liminalRouteComposition=bound&&bound->Resolved
&&bound->Resolved->recipeId==VoxelForgeCore::CoreLiminalFieldRecipeIdV1;
const bool nativeLattice=bound&&bound->Resolved
&&VoxelForgeCore::IsNativeLatticeFieldStratum(*bound->Resolved)
&&bound->Resolved->passageCapabilities.hasNativeLatticeField;
@@ -1546,7 +1548,9 @@ public:
VoxelForgeCore::Linux77Profiler::FScopedPhase l77StampPhase(
VoxelForgeCore::Linux77Profiler::EPhase::Stamps);
FScopedLegacyFieldTermTimer TermTimer(ELegacyFieldTerm::ComposerStamps);
stamped=ApplyResolvedSdfStamps(composed,X,Y,Z);
stamped=ApplyResolvedSdfStamps(composed,X,Y,Z,
liminalRouteComposition?std::string_view("core/liminal-field/route/")
:std::string_view{});
}
static const bool bL75TraceTnComposition=[]
{
@@ -1598,6 +1602,12 @@ public:
ELegacyFieldTerm::ComposerPassage);
final=ApplyResolvedStratePassageCarves(final,X,Y,Z);
}
// A liminal route is authored to terminate at fixed passage mouths. The
// passage carve owns the surrounding bore, while the deck/support stamps
// restore its walkable floor so the composed route crosses the interface.
if(liminalRouteComposition)
final=ApplyResolvedSdfStamps(final,X,Y,Z,{},
"core/liminal-field/route/");
if(bTraceTnComposition)
std::printf("[L75TNCompositionTrace] input=%.9g graph=%.9g boundary=%.9g passage=%.9g stamp=%.9g final=%.9g native=0\n",
density,graphDensity,boundary,composed,stamped,final);
@@ -7156,10 +7166,16 @@ private:
const float halfThickness=stamp.halfExtentsVoxels[2];
const float round=std::min(0.35f,std::min(halfWidth,halfThickness)*0.15f);
const float searchMargin=halfWidth+halfThickness+2.0f;
const auto first=std::lower_bound(path.begin(),path.end(),x-searchMargin,
[](const auto& point,float value){return point[0]<value;});
const auto last=std::upper_bound(first,path.end(),x+searchMargin,
[](float value,const auto& point){return value<point[0];});
const bool increasingX=std::adjacent_find(path.begin(),path.end(),
[](const auto& a,const auto& b){return a[0]>=b[0];})==path.end();
const auto first=increasingX
?std::lower_bound(path.begin(),path.end(),x-searchMargin,
[](const auto& point,float value){return point[0]<value;})
:path.begin();
const auto last=increasingX
?std::upper_bound(first,path.end(),x+searchMargin,
[](float value,const auto& point){return value<point[0];})
:path.end();
const std::size_t firstIndex=static_cast<std::size_t>(first-path.begin());
const std::size_t lastIndex=static_cast<std::size_t>(last-path.begin());
const std::size_t segmentBegin=std::min(path.size()-2,
@@ -7426,7 +7442,9 @@ private:
std::nextafter(maximum+outwardPadding,
std::numeric_limits<double>::infinity()),true};
}
float ApplyResolvedSdfStamps(float density,float X,float Y,float Z) const
float ApplyResolvedSdfStamps(float density,float X,float Y,float Z,
std::string_view excludedStableIdPrefix={},
std::string_view includedStableIdPrefix={}) const
{
if(StampRuntime.empty()||!Owner||Owner->CoreVoxelSizeMicrons==0)return density;
const auto* tileQueries=ActivePassageTileQueries;
@@ -7443,6 +7461,10 @@ private:
if(index>=StampRuntime.size())return;
const auto& runtime=StampRuntime[index];const auto& record=*runtime.record;
if(record.strateIndex!=bound->StrateIndex)return;
if(!excludedStableIdPrefix.empty()
&&record.stableId.starts_with(excludedStableIdPrefix))return;
if(!includedStableIdPrefix.empty()
&&!record.stableId.starts_with(includedStableIdPrefix))return;
if(UsesCoarsePillarProxy(runtime,CurrentStampSamplingStep()))return;
for(std::size_t axis=0;axis<3;++axis)
if(worldMicrometres[axis]<record.boundsMinimumMicrometres[axis]
@@ -539,6 +539,37 @@ namespace world_assembly_detail
if (squared == 0)
{ error = "world assembly route contains a zero-length segment"; return false; }
}
const auto& liminal = stratum.liminalField;
if (liminal.version != 0)
{
if (liminal.version != CoreLiminalFieldRecipeVersionV1
|| static_cast<std::uint32_t>(liminal.variant) >= CoreLiminalFieldVariantCountV1
|| liminal.seed != effectiveRecipe.seed
|| liminal.variant != SelectCoreLiminalFieldVariantV1(liminal.seed)
|| stratum.route.size() < 2
|| liminal.mouthFloorOffsetSubvoxels <= 0
|| stratum.route.front().positionSubvoxels[0] != liminal.arrivalMouthSubvoxels[0]
|| stratum.route.front().positionSubvoxels[1] != liminal.arrivalMouthSubvoxels[1]
|| stratum.route.front().positionSubvoxels[2]
!= liminal.arrivalMouthSubvoxels[2]-liminal.mouthFloorOffsetSubvoxels
|| stratum.route.back().positionSubvoxels[0] != liminal.departureMouthSubvoxels[0]
|| stratum.route.back().positionSubvoxels[1] != liminal.departureMouthSubvoxels[1]
|| stratum.route.back().positionSubvoxels[2]
!= liminal.departureMouthSubvoxels[2]-liminal.mouthFloorOffsetSubvoxels
|| liminal.routeHalfWidthSubvoxels < stratum.routeConstraints.capsuleRadiusSubvoxels
|| liminal.routeHalfThicknessSubvoxels <= 0
|| liminal.routeOffsetSubvoxels <= 0
|| liminal.supportSpacingSubvoxels <= 0
|| liminal.supportRadiusSubvoxels <= 0
|| stratum.surfaceProfile.version != 1)
{ error = "Core.Liminal.Field plan has invalid version, seed-selected variant, route mouths or dimensions"; return false; }
const std::int64_t bottom = static_cast<std::int64_t>(stratum.bottomChunkZ)
* layoutChunkWidthSubvoxels;
const std::int64_t top = (static_cast<std::int64_t>(stratum.topChunkZ) + 1)
* layoutChunkWidthSubvoxels;
if (liminal.floorHeightSubvoxels <= bottom || liminal.floorHeightSubvoxels >= top)
{ error = "Core.Liminal.Field floor escapes its finite stratum bounds"; return false; }
}
const auto& constraints = stratum.routeConstraints;
if (constraints.version == 0)
{
@@ -682,6 +713,24 @@ namespace world_assembly_detail
for (const auto value : point.positionSubvoxels) HashWord(hash, static_cast<std::uint64_t>(value), 8);
HashWord(hash, static_cast<std::uint64_t>(point.radiusSubvoxels), 8);
}
if (stratum.liminalField.version != 0)
{
const auto& liminal = stratum.liminalField;
HashWord(hash, 0x4c494d494e414c31ull, 8);
HashWord(hash, liminal.version, 4);
HashWord(hash, static_cast<std::uint32_t>(liminal.variant), 4);
HashWord(hash, liminal.seed, 4);
for (const auto value : liminal.arrivalMouthSubvoxels)
HashWord(hash, static_cast<std::uint64_t>(value), 8);
for (const auto value : liminal.departureMouthSubvoxels)
HashWord(hash, static_cast<std::uint64_t>(value), 8);
for (const auto value : {liminal.mouthFloorOffsetSubvoxels,
liminal.floorHeightSubvoxels,
liminal.routeHalfWidthSubvoxels, liminal.routeHalfThicknessSubvoxels,
liminal.routeOffsetSubvoxels, liminal.supportSpacingSubvoxels,
liminal.supportRadiusSubvoxels})
HashWord(hash, static_cast<std::uint64_t>(value), 8);
}
if (stratum.surfaceProfile.version != 0)
HashSurfaceProfile(hash, stratum.surfaceProfile);
return hash;
@@ -1059,6 +1108,30 @@ namespace world_assembly_detail
{ error = "world assembly route point is missing a fixed-scale field"; return false; }
stratum.route.push_back(point);
}
const VFJson::Value& liminalValue = item.Get("liminal_field");
if (!std::holds_alternative<std::nullptr_t>(liminalValue.Data))
{
auto& liminal = stratum.liminalField;
std::uint32_t variant = 0;
if (!liminalValue.IsObject()
|| !ReadU32(liminalValue.Get("version"), liminal.version)
|| !ReadU32(liminalValue.Get("variant"), variant)
|| !ReadU32(liminalValue.Get("seed"), liminal.seed)
|| !ReadArray(liminalValue.Get("arrival_mouth_q"),
liminal.arrivalMouthSubvoxels.data(), 3)
|| !ReadArray(liminalValue.Get("departure_mouth_q"),
liminal.departureMouthSubvoxels.data(), 3)
|| !ReadInteger(liminalValue.Get("mouth_floor_offset_q"),
liminal.mouthFloorOffsetSubvoxels)
|| !ReadInteger(liminalValue.Get("floor_height_q"), liminal.floorHeightSubvoxels)
|| !ReadInteger(liminalValue.Get("route_half_width_q"), liminal.routeHalfWidthSubvoxels)
|| !ReadInteger(liminalValue.Get("route_half_thickness_q"), liminal.routeHalfThicknessSubvoxels)
|| !ReadInteger(liminalValue.Get("route_offset_q"), liminal.routeOffsetSubvoxels)
|| !ReadInteger(liminalValue.Get("support_spacing_q"), liminal.supportSpacingSubvoxels)
|| !ReadInteger(liminalValue.Get("support_radius_q"), liminal.supportRadiusSubvoxels))
{ error = "Core.Liminal.Field plan is missing a fixed-scale field"; return false; }
liminal.variant = static_cast<WorldAssemblyLiminalVariantV1>(variant);
}
plan.strates.push_back(std::move(stratum));
}
return true;
@@ -2324,6 +2397,328 @@ bool WorldAssemblyManifest::validate(std::string& error) const
return true;
}
bool PlanCoreLiminalFieldV1(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 needs a finite stratum and resolved Core voxel size";return false;}
const auto resolvedStratum=std::find_if(layout.strates.begin(),layout.strates.end(),
[&](const auto& value){return value.strateIndex==stratum.strateIndex
&&value.generatorKind=="SurfaceWorld";});
if(resolvedStratum==layout.strates.end()||!resolvedStratum->content.presentInCurrentField)
{error="Core.Liminal.Field must target a resolved SurfaceWorld content band";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 requires one fixed arrival passage mouth";return false;}
arrival=&passage;
}
if(passage.upperStrateIndex==stratum.strateIndex)
{
if(departure){error="Core.Liminal.Field requires one fixed departure passage mouth";return false;}
departure=&passage;
}
}
if(!arrival||!departure)
{error="Core.Liminal.Field requires an adjacent passage on both sides";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 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 auto& start=arrival->lowerMouthSubvoxels;
const auto& finish=departure->upperMouthSubvoxels;
constexpr std::int64_t MaximumMouthCoordinateQ=1000000000ll;
if(std::abs(start[0])>MaximumMouthCoordinateQ||std::abs(start[1])>MaximumMouthCoordinateQ
||std::abs(start[2])>MaximumMouthCoordinateQ||std::abs(finish[0])>MaximumMouthCoordinateQ
||std::abs(finish[1])>MaximumMouthCoordinateQ||std::abs(finish[2])>MaximumMouthCoordinateQ)
{error="Core.Liminal.Field passage mouth exceeds the supported fixed-coordinate range";return false;}
const std::int64_t mouthPlayerCenterHeight=micrometresToQ(1130000);
auto routeStart=start;
auto routeFinish=finish;
routeStart[2]-=mouthPlayerCenterHeight;
routeFinish[2]-=mouthPlayerCenterHeight;
const auto findMouthControl=[&](const ResolvedLayoutPassageV1& passage,
const std::array<std::int64_t,3>& mouth)
{
std::size_t found=passage.controlPoints.size();
for(std::size_t i=0;i<passage.controlPoints.size();++i)
{
const auto& point=passage.controlPoints[i];
if(point.positionSubvoxels[0]==mouth[0]
&&point.positionSubvoxels[1]==mouth[1]
&&point.positionSubvoxels[2]-point.radiusSubvoxels
+mouthPlayerCenterHeight==mouth[2])
{
if(found!=passage.controlPoints.size())return passage.controlPoints.size();
found=i;
}
}
return found;
};
const std::size_t arrivalControl=findMouthControl(*arrival,start);
const std::size_t departureControl=findMouthControl(*departure,finish);
if(arrival->controlPoints.size()<2||departure->controlPoints.size()<2
||arrivalControl>=arrival->controlPoints.size()
||departureControl>=departure->controlPoints.size())
{error="Core.Liminal.Field needs exact passage-control bindings at both fixed mouths";return false;}
const auto horizontalLengthQ=[](std::int64_t dx,std::int64_t dy)
{
const auto absX=static_cast<std::uint64_t>(std::abs(dx));
const auto absY=static_cast<std::uint64_t>(std::abs(dy));
return world_assembly_detail::IntegerSqrt(absX*absX+absY*absY);
};
const auto roundRatio=[](std::int64_t numerator,std::uint64_t denominator)
{
if(denominator==0)return std::int64_t{0};
const auto positiveDenominator=static_cast<std::int64_t>(denominator);
return numerator>=0
?(numerator+positiveDenominator/2)/positiveDenominator
:-((-numerator+positiveDenominator/2)/positiveDenominator);
};
const auto passageSplineControls=[](const ResolvedLayoutPassageV1& passage)
{
std::vector<PassageSpline::FPoint> controls;
controls.reserve(passage.controlPoints.size());
for(const auto& point:passage.controlPoints)
controls.push_back({static_cast<double>(point.positionSubvoxels[0]),
static_cast<double>(point.positionSubvoxels[1]),
static_cast<double>(point.positionSubvoxels[2]-point.radiusSubvoxels),
static_cast<double>(point.radiusSubvoxels)});
return controls;
};
const auto arrivalSpline=passageSplineControls(*arrival);
const auto departureSpline=passageSplineControls(*departure);
constexpr double MouthTangentProbeParameter=0.5;
const std::size_t arrivalSegment=arrivalControl==0?0:arrivalControl-1;
const double arrivalAtT=arrivalControl==0?0.0:1.0;
const double arrivalNearT=arrivalControl==0?MouthTangentProbeParameter
:1.0-MouthTangentProbeParameter;
const auto arrivalNear=PassageSpline::EvaluateRaw(arrivalSpline,arrivalSegment,
arrivalNearT,static_cast<double>(qPerMetre));
const auto arrivalAt=PassageSpline::EvaluateRaw(arrivalSpline,arrivalSegment,
arrivalAtT,static_cast<double>(qPerMetre));
const std::size_t departureSegment=departureControl+1==departure->controlPoints.size()
?departureControl-1:departureControl;
const double departureAtT=departureControl+1==departure->controlPoints.size()?1.0:0.0;
const double departureNearT=departureControl+1==departure->controlPoints.size()
?1.0-MouthTangentProbeParameter:MouthTangentProbeParameter;
const auto departureAt=PassageSpline::EvaluateRaw(departureSpline,departureSegment,
departureAtT,static_cast<double>(qPerMetre));
const auto departureNear=PassageSpline::EvaluateRaw(departureSpline,departureSegment,
departureNearT,static_cast<double>(qPerMetre));
const auto roundedDelta=[](double startValue,double endValue)
{return static_cast<std::int64_t>(std::llround(endValue-startValue));};
const std::int64_t arrivalDx=roundedDelta(arrivalNear[0],arrivalAt[0]);
const std::int64_t arrivalDy=roundedDelta(arrivalNear[1],arrivalAt[1]);
const std::int64_t arrivalFloorDelta=roundedDelta(arrivalNear[2],arrivalAt[2]);
const std::uint64_t arrivalLength=horizontalLengthQ(arrivalDx,arrivalDy);
const std::int64_t departureDx=roundedDelta(departureAt[0],departureNear[0]);
const std::int64_t departureDy=roundedDelta(departureAt[1],departureNear[1]);
const std::int64_t departureFloorDelta=roundedDelta(departureAt[2],departureNear[2]);
const std::uint64_t departureLength=horizontalLengthQ(departureDx,departureDy);
if(arrivalLength==0||departureLength==0)
{error="Core.Liminal.Field passage mouth tangent is too short for a stable connector";return false;}
const auto extendMouth=[&](const std::array<std::int64_t,3>& mouth,
std::int64_t dx,std::int64_t dy,std::int64_t dz,std::uint64_t horizontalLength,
std::int64_t distance,bool forward)
{
const std::int64_t sign=forward?1:-1;
return std::array<std::int64_t,3>{
mouth[0]+roundRatio(sign*dx*distance,horizontalLength),
mouth[1]+roundRatio(sign*dy*distance,horizontalLength),
mouth[2]+roundRatio(sign*dz*distance,horizontalLength)};
};
constexpr std::int64_t MouthConnectorMidMetres=5;
constexpr std::int64_t MouthConnectorFullMetres=10;
const auto arrivalConnectorMid=extendMouth(routeStart,arrivalDx,arrivalDy,
arrivalFloorDelta,arrivalLength,MouthConnectorMidMetres*qPerMetre,true);
const auto arrivalConnector=extendMouth(routeStart,arrivalDx,arrivalDy,
arrivalFloorDelta,arrivalLength,MouthConnectorFullMetres*qPerMetre,true);
const auto departureConnector=extendMouth(routeFinish,departureDx,departureDy,
departureFloorDelta,departureLength,MouthConnectorFullMetres*qPerMetre,false);
const auto departureConnectorMid=extendMouth(routeFinish,departureDx,departureDy,
departureFloorDelta,departureLength,MouthConnectorMidMetres*qPerMetre,false);
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 minRouteFloor=std::min({routeStart[2],routeFinish[2],
arrivalConnectorMid[2],arrivalConnector[2],departureConnector[2],
departureConnectorMid[2]});
const std::int64_t contentBottom=micrometresToQ(
resolvedStratum->content.bottomMicrometres);
const std::int64_t profileRelief=variant==WorldAssemblyLiminalVariantV1::repeatingHills
?2*micrometresToQ(definition.hillAmplitudeMicrometres):0;
const std::int64_t floorHeight=std::max(contentBottom+profileRelief+qPerMetre/4,
minRouteFloor-8*qPerMetre);
if(floorHeight>=minRouteFloor-2*qPerMetre||floorHeight<=bottom||top<=floorHeight+8*qPerMetre)
{error="Core.Liminal.Field has no room for its floor and passage route";return false;}
stratum.hasRecipeOverride=true;
stratum.recipeOverride=recipe;
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);
}
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;
WorldAssemblyLiminalFieldPlanV1 liminal;
liminal.version=CoreLiminalFieldRecipeVersionV1;
liminal.variant=variant;
liminal.seed=seed;
liminal.arrivalMouthSubvoxels=start;
liminal.departureMouthSubvoxels=finish;
liminal.floorHeightSubvoxels=floorHeight;
liminal.routeHalfWidthSubvoxels=micrometresToQ(definition.routeHalfWidthMicrometres);
liminal.routeHalfThicknessSubvoxels=micrometresToQ(definition.routeHalfThicknessMicrometres);
liminal.supportSpacingSubvoxels=micrometresToQ(definition.supportSpacingMicrometres);
liminal.supportRadiusSubvoxels=micrometresToQ(definition.supportRadiusMicrometres);
liminal.mouthFloorOffsetSubvoxels=mouthPlayerCenterHeight;
constexpr std::int64_t GradeQ16=17560;
constexpr std::int64_t MinimumPathOffsetMetres=150;
constexpr std::int64_t ConnectorSpanMetres=16;
const std::int64_t dx=departureConnector[0]-arrivalConnector[0];
const std::int64_t dy=departureConnector[1]-arrivalConnector[1];
const std::uint64_t chord=horizontalLengthQ(dx,dy);
std::int64_t directionX=dx,directionY=dy;
std::uint64_t directionLength=chord;
if(directionLength<static_cast<std::uint64_t>(qPerMetre/4))
{directionX=Q;directionY=0;directionLength=static_cast<std::uint64_t>(Q);}
const std::int64_t normalX=-directionY;
const std::int64_t normalY=directionX;
const std::int64_t vertical=std::abs(departureConnector[2]-arrivalConnector[2]);
const std::int64_t requiredHorizontal=(vertical*65536+GradeQ16-1)/GradeQ16;
std::int64_t routeOffset=std::max(MinimumPathOffsetMetres*qPerMetre,
(requiredHorizontal+1)/2+20*qPerMetre);
if(chord<ConnectorSpanMetres*static_cast<std::uint64_t>(qPerMetre))
routeOffset=std::max(routeOffset,MinimumPathOffsetMetres*qPerMetre);
liminal.routeOffsetSubvoxels=routeOffset;
const auto normalOffset=[&](std::int64_t scale)
{
return std::array<std::int64_t,2>{
normalX*scale/static_cast<std::int64_t>(directionLength),
normalY*scale/static_cast<std::int64_t>(directionLength)};
};
const auto directionOffset=[&](std::int64_t scale)
{
return std::array<std::int64_t,2>{
directionX*scale/static_cast<std::int64_t>(directionLength),
directionY*scale/static_cast<std::int64_t>(directionLength)};
};
const auto normal=normalOffset(routeOffset);
const auto connector=chord<ConnectorSpanMetres*static_cast<std::uint64_t>(qPerMetre)
?directionOffset(ConnectorSpanMetres*qPerMetre):std::array<std::int64_t,2>{0,0};
std::vector<std::array<std::int64_t,3>> horizontalPath;
horizontalPath.reserve(8);
horizontalPath.push_back(routeStart);
horizontalPath.push_back(arrivalConnectorMid);
horizontalPath.push_back(arrivalConnector);
horizontalPath.push_back({arrivalConnector[0]+normal[0],
arrivalConnector[1]+normal[1],0});
horizontalPath.push_back({departureConnector[0]+normal[0]+connector[0],
departureConnector[1]+normal[1]+connector[1],0});
horizontalPath.push_back(departureConnector);
horizontalPath.push_back(departureConnectorMid);
horizontalPath.push_back(routeFinish);
std::vector<WorldAssemblyRoutePointV1> route;
route.reserve(horizontalPath.size());
std::vector<std::uint64_t> cumulative(horizontalPath.size(),0);
std::uint64_t totalHorizontal=0;
for(std::size_t i=1;i<horizontalPath.size();++i)
{
const std::int64_t sx=horizontalPath[i][0]-horizontalPath[i-1][0];
const std::int64_t sy=horizontalPath[i][1]-horizontalPath[i-1][1];
const std::uint64_t segment=horizontalLengthQ(sx,sy);
if(segment==0){error="Core.Liminal.Field route contains a zero-horizontal segment";return false;}
totalHorizontal+=segment;
cumulative[i]=totalHorizontal;
}
if(totalHorizontal<static_cast<std::uint64_t>(requiredHorizontal))
{error="Core.Liminal.Field route cannot meet the 15-degree grade bound";return false;}
const std::uint64_t centralFirst=horizontalLengthQ(
horizontalPath[3][0]-horizontalPath[2][0],
horizontalPath[3][1]-horizontalPath[2][1]);
const std::uint64_t centralMiddle=horizontalLengthQ(
horizontalPath[4][0]-horizontalPath[3][0],
horizontalPath[4][1]-horizontalPath[3][1]);
const std::uint64_t centralLast=horizontalLengthQ(
horizontalPath[5][0]-horizontalPath[4][0],
horizontalPath[5][1]-horizontalPath[4][1]);
const std::uint64_t centralTotal=centralFirst+centralMiddle+centralLast;
if(centralTotal==0)
{error="Core.Liminal.Field central route has no horizontal span";return false;}
const std::int64_t centralVertical=departureConnector[2]-arrivalConnector[2];
horizontalPath[3][2]=arrivalConnector[2]+roundRatio(
centralVertical*static_cast<std::int64_t>(centralFirst),centralTotal);
horizontalPath[4][2]=arrivalConnector[2]+roundRatio(
centralVertical*static_cast<std::int64_t>(centralFirst+centralMiddle),centralTotal);
for(std::size_t i=0;i<horizontalPath.size();++i)
{
auto point=horizontalPath[i];
WorldAssemblyRoutePointV1 routePoint;
routePoint.positionSubvoxels=point;
routePoint.radiusSubvoxels=std::max<std::int64_t>(liminal.routeHalfWidthSubvoxels,
micrometresToQ(500000));
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>(stratum.strateIndex),4);add(i,4);
routePoint.stableFeatureId=id?id:1;
route.push_back(routePoint);
}
stratum.route=std::move(route);
stratum.routeConstraints={1,micrometresToQ(340000),micrometresToQ(1760000),
GradeQ16,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 produced an invalid plan":validationError;return false;}
std::printf("[CoreLiminalFieldPlan] recipe=%.*s version=%u variant=%.*s seed=%u arrival=%s departure=%s route_points=%zu route_offset_m=%.3f 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,
arrival->stableId.c_str(),departure->stableId.c_str(),stratum.route.size(),
static_cast<double>(routeOffset)/qPerMetre);
return true;
}
std::string WorldAssemblyManifest::ToJson() const
{
std::string error;
@@ -2391,6 +2786,27 @@ std::string WorldAssemblyManifest::ToJson() const
<< ",\"minimum_clearance_q\":" << constraints.minimumClearanceSubvoxels
<< ",\"minimum_support_probes\":" << constraints.minimumSupportProbes << '}';
}
if (stratum.liminalField.version != 0)
{
const auto& liminal = stratum.liminalField;
out << ",\"liminal_field\":{\"version\":" << liminal.version
<< ",\"variant\":" << static_cast<std::uint32_t>(liminal.variant)
<< ",\"seed\":" << liminal.seed << ",\"arrival_mouth_q\":["
<< liminal.arrivalMouthSubvoxels[0] << ','
<< liminal.arrivalMouthSubvoxels[1] << ','
<< liminal.arrivalMouthSubvoxels[2] << "],\"departure_mouth_q\":["
<< liminal.departureMouthSubvoxels[0] << ','
<< liminal.departureMouthSubvoxels[1] << ','
<< liminal.departureMouthSubvoxels[2]
<< "],\"mouth_floor_offset_q\":" << liminal.mouthFloorOffsetSubvoxels
<< ",\"floor_height_q\":"
<< liminal.floorHeightSubvoxels
<< ",\"route_half_width_q\":" << liminal.routeHalfWidthSubvoxels
<< ",\"route_half_thickness_q\":" << liminal.routeHalfThicknessSubvoxels
<< ",\"route_offset_q\":" << liminal.routeOffsetSubvoxels
<< ",\"support_spacing_q\":" << liminal.supportSpacingSubvoxels
<< ",\"support_radius_q\":" << liminal.supportRadiusSubvoxels << '}';
}
out << ",\"route\":[";
for (std::size_t p = 0; p < stratum.route.size(); ++p)
{