At a glance

Magic
none - a bare u32 count opens the pack; identity comes from the enclosing chunk's type byte (0x01 TIM_LIST or 0x02 TMD)
Where on disc
inside DATA_FIELD chunks in scene and effect entries of PROT.DAT
Parser
legaia_container_formats::pack
Confidence
Confirmed - the type-0x02 arm of the dispatcher FUN_8001F05C walks it and calls FUN_80026B4C per member
Used by
asset loader, asset viewer

Overview

Inside a streaming chunk the bytes say nothing about what they are - the chunk header already said "a list of TIMs" or "a pack of meshes". So the pack itself is minimal: how many members, where each starts, then the members. Offsets count 4-byte words from the start of the pack data, and there is no per-pack magic.

Layout

+0x00countu32
+0x04word_offset[count]u32 × count
word_offset[0] × 4members, back to backto chunk end

Each word_offset counts 4-byte words from the start of this pack's data (not from the end of the table), and members sit on the 4-byte word grid with no other padding rule.

Sub-asset i lives at byte range [word_offset[i] * 4 .. word_offset[i+1] * 4), with the last sub-asset ending at the chunk's end.

Example

A TIM_LIST chunk header followed by a 2-TIM pack (a TIM is the PlayStation's standard texture format):

6c 02 01 01chunk header: type 0x01 TIM_LIST, size 0x01026Cu32
02 00 00 00count = 2u32
03 00 00 00offset[0] = 3 → byte 12u32
8b 20 00 00offset[1] = 0x208B → byte 0x822Cu32
pack +12TIM 0, then TIM 1…

Word offset 3 is byte 12 - exactly the size of the count word plus the two-entry table, so the first member starts right after the header.

One format, two readers

A hex dump of a scene's texture entry looks like a second pack format: a marker byte 0x01 at +3, a count at +4, and member offsets that need an extra +4. It is not a second format. Those first four bytes are a DATA_FIELD chunk header, (TIM_LIST << 24) | payload_len, and what follows is an ordinary pack. The older prot::timpack reader simply reads the pack with the header still attached, which is where both its marker test and its +4 come from. The "field-pack" word 0x01059B84 is the same chunk header on town01's texture pack.

A streaming chunk holding a pack: a 4-byte chunk header, then the pack's count word, its word-offset table and its members. One reader starts at the pack, the other starts four bytes earlier at the chunk header, and both land on the same member bytes. one streaming chunk chunk header type << 24 | size count u32 word_offset[ ] u32 x count member 0 member 1 ... member i starts word_offset[i] x 4 bytes after the count word container-formats::pack - starts at the count word; member i at offset[i] x 4 prot::timpack - starts at the chunk header; member i at offset[i] x 4 + 4
One layout, two starting points. The extra +4 in the older reader is the chunk header it did not step over; the "marker byte" it tests is that header's type.
Offset in the entryRead as a chunk + packRead by prot::timpack
+0x00chunk header; its high byte 0x01 is the TIM_LIST type"magic" bytes; byte[3] == 0x01 is the marker test
+0x04pack counttim_num
+0x08pack word_offset[0] …word_index[0] …
member i4 + word_offset[i] × 4word_index[i] × 4 + 4 - the same byte

Use legaia_container_formats::pack on a pack that starts at offset 0 (a chunk payload), and prot::timpack - or skip the 4-byte header first - on a whole chunk. legaia_scene_formats::field_pack::scene_pack locates the chunk-headered scene pack inside a CDNAME block. The former effect bundle (0x02018B0C) is not a different layout: it is this pack behind a type-0x02 chunk header, carrying 29 TMDs.

How we know

The chunk dispatcher's type-0x02 arm walks the count and word-offset table and hands each member to the TMD handler, which consumes it at word_offset[i] × 4 with no added constant.

Provenance: the two routines
FunctionAddressWhat it provesDump
Chunk dispatcherFUN_8001F05C (type-0x02 arm)Walks the count + word-offset table and hands each member to the TMD handlerfuncs/8001f05c.txt
Per-member handlerFUN_80026B4CConsumes one member at word_offset[i] * 4, no +4 constantfuncs/80026b4c.txt

Source of record: docs/formats/pack.md.

See also