Full correctness check against the docs: safer writes, reverts and texts
Safety - Writes are serialized (Workspace.lock): two background jobs rebuilding one package (a sound and its subtitle applied side by side) lost an edit. - A store copies a bank file or package as "original" only if it matches the shipped catalog (Workspace.unoriginal_files: in-memory sounds, bank copies of voice lines, subtitles); the editor refuses to switch stores while changes are applied. A second store could otherwise resurrect a reverted sound. - Mod import in the editor asks before overwriting files changed outside the tool (it forced silently). - Revert all in the editor reverts texts too; the uninstaller counts text edits before offering to delete the store. - ackit restore-backup: the full-backup restore decisions.md described; it keeps the sounds of WADs without a full copy recorded. - build_catalog also stops when a subtitle differs from the catalog. Languages and texts - Game.language() returns languages without voices (JPN, RUS, ...) and Game.voice_archive() their INT voices; ackit text --lang JPN works. - Menu lookups parse one cached file (find & replace: minutes -> ms). - Subtitles decode cp1252 as Windows does: the UTF-8-in-cp1252 line Speech_TAPE_J_Answer_1_00 (KOR/POL/POR/RUS) is written back byte-for-byte; SUB_KOR/SUB_RUS rebuilt from the original game (only those rows changed). - Mods exported while another language is loaded keep name and line. Other fixes - Down-mix folds extra channels in at -3 dB (a 5.1 centre voice was dropped). - e2e_editor no longer overwrites the user's settings.json; kill_game waits for the game to exit before reverts. - Recorder handles Int32/UInt8 input and split frames; package block cache locked; conflict messages, CLI help examples, stale docstrings and doc references fixed; tests no longer read this PC's game language. Docs (decisions, user guide, README, subtitles.md, banks.md, catalog README, REPORT, NOTES, CLAUDE.md) updated; check_docs: 102 claims match. 148 tests; e2e_features 9/9, e2e_editor and verify PASS; game original afterwards.
This commit is contained in:
@@ -38,19 +38,32 @@ loopback); it is a developer tool and not part of the editor.
|
||||
- **Originals store** per game folder: `<user data>/UnheardCity/stores/<id>/` (Windows `%APPDATA%`, Linux
|
||||
`~/.local/share/unheardcity`), id = hash of the game path; configurable (`--store`, editor settings).
|
||||
Before a sound is first changed, its original WEM bytes (SHA-256-named blob) and metadata are saved;
|
||||
the applied replacement is saved too. **Revert** re-injects the stored original; **Revert all** does this for
|
||||
every record. Stream-pack padding bytes are stored so pack reverts are byte-identical.
|
||||
the applied replacement is saved too. **Revert** re-injects the stored original; **Revert all** (editor toolbar,
|
||||
`ackit revert --all`) does this for every record of the store, sounds and texts, in every language. Stream-pack
|
||||
padding bytes are stored so pack reverts are byte-identical. The uninstaller counts sound and text records and
|
||||
does not offer to delete the store while any is left.
|
||||
- **One store per game at a time:** the changes are recorded only in the store that made them. The editor
|
||||
refuses to switch to another store folder while changes are applied (Revert all first). A store takes the
|
||||
full copy of a soundbank or package only from a file that matches the shipped catalog (every in-memory
|
||||
sound's checksum, every bank copy of a voice recording, every subtitle; `Workspace.unoriginal_files`), so a
|
||||
second store (`--store`) or another tool's change is a conflict, never a new "original". (Menu files and other
|
||||
game builds have no catalog checksums to check.)
|
||||
- **Full-file fallback:** before the first change to a WAD (and its pack index), one verified full copy is kept
|
||||
in the store (`full/`), default on, can be disabled. Used by "Restore from full backup" if the store is damaged.
|
||||
in the store (`full/`), default on, can be disabled. If the store is damaged, `ackit restore-backup --yes`
|
||||
copies the WADs back (their sounds are forgotten) and rebuilds the soundbanks, packages and localization files
|
||||
from their copies, keeping the sounds of WADs without a full copy recorded and revertible.
|
||||
Soundbank files, packages and localization files always get this copy (they are rebuilt from it, 4b/4c).
|
||||
- **Why the user data folder:** it survives app updates and reinstalls, needs no write access next to the game,
|
||||
and works the same on Linux/Proton. Steam never touches it.
|
||||
- **Safe writes:** every WAD is rebuilt into a temp file and atomically renamed over the original, pack indexes
|
||||
first. Several sounds of one WAD are written in one pass. A locked WAD (game running) gives a clear message.
|
||||
Writes are serialized (`Workspace.lock`): the editor runs them as background jobs, and two rebuilds of one
|
||||
package at once (e.g. a sound and its subtitle applied side by side) would otherwise lose one edit.
|
||||
- **Changed underneath:** each sound's state is computed from its bytes: original / modified (ours) / lost
|
||||
(ours was replaced by the original, e.g. Steam "verify") / changed (neither: update or another tool) /
|
||||
foreign (never touched by us, but not the catalog's original checksum). Writing over changed/foreign sounds
|
||||
requires explicit confirmation; the catalog is used only when the WAD fingerprint matches.
|
||||
or texts requires explicit confirmation (editor: a question, also when installing a mod; CLI: `--force`); the
|
||||
catalog is used only when the game's fingerprint matches.
|
||||
|
||||
## 4. Size rule
|
||||
Speech/ambience variations are addressed by offset+size from BKPK tables inside compressed `.upk` packages,
|
||||
@@ -77,7 +90,7 @@ tables): high risk for little gain, not done.
|
||||
optional like the WAD copies: the file is rebuilt from it). The file content is always "original copy +
|
||||
replacements applied now", so reverting the last one restores the original bytes exactly, and an interrupted
|
||||
operation is repaired by the next one. Conflicts: the whole-file SHA-1 must be the original's or the last one
|
||||
ackit wrote.
|
||||
ackit wrote, and before the copy is taken the file must match the catalog (section 3).
|
||||
- **Prefetch heads and whole copies:** 396 voice recordings (81 lines, 78-80 recordings per language) have
|
||||
their first bytes copied into banks, and 49 more are stored whole in banks (same media ID, identical bytes);
|
||||
a replacement of such a recording rewrites those copies too, otherwise the game could play the old line.
|
||||
@@ -130,8 +143,9 @@ copy per voice language) is filtered the same way, so the sound list never mixes
|
||||
WAD voice lines), numbered `NAME#2` in the event's own order when it plays two versions; the other 637 keep
|
||||
the name of their English (INT) recording's position. The position in each language stays an alias (`NAME#i`).
|
||||
- A recording stored twice in a WAD (5 per language) is written and reverted in both places.
|
||||
- The catalog records the ORIGINAL bytes: `tools/build_catalog.py` stops before writing anything if a sound
|
||||
differs from the current catalog (a modified game), unless `--accept-changes` (a game update).
|
||||
- The catalog records the ORIGINAL bytes and texts: `tools/build_catalog.py` stops before writing anything if a
|
||||
sound or a subtitle differs from the current catalog (a modified game), unless `--accept-changes` (a game
|
||||
update).
|
||||
- Category scheme: `docs/categories.md`.
|
||||
|
||||
## 6. Repository cleanup choices
|
||||
|
||||
Reference in New Issue
Block a user