Chunk Format
This page gives an overview of the SMP map format used in the protocol.
Contents
Packets
Two packets use this format:
- 0x21 chunk data - single column - used when player movement requires new chunks to be loaded. Also used to unload chunks.
- 0x26 map chunk bulk - multiple columns - used when first spawning into a world and when player is teleported.
Concepts
Storage
- Chunk Data: an array, either 2048 or 4096 bytes
- Chunk: a 16x16x16 area, logically made up of multiple Chunk Data arrays, storing things like block ids and skylight
- Chunk Column: 16 chunks aligned vertically (totalling 16x256x16). Chunks can be uninitialised (e.g. set to
null
) - World: a collection of chunk columns
Bitmasks
You will sometimes get a blob of data and a bitmask. Each bit in the 16-bit short represents a chunk. The least significant bit represents the chunk from Y=0 to Y=15, and so forth. If it's 0
, the chunk is entirely air and there's no data to read.
You need a loop like this:
chunks = array[16]; for (i=0; i<16; i++) { if (bitmask & (1 << i)) { // read a chunk data array } }
Format
Chunk Column Metadata
The packet contains important metadata which you'll need to pull out. For bulk packets, you'll need to loop over the metadata area. Specifically:
- Chunk X
- Chunk Z
- Section Bitmask
- Continuous? (only in 0x21 - assumed true in 0x26)
- Skylight? (only in 0x26 - only if overworld in 0x21)
Data
- See also: Pre-release protocol#Chunk Section for the new format in 1.9
In 0x21 the data describes of a single chunk column in the format below. In 0x26, the format below is repeated for each chunk column.
In half-byte arrays, two values are packed into each byte. Even-indexed items are packed into the high bits, odd-indexed into the low bits.
Chunks are sent bottom-to-top, i.e. the first chunk, if sent, extends from Y=0 to Y=15. Blocks are ordered Y, Z, X, i.e. the 'X' coordinate changes fastest.
Section | Misc | Contains |
---|---|---|
Array of Blocktypes and metadata | Encoded with block[y][z][x] = block_id << 4, | meta_data & 15 | Block ID and metadata |
Decoded with blockid = block[y][z][x] >> 4; metadata = block[y][z][x] & 15 | ||
Varint of bits of light data per block | (8 for both arrays, 4 for just block light, see below) | |
Varint of both array's total elements | Blocks represented (16*16*16) * number of light arrays (1 or 2) | |
Array of block light data | Each element is 1/2 byte , corresponds to block type and data position | 1 - 15 light level |
Array of skylight data (optional depending) | Each element is 1/2 byte, corresponds to block type and data position | 1 - 15 light level from sun |
Biome ID array, each element a byte (Sent with packet 0x26) | Corresponds to each z,x value, 256 elements. (Which column data is this sent in? After all of them?) | Biome ID |
The 'biome' array is always 256 bytes when sent. Values above 22 will cause the client to crash.