Files
RustNotMC/tools/test_structure_start_nbt_parity.py
SashegDev 874b6f20c2 Клиент: начальный импорт кодовой базы
Основа — Horizon (MIT). История апстрима не переносится: этот репозиторий ведёт свою.
2026-10-29 22:04:28 +03:00

101 lines
5.9 KiB
Python
Executable File

#!/usr/bin/env python3
"""Compare the structure starts Horizon saves with the tags vanilla's StructureStart.createTag writes.
The oracle (VanillaStructureStartOracle with HORIZON_START_NBT) generates the start of each case's chunk with the
pinned server's own classes and prints its tag; the probe (world_probe structure_start_nbt) prints the tag
Horizon saves for the same chunk. Both print sorted keys and typed numbers, and the lines must be identical.
The cases are the start chunks of one site of every structure kind (seed 12345, and a badlands mineshaft of seed
-7777), which between them use every StructurePieceType.
"""
import argparse
import collections
import json
import os
from pathlib import Path
import platform
import subprocess
try:
from . import lab, test_rust_parity as base
except ImportError:
import lab
import test_rust_parity as base
# (seed, dimension, chunk x, chunk z): the start chunk of one site of each structure kind.
CASES = [
(12345, 'overworld', -9, -52), (12345, 'overworld', -146, 37), (12345, 'overworld', -66, -98),
(12345, 'overworld', 91, 75), (12345, 'overworld', 75, -23), (12345, 'overworld', 17, -60),
(12345, 'overworld', 11, -11), (12345, 'overworld', 91, -90), (12345, 'overworld', 8, -33),
(12345, 'overworld', 2, -71), (12345, 'overworld', 39, -28), (12345, 'overworld', -90, -60),
(12345, 'the_nether', 11, -16),
(12345, 'overworld', 291, 441), (12345, 'overworld', 36, 41), (12345, 'overworld', -8, 2),
(12345, 'overworld', 114, -133), (12345, 'overworld', -16, 5), (12345, 'overworld', -109, 91),
(12345, 'overworld', 0, -18), (12345, 'overworld', -150, 51), (12345, 'overworld', 61, 49),
(12345, 'the_nether', 0, -18), (12345, 'the_nether', -22, 6), (12345, 'the_end', -15, -76),
(12345, 'overworld', 38, -115), (12345, 'overworld', -238, -313), (12345, 'overworld', -95, 2),
(12345, 'overworld', -126, -106), (12345, 'overworld', 47, 25), (12345, 'overworld', 110, 23),
(12345, 'overworld', 4, -1), (12345, 'the_nether', -13, -37), (-7777, 'overworld', 75, 84),
]
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.parse_args()
build = lab.LOCAL / 'rust-structure-start-nbt-parity'
build.mkdir(parents=True, exist_ok=True)
report_path = build / 'report.json'
report_path.unlink(missing_ok=True)
lock, jars, libraries = base.verify_artifacts()
oracle = lab.ROOT / 'mods/horizon/src/test/java/dev/horizonlab/parity/VanillaStructureStartOracle.java'
probe = lab.ROOT / 'crates/horizon-world/examples/probe/structure_start_nbt.rs'
sources = [oracle, probe, Path(__file__), lab.ROOT / 'tools/test_rust_parity.py', lab.ROOT / 'tools/lab.py',
lab.ROOT / 'Cargo.toml', lab.ROOT / 'Cargo.lock', 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'))]
tested_sources = base.source_hashes(sources)
def run(command, name, env=None):
with (build / (name + '.log')).open('w', encoding='utf-8') as log:
base.run(list(map(str, command)), stdout=log, stderr=subprocess.STDOUT, env=env)
classes = build / 'classes'
classes.mkdir(exist_ok=True)
dependencies = os.pathsep.join(map(str, [jars['client'], *libraries]))
run(['javac', '--release', lock['minecraft']['java_major'], '-proc:none', '-sourcepath',
lab.ROOT / 'mods/horizon/src/test/java', '-cp', dependencies, '-d', classes, oracle], 'compile-java')
run(['cargo', 'build', '--release', '-p', 'horizon-world', '--example', 'world_probe'], 'compile-rust')
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')
resources = lab.LOCAL / 'horizon-client' / lock['minecraft']['version']
groups = collections.defaultdict(list)
for seed, dimension, cx, cz in CASES:
groups[(seed, dimension)].append((cx, cz))
vanilla, horizon = [], []
for (seed, dimension), chunks in sorted(groups.items()):
name = f'{seed}-{dimension}'
out = build / f'client-{name}.txt'
env = dict(os.environ, HORIZON_START_NBT='1', HORIZON_DIMENSION=dimension,
HORIZON_CHUNKS=';'.join(f'{x},{z}' for x, z in chunks))
run(['java', '-Xmx2g', '-cp', str(classes) + os.pathsep + dependencies,
'dev.horizonlab.parity.VanillaStructureStartOracle', out, seed, 0, 0, 0, 0], 'client-' + name, env)
vanilla += sorted(l for l in out.read_text(encoding='utf-8').splitlines() if l.startswith('nbt '))
probe_out = subprocess.check_output([str(binary), 'structure_start_nbt', str(resources), str(seed), dimension,
*(f'{x},{z}' for x, z in chunks)], text=True)
horizon += sorted(probe_out.splitlines())
(build / 'client.txt').write_text(''.join(l + '\n' for l in vanilla), encoding='utf-8')
(build / 'rust.txt').write_text(''.join(l + '\n' for l in horizon), encoding='utf-8')
if len(vanilla) != len(CASES):
raise AssertionError(f'the oracle found {len(vanilla)} starts for {len(CASES)} cases')
matched = base.compare(build / 'client.txt', build / 'rust.txt')
base.ensure_sources_unchanged(sources, tested_sources)
lab.write_json(report_path, dict(
schema=1, minecraft=lock['minecraft']['version'], platform=platform.platform(), units=len(CASES),
sources_sha256=tested_sources, matched_output_lines=matched,
output_sha256=lab.digest(build / 'rust.txt', 'sha256'), client_jar_sha256=lab.digest(jars['client'], 'sha256')))
print(f'{len(CASES)} structure starts save as vanilla ({matched} lines): {report_path}', flush=True)
if __name__ == '__main__':
main()