wip: cave planner squash-merged into wip/combined (L173, RED - not for main)
Five conflicts resolved (CURRENT-STATE, ResolvedLayoutInternal.h, StreamBenchmarkHeadless.cpp, StreamBenchmarkPipeline.h, WorldAssemblyPrototype.h) keeping liminal + cave planner; L156 band fit only; evaluator v239 with v239 baselines (18/18 Clang/GCC W1/W8/W12). Fast tier FAILS (FI upper arrival: 40 unsupported chamber samples, 10 chamber-floor shell violations); TN and VS composed sweeps 0/16 (passage, seam, shell gates). Living plane loads at PostConfigInit (UE smoke passes). Source/: VoxelForgeCoreAdapter.cpp; VoxelForge.uplugin. 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
82eb5b1c66
commit
b09728354d
243 files changed
+23019
-307
No files matched your search
@@ -119,6 +119,48 @@ namespace VoxelForgeCore::PassageSpline
|
||||
return std::lerp(plannedFloor,receivingFloor,blend);
|
||||
}
|
||||
|
||||
inline void BlendEndpointFloorToRoute(std::span<const FPoint> controls,
|
||||
std::vector<double>& floorProfile,std::size_t endpoint,
|
||||
std::span<const std::array<double,3>> receivingRoute,double unitsPerMetre,
|
||||
double playerCenterAboveFloorMetres=1.13,double maximumGradeDegrees=12.0)
|
||||
{
|
||||
if(controls.size()!=floorProfile.size()||endpoint>=floorProfile.size()
|
||||
||receivingRoute.empty()||!(unitsPerMetre>0.0)
|
||||
||!(maximumGradeDegrees>0.0&&maximumGradeDegrees<45.0))return;
|
||||
const double maximumGrade=std::tan(maximumGradeDegrees
|
||||
*3.14159265358979323846/180.0);
|
||||
const double routeReach=controls[endpoint][3]/unitsPerMetre+0.5;
|
||||
constexpr double MouthProfileBlendDistanceMetres=10.0;
|
||||
double routeHeight=0.0,routeDistanceSquared=0.0;
|
||||
if(!ClosestRouteHeightAtXY(receivingRoute,controls[endpoint][0],
|
||||
controls[endpoint][1],routeHeight,routeDistanceSquared)
|
||||
||routeDistanceSquared>std::pow(routeReach*unitsPerMetre,2.0))return;
|
||||
floorProfile[endpoint]=routeHeight
|
||||
-playerCenterAboveFloorMetres*unitsPerMetre;
|
||||
double pathDistance=0.0;
|
||||
for(std::size_t step=1;step<controls.size();++step)
|
||||
{
|
||||
if(endpoint>0&&step>endpoint)break;
|
||||
const std::size_t index=endpoint==0?step:endpoint-step;
|
||||
const std::size_t previous=endpoint==0?index-1:index+1;
|
||||
const double dx=(controls[index][0]-controls[previous][0])/unitsPerMetre;
|
||||
const double dy=(controls[index][1]-controls[previous][1])/unitsPerMetre;
|
||||
const double horizontal=std::hypot(dx,dy);
|
||||
pathDistance+=horizontal;
|
||||
double localRouteHeight=0.0,localRouteDistanceSquared=0.0;
|
||||
const bool followsRoute=pathDistance<=MouthProfileBlendDistanceMetres
|
||||
&&ClosestRouteHeightAtXY(receivingRoute,
|
||||
controls[index][0],controls[index][1],localRouteHeight,localRouteDistanceSquared)
|
||||
&&localRouteDistanceSquared<=std::pow(routeReach*unitsPerMetre,2.0);
|
||||
double target=floorProfile[index];
|
||||
if(followsRoute)
|
||||
target=localRouteHeight-playerCenterAboveFloorMetres*unitsPerMetre;
|
||||
const double maximumStep=maximumGrade*horizontal*unitsPerMetre;
|
||||
floorProfile[index]=std::clamp(target,
|
||||
floorProfile[previous]-maximumStep,floorProfile[previous]+maximumStep);
|
||||
}
|
||||
}
|
||||
|
||||
inline std::vector<FSegment> BuildSegments(std::span<const FPoint> controls,
|
||||
std::size_t spanCount,double spacingMetres,double unitsPerMetre=1.0,
|
||||
std::span<const double> plannedFloorProfile={},
|
||||
|
||||
@@ -138,6 +138,9 @@ namespace VoxelForgeCore
|
||||
bool passageComposerProfiled = false;
|
||||
std::uint64_t passageTileFeatureCount = 0;
|
||||
std::uint64_t passageTileRouteSegmentCandidates = 0;
|
||||
std::uint64_t nativeCaveFieldSamples = 0;
|
||||
std::uint64_t cavernRoomCandidates = 0;
|
||||
std::uint64_t cavernEdgeCandidates = 0;
|
||||
std::uint64_t resolvedBoundaryBandQueries = 0;
|
||||
std::uint64_t passageComposerQueries = 0;
|
||||
std::uint64_t passageIterations = 0;
|
||||
@@ -496,8 +499,20 @@ namespace VoxelForgeCore
|
||||
// continuous floor while relaxing the spline chord tolerance and bounding shell work.
|
||||
// Version 226 unifies the passage influence reach in metres and converts it to core
|
||||
// voxels for every broadphase and proof bound. Version 227 uses the exact smooth-max
|
||||
// support width/6 when deriving that reach.
|
||||
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 227;
|
||||
// support width/6 when deriving that reach. Version 228 composes deterministic cave
|
||||
// graphs from fixed passage mouths and the owner Tunnel Network settings. Version 229
|
||||
// budgets cave floor support; 230 records a shared backbone floor profile and joint cap;
|
||||
// 231 carries passage tangents and floor slopes through cave portal lead-ins and keeps
|
||||
// floor backing local to the walk footprint, with depth measured along the floor normal;
|
||||
// 233 bounds passage ring jitter to the authored placement disk; 234 aligns route mouth
|
||||
// anchors with capsule foot height and carries support through the SurfaceWorld mouth;
|
||||
// 235 plans the cave backbone as a sampled curve with both passage mouth tangents and
|
||||
// preserves open cave lanes through passage shell overlaps; 236 binds passage mouths to
|
||||
// the planned graph route, preserves its walk corridor through shell overlaps, and keeps
|
||||
// boundary-blended host rock from widening the authored passage wall.
|
||||
// v238 plans one resolved passage spline with explicit landing chambers.
|
||||
// v239 plans their floor planes as the passage's continuous floor profile.
|
||||
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 239;
|
||||
|
||||
enum class FieldChannel : std::uint32_t
|
||||
{
|
||||
@@ -970,6 +985,8 @@ namespace VoxelForgeCore
|
||||
inline constexpr std::uint32_t ResolvedLayoutStampVocabularyVersionV6 = 6;
|
||||
inline constexpr std::uint32_t ResolvedLayoutStampVocabularyVersionV7 = 7;
|
||||
inline constexpr std::uint32_t ResolvedLayoutCavernGraphVocabularyVersionV1 = 1;
|
||||
inline constexpr std::uint32_t ResolvedLayoutCavernGraphVocabularyVersionV2 = 2;
|
||||
inline constexpr std::uint32_t ResolvedLayoutCavernGraphVocabularyVersionV3 = 3;
|
||||
inline constexpr std::uint32_t ResolvedLayoutOreVeinVocabularyVersionV1 = 1;
|
||||
enum class ResolvedLayoutValidationModeV3 : std::uint8_t { compatibility, strict };
|
||||
|
||||
@@ -1047,9 +1064,18 @@ namespace VoxelForgeCore
|
||||
{
|
||||
std::string stableId;
|
||||
std::int32_t strateIndex = -1;
|
||||
// 0 = floor-backed room; 1 = a true vertical cylindrical shaft. The
|
||||
// shaft form is part of the shared cave graph so other recipes can reuse
|
||||
// the same graph, indexing, interval and density machinery.
|
||||
std::uint8_t shapeKind = 0;
|
||||
std::array<std::int64_t, 3> centerMicrometres{};
|
||||
std::array<std::int64_t, 3> halfExtentsMicrometres{};
|
||||
std::int64_t floorMicrometres = 0;
|
||||
// Optional shared backbone profile reference. The room floor plane is
|
||||
// floorMicrometres plus this Q16 XY gradient from centerMicrometres.
|
||||
std::string floorProfileStableId;
|
||||
std::int64_t floorProfileDistanceMicrometres = -1;
|
||||
std::array<std::int32_t, 2> floorGradientQ16{};
|
||||
std::int64_t smoothWidthMicrometres = 0;
|
||||
// Optional feature-to-feature union width. Zero preserves the historical
|
||||
// behavior where smoothWidthMicrometres also controls the graph union.
|
||||
@@ -1057,6 +1083,11 @@ namespace VoxelForgeCore
|
||||
std::int64_t irregularityAmplitudeMicrometres = 0;
|
||||
std::int64_t irregularityWavelengthMicrometres = 0;
|
||||
std::uint64_t irregularitySeed = 0;
|
||||
// Used only by shapeKind=1. floorMicrometres is the shaft top; the
|
||||
// bottom is center.z - halfExtents.z. Ledges face one cardinal side.
|
||||
std::int64_t ledgeSpacingMicrometres = 0;
|
||||
std::int64_t ledgeDepthMicrometres = 0;
|
||||
std::uint8_t ledgeSide = 0;
|
||||
std::array<std::int64_t, 3> boundsMinimumMicrometres{};
|
||||
std::array<std::int64_t, 3> boundsMaximumMicrometres{};
|
||||
};
|
||||
@@ -1069,6 +1100,11 @@ namespace VoxelForgeCore
|
||||
std::int32_t strateIndex = -1;
|
||||
// A single cubic Bezier in XY. Its four Z values are the cubic floor profile.
|
||||
std::array<std::array<std::int64_t, 3>, 4> controlPointsMicrometres{};
|
||||
// Edges with the same profile ID are adjacent pieces of one shared h(s).
|
||||
// Distances are signed along that profile, so a terminal edge may be reversed.
|
||||
std::string floorProfileStableId;
|
||||
std::int64_t floorProfileStartDistanceMicrometres = -1;
|
||||
std::int64_t floorProfileEndDistanceMicrometres = -1;
|
||||
// Resolve-time, error-bounded approximation of the cubic centerline. Each
|
||||
// consecutive pair is a physical segment used by the native cave field.
|
||||
std::vector<std::array<std::int64_t, 3>> polylineMicrometres;
|
||||
@@ -1085,6 +1121,43 @@ namespace VoxelForgeCore
|
||||
std::array<std::int64_t, 3> boundsMaximumMicrometres{};
|
||||
};
|
||||
|
||||
// Inputs to the reusable, plan-time cave graph composer. All distances are
|
||||
// integer micrometres and unit-interval values are Q16 so the resolved graph
|
||||
// does not depend on worker count or floating-point random distributions.
|
||||
struct ResolvedCavernPlannerSettingsV1
|
||||
{
|
||||
std::int64_t roomSpacingMicrometres = 16000000;
|
||||
std::int64_t minimumRoomRadiusMicrometres = 2000000;
|
||||
std::int64_t maximumRoomRadiusMicrometres = 5000000;
|
||||
std::int64_t destinationRadiusMicrometres = 6000000;
|
||||
// Solid floor backing below the planned edge floor, preserved after graph
|
||||
// unions and passage composition. This is separate from bore height.
|
||||
std::int64_t floorSupportDepthMicrometres = 750000;
|
||||
std::int64_t minimumTunnelRadiusMicrometres = 750000;
|
||||
std::int64_t maximumTunnelRadiusMicrometres = 1000000;
|
||||
std::int64_t maximumTunnelLengthMicrometres = 45000000;
|
||||
std::int64_t tunnelWarpMicrometres = 0;
|
||||
std::int64_t caveWarpMicrometres = 0;
|
||||
std::int64_t smoothWidthMicrometres = 500000;
|
||||
std::int64_t irregularityAmplitudeMicrometres = 0;
|
||||
std::int64_t irregularityWavelengthMicrometres = 0;
|
||||
std::int32_t roomDensityQ16 = 22938;
|
||||
std::int32_t tunnelDensityQ16 = 26214;
|
||||
std::int32_t roomShapeVarietyQ16 = 32768;
|
||||
std::int32_t roomHeightRatioQ16 = 55706;
|
||||
std::int32_t roomFloorCutMinimumQ16 = 45875;
|
||||
std::int32_t roomFloorCutMaximumQ16 = 58982;
|
||||
std::int32_t tunnelHorizontalBiasQ16 = 32768;
|
||||
std::int32_t originRoomMaximumConnections = 4;
|
||||
bool tunnelsFlowTowardOrigin = true;
|
||||
// Vertical Shafts uses this same planner and graph field. It binds its
|
||||
// incoming passage and resolves a bedrock terminal when no departure
|
||||
// mouth exists, then adds shaft records beside the walk-only backbone.
|
||||
bool verticalShaftMode = false;
|
||||
std::int64_t ledgeSpacingMicrometres = 8000000;
|
||||
std::int64_t ledgeDepthMicrometres = 1000000;
|
||||
};
|
||||
|
||||
// Immutable material-only deposits. The capsule and its conservative bounds are in
|
||||
// micrometres; bounds include irregularity and the blend envelope.
|
||||
struct ResolvedLayoutOreVeinRequestV1
|
||||
@@ -1211,7 +1284,8 @@ namespace VoxelForgeCore
|
||||
|
||||
inline bool IsNativeCaveFieldStratum(const ResolvedLayoutStratumV2& stratum) noexcept
|
||||
{
|
||||
return stratum.generatorKind=="Caves"
|
||||
return (stratum.generatorKind=="Caves"||stratum.generatorKind=="TunnelNetwork"
|
||||
||stratum.generatorKind=="VerticalShafts")
|
||||
&&stratum.recipeId=="Core.Caves.PrimitiveField"
|
||||
&&stratum.recipeVersion==1;
|
||||
}
|
||||
@@ -1252,6 +1326,16 @@ namespace VoxelForgeCore
|
||||
std::int64_t radiusSubvoxels = 0;
|
||||
};
|
||||
|
||||
struct ResolvedLayoutPassageLandingChamberV1
|
||||
{
|
||||
// The chamber floor plane passes through this point. Gradient is dz/dx,
|
||||
// dz/dy in Q16 so the chamber continues the passage's authored h(s) grade.
|
||||
std::array<std::int64_t, 3> floorCenterSubvoxels{};
|
||||
std::array<std::int64_t, 2> floorGradientQ16{};
|
||||
std::int64_t radiusSubvoxels = 0;
|
||||
std::int64_t clearHeightSubvoxels = 0;
|
||||
};
|
||||
|
||||
struct ResolvedLayoutPassageV1
|
||||
{
|
||||
std::string stableId;
|
||||
@@ -1266,6 +1350,12 @@ namespace VoxelForgeCore
|
||||
std::int64_t midRadiusSubvoxels = 0;
|
||||
// Derived from the mouth binding; the main descent is monotone through this point.
|
||||
std::size_t lowerMouthControlIndex = 0;
|
||||
ResolvedLayoutPassageLandingChamberV1 upperLandingChamber;
|
||||
ResolvedLayoutPassageLandingChamberV1 lowerLandingChamber;
|
||||
// When true, each control point's position.z - radius is the planned
|
||||
// floor h(s), and both chamber planes continue that same endpoint profile.
|
||||
// False preserves older resolved snapshots' runtime floor composition.
|
||||
bool floorProfileIncludesLandingChambers = false;
|
||||
std::vector<ResolvedLayoutPassagePointV1> controlPoints;
|
||||
};
|
||||
|
||||
@@ -1381,6 +1471,17 @@ namespace VoxelForgeCore
|
||||
std::span<const ResolvedCavernRoomV1> rooms,
|
||||
std::span<const ResolvedCavernEdgeV1> edges,
|
||||
std::string& error);
|
||||
// Build a deterministic, walkable room-and-tunnel graph between the two
|
||||
// passage mouths that terminate in strateIndex. Compound rooms are emitted
|
||||
// as overlapping room primitives; the route is planned below a 15 degree
|
||||
// walking grade and every corridor carries a 4.5 m vertical clearance.
|
||||
VFCORE_API bool PlanResolvedCavernNetworkV1(
|
||||
const ResolvedLayoutSnapshotV3& layout, std::int32_t seed,
|
||||
std::int32_t strateIndex,
|
||||
const ResolvedCavernPlannerSettingsV1& settings,
|
||||
std::vector<ResolvedCavernRoomV1>& rooms,
|
||||
std::vector<ResolvedCavernEdgeV1>& edges,
|
||||
std::string& error);
|
||||
VFCORE_API bool ResolveResolvedLayoutOreVeinsV1(
|
||||
ResolvedLayoutSnapshotV3& layout, std::int32_t seed,
|
||||
std::span<const ResolvedLayoutOreVeinRequestV1> requests,
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user