TO:R Data Map

ARC: the engine's named archive (bl::archive)

Source
docs/formats/arc.md
SHA-256
a16150f3…52676d08

The Blade engine's archive: a header, an offset table, a list of named, typed records, and the data blocks they point to. It holds the menu layouts and their textures (menu/), the text presets and the font set, every menu texture pack, the shader package (Shaders/Shader.dat) and the one world-map model (worldmap/Worldmap.dat#28, behind a BMAR104 prefix). An ARC sits whole in a pakd entry or a ZIP member (containers.md), and a data block can hold another ARC, nested up to four deep. Textures inside are btx (another doc); layouts, presets and models are only named here (Leads).

Based on Every ARC in the game's Data/: a C# scan of all 10,016 files that unwrap as RotXor + ZIP found 220 top-level ARCs (a payload or a pakd entry starting ARC\0, or BMAR104\0 + ARC\0) and 254 more nested inside them, 474 in all, with 5,959 records. They are all in Shaders/Shader.dat (SHA-256 65f799f68dd1ed7392854bbf352bde8aa8f60a3ae179596b54c513c834ef9a77, 27,572 bytes), the 81 .dat files under menu/ that hold ARCs (among them menu/menu_layout.dat, SHA-256 c4ea277d468d02adbc7e74d866645f79f5fbfa11161d99bb2219d4437f77ce3c; menu/menu_parts.dat, b403e5d7eb07c486c5c69aeaad895af6df875cb5b4f1cfb214f50c046aa8f1e2; menu/fontset/fontset.dat, ca3e8380762155ebafad3093ce7923a5b5888c120e57c7b8027fbb0dc35c715f) and worldmap/Worldmap.dat (3c3c2577a0c0c79259117336594254dd0771da252678e2310507733f3496a698). No file pages yet. The unpacked executable, SHA-256 7b0230a11498f40396c9048345e7cfe0ef442cb7ca8faffc6f197920d2669599. Gibbed's ArcFile.cs and ArcDataHeader.cs (reference_tools/Gibbed.LetUsClingTogether/projects/Gibbed.Reborn.FileFormats/, read-only, no writer) and Gibbed.Reborn.UnpackPAC/Program.cs, checked 2026-10-11.
Checked 2026-10-11
Method Single-file C# exploration programs in the session scratchpad, over the game files unwrapped with the toolchain's Containers project: arcscan.cs tallies every header, record and block field of every ARC, nested ones included; arcrebuild.cs parses each ARC into a tree and writes it back from the parsed fields with the layout rules, comparing byte for byte; shaderscan.cs decodes the shader package; arclist.cs lists records per file. Static analysis of the executable with Ghidra 12.1.4 through the decompiled code in local/exe/decomp/, and a C# reader for its data (va.cs). No in-game tests.

Where it appears

