Skip to content

TAD Files

philyeahz edited this page Sep 7, 2018 · 30 revisions

The TAD files contain the indices of the files inside the corresponding TAC files.

Header (0x00 - 0x38) [56 Bytes]

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

Checksum

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

File Entry Header [32 Bytes]

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

File Entry String Hashes

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.

Final Filename Hash

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

Pre Filename Hash

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

Pre + Final Filename Hash Example

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

ASM Notes (Build Version: 108434)

File Initialization

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)

...

TADEntryReader()

Address: BaseOffset + 28FB40

ReadFunction(?)

Address: BaseOffset + 28F3E0

GetPointerFromFilename(char* filename, struct{int v1, int v2}** s)

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.