💾 Archived View for thingvellir.net › protocol-a112.gmi captured on 2024-05-12 at 15:14:06. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-11-14)

-=-=-=-=-=-=-

Alpha 1.1.2 Protocol

Minecraft is an unimaginably bad mess. If you want to make a network protocol for your game, please take this as a lesson on what *not* to do. If you want to make an old-school Minecraft client or server, consider targeting the Classic protocol instead.

Classic Protocol

NOTE: This information was reverse-engineered from a decompiled Mojang client and server. This document contains no original Mojang program code.

Types

All integers and floats are big-endian. All integers are signed. Text is encoded in a variant of UTF-8, length prefixed with a signed big-endian 16-bit integer.

Java InputStream 'modified UTF-8'

Login Sequence

Packet Structure

00 Empty

This packet serves no purpose. The Mojang client and server send this to eachother once per second.

struct {
    pid: i8 = 0x00,
}

01 Client Info

The client sends this packet to the server after recieving 02 Handshake Response.

struct {
    pid: i8 = 0x01,
    version: i32 = 0x02,
    nick_len: i16,
    nick: []i8,
    key_len: i16,
    key: []i8,
}

01 Server Info

The server sends this packet to the client after recieving 01 Client Info.

struct {
    pid: i8 = 0x01,
    player_id: i32,
    unused_1: i16 = 0x00,
    unused_2: i16 = 0x00,
}

02 Handshake Start

The client sends this to the server immediately upon connection. The Mojang server uses this to verify an account's premium status and and immediately sends FF Disconnect if it cannot verify the username.

struct {
    pid: i8 = 0x02,
    name_len: i16,
    name: []i8,
}

02 Handshake Response

The server sends this to the client in response to 02 Handshake Start.

The Mojang server sets 'key' to a random hex string or to `-` to indicate the server is not verifying usernames.

struct {
    pid: i8 = 0x02,
    key_len: i16,
    key: []i8,
}

03 Message

The client sends a user-input string to the server. The server can send this to any client to add a line of arbitrary text to that client's chat history box.

The server must send this packet to each connected client individually to echo a message to all of them.

struct {
    pid: i8 = 0x03,
    msg_len: i16,
    msg: []i8,
}

04 Set Time

The client uses this to update the skybox's state.

struct {
    pid: i8 = 0x04,
    time: i64,
}

05 Inventory Init

The server sends this to the client upon connection to initialize the content of its inventory. The client sends this to the server the to inform it of an inventory update.

Inventory type -1 is the player's main 9x4 inventory space. Type -2 is the player's 2x2 crafting space. Type -3 is the player's 1x4 armor space.

The `data_len` field describes the length of an array of 'item' structures, not individual bytes. If the item structure's `id` field is -1, the `amount` and `meta` fields are not sent and the next byte is the start of the next item in the array. Why the `amount` and `meta` fields are only conditionally sent is anyone's guess.

struct item {
    item: i16,  // 00-FF block ID or 100-7FFF item ID
    amount: i8, // ! These two fields may not be sent
    meta: i16,  // Item damage or block variant
}

struct {
    pid: i8 = 0x05,
    type: i32,
    data_len: i16,  // ! Array length, not byte length
    data: []item,
}

06 Set Spawn

The server sends this to the client to tell the them to prepare to spawn and update the location the compass item points to.

struct {
    pid: i8 = 0x06,
    x: i32,  // Block position
    y: i32,
    z: i32,
}

Packets 07-09

These packet IDs are unused.

0A Player Still

The Mojang client sends this every tick while they are not moving or rotating. It is optional for the client to send this.

struct {
    pid: i8 = 0x0a,
    flying: bool,
}

0B Player Move

The Mojang client sends this every tick while they are moving and not rotating. It is optional for the client to send this.

struct {
    pid: i8 = 0x0b,
    x: f64,
    y: f64,
    top: f64, // ! The `y` field plus the height of the player's hitbox.
    z: f64,
    flying: bool,
}

0C Player Rotate

The Mojang client sends this every tick while they are rotating and not moving. It is optional for the client to send this.

