XNB containers
An XNB is the compiled form of one content asset in games built on XNA 4.0, MonoGame or FNA. The file names the readers that deserialize it and then holds one object (the primary object) written by the first of them. STUNTBOOST (a .NET 8 game on BytingGames’ fork of MonoGame 3.8.1, DesktopGL) ships all its content this way. Observed · STUNTBOOST
Header and reader table
Section titled “Header and reader table”Little-endian. After the 10-byte header come the type-reader table, the shared-resource count and the primary object.
| Offset | Size | Type | Field | Confidence | Notes |
|---|---|---|---|---|---|
| 0x0 | 3 | char[3] = XNB | magic | Proven | |
| 0x3 | 1 | u8 | target platform | Proven | d (DesktopGL) in 1,872 files; w (Windows) in one font |
| 0x4 | 1 | u8 = 5 | version | Proven | XNA 4.0; MonoGame writes the same |
| 0x5 | 1 | u8 | flags | Proven | 0x01 HiDef profile (STUNTBOOST's w font only); 0x80 LZX-compressed (15,108 of Terraria's files, none of STUNTBOOST's); 0x40 LZ4-compressed is documented by MonoGame and occurs in no file read |
| 0x6 | 4 | u32 | file size | Proven | the length of the whole file |
After the header:
| Part | Content | Confidence |
|---|---|---|
| reader count | 7-bit encoded integer | Proven · STUNTBOOST |
| per reader | a 7-bit length-prefixed UTF-8 type name (assembly-qualified, Microsoft.Xna.Framework.Content.StringReader, MonoGame.Framework) and an i32 reader version |
Proven · STUNTBOOST |
| shared resource count | 7-bit encoded integer | Proven · STUNTBOOST |
| primary object | a 7-bit type id (0 null, otherwise 1 + the index of its reader) and the bytes that reader wrote | Proven · STUNTBOOST |
A 7-bit encoded integer is the .NET BinaryWriter form: seven bits per byte, low group first, the high bit set while more
follow. A 7-bit length-prefixed string is that length then the UTF-8 bytes. Sourced · MonoGame content pipeline A compressed file
(flags 0x40 or 0x80) carries a decompressed size and a compressed body; none of the 1,873 files of STUNTBOOST’s Content is
compressed. Proven · STUNTBOOST
STUNTBOOST’s Content holds 1,873 .xnb files, 4,953,823,117 bytes. All have version 5 and a stated size equal to the file’s;
1,872 are for platform d and flags 0, one (Fonts/Tiny.xnb) for platform w with the HiDef flag. Proven · STUNTBOOST
Compression
Section titled “Compression”A file with flag 0x80 is compressed with LZX, the codec of Microsoft’s cabinet files, as XNA 4.0’s content pipeline
writes it. After the 10-byte header comes the decompressed size (u32) of what follows the header in the uncompressed
file, then blocks to the end of the file. A block is a big-endian u16 compressed size, standing for 32 KiB of output;
or a byte 0xFF, a big-endian u16 output size and the compressed size. Each block is one LZX frame of a 64 KiB window,
its bits starting afresh; a block of size 0 ends the stream. Sourced · MonoGame ContentManager Every one of Terraria’s
15,108 compressed files decodes by that rule to exactly the bytes XNA 4.0’s own decompressor (the XNA Framework’s
internal DecompressStream) makes of it, and to its stated size. Proven · Terraria Their LZX blocks are verbatim
(5,671) and aligned-offset (9,942) blocks, none uncompressed, and none of their frames uses x86 call translation.
Proven · Terraria
Terraria’s Content holds 15,994 .xnb files, all of platform w and version 5: 15,108 compressed, 886 not.
Proven · Terraria The LZX inside is the cabinet form libmspack reads: the tree lengths are sent as deltas through a
pretree, and its run code 19 repeats one length (the first one’s old length less the delta) over the run.
Sourced · libmspack (lzxd.c)
Readers
Section titled “Readers”A reader is a .NET type. The primary object’s bytes are whatever its reader wrote, so reading a file means knowing its reader.
| Reader (first reader of the file) | Files | Object | Confidence |
|---|---|---|---|
BytingPipeline.QoiReader |
576 | an image: an i32 byte count and a QOI file |
Proven · STUNTBOOST |
Microsoft.Xna.Framework.Content.Texture2DReader |
401 | a texture, see XNB textures | Proven · STUNTBOOST |
Microsoft.Xna.Framework.Content.ArrayReader<System.Byte> |
245 | i32 count and the bytes |
Proven · STUNTBOOST |
BytingPipeline.GLTFReader |
189 | a glTF 2.0 JSON document: a 7-bit length-prefixed UTF-8 string | Proven · STUNTBOOST |
SE.Pipeline.CollisionModelReader |
159 | a level part’s collision, see collision | Proven · STUNTBOOST |
Microsoft.Xna.Framework.Content.ReflectiveReader<SE.Pipeline.ShortcutContent> |
159 | a level part’s shortcuts | Proven · STUNTBOOST |
Microsoft.Xna.Framework.Content.StringReader |
94 | a 7-bit length-prefixed UTF-8 string | Proven · STUNTBOOST |
Microsoft.Xna.Framework.Content.SpriteFontReader |
25 | a sprite font | Proven · STUNTBOOST |
Microsoft.Xna.Framework.Content.EffectReader |
18 | a compiled effect, see MGFX | Proven · STUNTBOOST |
BytingPipeline.AnimationReader |
7 | an animation | Proven · STUNTBOOST |
The counts add up to 1,873. Proven · STUNTBOOST QoiReader, GLTFReader, AnimationReader,
SE.Pipeline.CollisionModelReader and ShortcutContent belong to the game’s own libraries (BytingPipeline, SE.Pipeline,
BytingGames’ MonoGame fork); their layouts are described where their data is used. Observed · STUNTBOOST
A glTF is split across three kinds of file: the document (GLTFReader), its buffer (<name>.bin.xnb, an ArrayReader<Byte>
with the glTF buffer’s bytes) and each image (QoiReader, or Texture2DReader for textures the game draws itself). Images
named .png in the glTF are the .xnb file of the same name. Observed · STUNTBOOST
Content folders
Section titled “Content folders”Content/Models/Export (751 files) and Content/Models/Resources (509) hold models, levels and their bakes; Content/Textures
holds backgrounds (185), achievements (142), UI (131), controls (53), buttons (14), world textures (13), playtesting (11) and HUD
(9) textures; Content/Effects/D3 has 10 effects and D2 8; Content/Fonts has sprite fonts, Content/Audio the sounds, and
Content/Loca.loca the localization. Observed · STUNTBOOST
The version numbers the type-reader table stores for the game’s own readers are as written by the fork’s pipeline; whether upstream MonoGame 3.8.1 reads these files unchanged is not established.