wip(assembler): round L22 -- one 8 m layout chunk for every strate; real ceiling -> content -> bedrock

StrateLayoutChunkSizeMeters (world setting, default 8 m; owner decision) is resolved once in
the director/adapter and standalone loader; every generator reads the resolved width (no
CHUNK_SIZE / Core-tile inference). Every strate gets solid ceiling and bedrock bands from its
BoundarySealThickness in the shared composition path (diggable by default); faces come from the
shared boundary path. Owner world: FloatingIslands +8..-120 m (128 m, now with a bedrock floor),
SurfaceWorld -120..-632 m (unchanged; full-detail and exact-query hashes equal L21); the 60 m gap is
gone. The strict layout validator passes on the real world, with 0 endpoint dispatch
disagreements. Spawn/benchmark camera derived from route.front. Ledges under the islands gone
(reviewer capture). Evaluator 7, recipe schema 2, layout snapshot 2, FI geometry 4.
Open: SW cap profiles exceed the ceiling band (owner call); transitions still Hard; Unreal
setting/manager/adapter edits uncompiled here.

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 12:03:14 +02:00
1 parent 8753f6dbe4
commit 55c26a05a7
28 files changed
+1432 -579

No files matched your search

+25 -19
View File
@@ -235,6 +235,9 @@ namespace world_assembly_detail
|| recipe.evaluatorVersion > WorldAssemblyEvaluatorVersion
|| recipe.unitsPerVoxel != WorldAssemblySubvoxelsPerVoxel)
{ error = "world assembly recipe version, evaluator or fixed scale is unsupported"; return false; }
if (recipe.layoutChunkWidthSubvoxels <= 0
|| recipe.layoutChunkWidthSubvoxels > 256ll * 512ll)
{ error = "resolved strate-layout chunk width is outside the supported physical range"; return false; }
if (recipe.biomes.empty() || recipe.biomes.size() > MaxBiomeCount)
{ error = "world assembly recipe must contain one to eight biome profiles"; return false; }
if (recipe.biomeCellSizeSubvoxels <= 0 || recipe.biomeCellSizeSubvoxels > 100000000ll
@@ -296,7 +299,8 @@ namespace world_assembly_detail
return true;
}
inline bool ValidateStratum(const WorldAssemblyStratumPlanV1& stratum, std::string& error)
inline bool ValidateStratum(const WorldAssemblyStratumPlanV1& stratum,
std::int64_t layoutChunkWidthSubvoxels, std::string& error)
{
if (stratum.strateIndex < 0 || stratum.topChunkZ < stratum.bottomChunkZ
|| stratum.capWavelengthSubvoxels <= 0 || stratum.capUndulationSubvoxels < 0
@@ -330,9 +334,9 @@ namespace world_assembly_detail
if (feature.type == 2 || feature.type == 4)
{
const std::int64_t stratumMinZ = static_cast<std::int64_t>(stratum.bottomChunkZ)
* 32 * WorldAssemblySubvoxelsPerVoxel;
* layoutChunkWidthSubvoxels;
const std::int64_t stratumMaxZ = (static_cast<std::int64_t>(stratum.topChunkZ) + 1)
* 32 * WorldAssemblySubvoxelsPerVoxel;
* layoutChunkWidthSubvoxels;
constexpr std::int64_t maximumExceptionExtent = 1024
* WorldAssemblySubvoxelsPerVoxel;
for (std::size_t axis = 0; axis < 3; ++axis)
@@ -420,6 +424,7 @@ namespace world_assembly_detail
std::uint64_t hash = StartHash();
HashWord(hash, recipe.schemaVersion, 4); HashWord(hash, recipe.evaluatorVersion, 4);
HashWord(hash, recipe.unitsPerVoxel, 4); HashWord(hash, recipe.seed, 4);
HashWord(hash, static_cast<std::uint64_t>(recipe.layoutChunkWidthSubvoxels), 8);
HashWord(hash, static_cast<std::uint64_t>(recipe.biomeCellSizeSubvoxels), 8);
HashWord(hash, static_cast<std::uint64_t>(recipe.biomeWarpSubvoxels), 8);
HashWord(hash, static_cast<std::uint64_t>(recipe.biomeWarpWavelengthSubvoxels), 8);
@@ -628,6 +633,7 @@ namespace world_assembly_detail
if (!value.IsObject() || !ReadU32(value.Get("schema_version"), recipe.schemaVersion)
|| !ReadU32(value.Get("evaluator_version"), recipe.evaluatorVersion)
|| !ReadU32(value.Get("units_per_voxel"), recipe.unitsPerVoxel)
|| !ReadInteger(value.Get("layout_chunk_width_q"), recipe.layoutChunkWidthSubvoxels)
|| !ReadU32(value.Get("seed"), recipe.seed)
|| !ReadInteger(value.Get("biome_cell_size_q"), recipe.biomeCellSizeSubvoxels)
|| !ReadInteger(value.Get("biome_warp_q"), recipe.biomeWarpSubvoxels)
@@ -693,6 +699,7 @@ namespace world_assembly_detail
out << "{\"schema_version\":" << recipe.schemaVersion
<< ",\"evaluator_version\":" << recipe.evaluatorVersion
<< ",\"units_per_voxel\":" << recipe.unitsPerVoxel
<< ",\"layout_chunk_width_q\":" << recipe.layoutChunkWidthSubvoxels
<< ",\"seed\":" << recipe.seed
<< ",\"biome_cell_size_q\":" << recipe.biomeCellSizeSubvoxels
<< ",\"biome_warp_q\":" << recipe.biomeWarpSubvoxels
@@ -861,7 +868,8 @@ namespace world_assembly_detail
|| !ReadI32(islandValue.Get("bottom_chunk_z"), entry.bottomChunkZ))
{ error = "world assembly floating-island slot is missing its resolved strate bounds"; return std::nullopt; }
const std::string nestedJson = JsonText(islandValue.Get("manifest"));
auto parsedIsland = FloatingIslandManifestV1::FromJson(nestedJson, error);
auto parsedIsland = FloatingIslandManifestV1::FromJson(
nestedJson, error, manifest.recipe.layoutChunkWidthSubvoxels);
if (!parsedIsland) return std::nullopt;
entry.manifest = std::move(*parsedIsland);
manifest.floatingIslands.push_back(std::move(entry));
@@ -1751,15 +1759,15 @@ bool WorldAssemblyManifest::finalize(std::string& error)
{ error = "SurfaceWorld stratum recipe seed does not match the world assembly season seed"; return false; }
stratum.recipeOverride.contentHash = world_assembly_detail::HashRecipe(stratum.recipeOverride);
}
if (!world_assembly_detail::ValidateStratum(stratum, error)) return false;
if (!world_assembly_detail::ValidateStratum(stratum, recipe.layoutChunkWidthSubvoxels, error)) return false;
if (recipe.evaluatorVersion >= 4)
{
if (stratum.routeConstraints.version != 1 || stratum.route.size() < 2)
{ error = "world assembly evaluator 4 requires a versioned entrance-to-exit route"; return false; }
const std::int64_t bottomZ = static_cast<std::int64_t>(stratum.bottomChunkZ)
* 32 * WorldAssemblySubvoxelsPerVoxel;
* recipe.layoutChunkWidthSubvoxels;
const std::int64_t topZ = (static_cast<std::int64_t>(stratum.topChunkZ) + 1)
* 32 * WorldAssemblySubvoxelsPerVoxel;
* recipe.layoutChunkWidthSubvoxels;
const std::int64_t halfHeight = stratum.routeConstraints.capsuleHeightSubvoxels / 2;
for (const auto& point : stratum.route)
{
@@ -1789,14 +1797,12 @@ bool WorldAssemblyManifest::finalize(std::string& error)
const auto& Scale = islands.manifest.recipe;
if (Scale.ownerToCoreScaleNumerator == 0 || Scale.ownerToCoreScaleDenominator == 0)
{ error = "floating-island owner-to-Core scale is invalid"; return false; }
const double CoreVoxelsPerOwnerChunk = static_cast<double>(CoreTileVoxelCount)
* Scale.ownerToCoreScaleNumerator / Scale.ownerToCoreScaleDenominator;
const std::int64_t bottomQ = static_cast<std::int64_t>(std::llround(
static_cast<double>(islands.bottomChunkZ) * CoreVoxelsPerOwnerChunk
* WorldAssemblySubvoxelsPerVoxel));
const std::int64_t topQ = static_cast<std::int64_t>(std::llround(
static_cast<double>(static_cast<std::int64_t>(islands.topChunkZ) + 1)
* CoreVoxelsPerOwnerChunk * WorldAssemblySubvoxelsPerVoxel));
if(Scale.layoutChunkWidthSubvoxels<=0)
{error="floating-island strate has no resolved layout chunk width";return false;}
const std::int64_t bottomQ = static_cast<std::int64_t>(islands.bottomChunkZ)
*Scale.layoutChunkWidthSubvoxels;
const std::int64_t topQ = (static_cast<std::int64_t>(islands.topChunkZ)+1)
*Scale.layoutChunkWidthSubvoxels;
if (islands.manifest.recipe.layoutMinimumZSubvoxels < bottomQ
|| islands.manifest.recipe.layoutMaximumZSubvoxels > topQ)
{ error = "floating-island recipe layout escapes the resolved owner strate bounds"; return false; }
@@ -2000,7 +2006,7 @@ std::array<std::int64_t,2> Heightfield2D::capHeightBounds() const noexcept
if(recipe_->evaluatorVersion>=5)
{
const long double TopSubvoxels=(static_cast<long double>(plan_->topChunkZ)+1.0L)
*CoreTileVoxelCount*WorldAssemblySubvoxelsPerVoxel;
*recipe_->layoutChunkWidthSubvoxels;
Minimum=std::min(Minimum,TopSubvoxels);
Maximum=std::min(Maximum,TopSubvoxels);
}
@@ -2019,7 +2025,7 @@ std::int64_t Heightfield2D::farSurfaceCapHeightSubvoxels(std::int64_t x,
// Clip only the far render surface. Keep the near density evaluator bit-identical.
// Borner uniquement le plafond lointain. L'evaluateur de densite proche reste identique.
const std::int64_t ownedUpperBoundary=(static_cast<std::int64_t>(plan_->topChunkZ)+1)
*CoreTileVoxelCount*WorldAssemblySubvoxelsPerVoxel;
*recipe_->layoutChunkWidthSubvoxels;
return std::min(column.capHeightSubvoxels,ownedUpperBoundary);
}
@@ -2298,8 +2304,8 @@ FieldInfluenceBounds Heightfield2D::influenceBounds() const noexcept
{
FieldInfluenceBounds out;
if (!isValid()) return out;
out.minimumZSubvoxels = static_cast<std::int64_t>(plan_->bottomChunkZ) * 32 * WorldAssemblySubvoxelsPerVoxel;
out.maximumZSubvoxels = (static_cast<std::int64_t>(plan_->topChunkZ) + 1) * 32 * WorldAssemblySubvoxelsPerVoxel;
out.minimumZSubvoxels = static_cast<std::int64_t>(plan_->bottomChunkZ) * recipe_->layoutChunkWidthSubvoxels;
out.maximumZSubvoxels = (static_cast<std::int64_t>(plan_->topChunkZ) + 1) * recipe_->layoutChunkWidthSubvoxels;
return out;
}