struct {
    pid: i8 = 0x0c,
    yaw: f32,
    pitch: f32,
    flying: bool,
}

0D Player Update

The Mojang client sends this every tick while the player is both moving and rotating. If implementing this protocol, the client or server may send this packet exclusively rather than packets 0A-0C.

struct {
    pid: i8 = 0x0d,
    x: f64,
    y: f64,
    top: f64,  // ! The `y` field plus the height of the player's hitbox.
    z: f64,
    yaw: f32,
    pitch: f32,
    flying: bool,
}

0E Block Interact

The client sends this when the player starts breaking or using a block.

enum mode: i8 {
    Click = 0,  // Right click sends this mode only
    DigContinue = 1,
    Cancel = 2,
    Break = 3,
}

struct {
    pid: i8 = 0x0e,
    mode: i8,  // See the 'mode' enum above
    x: i32,
    y: i8,
    z: i32,
    side: i8,  // Undocumented, allowed to be 0x00
}

0F Use Item

The client sends this when the player places a block in the world or right-clicks with an item on a block surface.

struct {
    pid: i8 = 0x0f,
    item: i16,  // Either a 00-FF block or 100-7FFF item
    x: i32,
    y: i8,
    z: i32,
    dir: i8,  // Undocumented, allowed to be 0x00
}

10 Equip

The client sends this when they change their selected item slot. The server sends this to update the held item model in another player's hand. The unmodified Mojang client only allows the player to select slots 0-8.

struct {
    pid: i8 = 0x10,
    entity: i32, // Entity ID of the player to update, client sets this to 0
    slot: i16,   // Client sends inventory slot, server sends block/item ID
}

11 Give Item

The server sends this to the client to add an item to their inventory. It appears the client decides which slot the new item goes into. What happens when a client with a full inventory recieves this packet is unknown.

struct {
    pid: i8 = 0x11,
    item: i16,   // 00-FF block ID or 100-7FFF item ID
    amount: i8,  // How many items of this type are given
    meta: i16,   // Block variant or item damage
}

12 Animate

The server sends this to show a punching animation on an entity. The client sends this to tell the server to show a punching animation on their model.

struct {
    pid: i8 = 0x12,
    entity: i32,
    unused: i8,  // Almost always 0x01
}

14 Create Player

The server sends this packet to create a player model visible to the recieving client.

struct {
    pid: i8 = 0x14,
    name_len: i16,
    name: []i8,
    entity: i32,
    x: i32,  // ! Fixed-point position, divide by 32 to get real position
    y: i32,
    z: i32,
    yaw: i8,  // ! Fixed-point rotation, -128 to 127 is -π to π
    pitch: i8,
    equipped_item: i16, // 00-FF block ID or 100-7FFF item ID, visible in hand
}

15 Create Pickup

The server sends this to create an item entity that can be taken by a player.

struct {
    pid: i8 = 0x15,
    item: i16, // 00-FF block ID or 100-7FFF item ID
    amount: i8,
    x: i32,  // ! Fixed-point position, divide by 32 to get real position
    y: i32,
    z: i32,
    yaw: i8, // ! Fixed-point rotation, -128 to 127 is -π to π
    unused1: i8,
    unused2: i8,
}

16 Take Pickup

The server sends this to remove an item entity and show a 'picking up the item' animation.

struct {
    pid: i8 = 0x16,
    item_entity: i32,  // The entity ID of the item being picked up
    player_enity: i32, // The entity ID of the player picking up the item
}

17 Create Vehicle

The server sends this to create a vehicle entity on the client.

enum type {
    Boat = 1,
    MinecartEmpty = 10,
    MinecartChest = 11,
    MinecartFurnace = 12,
}

struct {
    pid: i8 = 0x17,
    entity: i32,
    type: i8, // See the 'type' enum above
    x: i32,   // ! Fixed-point position, divide by 32 to get real position
    y: i32,
    z: i32,
}

18 Create Monster

The server sends this to create a monster entity on the client.

enum type {
    // It seems like these were categorised in some way,
    // though their arrangement is still a huge mess
    ItemPickup = 1,
    Painting = 9,

