Version 3.1.0: voice lines linked across all languages from the game data
This commit is contained in:
@@ -69,18 +69,18 @@ def run(ws, key=DEFAULT_TARGET, wem=None, mode="modded", seconds=40.0, threshold
|
||||
report = dict(target=s.key, name=s.name, mode=mode)
|
||||
before = {f: _sha1_file(f) for f in files} if mode == "modded" else {}
|
||||
|
||||
if mode == "modded":
|
||||
ws.apply([(s, wem, {"source": "ingame-test"})], progress=log)
|
||||
expect = ws.current_bytes(s)
|
||||
orig = ws.original_bytes(s)
|
||||
from ..wem import Wem
|
||||
report["expect_hash"] = "%08x" % Wem.parse(expect).vorb["codebook_hash"]
|
||||
ref_expect, ref_orig = _mono48(expect), _mono48(orig)
|
||||
|
||||
rec = LoopbackRecorder(seconds + 10)
|
||||
rec.start()
|
||||
runner = Run(ws.game.exe, logp)
|
||||
try:
|
||||
rec = runner = None
|
||||
try: # from the first write on: whatever happens, the finally block reverts
|
||||
if mode == "modded":
|
||||
ws.apply([(s, wem, {"source": "ingame-test"})], progress=log)
|
||||
expect = ws.current_bytes(s)
|
||||
orig = ws.original_bytes(s)
|
||||
from ..wem import Wem
|
||||
report["expect_hash"] = "%08x" % Wem.parse(expect).vorb["codebook_hash"]
|
||||
ref_expect, ref_orig = _mono48(expect), _mono48(orig)
|
||||
rec = LoopbackRecorder(seconds + 10)
|
||||
rec.start()
|
||||
runner = Run(ws.game.exe, logp)
|
||||
report.update(runner.start())
|
||||
while time.time() - runner.t0 < seconds and runner.alive():
|
||||
time.sleep(0.5)
|
||||
@@ -88,9 +88,11 @@ def run(ws, key=DEFAULT_TARGET, wem=None, mode="modded", seconds=40.0, threshold
|
||||
break
|
||||
report["alive_at_end"] = runner.alive()
|
||||
finally:
|
||||
runner.stop()
|
||||
rec.stop_flag = True
|
||||
rec.join(5)
|
||||
if runner:
|
||||
runner.stop()
|
||||
if rec:
|
||||
rec.stop_flag = True
|
||||
rec.join(5)
|
||||
if mode == "modded" and revert_after:
|
||||
ws.revert([s], progress=log)
|
||||
report["reverted_byte_identical"] = all(_sha1_file(f) == h for f, h in before.items())
|
||||
@@ -123,10 +125,11 @@ def run(ws, key=DEFAULT_TARGET, wem=None, mode="modded", seconds=40.0, threshold
|
||||
|
||||
# --- 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."""
|
||||
"""Write markers into menu texts of the game's language (front-end files, loaded at startup), into the
|
||||
subtitles stored in Startup.upk (RSubtitle objects, loaded at startup) and into some other subtitles, start
|
||||
the game, then check: no crash, the menu and Startup subtitle markers are in the game's memory (it loaded the
|
||||
edited files), and after the revert every touched file is byte-identical. The other subtitles are not loaded
|
||||
on the title screen; 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
|
||||
@@ -136,21 +139,31 @@ def run_texts(ws, seconds=45.0, menu_files=("FRONTEND", "GFXUI"), n_menu=12, n_s
|
||||
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)))):
|
||||
startup = [s for s in subs if {l.file for l in tx.subtitle_locations("SUB:%s:%s:%d" % (lang, s.speech, s.line))}
|
||||
== {"Startup.upk"}]
|
||||
for i, s in enumerate(startup):
|
||||
changes["SUB:%s:%s:%d" % (lang, s.speech, s.line)] = ("AKST%02d " % i + s.text)[:s.room]
|
||||
others = [s for s in subs if s not in startup]
|
||||
for i, s in enumerate(rnd.sample(others, min(n_subs, len(others)))):
|
||||
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))
|
||||
report = dict(mode="texts", lang=lang, menu_texts=len(picks), startup_subtitles=len(startup),
|
||||
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))}
|
||||
sub_needles = {} # marker -> its byte forms (the game may keep cp1252 or UTF-16)
|
||||
for i in range(len(startup)):
|
||||
m = "AKST%02d " % i
|
||||
sub_needles[m] = {m.encode("utf-16-le"), m.encode("cp1252")}
|
||||
needles |= {n for v in sub_needles.values() for n in v}
|
||||
runner = Run(ws.game.exe, logp)
|
||||
found = set()
|
||||
try:
|
||||
try: # from the first write on: the finally block reverts
|
||||
tx.apply(changes, progress=log)
|
||||
report.update(runner.start())
|
||||
while time.time() - runner.t0 < seconds and runner.alive():
|
||||
time.sleep(0.5)
|
||||
@@ -164,9 +177,10 @@ def run_texts(ws, seconds=45.0, menu_files=("FRONTEND", "GFXUI"), n_menu=12, n_s
|
||||
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)
|
||||
report["menu_markers_in_memory"] = sum(1 for i in range(len(picks)) if ("ACKIT%02d " % i).encode("utf-16-le") in found)
|
||||
report["startup_subtitles_in_memory"] = sum(1 for v in sub_needles.values() if v & found)
|
||||
ok = (not report["crash"] and report["alive_at_end"] and report["menu_markers_in_memory"] > 0
|
||||
and report["reverted_byte_identical"])
|
||||
and (not startup or report["startup_subtitles_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
|
||||
@@ -221,7 +235,6 @@ def run_banks(ws, keys=None, seconds=45.0, logdir=None, log=print):
|
||||
if len(w) > 400:
|
||||
needles.add(w[len(w) // 2:len(w) // 2 + 32])
|
||||
report.update(probe_hashes=sorted(hashes), needles=len(needles))
|
||||
ws.apply([(s, w, {"source": "ingame-test"}) for s, w in probes], progress=log)
|
||||
from .debugger import ADDR
|
||||
# also log every setup parse (in-memory sources may not go through the stream setup cache)
|
||||
extra = 'bp %#x ".printf \\"ACKIT_PARSE2 hash=%%08x\\\\n\\", poi(poi(@esp+4)+0x9c); gc"' % ADDR["parse_setup"]
|
||||
@@ -229,7 +242,8 @@ def run_banks(ws, keys=None, seconds=45.0, logdir=None, log=print):
|
||||
found = set()
|
||||
rec = LoopbackRecorder(seconds + 10)
|
||||
rec.start()
|
||||
try:
|
||||
try: # from the first write on: the finally block reverts
|
||||
ws.apply([(s, w, {"source": "ingame-test"}) for s, w in probes], progress=log)
|
||||
report.update(runner.start())
|
||||
pid = report["pid"]
|
||||
while time.time() - runner.t0 < seconds and runner.alive():
|
||||
|
||||
Reference in New Issue
Block a user