Files
claude-timemachine 02a249a379 verify pass 2: resolve markers via ViaBackwards/ViaRewind/ViaLegacy
Closed most remaining UNCONFIRMED items + caught corrections: 1.7 data[]=proto5,
1.8 multi-block nibble order (z/x), stance y+1.62, 1.15 wolf idx18=begging,
1.18 below-zero sections NOT stripped (claim was wrong), CONTAINER_SLOT_STATE
1.20.3, + pinned first-appeared versions (report details/server links=1.21,
fluidCount=26.1, block-state id14=1.19.4, itemCount VarInt=1.20.5).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 19:13:19 +02:00

410 lines
27 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 (0x000x40 clientbound, 0x000x17 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 |
| 0x140x19 (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). ViaRewind's `EntityDataIndex1_7_6_10.java` enumerates the authoritative 1.8 index assignments used in 1.8→1.7 translation: base entity indices 0 (flags, byte) and 1 (air, short) are unchanged; `LIVING_ENTITY_BASE` health moves to index 6 (float); new 1.8 fields (name tag at 2, name tag visibility at 3, silent at 4) have no 1.7 equivalent and are dropped. `ARMOR_STAND` uses 1.8 indices 1016 (flags, head/body/arm/leg rotations). `GUARDIAN` metadata indices are not translated (no 1.7 equivalent entity). `RABBIT` is similarly absent (new 1.8 entity, no translation). Note this is the 1.8 side of a translation table, not a standalone per-entity reference, but it confirms the index assignments for entities present in both versions. (Source: `ViaRewind/common/src/main/java/com/viaversion/viarewind/protocol/v1_8to1_7_6_10/data/EntityDataIndex1_7_6_10.java`.)
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 `{z:4bits,x:4bits}` nibble byte (source: `minecraft-data/data/pc/1.7/protocol.json` bitfield definitions — z occupies the high nibble, x the low 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 **4096 × 16-bit little-endian unsigned shorts** per section (confirmed from `ViaVersion/ChunkSectionType1_8.java`: reads `littleEndianView.readUnsignedShort()` for each of `ChunkSection.SIZE` = 4096 blocks; writes via `littleEndianView.writeShort()`).
---
## 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. Cross-checked against ViaRewind's `WorldPacketRewriter1_8.java` and `PlayerPacketRewriter1_8.java` (1.8 client ↔ 1.7 server direction): S→C packets requiring position translation are `BLOCK_UPDATE` (→ `U_BYTE_POSITION`), `BLOCK_EVENT` (→ `SHORT_POSITION`), `BLOCK_DESTRUCTION` (→ `INT_POSITION`), `LEVEL_EVENT` (→ `BYTE_POSITION`), `UPDATE_SIGN` (→ `SHORT_POSITION`), `BLOCK_ENTITY_DATA` (→ `SHORT_POSITION`), and `LOGIN`/spawn position (→ `INT_POSITION`). On the C→S serverbound side, `block_dig` and `block_place` carry `BLOCK_POSITION1_8` mapped from `U_BYTE_POSITION`/`SHORT_POSITION` legacy types (ViaRewind `PlayerPacketRewriter1_8.java` lines 618, 635, 727). The list in the original derivation (`spawn_position, bed, block_change, block_action, block_break_animation, update_sign, tile_entity_data, open_sign_entity, world_event`) is consistent with ViaRewind's handler set. (Source: `ViaRewind/common/src/main/java/com/viaversion/viarewind/protocol/v1_8to1_7_6_10/rewriter/WorldPacketRewriter1_8.java` and `PlayerPacketRewriter1_8.java`.)
**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 as `y + 1.62F`. The `y + 1.62` synthesis constant is confirmed from ViaRewind's `PlayerPacketRewriter1_8.java`: `wrapper.set(Types.DOUBLE, 1, y + 1.62F)` in the `PLAYER_POSITION` clientbound handler, where the second DOUBLE slot is the stance field written into the 1.7 position packet. (Source: `ViaRewind/common/src/main/java/com/viaversion/viarewind/protocol/v1_8to1_7_6_10/rewriter/PlayerPacketRewriter1_8.java`, line 187.)
**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 (0x000x02 only) |
| Encryption buffer countType i16→varint | Both `protocol.json` files, `packet_encryption_begin` |
| Play packet IDs 0x000x49 (1.8) | `/tmp/mcproto-refs/minecraft-data/data/pc/1.8/protocol.json` play.toClient mapper |
| Play packet IDs 0x000x40 (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` |