parity: Unreal and headless resolve the same four-strate plan (L70, v214)

- Export commandlet writes the live Core adapter's world_assembly + resolved layout pair;
  the headless owner path imports that pair (manifest/layout equal, layout_chunk_width_q
  validated). owner_world.json re-exported from the owner's staged assets on the Linux host.
- Adapter SW route: Core clearance/radius floors, 0.5 m support search, outward-facing
  tie-break; passage mouth/mid radius floors match Core (36/24 owner voxels).
- FI in Unreal now uses the legacy (compiled analytic) generator unless a plan is imported:
  the auto native-FI plan failed the passage audit on the owner plan (1843 blocked samples,
  945 open-air violations). Owner decides whether native FI returns.
- In-engine spawn traces per strate (3 each): SW GenerateTile 42.7 worker-s vs 20.1 headless
  for equal tile counts; LOD0 p95 45-169 ms in UE.
- Fast tier green; all three passages pass on the shared plan.

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-10-27 06:22:48 +01:00
1 parent 81e2452a3d
commit bd68aee1ca
16 files changed
+939 -62

No files matched your search

@@ -2502,23 +2502,6 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t
{bestAlignment=alignment;phase=candidate;}
}
}
if(hasUpperRoute&&upperIsSurfaceWorld)
{
const auto& directionAtPhase=directions[phase];
const std::int64_t radialAlignment=upperMouth[0]*directionAtPhase[0]
+upperMouth[1]*directionAtPhase[1];
if(radialAlignment<0)
{
std::int64_t bestOutwardAlignment=std::numeric_limits<std::int64_t>::min();
for(std::uint32_t candidate=0;candidate<directions.size();++candidate)
{
const std::int64_t alignment=upperMouth[0]*directions[candidate][0]
+upperMouth[1]*directions[candidate][1];
if(alignment>bestOutwardAlignment)
{bestOutwardAlignment=alignment;phase=candidate;}
}
}
}
bool clockwise=(PassageSeed(seed,upper.strateIndex,lower.strateIndex,
connection,0x44495245u)&1u)!=0;
if(style==0&&anchoredIslandPassage&&!anchoredSpiral&&passageAnchor)
+83 -21
View File
@@ -973,7 +973,7 @@ public:
float composed=density;
float deferredSupportDensity=std::numeric_limits<float>::infinity();
const auto composeRouteMouthSupport=[&](std::int32_t strateIndex,
const std::array<std::int64_t,3>& mouth,bool departure)
const std::array<std::int64_t,3>& mouth)
{
// Surface-route treads may reinforce native solid terrain only.
if(!(density<0.0f))return;
@@ -985,25 +985,18 @@ public:
ResolvedLayout->strates.end(),[strateIndex](const auto& value)
{return value.strateIndex==strateIndex;});
if(stratum==ResolvedLayout->strates.end())return;
std::array<const VoxelForgeCore::ResolvedLayoutAnchorV2*,5> route{};
std::size_t routeCount=0;
std::vector<const VoxelForgeCore::ResolvedLayoutAnchorV2*> route;
route.reserve(stratum->anchors.size());
for(const auto& anchor:stratum->anchors)
if(anchor.kind=="route_point"&&anchor.values.size()>=3)
{
if(departure)
{
if(routeCount<route.size())route[routeCount++]=&anchor;
else
{
std::move(route.begin()+1,route.end(),route.begin());
route.back()=&anchor;
}
}
else if(routeCount<route.size())route[routeCount++]=&anchor;
}
if(routeCount<2)return;
const std::size_t lastSegment=routeCount-1;
route.push_back(&anchor);
if(route.size()<2)return;
const std::size_t lastSegment=route.size()-1;
constexpr double MouthSupportBlendMetres=0.45;
// Route anchors encode the player center at half the authored capsule
// height above the tread. Keep the support deck below that same foot
// plane so the route audit's 0.5 m support search reaches solid tread.
constexpr double RouteCenterAboveFootMetres=0.88;
const double mouthBlendWidth=MouthSupportBlendMetres*qPerMetre;
double mouthSupportDistance=std::numeric_limits<double>::infinity();
for(std::size_t index=0;index<lastSegment;++index)
@@ -1023,8 +1016,8 @@ public:
const double horizontalX=qx-centerX,horizontalY=qy-centerY;
const double horizontalDistance=DeterministicSqrt(
horizontalX*horizontalX+horizontalY*horizontalY);
const double floorQ=centerZ-(VoxelForgeCore::WorldAssemblyEvaluatorVersion>=184
?playerCenterAboveFloorQ+0.25*qPerMetre:1.20*qPerMetre);
const double floorQ=centerZ-RouteCenterAboveFootMetres*qPerMetre
-0.25*qPerMetre;
const double sideDistance=horizontalDistance-halfWidth;
const double topDistance=qz-floorQ;
const double bottomDistance=floorQ-qPerMetre-qz;
@@ -1883,7 +1876,7 @@ public:
if(!tileHasSupport
||ActivePassageTileQueries->hasMouthSupport(passageIndex))
composeRouteMouthSupport(passage.upperStrateIndex,
passage.upperMouthSubvoxels,true);
passage.upperMouthSubvoxels);
}
composed=std::min(composed,deferredSupportDensity);
return composed;
@@ -4986,7 +4979,7 @@ private:
// Add a subtle host-rock root only when the unmodified column lacks the
// vertical relief required for walkable passage support.
const double rootTaper=crossing.needsRootTaper
?0.08*qPerMetre*smoothStep((t-0.35)/0.50):0.0;
?0.30*qPerMetre*smoothStep((t-0.35)/0.50):0.0;
const double radius=static_cast<double>(crossing.minimumRadiusSubvoxels)
+std::max(0.15*qPerMetre,irregularity)+rootTaper+baseFlare+ceilingFlare;
const double radialDistanceField=radialDistance-radius;
@@ -10912,6 +10905,75 @@ private:
bool ValidatePassageRoutes()
{
if(Owner&&Owner->bHasUnrealResolvedCorePlan
&&ResolvedLayout&&!ResolvedLayout->passages.empty())
{
constexpr double SampleStep=0.5;
uint32 PassageIndex=0;
for(const auto& passage:ResolvedLayout->passages)
{
const auto& points=passage.controlPoints;
if(points.size()<2){++PassageIndex;continue;}
uint64 routeSamples=0,routeFailures=0;
int32 firstFailure[3]={0,0,0};
for(std::size_t segment=0;segment+1<points.size();++segment)
{
const auto& a=points[segment].positionSubvoxels;
const auto& b=points[segment+1].positionSubvoxels;
const double ax=static_cast<double>(a[0])/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
const double ay=static_cast<double>(a[1])/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
const double az=static_cast<double>(a[2])/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
const double bx=static_cast<double>(b[0])/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
const double by=static_cast<double>(b[1])/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
const double bz=static_cast<double>(b[2])/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
const double length=std::sqrt((bx-ax)*(bx-ax)+(by-ay)*(by-ay)+(bz-az)*(bz-az));
const int32 count=std::max(1,static_cast<int32>(std::ceil(length/SampleStep)));
uint64 segmentFailures=0;
for(int32 sample=0;sample<=count;++sample)
{
const double t=static_cast<double>(sample)/count;
const int32 vx=static_cast<int32>(std::lround(ax+(bx-ax)*t));
const int32 vy=static_cast<int32>(std::lround(ay+(by-ay)*t));
const int32 vz=static_cast<int32>(std::lround(az+(bz-az)*t));
++Stats.WalkSamples;
++routeSamples;
const float density=DensityAt(static_cast<float>(ax+(bx-ax)*t),
static_cast<float>(ay+(by-ay)*t),
static_cast<float>(az+(bz-az)*t));
if(!std::isfinite(density)||density<0.0f)
{
++Stats.WalkFailures;
++routeFailures;
++segmentFailures;
if(routeFailures==1)
{firstFailure[0]=vx;firstFailure[1]=vy;firstFailure[2]=vz;}
}
}
if(segmentFailures)
std::fprintf(stderr,"[WalkabilitySegment] source=resolved_core_layout passage=%s segment=%zu failures=%llu/%llu length=%.2f\n",
passage.stableId.c_str(),segment,
static_cast<unsigned long long>(segmentFailures),
static_cast<unsigned long long>(std::max(1,static_cast<int32>(std::ceil(length/SampleStep))+1)),
length);
}
if(routeFailures)
std::fprintf(stderr,"[WalkabilityRoute] source=resolved_core_layout passage=%u id=%s points=%zu failures=%llu/%llu first_solid=(%d,%d,%d)\n",
PassageIndex,passage.stableId.c_str(),points.size(),
static_cast<unsigned long long>(routeFailures),
static_cast<unsigned long long>(routeSamples),firstFailure[0],
firstFailure[1],firstFailure[2]);
++PassageIndex;
}
if(Stats.WalkFailures)
std::fprintf(stderr,"[Walkability] FAIL source=resolved_core_layout %llu/%llu compiled Core passage centerline samples are solid\n",
static_cast<unsigned long long>(Stats.WalkFailures),
static_cast<unsigned long long>(Stats.WalkSamples));
else
std::printf("[Walkability] PASS source=resolved_core_layout %llu/%llu compiled Core passage centerline samples remain open\n",
static_cast<unsigned long long>(Stats.WalkSamples),
static_cast<unsigned long long>(Stats.WalkSamples));
return Stats.WalkFailures==0;
}
constexpr double SampleStep=0.5;
uint32 PassageIndex=0;
for(const FVoxelPassage& P:Owner->Manager->GetPassages())
@@ -0,0 +1,155 @@
#!/usr/bin/env python3
"""Normalize and diff the Unreal export, headless import, and pre-export fallback."""
from __future__ import annotations
import difflib
import json
import hashlib
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l70"
REPORT_DIR = Path(__file__).resolve().parent
OWNER = ROOT / "Standalone/data/owner_world.json"
def load(path: Path):
return json.loads(path.read_text(encoding="utf-8"))
def normalized_layout(path: Path) -> dict:
value = load(path)
# Headless annotates imported entries with the owner's requested passage style.
# That annotation is not part of the serialized Unreal resolved layout.
value.pop("resolved_strate_passage_styles", None)
return value
def canonical(manifest_path: Path, layout_path: Path, *, include_owner_inputs: bool) -> dict:
manifest = load(manifest_path)
layout = normalized_layout(layout_path)
result = {
"manifest": manifest,
"layout": layout,
"native_floating_island_plans": [
{k: v for k, v in plan.items() if k in ("strate_index", "top_chunk_z", "bottom_chunk_z")}
for plan in manifest.get("floating_islands", [])
],
"generator_recipes": [
{
"strate_index": s.get("strate_index"),
"generator_kind": s.get("generator_kind"),
"recipe_id": s.get("recipe_id"),
"recipe_version": s.get("recipe_version"),
"query_dispatch_path": s.get("query_dispatch_path"),
}
for s in layout.get("strates", [])
],
}
if include_owner_inputs:
owner = load(OWNER)
result["owner_slots"] = [
{
"index": slot.get("index"),
"top_chunk_z": slot.get("top_chunk_z"),
"bottom_chunk_z": slot.get("bottom_chunk_z"),
"height_chunks": slot.get("height_chunks"),
"generator_recipe_setting": slot.get("asset", {}).get("CoreGeometry", {}).get("GeneratorRecipe"),
"passage_config": slot.get("passage_config"),
}
for slot in owner.get("strates", [])
]
result["owner_passages"] = owner.get("passages", [])
result["effective_layout_width_q"] = manifest.get("recipe", {}).get("layout_chunk_width_q")
stale = owner.get("settings_asset", {}).get("WorldAssemblyManifestJson", "")
result["inactive_settings_manifest"] = {
"sha256": hashlib.sha256(stale.encode("utf-8")).hexdigest() if stale else None,
"active": owner.get("settings_asset", {}).get("bUseWorldAssemblyManifestOverride", False),
}
return result
def json_text(value) -> str:
return json.dumps(value, indent=2, sort_keys=True, ensure_ascii=False) + "\n"
def write(name: str, value) -> Path:
path = OUT / name
path.write_text(json_text(value), encoding="utf-8")
return path
def main() -> int:
unreal = canonical(OUT / "manifest-unreal-strict-core.json",
OUT / "layout-unreal-strict-core.json", include_owner_inputs=True)
headless = canonical(OUT / "manifest-headless-imported-final.json",
OUT / "layout-headless-imported-final.json", include_owner_inputs=True)
unreal_path = write("resolved-plan-unreal-canonical.json", unreal)
headless_path = write("resolved-plan-headless-canonical.json", headless)
exact = unreal == headless
old = canonical(OUT / "manifest-headless-fallback-current.json",
OUT / "layout-headless-fallback-current.json", include_owner_inputs=False)
old_path = write("resolved-plan-headless-fallback-canonical.json", old)
compared_keys = ("manifest", "layout", "native_floating_island_plans", "generator_recipes")
unreal_core = {key: unreal[key] for key in compared_keys}
old_core = {key: old[key] for key in compared_keys}
old_diffs = list(difflib.unified_diff(
json_text(unreal_core).splitlines(), json_text(old_core).splitlines(),
fromfile="unreal-current", tofile="headless-pre-export-fallback", lineterm=""))
diff_path = OUT / "resolved-plan-diff.txt"
diff_path.write_text("\n".join(old_diffs) + "\n", encoding="utf-8")
# Report compact high-value field deltas for the previous independently planned pair.
old_layout = old["layout"]
new_layout = unreal["layout"]
old_slots = [(s.get("strate_index"), s.get("generator_kind"),
s.get("interior_bottom_um"), s.get("interior_top_um"))
for s in old_layout.get("strates", [])]
new_slots = [(s.get("strate_index"), s.get("generator_kind"),
s.get("interior_bottom_um"), s.get("interior_top_um"))
for s in new_layout.get("strates", [])]
route_rows = []
for label, layout in (("fallback", old_layout), ("unreal", new_layout)):
passages = []
for passage in layout.get("passages", []):
points = passage.get("control_points", [])
passages.append({
"id": passage.get("stable_id"),
"upper": passage.get("upper_strate_index"),
"lower": passage.get("lower_strate_index"),
"style": passage.get("style"),
"control_point_count": len(points),
"upper_mouth_q": passage.get("upper_mouth_q"),
"lower_mouth_q": passage.get("lower_mouth_q"),
})
route_rows.append((label, passages))
lines = [
f"final_unreal_equals_headless={exact}",
f"final_manifest_equal={unreal['manifest'] == headless['manifest']}",
f"final_layout_equal={unreal['layout'] == headless['layout']}",
f"final_stable_identity={new_layout.get('stable_identity')}",
f"layout_width_q={unreal['effective_layout_width_q']}",
f"native_fi_plans={unreal['native_floating_island_plans']}",
f"owner_slots_current={[(s.get('index'), s.get('top_chunk_z'), s.get('bottom_chunk_z')) for s in unreal['owner_slots']]}",
f"pre_export_stable_identity={old_layout.get('stable_identity')}",
f"pre_export_manifest_hash={old['manifest'].get('content_hash')}",
f"unreal_manifest_hash={unreal['manifest'].get('content_hash')}",
f"pre_export_slots={old_slots}",
f"unreal_slots={new_slots}",
f"routes={json.dumps(route_rows, sort_keys=True)}",
f"pre_export_diff_lines={len(old_diffs)}",
f"canonical_unreal={unreal_path}",
f"canonical_headless={headless_path}",
f"canonical_fallback={old_path}",
f"diff={diff_path}",
]
result = REPORT_DIR / "resolved-plan-comparison.txt"
result.write_text("\n".join(lines) + "\n", encoding="utf-8")
print("\n".join(lines), flush=True)
return 0 if exact else 2
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,41 @@
## Revised ranked divergences
1. **The audit’s compiled region changes which solidity query it uses.** **Changed:** this replaces the surface route builder as the top explanation. **Code read: both Unreal and headless bounds construction, plus the shared Core query.**
**[REPORT]** L68’s owner run used `workers=1`, `clip_radius=1`, `max_level=0`; its logged volume was only `(-64,-64,-2048)..(64,64,-1920)` and it passed. L69’s headless `probe-max8-old-camera` used `workers=12`, `clip_radius=3`, `max_level=8` and failed at the *same* voxel as Unreal. Both logs have the same source stamp, surface-plan hash, and resolved-layout identity. [L68 log](</home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l68/logs/final-clang-owner.log:2>) [L69 headless log](</home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l69/probe-max8-old-camera.log:2>) [L69 Unreal log](</home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l69/traces/failed-strate0-trial1-default-settings.stdout.log:1113>)
**[CODE]** The validator samples manager passage segments every 0.5 Core voxels, rounds each coordinate, then calls `IsRock`. From the logged segment endpoints, `Count=ceil(88.84/0.5)=178`; at `j=47`, `T=47/178`, interpolation gives about `(-171.54,-138.40,-1794.15)`, which rounds to `(-172,-138,-1794)`. That is the logged first failure. [validator](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:10913>) [segment log](</home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l69/traces/failed-strate0-trial1-default-settings.stdout.log:1113>)
**[CODE]** `IsRock` uses `EvaluateFast` when the point is outside the compiled region; inside, it reads the compiled `RockWords` bit. The region bounds are inclusive, and Core pads the requested minimum by only two voxels. [IsRock](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:6066>) [Contains](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:6946>) [build bounds](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:2358>)
**[INFERENCE, hand-derived]** In the L69 headless probe, the camera is at −374.569336 m; with 25 cm Core voxels that is about −1498.28 voxels, giving camera chunk −47. With clip radius 3, the level 1 ring’s lowest aligned tile is −28; at 64 voxels per tile, its origin is −1792. Two-voxel build padding makes `MinZ=-1794`. Levels 0 and 1 are full resolution (`full_res_clip_levels=2`), so the sample lies exactly on the inclusive compiled-region boundary. Its X and Y are also within that region. The L68 request filtered to level 0 and its logged bounds put this point outside; `IsRock` therefore took the `EvaluateFast` path there. The L69 headless and Unreal logs say the point is solid in the wider compile. [clipmap math](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Source/VoxelForge/Private/VoxelClipmapDesiredTiles.h:129>) [headless fine bounds](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Source/StreamBenchmarkPipeline.h:1942>) [Unreal fine bounds](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelWorld.cpp:7717>)
This explains how the L68 pass can miss the compiled-region result at this point; it does **not** identify which primitive or density term set the compiled bit solid. The logs contain only the `IsRock` result, not its density or contributor. The worker count, camera, and clip settings also changed between L68 and L69, so their individual effects are not isolated.
2. **The two surface route planners produce different plans, but that does not explain this sample.** **Demoted from the prior top claim. Code read: both planners and the shared passage planner.**
**[CODE/REPORT]** Unreal’s adapter has its own bounded `BuildFiniteSurfaceRoute`; L69 selected center `(32,80)`, direction 6, half-length 16, and resolved the departure at `(8,16)`, floor −373.205 m. Headless uses `BuildFiniteStrateRoute`; its L69 log reports departure `(0,0)`, floor −375.819 m, and a lower reach clamp from 318.539 m to 232.500 m. [adapter route](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp:248>) [headless route](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Source/WorldAssemblyPrototype.h:45>) [Unreal log](</home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l69/traces/failed-strate0-trial1-default-settings.stdout.log:1055>) [headless log](</home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l69/probe-max8-old-camera.log:41>)
**[CODE]** The walkability validator checks `Owner->Manager->GetPassages()` control points; those are distinct from the adapter’s SurfaceWorld route. **[REPORT]** The headless L69 run with its `(0,0)` route fails at the exact same sample. So the route-planner difference is real, but it does not reproduce the claimed Unreal-only failure.
3. **Native FI has no plan in the default headless owner run.** **Code read: both the headless assembly path and the Core binding/dispatch path. Runtime pointer value: inferred, not logged.**
**[CODE]** The default `FloatingIslandsRecipe` flag is false. With no canonical exported Core-plan pair, headless takes `AttachRound1WorldAssemblyPrototype`; it calls `AttachFloatingIslandWorldAssembly` only when that flag is true. The default prototype adds a SurfaceWorld plan, not an FI plan. [default flag](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Source/StreamBenchmarkHeadless.cpp:65>) [plan-source branch](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Source/StreamBenchmarkHeadless.cpp:1698>) [conditional FI attach](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Source/StreamBenchmarkHeadless.cpp:1747>) [surface-plan append](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Source/WorldAssemblyPrototype.h:901>)
**[CODE]** `BindResolvedStratumFields` sets `Bound->IslandPlan` only when it finds an FI plan with the exact live strate index and top/bottom bounds. `NativeFloatingIslandDensityAt` then returns false on `!Bound->IslandPlan` at line 6604. The owner log’s `compiled-analytic/FloatingIslands` dispatch confirms the fallback path; it does not print the pointer. So for the default headless owner run, **`Bound->IslandPlan == nullptr` is inferred from the code path and dispatch log**, not read as a runtime value. [binding](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:361>) [gate](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:6592>) [owner dispatch](</home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l68/logs/l66-owner.log:89>)
This is an FI divergence, not the direct cause at −448.5 m: the failed point is in the logged SurfaceWorld slot `[0,-63]`, while FI begins below it.
4. **The stale imported manifest is a separate branch, not the L69 default failure path. Units and width mostly converge when regenerated.** **Code read: both export/import sides; the stale bounds are report evidence.**
**[REPORT]** The imported FI plan had chunks `[-79,-16]` versus the live slot `[-93,-64]`, and the saved manifest lacked `layout_chunk_width_q`. **[CODE]** An imported plan with those bounds cannot bind to the live FI slot because the binder requires exact bounds equality. But L69’s failing Unreal run logs `generated_at_startup`, so that imported plan was not the active plan in that trace. [L69 report](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux69/REPORT.md:45>) [binding equality](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:366>) [generated-plan log](</home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l69/traces/failed-strate0-trial1-default-settings.stdout.log:1061>)
**[CODE]** Unreal derives width from the live manager and serializes Core/owner voxel sizes; headless uses root micrometres or the settings’ metre value, then computes Core width. Both resolve the effective 8 m layout width and 25 cm Core voxel size for the owner data. [Unreal serialization](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp:2070>) [headless width fallback](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Source/OwnerWorldLoader.h:420>)
**[CODE]** The exporter writes both per-strate `passage_config` and a `passages` array, but `OwnerWorldLoader` rebuilds the manager with `Initialize` from the serialized strate settings; it does not load the exported passage points. Thus both Core paths regenerate manager passages instead of consuming that array. [export](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForgeEditor/Private/VoxelForgeExploreCommandlet.cpp:13813>) [loader](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Source/OwnerWorldLoader.h:449>)
## Smallest one-source design
Make the adapter’s existing canonical `ResolvedWorldSnapshot` the required owner input: export its `core_world_assembly_json` and `resolved_layout_json`, including exact units, layout width, live slot bounds, FI plan, and resolved passage geometry. The export commandlet already writes that pair. Make headless require and strictly validate it instead of generating a second SurfaceWorld route or omitting FI. Have the validator consume the same resolved passage geometry used by composition, and reject stale plan bounds or missing width rather than silently falling back.
The immediate finding is narrower: L68’s small compile window let this sample take `EvaluateFast`; L69’s wider compile put it on the packed-rock path, where both headless and Unreal report it solid. The packed-path density cause remains unidentified.
@@ -0,0 +1,125 @@
# Linux 70: Unreal and headless plan parity
## Result
The strict Unreal export and the headless import now resolve the same Core manifest and layout:
`manifest_equal=True`, `layout_equal=True`, manifest hash `bcc0d0d33ea39435`, layout identity
`resolved-layout-v3-fnv64:0589300eb07dfe06`, and `layout_chunk_width_q=8192`. The headless log reports
`source=owner_export/unreal_core_adapter`. Slot bounds are `0: top 0 / bottom -63`,
`1: -64 / -93`, `2: -94 / -109`, and `3: -110 / -125`.
The exact-plan passage audit passes all three interfaces, with `natural=3/3` and zero route-binding
failures. The fast tier also passes (268.4 s), including peer determinism and the new four-strate
plan stage. The new floating-islands style-2 output is pinned in
`Standalone/Tools/verify/hash-baselines/owner-hash-floating-islands-style2-v214.log`; the historical
L68 baseline was left intact.
## Divergences and fixes
- **Export and manifest.** The pre-L70 owner JSON had no root resolved Core manifest/layout pair.
Its inactive `settings_asset.WorldAssemblyManifestJson` also lacked `layout_chunk_width_q` and
carried an FI plan with top/bottom `-16/-79`, while the live FI slot is `-64/-93`.
`bUseWorldAssemblyManifestOverride` is false, so Unreal did not consume that stale string; the
headless fallback instead made its own plan. The export commandlet now writes
`world_assembly`, `core_world_assembly_json`, and `resolved_layout_json` from the live Unreal
Core adapter. The headless owner path imports that pair and validates width and live slot bounds.
The embedded legacy string remains inactive; use the root pair.
- **Slots, passage inputs, and route.** The four live slot bounds and authored passage configs
agree after export. Before unification, the independently resolved SurfaceWorld upper mouth
differed: headless fallback `[0,0,-383938]` versus Unreal `[8192,16384,-381197]` in Q units.
Unreal's candidate search had weaker clearance and support constraints and a different tie
choice. The adapter now uses the Core clearance/radius floors, checks route support, and prefers
the outward-facing candidate; the Core radial phase override was removed. The composed route
support deck and root taper were corrected, and the imported-plan passage audit now samples the
serialized Core route. The final canonical routes and passage configs compare equal.
- **Generators and FI dispatch.** Recipes in the resolved layout are `SurfaceWorld.Heightfield2D`
v2, `FloatingIslands.ClusterField` v0, `legacy.TunnelNetwork`, and `legacy.VerticalShafts`.
The owner currently has no native FI plan: `bUseWorldAssemblyManifestOverride=false` leaves
`bImportedOverride=false`, so the adapter's `Type == FloatingIslands && bImportedOverride`
branch does not build one. `NativeFloatingIslandDensityAt` then has no bound `IslandPlan` and the
FI slot uses `compiled-analytic/FloatingIslands`. This is the same default FI dispatch on both
sides of the final plan.
- **The L69 solid sample.** R37's notes place `(-43.0,-34.5,-448.5) m` on the lower inclusive
boundary of the wider compiled region. L68's smaller compile queried `EvaluateFast`; L69's wider
compile read the packed rock bit, and the same point was solid in both L69 headless and Unreal
runs. The source of that historical packed bit is still unidentified. L70's exact-plan composed
density audit passes all three interfaces; that does not identify the old bit's density
contributor. The route-planner difference was real, but R37 did not find it sufficient to
explain that sample.
## Re-export on Windows
Set the three paths for the owner's machine, then run this PowerShell command. It overwrites
`Standalone\data\owner_world.json` with the live four-strate export and its canonical plan pair.
```powershell
$UE = 'C:\Path\To\UnrealEngine'
$VFHost = 'C:\Path\To\VFHost'
$VoxelForge = Join-Path $VFHost 'Plugins\VoxelForge'
& "$UE\Engine\Binaries\Win64\UnrealEditor-Cmd.exe" "$VFHost\VFHost.uproject" `
-run=VoxelForgeExplore -nullrhi -unattended -nop4 -nosplash -NoSound `
-NoZenAutoLaunch -notraceserver -nocrashreports -DDC-ForceMemoryCache `
-settingsref=/Game/VoxelForge/DA_Settings.DA_Settings -modes=export `
-gameconfig=1 -standaloneworldexport=1 -ownerfourstrateplan=1 `
"-out=$VoxelForge\Standalone\data" `
"-abslog=$VoxelForge\Saved\Linux\l70\owner-export.log"
```
## Spawn traces
Three Unreal traces per strate completed. The table uses Unreal medians; `walkable` is the 9/9
walkable-gate time, `LOD0` is the 512-tile ring time, `full` is spawn to `initial_set_ready`, and
`worker` is the sum of tile `worker_task_s`. Headless values are one run at the same arrival;
`worker` sums `WorldAssemblerLODWorker.worker_sum_s`.
| Strate | Walkable UE | LOD0 UE | Headless first / neighborhood | Full UE / headless (tiles) | Worker UE / headless (s) | UE LOD0 p50 / p95 (ms) | UE GenerateTile / mesh copy / RMC (s) |
|---|---:|---:|---:|---:|---:|---:|---:|
| 0 SurfaceWorld | 0.833 s | 2.063 s | 0.406 / 0.556 s | 7.039 / 2.057 s (2850 / 2850) | 42.912 / 20.064 | 0.924 / 125.243 | 42.688 / 0.035 / 0.190 |
| 1 FloatingIslands | 1.813 s | 3.200 s | 0.377 / 0.660 s | 6.642 / 5.493 s (2249 / 2249) | 48.219 / 61.516 | 16.819 / 168.878 | 47.968 / 0.037 / 0.214 |
| 2 TunnelNetwork | 0.361 s | 2.684 s | 0.393 / 0.547 s | 5.626 / 4.634 s (2233 / 2233) | 37.894 / 50.868 | 8.188 / 166.935 | 37.655 / 0.035 / 0.203 |
| 3 VerticalShafts | 0.379 s | 1.191 s | 0.400 / 0.413 s | 3.651 / 2.258 s (2329 / 2329) | 16.425 / 22.227 | 2.323 / 44.996 | 16.217 / 0.033 / 0.178 |
The full-set wall gaps exceed 30% at strates 0 (+242%) and 3 (+62%); the worker-sum gap exceeds
30% only at strate 0 (+114%). Unreal ran with `streaming_background_worker_cap=1`, an eight-slot
effective queue, startup apply boost, and the live asset clip settings (radius 6, max clip 6;
observed levels 0–8). The headless table used 12 workers, radius 3, max clip 8, max level 8. Its
tile counts match Unreal at every LOD for these arrivals, but these are not identical runtime
settings. The explicit headless radius-6/max-clip-6 run hit the 160-million-node shape safety
bound at 17,689 desired tiles before generation. Unreal's full-set milestone also includes its
tile scheduling and delivery path, while headless `whole_view_ready` is the direct pipeline
milestone. Strate 3's higher wall time with 26% fewer worker-seconds suggests readiness/scheduling
overhead. Strate 0's worker excess is in `GenerateTile` itself (42.688 s versus 20.064 s for the
headless worker sum); plan and per-LOD tile counts do not explain it, and this trace does not
isolate the remaining runtime cost.
## Native FI experiment
I temporarily removed the `&& bImportedOverride` gate, rebuilt, and exported the auto-native FI
plan (hash `303f3d266dc40a7c`). Dispatch changed to `FloatingIslands-native`; the 2249-tile
whole-view density/mesh/payload/topology hash changed from off
`c1e5e72f879b0327/2c3994301a77a14e/1e3c8f74f439e4ff/ba850f95f0b889c8` to
on `11042f19685926d1/56c6d3d46d8ed3b1/d81e70785c858145/7e608c8cb9027a70` (one run each).
The on-plan audit failed: 2/3 interfaces
passed, the FI route had 1843 blocked samples, and open-air had 945 violations. Leave native FI
off for the owner.
## Build and failed runs
Linux UBT succeeded with the final native-FI-off code. `Source/` files for the Windows build are
`Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp` and
`Source/VoxelForgeEditor/Private/VoxelForgeExploreCommandlet.cpp`. The build completed before the
timing series; no Unreal build ran during timing. Every process was taskset-limited and capped at
6 GiB; UE used RSS and headless used address space. No run exceeded 30 minutes; each valid Unreal
trace took about 53 s.
- Initial UE trace attempts inherited an address-space cap and failed during UE startup/mapping;
switching the trace driver to the RSS cap produced all 12 valid traces.
- The radius-6 headless comparison stopped at the 160-million-node bound noted above.
- A diagnostic passage-audit run with extra max-clip/output flags threw `std::bad_alloc`; the
bounded rerun without those diagnostic flags passed all three interfaces.
- The one-line native-FI experiment intentionally failed the passage audit as described above.
No commit, push, or stash was made.
@@ -0,0 +1,123 @@
#!/usr/bin/env python3
"""Run bounded Unreal startup traces at each exported owner-plan arrival."""
from __future__ import annotations
import argparse
import json
import subprocess
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
HOST = Path("/home/jahni/VFHost")
PLUGIN_SAVED = ROOT / "Saved/Linux/l70"
HOST_PLUGIN_SAVED = HOST / "Plugins/VoxelForge/Saved/Linux/l70"
HOST_SAVED = HOST / "Saved/Linux/l70"
EDITOR = Path("/home/jahni/UnrealEngine/Engine/Binaries/Linux/UnrealEditor-Cmd")
TRACES = PLUGIN_SAVED / "traces"
SPAWNS_M = {
0: (8.0, 16.0, -372.2626953125),
1: (25.8369140625, 3.19921875, -737.0),
2: (19.166015625, -14.2001953125, -753.3740234375),
3: (-20.0625, -5.068359375, -900.353515625),
}
def run(strate: int, trial: int) -> dict:
label = f"strate{strate}-trial{trial}"
trace = TRACES / f"{label}.trace.jsonl"
abslog = TRACES / f"{label}.log"
stdout = TRACES / f"{label}.stdout.log"
output = HOST_PLUGIN_SAVED / "output" / label
userdir = HOST_SAVED / label / "User"
zendata = HOST_SAVED / label / "Zen"
ddc = HOST_SAVED / "DDC"
for directory in (output, userdir, zendata, ddc, TRACES):
directory.mkdir(parents=True, exist_ok=True)
spawn_cm = ",".join(f"{value * 100.0:.3f}" for value in SPAWNS_M[strate])
command = [
str(EDITOR), str(HOST / "VFHost.uproject"), "-nullrhi", "-unattended",
"-nop4", "-nosplash", "-NoSound", "-corelimit=12", "-NoZenAutoLaunch",
"-notraceserver", "-nocrashreports",
"-DisablePlugins=AndroidFileServer",
"-ddc=NoZenLocalFallback",
f"-userdir={userdir}", f"-ZenDataPath={zendata}", f"-LocalDataCachePath={ddc}",
"-run=VoxelForgeExplore", "-seed=0", "-archetype=TunnelNetwork", "-slot=0",
"-modes=export", "-gameconfig=1", "-coreworldtest=1", "-ownerfourstrateplan=1",
"-corevoxelsizecm=25", "-coreislandtest=0", "-corefallbacktest=0",
"-coreofftest=0", "-coreplantest=0",
"-settingsref=/Game/VoxelForge/DA_Settings.DA_Settings", "-corehybridmesher=0",
f"-out={output}",
"-voxel.StreamingCoarseFirst=0", "-voxel.StreamingDynamicNearReserve=1",
"-voxel.StreamingLegacyPendingResultCap=0", "-voxel.CoreRegionConcurrentAdmission=1",
"-voxel.StreamingResultBacklogCap=256", "-voxel.StreamingReadyQueueDepth=8",
"-voxel.StreamingBackgroundWorkerCap=1", "-voxel.CoreColumnCacheDirectMapped=0",
"-voxel.CoreMCGradientMemoization=1", "-voxel.StreamingCollisionLookahead=1",
"-coreworldstreamtrace=1", "-voxel.TestMove=0",
"-voxel.TestMoveSpeedCmPerSecond=0", f"-voxel.StartupTraceSpawnCm={spawn_cm}",
f"-voxel.StartupTraceFile={trace}", "-voxel.StartupTraceUntilEndPlay=1",
"-voxel.StartupTraceMaxTiles=16384", "-voxel.CollisionGate=0",
f"-abslog={abslog}",
]
wrapped = ["taskset", "-c", "0-11", "prlimit", "--rss=6442450944", "--",
"timeout", "1740s", *command]
started = time.monotonic()
with stdout.open("w", encoding="utf-8") as stream:
result = subprocess.run(wrapped, cwd=ROOT, stdout=stream,
stderr=subprocess.STDOUT, timeout=1740, check=False)
elapsed = time.monotonic() - started
event_names: set[str] = set()
if trace.is_file():
for line in trace.read_text(encoding="utf-8", errors="replace").splitlines():
try:
event_names.add(json.loads(line).get("type", ""))
except json.JSONDecodeError:
continue
row = {
"label": label, "strate": strate, "trial": trial, "spawn_m": SPAWNS_M[strate],
"spawn_cm": spawn_cm, "elapsed_s": round(elapsed, 3), "exit_code": result.returncode,
"trace": str(trace), "stdout": str(stdout), "events": sorted(event_names),
"has_walkable_gate": "walkable_gate" in event_names,
"has_lod0_ring": "lod0_ring_ready" in event_names,
"has_initial_set": "stream_trace_milestone" in event_names,
"has_summary": "summary" in event_names,
}
print(f"[L70EngineTrace] {json.dumps(row, sort_keys=True)}", flush=True)
return row
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--strates", nargs="+", type=int, choices=range(4), required=True)
parser.add_argument("--first-trial", type=int, default=1, choices=range(1, 4))
parser.add_argument("--trials", type=int, default=3)
args = parser.parse_args()
if not EDITOR.is_file():
raise SystemExit(f"missing UE commandlet executable: {EDITOR}")
HOST_PLUGIN_SAVED.mkdir(parents=True, exist_ok=True)
if args.trials < args.first_trial or args.trials > 3:
parser.error("--trials must be 1..3 and >= --first-trial")
results = [run(strate, trial) for strate in args.strates
for trial in range(args.first_trial, args.trials + 1)]
summary = PLUGIN_SAVED / "traces" / ("engine-summary-" + "-".join(map(str, args.strates)) + ".json")
summary.parent.mkdir(parents=True, exist_ok=True)
if summary.is_file():
try:
previous = json.loads(summary.read_text(encoding="utf-8"))
merged = {row["label"]: row for row in previous}
merged.update({row["label"]: row for row in results})
results = sorted(merged.values(), key=lambda row: (row["strate"], row["trial"]))
except (OSError, json.JSONDecodeError, KeyError, TypeError):
pass
summary.write_text(json.dumps(results, indent=2) + "\n", encoding="utf-8")
complete = all(row["exit_code"] == 0 and row["has_walkable_gate"] and row["has_lod0_ring"]
and row["has_initial_set"] and row["has_summary"] for row in results)
print(f"[L70EngineTraceSet] strata={args.strates} trials_each={args.trials} "
f"total={len(results)} status={'PASS' if complete else 'INCOMPLETE'} summary={summary}",
flush=True)
return 0 if complete else 2
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,46 @@
#!/usr/bin/env python3
"""Benchmark the exact exported owner plan at its four arrivals."""
from __future__ import annotations
import subprocess
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OWNER = ROOT / "Standalone/data/owner_world.json"
BIN = ROOT / "Saved/Linux/l70/bin/VoxelForgeCoreHeadless-l70-clang"
OUT = ROOT / "Saved/Linux/l70/headless-arrivals"
SPAWNS_M = {
0: (8.0, 16.0, -372.2626953125),
1: (25.8369140625, 3.19921875, -737.0),
2: (19.166015625, -14.2001953125, -753.3740234375),
3: (-20.0625, -5.068359375, -900.353515625),
}
def main() -> int:
if not BIN.is_file() or not OWNER.is_file():
raise SystemExit(f"missing headless binary or owner export: {BIN} {OWNER}")
OUT.mkdir(parents=True, exist_ok=True)
result_codes = []
for strate, spawn in SPAWNS_M.items():
camera = ",".join([*(f"{x:.9f}" for x in spawn), "0", "0"])
log = OUT / f"strate{strate}.log"
command = [
str(BIN), str(OWNER), "--world-assembler-prototype", "--stream-benchmark",
"--stream-pipeline", "--force-generate", "--workers=12", "--clip-radius=3",
"--max-clip-level=8", "--max-level=8", f"--camera={camera}",
]
wrapped = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
"timeout", "1740s", *command]
with log.open("w", encoding="utf-8") as stream:
result = subprocess.run(wrapped, cwd=ROOT, stdout=stream,
stderr=subprocess.STDOUT, timeout=1740, check=False)
result_codes.append(result.returncode)
print(f"[L70HeadlessArrival] strate={strate} camera_m={camera} exit={result.returncode} log={log}",
flush=True)
return 0 if all(code == 0 for code in result_codes) else 2
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,124 @@
#!/usr/bin/env python3
"""Summarize L70 Unreal spawn traces beside exact-plan headless arrivals."""
from __future__ import annotations
import json
import re
import statistics
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
SAVED = ROOT / "Saved/Linux/l70"
TRACES = SAVED / "traces"
HEADLESS = SAVED / "headless-arrivals"
OUT = SAVED / "arrival-metrics.json"
def parse_trace(strate: int, trial: int) -> dict:
path = TRACES / f"strate{strate}-trial{trial}.trace.jsonl"
events = [json.loads(line) for line in path.read_text(encoding="utf-8").splitlines()
if line.strip()]
spawn = next(row for row in events if row.get("type") == "trace_spawn_location")
ready_gate = next(row for row in events if row.get("type") == "walkable_gate"
and row.get("ready") == 1)
ring = next(row for row in events if row.get("type") == "lod0_ring_ready")
full = next(row for row in events if row.get("type") == "stream_trace_milestone"
and row.get("name") == "initial_set_ready")
summary = next(row for row in events if row.get("type") == "summary")
tiles = [row for row in events if row.get("type") == "tile"]
lod0 = summary["tile_percentiles"]["lod0"]["worker_task_s"]
return {
"label": f"strate{strate}-trial{trial}",
"strate": strate,
"trial": trial,
"walkable_ring_s": ready_gate["t_s"] - spawn["t_s"],
"walkable_ready_tiles": ready_gate.get("ready_tiles"),
"walkable_required_tiles": ready_gate.get("required_tiles"),
"lod0_ring_s": ring["t_s"] - spawn["t_s"],
"lod0_tiles": ring.get("lod0_tiles"),
"initial_set_s": full["t_s"] - spawn["t_s"],
"initial_set_tiles": full.get("loaded"),
"worker_seconds": sum(row.get("worker_task_s", 0.0) for row in tiles),
"generate_tile_seconds": sum(row.get("core_generate_s", 0.0) for row in tiles),
"mesh_copy_seconds": sum(row.get("mesh_copy_s", 0.0) for row in tiles),
"rmc_seconds": sum(row.get("rmc_stream_build_s", 0.0) for row in tiles),
"lod0_worker_p50_s": lod0["p50"],
"lod0_worker_p95_s": lod0["p95"],
"tile_events": len(tiles),
"summary_tiles": summary["tile_percentiles"]["all"]["count"],
}
def parse_headless(strate: int) -> dict:
path = HEADLESS / f"strate{strate}.log"
text = path.read_text(encoding="utf-8", errors="replace")
milestone = re.search(r"\[PipelineMilestone\] first_tile_ready=([0-9.]+)s", text)
stream = re.search(r"\[StreamPipeline\] ([^\n]+)", text)
if not milestone or not stream:
raise ValueError(f"missing pipeline timings in {path}")
fields = dict(re.findall(r"([A-Za-z0-9_]+)=([^ ]+)", stream.group(1)))
worker_rows = re.findall(
r"\[WorldAssemblerLODWorker\] lod=(\d+) tiles=(\d+) worker_sum_s=([0-9.]+)"
r".*?mc_exclusive_ms=([0-9.]+).*?mesh_assembly_ms=([0-9.]+)", text)
return {
"strate": strate,
"first_tile_s": float(milestone.group(1)),
"neighborhood_ready_s": float(fields["neighborhood_ready"].rstrip("s")),
"full_detail_ready_s": float(fields["full_detail_ready"].rstrip("s")),
"whole_view_ready_s": float(fields["whole_view_ready"].rstrip("s")),
"neighborhood_tiles": fields["neighborhood_tiles"],
"full_detail_tiles": fields["full_detail_tiles"],
"whole_tiles": fields["whole_tiles"],
"worker_seconds": sum(float(row[2]) for row in worker_rows),
"worker_lods": len(worker_rows),
"mc_exclusive_seconds": sum(float(row[3]) for row in worker_rows) / 1000.0,
"mesh_assembly_seconds": sum(float(row[4]) for row in worker_rows) / 1000.0,
}
def median(rows: list[dict], key: str) -> float:
return statistics.median(float(row[key]) for row in rows)
def main() -> int:
results = []
for strate in range(4):
trials = [parse_trace(strate, trial) for trial in range(1, 4)]
headless = parse_headless(strate)
engine = {key: median(trials, key) for key in (
"walkable_ring_s", "lod0_ring_s", "initial_set_s", "worker_seconds",
"generate_tile_seconds", "mesh_copy_seconds", "rmc_seconds",
"lod0_worker_p50_s", "lod0_worker_p95_s")}
engine.update({"walkable_ready_tiles": trials[0]["walkable_ready_tiles"],
"walkable_required_tiles": trials[0]["walkable_required_tiles"],
"lod0_tiles": trials[0]["lod0_tiles"],
"initial_set_tiles": trials[0]["initial_set_tiles"],
"trace_tile_events": trials[0]["tile_events"],
"trace_summary_tiles": trials[0]["summary_tiles"]})
row = {"strate": strate, "engine_median": engine, "engine_trials": trials,
"headless": headless,
"initial_set_time_gap_percent":
100.0 * (engine["initial_set_s"] / headless["whole_view_ready_s"] - 1.0),
"worker_sum_gap_percent":
100.0 * (engine["worker_seconds"] / headless["worker_seconds"] - 1.0)}
results.append(row)
print(
f"strate={strate} walk={engine['walkable_ring_s']:.3f}s "
f"lod0={engine['lod0_ring_s']:.3f}s/{engine['lod0_tiles']} tiles "
f"full=UE {engine['initial_set_s']:.3f}s/{engine['initial_set_tiles']} "
f"vs headless {headless['whole_view_ready_s']:.3f}s/{headless['whole_tiles']} "
f"workers=UE {engine['worker_seconds']:.3f}s/{engine['trace_tile_events']} "
f"vs headless {headless['worker_seconds']:.3f}s "
f"LOD0 p50/p95={engine['lod0_worker_p50_s']:.6f}/{engine['lod0_worker_p95_s']:.6f}s "
f"GenerateTile/mesh-copy/RMC={engine['generate_tile_seconds']:.3f}/"
f"{engine['mesh_copy_seconds']:.3f}/{engine['rmc_seconds']:.3f}s "
f"gaps={row['initial_set_time_gap_percent']:+.1f}% time,"
f"{row['worker_sum_gap_percent']:+.1f}% worker")
OUT.write_text(json.dumps(results, indent=2) + "\n", encoding="utf-8")
print(f"[L70ArrivalMetrics] wrote {OUT}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,18 @@
final_unreal_equals_headless=True
final_manifest_equal=True
final_layout_equal=True
final_stable_identity=resolved-layout-v3-fnv64:0589300eb07dfe06
layout_width_q=8192
native_fi_plans=[]
owner_slots_current=[(0, 0, -63), (1, -64, -93), (2, -94, -109), (3, -110, -125)]
pre_export_stable_identity=resolved-layout-v3-fnv64:f13f5535457aa27c
pre_export_manifest_hash=d18bf10b0a23b665
unreal_manifest_hash=bcc0d0d33ea39435
pre_export_slots=[(0, 'SurfaceWorld', -504000000, 8000000), (1, 'FloatingIslands', -744000000, -504000000), (2, 'TunnelNetwork', -872000000, -744000000), (3, 'VerticalShafts', -1000000000, -872000000)]
unreal_slots=[(0, 'SurfaceWorld', -504000000, 8000000), (1, 'FloatingIslands', -744000000, -504000000), (2, 'TunnelNetwork', -872000000, -744000000), (3, 'VerticalShafts', -1000000000, -872000000)]
routes=[["fallback", [{"control_point_count": 211, "id": "passage/0-1/0", "lower": 1, "lower_mouth_q": [26457, 3276, -754688], "style": 1, "upper": 0, "upper_mouth_q": [0, 0, -383938]}, {"control_point_count": 19, "id": "passage/1-2/0", "lower": 2, "lower_mouth_q": [19626, -14541, -771455], "style": 1, "upper": 1, "upper_mouth_q": [19626, -14541, -749774]}, {"control_point_count": 83, "id": "passage/2-3/0", "lower": 3, "lower_mouth_q": [-20544, -5190, -921962], "style": 1, "upper": 2, "upper_mouth_q": [-20544, -5190, -831893]}]], ["unreal", [{"control_point_count": 211, "id": "passage/0-1/0", "lower": 1, "lower_mouth_q": [26457, 3276, -754688], "style": 1, "upper": 0, "upper_mouth_q": [8192, 16384, -381197]}, {"control_point_count": 19, "id": "passage/1-2/0", "lower": 2, "lower_mouth_q": [19626, -14541, -771455], "style": 1, "upper": 1, "upper_mouth_q": [19626, -14541, -749774]}, {"control_point_count": 83, "id": "passage/2-3/0", "lower": 3, "lower_mouth_q": [-20544, -5190, -921962], "style": 1, "upper": 2, "upper_mouth_q": [-20544, -5190, -831893]}]]]
pre_export_diff_lines=3304
canonical_unreal=/home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l70/resolved-plan-unreal-canonical.json
canonical_headless=/home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l70/resolved-plan-headless-canonical.json
canonical_fallback=/home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l70/resolved-plan-headless-fallback-canonical.json
diff=/home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l70/resolved-plan-diff.txt
+1
View File
@@ -80,6 +80,7 @@ struct FStandaloneOwnerWorld
std::uint32_t CoreVoxelSizeMicrons = 250000;
std::uint32_t StrateLayoutChunkSizeMicrometres = 8000000;
std::int64_t StrateLayoutChunkWidthSubvoxels = 8192;
bool bHasUnrealResolvedCorePlan = false;
std::shared_ptr<FStandalonePassageVoidCrossingCache> PassageVoidCrossingCache =
std::make_shared<FStandalonePassageVoidCrossingCache>();
};
+34 -4
View File
@@ -1695,6 +1695,18 @@ int main(int argc,char** argv)
&&!OverrideTransitions(ownerJsonRoot,options.TransitionModeOverride,
options.TransitionWidthChunksOverride,error))
{std::fprintf(stderr,"Transition fixture override failed: %s\n",error.c_str());return 2;}
const bool hasExportedAssembly=ownerJsonRoot.Get("core_world_assembly_json").IsString();
const bool hasExportedLayout=ownerJsonRoot.Get("resolved_layout_json").IsString();
if(hasExportedAssembly!=hasExportedLayout)
{std::fprintf(stderr,"Owner export has only half of its Unreal-resolved Core plan.\n");return 2;}
const bool useExportedCorePlan=hasExportedAssembly
&&!options.HasSeedOverride
&&!options.FloatingIslandsRecipe
&&!options.CavesRecipe
&&!options.LatticeRecipe
&&options.TransitionModeOverride<0
&&options.TransitionWidthChunksOverride<0;
ownerWorld->bHasUnrealResolvedCorePlan=useExportedCorePlan;
if(!StandaloneOwnerLoader::Resolve(ownerJsonRoot,*ownerWorld,error))
{std::fprintf(stderr,"Owner data load failed: %s\n",error.c_str());return 2;}
std::printf("[ColdTimeline] stage=owner_data_load end_ms=%.3f\n",
@@ -1720,10 +1732,20 @@ int main(int argc,char** argv)
const auto planStart=Clock::now();
VoxelForgeCore::WorldAssemblyManifest worldAssembly;
if(!StandaloneWorldAssemblyPrototype::AttachRound1WorldAssemblyPrototype(
if(useExportedCorePlan)
{
if(!StandaloneWorldAssemblyPrototype::ImportExportedCoreWorldAssembly(
ownerJsonRoot,worldAssembly,error))
{std::fprintf(stderr,"Unreal-resolved Core plan import failed: %s\n",error.c_str());return 2;}
std::printf("[WorldAssemblerPlanSource] source=owner_export/unreal_core_adapter manifest_hash=%016llx layout_chunk_width_q=%lld surface_strates=%zu floating_islands=%zu\n",
static_cast<unsigned long long>(worldAssembly.contentHash),
static_cast<long long>(worldAssembly.recipe.layoutChunkWidthSubvoxels),
worldAssembly.plan.strates.size(),worldAssembly.floatingIslands.size());
}
else if(!StandaloneWorldAssemblyPrototype::AttachRound1WorldAssemblyPrototype(
*ownerWorld,ownerJsonRoot,error,{},&worldAssembly))
{std::fprintf(stderr,"World assembler prototype setup failed: %s\n",error.c_str());return 2;}
if(options.FloatingIslandsRecipe
if(!useExportedCorePlan&&options.FloatingIslandsRecipe
&&!StandaloneWorldAssemblyPrototype::AttachFloatingIslandWorldAssembly(
*ownerWorld,ownerJsonRoot,worldAssembly,error))
{std::fprintf(stderr,"Floating-island assembly setup failed: %s\n",error.c_str());return 2;}
@@ -1757,9 +1779,17 @@ int main(int argc,char** argv)
?"lattice/"+std::to_string(options.LatticeStrateIndex)
:options.CavesRecipe?"caves"
:options.FloatingIslandsRecipe?"floating-islands":"surface-world";
if(!StandaloneWorldAssemblyPrototype::BuildResolvedLayoutSnapshot(
*ownerWorld,worldAssembly,variant,resolvedLayout,error))
const bool layoutResolved=useExportedCorePlan
?StandaloneWorldAssemblyPrototype::ImportExportedResolvedLayout(
ownerJsonRoot,resolvedLayout,error)
:StandaloneWorldAssemblyPrototype::BuildResolvedLayoutSnapshot(
*ownerWorld,worldAssembly,variant,resolvedLayout,error);
if(!layoutResolved)
{std::fprintf(stderr,"Resolved-layout snapshot failed: %s\n",error.c_str());return 2;}
if(useExportedCorePlan
&&!StandaloneWorldAssemblyPrototype::ValidateExportedCorePlanMatchesOwner(
*ownerWorld,worldAssembly,resolvedLayout,error))
{std::fprintf(stderr,"Unreal-resolved Core plan/owner slot validation failed: %s\n",error.c_str());return 2;}
if(!std::holds_alternative<std::nullptr_t>(ownerJsonRoot.Get("motif_family_override").Data))
{
std::vector<VoxelForgeCore::ResolvedLayoutStampRequestV1> requests;
@@ -1143,6 +1143,89 @@ namespace StandaloneWorldAssemblyPrototype
return "Unknown";
}
inline bool ImportExportedCoreWorldAssembly(const VFJson::Value& root,
VoxelForgeCore::WorldAssemblyManifest& out,std::string& error)
{
const VFJson::Value& assemblyJson=root.Get("core_world_assembly_json");
if(!assemblyJson.IsString())
{error="owner export has no Unreal-resolved Core world assembly";return false;}
auto parsed=VoxelForgeCore::WorldAssemblyManifest::FromJson(assemblyJson.String(),error);
if(!parsed)return false;
out=std::move(*parsed);
return true;
}
inline bool ImportExportedResolvedLayout(const VFJson::Value& root,
VoxelForgeCore::ResolvedLayoutSnapshotV3& out,std::string& error)
{
const VFJson::Value& layoutJson=root.Get("resolved_layout_json");
if(!layoutJson.IsString())
{error="owner export has no Unreal-resolved Core layout";return false;}
auto parsed=VoxelForgeCore::ResolvedLayoutSnapshotV3::FromJson(layoutJson.String(),error);
if(!parsed)return false;
std::vector<VoxelForgeCore::ResolvedLayoutIssueV2> issues;
if(!parsed->validate(VoxelForgeCore::ResolvedLayoutValidationModeV3::strict,issues,error))
return false;
out=std::move(*parsed);
return true;
}
inline bool ValidateExportedCorePlanMatchesOwner(const FStandaloneOwnerWorld& owner,
const VoxelForgeCore::WorldAssemblyManifest& assembly,
const VoxelForgeCore::ResolvedLayoutSnapshotV3& layout,std::string& error)
{
using namespace VoxelForgeCore;
if(!owner.Manager||assembly.recipe.seed!=static_cast<std::uint32_t>(owner.Seed)
||assembly.recipe.layoutChunkWidthSubvoxels!=owner.StrateLayoutChunkWidthSubvoxels
||layout.strateLayoutChunkWidthSubvoxels!=owner.StrateLayoutChunkWidthSubvoxels
||layout.strateLayoutChunkSizeMicrometres!=owner.StrateLayoutChunkSizeMicrometres
||layout.ownerVoxelSizeMicrometres!=owner.OwnerVoxelSizeMicrons
||layout.coreVoxelSizeMicrometres!=owner.CoreVoxelSizeMicrons
||layout.strates.size()!=static_cast<std::size_t>(owner.Manager->GetLayout().Num()))
{error="Unreal-resolved Core plan metadata does not match the exported owner settings/layout";return false;}
for(const auto& island:assembly.floatingIslands)
{
if(island.manifest.recipe.layoutChunkWidthSubvoxels
!=owner.StrateLayoutChunkWidthSubvoxels)
{error="Unreal-resolved floating-island plan has a stale layout chunk width";return false;}
}
for(const FStrateSlot& slot:owner.Manager->GetLayout())
{
if(!slot.Definition)continue;
const auto type=owner.Manager->GetGeneratorTypeForChunk(FIntVector(0,0,slot.TopChunkZ));
const auto resolved=std::find_if(layout.strates.begin(),layout.strates.end(),
[&](const auto& item){return item.strateIndex==slot.StrateIndex;});
const std::int64_t expectedBottom=static_cast<std::int64_t>(slot.BottomChunkZ)
*owner.StrateLayoutChunkSizeMicrometres;
const std::int64_t expectedTop=static_cast<std::int64_t>(slot.TopChunkZ+1)
*owner.StrateLayoutChunkSizeMicrometres;
if(resolved==layout.strates.end()
||resolved->interiorBottomMicrometres!=expectedBottom
||resolved->interiorTopMicrometres!=expectedTop)
{error="Unreal-resolved Core layout bounds do not match exported slot "+std::to_string(slot.StrateIndex);return false;}
if(type==ECaveGeneratorType::SurfaceWorld)
{
const auto plan=std::find_if(assembly.plan.strates.begin(),assembly.plan.strates.end(),
[&](const auto& item){return item.strateIndex==slot.StrateIndex;});
if(plan==assembly.plan.strates.end()||plan->topChunkZ!=slot.TopChunkZ
||plan->bottomChunkZ!=slot.BottomChunkZ)
{error="Unreal-resolved SurfaceWorld plan bounds do not match exported slot "+std::to_string(slot.StrateIndex);return false;}
}
else if(type==ECaveGeneratorType::FloatingIslands)
{
const auto plan=std::find_if(assembly.floatingIslands.begin(),assembly.floatingIslands.end(),
[&](const auto& item){return item.strateIndex==slot.StrateIndex;});
// A missing FI plan is the explicit compiled-analytic dispatch path.
// Validate exact live-slot bounds whenever an imported native plan exists.
if(plan!=assembly.floatingIslands.end()&&(plan->topChunkZ!=slot.TopChunkZ
||plan->bottomChunkZ!=slot.BottomChunkZ))
{error="Unreal-resolved floating-island bounds do not match exported slot "+std::to_string(slot.StrateIndex);return false;}
}
}
return true;
}
inline bool BuildResolvedLayoutSnapshot(const FStandaloneOwnerWorld& owner,
const VoxelForgeCore::WorldAssemblyManifest& assembly,std::string_view recipeVariant,
VoxelForgeCore::ResolvedLayoutSnapshotV3& out,std::string& error)
+3 -2
View File
@@ -31,6 +31,7 @@ LINUX58 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux58"
LINUX60 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux60"
LINUX67 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux67"
LINUX68 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux68"
LINUX70 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux70"
OWNER = ROOT / "Standalone/data/regression/owner_world_2strate_l61.json"
OWNER_NEW = ROOT / "Standalone/data/owner_world.json"
OWNER_2STRATE_SHA256 = "7b095f9bcc6b90133d5a463f99f0b571133b2c549ce1ecf2d64fe9175e41e183"
@@ -107,8 +108,8 @@ def owner_hash_baseline(recipe: str, style: int) -> tuple[Path, str]:
return (LINUX67 / "hash-baselines" / "owner-hash-surface-world-style1-v212.log",
"L67-v212")
if recipe == "floating-islands" and style == 2:
return (LINUX68 / "hash-baselines" / "owner-hash-floating-islands-style2-v213.log",
"L68-v213")
return (LINUX70 / "hash-baselines" / "owner-hash-floating-islands-style2-v214.log",
"L70-v214")
raise VerificationFailure(f"no pinned owner hash baseline for {recipe} style {style}")
+1 -1
View File
@@ -1 +1 @@
{"schema_version":1,"source":"VoxelForgeExplore standalone base-world export","voxel_size_cm":25,"seed":0,"open_surface_entry":true,"origin_spine_radius":28,"world_radius_voxels":0,"edge_seal_thickness":128,"total_strates":4,"inter_strate_gap_chunks":0,"clip_radius":6,"max_clip_level":6,"full_res_clip_levels":2,"coarse_tile_cells":16,"render_distance_chunks":1536,"generate_skirts":true,"skirt_cells":4,"lod_octave_drop":1,"strate_content_cut_min_level":9,"settings_asset":{"AssetBundleData":{"Bundles":[]},"bClampViewToStrate":true,"bDebugDrawDensityVolume":false,"bDensityVolumeGPUUpload":false,"bEnableDensityVolume":false,"bGenerateSkirts":true,"bOpenSurfaceEntry":true,"bUseWorldAssemblyManifestOverride":false,"ClipRadius":6,"CoarseTileCells":16,"CurrentSeason":1,"DecorationColumnDepthVoxels":320,"DecorationFarSpacingVoxels":8,"DecorationMarchStepVoxels":4,"DecorationMaxCrossingsPerColumn":4,"DecorationNearRadiusChunks":6,"DecorationRadiusChunks":12,"DecorationRegionSizeCells":8,"DecorationSpacingVoxels":8,"DensityVolumeDebugRadiusCells":12,"DensityVolumeFillSlabCells":8,"DensityVolumeLevels":3,"DensityVolumeMarchSteps":64,"DensityVolumeResolution":256,"EdgeSealThickness":128,"FixedStrates":[{"key":0,"value":"/Game/VoxelForge/DA_Strate1.DA_Strate1"},{"key":1,"value":"/Game/VoxelForge/DA_Strate2.DA_Strate2"},{"key":2,"value":"/Game/VoxelForge/DA_Strate3.DA_Strate3"},{"key":3,"value":"/Game/VoxelForge/DA_Strate4.DA_Strate4"}],"FullResClipLevels":2,"InterStrateGapChunks":0,"InterStrateGapMeters":0,"LODOctaveDrop":1,"MaxBrushRadius":30,"MaxClipLevel":6,"MaxConcurrentDecorationTasks":4,"MaxConcurrentTasks":16,"MaxDecorationCellsPerFrame":2,"MaxGenerationWorkerCores":0,"MaxMeshAppliesPerFrame":4,"MaxMeshApplyMilliseconds":2,"MaxModifications":0,"MaxTotalVolume":0,"MaxUnloadsPerFrame":16,"NativeClass":"/Script/VoxelForge.VoxelSettings","NearTaskReserve":4,"OriginSpineRadius":28,"PawnCollisionRadiusChunks":2,"RenderDistanceChunks":1536,"Season":"","Seed":0,"SkirtCells":4,"SourceWorldAssemblyManifestJson":{"FilePath":"../../../../../../Projet Unreal/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Round3/results/world_assembly_floating_islands.json"},"StrateContentCutMinLevel":9,"StrateLayoutChunkSizeMeters":8,"StratePool":[],"StrateViewMarginChunks":6,"TotalStrates":4,"ViewDistanceDown":10,"ViewDistanceUp":10,"ViewDistanceXY":32,"VoxelMaterial":"/Game/VoxelForge/M_Test1_Inst.M_Test1_Inst","WorldAssemblyManifestHash":"94b563f1ce622def","WorldAssemblyManifestJson":"{\"schema_version\":1,\"content_hash\":\"94b563f1ce622def\",\"recipe\":{\"schema_version\":1,\"evaluator_version\":4,\"units_per_voxel\":256,\"seed\":0,\"biome_cell_size_q\":204800,\"biome_warp_q\":64000,\"biome_warp_wavelength_q\":142222,\"biome_border_blend_q\":30720,\"climate_relief_wavelength_q\":853333,\"climate_moisture_wavelength_q\":640000,\"climate_relief_contrast_q16\":131072,\"content_hash\":\"c37de78b759c0a4c\",\"biomes\":[{\"id\":4097,\"base_height_q\":-516096,\"continent_amplitude_q\":128000,\"continent_wavelength_q\":256000,\"mountain_amplitude_q\":0,\"mountain_wavelength_q\":128000,\"detail_amplitude_q\":512,\"detail_wavelength_q\":6400,\"relief_min_q16\":0,\"relief_max_q16\":19661,\"moisture_min_q16\":0,\"moisture_max_q16\":19661,\"relief_strength_q16\":6554,\"relief_contrast_q16\":104858,\"relief_wavelength_q\":2560000,\"height_warp_strength_q\":12288,\"height_warp_wavelength_q\":32000,\"beach_width_q\":3072,\"cliff_strength_q16\":0,\"cliff_slope_threshold_q16\":32768,\"cliff_sharpness_q16\":131072,\"cliff_sample_distance_q\":512,\"cliff_max_displacement_q\":0,\"cap_enabled\":true,\"cap_height_q\":-149094,\"cap_warp_strength_q\":0,\"cap_warp_wavelength_q\":25600,\"cap_undulation_q\":256000,\"cap_wavelength_q\":1280000,\"cap_detail_amplitude_q\":2560,\"cap_detail_wavelength_q\":25600,\"cap_ridge_amplitude_q\":0,\"cap_ridge_wavelength_q\":12800},{\"id\":4098,\"base_height_q\":-484639,\"continent_amplitude_q\":128000,\"continent_wavelength_q\":256000,\"mountain_amplitude_q\":128000,\"mountain_wavelength_q\":512000,\"detail_amplitude_q\":512,\"detail_wavelength_q\":25600,\"relief_min_q16\":52429,\"relief_max_q16\":65536,\"moisture_min_q16\":52429,\"moisture_max_q16\":65536,\"relief_strength_q16\":45875,\"relief_contrast_q16\":104858,\"relief_wavelength_q\":170667,\"height_warp_strength_q\":12288,\"height_warp_wavelength_q\":25600,\"beach_width_q\":3072,\"cliff_strength_q16\":65536,\"cliff_slope_threshold_q16\":19661,\"cliff_sharpness_q16\":327680,\"cliff_sample_distance_q\":5120,\"cliff_max_displacement_q\":2570240,\"cap_enabled\":true,\"cap_height_q\":-149094,\"cap_warp_strength_q\":0,\"cap_warp_wavelength_q\":25600,\"cap_undulation_q\":230400,\"cap_wavelength_q\":1280000,\"cap_detail_amplitude_q\":2560,\"cap_detail_wavelength_q\":25600,\"cap_ridge_amplitude_q\":0,\"cap_ridge_wavelength_q\":12800},{\"id\":4099,\"base_height_q\":-516096,\"continent_amplitude_q\":20480,\"continent_wavelength_q\":85333,\"mountain_amplitude_q\":0,\"Line truncated
{"schema_version":1,"source":"VoxelForgeExplore standalone base-world export","voxel_size_cm":25,"seed":0,"open_surface_entry":true,"origin_spine_radius":28,"world_radius_voxels":0,"edge_seal_thickness":128,"total_strates":4,"inter_strate_gap_chunks":0,"clip_radius":6,"max_clip_level":6,"full_res_clip_levels":2,"coarse_tile_cells":16,"render_distance_chunks":1536,"generate_skirts":true,"skirt_cells":4,"lod_octave_drop":1,"strate_content_cut_min_level":9,"settings_asset":{"AssetBundleData":{"Bundles":[]},"bClampViewToStrate":true,"bDebugDrawDensityVolume":false,"bDensityVolumeGPUUpload":false,"bEnableDensityVolume":false,"bGenerateSkirts":true,"bOpenSurfaceEntry":true,"bUseWorldAssemblyManifestOverride":false,"ClipRadius":6,"CoarseTileCells":16,"CurrentSeason":1,"DecorationColumnDepthVoxels":320,"DecorationFarSpacingVoxels":8,"DecorationMarchStepVoxels":4,"DecorationMaxCrossingsPerColumn":4,"DecorationNearRadiusChunks":6,"DecorationRadiusChunks":12,"DecorationRegionSizeCells":8,"DecorationSpacingVoxels":8,"DensityVolumeDebugRadiusCells":12,"DensityVolumeFillSlabCells":8,"DensityVolumeLevels":3,"DensityVolumeMarchSteps":64,"DensityVolumeResolution":256,"EdgeSealThickness":128,"FixedStrates":[{"key":0,"value":"/Game/VoxelForge/DA_Strate1.DA_Strate1"},{"key":1,"value":"/Game/VoxelForge/DA_Strate2.DA_Strate2"},{"key":2,"value":"/Game/VoxelForge/DA_Strate3.DA_Strate3"},{"key":3,"value":"/Game/VoxelForge/DA_Strate4.DA_Strate4"}],"FullResClipLevels":2,"InterStrateGapChunks":0,"InterStrateGapMeters":0,"LODOctaveDrop":1,"MaxBrushRadius":30,"MaxClipLevel":6,"MaxConcurrentDecorationTasks":4,"MaxConcurrentTasks":16,"MaxDecorationCellsPerFrame":2,"MaxGenerationWorkerCores":0,"MaxMeshAppliesPerFrame":4,"MaxMeshApplyMilliseconds":2,"MaxModifications":0,"MaxTotalVolume":0,"MaxUnloadsPerFrame":16,"NativeClass":"/Script/VoxelForge.VoxelSettings","NearTaskReserve":4,"OriginSpineRadius":28,"PawnCollisionRadiusChunks":2,"RenderDistanceChunks":1536,"Season":"","Seed":0,"SkirtCells":4,"SourceWorldAssemblyManifestJson":{"FilePath":"../../../../../../Projet Unreal/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Round3/results/world_assembly_floating_islands.json"},"StrateContentCutMinLevel":9,"StrateLayoutChunkSizeMeters":8,"StratePool":[],"StrateViewMarginChunks":6,"TotalStrates":4,"ViewDistanceDown":10,"ViewDistanceUp":10,"ViewDistanceXY":32,"VoxelMaterial":null,"WorldAssemblyManifestHash":"94b563f1ce622def","WorldAssemblyManifestJson":"{\"schema_version\":1,\"content_hash\":\"94b563f1ce622def\",\"recipe\":{\"schema_version\":1,\"evaluator_version\":4,\"units_per_voxel\":256,\"seed\":0,\"biome_cell_size_q\":204800,\"biome_warp_q\":64000,\"biome_warp_wavelength_q\":142222,\"biome_border_blend_q\":30720,\"climate_relief_wavelength_q\":853333,\"climate_moisture_wavelength_q\":640000,\"climate_relief_contrast_q16\":131072,\"content_hash\":\"c37de78b759c0a4c\",\"biomes\":[{\"id\":4097,\"base_height_q\":-516096,\"continent_amplitude_q\":128000,\"continent_wavelength_q\":256000,\"mountain_amplitude_q\":0,\"mountain_wavelength_q\":128000,\"detail_amplitude_q\":512,\"detail_wavelength_q\":6400,\"relief_min_q16\":0,\"relief_max_q16\":19661,\"moisture_min_q16\":0,\"moisture_max_q16\":19661,\"relief_strength_q16\":6554,\"relief_contrast_q16\":104858,\"relief_wavelength_q\":2560000,\"height_warp_strength_q\":12288,\"height_warp_wavelength_q\":32000,\"beach_width_q\":3072,\"cliff_strength_q16\":0,\"cliff_slope_threshold_q16\":32768,\"cliff_sharpness_q16\":131072,\"cliff_sample_distance_q\":512,\"cliff_max_displacement_q\":0,\"cap_enabled\":true,\"cap_height_q\":-149094,\"cap_warp_strength_q\":0,\"cap_warp_wavelength_q\":25600,\"cap_undulation_q\":256000,\"cap_wavelength_q\":1280000,\"cap_detail_amplitude_q\":2560,\"cap_detail_wavelength_q\":25600,\"cap_ridge_amplitude_q\":0,\"cap_ridge_wavelength_q\":12800},{\"id\":4098,\"base_height_q\":-484639,\"continent_amplitude_q\":128000,\"continent_wavelength_q\":256000,\"mountain_amplitude_q\":128000,\"mountain_wavelength_q\":512000,\"detail_amplitude_q\":512,\"detail_wavelength_q\":25600,\"relief_min_q16\":52429,\"relief_max_q16\":65536,\"moisture_min_q16\":52429,\"moisture_max_q16\":65536,\"relief_strength_q16\":45875,\"relief_contrast_q16\":104858,\"relief_wavelength_q\":170667,\"height_warp_strength_q\":12288,\"height_warp_wavelength_q\":25600,\"beach_width_q\":3072,\"cliff_strength_q16\":65536,\"cliff_slope_threshold_q16\":19661,\"cliff_sharpness_q16\":327680,\"cliff_sample_distance_q\":5120,\"cliff_max_displacement_q\":2570240,\"cap_enabled\":true,\"cap_height_q\":-149094,\"cap_warp_strength_q\":0,\"cap_warp_wavelength_q\":25600,\"cap_undulation_q\":230400,\"cap_wavelength_q\":1280000,\"cap_detail_amplitude_q\":2560,\"cap_detail_wavelength_q\":25600,\"cap_ridge_amplitude_q\":0,\"cap_ridge_wavelength_q\":12800},{\"id\":4099,\"base_height_q\":-516096,\"continent_amplitude_q\":20480,\"continent_wavelength_q\":85333,\"mountain_amplitude_q\":0,\"mountain_wavelength_q\":128000,\"detail_Line truncated