In-game text test, version 3.0.0, report

This commit is contained in:
2026-10-09 22:50:15 +02:00
parent a10593ec24
commit 98ec2fe9c4
10 changed files with 123 additions and 40 deletions

View File

@@ -8,4 +8,4 @@ Library layers (low -> high):
inject (WAD writing), originals (store), workspace (apply/revert), modpack (share)
tools cli (`ackit` command), verify/ (offline self-check, in-game test on Windows)
"""
__version__ = "2.0.0"
__version__ = "3.0.0"

View File

@@ -310,6 +310,8 @@ def cmd_verify(a):
from .verify import ingame
if a.banks:
rep = ingame.run_banks(ws, a.sound or None)
elif a.texts:
rep = ingame.run_texts(ws)
elif a.baseline:
rep = ingame.run(ws, a.target, mode="baseline", seconds=a.seconds)
elif a.installed:
@@ -390,6 +392,7 @@ def build_parser():
s.add_argument("--banks", action="store_true",
help="with --ingame: test in-memory sounds (default: the front-end banks, or --sound NAME ...)")
s.add_argument("--sound", action="append", default=[], help="with --banks: a sound to test (repeatable)")
s.add_argument("--texts", action="store_true", help="with --ingame: test menu text and subtitle edits")
# advanced
s = add("encode", cmd_encode, "[advanced] audio -> .wem file", (enc,))
s.add_argument("audio"); s.add_argument("out"); s.add_argument("--like", metavar="NAME")

View File

@@ -121,6 +121,57 @@ def run(ws, key=DEFAULT_TARGET, wem=None, mode="modded", seconds=40.0, threshold
return report
# --- texts --------------------------------------------------------------------------------------
def run_texts(ws, seconds=45.0, menu_files=("FRONTEND", "GFXUI"), n_menu=12, n_subs=12, logdir=None, log=print):
"""Write markers into menu texts of the game's language (front-end files, loaded at startup) and into some
subtitles, start the game, then check: no crash, the menu markers are in the game's memory (it loaded the
edited localization files), and after the revert every touched file is byte-identical. Subtitles are not
loaded on the title screen, so for them the check is that the patched packages do not break the game."""
import random
from .debugger import Run, kill_game, search_memory
tx = ws.texts
lang = ws.game.language()
menu = [e for e in tx.menu(lang) if e.file.split(".")[0].upper() in menu_files and len(e.value) >= 4]
rnd = random.Random(3)
picks = rnd.sample(menu, min(n_menu, len(menu)))
changes = {"MENU:" + e.key: "ACKIT%02d %s" % (i, e.value) for i, e in enumerate(picks)}
subs = [s for s in tx.subtitles(lang) if s.room >= 12] if lang in tx.subtitle_languages() else []
for i, s in enumerate(rnd.sample(subs, min(n_subs, len(subs)))):
changes["SUB:%s:%s:%d" % (lang, s.speech, s.line)] = ("AKS%02d " % i + s.text)[:s.room]
files = sorted({p for k in changes for p in tx.files(k)})
logdir = logdir or os.path.join(os.getcwd(), "logs")
os.makedirs(logdir, exist_ok=True)
logp = os.path.join(logdir, "ingame_texts_%s.log" % time.strftime("%Y%m%d_%H%M%S"))
report = dict(mode="texts", lang=lang, menu_texts=len(picks), subtitles=len(changes) - len(picks),
files=len(files))
kill_game()
before = {f: _sha1_file(f) for f in files}
tx.apply(changes, progress=log)
needles = {("ACKIT%02d " % i).encode("utf-16-le") for i in range(len(picks))}
runner = Run(ws.game.exe, logp)
found = set()
try:
report.update(runner.start())
while time.time() - runner.t0 < seconds and runner.alive():
time.sleep(0.5)
if re.search(r"^ACKIT_CRASH", runner.log(), re.M):
break
if runner.alive():
found = search_memory(report["pid"], needles)
report["alive_at_end"] = runner.alive()
finally:
runner.stop()
tx.revert(list(changes), progress=log)
report["reverted_byte_identical"] = all(_sha1_file(f) == h for f, h in before.items())
report["crash"] = bool(re.search(r"^ACKIT_CRASH", runner.log(), re.M))
report["menu_markers_in_memory"] = len(found)
ok = (not report["crash"] and report["alive_at_end"] and report["menu_markers_in_memory"] > 0
and report["reverted_byte_identical"])
report["result"] = "PASS" if ok else "FAIL"
json.dump(report, open(logp.replace(".log", ".json"), "w"), indent=1)
return report
# --- in-memory sounds (soundbanks inside the packages) ------------------------------------------
PROBE_RATE, PROBE_Q = 28000, 4 # a codebook setup the game's own WEMs do not use (E10)