Version 3.4.0: Edit tab (edit list, large subtitle, replacements with effects and presets), Sounds tab only browses, ackit fx (pedalboard + own reverb) and replace --fx, first Linux build, catalog without a mod package

This commit is contained in:
2026-10-28 13:54:12 +01:00
parent a706dae419
commit 6de470174e
36 changed files with 2872 additions and 278 deletions

View File

@@ -1,17 +1,19 @@
"""Real end-to-end test of the EDITOR code path against the installed game (Windows, Steam running, WinDbg).
1. open the editor (offscreen) on the real game, select the intro music (Music_393BC53A);
2. load a 30 s probe file as replacement and press Apply (EditorPanel.apply);
1. open the editor (offscreen) on the real game, select the intro music (Music_393BC53A) and press Edit;
2. load a 30 s probe file as replacement and press Apply (EditorPanel.apply in the Edit tab);
3. start the game under cdb + speaker loopback: the probe must be heard, no crash, setup parsed;
4. press Revert (EditorPanel.revert) and check the WAD + pack index are byte-identical to before;
5. also apply/revert a speech line in place and check byte identity.
Uses the user's settings and originals store (an interrupted run shows up in `ackit status`); the settings file
is never written.
is never written, and the Edit tab's list and replacements go to a temporary folder (the user's edit list is
untouched).
python tools/e2e_editor.py
"""
import hashlib
import os
import shutil
import sys
import tempfile
@@ -40,6 +42,9 @@ def main():
# stores its settings on load and on close, which would overwrite the user's file with this test's ones
w = MainWindow(settings=dict(settings_mod.load(), full_backup=True), runner=Runner(sync=True))
w.save_settings = lambda: None
from app.edit import EditStore
edits = tempfile.mkdtemp() # not the user's edit list and replacements
w.edit.store = w.edit.model.store = EditStore(edits)
w.confirm = lambda *a: True
w.editor.confirm = lambda *a: True
errors = []
@@ -55,6 +60,7 @@ def main():
ws.texts.revert_all()
print("E2E EDITOR %s" % ("PASS" if ok else "FAIL"))
w.close()
shutil.rmtree(edits, ignore_errors=True)
return 0 if ok else 1
@@ -72,6 +78,7 @@ def run(w, ws, errors):
w.search.setText("Music_393BC53A")
w._filter_text()
assert w.select_name("Music_393BC53A")
w.edit_selected() # the Edit tab, on this sound
x, sr = ingame.probe_signal(30.0)
probe = os.path.join(td, "probe.wav")
audio.save_wav(probe, x, sr)
@@ -94,6 +101,7 @@ def run(w, ws, errors):
tb = sha(twad)
w.clear_filters()
assert w.select_name(t.name)
w.edit_selected()
y, ysr = audio.decode_wem(ws.original_bytes(t))
line = os.path.join(td, "line.wav")
audio.save_wav(line, y[::-1], ysr) # reversed speech, same length