4.1 KiB
Arkham City WAD / BKPK container format
All values little-endian. Verified by byte-identical round trips of every shipped WAD
(INT/ITA/FRA/DEU/ESN LOC WADs and SFX\17705D3E.wad) and every BKPK pack.
WWAD (*.wad)
| off | type | meaning |
|---|---|---|
| 0x00 | 4s | WWAD |
| 0x04 | u32 | version 0x01020000 |
| 0x08 | u32 | entry count N |
| 0x0C | u32 | table offset (always 0x1C) |
| 0x10 | u32 | table size (12*N) |
| 0x14 | u32 | data start (header area size; 0x8000 LOC, 0x1000 SFX) |
| 0x18 | u32 | data size (file size - data start) |
| 0x1C | N x {u32 hash, u32 size, u32 offset} |
Rules:
- Table sorted by
hashinterpreted as signed int32. Payloads stored in table order. - Each payload starts at the next 0x1000-aligned offset after the previous one.
size= payload length rounded up to 0x800; padding is zero.- File ends 0x1000-aligned; header area after the table is zero.
hash= Wwise ID of the soundbank whose streamed media the entry holds: FNV-1 of a bank name listed inCookedPCConsole\CookedBanks.txt(e.g.CHR_RadioScanner,AMB_Steel_B3,Music); this names every entry the game uses (2,544 of 2,547; ackit takes the names from there).
Payload kinds:
- LOC WADs: each entry is a group of WEMs, the variations of one line (every language: 10,816 WEMs in
2,464 entries; e.g.
CHR_RadioScannerholds 91). Each WEM starts at the next 0x800 boundary after the previous one (zero padding); 3 entries pack two WEMs back to back. AddressedHASH:i. The WEMs of an entry are stored in media-ID order and the languages have different media IDs, so variationiis a different line in each language (75 % of the lines). Which recording is which line comes from the banks (banks.md, Lines), not from positions. - SFX WAD: 79 grouped ambience/effect entries (260 WEMs) plus 4 stream packs (below).
Where the game gets the inner offsets: the entry IDs appear next to BKPK headers inside the
LZO-compressed UE3 packages (e.g. BmGame.upk, OW.upk, Church_B1_*.upk). A speech entry has one table
per language, inside a localized AkBank export (its k-th table belongs to the k-th language the export lists;
the SFX WAD's 79 tables are outside such exports). Those embedded BKPK tables give each WEM's offset and
size; in every language each WEM has exactly one row (banks.md, Lines). ackit never changes them,
so these WEMs are replaced in place, no larger than the original (zero-filled to the original size), and
the WAD layout never changes. The user's earlier quickbms-reimport mod did the same and was loaded by the game.
Only the 4 SFX stream packs, whose BKPK index is a loose .bnk, can change size.
BKPK stream packs (SFX\<ID>.bnk + SFX WAD entry <ID>)
EDF036D6 (Music, 314 WEMs, incl. the intro/front-end music 393BC53A), E8F980BE (Music_PDLC, 75),
57572DAC (Global, 1), FCA4F778 (1). The .bnk file is an index + an embedded soundbank; the WEM
data lives in the SFX WAD entry with the same ID.
| off | meaning |
|---|---|
| 0x00 | BKPK |
| 0x04 | version 0x01020000 |
| 0x08 | pack id (== WAD entry hash) |
| 0x10 | media count N |
| 0x18 | table size 12*N |
| 0x1C | table offset 0x48 |
| 0x20 | total stream size (== WAD entry size) |
| 0x2C | end of table (0x48 + 12*N) |
| 0x38 | embedded bank size |
| 0x3C | embedded bank offset (0x800 or 0x1000; a normal BKHD/HIRC/STID bank) |
| 0x48 | N x {u32 media id, u32 size, u32 offset in the WAD entry} |
Rules: table sorted by media id; each media starts at the next 0x800-aligned offset; total =
end rounded up to 0x800. Padding is mostly zero (a few non-zero bytes in EDF036D6; the tool keeps
original bytes where nothing moved).
Replacing a pack media (ackit target EDF036D6/393BC53A) rewrites the pack table (.bnk), the
WAD entry payload, and the WAD table/offsets. Verified in-game (findings E2, E14).
Regular soundbanks
The other SFX\*.bnk files and the banks embedded in .upk packages hold their WEMs in memory (not in a
WAD); ackit lists and writes them as the catalog archive BANK (banks.md).