From 4f93f3fffb18533bb235658d40b85fa23c90ff97 Mon Sep 17 00:00:00 2001 From: Fr0zka Date: Sun, 1 Nov 2026 08:08:40 +0100 Subject: [PATCH] research: Floating Islands planned around fixed tunnels (L140, 0/16; kept as patch) Native FI binds and its own route/clearance/mouth-support checks pass on seeds 0 and 10, but 14/16 seeds have no island arrangement that clears the fixed passage tubes and reaches both mouth heights; seed 10 has one composed collision; ripple 6-7 cm vs the 3.5 cm limit on both upper passages. Third failure of the 'islands adapt to fixed tunnels' premise (L133 x2, L140). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1 --- .../WorldAssemblerM3/Linux140/REPORT.md | 34 + .../Linux140/RunL140Captures.py | 224 +++ .../Linux140/RunL140Determinism.py | 100 ++ .../Linux140/RunL140SeedSweep.py | 111 ++ .../Linux140/RunL140Timing.py | 153 ++ .../RunL140SeedSweep.cpython-313.pyc | Bin 0 -> 9159 bytes .../baselines/native-owner-fi-seed0.json | 201 +++ .../Linux140/captures/after-arrival-mouth.jpg | Bin 0 -> 20205 bytes .../captures/after-departure-mouth.jpg | Bin 0 -> 23901 bytes .../Linux140/captures/after-island-edge.jpg | Bin 0 -> 19984 bytes .../captures/after-walk-between-islands.jpg | Bin 0 -> 20752 bytes .../captures/after-wide-silhouette.jpg | Bin 0 -> 22894 bytes .../captures/before-arrival-mouth.jpg | Bin 0 -> 13808 bytes .../captures/before-departure-mouth.jpg | Bin 0 -> 17309 bytes .../Linux140/captures/before-island-edge.jpg | Bin 0 -> 15208 bytes .../captures/before-walk-between-islands.jpg | Bin 0 -> 15126 bytes .../captures/before-wide-silhouette.jpg | Bin 0 -> 15268 bytes .../Linux140/captures/manifest.json | 229 +++ .../Linux140/l140-fi-around-tunnels.patch | 1279 +++++++++++++++++ 19 files changed, 2331 insertions(+) create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/REPORT.md create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/RunL140Captures.py create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/RunL140Determinism.py create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/RunL140SeedSweep.py create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/RunL140Timing.py create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/__pycache__/RunL140SeedSweep.cpython-313.pyc create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/baselines/native-owner-fi-seed0.json create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/captures/after-arrival-mouth.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/captures/after-departure-mouth.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/captures/after-island-edge.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/captures/after-walk-between-islands.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/captures/after-wide-silhouette.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/captures/before-arrival-mouth.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/captures/before-departure-mouth.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/captures/before-island-edge.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/captures/before-walk-between-islands.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/captures/before-wide-silhouette.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/captures/manifest.json create mode 100644 Standalone/Research/WorldAssemblerM3/Linux140/l140-fi-around-tunnels.patch diff --git a/Standalone/Research/WorldAssemblerM3/Linux140/REPORT.md b/Standalone/Research/WorldAssemblerM3/Linux140/REPORT.md new file mode 100644 index 0000000..449e31e --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux140/REPORT.md @@ -0,0 +1,34 @@ +# L140 — Floating Islands planned around passages + +**Not accepted: 0/16 composed seeds passed.** The new Core recipe reaches native S1 dispatch and meets its dedicated route, passage-clearance, and mouth-support checks on seeds 0 and 10. Seed 10 still has one blocked capsule in the composed owner route; both seeds fail the unchanged passage-ripple gate. Fourteen seeds cannot produce a corridor-aware plan. + +## Change + +Core evaluator version is 239 and Floating Islands geometry version is 10. The owner adapter resolves the fixed passage layout first, then plans nine native islands and a walk route around the 0–1 arrival and 1–2 departure tubes. The plan records route and island anchors in the resolved layout. The clearance check reserves the 1.053 m passage influence reach plus the 0.880 m capsule half-height and checks five support probes at each mouth. Shape composition preserves native landing support and passage shell distance for this recipe. Direct legacy recipe fixtures retain their earlier attach-before-layout order. + +S1 binds to `FloatingIslands-native` in the explicit Core owner mode. `bUseVoxelForgeCore` remains opt-in; the fast-tier default owner pose still reports the legacy analytic S1 path. + +## Composed sweep + +The final-source Clang run covered seeds 0–15. Results and per-seed logs are in [`summary.json`](../../../../Saved/Linux/l140/seeds/summary.json) and `Saved/Linux/l140/seeds/` (source stamp `6205e6c180ef32c41792dc3e0d8bf443a96df41974f40334af4bf3a157ab88da`). + +- **Seed 0:** the planner tried 11 detours; its 94.5 m route has 1.47 m conservative tube clearance. Native route audit: 128 points, 0 blocked capsule samples, 0 unsupported points, 0 grade failures. Passage check: 5,325 tube samples, 0 island conflicts, 676,275 route checks, 0 route conflicts, arrival and departure support 5/5, 2.824 m minimum excess clearance. The composed S1 route and seams pass. Ripple is 1/3: wall ripple is 6.85 cm on 0–1 and 7.10 cm on 1–2 against the unchanged 3.50 cm limit. +- **Seed 10:** the native route and passage checks pass, with 5/5 mouth support and 0 isolated route conflicts. The composed S1 capsule audit finds one blocked sample at `(-6.246, -28.615, -737.982) m`, inside the resolved 0–1 passage; composed density is `-0.002062` while native island density is `+1.730469`. Ripple is again 1/3 (6.22 cm on 0–1 and 7.19 cm on 1–2). Seams and negative controls pass. +- **Seeds 1, 2, 7, 8, 9, 12, 13, 15:** no candidate clears the tubes; best conservative clearances range from −5.994 m to −0.406 m. **Seeds 3, 5, 6, 14:** candidates clear the tubes but the supported island profile cannot reach both fixed mouth heights. **Seeds 4 and 11:** candidate islands escape the sealed vertical layout. + +The dedicated gate is therefore 0/16. No geometry variant was attempted after these results. The repeated 0–1/1–2 ripple failure is also consistent with L67's closed authored-radius experiment: it measured 7.27 cm on 1–2 against the same 3.50 cm limit ([L67 report](../../Linux67/REPORT.md)). + +## Other checks + +- **Fast tier:** PASS, 287.8 s; negative controls and existing worker-hash checks passed. It continues to verify the default legacy S1 dispatch. +- **Determinism:** PASS, six runs (Clang/GCC × W1/W8/W12). All produced the same 512-tile density, mesh, payload, topology, material, and exact-query hashes, with layout identity `resolved-layout-v3-fnv64:08da20d55ff6820f`. Native recipe hash: `0b6a23bc73a3b867`. See the [baseline](baselines/native-owner-fi-seed0.json) and [`summary.json`](../../../../Saved/Linux/l140/determinism/summary.json). +- **Captures:** ten before/after JPEGs passed the existing image-quality gate. The [manifest](captures/manifest.json) records eye-height arrival, island edge, route between islands, departure, and wide silhouette views for both versions. See [before](captures/before-arrival-mouth.jpg), [before edge](captures/before-island-edge.jpg), [before route](captures/before-walk-between-islands.jpg), [before departure](captures/before-departure-mouth.jpg), [before wide](captures/before-wide-silhouette.jpg); [after](captures/after-arrival-mouth.jpg), [after edge](captures/after-island-edge.jpg), [after route](captures/after-walk-between-islands.jpg), [after departure](captures/after-departure-mouth.jpg), [after wide](captures/after-wide-silhouette.jpg). +- **Linux VFHostEditor:** PASS in 73.58 s. Build log: [`ubt.log`](../../../../Saved/Linux/l140/ubt.log). +- **L80 timing:** not completed. The machine gate passed (load 0.97, 2-second CPU idle 98.5%), but the candidate warm-up could not construct native S1 around the checked-in Unreal-exported passage layout: 0 detours, best clearance −3.509 m. No measured L80 pairs were recorded; the ±1% A/A floor remains the L137 reference. A separate 30-second setup probe with a regenerated seed-0 owner plan timed out during passage-route planning, so I did not run a mismatched or incomplete timing matrix. +- `git diff --check`: PASS. + +## Remaining issues + +The fixed exported owner layout and many generated seeds leave no route-clear island arrangement. On seed 10, the native-only clearance check also misses a collision that the final composed owner route catches. Ripple remains above the existing limit on both upper passages. Native S1 is still opt-in and is not promoted by this round. + +Changed Unreal source: [`VoxelForgeCoreAdapter.cpp`](../../../../Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp). Windows compilation remains for the owner. diff --git a/Standalone/Research/WorldAssemblerM3/Linux140/RunL140Captures.py b/Standalone/Research/WorldAssemblerM3/Linux140/RunL140Captures.py new file mode 100644 index 0000000..1e300ba --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux140/RunL140Captures.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python3 +"""Capture comparable player-height and wide views of owner S1 before and after L140.""" +from __future__ import annotations + +import json +import argparse +import math +import os +import re +import subprocess +import sys +import time +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[4] +DATA = ROOT / "Standalone/data/owner_world.json" +LAYOUT = ROOT / "Saved/Linux/l140/seeds/seed0-composed-layout.json" +OUT = ROOT / "Saved/Linux/l140/captures" +ARTIFACTS = ROOT / "Standalone/Research/WorldAssemblerM3/Linux140/captures" +LIMIT = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--"] +STAMP_RE = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=([0-9a-f]{64})$", re.M) +VERSIONS = { + "before-head": { + "headless": ROOT / "Saved/Linux/l139/bin/VoxelForgeCoreHeadless-l139-clang", + "renderer": ROOT / "Saved/Linux/l139/bin/VoxelForgeOffscreenCapture-l139-clang", + "stamp": "b8603b6cb3975ca0f9669759e4e2464561c557fdb7aa6836acef123ecf0b99d1", + "native": False, + }, + "after-l140": { + "headless": ROOT / "Saved/Linux/l140/bin/VoxelForgeCoreHeadless-l140-clang", + "renderer": ROOT / "Saved/Linux/l140/bin/VoxelForgeOffscreenCapture-l140-clang", + "stamp": "6205e6c180ef32c41792dc3e0d8bf443a96df41974f40334af4bf3a157ab88da", + "native": True, + }, +} + + +def fmt(values: tuple[float, ...]) -> str: + return ",".join(f"{value:.6f}" for value in values) + + +def angles(camera: tuple[float, float, float], target: tuple[float, float, float]) -> tuple[float, float]: + dx, dy, dz = (target[i] - camera[i] for i in range(3)) + return math.degrees(math.atan2(dx, dy)), math.degrees(math.atan2(dz, math.hypot(dx, dy))) + + +def stamped_run(name: str, command: list[str], log: Path, expected: str, + env: dict[str, str]) -> str: + binary = Path(command[0]) + probe = subprocess.run([*LIMIT, "timeout", "15s", str(binary), "--print-source-stamp"], + cwd=ROOT, env=env, text=True, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, check=False, timeout=20) + match = STAMP_RE.search(probe.stdout or "") + if probe.returncode != 0 or not match or match.group(1) != expected: + raise RuntimeError(f"{name}: executable stamp mismatch for {binary}") + log.parent.mkdir(parents=True, exist_ok=True) + started = time.monotonic() + with log.open("w", encoding="utf-8") as stream: + result = subprocess.run([*LIMIT, "timeout", "1740s", *map(str, command)], + cwd=ROOT, env=env, stdout=stream, stderr=subprocess.STDOUT, + timeout=1745, check=False) + output = log.read_text(encoding="utf-8", errors="replace") + emitted = STAMP_RE.search(output) + if result.returncode != 0 or not emitted or emitted.group(1) != expected: + raise RuntimeError(f"{name}: process failed or source changed; see {log}") + print(f"[L140CaptureRun] step={name} elapsed_s={time.monotonic()-started:.1f} " + f"log={log.relative_to(ROOT)}", flush=True) + return output + + +def qpoint(values: list[int], scale_m: float) -> tuple[float, float, float]: + return tuple(value * scale_m for value in values[:3]) + + +def make_views(layout: dict) -> list[dict[str, object]]: + scale_m = layout["core_voxel_size_um"] / 1_000_000.0 / 256.0 + strate = next(row for row in layout["strates"] if row["strate_index"] == 1) + anchors = strate["anchors"] + route = [qpoint(row["values"], scale_m) for row in anchors if row["kind"] == "route_point"] + islands = [row for row in anchors if row["kind"] == "island_anchor"] + if len(route) < 8 or len(islands) < 5: + raise ValueError("seed-0 resolved layout lacks a complete S1 route or island chain") + + def tangent(index: int) -> tuple[float, float]: + a, b = route[max(0, index - 1)], route[min(len(route) - 1, index + 1)] + dx, dy = b[0] - a[0], b[1] - a[1] + length = max(1e-9, math.hypot(dx, dy)) + return dx / length, dy / length + + def eye(point: tuple[float, float, float]) -> tuple[float, float, float]: + return point[0], point[1], point[2] + 1.45 + + i = len(route) // 3 + tx, ty = tangent(i) + arrival_t = tangent(0) + departure_t = tangent(len(route) - 1) + arrival, departure = route[0], route[-1] + arrival_camera = eye((arrival[0] - 2.5 * arrival_t[0], arrival[1] - 2.5 * arrival_t[1], arrival[2])) + arrival_target = eye((arrival[0] + 8.0 * arrival_t[0], arrival[1] + 8.0 * arrival_t[1], arrival[2])) + departure_camera = eye((departure[0] - 2.5 * departure_t[0], departure[1] - 2.5 * departure_t[1], departure[2])) + departure_target = eye((departure[0] + 8.0 * departure_t[0], departure[1] + 8.0 * departure_t[1], departure[2])) + edge_point = route[i] + edge_camera = eye((edge_point[0] + 6.0 * ty, edge_point[1] - 6.0 * tx, edge_point[2])) + edge_target = (edge_point[0] + 4.0 * tx, edge_point[1] + 4.0 * ty, edge_point[2] + 0.35) + centers = [qpoint(row["values"], scale_m) for row in islands] + middle_index = len(route) // 2 + midpoint = route[middle_index] + mid_t = tangent(middle_index) + walk_camera = eye((midpoint[0] - 2.0 * mid_t[0], midpoint[1] - 2.0 * mid_t[1], midpoint[2])) + next_island_index = min(len(centers) - 1, 5) + next_island_top = centers[next_island_index][2] + islands[next_island_index]["values"][4] * scale_m + walk_target = (centers[next_island_index][0], centers[next_island_index][1], next_island_top + 0.5) + walk_focus = tuple((centers[4][axis] + centers[5][axis]) * 0.5 for axis in range(3)) + (18.0,) + cx = sum(p[0] for p in centers) / len(centers) + cy = sum(p[1] for p in centers) / len(centers) + cz = sum(p[2] + row["values"][4] * scale_m for p, row in zip(centers, islands)) / len(centers) + wide_camera = (cx, cy + 23.0, cz + 10.0) + wide_target = (cx, cy, cz) + return [ + {"name": "arrival-mouth", "camera": arrival_camera, "target": arrival_target, + "focus": (*arrival, 14.0), "note": "player eye at the fixed 0-1 arrival mouth"}, + {"name": "island-edge", "camera": edge_camera, "target": edge_target, + "focus": (*edge_point, 18.0), "note": "player eye beside the route on an island edge"}, + {"name": "walk-between-islands", "camera": walk_camera, "target": walk_target, + "focus": walk_focus, "note": "player eye looking from one route landing toward the next island"}, + {"name": "departure-mouth", "camera": departure_camera, "target": departure_target, + "focus": (*departure, 14.0), "note": "player eye approaching the fixed 1-2 departure mouth"}, + {"name": "wide-silhouette", "camera": wide_camera, "target": wide_target, + "focus": (cx, cy, cz, 48.0), "fov": 72.0, + "note": "wide side view showing the island chain silhouette"}, + ] + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--views", nargs="*", default=None, + help="optional view names to rerender in both phases") + args = parser.parse_args() + if not DATA.is_file() or not LAYOUT.is_file(): + raise SystemExit("missing owner fixture or final seed-0 resolved layout") + layout = json.loads(LAYOUT.read_text(encoding="utf-8")) + views = make_views(layout) + if args.views: + unknown = set(args.views) - {str(view["name"]) for view in views} + if unknown: + raise SystemExit(f"unknown capture views: {sorted(unknown)}") + views = [view for view in views if view["name"] in set(args.views)] + OUT.mkdir(parents=True, exist_ok=True) + ARTIFACTS.mkdir(parents=True, exist_ok=True) + env = os.environ.copy() + env["LP_NUM_THREADS"] = "12" + env["XDG_CACHE_HOME"] = str(OUT / "xdg-cache") + quality = ROOT / "Standalone/Tools/verify/capture_quality.py" + manifest: list[dict[str, object]] = [] + old_manifest_path = ARTIFACTS / "manifest.json" + existing = json.loads(old_manifest_path.read_text(encoding="utf-8")) \ + if old_manifest_path.is_file() else {"captures": []} + rerendered = {str(view["name"]) for view in views} + for row in existing.get("captures", []): + if row.get("view") not in rerendered: + manifest.append(row) + for version, config in VERSIONS.items(): + phase = "before" if version.startswith("before") else "after" + for view in views: + name = str(view["name"]) + camera, target = view["camera"], view["target"] + assert isinstance(camera, tuple) and isinstance(target, tuple) + yaw, pitch = angles(camera, target) + mesh_dir = OUT / "meshes" / phase + mesh_dir.mkdir(parents=True, exist_ok=True) + mesh = mesh_dir / f"{name}.vfmesh" + capture_layout = mesh_dir / f"{name}-layout.json" + flags = ["--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline", + "--workers=12", "--clip-radius=6", "--max-clip-level=0", "--max-level=0", + "--force-generate", "--seed=0", "--recipe=surface-world", + "--render-distance-chunks=0", f"--camera={fmt((*camera,yaw,pitch))}", + f"--resolved-layout-output={capture_layout}", f"--mesh-export={mesh}"] + if config["native"]: + flags.extend(["--native-owner-fi", "--density-dispatch-report"]) + export = [config["headless"], DATA, *flags] + stamped_run(f"{phase}-{name}-export", list(map(str, export)), + OUT / f"{phase}-{name}-export.log", config["stamp"], env) + if not mesh.is_file() or mesh.stat().st_size == 0: + raise RuntimeError(f"{phase}-{name}: empty mesh export") + png = OUT / f"{phase}-{name}.png" + jpg = ARTIFACTS / f"{phase}-{name}.jpg" + focus = view["focus"] + assert isinstance(focus, tuple) + fov = float(view.get("fov", 78.0)) + render = [config["renderer"], mesh, png, "--size=1280x720", + f"--fov-deg={fov:.1f}", f"--camera-m={fmt(camera)}", f"--yaw-deg={yaw:.6f}", + f"--pitch-deg={pitch:.6f}", "--tile-skirts=off", "--shade=readable", + "--headlamp=on", "--height-tint=on", "--height-center-m=-740", + "--height-range-m=70", "--tile-edges=off", f"--focus-region={fmt(focus)}"] + stamped_run(f"{phase}-{name}-render", list(map(str, render)), + OUT / f"{phase}-{name}-render.log", config["stamp"], env) + subprocess.run([*LIMIT, "timeout", "120s", "ffmpeg", "-nostdin", "-hide_banner", + "-loglevel", "error", "-y", "-i", png, "-frames:v", "1", "-q:v", "4", jpg], + cwd=ROOT, env=env, check=True, stdout=subprocess.DEVNULL, + stderr=subprocess.STDOUT, timeout=125) + check = subprocess.run([*LIMIT, "timeout", "120s", sys.executable, + quality, jpg], cwd=ROOT, env=env, text=True, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, check=False, timeout=125) + result = check.stdout.strip().splitlines()[-1] if check.stdout.strip() else f"exit={check.returncode}" + ok = check.returncode == 0 and "status=PASS" in check.stdout + manifest.append({"phase": phase, "view": name, "file": str(jpg.relative_to(ROOT)), + "bytes": jpg.stat().st_size, "camera_m": camera, "target_m": target, + "yaw_deg": yaw, "pitch_deg": pitch, "fov_deg": fov, + "note": view["note"], "quality_status": "PASS" if ok else "FAIL", "quality": result}) + print(f"[L140Capture] phase={phase} view={name} file={jpg.relative_to(ROOT)} " + f"quality={'PASS' if ok else 'FAIL'} {result}", flush=True) + manifest.sort(key=lambda row: (str(row["phase"]), str(row["view"]))) + summary = {"seed": 0, "source_stamp": VERSIONS["after-l140"]["stamp"], + "before_stamp": VERSIONS["before-head"]["stamp"], "views_per_phase": 5, + "all_quality_pass": all(row["quality_status"] == "PASS" for row in manifest), + "captures": manifest} + (ARTIFACTS / "manifest.json").write_text(json.dumps(summary, indent=2) + "\n", encoding="utf-8") + print(f"[L140CaptureSummary] views_per_phase={len(views)} captures={len(manifest)} " + f"all_quality_pass={summary['all_quality_pass']}", flush=True) + return 0 if summary["all_quality_pass"] else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/Standalone/Research/WorldAssemblerM3/Linux140/RunL140Determinism.py b/Standalone/Research/WorldAssemblerM3/Linux140/RunL140Determinism.py new file mode 100644 index 0000000..0e9a438 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux140/RunL140Determinism.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +"""Check native Floating Islands owner identity and hashes at W1/W8/W12.""" +from __future__ import annotations + +import json +import re +import subprocess +import time +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / "Saved/Linux/l140/determinism" +DATA = ROOT / "Standalone/data/owner_world.json" +STAMP = "6205e6c180ef32c41792dc3e0d8bf443a96df41974f40334af4bf3a157ab88da" +BINARIES = { + "clang": ROOT / "Saved/Linux/l140/bin/VoxelForgeCoreHeadless-l140-clang", + "gcc": ROOT / "Saved/Linux/l140/bin/VoxelForgeCoreHeadless-l140-gcc", +} +CAMERA = "25.836914,3.199219,-737.000000,0,0" +STAMP_RE = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=([0-9a-f]+)$", re.M) +HASH_RE = re.compile( + r"^\[Pipeline(?:FullDetailHash|WholeViewHash|MaterialHash|LODHash|ExactQueryHash)\].*$", + re.M) +NATIVE_FI = re.compile( + r"^\[DensityDispatch\] strate=1 generator=FloatingIslands " + r"recipe=FloatingIslands\.ClusterField version=10 " + r"bound_path=FloatingIslands-native adapter=FFloatingIslandFieldAdapter$", re.M) +FI_RECIPE_HASH = re.compile(r"^\[FloatingIslandWorldAssembly\].*recipe_hash=([0-9a-f]+) status=PASS$", re.M) +FI_CLEARANCE = re.compile(r"^\[FloatingIslandPassageClearance\].*status=PASS$", re.M) +FI_ROUTE_AUDIT = re.compile(r"^\[FloatingIslandRouteAudit\].*status=PASS$", re.M) + + +def main() -> int: + if not DATA.is_file() or any(not path.is_file() for path in BINARIES.values()): + raise SystemExit("missing L140 Clang/GCC determinism binary or owner fixture") + OUT.mkdir(parents=True, exist_ok=True) + rows: list[dict[str, object]] = [] + reference_hashes: list[str] | None = None + reference_identity: str | None = None + for compiler, binary in BINARIES.items(): + for workers in (1, 8, 12): + name = f"native-owner-fi-{compiler}-w{workers}" + log, layout = OUT / f"{name}.log", OUT / f"{name}.json" + command = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", + "timeout", "1740s", str(binary), str(DATA), "--world-assembler-prototype", + "--stream-benchmark", "--stream-pipeline", f"--workers={workers}", + "--clip-radius=3", "--max-clip-level=8", "--max-level=0", + f"--camera={CAMERA}", "--stream-hash", "--force-generate", "--seed=0", + "--recipe=surface-world", "--native-owner-fi", "--render-distance-chunks=0", + "--density-dispatch-report", f"--resolved-layout-output={layout}"] + started = time.monotonic() + with log.open("w", encoding="utf-8") as output: + proc = subprocess.run(command, cwd=ROOT, stdout=output, + stderr=subprocess.STDOUT, check=False, timeout=1740) + content = log.read_text(encoding="utf-8", errors="replace") + stamp = STAMP_RE.search(content) + hashes = HASH_RE.findall(content) + current_layout = json.loads(layout.read_text(encoding="utf-8")) if layout.is_file() else {} + identity = current_layout.get("stable_identity") + native_ok = bool(NATIVE_FI.search(content)) + plan_ok = ("[FloatingIslandRouteAudit]" in content + and "[FloatingIslandPassageClearance]" in content) + recipe_hash = FI_RECIPE_HASH.search(content) + clearance = FI_CLEARANCE.search(content) + route_audit = FI_ROUTE_AUDIT.search(content) + passed = (proc.returncode == 0 and stamp is not None and stamp.group(1) == STAMP + and len(hashes) >= 4 and native_ok and plan_ok and recipe_hash is not None + and clearance is not None and route_audit is not None and bool(identity)) + if reference_hashes is None and passed: + reference_hashes, reference_identity = hashes, identity + else: + passed = passed and hashes == reference_hashes and identity == reference_identity + row = {"compiler": compiler, "workers": workers, "exit": proc.returncode, + "source_stamp": stamp.group(1) if stamp else None, "hash_lines": hashes, + "layout_identity": identity, "native_fi_dispatch": native_ok, + "native_plan_audits": plan_ok, "floating_island_recipe_hash": + recipe_hash.group(1) if recipe_hash else None, + "passage_clearance_line": clearance.group(0) if clearance else None, + "route_audit_line": route_audit.group(0) if route_audit else None, + "passed": bool(passed), + "elapsed_s": round(time.monotonic() - started, 3), + "log": str(log.relative_to(ROOT)), "layout": str(layout.relative_to(ROOT))} + rows.append(row) + print("[L140DeterminismRun] " + json.dumps(row, sort_keys=True), flush=True) + (OUT / "runs-partial.json").write_text(json.dumps(rows, indent=2) + "\n") + if not passed: + (OUT / "summary.json").write_text(json.dumps({"status": "FAIL", "runs": rows}, indent=2) + "\n") + raise SystemExit(f"native owner determinism mismatch; see {log}") + summary = {"status": "PASS", "source_stamp": STAMP, + "layout_identity": reference_identity, "runs": rows} + (OUT / "summary.json").write_text(json.dumps(summary, indent=2) + "\n") + (ROOT / "Standalone/Research/WorldAssemblerM3/Linux140/baselines").mkdir(parents=True, exist_ok=True) + (ROOT / "Standalone/Research/WorldAssemblerM3/Linux140/baselines/native-owner-fi-seed0.json").write_text( + json.dumps(summary, indent=2) + "\n", encoding="utf-8") + print(f"[L140DeterminismSummary] runs={len(rows)} source_stamp={STAMP} status=PASS") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/Standalone/Research/WorldAssemblerM3/Linux140/RunL140SeedSweep.py b/Standalone/Research/WorldAssemblerM3/Linux140/RunL140SeedSweep.py new file mode 100644 index 0000000..d94d91e --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux140/RunL140SeedSweep.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 +"""Run the composed L140 owner gates for all requested seeds.""" +from __future__ import annotations + +import json +import re +import subprocess +import time +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / "Saved/Linux/l140/seeds" +BIN = ROOT / "Saved/Linux/l140/bin/VoxelForgeCoreHeadless-l140-clang" +DATA = ROOT / "Standalone/data/owner_world.json" +STAMP = "6205e6c180ef32c41792dc3e0d8bf443a96df41974f40334af4bf3a157ab88da" +STAMP_RE = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=([0-9a-f]+)$", re.M) +CHECKS = { + "native_dispatch": re.compile( + r"^\[DensityDispatch\] strate=1 generator=FloatingIslands " + r"recipe=FloatingIslands\.ClusterField version=10 " + r"bound_path=FloatingIslands-native adapter=FFloatingIslandFieldAdapter$", re.M), + "island_route": re.compile(r"^\[FloatingIslandRouteAudit\].*status=PASS$", re.M), + "passage_clearance": re.compile(r"^\[FloatingIslandPassageClearance\].*status=PASS$", re.M), + "strate1_route": re.compile( + r"^\[ResolvedStrateRouteAudit\] strate=1 .*blocked=0 .*unsupported=0 " + r"grade_failures=0 mouth_binding=PASS status=PASS$", re.M), + "route_summary": re.compile( + r"^\[ResolvedPassageAuditSummary\].*route_walkable=4 .*route_bindings=4 " + r"route_binding_failures=0 .*blocked_controls=3/3", re.M), + "passages": re.compile(r"^\[ResolvedPassageAuditSummary\].*status=PASS$", re.M), + "shell": re.compile(r"^\[PassageShellAuditSummary\].*status=PASS$", re.M), + "naturalness": re.compile(r"^\[PassageNaturalnessSummary\].*status=PASS$", re.M), + "mouth_profile": re.compile(r"^\[PassageMouthProfileSummary\].*status=PASS$", re.M), + "ripple": re.compile(r"^\[PassageRippleAuditSummary\].*status=PASS$", re.M), +} + + +def run(seed: int, label: str, seams_only: bool) -> tuple[int, str, float]: + log = OUT / f"seed{seed}-{label}.log" + layout = OUT / f"seed{seed}-{label}-layout.json" + command = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", + "timeout", "1740s", str(BIN), str(DATA), "--world-assembler-prototype", + "--stream-benchmark", "--stream-pipeline", "--workers=8", "--clip-radius=3", + "--max-clip-level=8", "--max-level=0", "--force-generate", f"--seed={seed}", + "--recipe=surface-world", "--native-owner-fi", "--density-dispatch-report"] + command.append("--audit-passage-tile-seams" if seams_only else "--audit-resolved-layout-passages") + if not seams_only: + command.append("--audit-passage-tile-seams") + command.append(f"--resolved-layout-output={layout}") + started = time.monotonic() + with log.open("w", encoding="utf-8") as output: + proc = subprocess.run(command, cwd=ROOT, stdout=output, + stderr=subprocess.STDOUT, check=False, timeout=1740) + return proc.returncode, str(log.relative_to(ROOT)), round(time.monotonic() - started, 3) + + +def main() -> int: + if not BIN.is_file() or not DATA.is_file(): + raise SystemExit("missing L140 Clang binary or composed owner fixture") + OUT.mkdir(parents=True, exist_ok=True) + results = [] + for seed in range(16): + exit_code, log_name, elapsed = run(seed, "composed", False) + content = (ROOT / log_name).read_text(encoding="utf-8", errors="replace") + stamp = STAMP_RE.search(content) + checks = {name: bool(pattern.search(content)) for name, pattern in CHECKS.items()} + checks["source_stamp"] = stamp is not None and stamp.group(1) == STAMP + checks["blocked_controls"] = len(re.findall( + r"^\[ResolvedPassageBlockedControl\].*detected=true$", content, re.M)) == 3 + checks["negative_controls"] = ( + "[ResolvedLayoutValidatorControls] rejected=10/10 status=PASS" in content + and len(re.findall(r"^\[PassageNaturalnessNegativeControl\].*detected=true$", + content, re.M)) == 1 + and len(re.findall(r"^\[PassageMouthProfileNegativeControl\].*detected=true$", + content, re.M)) == 1 + and len(re.findall(r"^\[PassageFloorStepNegativeControl\].*detected=true$", + content, re.M)) == 3 + and "synthetic_spheres_negative_control=DETECTED" in content + and "floor_beaded_negative_control=DETECTED" in content) + seam_match = re.search(r"^\[PassageTileSeamAudit\].*status=(PASS|FAIL)$", content, re.M) + seam_exit = exit_code + seam_log = log_name + seam_elapsed = 0.0 + if seam_match is None: + seam_exit, seam_log, seam_elapsed = run(seed, "seams", True) + seam_content = (ROOT / seam_log).read_text(encoding="utf-8", errors="replace") + stamp = STAMP_RE.search(seam_content) + checks["source_stamp"] &= stamp is not None and stamp.group(1) == STAMP + seam_match = re.search( + r"^\[PassageTileSeamAudit\].*status=(PASS|FAIL)$", seam_content, re.M) + content += "\n" + seam_content + checks["seams"] = seam_match is not None and seam_match.group(1) == "PASS" + all_gates = all(checks.values()) and exit_code == 0 and seam_exit == 0 + row = {"seed": seed, "exit": exit_code, "seam_exit": seam_exit, + "passed": all_gates, "checks": checks, + "elapsed_s": elapsed + seam_elapsed, "log": log_name, "seam_log": seam_log} + results.append(row) + print("[L140SeedSweep] " + json.dumps(row, sort_keys=True), flush=True) + (OUT / "runs-partial.json").write_text(json.dumps(results, indent=2) + "\n") + passed = sum(row["passed"] for row in results) + summary = {"source_stamp": STAMP, "seeds": list(range(16)), + "passed": passed, "failed": 16 - passed, "results": results} + (OUT / "summary.json").write_text(json.dumps(summary, indent=2) + "\n") + print(f"[L140SeedSweepSummary] passed={passed}/16 failed={16-passed} status={'PASS' if passed==16 else 'FAIL'}", + flush=True) + return 0 if passed == 16 else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/Standalone/Research/WorldAssemblerM3/Linux140/RunL140Timing.py b/Standalone/Research/WorldAssemblerM3/Linux140/RunL140Timing.py new file mode 100644 index 0000000..a9da171 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux140/RunL140Timing.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 +"""L80 timing: native L140 vs L139 HEAD and assembler/world, all owner strata.""" +from __future__ import annotations + +import json +import os +import re +import statistics +import subprocess +import time +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[4] +OUT = ROOT / "Saved/Linux/l140/timing" +DATA = ROOT / "Standalone/data/owner_world.json" +BINARIES = { + "assembler-world": ( + ROOT / "Saved/Linux/l137/bin/VoxelForgeCoreHeadless-l137-aa-a", + "4499fb2a8a4ede7d6cbc68d1b794f104658cdaae93ed9cacbc91fe7ff3fc3621"), + "head": ( + ROOT / "Saved/Linux/l139/bin/VoxelForgeCoreHeadless-l139-clang", + "b8603b6cb3975ca0f9669759e4e2464561c557fdb7aa6836acef123ecf0b99d1"), + "l140-native-fi": ( + ROOT / "Saved/Linux/l140/bin/VoxelForgeCoreHeadless-l140-clang", + "6205e6c180ef32c41792dc3e0d8bf443a96df41974f40334af4bf3a157ab88da"), +} +CAMERAS = { + # The camera override also selects the owner SurfaceWorld departure mouth. + # Hold XY to the seed-0 native-FI valid mouth so every layer/version shares one layout. + 0: (25.8369140625, 3.19921875, -372.2626953125), + 1: (25.8369140625, 3.19921875, -737.0), + 2: (25.8369140625, 3.19921875, -753.3740234375), + 3: (25.8369140625, 3.19921875, -900.353515625), +} +PIPELINE_RE = re.compile(r"^\[StreamPipeline\] (.*)$", re.M) +FIELDS_RE = re.compile(r"([a-zA-Z0-9_]+)=([^ ]+)") +NEAR_RE = re.compile( + r"^\[WorldAssemblerNearLODReady\] lods=0-2 tiles=(\d+)/(\d+) cold_ready_s=([0-9.]+)$", + re.M) +STAMP_RE = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=([0-9a-f]{64})$", re.M) +L140_AA_FLOOR_PCT = 1.0 # L137's same-binary A/A median control. + + +def quiet_machine() -> tuple[float, float]: + load_1m = os.getloadavg()[0] + + def totals() -> tuple[int, int]: + fields = Path("/proc/stat").read_text().splitlines()[0].split() + values = [int(value) for value in fields[1:]] + return sum(values), values[3] + values[4] + + before = totals() + time.sleep(2.0) + after = totals() + idle = 100.0 * (after[1] - before[1]) / max(1, after[0] - before[0]) + return load_1m, idle + + +def run(strate: int, workers: int, version: str, phase: str, replicate: int) -> dict[str, object]: + binary, expected_stamp = BINARIES[version] + camera = ",".join(f"{value:.12f}" for value in CAMERAS[strate]) + ",0,0" + label = f"s{strate}-w{workers}-{version}-{phase}{replicate}" + log = OUT / f"{label}.log" + command = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", + "timeout", "1740s", str(binary), str(DATA), "--world-assembler-prototype", + "--stream-benchmark", "--stream-pipeline", f"--workers={workers}", + "--clip-radius=3", "--max-clip-level=8", "--max-level=8", + f"--camera={camera}", "--profile-lod-work", "--stream-scheduler-policy=3", + "--recipe=surface-world"] + if version == "l140-native-fi": + command.append("--native-owner-fi") + started = time.monotonic() + with log.open("w", encoding="utf-8") as output: + proc = subprocess.run(command, cwd=ROOT, stdout=output, + stderr=subprocess.STDOUT, check=False, timeout=1740) + content = log.read_text(encoding="utf-8", errors="replace") + pipeline, near, stamp = PIPELINE_RE.search(content), NEAR_RE.search(content), STAMP_RE.search(content) + if (proc.returncode or pipeline is None or near is None or stamp is None + or stamp.group(1) != expected_stamp): + raise SystemExit(f"L80 run failed or stamp mismatch: {log}; exit={proc.returncode}") + if version == "l140-native-fi" and not re.search( + r"^\[FloatingIslandWorldAssembly\].*dispatch=FloatingIslands-native .*status=PASS$", + content, re.M): + raise SystemExit(f"candidate timing did not bind native FloatingIslands: {log}") + fields = dict(FIELDS_RE.findall(pipeline.group(1))) + row = {"strate": strate, "workers": workers, "version": version, + "phase": phase, "replicate": replicate, "source_stamp": stamp.group(1), + "lod02_ready_s": float(near.group(3)), + "whole_view_ready_s": float(fields["whole_view_ready"].removesuffix("s")), + "whole_tiles": int(fields["whole_tiles"].split("/")[0]), + "wall_s": round(time.monotonic() - started, 3), "log": str(log.relative_to(ROOT))} + print("[L140TimingRun] " + json.dumps(row, sort_keys=True), flush=True) + return row + + +def main() -> int: + if any(not path.is_file() for path, _ in BINARIES.values()) or not DATA.is_file(): + raise SystemExit("missing L80 timing binaries or owner fixture") + OUT.mkdir(parents=True, exist_ok=True) + load_1m, idle = quiet_machine() + (OUT / "machine-load-before.txt").write_text( + f"1-minute load: {load_1m:.2f}\n2-second CPU idle: {idle:.1f}%\n") + print(f"[L140TimingGate] load_1m={load_1m:.2f} cpu_idle_2s={idle:.1f}%", flush=True) + if load_1m >= 1.5 or idle < 97.0: + raise SystemExit("timing refused: machine is above the L80 quiet-load gate") + rows: list[dict[str, object]] = [] + for strate in range(4): + for workers in (8, 12): + for version in BINARIES: + run(strate, workers, version, "warmup", 0) + for replicate in range(1, 6): + order = tuple(BINARIES) + order = order[replicate % len(order):] + order[:replicate % len(order)] + if replicate % 2 == 0: + order = tuple(reversed(order)) + for version in order: + rows.append(run(strate, workers, version, "measured", replicate)) + (OUT / "runs-partial.json").write_text(json.dumps(rows, indent=2) + "\n") + measured = [row for row in rows if row["phase"] == "measured"] + summary = [] + for strate in range(4): + for workers in (8, 12): + group = [row for row in measured if row["strate"] == strate and row["workers"] == workers] + medians = {version: {key: statistics.median( + row[key] for row in group if row["version"] == version) + for key in ("lod02_ready_s", "whole_view_ready_s")} for version in BINARIES} + entry: dict[str, object] = {"strate": strate, "workers": workers, + "replicates_per_version": 5, "medians": medians} + for key in ("lod02_ready_s", "whole_view_ready_s"): + for baseline in ("head", "assembler-world"): + entry[f"l140_vs_{baseline}_{key}_delta_pct"] = round( + 100.0 * (medians["l140-native-fi"][key] / medians[baseline][key] - 1.0), 2) + entry[f"l140_vs_{baseline}_{key}_paired_deltas_pct"] = [round(100.0 * ( + next(row[key] for row in group if row["version"] == "l140-native-fi" + and row["replicate"] == replicate) + / next(row[key] for row in group if row["version"] == baseline + and row["replicate"] == replicate) - 1.0), 3) + for replicate in range(1, 6)] + summary.append(entry) + result = {"a_a_noise_floor_pct": L140_AA_FLOOR_PCT, + "a_a_reference": "L137 same-binary median control; assembler/world source stamp", + "timing_protocol": "quiet machine; one warm-up per binary per cell; five interleaved measured runs; W8/W12; all four owner layers", + "machine": {"load_1m": load_1m, "cpu_idle_2s_pct": idle}, + "source_stamps": {name: stamp for name, (_path, stamp) in BINARIES.items()}, + "runs": rows, "summary": summary} + (OUT / "summary.json").write_text(json.dumps(result, indent=2) + "\n") + print(f"[L140TimingSummary] measured_runs={len(measured)} warmups=24 aa_floor_pct=1.0 status=PASS", + flush=True) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/Standalone/Research/WorldAssemblerM3/Linux140/__pycache__/RunL140SeedSweep.cpython-313.pyc b/Standalone/Research/WorldAssemblerM3/Linux140/__pycache__/RunL140SeedSweep.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2e2fe0d4ab8a1608dbb7dbf84c03d1a082ecbaa3 GIT binary patch literal 9159 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 literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux140/baselines/native-owner-fi-seed0.json b/Standalone/Research/WorldAssemblerM3/Linux140/baselines/native-owner-fi-seed0.json new file mode 100644 index 0000000..1d6d810 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux140/baselines/native-owner-fi-seed0.json @@ -0,0 +1,201 @@ +{ + "status": "PASS", + "source_stamp": "6205e6c180ef32c41792dc3e0d8bf443a96df41974f40334af4bf3a157ab88da", + "layout_identity": "resolved-layout-v3-fnv64:08da20d55ff6820f", + "runs": [ + { + "compiler": "clang", + "workers": 1, + "exit": 0, + "source_stamp": "6205e6c180ef32c41792dc3e0d8bf443a96df41974f40334af4bf3a157ab88da", + "hash_lines": [ + "[PipelineFullDetailHash] tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineWholeViewHash] tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineMaterialHash] tiles=512 material=0xc3cb5fcccf78f4ee", + "[PipelineLODHash] lod=0 tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineLODHash] lod=1 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=2 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=3 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=4 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=5 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=6 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=7 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=8 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineExactQueryHash] probes=9 density=0x74eac0457ddc2026 unclamped=0x74eac0457ddc2026 detail=0xefcba20c0c70c415 collision=0xdd5b083a1fa82cc7 path=direct-Core-queries" + ], + "layout_identity": "resolved-layout-v3-fnv64:08da20d55ff6820f", + "native_fi_dispatch": true, + "native_plan_audits": true, + "passed": true, + "elapsed_s": 101.92, + "log": "Saved/Linux/l140/determinism/native-owner-fi-clang-w1.log", + "layout": "Saved/Linux/l140/determinism/native-owner-fi-clang-w1.json", + "floating_island_recipe_hash": "0b6a23bc73a3b867", + "passage_clearance_line": "[FloatingIslandPassageClearance] strate=1 tube_samples=5325 island_blocked=0 route_checks=676275 route_blocked=0 arrival_support=5/5 departure_support=5/5 clearance_excess_m=2.824 portal_exclusion_m=13.0 influence_reach_m=1.053 capsule_bound_m=0.880 status=PASS", + "route_audit_line": "[FloatingIslandRouteAudit] points=128 centers=911 capsule_samples=247792 blocked=0 support_samples=6961 unsupported=0 grade_failures=0 status=PASS" + }, + { + "compiler": "clang", + "workers": 8, + "exit": 0, + "source_stamp": "6205e6c180ef32c41792dc3e0d8bf443a96df41974f40334af4bf3a157ab88da", + "hash_lines": [ + "[PipelineFullDetailHash] tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineWholeViewHash] tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineMaterialHash] tiles=512 material=0xc3cb5fcccf78f4ee", + "[PipelineLODHash] lod=0 tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineLODHash] lod=1 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=2 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=3 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=4 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=5 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=6 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=7 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=8 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineExactQueryHash] probes=9 density=0x74eac0457ddc2026 unclamped=0x74eac0457ddc2026 detail=0xefcba20c0c70c415 collision=0xdd5b083a1fa82cc7 path=direct-Core-queries" + ], + "layout_identity": "resolved-layout-v3-fnv64:08da20d55ff6820f", + "native_fi_dispatch": true, + "native_plan_audits": true, + "passed": true, + "elapsed_s": 68.892, + "log": "Saved/Linux/l140/determinism/native-owner-fi-clang-w8.log", + "layout": "Saved/Linux/l140/determinism/native-owner-fi-clang-w8.json", + "floating_island_recipe_hash": "0b6a23bc73a3b867", + "passage_clearance_line": "[FloatingIslandPassageClearance] strate=1 tube_samples=5325 island_blocked=0 route_checks=676275 route_blocked=0 arrival_support=5/5 departure_support=5/5 clearance_excess_m=2.824 portal_exclusion_m=13.0 influence_reach_m=1.053 capsule_bound_m=0.880 status=PASS", + "route_audit_line": "[FloatingIslandRouteAudit] points=128 centers=911 capsule_samples=247792 blocked=0 support_samples=6961 unsupported=0 grade_failures=0 status=PASS" + }, + { + "compiler": "clang", + "workers": 12, + "exit": 0, + "source_stamp": "6205e6c180ef32c41792dc3e0d8bf443a96df41974f40334af4bf3a157ab88da", + "hash_lines": [ + "[PipelineFullDetailHash] tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineWholeViewHash] tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineMaterialHash] tiles=512 material=0xc3cb5fcccf78f4ee", + "[PipelineLODHash] lod=0 tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineLODHash] lod=1 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=2 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=3 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=4 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=5 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=6 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=7 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=8 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineExactQueryHash] probes=9 density=0x74eac0457ddc2026 unclamped=0x74eac0457ddc2026 detail=0xefcba20c0c70c415 collision=0xdd5b083a1fa82cc7 path=direct-Core-queries" + ], + "layout_identity": "resolved-layout-v3-fnv64:08da20d55ff6820f", + "native_fi_dispatch": true, + "native_plan_audits": true, + "passed": true, + "elapsed_s": 68.96, + "log": "Saved/Linux/l140/determinism/native-owner-fi-clang-w12.log", + "layout": "Saved/Linux/l140/determinism/native-owner-fi-clang-w12.json", + "floating_island_recipe_hash": "0b6a23bc73a3b867", + "passage_clearance_line": "[FloatingIslandPassageClearance] strate=1 tube_samples=5325 island_blocked=0 route_checks=676275 route_blocked=0 arrival_support=5/5 departure_support=5/5 clearance_excess_m=2.824 portal_exclusion_m=13.0 influence_reach_m=1.053 capsule_bound_m=0.880 status=PASS", + "route_audit_line": "[FloatingIslandRouteAudit] points=128 centers=911 capsule_samples=247792 blocked=0 support_samples=6961 unsupported=0 grade_failures=0 status=PASS" + }, + { + "compiler": "gcc", + "workers": 1, + "exit": 0, + "source_stamp": "6205e6c180ef32c41792dc3e0d8bf443a96df41974f40334af4bf3a157ab88da", + "hash_lines": [ + "[PipelineFullDetailHash] tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineWholeViewHash] tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineMaterialHash] tiles=512 material=0xc3cb5fcccf78f4ee", + "[PipelineLODHash] lod=0 tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineLODHash] lod=1 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=2 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=3 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=4 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=5 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=6 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=7 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=8 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineExactQueryHash] probes=9 density=0x74eac0457ddc2026 unclamped=0x74eac0457ddc2026 detail=0xefcba20c0c70c415 collision=0xdd5b083a1fa82cc7 path=direct-Core-queries" + ], + "layout_identity": "resolved-layout-v3-fnv64:08da20d55ff6820f", + "native_fi_dispatch": true, + "native_plan_audits": true, + "passed": true, + "elapsed_s": 100.676, + "log": "Saved/Linux/l140/determinism/native-owner-fi-gcc-w1.log", + "layout": "Saved/Linux/l140/determinism/native-owner-fi-gcc-w1.json", + "floating_island_recipe_hash": "0b6a23bc73a3b867", + "passage_clearance_line": "[FloatingIslandPassageClearance] strate=1 tube_samples=5325 island_blocked=0 route_checks=676275 route_blocked=0 arrival_support=5/5 departure_support=5/5 clearance_excess_m=2.824 portal_exclusion_m=13.0 influence_reach_m=1.053 capsule_bound_m=0.880 status=PASS", + "route_audit_line": "[FloatingIslandRouteAudit] points=128 centers=911 capsule_samples=247792 blocked=0 support_samples=6961 unsupported=0 grade_failures=0 status=PASS" + }, + { + "compiler": "gcc", + "workers": 8, + "exit": 0, + "source_stamp": "6205e6c180ef32c41792dc3e0d8bf443a96df41974f40334af4bf3a157ab88da", + "hash_lines": [ + "[PipelineFullDetailHash] tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineWholeViewHash] tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineMaterialHash] tiles=512 material=0xc3cb5fcccf78f4ee", + "[PipelineLODHash] lod=0 tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineLODHash] lod=1 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=2 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=3 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=4 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=5 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=6 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=7 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=8 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineExactQueryHash] probes=9 density=0x74eac0457ddc2026 unclamped=0x74eac0457ddc2026 detail=0xefcba20c0c70c415 collision=0xdd5b083a1fa82cc7 path=direct-Core-queries" + ], + "layout_identity": "resolved-layout-v3-fnv64:08da20d55ff6820f", + "native_fi_dispatch": true, + "native_plan_audits": true, + "passed": true, + "elapsed_s": 70.398, + "log": "Saved/Linux/l140/determinism/native-owner-fi-gcc-w8.log", + "layout": "Saved/Linux/l140/determinism/native-owner-fi-gcc-w8.json", + "floating_island_recipe_hash": "0b6a23bc73a3b867", + "passage_clearance_line": "[FloatingIslandPassageClearance] strate=1 tube_samples=5325 island_blocked=0 route_checks=676275 route_blocked=0 arrival_support=5/5 departure_support=5/5 clearance_excess_m=2.824 portal_exclusion_m=13.0 influence_reach_m=1.053 capsule_bound_m=0.880 status=PASS", + "route_audit_line": "[FloatingIslandRouteAudit] points=128 centers=911 capsule_samples=247792 blocked=0 support_samples=6961 unsupported=0 grade_failures=0 status=PASS" + }, + { + "compiler": "gcc", + "workers": 12, + "exit": 0, + "source_stamp": "6205e6c180ef32c41792dc3e0d8bf443a96df41974f40334af4bf3a157ab88da", + "hash_lines": [ + "[PipelineFullDetailHash] tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineWholeViewHash] tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineMaterialHash] tiles=512 material=0xc3cb5fcccf78f4ee", + "[PipelineLODHash] lod=0 tiles=512 density=0xe10ac12305f1dbc0 mesh=0x822e56e8f5bfa6f0 payload=0x0be1f08906997251 topology=0x650bbeb9e554d390", + "[PipelineLODHash] lod=1 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=2 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=3 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=4 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=5 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=6 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=7 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineLODHash] lod=8 tiles=0 density=0xcbf29ce484222325 mesh=0xcbf29ce484222325 payload=0xcbf29ce484222325 topology=0xcbf29ce484222325", + "[PipelineExactQueryHash] probes=9 density=0x74eac0457ddc2026 unclamped=0x74eac0457ddc2026 detail=0xefcba20c0c70c415 collision=0xdd5b083a1fa82cc7 path=direct-Core-queries" + ], + "layout_identity": "resolved-layout-v3-fnv64:08da20d55ff6820f", + "native_fi_dispatch": true, + "native_plan_audits": true, + "passed": true, + "elapsed_s": 69.061, + "log": "Saved/Linux/l140/determinism/native-owner-fi-gcc-w12.log", + "layout": "Saved/Linux/l140/determinism/native-owner-fi-gcc-w12.json", + "floating_island_recipe_hash": "0b6a23bc73a3b867", + "passage_clearance_line": "[FloatingIslandPassageClearance] strate=1 tube_samples=5325 island_blocked=0 route_checks=676275 route_blocked=0 arrival_support=5/5 departure_support=5/5 clearance_excess_m=2.824 portal_exclusion_m=13.0 influence_reach_m=1.053 capsule_bound_m=0.880 status=PASS", + "route_audit_line": "[FloatingIslandRouteAudit] points=128 centers=911 capsule_samples=247792 blocked=0 support_samples=6961 unsupported=0 grade_failures=0 status=PASS" + } + ], + "world_assembly_evaluator_version": 239, + "floating_island_geometry_version": 10, + "native_dispatch": "FloatingIslands-native", + "route_and_clearance_baseline": { + "route_audit": "[FloatingIslandRouteAudit] points=128 centers=... status=PASS", + "passage_clearance": "[FloatingIslandPassageClearance] strate=1 tube_samples=5325 island_blocked=0 route_checks=676275 route_blocked=0 arrival_support=5/5 departure_support=5/5 clearance_excess_m=2.824 portal_exclusion_m=13.0 influence_reach_m=1.053 capsule_bound_m=0.880 status=PASS", + "note": "The six identical hash/layout rows are the concrete baselines; route point counts differ by seed only in other sweep cases." + } +} diff --git a/Standalone/Research/WorldAssemblerM3/Linux140/captures/after-arrival-mouth.jpg b/Standalone/Research/WorldAssemblerM3/Linux140/captures/after-arrival-mouth.jpg new file mode 100644 index 0000000000000000000000000000000000000000..58f9af4fffc3009e7facbd3543895751c46d6d43 GIT binary patch literal 20205 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 literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux140/captures/after-island-edge.jpg b/Standalone/Research/WorldAssemblerM3/Linux140/captures/after-island-edge.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0e8d0f5931565b851c983d8a0e086540e4df0877 GIT binary patch literal 19984 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 literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux140/captures/after-walk-between-islands.jpg b/Standalone/Research/WorldAssemblerM3/Linux140/captures/after-walk-between-islands.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3f2d9c84cda356c7e2a3ff62a7825965f114590d GIT binary patch literal 20752 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 literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux140/captures/after-wide-silhouette.jpg b/Standalone/Research/WorldAssemblerM3/Linux140/captures/after-wide-silhouette.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b37c0a547482449a88a2db07e2dfc19a8294e134 GIT binary patch literal 22894 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
    AE;3@mJPf#}SQl=yrd+Q!y6w7iC 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 literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux140/captures/before-island-edge.jpg b/Standalone/Research/WorldAssemblerM3/Linux140/captures/before-island-edge.jpg new file mode 100644 index 0000000000000000000000000000000000000000..03ebc0b256d0623348386438b06211cd67f3bb79 GIT binary patch literal 15208 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 Ky;EOov-dwvT;liu literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux140/captures/before-walk-between-islands.jpg b/Standalone/Research/WorldAssemblerM3/Linux140/captures/before-walk-between-islands.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a20445bac0a51f20527c79cde6aeb4152b16a3de GIT binary patch literal 15126 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%0D;nIh#x?u4kEd=YcD`r;{$W2~c zP9OuUBwGbQpuCoC@}dIy8NmbqbY23inA~z&kYxOUKs>v>pH{N1)vn1DQ$5gLXaF|s zlwuH+*vRyQh}E8A&%IaO#}wv*BYbSRxG;s6O?VB?PL%t|iIXKMHy-=5^|iR8mH{?o zK$1bRh0S<*y++E3||!-0ftvfwr@_%VEaKP+&*jA zR6`E$m=le%9I;9r=!zS{BqtrFJPlp>LI0cSKg$AgjfQi-w0mXoNSS5vCasx!DQPXy z6C=J!R1L}0ly;;O$`%;g7o%?KV5S=9@uqEjfaPnh^Qzo|G@M1lF1ex2c4F-db8ppS zmWZehv7Zuait{5PV(mliY}1fOhiLm?FlUxsTT6{9uGF{#B zvJDN5TuB@f>5s+U9xo@)m{yoL!RhBZZ^qh^^j_MLM!1v%tx8x)zmf2sV=mtFs zy|1a*H4Q&7oI>u+$1mP1++{(Jt-EgPH>{SuH#&koTc5W{BH0Ez3nilv3ei$qXLo68 zTb5~R-oG9np9li&3H|O*zzXX3za0F~7R2>oL5zQ{{L9*AEmYSc`txXAi|Cazfv+ro z_+#9!9tkU!x5^9btVJ|GMOLk@B;2~$2X^Cf-4va-W8;~jmhD!dA8vJq1_rc1n?1Nj zo)c36*r(%vNFr)*@)?2dW~L8WD8M$OT@|8XEpHbLa$CXrftkeRJ7-yj-6g8UxTP{F z_M(k3UDF@ZFloayv5U$%7Yde=g%~%!c}23n59_24+NKXCEueT6Ka`cE){|B0kCu85 zxWVN{z2g)nl}Kg5_WNFijT4V=4D^NhB+H>`a%JvLQgxh~*JfzQ=IOznQn!ez*!H;K zhpRv4uV=X+pQ(3ZE8X3b+Z6PB0MrlVG-Li6YS%?a!f(ccNqXE9j@GT`I@647>#iB! zl_|YyUu)H|SD~v63~|x~?s^{H)?iZR?%sDdJ|h#P>=iQh1d~y!kwtx0(kegn9w0_G zudY?|Y#p0y#-Fn*BBnNwG-{5{3}GDZPMPuVm90jr_eu(aGPrWDtgO?1^9~Ft$tp%u zq#J9?>hr`U1px+W8*5guY5TY1iysW@(g1mvRL^c+t6_hQ;!mG`h&8?fKiod4ty%pQ z{B!4}wN?eNsw+|m@O~(#wW|8DfUfF%ET9{%ue32AV|G>BxO=Br4SM3U^rpFWJk*^&YIo-Ls$r^XPT)q)r|WVT!e7iN0Xb6%usG->OzBTZri$S*tZke z-L<31%dw|SeKNfz8qC|@Y}XUUKqDqDSmnw0*KReKVaRgO2;If0ao@qa_fFZp{94+%He>#4lGpF|)jH)Ajx@4Wm(;j7gNY0&f+LfJJp z{5}5ogYhkY*nQgk57p&^ALS2k5MNbXJ6HLoKwR$2QXrE1g?mIz|8M~MLl`;@ZB|1^ zkjm;d07(yr)?$ummPdFo;e`d5daUpZA437-v zrizfzd8T3n%E_-vuRvc`zgCrJhCW}hNjVB~hH1oTY&vPHN>Yo*W+JUKVVaOOh{NHv z1O5{m{_4MqP99pXE@JTq;orUy`2Ej}u5=||Jp3w8|I}q#XV?7o{A0?wedqm9a1Mz0 ze&|^Mt1hdly)|{^hW*xYOzZBdjSBwq!ESa6abvD5OQX_=cqlptN65fnO3ztiuDHmg^|&uKT5&7vXx3n`zXe<`Js%Z% zs{^N;(Uqq6x57N~xmOJ8Nt2NjXrwJuWj=QSO1IZ^pv*SgMCx2;yeUw>ICg#0tr z$QEX2S>D!ATg$Z6rllG~j0_sMI>{mVvrS|)!q8y*KgPML+3Ig2EO||NU_w-xb7xW< z=4O7C{i&w}+peoFN@p^)7k!+yz2JUatKFIyvpSMCRDq;jgnpoSp+BQb;fPjfLfVt^ z(8w^4d9MqWhW@aCw~?60!wS%#+OFF zLJe4p?9UZH6)dd}1?yu1oh3PRR0JY-v9sr literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux140/captures/before-wide-silhouette.jpg b/Standalone/Research/WorldAssemblerM3/Linux140/captures/before-wide-silhouette.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a8414e12c32b6b027c97d3c23b8be7bf35c0ed61 GIT binary patch literal 15268 zcmeHMcUV)&+CK?Iup0@A1!ZwBASj9`0s#ptfo~NdRF$GDC`IYLn|1dpV!(A(6sZ@k zf}t%SK|w%8K@mijRfG_b-b7Rcq$uB z76SrNLV`phNl7hTx^ktotnAvUyAT7yAq5f?99~3}fKqWd44EJ*f}gbrFd#fc5D^vO zGI7Mkcu$qDbR`amnAG0h^y>R>T66wI#6dVbe%5SJ98V4>f+yB`o+16qRP^WXztJ_3 zSgi8Zf!jHDtzN3K$!)I*n_f-bf{5by#{@_Ow-~}NhC~)aQ;pC(5ilN6gb3+CW9?3M zbistaw7wwl1%WRJd_mv~0$&jLg1{F9J{JM}gKL3LuXdUh4vN34fB^<`lHHeU-%&lxH@sJo)YZi7h(G zgLjJ+rXat>VfGmB?fb$n%-6b|{(j@+^S{v&KXtrC>)0>_t;l?p zXc-r#U2@UgqxR}%CbjWH&J;B0p1$U{z!@g-b(OVL)m;O|DWa;no?*>n8|ItBVx`c* zg7og!5!!Z<){Ql_#@MiV!J7sCU6Q{!^XH-5nrsa5^GQ)#v!e3q?W6kE%5IVO(~ZJpCxU2YcGa3^o)ww1;y5c_%#!e}t}VHB zvaCyLSHqaMPx*vI_0@`_JG>95g)l>w_#CLd>6&Agzb7u#-}ezYwUzPg(&j50-&#MB zazDP}e&az`i|Yl}XQeaqOj=v~T(+Lcsw{|0U-cpOTKS$$R^FAS2@16uZDlrA8TY#n z`?K998zR?s^uFU1$yv44dAPQuP8_{=Y4BO;(cuq!ZTzpN#OE!HbvrqJKqtV1EPu9i z^{LE@WU;PwA=B%CTe_|&-o&c5>{qZPYr+KK%nMb5K? z($kN`>zC&J99ZcYMfB;rnSx^4F0qepYS$j<%0D92fmKNBK41G#fQf zT=5BUco?{R-KiVQ0{fxk+lZ@2ixZv{L|>K)u|L6hUtF-Ur~ZI#=xE5UdZU<_Luzdg zT}N2YYKb6OOGjN zrONAzQxGdp%gWjIQ3J=dE>*nx(xWJ&4-=V@Qjc~m3Ai>;6kl4%wl`8ed$M9>eDSEQ z=0*nRIrD=MQGB%%Vz8{ZZ7BxXsBoUm7~`$nUu zqU%BUxRH*N<8}F;8LpPV%R>fMD_45Z1?Ka3dbF)b}Ez1xTQXaekpSu5t)A-)bg=rQ6J8AmAQUHhvoIms0MXFz@IHe(@v#gp1}XPpi0*f%=7Fspn0}OAr4P zL{z_7^B181^P9!hh`FVGD{$=EyBEEbw{MspwzWS6X}M+ZXbElyhtH{Meh5G#0j`_j zocmx9$+_Q+dKqgN-|6jRG%v{fIW@AdTgLZ#cYJEA-;1WK;wW$i`gbVh+-7}99GHTZ zt|_v6KLyo~QT_9}-WIkv-;^|f(XT94YrL5#dtyNWU`jevOvA%bc-&G#D zH^*|sKD&D;Lg~P%uHV{AFKgtk*k-Y9uJ1QW&L_5V{EO=}9S$+rr`8oTvhDTsWDBI$ z>GvrG9=qd~%({uDYb9>FR>;g&OO%dRsE#NHpzN=Wu2gb3Vj5mi?{3~+xNT2WK#HZ~ zLMq4e_?U}qK1=v?3KT1T(#IJL84d~C7;w|>pGu(_QKgBGHqhiew?89L5ZnnA!e8Do z(T_DnX+lIC4c9BFXy7*B^)4jP&)AMbn=ssc(_1om<8aMBi4yyzKa>XsnW>N4r%Q1b zk2o&(HPEnJlc%$napkMZ&IHrAn#0@9XxuG~DUYvx#A!Kbbh2#g+=xK+mxcC*_Gk0s zEE(P`f3}a)9WO`K?z2UOJ@M-0uA=u2v#Wni3~>b~M5TkVlBJfsUiS~XqGO3wrbPwP z0Ttb|$Z}2=1$o;0br@Dv*Vqx!w(8WURqy4b7|y97`l_zAtM^1dT)*|AiRwJHrt)>y zICf+C>Vv&Ii8-BS&kIuKU28m8p=w38PLU(;cD$?|KNPDJ>2T27*N&_@e6jMtxnKD+ zPj258zq0fF2wPKy(U3X2V*t$DNaAPZ%{FBB-VZHh+MJvZQ&9h8a{G-3EVEao<{&~{ z&TF~WYsj`|RfTd(6>ZhmKjO zEBD;jUab;Z5NzwxbMZo1pG#p&u*2rNx3-%mf;b z+gnG$5n2R}(10419r6p!eeKC@s~0+T_Ep*U*8doG&?Z<*?Gk)3Y8!1}z8YlIdcN#T zaEmiO9G0`JYUk~`m6yMbstT3!I!UcCJL{6#8kSaF)&Hz7fSu(!T7Q8{5COan9|IP1jOMR=szr zF3R*=z@wOlqDPi9;;$4e>GyKj;&)h!{IWXwQk8S2rQ>Q_j@j{^cZbwuBh?w&ONPtI zozb!DzP)N1?0+Ph?D#O3yrl2AmFq8is>`k1Y(rTSRr)cvkKa4xR@5lxqrd)&m1`iJ zlD12pMj%-KaJbL3ZzjwH1>ke|454Z^*+SJay30s|vsAI2vx1Xu%pvuxr zPy?BNZNy-L|J#;H^_Aq+gGFQha!Q4PZ1hUp>S-X4UWxs#C}pD==zb@ffqdnZk^`Ad zdwlhc{Et`fJQ3103PNZ|@(KtcOJd0y5JDP3CLn~emvJ_Y817C*j*Ocvt3bX9+BiYo z8&l{R6O+jNT2Jo)k+_Pdi=(xcqkA|B<`5SV^7r zDc>7ft5$4LmL7`bsMr$06{G@OL2jxYwjpmwV32e!Z$^4qO>rmZa+#Z}XA@CdF^wF z@v<~XVb4}2xEhhiO@~4Pk-Nr=>HXDap`*bZpWc`Y54+Z}T8`Ll*4y60+ad0oXn~WY z@v52q2ZCVNGr`D7nwSWGXyDj@-G*jDLWF?=Vjp#nKUND(4DoiX$0H7CLP5NYUzwZh zBGEyl@EuRc3bsQPHK$Rj=HR0X7HrNR03PI156~Bd%;5)TK|pj-3rLN|9#Uh+5pE;# z$&(}zO>`x>6&g{xm%$roa08hq2;M?vh6!T$+#nQCs9;nah-8xFBCw+fo6i)rpis?4 zEoM##Ac#%)l7FQ^K#ao`=?|+DX_AsS6Hq~t(jfQzXDEd5MBt)e27;YL;0a*EiGqv< zU;vV$aF)^|(BPc_>Re^uy%c^2V-E))L~w*F5?2_*|NW*Y#sFgK_f)12;)_EmIMiW2 zQ41E$wGZPYFa=NntL9ol7`#N!#Y@zJsz;(BPQld#`zO%n8iilncpy>rfC~2mu;V){ z5-n)VU}}s3;U;iJuFKFqT7$48zX$HWZ~_oJq)Xw`W^N$Pf`em#UvMM{C{uXeNrA%y zi4q7x#)p9*&=vtYQWnv;4Zx*A(}M=lfX_Sv8f|=65jYK14|Z^z%$Xqk%+v@2#yCYNMyWw z2x^%t&K(B4z?7gr6GgDk^K(6V!QgiVR)t#_u)rF?dBoeaAYnOf50(+Q14^X8F99OR zGDJ}+t}&v8>e|g4*7KYN*(IAbg>+cH;6Rt+*rX z*G!Rn<;6{sxVF}PFXzx-du00)C;?%bqaNmBC)%_9A*2?EUQPPGY)exryHnhxEB3=b zgRd)!z->v~^Y(o&iL{mI3TCchhk{RGp~VwO;F`sg7ljitKZ_$MB0QWfDj^DvN5O?|54eT$FOsJWn6U zeg)(RKFc9PCtMuzQK3k{TNh1V2D-Fao=M;%M*okK05CwnwI~818fc@ZIZQ)?56wns z9Kk#s1qdO9B4`TM4>(w4c(9-v!abDsC+j^>uBI=2Zhd+NT{P+p^tBVsfd|$@t3EexvjBun?n1Md_Vt#tzO`gDQAYO#!3Kk90GRDU!eEXPH@~pu;3>oyW z9KI&pfKxf9fHN6=Ff@J>SC_FbX~CKAL_Fy8Z{hw8IYG|Q@`Iq^91l51LhgGy@M_)n zC8f7i{G>=ea$=*ofBgbGCb_@njVx1p`OsuI^R)iWDM)tCX(RBGfqRp+7ONsXx+2mB zv$P(Y`_(H`QnGHmfdVP~LAedC;{c!mfzO2(iM`;6Vtc~p*o@d=VG#n1KLQwF8k8`F zTPVE7^f%%aLR_&uRgfQ}66#+@UyyNY)?*xtvci#~pI<{YceimrNb@O92yP%rXZy!e zKs6uoDQ=>#=(r_f69XOD3)xZ#zwxSBH!LYDI`=?6U0u+?8+Gf%F)hlf?|~~$FW`y< z7Yb4fDxq~^T?&H`mMqZ6XkvjA&VAro@zIdz;DS&WOa{~9uK*r!PlQND#tvveX)&Fw ze+cqDh+|Q8eNRyq*OMu8_hP4qv4E?|A0UUSKHM$7I(68wx;K&#I1@x=;IupQ9GY%%CzcNxpUv@uO# zWsGG}2>YD?F)GQwZE`1owF8gL`!*r?USV!dg+E;R=`X7Jtiq84l%Rij^|KrFq!pk$ zbeZWg-2UuKH5D3O!!3i)aeadC1zaY`e$&*1XNHADIJPk1gJ}w3h*5y83Vpfe4!elP zyN@H&z*?F%um98)r2#ZXGVGF-(&Gja!i@h-b@|lq0gl&LK{iv+>ft0YPaziprsPEg_LbKsfy18?Jf%(VGC zm88Z)k_$E7^ii zD-Pj-A(mF(Mp;#b+iJo1j@`P1}Y%A`SQczSpehR%fvKSwrM z5vB8hgXoX~9m4Yo4V*!GIB&J{m>3BLuR0fq2XDZNT>1cNTd!W3H@9 z%gx>{Xjm4b3pg+u;&?@T5)TJRoGT!cj41N97|7wnc|5=YeL=xu0^|e?#Az^x4Ift& z2=ts0l81F8($c`^SOj8+2PM|%pKV9)NSeJKMu`;PU7C8j@8Wn!$$q0K4af7LYdUQ& z#!o>yEgUnF<*$3qb<0Wvw{jjPhJT&?=m#0>NZ2+`_}3vU3vCC9J*I;exJf~%m-0nq z038#cs5^**OoJ3&G);F0{uZNRpcbOYAY^{#n#RQ|CMVBPKt$+B4MDOX1Hq3BxBuUH z;ki~t9-sc#8^w=p9s_}ag+p9HMm%i}9i18w=dGR&#|A(10>;PAJdFZ0;KDNiFHi=d z@GC*i_=p9|M9lEe`N}gll0cYEd!`G%{P^#588A1j*fG!nR(K@t62SVBVG?Ffr!5)g i%D|PN@FYNH=2.0,coverage>=0.001) status=PASS" + }, + { + "phase": "after", + "view": "departure-mouth", + "file": "Standalone/Research/WorldAssemblerM3/Linux140/captures/after-departure-mouth.jpg", + "bytes": 23901, + "camera_m": [ + 21.556817528943192, + -14.930993681478485, + -730.751171875 + ], + "target_m": [ + 11.51544953238179, + -11.861640531768845, + -730.751171875 + ], + "yaw_deg": -73.00313688448165, + "pitch_deg": 0.0, + "fov_deg": 78.0, + "note": "player eye approaching the fixed 1-2 departure mouth", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux140/captures/after-departure-mouth.jpg pixels=921600 mean_luma=112.186 stddev_luma=5.529 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "phase": "after", + "view": "island-edge", + "file": "Standalone/Research/WorldAssemblerM3/Linux140/captures/after-island-edge.jpg", + "bytes": 19984, + "camera_m": [ + 47.84242754056169, + -19.331304817383565, + -734.4728515625 + ], + "target_m": [ + 54.57926831575571, + -16.75934518129221, + -735.5728515625 + ], + "yaw_deg": 69.10437717375885, + "pitch_deg": -8.673184187101441, + "fov_deg": 78.0, + "note": "player eye beside the route on an island edge", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux140/captures/after-island-edge.jpg pixels=921600 mean_luma=114.169 stddev_luma=8.688 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "phase": "after", + "view": "walk-between-islands", + "file": "Standalone/Research/WorldAssemblerM3/Linux140/captures/after-walk-between-islands.jpg", + "bytes": 20752, + "camera_m": [ + 64.3971173756484, + -22.884388870806152, + -733.137890625 + ], + "target_m": [ + 53.12109375, + -24.2802734375, + -734.537109375 + ], + "yaw_deg": -97.05687302971492, + "pitch_deg": -7.020510748634912, + "fov_deg": 78.0, + "note": "player eye looking from one route landing toward the next island", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux140/captures/after-walk-between-islands.jpg pixels=921600 mean_luma=111.849 stddev_luma=7.186 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "phase": "after", + "view": "wide-silhouette", + "file": "Standalone/Research/WorldAssemblerM3/Linux140/captures/after-wide-silhouette.jpg", + "bytes": 22894, + "camera_m": [ + 41.099609375, + 8.620008680555555, + -725.6368272569445 + ], + "target_m": [ + 41.099609375, + -14.379991319444445, + -735.6368272569445 + ], + "yaw_deg": 180.0, + "pitch_deg": -23.498565675952097, + "fov_deg": 72.0, + "note": "wide side view showing the island chain silhouette", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux140/captures/after-wide-silhouette.jpg pixels=921600 mean_luma=116.109 stddev_luma=7.003 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "phase": "before", + "view": "arrival-mouth", + "file": "Standalone/Research/WorldAssemblerM3/Linux140/captures/before-arrival-mouth.jpg", + "bytes": 13808, + "camera_m": [ + 23.77218612173332, + 4.6087926326387905, + -735.55 + ], + "target_m": [ + 32.44404347295337, + -1.3114176744441277, + -735.55 + ], + "yaw_deg": 124.32105280346487, + "pitch_deg": 0.0, + "fov_deg": 78.0, + "note": "player eye at the fixed 0-1 arrival mouth", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux140/captures/before-arrival-mouth.jpg pixels=921600 mean_luma=132.078 stddev_luma=8.080 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "phase": "before", + "view": "departure-mouth", + "file": "Standalone/Research/WorldAssemblerM3/Linux140/captures/before-departure-mouth.jpg", + "bytes": 17309, + "camera_m": [ + 21.556817528943192, + -14.930993681478485, + -730.751171875 + ], + "target_m": [ + 11.51544953238179, + -11.861640531768845, + -730.751171875 + ], + "yaw_deg": -73.00313688448165, + "pitch_deg": 0.0, + "fov_deg": 78.0, + "note": "player eye approaching the fixed 1-2 departure mouth", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux140/captures/before-departure-mouth.jpg pixels=921600 mean_luma=118.383 stddev_luma=9.908 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "phase": "before", + "view": "island-edge", + "file": "Standalone/Research/WorldAssemblerM3/Linux140/captures/before-island-edge.jpg", + "bytes": 15208, + "camera_m": [ + 47.84242754056169, + -19.331304817383565, + -734.4728515625 + ], + "target_m": [ + 54.57926831575571, + -16.75934518129221, + -735.5728515625 + ], + "yaw_deg": 69.10437717375885, + "pitch_deg": -8.673184187101441, + "fov_deg": 78.0, + "note": "player eye beside the route on an island edge", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux140/captures/before-island-edge.jpg pixels=921600 mean_luma=109.945 stddev_luma=4.383 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "phase": "before", + "view": "walk-between-islands", + "file": "Standalone/Research/WorldAssemblerM3/Linux140/captures/before-walk-between-islands.jpg", + "bytes": 15126, + "camera_m": [ + 64.3971173756484, + -22.884388870806152, + -733.137890625 + ], + "target_m": [ + 53.12109375, + -24.2802734375, + -734.537109375 + ], + "yaw_deg": -97.05687302971492, + "pitch_deg": -7.020510748634912, + "fov_deg": 78.0, + "note": "player eye looking from one route landing toward the next island", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux140/captures/before-walk-between-islands.jpg pixels=921600 mean_luma=110.305 stddev_luma=4.132 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + }, + { + "phase": "before", + "view": "wide-silhouette", + "file": "Standalone/Research/WorldAssemblerM3/Linux140/captures/before-wide-silhouette.jpg", + "bytes": 15268, + "camera_m": [ + 41.099609375, + 8.620008680555555, + -725.6368272569445 + ], + "target_m": [ + 41.099609375, + -14.379991319444445, + -735.6368272569445 + ], + "yaw_deg": 180.0, + "pitch_deg": -23.498565675952097, + "fov_deg": 72.0, + "note": "wide side view showing the island chain silhouette", + "quality_status": "PASS", + "quality": "[CaptureQuality] image=/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux140/captures/before-wide-silhouette.jpg pixels=921600 mean_luma=114.186 stddev_luma=3.531 coverage_luma_gt12=1.00000 thresholds=(stddev>=2.0,coverage>=0.001) status=PASS" + } + ] +} diff --git a/Standalone/Research/WorldAssemblerM3/Linux140/l140-fi-around-tunnels.patch b/Standalone/Research/WorldAssemblerM3/Linux140/l140-fi-around-tunnels.patch new file mode 100644 index 0000000..c4bcb95 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux140/l140-fi-around-tunnels.patch @@ -0,0 +1,1279 @@ +diff --git a/Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp b/Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp +index 5e66412..8d21685 100644 +--- a/Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp ++++ b/Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp +@@ -892,6 +892,7 @@ bool BuildSurfaceStratumPlan(const UVoxelStrateManager* StrateManager, + + bool BuildFloatingIslandStratumPlan(const UVoxelStrateManager* StrateManager, + const FStrateSlot& Slot, VoxelForgeCore::WorldAssemblyManifest& Manifest, ++ const VoxelForgeCore::ResolvedLayoutSnapshotV3& Layout, + double CoreVoxelSizeCm, std::int64_t LayoutChunkWidthSubvoxels, FString& OutError) + { + using namespace VoxelForgeCore; +@@ -903,7 +904,8 @@ bool BuildFloatingIslandStratumPlan(const UVoxelStrateManager* StrateManager, + IslandPlan.topChunkZ = Slot.TopChunkZ; + IslandPlan.bottomChunkZ = Slot.BottomChunkZ; + auto& Recipe = IslandPlan.manifest.recipe; +- Recipe.geometryVersion = 8; ++ Recipe.geometryVersion = 10; ++ Recipe.primaryIslandCount = 9; + Recipe.terrainFollowingRoute = static_cast(Passage.Style) == 0; + Recipe.layoutChunkWidthSubvoxels = LayoutChunkWidthSubvoxels; + Recipe.seed = static_cast(StrateManager->GetWorldSeed()); +@@ -929,13 +931,24 @@ bool BuildFloatingIslandStratumPlan(const UVoxelStrateManager* StrateManager, + / Recipe.ownerToCoreScaleDenominator; + Recipe.spacingSubvoxels = WorldAssemblyFixed(Params.IslandSpacing * OwnerToCoreScale); + Recipe.minimumRadiusSubvoxels = WorldAssemblyFixed(Params.IslandMinRadius * OwnerToCoreScale); +- Recipe.maximumRadiusSubvoxels = WorldAssemblyFixed(Params.IslandMaxRadius * OwnerToCoreScale); ++ Recipe.maximumRadiusSubvoxels = WorldAssemblyFixed(28.0 * OwnerToCoreScale); + Recipe.thicknessRatioQ16 = WorldAssemblyQ16(Params.ThicknessRatio); + Recipe.verticalJitterQ16 = WorldAssemblyQ16(Params.VerticalJitter); + Recipe.topFlattenQ16 = WorldAssemblyQ16(Params.TopFlatten); +- Recipe.roughnessSubvoxels = WorldAssemblyFixed(Params.SurfaceRoughness * OwnerToCoreScale); +- Recipe.blendRadiusSubvoxels = WorldAssemblyFixed(Params.SDFBlendRadius * OwnerToCoreScale); ++ Recipe.roughnessSubvoxels = std::min(WorldAssemblyFixed( ++ Params.SurfaceRoughness * OwnerToCoreScale), WorldAssemblySubvoxelsPerVoxel / 2); ++ Recipe.blendRadiusSubvoxels = 2 * WorldAssemblySubvoxelsPerVoxel; ++ Recipe.contourWarpSubvoxels = WorldAssemblySubvoxelsPerVoxel; + Recipe.boundarySealSubvoxels = WorldAssemblyFixed(Params.BoundarySealThickness * OwnerToCoreScale); ++ Recipe.routeConstraints.version = 1; ++ Recipe.routeConstraints.capsuleRadiusSubvoxels = 348; ++ Recipe.routeConstraints.capsuleHeightSubvoxels = 1802; ++ Recipe.routeConstraints.maximumGradeQ16 = 17560; ++ Recipe.routeConstraints.sweepSpacingSubvoxels = 128; ++ Recipe.routeConstraints.supportProbeRadiusSubvoxels = 230; ++ Recipe.routeConstraints.supportSearchDepthSubvoxels = 512; ++ Recipe.routeConstraints.minimumClearanceSubvoxels = 128; ++ Recipe.routeConstraints.minimumSupportProbes = 3; + const auto OwnerVoxelsToCoreQ=[&](double Value) + { + return static_cast(std::llround(Value*Recipe.ownerVoxelSizeMicrons +@@ -944,40 +957,21 @@ bool BuildFloatingIslandStratumPlan(const UVoxelStrateManager* StrateManager, + Recipe.anchorIslandOrdinal=Recipe.primaryIslandCount-1; + Recipe.anchorPlacementRadiusSubvoxels=WorldAssemblyMicrometresToSubvoxels( + Slot.PassageDistanceMaximumMicrometres, Recipe.coreVoxelSizeMicrons); +- const std::int64_t spiralRadius=WorldAssemblyMicrometresToSubvoxels( +- Slot.PassageSpiralRadiusMicrometres, Recipe.coreVoxelSizeMicrons); +- // Reserve at least a 1.5 m mid-bore through the anchor root. +- constexpr double AnchorPassageMinimumBoreOwnerVoxels=12.0; +- const std::int64_t OwnerVoxelMicrometres = Recipe.ownerVoxelSizeMicrons; +- const std::int64_t mouthBore=std::max( +- WorldAssemblyMicrometresToSubvoxels(Slot.PassageMouthRadiusMicrometres, +- Recipe.coreVoxelSizeMicrons), +- WorldAssemblyMicrometresToSubvoxels(12 * OwnerVoxelMicrometres, +- Recipe.coreVoxelSizeMicrons)); +- const std::int64_t bore=std::max( +- WorldAssemblyMicrometresToSubvoxels(Slot.PassageMidRadiusMicrometres, +- Recipe.coreVoxelSizeMicrons), +- WorldAssemblyMicrometresToSubvoxels( +- static_cast(AnchorPassageMinimumBoreOwnerVoxels * OwnerVoxelMicrometres), +- Recipe.coreVoxelSizeMicrons)); +- const std::int64_t wallReserve=WorldAssemblyMicrometresToSubvoxels( +- 12 * OwnerVoxelMicrometres, Recipe.coreVoxelSizeMicrons); +- const std::int64_t FourOwnerVoxelsSubvoxels=WorldAssemblyMicrometresToSubvoxels( +- 4 * OwnerVoxelMicrometres, Recipe.coreVoxelSizeMicrons); +- Recipe.anchorMouthOffsetSubvoxels=spiralRadius+mouthBore+FourOwnerVoxelsSubvoxels; +- const std::int64_t excursion=std::max( +- WorldAssemblyMicrometresToSubvoxels(Slot.PassageWanderMicrometres, +- Recipe.coreVoxelSizeMicrons), spiralRadius); +- Recipe.anchorRootRadiusSubvoxels=excursion+bore+wallReserve; +- Recipe.anchorIslandMinimumRadiusSubvoxels=std::max(Recipe.minimumRadiusSubvoxels, +- Recipe.anchorMouthOffsetSubvoxels+mouthBore+FourOwnerVoxelsSubvoxels); ++ Recipe.anchorMouthOffsetSubvoxels = OwnerVoxelsToCoreQ(4.0); ++ Recipe.anchorRootRadiusSubvoxels = std::max(OwnerVoxelsToCoreQ(16.0), ++ Recipe.anchorMouthOffsetSubvoxels + Recipe.routeConstraints.capsuleRadiusSubvoxels ++ + WorldAssemblySubvoxelsPerVoxel); ++ Recipe.anchorIslandMinimumRadiusSubvoxels = std::max(Recipe.maximumRadiusSubvoxels, ++ Recipe.anchorMouthOffsetSubvoxels + Recipe.routeConstraints.capsuleRadiusSubvoxels ++ + WorldAssemblySubvoxelsPerVoxel); + Recipe.anchorRootBottomZSubvoxels=Recipe.layoutMinimumZSubvoxels + +Recipe.boundarySealSubvoxels; + std::string PlanError; +- const std::optional Planned = PlanFloatingIslandCluster(Recipe, PlanError); ++ const std::optional Planned = ++ PlanFloatingIslandClusterAroundPassages(Recipe, Layout, Slot.StrateIndex, PlanError); + if (!Planned) + { +- OutError = FString::Printf(TEXT("FloatingIslands automatic plan for strate %d failed: %s"), ++ OutError = FString::Printf(TEXT("FloatingIslands passage-aware plan for strate %d failed: %s"), + Slot.StrateIndex, UTF8_TO_TCHAR(PlanError.c_str())); + return false; + } +@@ -1671,18 +1665,6 @@ bool AttachValidatedWorldAssembly(const UVoxelSettings* Settings, + Generated.plan.strates.push_back(std::move(Stratum)); + ++BuiltSurfaceCount; + } +- // Native floating-island evaluation remains an explicit imported-plan opt-in. +- // The default owner path uses the legacy generator for this slot; emitting an +- // automatic FI plan here silently switches density dispatch and changes the +- // shared passage mouth before the owner has opted into that field. +- else if (Type == ECaveGeneratorType::FloatingIslands && bImportedOverride) +- { +- if (!BuildFloatingIslandStratumPlan(StrateManager, Slot, Generated, +- CoreVoxelSizeCm, LayoutChunkWidthSubvoxels, OutError)) +- { +- return false; +- } +- } + } + if (BuiltSurfaceCount > 1) + { +@@ -2031,6 +2013,98 @@ bool AttachValidatedWorldAssembly(const UVoxelSettings* Settings, + { + return false; + } ++ bool bAddedFloatingIslandPlan = false; ++ for (const FStrateSlot& Slot : StrateManager->GetLayout()) ++ { ++ if (Slot.Definition == nullptr ++ || StrateManager->GetGeneratorTypeForChunk(FIntVector(0, 0, Slot.TopChunkZ)) ++ != ECaveGeneratorType::FloatingIslands) ++ { ++ continue; ++ } ++ const auto Existing = std::find_if(Manifest->floatingIslands.begin(), ++ Manifest->floatingIslands.end(), [&Slot](const auto& Plan) ++ { return Plan.strateIndex == Slot.StrateIndex; }); ++ if (Existing != Manifest->floatingIslands.end()) continue; ++ if (!BuildFloatingIslandStratumPlan(StrateManager, Slot, *Manifest, Layout, ++ CoreVoxelSizeCm, LayoutChunkWidthSubvoxels, OutError)) ++ { ++ return false; ++ } ++ bAddedFloatingIslandPlan = true; ++ } ++ if (bAddedFloatingIslandPlan) ++ { ++ if (!Manifest->finalize(CoreError)) ++ { ++ OutError = FString::Printf(TEXT("Core passage-aware FloatingIslands planning failed: %s"), ++ UTF8_TO_TCHAR(CoreError.c_str())); ++ return false; ++ } ++ ManifestHash = FString::Printf(TEXT("%016llx"), ++ static_cast(Manifest->contentHash)); ++ for (const auto& Plan : Manifest->floatingIslands) ++ { ++ auto Stratum = std::find_if(Layout.strates.begin(), Layout.strates.end(), ++ [&Plan](const auto& Item) { return Item.strateIndex == Plan.strateIndex; }); ++ if (Stratum == Layout.strates.end()) ++ { ++ OutError = FString::Printf(TEXT("FloatingIslands strate %d disappeared before anchor export."), ++ Plan.strateIndex); ++ return false; ++ } ++ Stratum->recipeVersion = Plan.manifest.recipe.geometryVersion; ++ std::erase_if(Stratum->anchors, [](const auto& Anchor) ++ { ++ return Anchor.kind == "island_anchor" || Anchor.kind == "passage_anchor" ++ || Anchor.kind == "route_point"; ++ }); ++ const auto& NativePlan = Plan.manifest.plan; ++ const auto& NativeRecipe = Plan.manifest.recipe; ++ for (std::size_t IslandIndex = 0; IslandIndex < NativePlan.islands.size(); ++IslandIndex) ++ { ++ const auto& Island = NativePlan.islands[IslandIndex]; ++ VoxelForgeCore::ResolvedLayoutAnchorV2 Anchor; ++ Anchor.kind = "island_anchor"; ++ Anchor.stableId = "island/" + std::to_string(IslandIndex); ++ Anchor.units = "1/256 Core voxel"; ++ Anchor.values = { Island.centerSubvoxels[0], Island.centerSubvoxels[1], ++ Island.centerSubvoxels[2], Island.radiusSubvoxels, Island.topHalfSubvoxels }; ++ Stratum->anchors.push_back(std::move(Anchor)); ++ if (IslandIndex == NativeRecipe.anchorIslandOrdinal) ++ { ++ 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], ++ NativeRecipe.anchorRootRadiusSubvoxels, ++ NativeRecipe.anchorMouthOffsetSubvoxels, ++ NativeRecipe.anchorPlacementRadiusSubvoxels, ++ NativeRecipe.anchorRootBottomZSubvoxels, Island.radiusSubvoxels }; ++ if (!NativePlan.route.empty()) ++ { ++ const auto& Mouth = NativePlan.route.back().positionSubvoxels; ++ PassageAnchor.values.insert(PassageAnchor.values.end(), ++ { Mouth[0], Mouth[1], Mouth[2] }); ++ } ++ Stratum->anchors.push_back(std::move(PassageAnchor)); ++ } ++ } ++ for (std::size_t RouteIndex = 0; RouteIndex < NativePlan.route.size(); ++RouteIndex) ++ { ++ const auto& Point = NativePlan.route[RouteIndex]; ++ VoxelForgeCore::ResolvedLayoutAnchorV2 Anchor; ++ Anchor.kind = "route_point"; ++ Anchor.stableId = "route/" + std::to_string(RouteIndex); ++ Anchor.units = "1/256 Core voxel"; ++ Anchor.values = { Point.positionSubvoxels[0], Point.positionSubvoxels[1], ++ Point.positionSubvoxels[2], Point.radiusSubvoxels }; ++ Stratum->anchors.push_back(std::move(Anchor)); ++ } ++ } ++ } + std::string LayoutError; + if (!Layout.finalize(LayoutError)) + { +diff --git a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h +index 8c44461..ec7cfe3 100644 +--- a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h ++++ b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h +@@ -511,7 +511,7 @@ namespace VoxelForgeCore + // the planned graph route, preserves its walk corridor through shell overlaps, and keeps + // boundary-blended host rock from widening the authored passage wall. + // v237 adds the shared Core cave-graph shaft primitive and basal terminal route. +- inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 237; ++ inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 239; + + enum class FieldChannel : std::uint32_t + { +@@ -1417,6 +1417,19 @@ namespace VoxelForgeCore + bool passed = false; + }; + ++ struct FloatingIslandPassageClearanceAuditResult ++ { ++ std::uint64_t passageSamples = 0; ++ std::uint64_t blockedIslandSamples = 0; ++ std::uint64_t routeSamples = 0; ++ std::uint64_t blockedRouteSamples = 0; ++ std::uint32_t arrivalMouthSupportProbes = 0; ++ std::uint32_t departureMouthSupportProbes = 0; ++ std::int64_t minimumExcessClearanceSubvoxels = 0; ++ double portalExclusionMetres = 0.0; ++ bool passed = false; ++ }; ++ + struct FloatingIslandInfluenceBounds + { + bool finite = false; +@@ -1461,11 +1474,17 @@ namespace VoxelForgeCore + // Planner output is ordinary reviewed data; clients can load it without re-running the planner. + VFCORE_API std::optional PlanFloatingIslandCluster( + const FloatingIslandRecipeV1& recipe, std::string& error); ++ VFCORE_API std::optional PlanFloatingIslandClusterAroundPassages( ++ const FloatingIslandRecipeV1& recipe, const ResolvedLayoutSnapshotV3& layout, ++ std::int32_t strateIndex, std::string& error); + VFCORE_API FloatingIslandBoundsAuditResult AuditFloatingIslandBounds( + const FloatingIslandFieldV1& field, std::uint32_t boxCount = 256, + std::uint64_t seed = 0x49534c414e444231ull); + VFCORE_API FloatingIslandRouteAuditResult AuditFloatingIslandRoute( + const FloatingIslandFieldV1& field, std::int64_t routeOffsetSubvoxels = 0); ++ VFCORE_API FloatingIslandPassageClearanceAuditResult AuditFloatingIslandPassageClearance( ++ const FloatingIslandFieldV1& field, const ResolvedLayoutSnapshotV3& layout, ++ std::int32_t strateIndex, double portalExclusionMetres = 10.0); + VFCORE_API FloatingIslandThicknessAuditResult AuditFloatingIslandThickness( + const FloatingIslandPlanV1& plan, double minimumDepthToDiameterRatio = 0.70); + +diff --git a/Standalone/Core/src/FloatingIslandsInternal.h b/Standalone/Core/src/FloatingIslandsInternal.h +index 33d97d6..58f0959 100644 +--- a/Standalone/Core/src/FloatingIslandsInternal.h ++++ b/Standalone/Core/src/FloatingIslandsInternal.h +@@ -4,6 +4,7 @@ + #include "VoxelForgeCore/CpuCycleCounter.h" + #include "VoxelForgeCore/FloatingIslandInstrumentation.h" + #include "VoxelForgeCore/SharedColumnCache.h" ++#include "VoxelForgeCore/PassageSpline.h" + #include "Json.h" + #include "VoxelForgeCore/VoxelForgeCore.h" + +@@ -285,7 +286,7 @@ namespace floating_island_detail + ? recipe.ownerVoxelSizeMicrons / ScaleGcd : 0; + const std::uint32_t ExpectedDenominator = ScaleGcd > 0 + ? recipe.coreVoxelSizeMicrons / ScaleGcd : 0; +- if (recipe.schemaVersion != 1 || recipe.geometryVersion < 1 || recipe.geometryVersion > 8 ++ if (recipe.schemaVersion != 1 || recipe.geometryVersion < 1 || recipe.geometryVersion > 10 + || (recipe.geometryVersion == 1 + && (recipe.crustDepthBonusQ16 != 0 || recipe.rootDepthRatioQ16 != 0)) + || recipe.unitsPerVoxel != Q +@@ -1988,6 +1989,229 @@ std::string FloatingIslandManifestV1::ToJson() const + return out.str(); + } + ++namespace floating_island_detail ++{ ++ struct FIslandPassageSpan ++ { ++ PassageSpline::FSegment segment; ++ double alongMetres = 0.0; ++ double totalMetres = 0.0; ++ double radiusSubvoxels = 0.0; ++ bool portalAtStart = false; ++ }; ++ ++ inline double SegmentDistanceSquared3D(const PassageSpline::FPoint& p1, ++ const PassageSpline::FPoint& q1, const PassageSpline::FPoint& p2, ++ const PassageSpline::FPoint& q2) ++ { ++ const std::array d1={q1[0]-p1[0],q1[1]-p1[1],q1[2]-p1[2]}; ++ const std::array d2={q2[0]-p2[0],q2[1]-p2[1],q2[2]-p2[2]}; ++ const std::array r={p1[0]-p2[0],p1[1]-p2[1],p1[2]-p2[2]}; ++ const auto dot=[](const auto& a,const auto& b) ++ {return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];}; ++ const double a=dot(d1,d1),e=dot(d2,d2),f=dot(d2,r); ++ double s=0.0,t=0.0; ++ if(a<=1.0e-18&&e<=1.0e-18)return dot(r,r); ++ if(a<=1.0e-18)t=std::clamp(f/e,0.0,1.0); ++ else ++ { ++ const double c=dot(d1,r); ++ if(e<=1.0e-18)s=std::clamp(-c/a,0.0,1.0); ++ else ++ { ++ const double b=dot(d1,d2); ++ const double denominator=a*e-b*b; ++ if(std::abs(denominator)>1.0e-18) ++ s=std::clamp((b*f-c*e)/denominator,0.0,1.0); ++ t=(b*s+f)/e; ++ if(t<0.0){t=0.0;s=std::clamp(-c/a,0.0,1.0);} ++ else if(t>1.0){t=1.0;s=std::clamp((b-c)/a,0.0,1.0);} ++ } ++ } ++ std::array delta{}; ++ for(std::size_t axis=0;axis<3;++axis) ++ delta[axis]=r[axis]+s*d1[axis]-t*d2[axis]; ++ return dot(delta,delta); ++ } ++ ++ inline std::vector BuildIslandPassageSpans( ++ const ResolvedLayoutSnapshotV3& layout,std::int32_t strateIndex, ++ const FloatingIslandRecipeV1& recipe,double portalExclusionMetres) ++ { ++ std::vector spans; ++ const double qPerMetre=static_cast(WorldAssemblySubvoxelsPerVoxel) ++ *1000000.0/std::max(1,recipe.coreVoxelSizeMicrons); ++ for(const auto& passage:layout.passages) ++ { ++ const bool upper=passage.upperStrateIndex==strateIndex; ++ const bool lower=passage.lowerStrateIndex==strateIndex; ++ if((!upper&&!lower)||passage.controlPoints.size()<2)continue; ++ std::vector controls; ++ controls.reserve(passage.controlPoints.size()); ++ for(const auto& point:passage.controlPoints) ++ controls.push_back({static_cast(point.positionSubvoxels[0]), ++ static_cast(point.positionSubvoxels[1]), ++ static_cast(point.positionSubvoxels[2]), ++ static_cast(point.radiusSubvoxels)}); ++ const auto built=PassageSpline::BuildSegments(controls,controls.size()-1, ++ 0.25,qPerMetre,{},0.04); ++ if(built.empty())continue; ++ const double total=built.back().alongMetres+built.back().lengthMetres; ++ const auto& first=controls.front(); ++ const auto& last=controls.back(); ++ const auto distanceSquaredTo=[&](const PassageSpline::FPoint& point, ++ const std::array& mouth) ++ { ++ double result=0.0; ++ for(std::size_t axis=0;axis<3;++axis) ++ {const double delta=point[axis]-mouth[axis];result+=delta*delta;} ++ return result; ++ }; ++ const bool upperAtStart=distanceSquaredTo(first,passage.upperMouthSubvoxels) ++ <=distanceSquaredTo(last,passage.upperMouthSubvoxels); ++ const bool portalAtStart=upper?upperAtStart:!upperAtStart; ++ for(const auto& segment:built) ++ { ++ const double along=segment.alongMetres+0.5*segment.lengthMetres; ++ const double portalDistance=portalAtStart?along:total-along; ++ if(portalDistance<=portalExclusionMetres)continue; ++ const PassageSpline::FPoint midpoint={ ++ 0.5*(segment.a[0]+segment.b[0]), ++ 0.5*(segment.a[1]+segment.b[1]), ++ 0.5*(segment.a[2]+segment.b[2]), ++ 0.5*(segment.a[3]+segment.b[3])}; ++ const double minZ=std::min(segment.a[2],segment.b[2]); ++ const double maxZ=std::max(segment.a[2],segment.b[2]); ++ if(maxZ(recipe.layoutMinimumZSubvoxels) ++ ||minZ>static_cast(recipe.layoutMaximumZSubvoxels))continue; ++ spans.push_back({segment,along,total,midpoint[3],portalAtStart}); ++ } ++ } ++ return spans; ++ } ++ ++ inline std::array EvaluateIslandRouteBezier( ++ const std::array& a,const std::array& b, ++ const std::array& waypoint,double t) ++ { ++ const double u=1.0-t; ++ const std::array result={ ++ u*u*u*a[0]+3.0*u*u*t*waypoint[0]+3.0*u*t*t*waypoint[0]+t*t*t*b[0], ++ u*u*u*a[1]+3.0*u*u*t*waypoint[1]+3.0*u*t*t*waypoint[1]+t*t*t*b[1], ++ std::lerp(a[2],b[2],t),t}; ++ return result; ++ } ++ ++ struct FIslandDetourCandidate ++ { ++ std::array,9> centers{}; ++ double horizontalLengthMetres=0.0; ++ double conservativeClearanceMetres=-std::numeric_limits::infinity(); ++ double waypointAngle=0.0; ++ double waypointRadiusMetres=0.0; ++ }; ++ ++ inline std::vector BuildIslandDetourCandidates( ++ const FloatingIslandRecipeV1& recipe,const ResolvedLayoutPassageV1& arrival, ++ const ResolvedLayoutPassageV1& departure, ++ const std::vector& spans) ++ { ++ std::vector candidates; ++ const double qPerMetre=static_cast(WorldAssemblySubvoxelsPerVoxel) ++ *1000000.0/std::max(1,recipe.coreVoxelSizeMicrons); ++ const std::array a={static_cast(arrival.lowerMouthSubvoxels[0]), ++ static_cast(arrival.lowerMouthSubvoxels[1]), ++ static_cast(arrival.lowerMouthSubvoxels[2])}; ++ const std::array b={static_cast(departure.upperMouthSubvoxels[0]), ++ static_cast(departure.upperMouthSubvoxels[1]), ++ static_cast(departure.upperMouthSubvoxels[2])}; ++ for(int angleIndex=0;angleIndex<16;++angleIndex) ++ for(const double radiusMetres:{60.0,72.0,84.0}) ++ { ++ FIslandDetourCandidate candidate; ++ candidate.waypointAngle=2.0*Pi*angleIndex/16.0; ++ candidate.waypointRadiusMetres=radiusMetres; ++ const std::array waypoint={ ++ static_cast(recipe.layoutOriginXSubvoxels) ++ +std::cos(candidate.waypointAngle)*radiusMetres*qPerMetre, ++ static_cast(recipe.layoutOriginYSubvoxels) ++ +std::sin(candidate.waypointAngle)*radiusMetres*qPerMetre, ++ 0.5*(a[2]+b[2])}; ++ constexpr std::size_t CurveSteps=512; ++ std::array arc{}; ++ std::array,CurveSteps+1> curve{}; ++ auto prior=EvaluateIslandRouteBezier(a,b,waypoint,0.0); ++ curve[0]={prior[0],prior[1],prior[2]}; ++ for(std::size_t n=1;n<=CurveSteps;++n) ++ { ++ const auto value=EvaluateIslandRouteBezier(a,b,waypoint, ++ static_cast(n)/CurveSteps); ++ curve[n]={value[0],value[1],value[2]}; ++ const double dx=(value[0]-prior[0])/qPerMetre; ++ const double dy=(value[1]-prior[1])/qPerMetre; ++ arc[n]=arc[n-1]+std::hypot(dx,dy); ++ prior=value; ++ } ++ candidate.horizontalLengthMetres=arc.back(); ++ if(!(candidate.horizontalLengthMetres>1.0))continue; ++ for(std::size_t island=0;island( ++ CurveSteps,static_cast(upper-arc.begin())); ++ const std::size_t lowerIndex=upperIndex?upperIndex-1:0; ++ const double span=arc[upperIndex]-arc[lowerIndex]; ++ const double t=span>1.0e-9?(target-arc[lowerIndex])/span:0.0; ++ auto point=std::array{ ++ std::lerp(curve[lowerIndex][0],curve[upperIndex][0],t), ++ std::lerp(curve[lowerIndex][1],curve[upperIndex][1],t), ++ std::lerp(a[2],b[2],target/arc.back())}; ++ if(island==0)point=a; ++ if(island+1==candidate.centers.size())point=b; ++ for(std::size_t axis=0;axis<3;++axis) ++ candidate.centers[island][axis]=RoundQ(point[axis]); ++ } ++ double minimumClearance=std::numeric_limits::infinity(); ++ for(std::size_t routeIndex=1;routeIndex(candidate.centers[routeIndex-1][axis]); ++ routeB[axis]=static_cast(candidate.centers[routeIndex][axis]); ++ } ++ for(const auto& span:spans) ++ { ++ const double distance=std::sqrt(SegmentDistanceSquared3D( ++ routeA,routeB,span.segment.a,span.segment.b))/qPerMetre; ++ const double passageRadius=span.radiusSubvoxels/qPerMetre; ++ const double capsuleRadius=0.5*recipe.routeConstraints.capsuleHeightSubvoxels/qPerMetre; ++ const double featureReach=recipe.maximumRadiusSubvoxels/qPerMetre ++ +(recipe.contourWarpSubvoxels+IslandBlendMargin(recipe) ++ +recipe.roughnessSubvoxels)/qPerMetre; ++ minimumClearance=std::min(minimumClearance,distance-passageRadius ++ -1.0533-capsuleRadius-featureReach-0.15); ++ } ++ } ++ candidate.conservativeClearanceMetres=std::isfinite(minimumClearance) ++ ?minimumClearance:1.0e6; ++ candidates.push_back(candidate); ++ } ++ std::stable_sort(candidates.begin(),candidates.end(), ++ [](const auto& left,const auto& right) ++ { ++ const bool leftSafe=left.conservativeClearanceMetres>=0.0; ++ const bool rightSafe=right.conservativeClearanceMetres>=0.0; ++ if(leftSafe!=rightSafe)return leftSafe; ++ if(left.horizontalLengthMetres!=right.horizontalLengthMetres) ++ return left.horizontalLengthMetresright.conservativeClearanceMetres; ++ }); ++ return candidates; ++ } ++} ++ + std::optional PlanFloatingIslandCluster( + const FloatingIslandRecipeV1& inputRecipe, std::string& error) + { +@@ -2264,6 +2488,210 @@ std::optional PlanFloatingIslandCluster( + return manifest; + } + ++std::optional PlanFloatingIslandClusterAroundPassages( ++ const FloatingIslandRecipeV1& inputRecipe,const ResolvedLayoutSnapshotV3& layout, ++ std::int32_t strateIndex,std::string& error) ++{ ++ using namespace floating_island_detail; ++ FloatingIslandRecipeV1 recipe=inputRecipe; ++ if(recipe.routeConstraints.version==0) ++ { ++ recipe.routeConstraints.version=1; ++ recipe.routeConstraints.capsuleRadiusSubvoxels=348; ++ recipe.routeConstraints.capsuleHeightSubvoxels=1802; ++ recipe.routeConstraints.maximumGradeQ16=17560; ++ recipe.routeConstraints.sweepSpacingSubvoxels=128; ++ recipe.routeConstraints.supportProbeRadiusSubvoxels=230; ++ recipe.routeConstraints.supportSearchDepthSubvoxels=512; ++ recipe.routeConstraints.minimumClearanceSubvoxels=128; ++ recipe.routeConstraints.minimumSupportProbes=3; ++ } ++ if(recipe.geometryVersion<10||recipe.primaryIslandCount!=9) ++ {error="corridor-aware FloatingIslands requires geometry version 10 and nine route islands";return std::nullopt;} ++ if(!ValidateRecipe(recipe,error))return std::nullopt; ++ ++ const ResolvedLayoutPassageV1* arrival=nullptr; ++ const ResolvedLayoutPassageV1* departure=nullptr; ++ for(const auto& passage:layout.passages) ++ { ++ if(passage.lowerStrateIndex==strateIndex ++ &&passage.upperStrateIndexstrateIndex)departure=&passage; ++ } ++ if(!arrival||!departure) ++ {error="corridor-aware FloatingIslands needs resolved arrival and departure mouths";return std::nullopt;} ++ ++ constexpr double PortalExclusionMetres=13.0; ++ const auto passageSpans=BuildIslandPassageSpans(layout,strateIndex,recipe, ++ PortalExclusionMetres); ++ if(passageSpans.empty()) ++ {error="corridor-aware FloatingIslands found no resolved passage spans inside its strate";return std::nullopt;} ++ auto candidates=BuildIslandDetourCandidates(recipe,*arrival,*departure,passageSpans); ++ const double qPerMetre=static_cast(WorldAssemblySubvoxelsPerVoxel) ++ *1000000.0/std::max(1,recipe.coreVoxelSizeMicrons); ++ const double capsuleHalf=0.5*recipe.routeConstraints.capsuleHeightSubvoxels; ++ const double routeLift=capsuleHalf+recipe.routeConstraints.minimumClearanceSubvoxels+Q/8.0; ++ std::uint32_t tried=0; ++ std::string lastFailure="no outer detour has conservative tube clearance"; ++ for(const auto& candidate:candidates) ++ { ++ if(candidate.conservativeClearanceMetres<0.0)break; ++ ++tried; ++ FloatingIslandManifestV1 manifest; ++ manifest.recipe=recipe; ++ auto& plan=manifest.plan; ++ plan.islands.reserve(recipe.primaryIslandCount); ++ bool candidateValid=true; ++ for(std::uint32_t ordinal=0;ordinal(ordinal)/(recipe.primaryIslandCount-1); ++ const std::int64_t topZ=RoundQ(std::lerp( ++ static_cast(arrival->lowerMouthSubvoxels[2])-routeLift, ++ static_cast(departure->upperMouthSubvoxels[2])-routeLift,t)); ++ auto island=MakeIsland(recipe,ordinal,center[0],center[1],topZ, ++ 0x100000000ull+ordinal); ++ if(ordinal==recipe.anchorIslandOrdinal) ++ island.radiusSubvoxels=std::max(island.radiusSubvoxels, ++ recipe.anchorIslandMinimumRadiusSubvoxels); ++ island.topHalfSubvoxels=std::max(1,island.radiusSubvoxels/5); ++ island.centerSubvoxels[2]=island.topZSubvoxels-island.topHalfSubvoxels; ++ island.bottomZSubvoxels=IslandBottom(recipe,island.topZSubvoxels, ++ island.radiusSubvoxels); ++ SetIslandBounds(recipe,island); ++ if(island.bottomZSubvoxelsrecipe.layoutMaximumZSubvoxels ++ -recipe.boundarySealSubvoxels) ++ {candidateValid=false;lastFailure="detour island escaped the sealed vertical layout";break;} ++ plan.islands.push_back(std::move(island)); ++ } ++ if(!candidateValid)continue; ++ for(std::uint32_t ordinal=0;ordinal+1(b[0]-a[0]); ++ const double dy=static_cast(b[1]-a[1]); ++ const std::uint32_t pieces=static_cast(std::max(1.0, ++ std::ceil(std::hypot(dx,dy)/routeStep))); ++ for(std::uint32_t piece=segment==0?0:1;piece<=pieces;++piece) ++ { ++ const double t=static_cast(piece)/pieces; ++ const std::int64_t x=RoundQ(static_cast(a[0])+dx*t); ++ const std::int64_t y=RoundQ(static_cast(a[1])+dy*t); ++ const auto surface=FindCapsuleFootingTopZ(recipe,plan,x,y); ++ if(!surface) ++ {candidateValid=false;lastFailure="detour route has no full capsule-width island support";break;} ++ WorldAssemblyRoutePointV1 point; ++ point.stableFeatureId=StableId(recipe.seed,0x500000000ull+routeOrdinal, ++ 0x524f555445ull); ++ point.positionSubvoxels={x,y,*surface+static_cast(std::llround(routeLift))}; ++ point.radiusSubvoxels=4*Q; ++ if(segment==0&&piece==0) ++ point.positionSubvoxels=arrival->lowerMouthSubvoxels; ++ if(segment+2==plan.islands.size()&&piece==pieces) ++ point.positionSubvoxels=departure->upperMouthSubvoxels; ++ if(!plan.route.empty()&&plan.route.back().positionSubvoxels==point.positionSubvoxels) ++ continue; ++ plan.route.push_back(point); ++ ++routeOrdinal; ++ } ++ if(!candidateValid)break; ++ } ++ if(!candidateValid||plan.route.size()<2)continue; ++ ++ const double maximumGrade=Q16ToDouble(recipe.routeConstraints.maximumGradeQ16)*0.95; ++ std::vector baseHeights; ++ baseHeights.reserve(plan.route.size()); ++ for(const auto& point:plan.route)baseHeights.push_back(point.positionSubvoxels[2]); ++ std::vector profile=baseHeights; ++ for(std::size_t i=0;i(baseHeights[i]); ++ for(std::size_t j=0;j(plan.route[i].positionSubvoxels[0] ++ -plan.route[j].positionSubvoxels[0]); ++ const double dy=static_cast(plan.route[i].positionSubvoxels[1] ++ -plan.route[j].positionSubvoxels[1]); ++ adjusted=std::max(adjusted,static_cast(baseHeights[j]) ++ -maximumGrade*std::hypot(dx,dy)); ++ } ++ profile[i]=RoundQ(adjusted); ++ } ++ const auto arrivalZ=arrival->lowerMouthSubvoxels[2]; ++ const auto departureZ=departure->upperMouthSubvoxels[2]; ++ if(profile.front()>arrivalZ+Q/2||profile.back()>departureZ+Q/2) ++ {lastFailure="island support profile cannot meet both fixed mouth elevations";continue;} ++ for(std::size_t i=1;i+1lowerMouthSubvoxels; ++ plan.route.back().positionSubvoxels=departure->upperMouthSubvoxels; ++ ++ if(!manifest.finalize(error)) ++ {lastFailure=error;continue;} ++ const FloatingIslandFieldV1 field(manifest.recipe,manifest.plan); ++ const auto routeAudit=AuditFloatingIslandRoute(field); ++ if(!routeAudit.passed) ++ { ++ lastFailure="detour route sweep failed: blocked=" ++ +std::to_string(routeAudit.blockedCapsuleSamples)+" unsupported=" ++ +std::to_string(routeAudit.unsupportedCenterSamples)+" grade=" ++ +std::to_string(routeAudit.gradeFailures)+" detour_angle_deg=" ++ +std::to_string(candidate.waypointAngle*180.0/Pi)+" detour_radius_m=" ++ +std::to_string(candidate.waypointRadiusMetres)+" first_unsupported_q=(" ++ +std::to_string(routeAudit.firstUnsupportedCenterSubvoxels[0])+","+ ++ std::to_string(routeAudit.firstUnsupportedCenterSubvoxels[1])+","+ ++ std::to_string(routeAudit.firstUnsupportedCenterSubvoxels[2])+") segment=" ++ +std::to_string(routeAudit.firstUnsupportedSegment); ++ continue; ++ } ++ const auto clearance=AuditFloatingIslandPassageClearance(field,layout, ++ strateIndex,PortalExclusionMetres); ++ if(!clearance.passed) ++ { ++ lastFailure="passage clearance failed: island=" ++ +std::to_string(clearance.blockedIslandSamples)+" route=" ++ +std::to_string(clearance.blockedRouteSamples)+" mouth_support=" ++ +std::to_string(clearance.arrivalMouthSupportProbes)+"/" ++ +std::to_string(clearance.departureMouthSupportProbes); ++ continue; ++ } ++ const std::string encoded=manifest.ToJson(); ++ const auto roundTrip=FloatingIslandManifestV1::FromJson(encoded,error); ++ if(!roundTrip||roundTrip->ToJson()!=encoded ++ ||roundTrip->contentHash!=manifest.contentHash) ++ {if(error.empty())error="corridor-aware floating-island plan did not canonical-round-trip";return std::nullopt;} ++ std::printf("[FloatingIslandCorridorPlan] strate=%d detours_tried=%u waypoint_angle_deg=%.1f waypoint_radius_m=%.1f route_m=%.1f conservative_clearance_m=%.2f portal_exclusion_m=%.1f islands=%zu arrival_binding=PASS departure_binding=PASS status=PASS\n", ++ strateIndex,tried,candidate.waypointAngle*180.0/Pi, ++ candidate.waypointRadiusMetres,candidate.horizontalLengthMetres, ++ candidate.conservativeClearanceMetres,PortalExclusionMetres, ++ manifest.plan.islands.size()); ++ error.clear(); ++ return manifest; ++ } ++ const auto bestCandidate=std::max_element(candidates.begin(),candidates.end(), ++ [](const auto& left,const auto& right) ++ {return left.conservativeClearanceMetresconservativeClearanceMetres)) ++ +" last="+lastFailure; ++ return std::nullopt; ++} ++ + FloatingIslandFieldV1::FloatingIslandFieldV1(const FloatingIslandRecipeV1& recipe, + const FloatingIslandPlanV1& plan) noexcept : recipe_(&recipe), plan_(&plan) + {} +@@ -2848,6 +3276,107 @@ FloatingIslandRouteAuditResult AuditFloatingIslandRoute(const FloatingIslandFiel + return result; + } + ++FloatingIslandPassageClearanceAuditResult AuditFloatingIslandPassageClearance( ++ const FloatingIslandFieldV1& field,const ResolvedLayoutSnapshotV3& layout, ++ std::int32_t strateIndex,double portalExclusionMetres) ++{ ++ using namespace floating_island_detail; ++ FloatingIslandPassageClearanceAuditResult result; ++ result.portalExclusionMetres=portalExclusionMetres; ++ if(!field.isValid()||!field.recipe()||!field.plan() ++ ||field.plan()->route.size()<2||!std::isfinite(portalExclusionMetres) ++ ||portalExclusionMetres<0.0)return result; ++ const auto& recipe=*field.recipe(); ++ const double qPerMetre=static_cast(WorldAssemblySubvoxelsPerVoxel) ++ *1000000.0/std::max(1,recipe.coreVoxelSizeMicrons); ++ const std::int64_t influenceReach=RoundQ(1.0533*qPerMetre); ++ const std::int64_t capsuleReach=recipe.routeConstraints.capsuleHeightSubvoxels/2; ++ const std::int64_t sampleGuard=RoundQ(0.15*qPerMetre); ++ const auto spans=BuildIslandPassageSpans(layout,strateIndex,recipe, ++ portalExclusionMetres); ++ bool haveClearance=false; ++ std::int64_t minimumExcess=std::numeric_limits::max(); ++ for(const auto& span:spans) ++ { ++ const PassageSpline::FPoint center={ ++ 0.5*(span.segment.a[0]+span.segment.b[0]), ++ 0.5*(span.segment.a[1]+span.segment.b[1]), ++ 0.5*(span.segment.a[2]+span.segment.b[2]), ++ 0.5*(span.segment.a[3]+span.segment.b[3])}; ++ const std::int64_t density=field.densitySubvoxels(RoundQ(center[0]), ++ RoundQ(center[1]),RoundQ(center[2])); ++ const std::int64_t required=RoundQ(center[3])+influenceReach ++ +capsuleReach+sampleGuard; ++ const std::int64_t excess=density-required; ++ minimumExcess=std::min(minimumExcess,excess); ++ haveClearance=true; ++ ++result.passageSamples; ++ if(excess<0)++result.blockedIslandSamples; ++ ++ for(std::size_t routeSegment=0;routeSegment+1route.size();++routeSegment) ++ { ++ const auto& routeA=field.plan()->route[routeSegment].positionSubvoxels; ++ const auto& routeB=field.plan()->route[routeSegment+1].positionSubvoxels; ++ PassageSpline::FPoint a{},b{}; ++ for(std::size_t axis=0;axis<3;++axis) ++ {a[axis]=static_cast(routeA[axis]);b[axis]=static_cast(routeB[axis]);} ++ const double distance=std::sqrt(SegmentDistanceSquared3D(a,b, ++ span.segment.a,span.segment.b)); ++ const double requiredDistance=center[3]+influenceReach ++ +capsuleReach+sampleGuard; ++ ++result.routeSamples; ++ if(distancestrateIndex) ++ departure=&passage; ++ } ++ const auto mouthSupport=[&](const std::array& mouth) ++ { ++ constexpr std::array,5> probes={{{0.0,0.0}, ++ {1.0,0.0},{-1.0,0.0},{0.0,1.0},{0.0,-1.0}}}; ++ const double radius=static_cast(recipe.routeConstraints.supportProbeRadiusSubvoxels); ++ const std::int64_t foot=mouth[2]-recipe.routeConstraints.capsuleHeightSubvoxels/2; ++ const std::int64_t sampleZ=foot-recipe.routeConstraints.minimumClearanceSubvoxels-Q/2; ++ std::uint32_t supported=0; ++ for(const auto& probe:probes) ++ { ++ const auto x=RoundQ(static_cast(mouth[0])+probe[0]*radius); ++ const auto y=RoundQ(static_cast(mouth[1])+probe[1]*radius); ++ if(field.densitySubvoxels(x,y,sampleZ)<0)++supported; ++ } ++ return supported; ++ }; ++ bool bound=false; ++ if(arrival&&departure) ++ { ++ const auto& route=field.plan()->route; ++ const auto close=[](const auto& a,const auto& b) ++ { ++ for(std::size_t axis=0;axis<3;++axis) ++ if(std::abs(a[axis]-b[axis])>2)return false; ++ return true; ++ }; ++ bound=close(route.front().positionSubvoxels,arrival->lowerMouthSubvoxels) ++ &&close(route.back().positionSubvoxels,departure->upperMouthSubvoxels); ++ result.arrivalMouthSupportProbes=mouthSupport(arrival->lowerMouthSubvoxels); ++ result.departureMouthSupportProbes=mouthSupport(departure->upperMouthSubvoxels); ++ } ++ result.passed=bound&&haveClearance&&result.blockedIslandSamples==0 ++ &&result.blockedRouteSamples==0 ++ &&result.arrivalMouthSupportProbes>=recipe.routeConstraints.minimumSupportProbes ++ &&result.departureMouthSupportProbes>=recipe.routeConstraints.minimumSupportProbes; ++ return result; ++} ++ + FloatingIslandThicknessAuditResult AuditFloatingIslandThickness( + const FloatingIslandPlanV1& plan, double minimumDepthToDiameterRatio) + { +diff --git a/Standalone/Core/src/ShapeWorldInternal.h b/Standalone/Core/src/ShapeWorldInternal.h +index 1a57f85..98dabf5 100644 +--- a/Standalone/Core/src/ShapeWorldInternal.h ++++ b/Standalone/Core/src/ShapeWorldInternal.h +@@ -1754,9 +1754,81 @@ public: + ?passageAirDistance:density); + if(nativeTunnelFieldDensity!=std::numeric_limits::lowest()) + return std::max(density,passageAirDistance); ++ const VoxelForgeCore::WorldAssemblyFloatingIslandPlanV1* landingPlan=nullptr; ++ if(WorldAssembly&&queryStratum&&queryStratum->Resolved ++ &&queryStratum->Resolved->generatorKind=="FloatingIslands") ++ { ++ const auto island=std::find_if(WorldAssembly->floatingIslands.begin(), ++ WorldAssembly->floatingIslands.end(),[&](const auto& candidate) ++ {return candidate.strateIndex==queryStratum->StrateIndex;}); ++ if(island!=WorldAssembly->floatingIslands.end())landingPlan=&*island; ++ } ++ const auto preserveFloatingIslandLandingSupport=[&](float composedDensity) ++ { ++ if(!landingPlan||landingPlan->manifest.recipe.geometryVersion<10) ++ return composedDensity; ++ const auto& constraints=landingPlan->manifest.recipe.routeConstraints; ++ if(constraints.version!=1)return composedDensity; ++ const auto* routeField=std::get_if( ++ &queryStratum->Evaluator); ++ const auto& route=landingPlan->manifest.plan.route; ++ if(!routeField||route.size()<2)return composedDensity; ++ ++ constexpr std::size_t LandingRouteSegments=18; ++ const double supportRadiusMetres=std::min(0.45, ++ constraints.supportProbeRadiusSubvoxels/qPerMetre+0.10); ++ const double queryX=qx,queryY=qy,queryZ=qz; ++ for(std::size_t segment=0;segment+1=LandingRouteSegments ++ &&segment+LandingRouteSegments(b[0]-a[0]); ++ const double dy=static_cast(b[1]-a[1]); ++ const double dz=static_cast(b[2]-a[2]); ++ const double horizontalSquared=dx*dx+dy*dy; ++ if(horizontalSquared<=1.0e-12)continue; ++ const double t=std::clamp(((queryX-a[0])*dx+(queryY-a[1])*dy) ++ /horizontalSquared,0.0,1.0); ++ const double routeX=a[0]+t*dx,routeY=a[1]+t*dy; ++ if(std::hypot(queryX-routeX,queryY-routeY) ++ >supportRadiusMetres*qPerMetre) ++ continue; ++ const double routeCenterZ=a[2]+t*dz; ++ const double footZ=routeCenterZ ++ -0.5*constraints.capsuleHeightSubvoxels; ++ const double shallowDepth=constraints.minimumClearanceSubvoxels+Q/2.0; ++ const double deepDepth=constraints.minimumClearanceSubvoxels ++ +constraints.supportSearchDepthSubvoxels; ++ if(queryZ<=footZ-shallowDepth&&queryZ>=footZ-deepDepth) ++ { ++ const std::int64_t nativeDensity=routeField->densitySubvoxelsAt( ++ static_cast(std::llround(queryX)), ++ static_cast(std::llround(queryY)), ++ static_cast(std::llround(queryZ))); ++ if(nativeDensity<0) ++ return std::min(composedDensity, ++ static_cast(static_cast(nativeDensity)/Q)); ++ } ++ } ++ return composedDensity; ++ }; + if(unionDistance>0.0&&unionShellDistance<0.0&&density>=0.0f) + return static_cast(unionShellDistance/Q); +- return std::max(density,passageAirDistance); ++ float composedDensity=std::max(density,passageAirDistance); ++ if(landingPlan&&landingPlan->manifest.recipe.geometryVersion>=10 ++ &&density>=0.0f&&unionDistance<0.0&&unionShellDistance>0.0) ++ { ++ // In open-air parts of the island stratum, the boolean air union saturates ++ // the passage's positive interior distance to the farther island-air ++ // distance. Keep the nearest positive bore/shell distance so the explicit ++ // passage shell remains measurable without changing any field signs. ++ composedDensity=std::min(composedDensity, ++ std::min(passageAirDistance, ++ static_cast(unionShellDistance/Q))); ++ } ++ return preserveFloatingIslandLandingSupport(composedDensity); + } + + float ApplyResolvedStrateComposition(float density,float X,float Y,float Z) const +@@ -7217,9 +7289,11 @@ private: + Density=filteredDensity; + if(routeNativeBlend>0.0&&NativeDensity<0) + { ++ const double routePreservation=Plan->manifest.recipe.geometryVersion>=10 ++ ?routeNativeBlend:routeNativeBlend*0.60; + const double routePreserved=std::lerp(static_cast(Density), + static_cast(std::min(Density,NativeDensity)), +- routeNativeBlend*0.60); ++ routePreservation); + Density=static_cast(std::llround(routePreserved)); + } + // Marching Cubes can retain an isolated solid with no two-metre axis +diff --git a/Standalone/Source/StandaloneViewer.cpp b/Standalone/Source/StandaloneViewer.cpp +index 1c0ed4c..80ad688 100644 +--- a/Standalone/Source/StandaloneViewer.cpp ++++ b/Standalone/Source/StandaloneViewer.cpp +@@ -9208,11 +9208,15 @@ int main(int Argc,char** Argv) + { + const auto PlanStart=std::chrono::steady_clock::now(); + VoxelForgeCore::WorldAssemblyManifest WorldAssembly; ++ VoxelForgeCore::ResolvedLayoutSnapshotV3 ResolvedLayout; + const bool bPlanReady=StandaloneWorldAssemblyPrototype::AttachRound1WorldAssemblyPrototype(*App.World,App.OwnerJsonRoot, + Error,WorldAssemblyManifestOutputPath,&WorldAssembly) + &&(!bFloatingIslandsRecipe + ||StandaloneWorldAssemblyPrototype::AttachFloatingIslandWorldAssembly( +- *App.World,App.OwnerJsonRoot,WorldAssembly,Error)); ++ *App.World,App.OwnerJsonRoot,WorldAssembly,Error)) ++ &&(!bFloatingIslandsRecipe ++ ||StandaloneWorldAssemblyPrototype::BuildResolvedLayoutSnapshot( ++ *App.World,WorldAssembly,"floating-islands",ResolvedLayout,Error)); + const double PlanMilliseconds=std::chrono::duration( + std::chrono::steady_clock::now()-PlanStart).count(); + std::printf("[WorldAssemblerPlanTiming] total_ms=%.3f status=%s\n", +diff --git a/Standalone/Source/StreamBenchmarkHeadless.cpp b/Standalone/Source/StreamBenchmarkHeadless.cpp +index 1afcff5..f22afe9 100644 +--- a/Standalone/Source/StreamBenchmarkHeadless.cpp ++++ b/Standalone/Source/StreamBenchmarkHeadless.cpp +@@ -1830,31 +1830,11 @@ int main(int argc,char** argv) + else if(!StandaloneWorldAssemblyPrototype::AttachRound1WorldAssemblyPrototype( + *ownerWorld,ownerJsonRoot,error,{},&worldAssembly)) + {std::fprintf(stderr,"World assembler prototype setup failed: %s\n",error.c_str());return 2;} +- if(((!useExportedCorePlan&&options.FloatingIslandsRecipe) +- ||(options.NativeOwnerFloatingIslandsRecipe +- &&worldAssembly.floatingIslands.empty())) ++ if(!useExportedCorePlan&&options.FloatingIslandsRecipe ++ &&!options.NativeOwnerFloatingIslandsRecipe + &&!StandaloneWorldAssemblyPrototype::AttachFloatingIslandWorldAssembly( + *ownerWorld,ownerJsonRoot,worldAssembly,error)) + {std::fprintf(stderr,"Floating-island assembly setup failed: %s\n",error.c_str());return 2;} +- if(!options.WorldAssemblyManifestOutputPath.empty()) +- { +- const std::string manifestText=worldAssembly.ToJson(); +- const auto& outputPath=options.WorldAssemblyManifestOutputPath; +- std::error_code directoryError; +- if(!outputPath.parent_path().empty()) +- std::filesystem::create_directories(outputPath.parent_path(),directoryError); +- if(directoryError) +- {std::fprintf(stderr,"Could not create the complete world assembly manifest output directory.\n");return 2;} +- std::ofstream output(outputPath,std::ios::binary); +- if(!output) +- {std::fprintf(stderr,"Could not open the complete world assembly manifest output path.\n");return 2;} +- output.write(manifestText.data(),static_cast(manifestText.size())); +- if(!output) +- {std::fprintf(stderr,"Could not write the complete world assembly manifest payload.\n");return 2;} +- std::printf("[WorldAssemblerFullManifest] bytes=%zu surface_strates=%zu floating_islands=%zu path=%s status=PASS\n", +- manifestText.size(),worldAssembly.plan.strates.size(),worldAssembly.floatingIslands.size(), +- outputPath.string().c_str()); +- } + if (options.AuditHeightfieldProfile && !RunHeightfieldProfileAudit(worldAssembly)) + { + std::fprintf(stderr,"Profiled SurfaceWorld interval, classification or route audit failed.\n"); +@@ -1886,6 +1866,31 @@ int main(int argc,char** argv) + &&!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(options.NativeOwnerFloatingIslandsRecipe ++ &&worldAssembly.floatingIslands.empty() ++ &&!StandaloneWorldAssemblyPrototype::AttachFloatingIslandWorldAssembly( ++ *ownerWorld,ownerJsonRoot,worldAssembly,resolvedLayout,error, ++ true)) ++ {std::fprintf(stderr,"Floating-island assembly setup failed: %s\n",error.c_str());return 2;} ++ if(!options.WorldAssemblyManifestOutputPath.empty()) ++ { ++ const std::string manifestText=worldAssembly.ToJson(); ++ const auto& outputPath=options.WorldAssemblyManifestOutputPath; ++ std::error_code directoryError; ++ if(!outputPath.parent_path().empty()) ++ std::filesystem::create_directories(outputPath.parent_path(),directoryError); ++ if(directoryError) ++ {std::fprintf(stderr,"Could not create the complete world assembly manifest output directory.\n");return 2;} ++ std::ofstream output(outputPath,std::ios::binary); ++ if(!output) ++ {std::fprintf(stderr,"Could not open the complete world assembly manifest output path.\n");return 2;} ++ output.write(manifestText.data(),static_cast(manifestText.size())); ++ if(!output) ++ {std::fprintf(stderr,"Could not write the complete world assembly manifest payload.\n");return 2;} ++ std::printf("[WorldAssemblerFullManifest] bytes=%zu surface_strates=%zu floating_islands=%zu path=%s status=PASS\n", ++ manifestText.size(),worldAssembly.plan.strates.size(),worldAssembly.floatingIslands.size(), ++ outputPath.string().c_str()); ++ } + if(!std::holds_alternative(ownerJsonRoot.Get("motif_family_override").Data)) + { + std::vector requests; +diff --git a/Standalone/Source/WorldAssemblyPrototype.h b/Standalone/Source/WorldAssemblyPrototype.h +index 4e20068..70c4c61 100644 +--- a/Standalone/Source/WorldAssemblyPrototype.h ++++ b/Standalone/Source/WorldAssemblyPrototype.h +@@ -1366,7 +1366,9 @@ namespace StandaloneWorldAssemblyPrototype + } + + inline bool AttachFloatingIslandWorldAssembly(FStandaloneOwnerWorld& owner, +- VFJson::Value& root,VoxelForgeCore::WorldAssemblyManifest& assembly,std::string& error) ++ VFJson::Value& root,VoxelForgeCore::WorldAssemblyManifest& assembly, ++ VoxelForgeCore::ResolvedLayoutSnapshotV3& resolvedLayout, ++ std::string& error,bool planAroundPassages=false) + { + if(!owner.Manager) + {error="floating-island assembly needs the resolved standalone strate manager";return false;} +@@ -1386,7 +1388,8 @@ namespace StandaloneWorldAssemblyPrototype + FIntVector(0,0,islandSlot->TopChunkZ)); + const FStratePassageConfig& passage=islandSlot->Definition->PassageConfig; + recipe.seed=static_cast(owner.Seed); +- recipe.geometryVersion=8; ++ recipe.geometryVersion=planAroundPassages?10:8; ++ if(planAroundPassages)recipe.primaryIslandCount=9; + recipe.terrainFollowingRoute=static_cast(passage.Style)==0; + recipe.ownerVoxelSizeMicrons=owner.OwnerVoxelSizeMicrons; + recipe.coreVoxelSizeMicrons=owner.CoreVoxelSizeMicrons; +@@ -1406,43 +1409,79 @@ namespace StandaloneWorldAssemblyPrototype + recipe.islandDensityQ16=WorldAssemblyQ16(std::clamp(params.IslandDensity,0.0,1.0)); + recipe.spacingSubvoxels=WorldAssemblyFixed(params.IslandSpacing*ownerToCoreScale); + recipe.minimumRadiusSubvoxels=WorldAssemblyFixed(params.IslandMinRadius*ownerToCoreScale); +- recipe.maximumRadiusSubvoxels=WorldAssemblyFixed(params.IslandMaxRadius*ownerToCoreScale); ++ recipe.maximumRadiusSubvoxels=WorldAssemblyFixed((planAroundPassages ++ ?28.0:params.IslandMaxRadius)*ownerToCoreScale); + recipe.thicknessRatioQ16=WorldAssemblyQ16(params.ThicknessRatio); + recipe.verticalJitterQ16=WorldAssemblyQ16(params.VerticalJitter); + recipe.topFlattenQ16=WorldAssemblyQ16(params.TopFlatten); +- recipe.blendRadiusSubvoxels=WorldAssemblyFixed(params.SDFBlendRadius*ownerToCoreScale); ++ recipe.blendRadiusSubvoxels=planAroundPassages ++ ?2*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel ++ :WorldAssemblyFixed(params.SDFBlendRadius*ownerToCoreScale); ++ if(planAroundPassages) ++ recipe.contourWarpSubvoxels=VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; + recipe.roughnessSubvoxels=WorldAssemblyFixed(params.SurfaceRoughness*ownerToCoreScale); ++ if(planAroundPassages) ++ recipe.roughnessSubvoxels=std::min(recipe.roughnessSubvoxels, ++ VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel/2); + recipe.boundarySealSubvoxels=WorldAssemblyFixed(params.BoundarySealThickness*ownerToCoreScale); ++ if(planAroundPassages) ++ { ++ recipe.routeConstraints.version=1; ++ recipe.routeConstraints.capsuleRadiusSubvoxels=348; ++ recipe.routeConstraints.capsuleHeightSubvoxels=1802; ++ recipe.routeConstraints.maximumGradeQ16=17560; ++ recipe.routeConstraints.sweepSpacingSubvoxels=128; ++ recipe.routeConstraints.supportProbeRadiusSubvoxels=230; ++ recipe.routeConstraints.supportSearchDepthSubvoxels=512; ++ recipe.routeConstraints.minimumClearanceSubvoxels=128; ++ recipe.routeConstraints.minimumSupportProbes=3; ++ } + const auto ownerVoxelsToCoreQ=[&](double value) + {return static_cast(std::llround(value*owner.OwnerVoxelSizeMicrons + *VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel/owner.CoreVoxelSizeMicrons));}; + recipe.anchorIslandOrdinal=recipe.primaryIslandCount-1; + recipe.anchorPlacementRadiusSubvoxels=ownerVoxelsToCoreQ(passage.DistanceMax); +- const std::int64_t spiralRadius=ownerVoxelsToCoreQ(passage.SpiralRadius); +- const std::int64_t mouthBore=std::max(ownerVoxelsToCoreQ(passage.MouthRadius), +- ownerVoxelsToCoreQ(36.0)); +- const std::int64_t bore=std::max(ownerVoxelsToCoreQ(passage.MidRadius), +- ownerVoxelsToCoreQ(24.0)); +- const std::int64_t wallReserve=ownerVoxelsToCoreQ(20.0); +- // Retain a 4.5-metre mouth for capsule clearance while keeping the long +- // ramp at three metres to leave more rock around the first coil. +- recipe.anchorMouthOffsetSubvoxels=ownerVoxelsToCoreQ(40.0); +- const std::int64_t supportOverhang=ownerVoxelsToCoreQ(16.0); +- const std::int64_t rootTaperReserve=ownerVoxelsToCoreQ(10.0); +- const std::int64_t mouthEnvelope=recipe.anchorMouthOffsetSubvoxels+mouthBore; +- const std::int64_t treadEnvelope=spiralRadius+bore+supportOverhang; +- recipe.anchorRootRadiusSubvoxels=std::max(mouthEnvelope,treadEnvelope) +- +wallReserve+rootTaperReserve; +- recipe.anchorIslandMinimumRadiusSubvoxels=std::max(recipe.minimumRadiusSubvoxels, +- std::max(recipe.anchorMouthOffsetSubvoxels+mouthBore+ownerVoxelsToCoreQ(4.0), +- recipe.anchorRootRadiusSubvoxels+wallReserve)); ++ if(planAroundPassages) ++ { ++ recipe.anchorMouthOffsetSubvoxels=ownerVoxelsToCoreQ(4.0); ++ recipe.anchorRootRadiusSubvoxels=std::max(ownerVoxelsToCoreQ(16.0), ++ recipe.anchorMouthOffsetSubvoxels+recipe.routeConstraints.capsuleRadiusSubvoxels ++ +VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel); ++ recipe.anchorIslandMinimumRadiusSubvoxels=std::max(recipe.maximumRadiusSubvoxels, ++ recipe.anchorMouthOffsetSubvoxels+recipe.routeConstraints.capsuleRadiusSubvoxels ++ +VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel); ++ } ++ else ++ { ++ const std::int64_t spiralRadius=ownerVoxelsToCoreQ(passage.SpiralRadius); ++ const std::int64_t mouthBore=std::max(ownerVoxelsToCoreQ(passage.MouthRadius), ++ ownerVoxelsToCoreQ(36.0)); ++ const std::int64_t bore=std::max(ownerVoxelsToCoreQ(passage.MidRadius), ++ ownerVoxelsToCoreQ(24.0)); ++ const std::int64_t wallReserve=ownerVoxelsToCoreQ(20.0); ++ recipe.anchorMouthOffsetSubvoxels=ownerVoxelsToCoreQ(40.0); ++ const std::int64_t supportOverhang=ownerVoxelsToCoreQ(16.0); ++ const std::int64_t rootTaperReserve=ownerVoxelsToCoreQ(10.0); ++ const std::int64_t mouthEnvelope=recipe.anchorMouthOffsetSubvoxels+mouthBore; ++ const std::int64_t treadEnvelope=spiralRadius+bore+supportOverhang; ++ recipe.anchorRootRadiusSubvoxels=std::max(mouthEnvelope,treadEnvelope) ++ +wallReserve+rootTaperReserve; ++ recipe.anchorIslandMinimumRadiusSubvoxels=std::max(recipe.minimumRadiusSubvoxels, ++ std::max(recipe.anchorMouthOffsetSubvoxels+mouthBore+ownerVoxelsToCoreQ(4.0), ++ recipe.anchorRootRadiusSubvoxels+wallReserve)); ++ } + recipe.anchorRootBottomZSubvoxels=recipe.layoutMinimumZSubvoxels + +recipe.boundarySealSubvoxels; + +- auto planned=VoxelForgeCore::PlanFloatingIslandCluster(recipe,error); ++ auto planned=planAroundPassages ++ ?VoxelForgeCore::PlanFloatingIslandClusterAroundPassages( ++ recipe,resolvedLayout,islandSlot->StrateIndex,error) ++ :VoxelForgeCore::PlanFloatingIslandCluster(recipe,error); + if(!planned)return false; + const VoxelForgeCore::FloatingIslandFieldV1 routeField( + planned->recipe,planned->plan); ++ const double metresPerSubvoxel=static_cast(owner.CoreVoxelSizeMicrons) ++ /(1000000.0*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel); + const auto routeAudit=VoxelForgeCore::AuditFloatingIslandRoute(routeField); + std::printf("[FloatingIslandRouteAudit] points=%zu centers=%llu capsule_samples=%llu blocked=%llu support_samples=%llu unsupported=%llu grade_failures=%llu status=%s\n", + planned->plan.route.size(), +@@ -1453,8 +1492,27 @@ namespace StandaloneWorldAssemblyPrototype + static_cast(routeAudit.unsupportedCenterSamples), + static_cast(routeAudit.gradeFailures), + routeAudit.passed?"PASS":"FAIL"); +- const double metresPerSubvoxel=static_cast(owner.CoreVoxelSizeMicrons) +- /(1000000.0*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel); ++ VoxelForgeCore::FloatingIslandPassageClearanceAuditResult passageAudit; ++ if(planAroundPassages) ++ { ++ constexpr double PortalExclusionMetres=13.0; ++ passageAudit=VoxelForgeCore::AuditFloatingIslandPassageClearance( ++ routeField,resolvedLayout,islandSlot->StrateIndex,PortalExclusionMetres); ++ std::printf("[FloatingIslandPassageClearance] strate=%d tube_samples=%llu island_blocked=%llu route_checks=%llu route_blocked=%llu arrival_support=%u/5 departure_support=%u/5 clearance_excess_m=%.3f portal_exclusion_m=%.1f influence_reach_m=1.053 capsule_bound_m=%.3f status=%s\n", ++ islandSlot->StrateIndex, ++ static_cast(passageAudit.passageSamples), ++ static_cast(passageAudit.blockedIslandSamples), ++ static_cast(passageAudit.routeSamples), ++ static_cast(passageAudit.blockedRouteSamples), ++ passageAudit.arrivalMouthSupportProbes, ++ passageAudit.departureMouthSupportProbes, ++ passageAudit.minimumExcessClearanceSubvoxels*metresPerSubvoxel, ++ passageAudit.portalExclusionMetres, ++ planned->recipe.routeConstraints.capsuleHeightSubvoxels*metresPerSubvoxel*0.5, ++ passageAudit.passed?"PASS":"FAIL"); ++ if(!routeAudit.passed||!passageAudit.passed) ++ {error="corridor-aware floating-island route or passage audit failed";return false;} ++ } + const double bedrockTopMetres=(minimumZ+recipe.boundarySealSubvoxels)*metresPerSubvoxel; + const double ceilingBottomMetres=(maximumZ-recipe.boundarySealSubvoxels)*metresPerSubvoxel; + for(const auto& island:planned->plan.islands) +@@ -1473,18 +1531,82 @@ namespace StandaloneWorldAssemblyPrototype + assembly.floatingIslands.push_back(std::move(islands)); + if(!assembly.finalize(error))return false; + ++ if(planAroundPassages) ++ { ++ auto resolvedStratum=std::find_if(resolvedLayout.strates.begin(), ++ resolvedLayout.strates.end(),[&](const auto& item) ++ {return item.strateIndex==islandSlot->StrateIndex;}); ++ if(resolvedStratum==resolvedLayout.strates.end()) ++ {error="resolved FloatingIslands stratum disappeared before native anchor attachment";return false;} ++ resolvedStratum->recipeVersion=assembly.floatingIslands.back().manifest.recipe.geometryVersion; ++ resolvedStratum->anchors.erase(std::remove_if(resolvedStratum->anchors.begin(), ++ resolvedStratum->anchors.end(),[](const auto& anchor) ++ {return anchor.kind=="island_anchor"||anchor.kind=="passage_anchor" ++ ||anchor.kind=="route_point";}),resolvedStratum->anchors.end()); ++ const auto& nativePlan=assembly.floatingIslands.back().manifest.plan; ++ const auto& nativeRecipe=assembly.floatingIslands.back().manifest.recipe; ++ for(std::size_t n=0;nanchors.push_back(std::move(anchor)); ++ if(n==nativeRecipe.anchorIslandOrdinal) ++ { ++ VoxelForgeCore::ResolvedLayoutAnchorV2 passageAnchor; ++ passageAnchor.kind="passage_anchor"; ++ passageAnchor.stableId="passage-anchor/island/"+std::to_string(n); ++ passageAnchor.units="1/256 Core voxel"; ++ passageAnchor.values={island.centerSubvoxels[0],island.centerSubvoxels[1], ++ nativeRecipe.anchorRootRadiusSubvoxels, ++ nativeRecipe.anchorMouthOffsetSubvoxels, ++ nativeRecipe.anchorPlacementRadiusSubvoxels, ++ nativeRecipe.anchorRootBottomZSubvoxels,island.radiusSubvoxels}; ++ if(!nativePlan.route.empty()) ++ { ++ const auto& mouth=nativePlan.route.back().positionSubvoxels; ++ passageAnchor.values.insert(passageAnchor.values.end(), ++ {mouth[0],mouth[1],mouth[2]}); ++ } ++ resolvedStratum->anchors.push_back(std::move(passageAnchor)); ++ } ++ } ++ for(std::size_t n=0;nanchors.push_back(std::move(anchor)); ++ } ++ if(!resolvedLayout.finalize(error))return false; ++ } ++ + VFJson::Value assemblyJson; + if(!VFJson::Parser(assembly.ToJson()).Parse(assemblyJson,error))return false; + auto* rootObject=std::get_if(&root.Data); + if(!rootObject){error="owner snapshot root is not a JSON object";return false;} + (*rootObject)["world_assembly"]=std::move(assemblyJson); +- std::printf("[FloatingIslandWorldAssembly] seed=%d strate_index=%d chunks=%d..%d island_count=%zu recipe_hash=%016llx status=PASS\n", ++ std::printf("[FloatingIslandWorldAssembly] seed=%d strate_index=%d chunks=%d..%d island_count=%zu dispatch=FloatingIslands-native recipe_hash=%016llx status=PASS\n", + owner.Seed,islandSlot->StrateIndex,islandSlot->TopChunkZ,islandSlot->BottomChunkZ, + assembly.floatingIslands.back().manifest.plan.islands.size(), + static_cast(assembly.floatingIslands.back().manifest.recipe.contentHash)); + return true; + } + ++ inline bool AttachFloatingIslandWorldAssembly(FStandaloneOwnerWorld& owner, ++ VFJson::Value& root,VoxelForgeCore::WorldAssemblyManifest& assembly, ++ std::string& error) ++ { ++ VoxelForgeCore::ResolvedLayoutSnapshotV3 unusedLayout; ++ return AttachFloatingIslandWorldAssembly(owner,root,assembly,unusedLayout,error,false); ++ } ++ + inline const char* GeneratorKind(ECaveGeneratorType type) + { + switch(type) +@@ -1964,6 +2086,7 @@ namespace StandaloneWorldAssemblyPrototype + :it->manifest.plan.route.size()-1; + std::size_t resolvedRoutePointCount=it->manifest.plan.route.size(); + if(it->manifest.recipe.geometryVersion>=5 ++ &&it->manifest.recipe.geometryVersion<10 + &&!it->manifest.plan.route.empty() + &&it->manifest.recipe.anchorIslandOrdinalmanifest.plan.islands.size()) + {