Skip to content

PAK archives

Robomodo RMEArchives and filesApplies toSHRED

Every resource of Tony Hawk: SHRED sits in a PAK file. A PAK is a flat table of entries, then a string table of their names, then the entries’ bytes; the engine loads a PAK by sections (MAIN, LOCAL, TEXTURES_STREAMED, …), which are runs of entries opened by marker entries. There are 336 PAKs on the disc, with 67,320 entries in all, and the same container holds the game’s compiled scripts. Proven · all 336 PAKs

Every number in this page is big-endian. The disc carries these PAKs: 209 in levels/layers, 105 in characters, 10 in levels, 5 in anim, 3 in flash, 3 in the root of USRDIR and 1 in database. Observed

PAK header16 bytesSHRED100% known

Followed at once by the entry table.

ProvenObservedSourcedInferredUnknownNot described
OffsetSizeTypeFieldConfidenceNotes
0x04char[4] = PAK\0magicProven
0x42u16 = 0xFEEBbyte_order_markProventhe same in every PAK
0x62u16 = 4versionProven
0x84u32entry_countProven
0xC4u32string_table_sizeProvenbytes of names between the entry table and the data

The entry table follows at offset 16 (16 + 32 × entry_count), then the string table, then the data. The string table holds every name once as a zero-terminated string and the longest name is 137 characters. Proven · all 336 PAKs The executable’s own reader does not check the magic or the version; they are the values every PAK carries. Observed

PAK entry32 bytesSHRED100% known

A section marker precedes the entries it opens.

ProvenObservedSourcedInferredUnknownNot described
OffsetSizeTypeFieldConfidenceNotes
0x04u32hashProvensdbm of the name bytes, see Names and hashes
0x44u32name_offsetProvenfrom the start of the string table
0x84u32attributesProvenflag value 1 section marker, 2 compressed (CSTR); the values on the disc are 0, 1 and 2
0xC4u32alignmentObserved0, 16, 64 or 128; the allocation alignment the loader asks for
0x104u32offsetProvenof the payload from the start of the file
0x144u32sizeProvenuncompressed bytes
0x184u32compressed_sizeProvenstored bytes of a compressed entry, otherwise 0
0x1C4u32loaded_offsetObserved0 on the disc; the loader writes it when it materialises a section

The three attribute values divide the 67,320 entries into 2,744 section markers (1), 33,349 plain entries (0) and 31,227 compressed entries (2). Proven · all 336 PAKs A plain entry is stored as it is, size bytes at offset; a compressed entry occupies compressed_size bytes there and decodes to size bytes (CSTR streams). Proven · all 336 PAKs Offsets add up exactly: the entries follow the string table without a gap, and over all 336 PAKs they tile the file to its last byte. Proven · all 336 PAKs

The executable’s reader rejects section markers when it opens a file, picks the compressed-stream wrapper when bit 1 is set, and passes the alignment word to its allocator, with values 0x10, 0x40 and 0x80 meaning 16, 64 and 128 bytes. Observed · static reading of the executable Of the 63,175 entries with a nonzero alignment 59,206 are not aligned in the file, so the word is not a file layout rule. Observed The alignment values over the disc are 0 for the 2,744 markers, 16 for 63,175 entries, 64 for 81 and 128 for 1,320. Proven · all 336 PAKs The executable’s lookup also uses the flag value 4 as a loader state; no entry on the disc has it set. Observed

A section marker is an entry with attribute 1, no extension, size 0 and compressed size 0; it names the section that the entries after it belong to, up to the next marker. Proven · all 336 PAKs