Files Archive name (header) Record tags Nested
Shaders/Shader.dat (ZIP member sh_tacos.pac, not a pakd) sh_tacos.pac 21 × bin each bin is an ARC <shader>.pac of 2 × bin, each an ARC BlShaderArchive of 1 × SHG, each an ARC BlShaderGroup: see The shader package
menu/menu_layout.dat (69 entries), menu/menu_parts.dat (70 entries) CrowleyArchiveDatas 1 × lyt, then 0–69 × tex —
menu/fontset/fontset.dat (1 entry) CrowleyArchiveDatas 1 × lpj named fontset —
menu/text/textPreset_ea.dat, textPreset_asia.dat (1 entry each) ea_text_preset.pac, asia_text_preset.pac 75 / 74 × bin named font_*.lpja each bin is an ARC CrowleyArchiveDatas of 1 × lpj
menu/texture_x4/*.dat and its 8 <lang>/ folders (1 entry each) <stem>.pac, e.g. com_icon.pac, common_x4.pac tex only (0 to 439); tex_common_x4.dat's ARC is empty —
worldmap/Worldmap.dat#28 BladeModelPac, after the 8 bytes BMAR104\0 BML, BMD, BMA, BMT, all named worldModel00 — (contents are chunk chains, BMAR)

confirmed: these are the only ARCs in the 10,016 unwrapped files, and no other blob has the 6-byte signature ARC\0 00 01 anywhere inside it except Worldmap.dat#28 at +8. Source: arcrebuild.cs over Data/, all files.

Offsets are from the start of the ARC.

Offset Size Type Name Meaning Confidence Source
0x00 4 raw[4] magic ARC\0. Every reader checks it. confirmed C# scan, all 474 ARCs (fields tallied by arcscan.cs for the 473 in Shaders/ and menu/, and the BMAR one by its byte-identical rebuild); checked in 0x14005bfa0, 0x14005c0c0 and every inlined walk.
0x04 2 u16 version 0x0100 (bytes 00 01). Every reader checks it and ignores an ARC with any other value. confirmed C# scan, all 474; 0x14005c0c0; Gibbed ArcFile (rejects other versions).
0x06 2 u16 record_count Number of records. Equals offset_count in every ARC. confirmed C# scan, all 474; 0x14005bfa0 loops this many times.
0x08 2 u16 offset_count Number of data blocks (entries of the offset table). The records start at align32(0x30 + 4 × offset_count), which the game computes as (4 × offset_count + 0x4F) & ~0x1F. confirmed C# scan, all 474; 0x14005bfa0.
0x0A 2 u16 unk_0x0A 0 in every ARC. Not read. confirmed C# scan, all 474; no reader reads it.
0x0C 4 u32 unk_0x0C 0 in every ARC. Not read. confirmed C# scan, all 474; no reader reads it.
0x10 32 raw[32] archive_name The archive's name, NUL-terminated and zero-padded (sh_tacos.pac, CrowleyArchiveDatas, BlShaderGroup, …). Not read by the game. confirmed C# scan, all 474 (NUL inside the 32 bytes, zeros after it); no reader reads it.
0x30 4 × offset_count u32[offset_count] offsets Start of each data block, from the start of the ARC. confirmed C# scan, all 474; 0x14005bfa0 (ARC + offsets[data_index]).
next to align32 raw[n] padding Zeros up to the first record. confirmed C# scan, all 474.

Byte-swapped ARCs (Gibbed reads CRA\0 as big-endian) don't occur, and this executable's walkers have no byte-swap path for them. Source: C# scan; 0x14005bfa0.

Records

One per data block, back to back from align32(0x30 + 4 × offset_count). Each is align32(0x14 + filename_length) bytes, and the game steps to the next one as (filename_length + 0x33) & ~0x1F. The game's own word for a record's name is "filename" (classes Traverser_filename, Traverser_type_filename). Offsets are from the start of the record.

Offset Size Type Name Meaning Confidence Source
0x00 4 raw[4] type The record's kind, as 3 or 4 ASCII bytes, NUL-padded: see Record types. Every lookup matches it. confirmed C# scan, all 5,959 records; every traverser in How the game reads it.
0x04 2 u16 id_u16 The record's ID when uses_id_u32 is 0. 0 in every record (all use id_u32). confirmed C# scan, all records; 0x14005bc00, 0x14005bfa0.
0x06 2 u16 offset_index Index into offsets of the record's data block. Equals the record's own index in every record. confirmed C# scan, all records; 0x14005bfa0 (ARC[0x30 + 4 × offset_index]).
0x08 4 u32 filename_hash Hash of filename, as in Filename hash. Correct in every record. Compared only by name lookups that ask for an exact match (the font set's). confirmed C# scan, all records; 0x14005bc30, 0x14008b740.
0x0C 1 u8 unk_0x0C 0 in every record. Every lookup matches it against a value the caller passes, always 0 in the calls read so far: a sub-kind or group. Gibbed rejects non-zero. likely C# scan, all records; 0x14005bc00, 0x14005bc30, 0x14005bed0, 0x14005bef0.
0x0D 1 bool8 uses_id_u32 1 in every record: the ID is id_u32. With 0 the game would take id_u16. confirmed C# scan, all records; 0x14005bc00, 0x14005bfa0.
0x0E 1 u8 filename_length Length of filename with its NUL. Sets the record's size, so it must be right. confirmed C# scan, all records (strlen + 1); 0x14005bfa0 and every walk.
0x0F 1 u8 unk_0x0F 0 in every record. Not read. Gibbed rejects non-zero. confirmed C# scan, all records.
0x10 4 u32 id_u32 The record's ID, matched by ID lookups. The record's index within its archive in most; 0 for every tex record of a layout archive (CrowleyArchiveDatas) and the 4 BladeModelPac records; for SHP records, the index among the SHPs (the SARC is ID 0). confirmed C# scan, all records; 0x14005bc00.
0x14 filename_length raw[filename_length] filename ASCII, NUL-terminated. Some carry an extension (font_battle_name_s.lpja); SARC and SHP records have an empty one. confirmed C# scan, all records; the name lookups 0x14005bc30 (Traverser_filename) and 0x14005bd70 (Traverser_type_filename) match on it.
next to align32 raw[n] padding Zeros to the record's end. confirmed C# scan, all records.

Filename hash

h = 0; for each byte c of the filename: h = h × 33 + c (32-bit); hash = h + (h >> 5). Source: 0x14008b740 (hashes fontset), 0x1400bc530, 0x1400640b0, 0x140073d70; confirmed against every record's filename_hash (C# scan).

Data blocks

Each offsets entry points to a block: an 8-byte header, zeros, then the content. Offsets are from the start of the block.

Offset Size Type Name Meaning Confidence Source
0x0 4 u32 size Size of the content. The game passes it on as the content's length. For a nested ARC it includes that ARC's trailing padding. confirmed C# scan; 0x14005bfa0 (result's size).
0x4 2 u16 alignment 16, 32 or 128. The content starts at align(8, alignment) from the block, which for these values is alignment itself (Gibbed reads the field as that offset). The block itself starts at a multiple of it from the ARC's start. confirmed C# scan, all 5,959 blocks (16: the 4 in BladeModelPac; 32: bin and tex in *.pac archives; 128: the rest, tex in layout archives included); 0x14005bfa0, 0x140037f40-style (a − 1 + 8) & −a.
0x6 1 u8 unk_0x06 0 in every block. Read into the lookup result (offset 0x1C) and handed to the caller; no use seen. Gibbed rejects non-zero. likely C# scan, all blocks; 0x14005bfa0.
0x7 1 u8 unk_0x07 0 in every block. Not read. confirmed C# scan, all blocks.
0x8 to alignment raw[n] padding Zeros. confirmed C# scan, all blocks.
alignment size raw[size] content The record's data, read in place: see Record types. confirmed C# scan; 0x14005bfa0.

Layout rules

arcrebuild.cs writes each ARC from its parsed fields with these rules, nested ARCs first, and the result is confirmed byte-identical for all 220 top-level ARCs (474 in all, every nested one included), with the zero padding as described:

  1. Header (0x30 bytes), offsets, zeros to a multiple of 32.
  2. The records in order, each padded to a multiple of 32, with filename_hash and filename_length computed from the name.
  3. The data blocks in offsets order (the same as record order). Each starts at the end of the previous content (for the first, the end of the records) rounded up to the block's alignment, measured from the ARC's start.
  4. The ARC ends at the last content's end rounded up to the largest alignment among its blocks (32 when it has none: the empty common_x4.pac is 0x40 bytes). A nested ARC's block size is this padded length.
  5. Outside: a pakd entry holding an ARC adds its usual 16 zero bytes, and the BMAR104\0 prefix 8 (containers.md).

likely: the game needs only rules 1–3's offsets to be right, not the padding: it reads offsets, filename_length and each block's alignment, never an ARC's length. Alignment above 16 is relative to the ARC's start, and a pakd entry is only 16-aligned (menu_layout.dat's first entry is at 0x130), so nothing in memory relies on more. Source: How the game reads it.

Record types

Tag In Content Read by Confidence
bin sh_tacos.pac, <shader>.pac, the text-preset archives A nested ARC (all 212). Shader package: 0x1400b1240, 0x1400b13b0, 0x1400b14c0 (only bin records). Text presets: 0x14008b680. confirmed (content); likely (reader)
SHG BlShaderArchive A nested ARC BlShaderGroup. 0x1400b0b80 (counts and walks SHG records by type index). confirmed (content); likely (reader)
SARC BlShaderGroup (record 0) The shader group's description, 0x10C bytes (below). 0x140072f40, 0x1400730e0 (find SARC ID 0). confirmed (content); likely (reader)
SAEX BlShaderGroup Not in the game's files; optional, looked up after SARC. 0x1400730e0. likely
SHP BlShaderGroup One compiled shader variant: a key, a size and a DXBC blob (below). 0x140073380 (every SHP). confirmed (content); likely (reader)
lyt layout archives (CrowleyArchiveDatas in menu_layout.dat, menu_parts.dat), always record 0 A bl::lyt layout: starts 01 03 0D 00 (a version the game compares to 0x140caa70c), the layout from +0x10. 0x1400bc530 (by index or by name), 0x14008ad70, 0x1402725d0. confirmed (bytes); likely (reader)
tex layout archives and texture packs A btx texture (all 5,313). 0x1400640b0 (by tex + name, extension ignored). confirmed (content); likely (reader)
lpj fontset.dat's archive (fontset), and each text preset's inner archive Font set: starts 01 00 00 00 (compared to 0x140caa71c), data from +0x10, font names per language. Text presets: a binary preset. 0x14008b740 (font set, by name fontset); 0x14008bba0 (presets). confirmed (bytes); likely (reader)
BML, BMD, BMA, BMT BladeModelPac Chunk chains starting BML, mad, ANHD, BMT (BMAR). Model code, not traced. BMT (and pac) records are also searched for textures by 0x1400642a0. confirmed (bytes); guess (meaning)
MDL (none in the game's files) A model. 0x140038570 checks for one. likely

cmp\0 content (compressed, below) never occurs. Source for every "content" claim: arcrebuild.cs, all files.

How the game reads it

Static analysis only, so every fact is at most likely; functions are in the names list.

The menu files

So the names are what binds things: a modder can add, remove or reorder tex records and resize their btx content freely, as long as the names the layout uses still resolve, and must keep menu_layout.dat's first 19 entries in order.

Compressed content

The shader package

Shaders/Shader.dat is RotXor + ZIP like the other .dat files, but it is not in FileTable.bin (confirmed: its path isn't in the file) and the game reads it by path.

Every shader has two <shader>.pac records: ID 0 holds the pixel-shader group (SARC kind 2) and ID 1 the vertex-shader group (kind 0). confirmed for all 21. Source: shaderscan.cs.

SARC

The 0x10C-byte content of a SARC record.

Offset Size Type Name Meaning Confidence Source
0x000 256 raw[256] name The shader's name (bg, unit_outline_2d, …), NUL-terminated, zero-padded. The group is registered under it. Equals the enclosing <shader>.pac record's name in all 42. confirmed (values); likely (use) shaderscan.cs, all 42; 0x140072f40, 0x140073ec0.
0x100 4 u32 variant_count Number of SHP records in the group: 1, 2 or 8. confirmed shaderscan.cs, all 42 (equals the SHP count); 0x1400730e0.
0x104 4 u32 variant_mask 0, 0x1, 0x100 or 0x800101: the OR of the group's SHP variant_keys. Copied into the group (+0x2C). confirmed (values); guess (meaning) shaderscan.cs, all 42; 0x1400730e0.
0x108 4 u32 kind Shader stage: 0 vertex, 2 pixel (1 is probably geometry; unused). Its low byte picks the shader-database slot. confirmed (values match the DXBC types); likely (use) shaderscan.cs; 0x140072f40 (byte at +0x108).

SHP

Offset Size Type Name Meaning Confidence Source
0x0 4 u32 variant_key Which variant this is: 0, 1, 0x100, 0x101, 0x800000, 0x800001, 0x800100, 0x800101 (the last four only in model). confirmed (values); likely (use) shaderscan.cs, all 57; 0x140073380 (FUN_1400504a0(group, key, …)).
0x4 4 u32 dxbc_size Size of dxbc. The block's size is dxbc_size + 8 and the DXBC's own total-size field equals it in all 57. confirmed shaderscan.cs, all 57.
0x8 dxbc_size raw[dxbc_size] dxbc A compiled Direct3D 11 shader (DXBC container, shader model 5.0, SHEX chunk): pixel shaders in kind 2 groups, vertex shaders in kind 0. Read as a CompressibleData (could be cmp). confirmed (format); likely (use) shaderscan.cs (container header and SHEX version token); 0x140073380.

guess: a replaced shader must be a valid DXBC blob from Microsoft's compiler (fxc or D3DCompile, target vs_5_0 / ps_5_0), with its constant buffers and input layout compatible with what the game binds; a hand-edited blob would need its DXBC checksum recomputed (vkd3d's DXBC parser rejects a bad one unless told to ignore it: vkd3d MR 582, checked 2026-10-11). Whether Direct3D 11 itself rejects a bad checksum is untested.

BMAR models

worldmap/Worldmap.dat#28 is BMAR + 104\0 + an ARC BladeModelPac with four records, all named worldModel00: BML, BMD, BMA, BMT, in 16-aligned blocks. Their contents are chains of chunks: a u32 tag, a u32 size, a byte, a flags byte (bit 0: byte-swapped), a u16 alignment, the content at the next multiple of the alignment, and the next chunk at the content's end rounded up to 4; a chunk with tag 0 and size 0 ends the chain (NODE, DATA, … inside BML). Pointer fixups are applied from a POF0 chunk. likely, from 0x140037f40 (next chunk), 0x14005ba90 (POF0 fixups) and 0x140038570 (the model check: version 104\0, then either MDL\0 or BMAR with an ARC holding an MDL record). confirmed: the ARC part rebuilds byte for byte with the layout rules. The model formats are Leads.

Rebuilding

Rebuild an ARC from its records and contents with the layout rules; unchanged data comes back byte for byte (confirmed, 220/220). For an edited ARC (a changed layout, an added or resized texture) the game needs, likely:

It need not be byte-identical: the padding, archive_name, unk_0x0A and unk_0x0C aren't read. A changed ARC changes its pakd entry and so its .dat's size, which needs the FileTable.bin entry updated (filetable.md), except Shaders/Shader.dat, which is read by path.

Leads