Bedrock Edition level format

From wiki.vg
Jump to navigation Jump to search

Overview

  • Chunk block and biome data in Bedrock Edition is stored in sub-chunks, grouped under one Chunk Column similar to Java Edition
  • Chunk data is only saved to disk by the server if it has changed since chunk generation
  • Block data is stored across 4-dimensions: x, y, z and storage layer. Currently, only two block layers are utilized by the vanilla game. Layer 0 stores normal terrain, and layer 1 stores liquid and snow data.
  • This is unlike Java Edition, where blocks typically have “waterlogged” or “snowy” block state properties.

Disk serialization

Minecraft Bedrock Edition stores world data in LevelDB databases. The Mojang LevelDB code can be found here, it is forked from Google’s repo with the addition of Zlib compressors, which are used in Minecraft. Depending on the version of the data, the database could be saved with either raw DEFLATE or GZIP encoding.

Key derivation

The keys inside the database are of variable length. Keys relating to locational chunk data, such as chunk column blocks, entities, block entities and biomes have their keys serialized under the following rules:

  • Write the X and Z coordinates as 32-bit signed little endian integers
  • If non-overworld data, write a LE i32 for the dimension (1 for Nether, 2 for End) else continue
  • Write a 8-bit integer (Key Type) specifying the type of data being stored (see below)
  • If writing data at a specific SubChunk, write the subchunk index as in i8 else continue

Example


Some other keys, those that to not correspond to 3D locational data, such as information about players or villagers may be stored in text-encoded keys. See the Minecraft Wiki for more information.

Key Type

Some known key tag types are below:

enum Tag {
  Data3D = 43, // 0x2b (+)
  VersionNew = 44, // 0x2c (,)
  Data2D = 45, // 0x2d (-), height map + biomes
  Data2DLegacy = 46, // 0x2e (.)
  SubChunkTerrain = 47, // 0x2f (/)
  LegacyTerrain = 48, // 0x30 (0)
  BlockEntity = 49,
  Entity = 50,
  PendingTicks = 51,
  BlockExtraData = 52,
  BiomeState = 53,
  FinalizedState = 54,
  BorderBlocks = 56, // Education Edition Feature
  HardCodedSpawnAreas = 57,
  Checksums = 59, // 0x3b (;)
  VersionOld = 118 // 0x76 (v)
}

SubChunk serialization

A SubChunk is a 16x16x16 subsection of a chunk column. Block and biome data is stored by SubChunks. As of 1.18, SubChunks range from Y=-64 to Y=320. A SubChunk’s payload is encoded as follows:

Infographic

Palette

If the subchunk is serialized for disk (Persistence) then the palette size is written as a LE i32, followed by that many NBT tags, which can look like:

  // Root compound tag, empty string name
  '': Compound({
    name: String('minecraft:bedrock'),
    states: Compound({
      infiniburn_bit: Byte(0)
    })
  })

If the subchunk is serialized over the network (Runtime) then the pelette size is a varint, followed by that many varints which are indexes to the global block palette.

Network serialization

Chunk Fetching Procedure

  • Client ➡️ Server – Send Client Cache Status packet to inform server if client supports caching
  • Server ➡️ Client – Send preliminary Level Chunk packets close to the player
  • Server ➡️ Client – Send Network Chunk Publisher Update packet to specify the origin point for the client to start requesting chunks from

The LevelChunk packet’s sent by the server can either:

  • Contain a full payload including that includes terrain, biome and height map data for the column, OR
  • Contain blob hashes with data which correlate to the above if client supports caching, OR
  • Have a SubChunkCount set to -1, if so:
    • Payload contains ONLY biome data, OR
    • Payload contains blob hashes which have biome data if the client supports caching

If the payload only contains biome data, the client will have to continually poll for the information from the server via Subchunk Request packets.

Caching

  • If blob hashes are sent by the server, then the client must look up the blob hash from its Blob Store and see if the relevant hash exists in the store. The client should inform the server of chunks it has (HIT) and does not have (MISS) in Client Cache Blob Status packet to the server.
  • If a hash is missing, the client must send a Chunk Cache Miss Packet and request the missing data, then cache it in the blob store. The server will respond with the Chunk Cache Miss Response packet.

Scenario 1 (pre-1.18 format)

If LevelChunk packet sent by server contains full chunk data ( SubChunkCount != -1)…

The Payload section contains the following concatenated data:

  • Sub-chunk buffers, amount based on LevelChunk’s SubChunkCount field.
  • Heightmap data, 512-byte height map data
  • Biome buffer data, 256-byte 2D biome data
  • Border blocks, Varint of length + that many sequential Border Blocks. Only used on Education Edition, length of 0 written otherwise.
  • Block entities, written as a sequential set of NBT tags, read until EOF

Scenario 2 (pre-1.18 format, with caching enabled)

If LevelChunk packet sent by server contains full chunk data (SubChunkCount != -1)…

The Payload section contains the following concatenated data:

  • Border blocks, Varint of length + that many sequential Border Blocks. Only used on Education Edition, length of 0 written otherwise.
  • Block entities, written as a sequential set of NBT tags, read until EOF

Scenario 3 (1.18 format+)

If LevelChunk packet sent by server doesn't contain full chunk data (SubChunkCount == -1)…

The Payload section contains the following concatenated data:

  • Border blocks, Varint of length + that many sequential Border Blocks. Only used on Education Edition, length of 0 written otherwise.
  • Block entities, written as a sequential set of NBT tags, read until EOF

After the client has received LevelChunk, it may send SubChunkRequest packets for terrain data in that chunk. The SubChunk response packet will contain height map data (if it exists for the chunk section) and a data section that contains block and biome data.