a3d5f64ef5
Corrected real errors: several 1.7.x release dates, resource_pack_send version, config packet ordering, structured-component count (56), PLAYER_LOADED (1.21.4), entity_sound_effect field order. Confirmed+cited the rest; remaining ~19 items re-marked UNCONFIRMED (third-party/ViaLegacy/26.2 internals unreachable from refs). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
410 lines
26 KiB
Markdown
410 lines
26 KiB
Markdown
# 1.8.x — The Bountiful Update
|
||
|
||
**Protocol:** 47
|
||
**Versions:** 1.8 (2014-09-02) through 1.8.9 (2015-12-09) — all share the same protocol number
|
||
**Minecraft wiki release article:** <https://minecraft.wiki/w/Java_Edition_1.8> (fetched 2026-06-19)
|
||
**minecraft-data sources:** `/tmp/mcproto-refs/minecraft-data/data/pc/1.8/protocol.json`, `version.json`; diff against `/tmp/mcproto-refs/minecraft-data/data/pc/1.7/protocol.json`
|
||
**ViaVersion source:** `/tmp/mcproto-refs/ViaVersion/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/packet/` — `ClientboundPackets1_8.java`, `ServerboundPackets1_8.java`
|
||
**Protocol version confirmed:** `version.json` (`/tmp/mcproto-refs/minecraft-data/data/pc/1.8/version.json`) = `{"version":47,"minecraftVersion":"1.8.8","majorVersion":"1.8"}`; 1.7.10 = `{"version":5}`.
|
||
|
||
---
|
||
|
||
## Headline changes
|
||
|
||
1.8 ("The Bountiful Update") shipped 2014-09-02. On the wire it made three structural additions that defined the protocol for years:
|
||
|
||
**Packet compression.** A new `Set Compression` packet was inserted into the login flow (login-state, clientbound 0x03). From that point forward, each packet carries a second VarInt (`Data Length`) between the existing `Packet Length` VarInt and the payload, enabling optional zlib deflate per-packet. This is the biggest framing change since the Netty rewrite in 1.7. See [§ Compression detail](#compression-in-detail) below.
|
||
|
||
**Palette-based block and chunk encoding.** The `Map Chunk` (`0x21`) and `Multi Block Change` (`0x22`) packets switched from the 1.7 format (separate 8-bit block-ID + 4-bit metadata nibble-plane) to a single unified block-state integer. The `Multi Block Change` record went from a packed `{12-bit blockId, 4-bit metadata}` bitfield (separate words) to a single VarInt block-state ID per record. The `block_change` packet's payload similarly changed from `{type:varint, metadata:u8}` (two fields) to a single `{type:varint}` block-state ID.
|
||
|
||
**New packed-integer Position type.** Block coordinates moved from three separate `i32`/`i16`/`i32` fields in a `position_iii`/`position_isi`/`position_ibi` struct to a single `i64` packed as `{x:26-bit signed, y:12-bit signed, z:26-bit signed}`. This is the `position` bitfield type that appears throughout the 1.8 protocol.
|
||
|
||
**Why protocol 47 stayed so long.** 1.8 was the last major version for ~17 months (1.9 shipped 2016-02-29). Server operators preferred it for PvP because 1.9 introduced a weapon cooldown mechanic that most competitive networks rejected. Combined with Mojang's slow adoption of forced upgrades, protocol 47 remained the dominant live-traffic version until at least 2017 — the era that spawned the entire ViaVersion ecosystem.
|
||
|
||
---
|
||
|
||
## Compression in detail
|
||
|
||
> Cross-reference: [../05-login-encryption.md](../05-login-encryption.md) covers the full login flow; this section focuses on the 1.8 addition.
|
||
|
||
### The Set Compression packet
|
||
|
||
Sent by the server **during the login state**, after `Login Success` is in the pipeline but **before** it is actually sent:
|
||
|
||
| State | Direction | ID | Name | Field | Type |
|
||
|---|---|---|---|---|---|
|
||
| login | clientbound | `0x03` | Set Compression | threshold | VarInt |
|
||
|
||
Source: `minecraft-data/data/pc/1.8/protocol.json` login.toClient mappings `"0x03": "compress"` and `packet_compress` definition `[{"name":"threshold","type":"varint"}]`.
|
||
|
||
The 1.7 login state had only three clientbound packets (`0x00` disconnect, `0x01` encryption_begin, `0x02` success). 1.8 added `0x03` compress.
|
||
|
||
A negative `threshold` value disables compression. A value ≥ 0 means: packets whose uncompressed payload is ≥ `threshold` bytes **must** be zlib-compressed; smaller packets **may** be sent uncompressed (Data Length = 0).
|
||
|
||
### Framing change: the Data Length VarInt
|
||
|
||
Before compression is enabled the packet format is identical to 1.7:
|
||
|
||
```
|
||
[Packet Length : VarInt] [Packet ID : VarInt] [Payload...]
|
||
```
|
||
|
||
After `Set Compression` is received, **all** subsequent packets (in both directions) add a second VarInt:
|
||
|
||
```
|
||
[Packet Length : VarInt] [Data Length : VarInt] [Packet ID + Payload : zlib or raw]
|
||
```
|
||
|
||
- `Packet Length` = byte-count of everything that follows, i.e. `len(Data Length varint) + len(compressed-or-raw-data)`.
|
||
- `Data Length = 0` → the following bytes are **not** compressed (uncompressed payload was below threshold).
|
||
- `Data Length > 0` → the following bytes are zlib-deflated; `Data Length` is the **uncompressed** byte count (used to size the decompression buffer).
|
||
|
||
This second VarInt is invisible in the 1.7 framing; adding it is the entire framing change. The rest of the packet (ID + payload) is structurally unchanged — compression is a wrapper layer only.
|
||
|
||
### Login flow with compression (1.8)
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant C as Client
|
||
participant S as Server
|
||
C->>S: Login Start (0x00) [username]
|
||
S->>C: Encryption Request (0x01) [serverId, pubKey, verifyToken]
|
||
C->>S: Encryption Response (0x02) [encSharedSecret, encVerifyToken]
|
||
Note over C,S: AES/CFB8 encryption begins (both directions)
|
||
S->>C: Set Compression (0x03) [threshold] — NEW in 1.8
|
||
Note over C,S: Framing switches to compressed format (both directions)
|
||
S->>C: Login Success (0x02) [uuid, username]
|
||
Note over C,S: Transition to PLAY state
|
||
```
|
||
|
||
Note: `Set Compression` is sent **encrypted** (after the AES stream is established) but **before** the state transitions to PLAY. The compression threshold is server-controlled; vanilla default is 256 bytes.
|
||
|
||
---
|
||
|
||
## Protocol changes vs 1.7 (from minecraft-data diff)
|
||
|
||
The 1.7 and 1.8 protocol.json files share the same top-level packet names and IDs for nearly all play-state packets (0x00–0x40 clientbound, 0x00–0x17 serverbound). The protocol-breaking changes are in field types and the new packets. Key diffs:
|
||
|
||
### Handshake state
|
||
|
||
Identical. Both: `0x00` set_protocol (`protocolVersion:varint, serverHost:string, serverPort:u16, nextState:varint`).
|
||
|
||
### Login state (clientbound)
|
||
|
||
| ID | 1.7 packet | 1.8 change |
|
||
|---|---|---|
|
||
| 0x00 | disconnect | unchanged |
|
||
| 0x01 | encryption_begin | **field type change**: `publicKey` and `verifyToken` lengths changed from `i16`-prefixed buffers (1.7) to `varint`-prefixed buffers (1.8) |
|
||
| 0x02 | success | unchanged (`uuid:string, username:string`) |
|
||
| 0x03 | — | **NEW**: `compress` (`threshold:varint`) |
|
||
|
||
Source: compare `login.toClient` in both `protocol.json` files. In 1.7, `packet_encryption_begin` uses `{"countType":"i16"}` for both fields; in 1.8 they use `{"countType":"varint"}`.
|
||
|
||
### Login state (serverbound)
|
||
|
||
Same change: 1.8 `encryption_begin` uses `varint`-prefixed `sharedSecret` and `verifyToken` buffers instead of `i16`-prefixed.
|
||
|
||
### Play state — new/changed clientbound packets
|
||
|
||
| ID | Name | 1.7 → 1.8 change |
|
||
|---|---|---|
|
||
| 0x01 (login) | Login | **Added** `reducedDebugInfo:bool` field in 1.8 |
|
||
| 0x02 (chat) | Chat | **Added** `position:i8` field in 1.8 (chat box=0, system=1, game info/action bar=2) |
|
||
| 0x04 (entity_equipment) | Entity Equipment | Entity ID: `i32` → `varint` |
|
||
| 0x05 (spawn_position) | Spawn Position | `location`: `position_iii` (3×i32) → packed `position` (single i64 bitfield) |
|
||
| 0x06 (update_health) | Update Health | `food`: `i16` → `varint` |
|
||
| 0x0a (bed) | Use Bed | Entity ID `i32` → `varint`; `location`: `position_ibi` → packed `position` |
|
||
| 0x0c (named_entity_spawn) | Named Entity Spawn | **Major**: removed inline `playerName:string` and `data[]` properties array (1.7 sent these inline); added `playerUUID:UUID` binary type; removed `currentItem` field; 1.7 had string UUID + full profile inline |
|
||
| 0x0d (collect) | Collect | Both entity IDs `i32` → `varint` |
|
||
| 0x0e (spawn_entity) | Spawn Entity | `objectData` refactored: was inline `{intField:i32, velocityX/Y/Z:i16-conditional}`; same semantics, slightly different schema |
|
||
| 0x12 (entity_velocity) | Entity Velocity | Entity ID `i32` → `varint` |
|
||
| 0x13 (entity_destroy) | Entity Destroy | Count prefix `i8`+entity `i32` array → `varint` count + `varint` array |
|
||
| 0x14–0x19 (entity move/look/teleport) | Entity movement | Entity ID `i32` → `varint`; `onGround:bool` added to rel_entity_move, entity_look, entity_move_look, entity_teleport |
|
||
| 0x1a (entity_status) | Entity Status | Entity ID unchanged (`i32`) |
|
||
| 0x1c (entity_metadata) | Entity Metadata | Entity ID `i32` → `varint` |
|
||
| 0x1d (entity_effect) | Entity Effect | `duration`: `i16` → `varint`; added `hideParticles:bool` |
|
||
| 0x1e (remove_entity_effect) | Remove Entity Effect | Entity ID `i32` → `varint` |
|
||
| 0x1f (experience) | Set Experience | `level` and `totalExperience`: `i16` → `varint` |
|
||
| 0x20 (update_attributes) | Update Attributes | Modifier count prefix: `i16` → `varint` |
|
||
| 0x21 (map_chunk) | Map Chunk | **Major**: removed `addBitMap:u16` and `compressedChunkData` (zlib-in-packet); replaced with raw `chunkData:ByteArray(varint-prefixed)`; blocks now use palette block-state IDs |
|
||
| 0x22 (multi_block_change) | Multi Block Change | **Major**: record format changed from separate `{metadata+blockId bitfield, y:u8, x+z bitfield}` to `{horizontalPos:u8, y:u8, blockId:varint}`; count now `varint`, removed `dataLength:i32` |
|
||
| 0x23 (block_change) | Block Change | `location`: `position_ibi` → packed `position`; removed `metadata:u8` field — block-state ID in `type:varint` encodes both |
|
||
| 0x24 (block_action) | Block Action | `location`: `position_isi` → packed `position` |
|
||
| 0x25 (block_break_animation) | Block Break Animation | `location`: `position_iii` → packed `position` |
|
||
| 0x26 (map_chunk_bulk) | Map Chunk Bulk | **Major**: removed per-chunk `addBitMap:u16`; removed `compressedChunkData` bulk buffer; switched to `skyLightSent:bool` + varint-prefixed meta array + raw data buffer |
|
||
| 0x28 (world_event) | World Event | `location`: `position_ibi` → packed `position` |
|
||
| 0x2a (world_particles) | World Particles | Switched from `particleName:string` to `particleId:i32`; added `longDistance:bool`; added extra `data[]` varint array for item/block particles |
|
||
| 0x2c (spawn_entity_weather) | Spawn Weather Entity | Entity ID unchanged (`varint`) |
|
||
| 0x2d (open_window) | Open Window | `inventoryType`: `u8` numeric → `string` identifier; removed `useProvidedTitle:bool` |
|
||
| 0x33 (update_sign) | Update Sign | `location`: `position_isi` → packed `position` |
|
||
| 0x34 (map) | Map Item Data | **Major reformat**: 1.7 had just `{itemDamage:varint, data:buffer(i16)}`; 1.8 expanded to `{itemDamage:varint, scale:i8, icons:[...], columns:i8, rows:i8, x:i8, y:i8, data:ByteArray}` |
|
||
| 0x35 (tile_entity_data) | Tile Entity Data | `location`: `position_isi` → packed `position`; `nbtData`: `compressedNbt` → uncompressed `optionalNbt` |
|
||
| 0x36 (open_sign_entity) | Open Sign Editor | `location`: `position_iii` → packed `position` |
|
||
| 0x38 (player_info) | Player Info | **Major**: 1.7 was a flat `{playerName:string, online:bool, ping:i16}`; 1.8 became an action-based structure with `{action:varint, data:[{uuid:UUID, ...}]}` supporting add/remove/update-gamemode/update-latency/update-displayname actions |
|
||
| 0x41 (difficulty) | Change Difficulty | **NEW** in 1.8 (absent from 1.7) |
|
||
| 0x42 (combat_event) | Player Combat | **NEW** in 1.8 |
|
||
| 0x43 (camera) | Set Camera | **NEW** in 1.8 |
|
||
| 0x44 (world_border) | World Border | **NEW** in 1.8 |
|
||
| 0x45 (title) | Title | **NEW** in 1.8 |
|
||
| 0x46 (set_compression) | Set Compression | **NEW** in 1.8 (play-state duplicate; also exists in login state as 0x03) |
|
||
| 0x47 (playerlist_header) | Tab List Header/Footer | **NEW** in 1.8 |
|
||
| 0x48 (resource_pack_send) | Resource Pack | **NEW** in 1.8 |
|
||
| 0x49 (update_entity_nbt) | Update Entity NBT | **NEW** in 1.8 |
|
||
|
||
Source: packet maps in `minecraft-data/data/pc/1.8/protocol.json` play.toClient vs `data/pc/1.7/protocol.json` play.toClient. 1.7 clientbound play topped at `0x40` (kick_disconnect); 1.8 extends to `0x49`.
|
||
|
||
### Play state — changed serverbound packets
|
||
|
||
| ID | Name | 1.7 → 1.8 change |
|
||
|---|---|---|
|
||
| 0x02 (use_entity) | Interact | `target:i32` → `varint`; `mouse:i8` → `varint`; added optional `{x,y,z}:f32` fields when `mouse=2` (interact-at) |
|
||
| 0x04 (position) | Player Position | **Removed** `stance:f64` field (1.7 had x,stance,y,z; 1.8 has x,y,z) |
|
||
| 0x06 (position_look) | Player Pos+Look | Same: removed `stance:f64` |
|
||
| 0x07 (block_dig) | Player Action | `status:i8` → `varint`; `location`: `position_ibi` → packed `position` |
|
||
| 0x08 (block_place) | Use Item On | `location`: `position_ibi` → packed `position` |
|
||
| 0x0a (arm_animation) | Swing Arm | 1.7 had `{entityId:i32, animation:i8}`; 1.8 is empty (no fields) |
|
||
| 0x0b (entity_action) | Player Command | `entityId:i32` → `varint`; `actionId:i8` → `varint`; `jumpBoost:i32` → `varint` |
|
||
| 0x0c (steer_vehicle) | Player Input | `jump:bool+unmount:bool` → single `jump:u8` flags byte |
|
||
| 0x12 (update_sign) | Sign Update | `location`: `position_isi` → packed `position` |
|
||
| 0x14 (tab_complete) | Command Suggestion | Added optional `block:option<position>` field |
|
||
| 0x15 (settings) | Client Information | Removed `difficulty:u8` and `showCape:bool`; added `skinParts:u8` bitmask |
|
||
| 0x18 (spectate) | Teleport To Entity | **NEW** in 1.8 |
|
||
| 0x19 (resource_pack_receive) | Resource Pack Status | **NEW** in 1.8 |
|
||
|
||
Source: `minecraft-data/data/pc/1.8/protocol.json` play.toServer vs `data/pc/1.7/protocol.json` play.toServer. 1.7 serverbound play topped at `0x17` (custom_payload); 1.8 extends to `0x19`.
|
||
|
||
---
|
||
|
||
## Entity metadata format
|
||
|
||
Both 1.7 and 1.8 use the same sentinel-terminated metadata loop structure:
|
||
- Each entry is a header byte with `{type:3 bits, key:5 bits}`.
|
||
- End of stream signalled by byte `0x7F` (127).
|
||
- Entry values by type: 0=i8, 1=i16, 2=i32, 3=f32, 4=string, 5=slot, 6={x:i32,y:i32,z:i32}, 7={pitch:f32,yaw:f32,roll:f32}.
|
||
|
||
The type table is identical in both versions (verified from `entityMetadataItem` in both `protocol.json` files). However, the set of actual metadata indices and their meanings changed for several entity types in 1.8 to accommodate new entity properties (guardians, rabbits, armor stands). <!-- UNCONFIRMED: per-entity metadata index assignments for new 1.8 entities are not enumerated in minecraft-data protocol.json (which only defines the loop encoding format, not per-entity index semantics); ViaVersion's EntityDataIndex1_9.java covers 1.8→1.9 index mapping but does not provide a standalone 1.8 per-entity index table. Wiki or source-level game data would be needed. -->
|
||
|
||
The container types `entityMetadata` and `entityMetadataItem` in 1.8's `protocol.json` are structurally identical to 1.7 — confirming that the metadata **encoding format** did not change between protocol 5 and 47; the changes were in which indices are used, not the framing.
|
||
|
||
---
|
||
|
||
## Chunk and block encoding
|
||
|
||
### 1.7 chunk format (for comparison)
|
||
|
||
In 1.7, `Map Chunk` (`0x21`) contained:
|
||
- `bitMap:u16` — which of the 16 vertical sections are present
|
||
- `addBitMap:u16` — additional-data sections for blocks requiring >8 bits of block ID (extended blocks)
|
||
- `compressedChunkData:buffer(i32-count)` — zlib-deflated payload containing raw nibble arrays: 8-bit block IDs + 4-bit metadata nibbles + 4-bit block light + optional 4-bit sky light + optional 4-bit add-data
|
||
|
||
The 1.7 format encoded block type as `(blockID << 4) | metadata` using two separate nibble planes.
|
||
|
||
### 1.8 chunk format
|
||
|
||
In 1.8, `Map Chunk` (`0x21`) contains:
|
||
- `bitMap:u16` — which sections are present
|
||
- `chunkData:ByteArray` (varint-prefixed) — raw uncompressed per-section data
|
||
|
||
The per-section data layout in 1.8 encodes blocks as **block-state IDs** — a single integer combining what was previously `blockId` and `metadata`. Each section now stores:
|
||
- 4096 block-state values as 16-bit entries (2 bytes per block, stored little-endian in a flat array of `4096 × 2` bytes)
|
||
- 2048 bytes block light nibble array
|
||
- 2048 bytes sky light nibble array (overworld only)
|
||
|
||
The `addBitMap` field and the separate metadata nibble plane are gone entirely. Block state IDs are the canonical 1.8+ block representation: e.g., oak log facing north is a single integer distinct from oak log facing east, rather than `id=17, meta=4` vs `id=17, meta=0`.
|
||
|
||
The `Multi Block Change` record format reflects this too: in 1.7, each record packed `{metadata:4bits, blockId:12bits}` in one i16 plus a separate `y:u8` and `{x:4bits,z:4bits}` nibble. In 1.8, each record is `{horizontalPos:u8, y:u8, blockId:varint}` where `blockId` is the full block-state ID (confirmed from `packet_multi_block_change` in `minecraft-data/data/pc/1.8/protocol.json` — `{"countType":"varint"}` for blockId). For chunk section data (per-block encoding inside the `chunkData` buffer), the 1.8 format stores block-state IDs as 16-bit little-endian shorts per block (4096 × 2 bytes per section); this is not expressible in the minecraft-data schema level and the local ref set contains no authoritative source for the per-section layout. <!-- UNCONFIRMED: chunk section per-block encoding (16-bit shorts vs other) — no local source; web.archive.org fetch unavailable. -->
|
||
|
||
---
|
||
|
||
## Packet inventory by state — 1.8 (protocol 47)
|
||
|
||
Source: `minecraft-data/data/pc/1.8/protocol.json` packet mapper sections. ViaVersion `ClientboundPackets1_8.java` and `ServerboundPackets1_8.java` confirm the same IDs.
|
||
|
||
### Handshake (C→S)
|
||
|
||
| ID | Name |
|
||
|---|---|
|
||
| 0x00 | Set Protocol (Handshake) |
|
||
| 0xFE | Legacy Server List Ping |
|
||
|
||
### Status
|
||
|
||
| ID | Direction | Name |
|
||
|---|---|---|
|
||
| 0x00 | S→C | Server Info (JSON response) |
|
||
| 0x01 | S→C | Ping (i64 payload echo) |
|
||
| 0x00 | C→S | Request (empty) |
|
||
| 0x01 | C→S | Ping (i64 timestamp) |
|
||
|
||
### Login
|
||
|
||
| ID | Direction | Name |
|
||
|---|---|---|
|
||
| 0x00 | S→C | Disconnect |
|
||
| 0x01 | S→C | Encryption Request |
|
||
| 0x02 | S→C | Login Success |
|
||
| 0x03 | S→C | **Set Compression** ← new in 1.8 |
|
||
| 0x00 | C→S | Login Start |
|
||
| 0x01 | C→S | Encryption Response |
|
||
|
||
### Play — Clientbound (S→C)
|
||
|
||
| ID | Name |
|
||
|---|---|
|
||
| 0x00 | Keep Alive |
|
||
| 0x01 | Login (Join Game) |
|
||
| 0x02 | Chat Message |
|
||
| 0x03 | Time Update |
|
||
| 0x04 | Entity Equipment |
|
||
| 0x05 | Spawn Position |
|
||
| 0x06 | Update Health |
|
||
| 0x07 | Respawn |
|
||
| 0x08 | Player Position and Look |
|
||
| 0x09 | Held Item Change |
|
||
| 0x0A | Use Bed |
|
||
| 0x0B | Animation |
|
||
| 0x0C | Spawn Named Entity |
|
||
| 0x0D | Collect Item |
|
||
| 0x0E | Spawn Object |
|
||
| 0x0F | Spawn Mob |
|
||
| 0x10 | Spawn Painting |
|
||
| 0x11 | Spawn Experience Orb |
|
||
| 0x12 | Entity Velocity |
|
||
| 0x13 | Destroy Entities |
|
||
| 0x14 | Entity (no-op move) |
|
||
| 0x15 | Entity Relative Move |
|
||
| 0x16 | Entity Look |
|
||
| 0x17 | Entity Look and Relative Move |
|
||
| 0x18 | Entity Teleport |
|
||
| 0x19 | Entity Head Look |
|
||
| 0x1A | Entity Status |
|
||
| 0x1B | Attach Entity |
|
||
| 0x1C | Entity Metadata |
|
||
| 0x1D | Entity Effect |
|
||
| 0x1E | Remove Entity Effect |
|
||
| 0x1F | Set Experience |
|
||
| 0x20 | Entity Properties |
|
||
| 0x21 | Chunk Data |
|
||
| 0x22 | Multi Block Change |
|
||
| 0x23 | Block Change |
|
||
| 0x24 | Block Action |
|
||
| 0x25 | Block Break Animation |
|
||
| 0x26 | Map Chunk Bulk |
|
||
| 0x27 | Explosion |
|
||
| 0x28 | Effect |
|
||
| 0x29 | Sound Effect |
|
||
| 0x2A | Particle |
|
||
| 0x2B | Change Game State |
|
||
| 0x2C | Spawn Global Entity |
|
||
| 0x2D | Open Window |
|
||
| 0x2E | Close Window |
|
||
| 0x2F | Set Slot |
|
||
| 0x30 | Window Items |
|
||
| 0x31 | Window Property |
|
||
| 0x32 | Confirm Transaction |
|
||
| 0x33 | Update Sign |
|
||
| 0x34 | Maps |
|
||
| 0x35 | Update Block Entity |
|
||
| 0x36 | Open Sign Editor |
|
||
| 0x37 | Statistics |
|
||
| 0x38 | Player List Item |
|
||
| 0x39 | Player Abilities |
|
||
| 0x3A | Tab-Complete |
|
||
| 0x3B | Scoreboard Objective |
|
||
| 0x3C | Update Score |
|
||
| 0x3D | Display Scoreboard |
|
||
| 0x3E | Teams |
|
||
| 0x3F | Plugin Message |
|
||
| 0x40 | Disconnect |
|
||
| 0x41 | Server Difficulty ← new in 1.8 |
|
||
| 0x42 | Combat Event ← new in 1.8 |
|
||
| 0x43 | Camera ← new in 1.8 |
|
||
| 0x44 | World Border ← new in 1.8 |
|
||
| 0x45 | Title ← new in 1.8 |
|
||
| 0x46 | Set Compression (play-state) ← new in 1.8 |
|
||
| 0x47 | Player List Header and Footer ← new in 1.8 |
|
||
| 0x48 | Resource Pack Send ← new in 1.8 |
|
||
| 0x49 | Update Entity NBT ← new in 1.8 |
|
||
|
||
### Play — Serverbound (C→S)
|
||
|
||
| ID | Name |
|
||
|---|---|
|
||
| 0x00 | Keep Alive |
|
||
| 0x01 | Chat Message |
|
||
| 0x02 | Use Entity |
|
||
| 0x03 | Player (ground status only) |
|
||
| 0x04 | Player Position |
|
||
| 0x05 | Player Look |
|
||
| 0x06 | Player Position and Look |
|
||
| 0x07 | Player Digging |
|
||
| 0x08 | Player Block Placement |
|
||
| 0x09 | Held Item Change |
|
||
| 0x0A | Animation (arm swing — empty payload in 1.8) |
|
||
| 0x0B | Entity Action |
|
||
| 0x0C | Steer Vehicle |
|
||
| 0x0D | Close Window |
|
||
| 0x0E | Click Window |
|
||
| 0x0F | Confirm Transaction |
|
||
| 0x10 | Creative Inventory Action |
|
||
| 0x11 | Enchant Item |
|
||
| 0x12 | Update Sign |
|
||
| 0x13 | Player Abilities |
|
||
| 0x14 | Tab-Complete |
|
||
| 0x15 | Client Settings |
|
||
| 0x16 | Client Status |
|
||
| 0x17 | Plugin Message |
|
||
| 0x18 | Spectate ← new in 1.8 |
|
||
| 0x19 | Resource Pack Status ← new in 1.8 |
|
||
|
||
---
|
||
|
||
## Proxy and translation impact
|
||
|
||
**ViaVersion floor.** Protocol 47 is ViaVersion's oldest natively supported client. There is no `v1_7to1_8` package in ViaVersion — 1.7 support requires ViaLegacy/ViaRewind. The `v1_8to1_9` package (`/tmp/mcproto-refs/ViaVersion/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/`) is the FROM-1.8 direction and serves as the canonical definition of the 1.8 packet set.
|
||
|
||
**Compression negotiation at the proxy.** A proxy operating in front of a 1.8+ server must intercept `Set Compression` (login 0x03) from the backend and decide whether to relay, modify, or suppress it. The compression threshold may differ between the proxy's own connection to the client and the proxy-to-server leg. BungeeCord and Velocity both intercept this packet and re-issue their own `Set Compression` to the client with their own threshold, then maintain separate compression state for each half of the connection.
|
||
|
||
**Position type translation.** Any proxy accepting 1.7 clients and forwarding to a 1.8+ server must translate between the old triple-i32/i16 position types and the new packed `i64` `position` type for every block-coordinate field (spawn_position, bed, block_change, block_action, block_break_animation, update_sign, tile_entity_data, open_sign_entity, world_event, and on the serverbound side: block_dig, block_place, update_sign). <!-- UNCONFIRMED: completeness of this list against actual ViaLegacy implementation — ViaLegacy source is not present in the ref set (/tmp/mcproto-refs/ contains only ViaVersion which handles 1.8+). The list was derived from the protocol.json diff of all fields using position_iii/position_isi/position_ibi types, which is likely complete but not cross-checked against ViaLegacy's actual packet handlers. -->
|
||
|
||
**block_change metadata removal.** A 1.7-to-1.8 translator must combine the 1.7 `{type:varint, metadata:u8}` pair into a single 1.8 block-state VarInt on `block_change`, and split in the reverse direction.
|
||
|
||
**Stance removal.** The 1.7 serverbound `position` packet had a `stance:f64` field (eye-height offset for collision) that was removed in 1.8 (confirmed from protocol.json diff). A proxy bridging 1.7→1.8 must strip this field; a 1.8→1.7 bridge must synthesise it (commonly cited as `y + 1.62` for the default player eye height). <!-- UNCONFIRMED: the `y + 1.62` synthesis constant is widely cited in community protocol documentation but is not present in the ViaVersion source set (ViaVersion handles 1.8+, not 1.7↔1.8 bridging); ViaLegacy source would be authoritative but is not available in the ref set. -->
|
||
|
||
**Player Info restructure.** The flat single-player `player_info` from 1.7 (`playerName, online, ping`) was replaced in 1.8 with the action-based multi-player structure. Proxies doing tab-list passthrough must understand the 1.8 structure.
|
||
|
||
**New packets requiring proxy awareness.** `World Border` (0x44), `Title` (0x45), `Combat Event` (0x42), and `Set Compression` (0x46 in play-state) are all 1.8-new and unknown to 1.7 clients. A proxy connecting a 1.7 client to a 1.8 server must either translate or drop these; ViaLegacy/ViaRewind handle this for the compatibility layer.
|
||
|
||
---
|
||
|
||
## Sub-version notes (1.8.1 – 1.8.9)
|
||
|
||
All 1.8.x patches share **protocol 47**. Patch releases addressed server-side exploits (combat, enchantment mechanics, item duplication), server crash vectors, and connectivity bugs but made **no wire-format changes**. A 1.8 client connects to a 1.8.9 server without negotiation issues, and vice versa.
|
||
|
||
Confirmed: all 1.8.x releases share protocol 47. The minecraft-data `version.json`
|
||
for the 1.8 majorVersion slot records `{"version":47,"minecraftVersion":"1.8.8"}`,
|
||
and the minecraft-data schema keys the entire 1.8 family to a single `protocol.json`
|
||
with no sub-version splits — consistent with zero wire-format changes across the
|
||
patch line. (Source: `minecraft-data/data/pc/1.8/version.json`.)
|
||
|
||
---
|
||
|
||
## Sources summary
|
||
|
||
| Claim | Source |
|
||
|---|---|
|
||
| Protocol 47; version 1.8.8 as representative | `/tmp/mcproto-refs/minecraft-data/data/pc/1.8/version.json` |
|
||
| Release date 2014-09-02 | <https://minecraft.wiki/w/Java_Edition_1.8> (fetched 2026-06-19) |
|
||
| Login 0x03 `compress` packet field def | `/tmp/mcproto-refs/minecraft-data/data/pc/1.8/protocol.json` login.toClient |
|
||
| 1.7 login had no 0x03 | `/tmp/mcproto-refs/minecraft-data/data/pc/1.7/protocol.json` login.toClient (0x00–0x02 only) |
|
||
| Encryption buffer countType i16→varint | Both `protocol.json` files, `packet_encryption_begin` |
|
||
| Play packet IDs 0x00–0x49 (1.8) | `/tmp/mcproto-refs/minecraft-data/data/pc/1.8/protocol.json` play.toClient mapper |
|
||
| Play packet IDs 0x00–0x40 (1.7) | `/tmp/mcproto-refs/minecraft-data/data/pc/1.7/protocol.json` play.toClient mapper |
|
||
| 1.8 clientbound packet enum with IDs | `/tmp/mcproto-refs/ViaVersion/…/v1_8to1_9/packet/ClientboundPackets1_8.java` |
|
||
| 1.8 serverbound packet enum with IDs | `/tmp/mcproto-refs/ViaVersion/…/v1_8to1_9/packet/ServerboundPackets1_8.java` |
|
||
| Compression framing (Data Length VarInt) | <https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol> (fetched 2026-06-19) |
|
||
| chunk_data addBitMap present in 1.7, absent in 1.8 | diff of `packet_map_chunk` in both `protocol.json` |
|
||
| multi_block_change record format change | diff of `packet_multi_block_change` in both `protocol.json` |
|
||
| `stance` field in 1.7 position, absent in 1.8 | `packet_position` in both `protocol.json` |
|
||
| metadata loop structure identical 1.7 and 1.8 | `entityMetadata`/`entityMetadataItem` in both `protocol.json` |
|