Files
NX2navi/tests/prp_file_check.py
chrg6 cba95f8d0a Record in shader-prepared.bin which seed it was prepared from, and prepare again at an update when the seed changed.
The prepared list named its shader variants and nothing about where they came from, so an update that keeps the prepared shaders (shader_carry) kept the old list whatever seed the new kit writes: variants only the new seed names, from a newer pipeline list or a change to which variants are prepared, were translated when play first drew them. The existing identities do not cover this: nx2navi_xlate.id and identities.txt name translators, which decide cache keys and what is carried over, not which variants are listed.

The list is now version 2 (runtime/prp_file.h): after the head come the sha256 of seed-programs.bin, the sha256 of seed-answers.bin and the translator identity, written by gfx_shader_prepare_seed; the three readers go through gfx_shader_prepared_read and still read a version 1 list. At an update step_shaders writes the seed first (prepare_shaders.py --no-run, about 4 s) and keeps the list only when its digests are that seed's (make_game.py seed_changed); another seed, or a list that does not say, is prepared again. Another translator alone still carries over: input ids do not depend on the translator, and preparing everything again for it is what carrying was made to avoid.

Checked with tests/prp_file_check.py (the C layout against make_game's reader), three launcher tests, and the exe's --prepare-shaders on a seed without records in a folder of its own: the digests it wrote are those of the seed files, one byte more in the seed reads as changed, and after preparing again it does not. A version 1 list of 42,142 variants and the same list as version 2 are both read whole by --probe-prewarm.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-11 04:36:33 -05:00

54 lines
2.0 KiB
Python

"""Build and run tests/prp_file_check.c: runtime/prp_file.h, the layout of shader-prepared.bin with what the list was
prepared from. The list the C side writes is then read by tools/make_game.py prepared_from, so the game's writer and
the build's reader cannot drift apart. No game files, no GPU.
Usage: prp_file_check.py
"""
import importlib.util
import os
import shutil
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
MSYS_BIN = Path(r'C:\msys64\ucrt64\bin')
def compiler():
if os.environ.get('CC'):
return os.environ['CC']
if os.name == 'nt' and (MSYS_BIN / 'clang.exe').exists():
return str(MSYS_BIN / 'clang.exe')
return shutil.which('clang') or 'clang'
def main():
work = ROOT / 'build' / 'test' / 'prp_file'
work.mkdir(parents=True, exist_ok=True)
exe = work / ('prp_file_check.exe' if os.name == 'nt' else 'prp_file_check')
env = dict(os.environ)
if os.name == 'nt' and MSYS_BIN.exists():
env['PATH'] = str(MSYS_BIN) + os.pathsep + env.get('PATH', '')
subprocess.check_call([compiler(), '-O1', '-Wall', '-Werror', '-I', str(ROOT / 'runtime'),
str(ROOT / 'tests' / 'prp_file_check.c'), '-o', str(exe)], env=env)
rc = subprocess.run([str(exe), str(work)], env=env).returncode
if rc:
return rc
sys.path.insert(0, str(ROOT / 'tools'))
spec = importlib.util.spec_from_file_location('make_game', ROOT / 'tools' / 'make_game.py')
mg = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mg)
want = {'programs': bytes(range(32)).hex(), 'answers': bytes(range(0x40, 0x60)).hex(),
'translator': bytes(range(0x80, 0xa0)).hex()}
got = mg.prepared_from(work)
if got != want:
print(f'FAIL: tools/make_game.py prepared_from reads {got}, the game wrote {want}')
return 1
print('prepared list file: tools/make_game.py reads what the game writes')
return 0
if __name__ == '__main__':
sys.exit(main())