Game line names across languages; RSubtitle; editor in three columns
This commit is contained in:
@@ -60,8 +60,12 @@ Two separate fields, because Wwise names describe a *scene*, not the speaker of
|
||||
alternates speakers between `NAME_1`, `NAME_2`, ...):
|
||||
|
||||
- **character** - the verified speaker, only from the curated lists in `data/catalog/source/<lang>/*.txt`
|
||||
(one file per character, listening-based). Mapped by sound name, so labels made on the Italian files apply to
|
||||
every language (the five language WADs have identical names and variation counts). Display names:
|
||||
(one file per character, listening-based). The lists name ITA sounds by their position in the ITA WAD
|
||||
(wemscan names); positions differ between languages, so each label is moved to the game's line name of that
|
||||
sound (`characters.csv`, empty `language`) and then applies to the same line in every language. Labels of
|
||||
sounds no event plays stay ITA-only (`language` = ITA). Checked against the speaker field of the game's
|
||||
dialogue objects: 955 / 955 labelled lines agree (spelling aside: TwoFace, Mysterious_stranger = Azrael).
|
||||
Display names:
|
||||
Calendar -> Calendar Man, Croc -> Killer Croc, Freeze -> Mr. Freeze, Ivy -> Poison Ivy, Madhatter -> Mad
|
||||
Hatter, Quinn -> Harley Quinn, Ras -> Ra's al Ghul, Strange -> Hugo Strange, Talia -> Talia al Ghul,
|
||||
Twoface -> Two-Face, Vicky -> Vicki Vale, Zsazz -> Victor Zsasz, Unknown -> Unknown (speaker checked but not
|
||||
|
||||
@@ -103,6 +103,10 @@ copy per voice language) is filtered the same way, so the sound list never mixes
|
||||
- Shipped CSVs per archive (names, categories, characters, original size + checksum) make loading instant and
|
||||
enable change detection; any other build is scanned at runtime (header reads only, cached).
|
||||
- Verified speakers come only from the user's lists; name-based character inference is kept in a separate field.
|
||||
- Speech sounds are named after the game's line (speech event), not after their position in the WAD entry:
|
||||
the WEMs of an entry are stored in media-ID order and every language has its own media IDs, so position i
|
||||
is a different line in each language (75 % of the multi-variation lines). Line names make names, speaker
|
||||
labels, mod packages and subtitles agree across languages.
|
||||
- Category scheme: `docs/categories.md`.
|
||||
|
||||
## 6. Repository cleanup choices
|
||||
|
||||
@@ -13,6 +13,13 @@ the UE3 packages (`upk.md`), holding the subtitle text of all 11 languages. acki
|
||||
- Strings are stored as cp1252 (positive FString length) or UTF-16 (negative length): RUS, POL, JPN, KOR
|
||||
and some INT/ESN/FRA/DEU strings are UTF-16.
|
||||
|
||||
## Scripted subtitles (`RSubtitle`)
|
||||
41 more subtitles (radio and encryption-card lines) are `RSubtitle` objects in `Startup.upk`: the same layout,
|
||||
with the per-language array named `ArraySubtitles` and a float (duration) at `0x2C` instead of a speech
|
||||
reference. `RSubtitleLookup` (`Startup.upk`, `Lookups`) is an array of `{int key @0, object @4}`, key =
|
||||
FNV-1 of the speech line name without `Speech_` (e.g. `CH_ZERO_CH0_ENCRYPTION_CARD2_01`), which links each
|
||||
`RSubtitle` exactly to its line. ackit reads and writes both kinds the same way.
|
||||
|
||||
## Object layout (compact tagged properties)
|
||||
The export data is a list of properties `u16 type, u16 field offset, value`, ended by `u16 0`. Types seen:
|
||||
`0x10` object reference (i32 export/import index), `0x0D` FString, `0x09` struct/array (name i32+i32 = struct
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 204 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 192 KiB |
@@ -89,6 +89,17 @@ Conclusion: approach A works end-to-end in-game. Use >= 30 s probes for the intr
|
||||
prefixed with markers and 12 subtitles patched in place (21 files). All 12 markers are found as UTF-16 in the
|
||||
game's memory after ~45 s (the localization files are read at startup), no crash, revert byte-identical:
|
||||
PASS. Subtitles are not loaded on the title screen (no dialogue object in Frontend*/Startup/BmGame).
|
||||
20. (2026-10-10) **Variation positions differ between languages.** A WAD entry stores its WEMs in media-ID order
|
||||
and each language has its own media IDs, so for 7,010 of 9,366 lines (75 %) the same game line is at a
|
||||
different position in the ITA and INT entries (e.g. Speech_CH_ZERO_CH0_fight_intro_01 = ITA :0, INT :2).
|
||||
Position names (NAME_i, wemscan) therefore mean different lines per language. Speech sounds are now named
|
||||
after their speech event (same in every language); the curated ITA lists are mapped through it. Independent
|
||||
check: the speaker field of the dialogue objects agrees with the mapped labels for 955 / 955 lines.
|
||||
21. (2026-10-10) In-memory speech banks are localized (language list + one bank per language in one AkBank
|
||||
export, checked on 215 banks against the WAD languages of their streamed lines); 41 more subtitles are
|
||||
RSubtitle objects linked through RSubtitleLookup (key = FNV-1 of the line name without `Speech_`). Subtitle
|
||||
coverage by category is uneven in the game itself: efforts 0 %, combat barks 11 %, cinematics 10 % (cutscene
|
||||
lines are mostly not reached by speech events and have no dialogue object), story/predator/open world ~90 %+.
|
||||
|
||||
## Old path -> new path
|
||||
`scripts/harness.py` -> `ackit verify --ingame` (ackit/verify/ingame.py); `scripts/validate_builder.py` ->
|
||||
|
||||
@@ -26,6 +26,12 @@ game is set to (Steam > game properties > Language) and applies to everything yo
|
||||
- **Subtitles** and **Menu text**: the texts of that language.
|
||||
Changing it reloads the lists; the next start is again in the game's language.
|
||||
|
||||
## Names
|
||||
Voice lines carry the game's own line names (e.g. `Speech_TAPE_JOKER_1_04`), the same in every language and the
|
||||
same as in the Subtitles tab. Inside a WAD entry the game stores the variations of a line in a different order
|
||||
in each language, so the position-based name is kept only as a second name (`Speech_TAPE_JOKER_1#4` = the 4th
|
||||
WEM of that entry in this language; search finds both).
|
||||
|
||||
## Find a sound
|
||||
- Type in the **search box** (Ctrl+F): words can be parts of the name, a category, a character, your own
|
||||
notes or tags, or an ID like `b49cdf48`. All words must match.
|
||||
@@ -44,7 +50,9 @@ Changing it reloads the lists; the next start is again in the game's language.
|
||||

|
||||
|
||||
## Listen
|
||||
Select a row and press **Space** (or double-click) to play the original. In the editor below:
|
||||
The editor under the list shows the selected sound in three columns side by side (drag the dividers to
|
||||
resize them): **Listen**, **Replace** and **Subtitle**. Select a row and press **Space** (or double-click) to
|
||||
play the original. In **Listen**:
|
||||
- **Original** / **Installed** play the game's original and what is currently in the game. Click on a
|
||||
waveform to play from that point. **Loop**, **Volume** and **Stop** (Esc) work for everything.
|
||||
- **A/B** switches between the original and your replacement at the same position, to compare.
|
||||
@@ -54,8 +62,8 @@ Select a row and press **Space** (or double-click) to play the original. In the
|
||||
1. **Load file…** (Ctrl+O): WAV, FLAC, OGG, OPUS, MP3 or AIFF. (M4A/WMA work only if ffmpeg is installed.)
|
||||
Or choose a microphone in the list and press **Record**, then **Stop recording**. Listen with
|
||||
**Replacement**; record again as often as you like.
|
||||
2. Adjust: **Keep from / to** trims (or right-drag on the replacement waveform), **Trim silence**, **Gain**,
|
||||
**Normalize**, **Match original loudness** (recommended for voice lines).
|
||||
2. Adjust: **Keep … to** trims (or right-drag on the replacement waveform), **Trim silence**, **Gain**,
|
||||
**Normalize**, **Match loudness** (to the original; recommended for voice lines).
|
||||
3. **Apply to game** (Ctrl+S). The audio is converted to the original's format and written into the game files.
|
||||
The row turns bold and shows *Modified*.
|
||||
|
||||
@@ -65,7 +73,7 @@ you are asked to shorten it. Music (`Music_…`) can be any length. A warning ap
|
||||
than the original, since the game may cut it off.
|
||||
|
||||
## Undo
|
||||
- **Revert to original** in the editor puts that sound back exactly.
|
||||
- **Revert** in the editor puts that sound back exactly.
|
||||
- Right-click rows → **Revert selected**; toolbar **Revert all** puts every original back.
|
||||
- Originals are kept in your user data folder (`%APPDATA%\UnheardCity` on Windows,
|
||||
`~/.local/share/unheardcity` on Linux), so reverting works after updating or reinstalling the app too.
|
||||
|
||||
Reference in New Issue
Block a user