874b6f20c2
Основа — Horizon (MIT). История апстрима не переносится: этот репозиторий ведёт свою.
88 lines
5.6 KiB
Python
88 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Validate registry-backed cached collisions against the pinned vanilla binaries."""
|
|
import argparse
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import platform
|
|
import shutil
|
|
import subprocess
|
|
import tempfile
|
|
|
|
try:
|
|
from . import lab, test_rust_parity
|
|
except ImportError:
|
|
import lab
|
|
import test_rust_parity
|
|
|
|
|
|
def counts(output):
|
|
marker = "HORIZON_COLLISION_RESULT "
|
|
found = [json.loads(line.split(marker, 1)[1]) for line in output.splitlines() if marker in line]
|
|
if len(found) != 1:
|
|
raise AssertionError(f"Missing collision counts: {found}")
|
|
result = found[0]
|
|
if result["registry_states"] != 35723 or result["cached_states"] + result["uncached_states"] != result["registry_states"] or result["queries"] != result["cached_states"] * 6 or result["unique_shapes"] <= 0:
|
|
raise AssertionError(f"Incomplete collision coverage: {result}")
|
|
return result
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--prepare", action="store_true")
|
|
args = parser.parse_args()
|
|
directory = lab.LOCAL / "rust-collision-parity"
|
|
directory.mkdir(parents=True, exist_ok=True)
|
|
report_path = directory / "report.json"
|
|
report_path.unlink(missing_ok=True)
|
|
if args.prepare:
|
|
lab.prepare()
|
|
lock, jars, libraries = test_rust_parity.verify_artifacts()
|
|
for earlier in directory.glob("run-*"): # one run per run used to stay behind: 5 GB here after a few weeks
|
|
shutil.rmtree(earlier, ignore_errors=True)
|
|
base = Path(tempfile.mkdtemp(prefix="run-", dir=directory))
|
|
oracle = lab.ROOT / "mods/horizon/src/test/java/dev/horizonlab/parity/VanillaCollisionOracle.java"
|
|
sources = [oracle, Path(__file__).resolve(), lab.ROOT / "tools/test_rust_parity.py", lab.ROOT / "Cargo.toml", lab.ROOT / "Cargo.lock", lab.ROOT / "crates/horizon-core/Cargo.toml", lab.ROOT / "crates/horizon-world/Cargo.toml", *sorted((lab.ROOT / "crates/horizon-core/src").rglob("*.rs")), *sorted((lab.ROOT / "crates/horizon-world/src").rglob("*.rs")), lab.ROOT / "crates/horizon-world/examples/probe/collision_fixture.rs"]
|
|
tested_sources = test_rust_parity.source_hashes(sources)
|
|
classes = base / "classes"
|
|
classes.mkdir()
|
|
dependency_path = os.pathsep.join(map(str, libraries))
|
|
test_rust_parity.run(["javac", "--release", "25", "-proc:none", "-cp", os.pathsep.join([str(jars["server"]), dependency_path]), "-d", str(classes), str(oracle)])
|
|
def java(side, mode):
|
|
result = subprocess.run(["java", "-Xmx1G", "-cp", os.pathsep.join([str(classes), str(jars[side]), dependency_path]), "dev.horizonlab.parity.VanillaCollisionOracle", mode, str(base)], cwd=lab.ROOT, capture_output=True, text=True, timeout=300)
|
|
(base / f"{side}-{mode}.log").write_text(result.stdout + result.stderr, encoding="utf-8")
|
|
result.check_returncode()
|
|
return result.stdout
|
|
expected = counts(java("server", "generate"))
|
|
test_rust_parity.run(["cargo", "build", "--release", "-p", "horizon-world", "--example", "world_probe"])
|
|
metadata = json.loads(subprocess.check_output(["cargo", "metadata", "--no-deps", "--format-version", "1"], cwd=lab.ROOT, text=True))
|
|
binary = Path(metadata["target_directory"]) / "release/examples" / ("world_probe.exe" if os.name=="nt" else "world_probe")
|
|
actual = counts(subprocess.check_output([str(binary), "collision_fixture", str(base)], cwd=lab.ROOT, text=True))
|
|
if actual != expected:
|
|
raise AssertionError(f"Collision coverage differs: vanilla={expected}, Rust={actual}")
|
|
canonical = {"empty_states":0,"block_states":0,"other_cached_states":0}
|
|
for line in (base / "rust.txt").read_text().splitlines():
|
|
if line == 'canonical true false': canonical['empty_states'] += 1
|
|
elif line == 'canonical false true': canonical['block_states'] += 1
|
|
elif line == 'canonical false false': canonical['other_cached_states'] += 1
|
|
if sum(canonical.values()) != expected['cached_states']: raise AssertionError('incomplete canonical identity comparison')
|
|
references = []
|
|
for side, jar in jars.items():
|
|
java(side, side)
|
|
reference = base / f"vanilla-{side}.txt"
|
|
matched = test_rust_parity.compare(reference, base / "rust.txt")
|
|
references.append({"side": side, "jar_sha256": lab.digest(jar, "sha256"), "output_sha256": lab.digest(reference, "sha256"), "matched_output_lines": matched, **expected})
|
|
print(f"{side}: {matched:,} cached collision output lines match", flush=True)
|
|
test_rust_parity.ensure_sources_unchanged(sources, tested_sources)
|
|
report = {"schema": 1, "minecraft": lock["minecraft"]["version"], "manifest_sha1": lock["minecraft"]["manifest_sha1"], "platform": platform.platform(),
|
|
"java": subprocess.check_output(["java", "--version"], text=True).splitlines()[0], "rustc": subprocess.check_output(["rustc", "--version"], text=True).strip(),
|
|
"inputs_sha256": lab.digest(base / "inputs.txt", "sha256"), "rust_output_sha256": lab.digest(base / "rust.txt", "sha256"), "sources_sha256": tested_sources, "references": references, "canonical_identities":canonical,
|
|
"scope": "Pinned no-context cached collision branch only. Registry identity validation, resident section lookup, grids, native canonical empty/block identities distinct from equal geometry, discrete extrema including empty shapes, greedy boxes, bounds, translated collide, ray hits, closest points and moved cell lookup. Uncached and entity-context behavior have separate comparison suites."}
|
|
lab.write_json(report_path, report)
|
|
lab.write_json(base / "report.json", report)
|
|
print(f"Cached collision comparison passed: {report_path}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|