    Arrow = 10,
    Snowball = 11,

    LitTNT = 20,
    FallingBlock = 21,

    // Not spawned with this packet, but uses these IDs internally
    Minecart = 40,
    Boat = 41,

    Creeper = 50,
    Skeleton = 51,
    Spider = 52,
    Giant = 53, // Never spawns and has no AI in vanilla
    Zombie = 54,
    Slime = 55,

    Pig = 90,

    // BUG! Sheep, cows and chickens all have the same ID for some reason,
    // so they will all appear as chickens to the client
    Sheep = 91,
    Cow = 91,     // is 92 in later versions
    Chicken = 91, // is 93 in later versions
}

struct {
    pid: i8 = 0x18,
    entity: i32,
    type: i8,  // See the 'type' enum above
    x: i32,    // ! Fixed-point position, divide by 32 to get real position
    y: i32,
    z: i32,
    yaw: i8,   // ! Fixed-point rotation, -128 to 127 is -π to π
    pitch: i8,
}

1E Entity Still

This packet is similar to 0A Player Still, but for non-player entities.

struct {
    pid: i8 = 0x1e,
    entity: i32,
}

1F Entity Move

This packet is similar to 0B Player Move, but for non-player entities.

struct {
    pid: i8 = 0x1f,
    entity: i32,
    dx: i8,  // ! Fixed-point position offset, divide by 32 to get real offset
    dy: i8,
    dz: i8,
}

20 Entity Rotate

This packet is similar to 0C Player Rotate, but for non-player entities.

struct {
    pid: i8 = 0x20,
    entity: i32,
    yaw: i8,  // ! Fixed-point rotation, -128 to 127 is -π to π
    pitch: i8,
}

21 Entity Relative Update

This packet offsets an entity.

struct {
    pid: i8 = 0x21,
    entity: i32,
    dx: i8,   // ! Fixed-point position offset, divide by 32 to get real offset
    dy: i8,
    dz: i8,
    yaw: i8,  // ! Fixed-point rotation, -128 to 127 is -π to π
    pitch: i8,
}

22 Entity Absolute Update

This sets the absolute position of an entity in world-space.

struct {
    pid: i8 = 0x22,
    entity: i32,
    x: i32,   // ! Fixed-point position, divide by 32 to get real position
    y: i32,
    z: i32,
    yaw: i8,  // ! Fixed-point rotation, -128 to 127 is -π to π
    pitch: i8,
}

32 Chunk Prepare

This tells a client to prepare to load or unload a world chunk. Use of this packet is optional and clients should prepare to recieve chunk data upon recieving 33 Chunk Data.

struct {
    pid: i8 = 0x32,
    x: i32,
    z: i32,
    load: bool,  // If false, the client unloads this chunk
}

33 Chunk Data

This sends world chunk data to the client.

struct {
    pid: i8 = 0x33,
    x: i32,
    y: i16,
    z: i32,
    x_size: i8,
    y_size: i8,
    z_size: i8,
    data_len: i32,
    data: []u8,  // DEFLATE-compressed data
}

34 Mass Block Update

This updates a large portion of a world chunk.

struct {
    pid: i8 = 0x34,
    x: i32,
    z: i32,
    data_len: i16,  // ! This is an array-length for the following three fields
    indices: []i16, // TODO: figure out how these are arranged
    blocks: []i8,
    metas: []i8,
}

35 Single Block Update

This updates a single block in a world chunk.

struct {
    pid: i8 = 0x35,
    x: i32,
    y: i8,
    z: i32,
    block: i8, // 00-7F block ID
    meta: i8,
}

3B Block NBT

This sets special NBT data on a single block in a world chunk.

struct {
    pid: i8 = 0x3b,
    x: i32,
    y: i16,  // ! Most block packets use an i8 for the y field, this doesn't
    z: i32,
    data_len: i16,
    data: []u8,  // Gzip compressed NBT data
}

FF Disconnect

This is sent by a server to kick a player. This is sent by a client to tell the server it is about to disconnect.

struct {
    pid: i8 = 0xff,
    msg_len: i16,
    msg: []u8,
}