Section PAKs with it Entries (excluding markers) Holds
MAIN 336 5,969 .scp, .mlp, .mmp of the level; textures, animation, other .bin files
LOCAL 325 624 .mgp of the level (extra vertex attributes), a few textures
SHADERS 324 2,854 .shp, .psp, .vsp shader programs
TEXTURES_PREFETCH 324 19,884 .thp headers and .txp pixels of the small mip levels
TEXTURES_STREAMED 324 25,962 .thp and .txp of the textures
PHYSICS 219 482 .hkw Havok files
ROBOTRAX 219 633 .bin files
ACTORS_MAIN, ACTORS_LOCAL, ACTORS_PREFETCH 219 each 126, 42, 5,478 the same kinds as the level’s own sections, for actors
CACHE_MOVIES, CACHE_TEXTURES, CACHE_MAIN, CACHE_LOCAL 3, 3, 2, 1 33, 722, 426, 88 .gfx Scaleform movies, textures
CHARACTERS, ENVIRONMENTS, ACTORS, ICE_PROGRAMS, LENS_FLARE, EFFECTS 2, 1, 1, 1, 1, 1 778, 2, 2, 286, 23, 162 texture, material-bank, .ice and effect files

The counts are over the 336 PAKs. Proven · all 336 PAKs The executable’s section loader names SHADERS, TEXTURES_PREFETCH, MAIN and LOCAL; what the remaining sections mean is read from their names and contents. Inferred

A texture appears in TEXTURES_PREFETCH and TEXTURES_STREAMED under the same name: the prefetch copy is its small mip levels. Observed

An entry’s name is a lower-case path with backslash separators and its extension kept, for example anim\actor_male\actor_male. All 64,576 non-marker names contain a backslash and none contains an upper-case letter or a forward slash. The names of section markers are upper-case words. Proven · all 336 PAKs

The hash is sdbm of the name’s bytes, as stored, with no case change or separator change:

h = 0
for each byte c of the name: h = (h * 65599 + c) mod 2^32

It matches the stored hash of all 67,320 entries, markers included. Proven · all 336 PAKs Five entries have no extension; the others carry one of 19 extensions: .txp 28,046, .thp 27,446, .shp 1,508, .bin 1,341, .qsa 1,142, .psp 765, .vsp 743, .scp, .mlp, .mmp and .mgp 657 each, .hkw 482, .ice 286, .dwa 76, .gfx 59, .acs 42, .mbp 3, .mdp 3 and .lfx 1. Proven · all 336 PAKs The executable looks entries up by hash (0x003a5ebc) and by name (0x003a59f4) and prefixes its PAK filesystem paths with PAK: or PAKh:. Observed

A name is not unique within a PAK: 25,365 names occur in two sections (a texture’s prefetch and streamed copies), and 3 occur twice inside one section. Observed The game’s level files use the same hash for their own names (spots and splines). Observed

SCRIPTS.SDAT is an NPD-wrapped file that the RPCS3 emulator decrypts without any key to a PAK of this format: 1,282 entries, four section markers and 1,278 compiled Lua 5.1 scripts, 252 of them in CSTR streams. Observed The scripts are not decompiled; their constants were parsed from every chunk. Observed

A strict Lua 5.1 reader (header, bounds, the opcode and operand checks of luac’s code verifier that need no symbolic execution, nesting depth, no bytes after the chunk) accepts every one of the 1,278 chunks (3,496,540 decoded bytes) and refuses none. Proven · all 1,278 script chunks

  • All 1,278 share one header, 1B 4C 75 61 51 00 01 04 04 04 08 00: format 0, little-endian, 4-byte int, size_t and instruction, 8-byte floating-point numbers. Proven · all 1,278 script chunks
  • The chunks are stripped: none of the 1,323 functions has a source name, line table, local-variable record or upvalue name. Proven · all 1,323 functions
  • 1,273 scripts are the main function alone. Five have nested functions, 45 in all. Proven · all 1,278 script chunks
  • 695 scripts are straight-line code in their main function; the other 583 have a nested function or one of the jump, comparison, test, loop or closure opcodes there. Proven · all 1,278 script chunks
  • Every function, nested ones included, ends in RETURN with B equal to 1 (1,323 of 1,323). Proven · all 1,323 functions
What does the offset of a section marker mean?

A marker has zero sizes and, in the entries inspected, an offset equal to the start of the entry after it. The loader’s use of that field is not traced.

Which names occur twice in one section?

Three names do so on the disc; whether the engine keeps the first or the last was not checked.