- Capture exports now cover a 90-degree player frustum (radius 3, LOD 0-8, overlap patches); a 17x9 ray coverage probe aborts before rendering if tiles are missing (truncated-mesh control: 480 uncovered samples, rejected). Clear colour is sky blue, so un-meshed space can't pass as dark rock. 16 views of the owner's four-strate plan. - Explore commandlet: finite XYZ spawn override for traces (Source/, Linux-compiled). - In-engine four-strate trace NOT obtained: the engine-generated plan fails passage validation at a solid centerline voxel (~(-43,-34.5,-448.5) m) while the headless owner_world.json plan passes. Engine and headless plans diverge. - R36 (read-only): order TN -> VS -> FI for native migration; native FI is reachable from the adapter but not selected in the owner run, cause unknown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
97 lines
4.6 KiB
Python
97 lines
4.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Run three interleaved UE startup traces at each owner-plan arrival."""
|
|
import subprocess
|
|
import time
|
|
import json
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[4]
|
|
HOST = Path("/home/jahni/VFHost")
|
|
PLUGIN_SAVED = ROOT / "Saved/Linux/l69"
|
|
HOST_PLUGIN_SAVED = HOST / "Plugins/VoxelForge/Saved/Linux/l69"
|
|
OWNER_WORLD = ROOT / "Standalone/data/owner_world.json"
|
|
OWNER_MANIFEST = HOST_PLUGIN_SAVED / "owner_world_manifest.json"
|
|
EDITOR = Path("/home/jahni/UnrealEngine/Engine/Binaries/Linux/UnrealEditor-Cmd")
|
|
TRACES = PLUGIN_SAVED / "traces"
|
|
HOST_SAVED = HOST / "Saved/Linux/l69"
|
|
SPAWNS_M = {
|
|
0: (0.0, 0.0, -374.939453),
|
|
1: (25.836914, 3.199219, -737.0),
|
|
2: (19.166016, -14.200195, -753.374023),
|
|
3: (-20.0625, -5.068359, -900.353516),
|
|
}
|
|
ORDER = ((0, 1), (1, 1), (2, 1), (3, 1),
|
|
(1, 2), (2, 2), (3, 2), (0, 2),
|
|
(2, 3), (3, 3), (0, 3), (1, 3))
|
|
|
|
|
|
def run(strate, trial):
|
|
label = f"strate{strate}-trial{trial}"
|
|
trace = TRACES / f"{label}.trace.jsonl"
|
|
abslog = TRACES / f"{label}.log"
|
|
stdout = TRACES / f"{label}.stdout.log"
|
|
output = HOST_PLUGIN_SAVED / "output" / label
|
|
userdir = HOST_SAVED / label / "User"
|
|
zendata = HOST_SAVED / label / "Zen"
|
|
ddc = HOST_SAVED / "DDC"
|
|
for directory in (output, userdir, zendata, ddc, TRACES):
|
|
directory.mkdir(parents=True, exist_ok=True)
|
|
spawn_cm = ",".join(f"{value * 100.0:.3f}" for value in SPAWNS_M[strate])
|
|
command = [
|
|
str(EDITOR), str(HOST / "VFHost.uproject"), "-nullrhi", "-unattended",
|
|
"-nop4", "-nosplash", "-NoSound", "-corelimit=12", "-NoZenAutoLaunch",
|
|
"-notraceserver", "-nocrashreports", "-ddc=NoZenLocalFallback",
|
|
f"-userdir={userdir}", f"-ZenDataPath={zendata}", f"-LocalDataCachePath={ddc}",
|
|
"-run=VoxelForgeExplore", "-seed=0", "-archetype=TunnelNetwork", "-slot=0",
|
|
"-modes=export", "-gameconfig=1", "-coreworldtest=1", "-ownerfourstrateplan=1",
|
|
"-corevoxelsizecm=25", "-coreislandtest=0", "-corefallbacktest=0",
|
|
"-coreofftest=0", "-coreplantest=0",
|
|
"-settingsref=/Game/VoxelForge/DA_Settings.DA_Settings", "-corehybridmesher=0",
|
|
f"-coreworldassembly={OWNER_MANIFEST}",
|
|
f"-out={output}",
|
|
"-voxel.StreamingCoarseFirst=0", "-voxel.StreamingDynamicNearReserve=1",
|
|
"-voxel.StreamingLegacyPendingResultCap=0", "-voxel.CoreRegionConcurrentAdmission=1",
|
|
"-voxel.StreamingResultBacklogCap=256", "-voxel.StreamingReadyQueueDepth=8",
|
|
"-voxel.StreamingBackgroundWorkerCap=1", "-voxel.CoreColumnCacheDirectMapped=0",
|
|
"-voxel.CoreMCGradientMemoization=1", "-voxel.StreamingCollisionLookahead=1",
|
|
"-coreworldstreamtrace=1", "-voxel.TestMove=0",
|
|
"-voxel.TestMoveSpeedCmPerSecond=0", f"-voxel.StartupTraceSpawnCm={spawn_cm}",
|
|
f"-voxel.StartupTraceFile={trace}", "-voxel.StartupTraceUntilEndPlay=1",
|
|
"-voxel.StartupTraceMaxTiles=16384", "-voxel.CollisionGate=0",
|
|
f"-abslog={abslog}",
|
|
]
|
|
wrapped = ["taskset", "-c", "0-11", "prlimit", "--rss=6442450944", "--",
|
|
"timeout", "1740s", *command]
|
|
started = time.monotonic()
|
|
with stdout.open("w", encoding="utf-8") as stream:
|
|
result = subprocess.run(wrapped, cwd=ROOT, stdout=stream,
|
|
stderr=subprocess.STDOUT, timeout=1740, check=False)
|
|
elapsed = time.monotonic() - started
|
|
print(f"[L69EngineTrace] label={label} spawn_cm={spawn_cm} elapsed_s={elapsed:.2f} "
|
|
f"exit={result.returncode} trace={trace} stdout={stdout}", flush=True)
|
|
if result.returncode != 0:
|
|
raise SystemExit(f"{label} failed; inspect {stdout} and {abslog}")
|
|
if not trace.is_file() or trace.stat().st_size == 0:
|
|
raise SystemExit(f"{label} exited successfully but produced no startup trace")
|
|
|
|
|
|
def main():
|
|
if not EDITOR.is_file():
|
|
raise SystemExit(f"missing UE commandlet executable: {EDITOR}")
|
|
HOST_PLUGIN_SAVED.mkdir(parents=True, exist_ok=True)
|
|
owner = json.loads(OWNER_WORLD.read_text(encoding="utf-8"))
|
|
assembly = owner.get("settings_asset", {}).get("WorldAssemblyManifestJson")
|
|
if not isinstance(assembly, str) or not assembly:
|
|
raise SystemExit(f"{OWNER_WORLD} has no serialized world-assembly manifest")
|
|
OWNER_MANIFEST.write_text(assembly + "\n", encoding="utf-8")
|
|
print(f"[L69EngineTracePlan] source={OWNER_WORLD} manifest={OWNER_MANIFEST} "
|
|
f"bytes={OWNER_MANIFEST.stat().st_size}", flush=True)
|
|
for strate, trial in ORDER:
|
|
run(strate, trial)
|
|
print("[L69EngineTraceSet] strata=4 trials_each=3 total=12 status=PASS", flush=True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|