wip(assembler): M3 round 4 -- plans built inside Unreal from the owner's strates; no import needed

SurfaceWorld and FloatingIslands plans generate at startup from the resolved seed,
strate types and heights (hashed, cached). Imported JSON is an opt-in override (off by
default); an invalid override shows an on-screen notice and falls back to legacy.
BuildHost on staged owner assets: SurfaceWorld cross-system checks, islands at owner
height (route, collision, anchors, BP edits), seed 137501, W1/W8/W16, Core-off legacy.
XY-column cache verified (hashes kept); island LOD0 p95 91 ms vs 133 ms sprint deadline.
Not exercised: season-seed path (no Season in staged settings), rendered notice pixels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-10 22:48:46 +02:00
1 parent 48fa028086
commit 111cf3d262
21 files changed
+1934 -391

No files matched your search

+94 -59
View File
@@ -342,6 +342,11 @@ namespace world_assembly_detail
HashWord(hash, static_cast<std::uint32_t>(stratum.strateIndex), 4);
HashWord(hash, static_cast<std::uint32_t>(stratum.topChunkZ), 4);
HashWord(hash, static_cast<std::uint32_t>(stratum.bottomChunkZ), 4);
if (stratum.hasRecipeOverride)
{
HashWord(hash, 0x5354524154455250ull, 8);
HashWord(hash, HashRecipe(stratum.recipeOverride), 8);
}
HashWord(hash, static_cast<std::uint64_t>(stratum.capHeightSubvoxels), 8);
HashWord(hash, static_cast<std::uint64_t>(stratum.capUndulationSubvoxels), 8);
HashWord(hash, static_cast<std::uint64_t>(stratum.capWavelengthSubvoxels), 8);
@@ -554,6 +559,65 @@ namespace world_assembly_detail
return true;
}
inline std::string RecipeJson(const WorldAssemblyRecipeV1& recipe)
{
std::ostringstream out;
out << "{\"schema_version\":" << recipe.schemaVersion
<< ",\"evaluator_version\":" << recipe.evaluatorVersion
<< ",\"units_per_voxel\":" << recipe.unitsPerVoxel
<< ",\"seed\":" << recipe.seed
<< ",\"biome_cell_size_q\":" << recipe.biomeCellSizeSubvoxels
<< ",\"biome_warp_q\":" << recipe.biomeWarpSubvoxels
<< ",\"biome_warp_wavelength_q\":" << recipe.biomeWarpWavelengthSubvoxels
<< ",\"biome_border_blend_q\":" << recipe.biomeBorderBlendSubvoxels;
if (recipe.evaluatorVersion >= 2)
out << ",\"climate_relief_wavelength_q\":" << recipe.biomeClimateReliefWavelengthSubvoxels
<< ",\"climate_moisture_wavelength_q\":" << recipe.biomeClimateMoistureWavelengthSubvoxels
<< ",\"climate_relief_contrast_q16\":" << recipe.biomeClimateReliefContrastQ16;
out << ",\"content_hash\":\"" << HashText(recipe.contentHash) << "\",\"biomes\":[";
for (std::size_t i = 0; i < recipe.biomes.size(); ++i)
{
const auto& biome = recipe.biomes[i];
if (i) out << ',';
out << "{\"id\":" << biome.stableId << ",\"base_height_q\":" << biome.baseHeightSubvoxels
<< ",\"continent_amplitude_q\":" << biome.continentAmplitudeSubvoxels
<< ",\"continent_wavelength_q\":" << biome.continentWavelengthSubvoxels
<< ",\"mountain_amplitude_q\":" << biome.mountainAmplitudeSubvoxels
<< ",\"mountain_wavelength_q\":" << biome.mountainWavelengthSubvoxels
<< ",\"detail_amplitude_q\":" << biome.detailAmplitudeSubvoxels
<< ",\"detail_wavelength_q\":" << biome.detailWavelengthSubvoxels;
if (recipe.evaluatorVersion >= 2)
out << ",\"relief_min_q16\":" << biome.reliefMinimumQ16
<< ",\"relief_max_q16\":" << biome.reliefMaximumQ16
<< ",\"moisture_min_q16\":" << biome.moistureMinimumQ16
<< ",\"moisture_max_q16\":" << biome.moistureMaximumQ16
<< ",\"relief_strength_q16\":" << biome.reliefStrengthQ16
<< ",\"relief_contrast_q16\":" << biome.reliefContrastQ16
<< ",\"relief_wavelength_q\":" << biome.reliefWavelengthSubvoxels
<< ",\"height_warp_strength_q\":" << biome.heightWarpStrengthSubvoxels
<< ",\"height_warp_wavelength_q\":" << biome.heightWarpWavelengthSubvoxels
<< ",\"beach_width_q\":" << biome.beachWidthSubvoxels
<< ",\"cliff_strength_q16\":" << biome.cliffStrengthQ16
<< ",\"cliff_slope_threshold_q16\":" << biome.cliffSlopeThresholdQ16
<< ",\"cliff_sharpness_q16\":" << biome.cliffSharpnessQ16
<< ",\"cliff_sample_distance_q\":" << biome.cliffSampleDistanceSubvoxels
<< ",\"cliff_max_displacement_q\":" << biome.cliffMaximumDisplacementSubvoxels
<< ",\"cap_enabled\":" << (biome.hasCapProfile ? "true" : "false")
<< ",\"cap_height_q\":" << biome.capHeightSubvoxels
<< ",\"cap_warp_strength_q\":" << biome.capWarpStrengthSubvoxels
<< ",\"cap_warp_wavelength_q\":" << biome.capWarpWavelengthSubvoxels
<< ",\"cap_undulation_q\":" << biome.capUndulationSubvoxels
<< ",\"cap_wavelength_q\":" << biome.capWavelengthSubvoxels
<< ",\"cap_detail_amplitude_q\":" << biome.capDetailAmplitudeSubvoxels
<< ",\"cap_detail_wavelength_q\":" << biome.capDetailWavelengthSubvoxels
<< ",\"cap_ridge_amplitude_q\":" << biome.capRidgeAmplitudeSubvoxels
<< ",\"cap_ridge_wavelength_q\":" << biome.capRidgeWavelengthSubvoxels;
out << '}';
}
out << "]}";
return out.str();
}
inline bool ParsePlan(const VFJson::Value& value, WorldAssemblyPlanV1& plan,
std::string& error)
{
@@ -573,6 +637,12 @@ namespace world_assembly_detail
|| !ReadHash(item.Get("content_hash"), stratum.contentHash)
|| !item.Get("features").IsArray() || !item.Get("route").IsArray())
{ error = "world assembly stratum is missing a required fixed-scale field"; return false; }
const VFJson::Value& recipeOverrideValue = item.Get("recipe_override");
if (!std::holds_alternative<std::nullptr_t>(recipeOverrideValue.Data))
{
if (!ParseRecipe(recipeOverrideValue, stratum.recipeOverride, error)) return false;
stratum.hasRecipeOverride = true;
}
const auto readOptional = [&item](const char* name, std::int64_t& output)
{
const VFJson::Value& field = item.Get(name);
@@ -1402,6 +1472,13 @@ bool WorldAssemblyManifest::finalize(std::string& error)
std::vector<std::int32_t> strateIds;
for (auto& stratum : plan.strates)
{
if (stratum.hasRecipeOverride)
{
if (!world_assembly_detail::ValidateRecipe(stratum.recipeOverride, error)) return false;
if (stratum.recipeOverride.seed != recipe.seed)
{ 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 (recipe.evaluatorVersion >= 4)
{
@@ -1460,16 +1537,25 @@ bool WorldAssemblyManifest::validate(std::string& error) const
const std::uint64_t expectedPlan = plan.contentHash;
const std::uint64_t expectedManifest = contentHash;
std::vector<std::uint64_t> expectedStrates;
for (const auto& stratum : plan.strates) expectedStrates.push_back(stratum.contentHash);
std::vector<std::uint64_t> expectedStratumRecipes;
for (const auto& stratum : plan.strates)
{
expectedStrates.push_back(stratum.contentHash);
expectedStratumRecipes.push_back(stratum.hasRecipeOverride
? stratum.recipeOverride.contentHash : 0);
}
std::vector<std::uint64_t> expectedIslandManifests;
for (const auto& islands : floatingIslands) expectedIslandManifests.push_back(islands.manifest.contentHash);
if (!copy.finalize(error)) return false;
if (expectedRecipe != copy.recipe.contentHash || expectedPlan != copy.plan.contentHash
|| expectedManifest != copy.contentHash || expectedStrates.size() != copy.plan.strates.size()
|| expectedStratumRecipes.size() != copy.plan.strates.size()
|| expectedIslandManifests.size() != copy.floatingIslands.size())
{ error = "world assembly recipe, plan or manifest content hash does not match its fields"; return false; }
for (std::size_t i = 0; i < expectedStrates.size(); ++i)
if (expectedStrates[i] != copy.plan.strates[i].contentHash)
if (expectedStrates[i] != copy.plan.strates[i].contentHash
|| expectedStratumRecipes[i] != (copy.plan.strates[i].hasRecipeOverride
? copy.plan.strates[i].recipeOverride.contentHash : 0))
{ error = "world assembly stratum content hash does not match its fields"; return false; }
for (std::size_t i = 0; i < expectedIslandManifests.size(); ++i)
if (expectedIslandManifests[i] != copy.floatingIslands[i].manifest.contentHash)
@@ -1485,62 +1571,8 @@ std::string WorldAssemblyManifest::ToJson() const
std::ostringstream out;
out << "{\"schema_version\":" << value.schemaVersion
<< ",\"content_hash\":\"" << world_assembly_detail::HashText(value.contentHash)
<< "\",\"recipe\":{\"schema_version\":" << value.recipe.schemaVersion
<< ",\"evaluator_version\":" << value.recipe.evaluatorVersion
<< ",\"units_per_voxel\":" << value.recipe.unitsPerVoxel
<< ",\"seed\":" << value.recipe.seed
<< ",\"biome_cell_size_q\":" << value.recipe.biomeCellSizeSubvoxels
<< ",\"biome_warp_q\":" << value.recipe.biomeWarpSubvoxels
<< ",\"biome_warp_wavelength_q\":" << value.recipe.biomeWarpWavelengthSubvoxels
<< ",\"biome_border_blend_q\":" << value.recipe.biomeBorderBlendSubvoxels
;
if (value.recipe.evaluatorVersion >= 2)
out << ",\"climate_relief_wavelength_q\":" << value.recipe.biomeClimateReliefWavelengthSubvoxels
<< ",\"climate_moisture_wavelength_q\":" << value.recipe.biomeClimateMoistureWavelengthSubvoxels
<< ",\"climate_relief_contrast_q16\":" << value.recipe.biomeClimateReliefContrastQ16;
out
<< ",\"content_hash\":\"" << world_assembly_detail::HashText(value.recipe.contentHash)
<< "\",\"biomes\":[";
for (std::size_t i = 0; i < value.recipe.biomes.size(); ++i)
{
const auto& biome = value.recipe.biomes[i];
if (i) out << ',';
out << "{\"id\":" << biome.stableId << ",\"base_height_q\":" << biome.baseHeightSubvoxels
<< ",\"continent_amplitude_q\":" << biome.continentAmplitudeSubvoxels
<< ",\"continent_wavelength_q\":" << biome.continentWavelengthSubvoxels
<< ",\"mountain_amplitude_q\":" << biome.mountainAmplitudeSubvoxels
<< ",\"mountain_wavelength_q\":" << biome.mountainWavelengthSubvoxels
<< ",\"detail_amplitude_q\":" << biome.detailAmplitudeSubvoxels
<< ",\"detail_wavelength_q\":" << biome.detailWavelengthSubvoxels;
if (value.recipe.evaluatorVersion >= 2)
out << ",\"relief_min_q16\":" << biome.reliefMinimumQ16
<< ",\"relief_max_q16\":" << biome.reliefMaximumQ16
<< ",\"moisture_min_q16\":" << biome.moistureMinimumQ16
<< ",\"moisture_max_q16\":" << biome.moistureMaximumQ16
<< ",\"relief_strength_q16\":" << biome.reliefStrengthQ16
<< ",\"relief_contrast_q16\":" << biome.reliefContrastQ16
<< ",\"relief_wavelength_q\":" << biome.reliefWavelengthSubvoxels
<< ",\"height_warp_strength_q\":" << biome.heightWarpStrengthSubvoxels
<< ",\"height_warp_wavelength_q\":" << biome.heightWarpWavelengthSubvoxels
<< ",\"beach_width_q\":" << biome.beachWidthSubvoxels
<< ",\"cliff_strength_q16\":" << biome.cliffStrengthQ16
<< ",\"cliff_slope_threshold_q16\":" << biome.cliffSlopeThresholdQ16
<< ",\"cliff_sharpness_q16\":" << biome.cliffSharpnessQ16
<< ",\"cliff_sample_distance_q\":" << biome.cliffSampleDistanceSubvoxels
<< ",\"cliff_max_displacement_q\":" << biome.cliffMaximumDisplacementSubvoxels
<< ",\"cap_enabled\":" << (biome.hasCapProfile ? "true" : "false")
<< ",\"cap_height_q\":" << biome.capHeightSubvoxels
<< ",\"cap_warp_strength_q\":" << biome.capWarpStrengthSubvoxels
<< ",\"cap_warp_wavelength_q\":" << biome.capWarpWavelengthSubvoxels
<< ",\"cap_undulation_q\":" << biome.capUndulationSubvoxels
<< ",\"cap_wavelength_q\":" << biome.capWavelengthSubvoxels
<< ",\"cap_detail_amplitude_q\":" << biome.capDetailAmplitudeSubvoxels
<< ",\"cap_detail_wavelength_q\":" << biome.capDetailWavelengthSubvoxels
<< ",\"cap_ridge_amplitude_q\":" << biome.capRidgeAmplitudeSubvoxels
<< ",\"cap_ridge_wavelength_q\":" << biome.capRidgeWavelengthSubvoxels;
out << '}';
}
out << "]},\"plan\":{\"schema_version\":" << value.plan.schemaVersion
<< "\",\"recipe\":" << world_assembly_detail::RecipeJson(value.recipe)
<< ",\"plan\":{\"schema_version\":" << value.plan.schemaVersion
<< ",\"content_hash\":\"" << world_assembly_detail::HashText(value.plan.contentHash)
<< "\",\"strates\":[";
for (std::size_t i = 0; i < value.plan.strates.size(); ++i)
@@ -1563,6 +1595,9 @@ std::string WorldAssemblyManifest::ToJson() const
<< ",\"cap_ridge_wavelength_q\":" << stratum.capRidgeWavelengthSubvoxels
<< ",\"water_surface_q\":" << stratum.waterSurfaceSubvoxels
<< ",\"water_enabled\":" << (stratum.waterEnabled ? "true" : "false");
if (stratum.hasRecipeOverride)
out << ",\"recipe_override\":"
<< world_assembly_detail::RecipeJson(stratum.recipeOverride);
out
<< ",\"content_hash\":\"" << world_assembly_detail::HashText(stratum.contentHash)
<< "\",\"features\":[";
@@ -1626,7 +1661,7 @@ std::string WorldAssemblyManifest::ToJson() const
Heightfield2D::Heightfield2D(const WorldAssemblyRecipeV1& recipe,
const WorldAssemblyStratumPlanV1& plan) noexcept
: recipe_(&recipe), plan_(&plan)
: recipe_(plan.hasRecipeOverride ? &plan.recipeOverride : &recipe), plan_(&plan)
{}
bool Heightfield2D::isValid() const noexcept