874b6f20c2
Основа — Horizon (MIT). История апстрима не переносится: этот репозиторий ведёт свою.
111 lines
6.4 KiB
Python
111 lines
6.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Compare the creative inventory's tabs and search with the vanilla client's.
|
|
|
|
The Java oracle (VanillaCreativeSearchOracle) writes the creative-inventory.json
|
|
that horizon-prepare exports (VanillaCreativeTabsExporter: every
|
|
tab built by vanilla's CreativeModeTabs over the vanilla data pack's
|
|
registries), then what the vanilla client shows: every tab's display items
|
|
and, for each search query, CreativeModeInventoryScreen.refreshSearchResults'
|
|
items, searched through the client's own SessionSearchTrees.
|
|
examples/probe/creative_search_fixture loads the export into
|
|
horizon_client::creative::Creative. The tabs it shows (id, title, icon,
|
|
position, every stack with its components), the search tab's stacks and the
|
|
results of every query must agree. The queries are QUERIES below, then every
|
|
search stack's item path and tooltip lines, every item tag with and without
|
|
"#", and half of each as a prefix.
|
|
|
|
test_creative_parity.py [--detail N]
|
|
"""
|
|
import argparse
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
try:
|
|
from . import interaction_lab as lib, lab, test_rust_parity as base, test_model_baking_parity as baking
|
|
except ImportError:
|
|
import interaction_lab as lib
|
|
import lab
|
|
import test_rust_parity as base
|
|
import test_model_baking_parity as baking
|
|
|
|
PARITY = lab.ROOT / 'mods/horizon/src/test/java/dev/horizonlab/parity'
|
|
# Players' reports (anvil, crafting table, smithing table), other blocks of the
|
|
# functional tab, case, spaces, colons and tag searches.
|
|
QUERIES = ['', 'anvil', 'Anvil', 'ANVIL', 'crafting', 'crafting table', 'smithing', 'smithing table', 'table', 'chest',
|
|
'furnace', 'bed', 'sign', 'banner', 'ominous', 'painting', 'loom', 'grindstone', 'lectern', 'stone', 'oak',
|
|
'a', 'e', ' ', ' ', 'xyz', 'potion', 'healing', 'splash', 'sharpness', 'enchanted', 'book', 'mending',
|
|
'goat horn', 'ponder', 'firework', 'flight', 'music disc', 'disc', 'spawn egg', 'egg', 'stew', 'arrow',
|
|
'tipped', 'light gray', 'red ', ' red', 'minecraft:', 'minecraft:anvil', 'minecraft:table', 'mine:craft',
|
|
':anvil', ':', 'anvil:', 'minecraft: anvil', ' minecraft : anvil ', 'diamond_sword', 'diamond sword',
|
|
'attack', 'when in main hand', '+', '-3', 'command', 'barrier', 'debug', 'light', 'structure', 'jigsaw',
|
|
'#', '#logs', '#minecraft:logs', '#minecraft:', '#:planks', '#wool', '#LOGS', '#swords', '#anvil', '#xyz',
|
|
'#minecraft', '#enchantable/', 'é', 'İ', 'Σ']
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument('--detail', type=int, default=5)
|
|
args = parser.parse_args()
|
|
lock, jars, _ = base.verify_artifacts()
|
|
libraries = baking.client_libraries()
|
|
build = lab.LOCAL / 'creative-parity'; build.mkdir(parents=True, exist_ok=True)
|
|
queries = build / 'queries.json'; queries.write_text(json.dumps(QUERIES))
|
|
classes = build / 'classes'; classes.mkdir(exist_ok=True)
|
|
dependencies = os.pathsep.join(map(str, [jars['client'], *libraries]))
|
|
|
|
def run(command, name):
|
|
with (build / (name + '.log')).open('w') as log:
|
|
result = subprocess.run(list(map(str, command)), cwd=lab.ROOT, timeout=3600, stdout=log, stderr=subprocess.STDOUT)
|
|
if result.returncode:
|
|
print((build / (name + '.log')).read_text()[-4000:]); sys.exit(f'{name} failed')
|
|
run(['javac', '--release', lock['minecraft']['java_major'], '-proc:none', '-nowarn', '-cp', dependencies, '-d', classes,
|
|
*(PARITY / f'{n}.java' for n in ('ParityData', 'VanillaCreativeTabsExporter', 'VanillaCreativeSearchOracle'))],
|
|
'compile-java')
|
|
run(['java', '-Xmx2G', '-cp', str(classes) + os.pathsep + dependencies, 'dev.horizonlab.parity.VanillaCreativeSearchOracle',
|
|
queries, build / 'creative-inventory.json', build / 'vanilla.json'], 'vanilla')
|
|
lib.cargo_example('horizon-client', 'creative_search_fixture', lib.RESOURCES, build / 'creative-inventory.json',
|
|
build / 'vanilla.json', build / 'rust.json')
|
|
vanilla = json.loads((build / 'vanilla.json').read_text())
|
|
rust = json.loads((build / 'rust.json').read_text())
|
|
bad = 0
|
|
shown = [{k: t[k] for k in ('id', 'title', 'icon', 'row', 'column', 'items')} for t in vanilla['tabs'] if t['shown']]
|
|
if [t['id'] for t in shown] != [t['id'] for t in rust['tabs']]:
|
|
bad += 1
|
|
print('TABS vanilla', [t['id'] for t in shown], '\n horizon', [t['id'] for t in rust['tabs']])
|
|
for v, r in zip(shown, rust['tabs']):
|
|
for k in ('title', 'icon', 'row', 'column'):
|
|
if v[k] != r[k]:
|
|
bad += 1; print(f'TAB {v["id"]} {k}: vanilla {v[k]!r} | horizon {r[k]!r}')
|
|
if v['items'] != r['items']:
|
|
bad += 1
|
|
i = next((i for i, (a, b) in enumerate(zip(v['items'], r['items'])) if a != b), min(len(v['items']), len(r['items'])))
|
|
print(f'TAB {v["id"]}: {len(v["items"])} vanilla stacks, {len(r["items"])} horizon; first difference at {i}:')
|
|
print(' vanilla', v['items'][i] if i < len(v['items']) else None)
|
|
print(' horizon', r['items'][i] if i < len(r['items']) else None)
|
|
print(f' {v["id"]}: {len(v["items"])} stacks')
|
|
search = next(t['items'] for t in vanilla['tabs'] if t['type'] == 'SEARCH')
|
|
if search != rust['search']:
|
|
bad += 1; print(f'SEARCH TAB: {len(search)} vanilla stacks, {len(rust["search"])} horizon')
|
|
wrong = [(v, r) for v, r in zip(vanilla['searches'], rust['searches']) if v != r]
|
|
for v, r in wrong[:args.detail]:
|
|
missing = [search[i] for i in v['results'] if i not in r['results']][:3]
|
|
extra = [search[i] for i in r['results'] if i not in v['results']][:3]
|
|
print(f'SEARCH {v["query"]!r}: vanilla {len(v["results"])} results, horizon {len(r["results"])}; '
|
|
f'missing {missing} extra {extra}')
|
|
bad += len(wrong) + abs(len(vanilla['searches']) - len(rust['searches']))
|
|
for q in ('anvil', 'crafting', 'smithing'):
|
|
hits = next(v['results'] for v in vanilla['searches'] if v['query'] == q)
|
|
print(f' search {q!r}: {len(hits)} results, ' + ', '.join(json.loads('"' + search[i].split('id:"')[1].split('"')[0] + '"')
|
|
for i in hits[:6]))
|
|
print(f'{len(vanilla["searches"]) - len(wrong)}/{len(vanilla["searches"])} searches match; {len(shown)} tabs, '
|
|
f'{len(search)} search stacks')
|
|
if bad:
|
|
sys.exit(1)
|
|
print('creative parity ok')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|