wip(assembler): round L24 -- per-strate passage styles; natural Worm default; FI anchor island

Core plans inter-strate passages from each upper strate's FStratePassageConfig for every
generator: Straight / Worm (the new natural default: meander, variable radius, rough walls) /
Spiral / Cascading. A naturalness audit (no >8 m flat runs, >=0.20 m wall relief) fails on L23's
smooth tube. FloatingIslands selects Spiral, with a deterministic unique anchor island (ordinal 2)
joined to the bedrock floor by a rock root. The SW arrival no longer stamps flat shelves.
Capsule audits 0 blocked / 0 unsupported / 0 grade failures, all styles. Full-view hashes
deterministic W1/W8/W12, Clang = GCC (reviewer re-run). Evaluator 10, FI geometry 5.
KNOWN: the FI helix renders as a spiral ribbon in open air around the pillar instead of a tunnel
enclosed in rock; fix next round. Unreal edits uncompiled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-20 21:42:21 +02:00
1 parent 71d09a8c52
commit cb9236c265
17 files changed
+922 -122

No files matched your search

@@ -479,12 +479,13 @@ bool BuildFloatingIslandStratumPlan(const UVoxelStrateManager* StrateManager,
using namespace VoxelForgeCore;
const FIntVector Chunk(0, 0, Slot.TopChunkZ);
const FFloatingIslandParams Params = StrateManager->GetFloatingIslandParamsForChunk(Chunk);
const FStratePassageConfig& Passage = Slot.Definition->PassageConfig;
WorldAssemblyFloatingIslandPlanV1 IslandPlan;
IslandPlan.strateIndex = Slot.StrateIndex;
IslandPlan.topChunkZ = Slot.TopChunkZ;
IslandPlan.bottomChunkZ = Slot.BottomChunkZ;
auto& Recipe = IslandPlan.manifest.recipe;
Recipe.geometryVersion = 4;
Recipe.geometryVersion = 5;
Recipe.layoutChunkWidthSubvoxels = LayoutChunkWidthSubvoxels;
Recipe.seed = static_cast<std::uint32_t>(StrateManager->GetWorldSeed());
Recipe.ownerVoxelSizeMicrons = static_cast<std::uint32_t>(std::llround(OwnerVoxelSizeCm * 10000.0));
@@ -516,6 +517,28 @@ bool BuildFloatingIslandStratumPlan(const UVoxelStrateManager* StrateManager,
Recipe.roughnessSubvoxels = WorldAssemblyFixed(Params.SurfaceRoughness * OwnerToCoreScale);
Recipe.blendRadiusSubvoxels = WorldAssemblyFixed(Params.SDFBlendRadius * OwnerToCoreScale);
Recipe.boundarySealSubvoxels = WorldAssemblyFixed(Params.BoundarySealThickness * OwnerToCoreScale);
const auto OwnerVoxelsToCoreQ=[&](double Value)
{
return static_cast<std::int64_t>(std::llround(Value*Recipe.ownerVoxelSizeMicrons
*WorldAssemblySubvoxelsPerVoxel/Recipe.coreVoxelSizeMicrons));
};
Recipe.anchorIslandOrdinal=Recipe.primaryIslandCount-1;
Recipe.anchorPlacementRadiusSubvoxels=OwnerVoxelsToCoreQ(Passage.DistanceMax);
const std::int64_t spiralRadius=OwnerVoxelsToCoreQ(Passage.SpiralRadius);
// Reserve at least a 1.5 m mid-bore through the anchor root.
constexpr double AnchorPassageMinimumBoreOwnerVoxels=12.0;
const std::int64_t mouthBore=std::max(OwnerVoxelsToCoreQ(Passage.MouthRadius),
OwnerVoxelsToCoreQ(12.0));
const std::int64_t bore=std::max(OwnerVoxelsToCoreQ(Passage.MidRadius),
OwnerVoxelsToCoreQ(AnchorPassageMinimumBoreOwnerVoxels));
const std::int64_t wallReserve=OwnerVoxelsToCoreQ(12.0);
Recipe.anchorMouthOffsetSubvoxels=spiralRadius+mouthBore+OwnerVoxelsToCoreQ(4.0);
const std::int64_t excursion=std::max(OwnerVoxelsToCoreQ(Passage.Wander),spiralRadius);
Recipe.anchorRootRadiusSubvoxels=excursion+bore+wallReserve;
Recipe.anchorIslandMinimumRadiusSubvoxels=std::max(Recipe.minimumRadiusSubvoxels,
Recipe.anchorMouthOffsetSubvoxels+mouthBore+OwnerVoxelsToCoreQ(4.0));
Recipe.anchorRootBottomZSubvoxels=Recipe.layoutMinimumZSubvoxels
+Recipe.boundarySealSubvoxels;
std::string PlanError;
const std::optional<FloatingIslandManifestV1> Planned = PlanFloatingIslandCluster(Recipe, PlanError);
if (!Planned)
@@ -1042,13 +1065,23 @@ bool AttachValidatedWorldAssembly(const UVoxelSettings* Settings,
VoxelForgeCore::ResolvedLayoutPassageConfigV1 PassageConfig;
PassageConfig.upperStrateIndex = Slot.StrateIndex;
PassageConfig.connections = AuthoredPassage.Connections;
PassageConfig.mouthRadiusSubvoxels = OwnerVoxelsToCoreQ(AuthoredPassage.MouthRadius);
PassageConfig.midRadiusSubvoxels = OwnerVoxelsToCoreQ(AuthoredPassage.MidRadius);
PassageConfig.style = static_cast<std::uint32_t>(AuthoredPassage.Style);
PassageConfig.mouthRadiusSubvoxels = std::max(OwnerVoxelsToCoreQ(AuthoredPassage.MouthRadius),
OwnerVoxelsToCoreQ(12.0));
PassageConfig.midRadiusSubvoxels = std::max(OwnerVoxelsToCoreQ(AuthoredPassage.MidRadius),
OwnerVoxelsToCoreQ(12.0));
PassageConfig.reachMinimumSubvoxels = OwnerVoxelsToCoreQ(AuthoredPassage.ReachMin);
PassageConfig.reachMaximumSubvoxels = OwnerVoxelsToCoreQ(AuthoredPassage.ReachMax);
PassageConfig.distanceMinimumSubvoxels = OwnerVoxelsToCoreQ(AuthoredPassage.DistanceMin);
PassageConfig.distanceMaximumSubvoxels = OwnerVoxelsToCoreQ(AuthoredPassage.DistanceMax);
PassageConfig.wanderSubvoxels = OwnerVoxelsToCoreQ(AuthoredPassage.Wander);
PassageConfig.segments = static_cast<std::uint32_t>(FMath::Clamp(AuthoredPassage.Segments,1,48));
PassageConfig.verticalWobbleSubvoxels = OwnerVoxelsToCoreQ(AuthoredPassage.VerticalWobble);
PassageConfig.spiralRadiusSubvoxels = OwnerVoxelsToCoreQ(AuthoredPassage.SpiralRadius);
PassageConfig.spiralTurnsQ16 = static_cast<std::int64_t>(std::llround(
static_cast<double>(AuthoredPassage.SpiralTurns)*65536.0));
PassageConfig.cascadeSteps = static_cast<std::uint32_t>(FMath::Clamp(AuthoredPassage.CascadeSteps,1,16));
PassageConfig.cascadeLedgeSubvoxels = OwnerVoxelsToCoreQ(AuthoredPassage.CascadeLedge);
PassageConfigs.push_back(PassageConfig);
const ECaveGeneratorType Type = StrateManager->GetGeneratorTypeForChunk(
FIntVector(0, 0, Slot.TopChunkZ));
@@ -1134,6 +1167,21 @@ bool AttachValidatedWorldAssembly(const UVoxelSettings* Settings,
Anchor.values = { Island.centerSubvoxels[0], Island.centerSubvoxels[1],
Island.centerSubvoxels[2], Island.radiusSubvoxels, Island.topHalfSubvoxels };
Item.anchors.push_back(std::move(Anchor));
if(IslandIndex==Plan->manifest.recipe.anchorIslandOrdinal
&&Plan->manifest.recipe.geometryVersion>=5)
{
VoxelForgeCore::ResolvedLayoutAnchorV2 PassageAnchor;
PassageAnchor.kind="passage_anchor";
PassageAnchor.stableId="passage-anchor/island/"+std::to_string(IslandIndex);
PassageAnchor.units="1/256 Core voxel";
PassageAnchor.values={Island.centerSubvoxels[0],Island.centerSubvoxels[1],
Plan->manifest.recipe.anchorRootRadiusSubvoxels,
Plan->manifest.recipe.anchorMouthOffsetSubvoxels,
Plan->manifest.recipe.anchorPlacementRadiusSubvoxels,
Plan->manifest.recipe.anchorRootBottomZSubvoxels,
Island.radiusSubvoxels};
Item.anchors.push_back(std::move(PassageAnchor));
}
}
for (std::size_t RouteIndex = 0; RouteIndex < Plan->manifest.plan.route.size(); ++RouteIndex)
{
+7 -11
View File
@@ -1852,8 +1852,6 @@ struct VOXELFORGE_API FStrateDisturbanceParams
UENUM(BlueprintType)
enum class EVoxelPassageStyle : uint8
{
// “Straight” is retained as the authored style name for the base connection, but its runtime
// geometry is a gentle two-leg switchback rather than a vertical shaft.
Straight UMETA(DisplayName = "Straight (walkable sloped tunnel)"),
Worm UMETA(DisplayName = "Worm (organic meander around the axis)"),
Spiral UMETA(DisplayName = "Spiral (corkscrew descent)"),
@@ -1878,14 +1876,12 @@ struct VOXELFORGE_API FStratePassageConfig
// Tunnel shape.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Passage")
EVoxelPassageStyle Style = EVoxelPassageStyle::Straight;
EVoxelPassageStyle Style = EVoxelPassageStyle::Worm;
// ----- WIDTH (tapers along the length) -----
// Radius at the two mouths (entry/exit) and at the middle. Equal = uniform tube;
// The walkable default is 1.5x the original comfortable profile: 2.25 m diameter at mouths
// and 1.875 m at the waist when the stored radii remain 9/7.5 voxels at 12.5 cm per voxel.
// Double these asset values to retain the previous 4.5/3.75 m dimensions. The §6.5 landing
// room remains wider for turning.
// Core raises both radii to at least 12 owner voxels (1.5 m) for capsule clearance.
// The passage landing remains wider for turning.
// Mouth > Mid = chambers at the ends with a squeeze between; Mid > Mouth = a bulge.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Passage|Width", meta = (ClampMin = "1.0"))
float MouthRadius = 9.0f;
@@ -1912,8 +1908,8 @@ struct VOXELFORGE_API FStratePassageConfig
float DistanceMax = 192.0f;
// ----- SHAPE detail -----
// Exotic styles only: max sideways excursion from the axis (voxels). 24 = 6 m; 0 = straight
// even in Worm style. The default walkable switchback does not use this wander value.
// Max sideways variation from the winding path's axis (voxels). Core keeps the route inside
// DistanceMax and adds enough distance to meet the walkable grade.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Passage|Shape", meta = (ClampMin = "0.0"))
float Wander = 24.0f;
@@ -1926,8 +1922,8 @@ struct VOXELFORGE_API FStratePassageConfig
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Passage|Shape", meta = (ClampMin = "0.0"))
float VerticalWobble = 0.0f;
// Spiral style: helix radius (voxels) and number of full turns over the descent. The default
// radius is 6 m.
// Spiral style: helix radius (voxels) and minimum number of turns. Core adds turns when
// needed to meet the walkable grade. The default stored radius is 3 m at the legacy scale.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Passage|Spiral", meta = (ClampMin = "1.0"))
float SpiralRadius = 24.0f;