Formats
Byte-level specs for everything on the disc, each with provenance back to a Ghidra-traced function dump. Every format here has a clean-room Rust parser somewhere in the workspace.
Confidence levels
Each format below carries a badge for how solid its decode is:
- Confirmed - verified end-to-end against real on-disc data, with passing tests.
- Inferred - deduced empirically from byte patterns; structurally consistent but not yet exhaustively validated.
Disc + container layer
What the disc image looks like before any in-game format gets involved.
PSX disc geometry Confirmed
Mode2/2352 sectors, 24-byte ECC overhead, ISO9660 path resolution. The
iso crate's RawDisc::read_sector hides the sector layer and returns clean 2048-byte user data.PROT.DAT TOC Confirmed
The project archive. 1234 entries indexed by a 16-byte TOC.
start_lba = toc[p+2], size = toc[p+5] - toc[p+3] + 4. Walked at boot by FUN_8003E4E8.CDNAME.TXT name map Confirmed
#define name N markers tag block starts; names inherit forward to subsequent entries. The define numbers are raw in-RAM TOC indices - extraction filename labels are shifted +2 (the historical vab_01 / move_program_no “mislabels” were this shift). Verify against the loader-call constant or magic bytes.DMY.DAT (dev fixtures) Confirmed
Memory-bus test pattern + paired random blobs. Not real game data.
Compression + dispatch
Legaia LZS Confirmed
Custom LZSS decoder reverse-engineered from
FUN_8001A55C. 4096-byte ring buffer, zero-init. "Decompresses without error" is not a validity signal - always magic-check the decoded output.Asset type dispatcher Confirmed
FUN_8001F05C dispatches by 8-bit type byte: 0=TIM, 2=TMD, 4=MES, 6=ANM, 7=VDF, 8=SIN, 9=TMD2, B=MOVE2. LZS-vs-raw decided per asset.Asset descriptor format Confirmed
The
(type_byte << 24) | size calling convention used by FUN_8001F05C and the descriptor-pair walker.Pack format Confirmed
Used inside DATA_FIELD streaming chunks. Header
u32 count + u32 word_offsets[count].Standalone TIM-pack Confirmed
Used by some standalone PROT entries. Header
(magic_lo, magic_hi, count<16, marker=0x01) + offsets; byte_offset = word_index*4 + 4.Field-pack format Confirmed
Magic
0x01059B84. 4 PROT entries share a byte-identical 97-entry static schema. Consumer is FUN_801D6704 (overlay 0897); slots are read at hard-coded offsets.Player battle files Confirmed
The per-character player battle files
data\battle\PLAYER1..4 (retail battle_data, extraction 0863..0866): header + LZS palette chain + 12-byte descriptor table + per-slot LZS streams that decompress to [32-byte header + Legaia TMD + texture pool]. The old “16 MB container at 0865” was an over-read window into the monster archive (0867).Row-479 NPC CLUTs Confirmed
Plain PSX TIMs in scene PROT entries with CLUT block at
(fb_x=0, fb_y=479, w=256, h=1). Engine uploads them via the targeted-upload CLUT pass with merge-zeros semantics so multiple scene-pack TIMs targeting the same row coexist (full slots 0..14 + partial slots 0..7).Per-asset formats
PSX TIM Confirmed
Standard PlayStation texture format. 4 / 8 / 15 bpp; CLUTs scatter across PROT entries.
crates/tim exports to PNG.Legaia TMD Confirmed
Custom PSX TMD variant - magic
0x80000002. Object pointers are byte offsets relative to header end. Primitives use a custom 8-byte group header + per-mode descriptor table at DAT_8007326C.VAB sound bank Confirmed
PSX-standard VAB (program/tone/SPU-ADPCM sample).
crates/vab extracts and decodes to WAV. Banks live across the sound blocks; the retail vab_01 block (extraction 1070..1192) is wall-to-wall VAB - the old “vab_01 is misleading” was the +2 filename shift.PsyQ SEQ Confirmed
PsyQ's MIDI-derived sequence format (
pQES magic). 13-byte header (PPQN, tempo, time-sig) + delta-time / MIDI events with running status. Drives SsSeqOpen / SsSeqPlay. crates/seq parses + walks.XA-ADPCM Confirmed
CD-XA Mode 2 Form 2 audio.
crates/xa demuxes per (file_no, ch_no) channel and emits one WAV per stream.MES dialog Confirmed
Two variants: Compact (
0x404 magic) and Records (0x44 0x78). Bytecode tokens (Glyph / Op65 / Op4c / Op26 / End). Renderer is overlay-resident.Dialog font Confirmed
Proportional Latin font (
FUN_80036888). 256-byte width table at 0x80073F1C; 38-entry escape table at 0x80074050; glyph bitmaps in VRAM at (896, 0), 4bpp, 16x16 cells (drawn 14x15).ANM animation Confirmed
Asset-type 6 container.
(count + byte_offsets + records); marker_1 = 0x080C across all observed records. Keyframe pose decoder ported in legaia_anm::AnimPlayer.Monster animation Confirmed
Enemy battle animation inside the monster archive (PROT 867). Per-action transform-keyframe stream at entry
+0x8c: [u8 parts][u8 frames] + nine-byte TRS records (one part per TMD object). Action 0 is the idle loop; decoder FUN_8004998c.MDT - move tables Confirmed
Tactical Arts move records. Both layouts parse cleanly; the consumer is
FUN_800204F8. The runtime MOVE base is sourced per-scene from a CDNAME slot, not from a single boot-time PROT entry.Move-power table Confirmed
Battle-action per-move power + behaviour records (26-byte stride, VA
0x801F4F5C, PROT 0898). Damage roll, homing, hit reaction, sound cue and spawned-effect lists; resolved via the id→index map at 0x801F4E63 (the same id space as the spell table).Art data - Tactical Arts records Confirmed
Per-character art records (Vahn / Noa / Gala; PROT entry
0x05C4). 40-field schema: command sequence, action constant, power bytes, hit timing, special / hit effect cues, status effects, repeat-frame replay.Per-character save record Confirmed
Runtime
0x414-byte record at 0x80084708 + slot * 0x414. Cheat-database-pinned offset table for stats, level, magic rank, spells, summons, equipment.Streaming + scene containers
DATA_FIELD streaming Confirmed
Chunked container parsed by
crates/asset::parse_streaming. Sister detector data_field_truncated catches the shape where the final chunk's declared size walks past EOF.Scene bundles Confirmed
Five sister detectors covering ~50% of PROT entries:
scene_tmd_stream, scene_vab_stream, scene_asset_table, scene_scripted_asset_table, scene_event_scripts, plus tmd_size_prefix.scene_v12_table Confirmed
Per-scene container: runtime-fixup header + inline record table + event-script prescript at sector offset
0x800. 97 PROT entries (one per scene); strict header algebra N = 4*param + 22; field VM (FUN_801DE840) walks the prescript.World-map slot-4 records Inferred
Slot 4 of each kingdom bundle (PROT 0085 / 0244 / 0391, type byte
0x05). Outer pack of 15 sub-bodies; per-body header [u8 count_a, u8 flag_a, u8 count_b, u8 flag_b, u16 0x080C, u16 kind] + count_a*count_b 8-byte records. Container byte-verified vs live RAM; record interpretation open (wireframe / coastline hypothesis falsified). Most likely a runtime library of small object-local 3D meshes. Not the bulk continent terrain source.Effect bundles Confirmed
Magic
0x02018B0C (efect.dat). 2-pack wrapper: 14 sprite-anim entries + 33 effect scripts indexed by effect ID.Per-scene primitive scratch buffer Inferred
Negative-finding entry. The 1700-byte cluster at
0x80108EA4..0x80109550 that earlier readings called "navmesh" is actually a per-scene scratch buffer the renderer fills with assembled GPU primitive data on scene entry. No RAM cell anywhere holds a pointer into the window.Encounter record Confirmed
On-disc encounter record installed at
actor[+0x94] by the script-VM and read by FUN_801DA51C. Layout: [3 reserved][count: u8][monster_ids: u8[count]]. Reader copies the ids into the global formation cell at 0x8007BD0C.MAN relocation Confirmed
Variable-length editing of a decompressed MAN. Scene-transition (
0x3F door) destinations are partition-2 records reached via the partition-2 record-offset table (runtime-pinned); resizing a destination name fixes the partition tables, section-0 offset, intra-record jump deltas, and the external descriptor size. Powers the door randomizer.STR FMV table Confirmed
In-RAM compact table the cutscene / MDEC overlay uses to look up MV*.STR files. Six 24-byte entries at
0x801CAE40: filename + libcd BCD MSF + size. Pinned via mc1 capture during FMV playback.Runtime overlay carriers
MIPS overlay code Inferred
Some PROT entries carry MIPS code that loads into the overlay window at
0x801C0000+. The detector finds them by SP-prologue density.Overlay pointer-table code Inferred
Sister format to MIPS overlay. Header is a pointer table; the rest is overlay code referenced by those pointers. 42 PROT entries.
Auxiliary
SFX descriptor table Confirmed
Static
DAT_8006F198 sound-effect table (8-byte stride, 100 entries). Per cue: VAB program/tone, voice count, mixer channel. Byte-exact vs live save-state RAM.Sound-driver path strings Confirmed
3 SCUS consumers: sound init / streaming-asset loader / mode-aware ext dispatcher. 8 extensions: .MAP, .PCH, .spk, .dpk, etc.
Pochi-filler placeholder slots Confirmed
265 PROT entries are dev-fill placeholders ("pochipochi..." byte pattern). Reserved-but-unused scene asset slots.