-
Notifications
You must be signed in to change notification settings - Fork 1
TAD Files
The TAD files contain the indices of the files inside the corresponding TAC files.
Position | Length | Value | Description | Changeable |
---|---|---|---|---|
0x00 | 0x04 | 0x01000000 (1) | File Type Identifier | false |
0x04 | 0x04 | 0x05000000 (5) | Hardcoded Identifier | false |
0x08 | 0x04 | 0x02000000 (2) | Hardcoded Identifier | false |
0x10 | 0x04 | - | Timestamp (time_t) | true |
0x18 | 0x04 | 0x64783131 ("dx11") | Graphics API that should be used | false? |
0x20 | 0x04 | - | Header Checksum (MurmurHash2) | true |
0x28 | 0x08 | - | TAC File Size | true |
0x30 | 0x08 | - | File Count | true |
After the TAD header there are 4 bytes for the file count again:
Position | Length | Description | Changeable |
---|---|---|---|
0x38 | 0x04 | File Count | true |
The Header checksum is calculated with an special MurmurHash2 hash function using the following parameters:
Parameter | Value |
---|---|
Initialization Seed | 66EE5D0h |
m (multiplier) | 5BD1E995h |
r (rotation) | 18h |
Before hashing the header zero the hash inside the header. For code implementation: Link
Position | Length | Description | Changeable |
---|---|---|---|
0x00 | 0x04 | Final Filename Hash | false (changeable if the filename is not already in use) |
0x04 | 0x04 | Pre Filename Hash | false (changeable if the filename is not already in use) |
0x08 | 0x04 | Unknown (Hash?) | ? |
0x0C | 0x04 | Empty | - |
0x10 | 0x08 | File start offset inside TAC | true |
0x18 | 0x08 | File size | true |
The file entries contain 16 Bytes of some sort of hash values which correspond to the filenames in some way.
Hash Table Lookup seems not plausible because not all filename string parts are inside the executable.
BUT the AssetRemapping.json gets loaded at the start of the game which is found in the common_5b6c4cd0.tad/tac as the first entry. This file holds all the strings for the filenames inside an hash collision map which would suggest an hash table lookup.
The first DWord (4 Bytes) contains an MurmurHash2 of the filename which before gets trimmed off, set all characters to there lower self and removing all the '/' forward slashes from the path.
Step | Value |
---|---|
Input | "./tex/assets//Remap/AssetRemapping.json" |
String Preperation | "texassetsremapassetremapping.json" |
MurmurHash2 | 0xD931A585 |
Final Hash | 0x46C8021E |
The final hash gets calculated from the MurmurHash2 and goes as follows:
MurmurHash2 * 0x1003F + Filename.Length^2 * 0x2001F
The second DWord (4 Bytes) contains the first MurmurHash2 that is needed for the Final Filename Hash. The hash gets appended to the filename before hashing the Final Filename Hash.
Step | Value |
---|---|
Input | "/ui/font/english.fontdef?font=0&image=1" |
MurmurHash2 | 0x6F742957 |
New Filename | "/ui/font/english.fontdef.6f742957.00000000" |
String Preperation | "uifontenglish.fontdef.6f742957" |
Hash = 0x6F742957
Step | Value |
---|---|
Input | "/ui/font/english.fontdef?font=0&image=1" |
MurmurHash2 | 0x6F742957 |
New Filename | "/ui/font/english.fontdef.6f742957.00000000" |
String Preperation | "uifontenglish.fontdef.6f742957" |
MurmurHash2 | 0xBCF67468 (Don't know use) |
Final Hash | 0xFE333346 (Don't know use) |
Add Prefix | "./tex/assets///ui/font/english.fontdef.6f742957.00000000" |
String Preperation | "texassetsuifontenglish.fontdef.6f742957" |
MurmurHash2 | 0xA1C2969A |
Final Hash | 0x741DF296 |
First Loading
Here the TAD files get validated via the header hash and sorted by their timestamp to know which to load and overwrite another.
ReadFile(.//Archives/dx11//data//audio_eng_5b69b0ee.tad, 1759B329EE0)
ReadFile(.//Archives/dx11//data//audio_jap_5b69b0ee.tad, 1759B329EE0)
ReadFile(.//Archives/dx11//data//common_5b69b0ee.tad, 1759B332140)
ReadFile(.//Archives/dx11//data//common_5b6c4cd0.tad, 1759CCE3C50)
ReadFile(.//Archives/dx11//data//disk_5b69b0ee.tad, 1759CCE3C50)
ReadFile(.//Archives/dx11//data//shaders_pc_5b69b0ee.tad, 1759B329EE0)
ReadFile(.//Archives/dx11//data//shaders_xb1_5b69b0ee.tad, 1759B329EE0)
Second Loading
Seems to load the TAD file entries and stores them in RAM. Only valid TAD files get loaded.
ReadFile(.//Archives/dx11//data//common_5b6c4cd0.tad, 1759979FB60)
ReadFile(.//Archives/dx11//data//audio_eng_5b69b0ee.tad, 1759B328FD0)
ReadFile(.//Archives/dx11//data//audio_jap_5b69b0ee.tad, 1759B328FD0)
ReadFile(.//Archives/dx11//data//common_5b69b0ee.tad, 1759B332140)
ReadFile(.//Archives/dx11//data//disk_5b69b0ee.tad, 1759CCE3C50)
ReadFile(.//Archives/dx11//data//shaders_pc_5b69b0ee.tad, 1759B328FD0)
ReadFile(.//Archives/dx11//data//shaders_xb1_5b69b0ee.tad, 1759B328FD0)
AssetRemapping.json
GetPointerFromFilename(./tex/assets//Remap/AssetRemapping.json, s0[7FF9C11F0704]{48C88B48, 48C88B4C})
//Forced by AssetRemapping.json
ReadFile(.//Archives/dx11//data//common_5b6c4cd0.tac, 1759CCE3C50)
TAC Loading
ReadFile(.//Archives/dx11//data//disk_5b69b0ee.tac, 175A71055C0)
ReadFile(.//Archives/dx11//data//shaders_pc_5b69b0ee.tac, 175A70341D0)
...
ReadFile(.//Archives/dx11//data//common_5b69b0ee.tac, 175A73492C0)
...
Address: BaseOffset + 28FB40
Address: BaseOffset + 28F3E0
Address: BaseOffset + 2A2640
This function returns the pointer of the given file inside the tac file. The struct argument is mostly an nullptr and has no big impact, but when it is not it points to other modules which is weird.