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>
300 lines
18 KiB
Markdown
300 lines
18 KiB
Markdown
# Java Edition 1.17 — Caves & Cliffs Part I
|
||
|
||
| Release | Protocol | Release Date | Data Version |
|
||
|---------|----------|--------------|--------------|
|
||
| 1.17 | 755 | 2021-06-08 | 2724 |
|
||
| 1.17.1 | 756 | 2021-07-06 | 2730 |
|
||
|
||
Sources: minecraft.wiki/w/Java_Edition_1.17 (fetched 2026-06-19); minecraft.wiki/w/Java_Edition_1.17.1 (fetched 2026-06-19); `ViaVersion/common/.../protocols/v1_16_4to1_17/` + `v1_17to1_17_1/`; `minecraft-data/data/pc/1.17/protocol.json`, `entities.json`, `loginPacket.json`; `minecraft-data/data/pc/1.17.1/protocol.json`.
|
||
|
||
---
|
||
|
||
## Headline Changes (Caves & Cliffs Part I)
|
||
|
||
1.17 was the first half of the Caves & Cliffs split — the world-height expansion (Y -64 to 320) shipped in 1.18; what 1.17 delivered was the **groundwork** for it. The dimension codec in LOGIN gained two new mandatory NBT fields (`min_y`, `height`) and the chunk/light formats were updated to support variable-height sections. Three new mobs were added (axolotl, glow squid, goat), shifting all existing entity type IDs. The most sweeping protocol-visible change was **packet explosion-splitting**: the single `SET_TITLES` packet (6 actions via a VarInt discriminant) was split into 6 independent packets; similarly `SET_BORDER` (6 actions) became 6 packets; `PLAYER_COMBAT` (3 actions) became 3 packets. The `CONTAINER_ACK` / `TRANSACTION` packet and the abstract `MOVE_ENTITY` parent were removed. A `PING` / `PONG` round-trip pair was added. Tags now carry a generic resource-location prefix, and a new `GAME_EVENT` tag type was introduced.
|
||
|
||
---
|
||
|
||
## Protocol Changes vs 1.16.4 (754 → 755)
|
||
|
||
### Play state — Clientbound (new / removed / restructured)
|
||
|
||
**Packet-split: SET_TITLES → 6 packets**
|
||
|
||
1.16 had a single `SET_TITLES` (0x4F) with a leading `VarInt` action discriminant (0=title, 1=subtitle, 2=actionbar, 3=animation, 4=clear, 5=reset). In 1.17 this became six independent packets:
|
||
|
||
| 1.17 ID | Name | Notes |
|
||
|---------|------|-------|
|
||
| 0x10 | `CLEAR_TITLES` | carries a `Boolean` reset-times field |
|
||
| 0x41 | `SET_ACTION_BAR_TEXT` | action-bar chat component |
|
||
| 0x5A | `SET_TITLES_ANIMATION` | fade-in / stay / fade-out ticks |
|
||
| 0x59 | `SET_TITLE_TEXT` | title component |
|
||
| 0x57 | `SET_SUBTITLE_TEXT` | subtitle component |
|
||
|
||
Sources: `v1_16_4to1_17/Protocol1_16_4To1_17.java:110–134`; `v1_16_4to1_17/packet/ClientboundPackets1_17.java:88–114`; minecraft-data `1.17/protocol.json` 0x10/0x41/0x57/0x59/0x5A.
|
||
|
||
**Packet-split: SET_BORDER → 6 packets**
|
||
|
||
1.16 had `SET_BORDER` (0x3D) with 6 action types. In 1.17 these became:
|
||
|
||
| 1.17 ID | Name |
|
||
|---------|------|
|
||
| 0x20 | `INITIALIZE_BORDER` |
|
||
| 0x42 | `SET_BORDER_CENTER` |
|
||
| 0x43 | `SET_BORDER_LERP_SIZE` |
|
||
| 0x44 | `SET_BORDER_SIZE` |
|
||
| 0x45 | `SET_BORDER_WARNING_DELAY` |
|
||
| 0x46 | `SET_BORDER_WARNING_DISTANCE` |
|
||
|
||
Sources: `v1_16_4to1_17/rewriter/WorldPacketRewriter1_17.java:42–56`; `v1_16_4to1_17/packet/ClientboundPackets1_17.java:56/90–96`.
|
||
|
||
**Packet-split: PLAYER_COMBAT → 3 packets**
|
||
|
||
1.16 had `PLAYER_COMBAT` (0x31) with action types 0=enter, 1=end, 2=kill. In 1.17:
|
||
|
||
| 1.17 ID | Name |
|
||
|---------|------|
|
||
| 0x33 | `PLAYER_COMBAT_END` |
|
||
| 0x34 | `PLAYER_COMBAT_ENTER` |
|
||
| 0x35 | `PLAYER_COMBAT_KILL` |
|
||
|
||
Sources: `v1_16_4to1_17/rewriter/EntityPacketRewriter1_17.java:148–164`; `v1_16_4to1_17/packet/ClientboundPackets1_17.java:75–77`.
|
||
|
||
**New packet: ADD_VIBRATION_SIGNAL (0x05)**
|
||
|
||
Sculk sensors (command-only in 1.17) transmit vibration signals via this new packet. Inserted at 0x05, shifting all former 0x05+ clientbound IDs up by one.
|
||
|
||
Sources: `v1_16_4to1_17/packet/ClientboundPackets1_17.java:29`; minecraft-data `1.17/protocol.json` 0x05 `sculk_vibration_signal`.
|
||
|
||
**New packet: PING (0x30)**
|
||
|
||
Added alongside the serverbound `PONG` (0x1D) to support a ping/pong round-trip independent of the `KEEP_ALIVE` flow. Sent as a single `Int` ID; client echoes it in `PONG`.
|
||
|
||
Sources: `v1_16_4to1_17/packet/ClientboundPackets1_17.java:72`; `v1_16_4to1_17/packet/ServerboundPackets1_17.java:53`.
|
||
|
||
**Removed: CONTAINER_ACK / TRANSACTION (0x11 in 1.16)**
|
||
|
||
The `TRANSACTION` (also known as `CONTAINER_ACK`) packet was removed. Servers no longer send transaction-confirmation packets for inventory clicks; the mechanism was replaced by a state ID approach in 1.17.1 (see §1.17.1 below).
|
||
|
||
Sources: `v1_16_4to1_17/Protocol1_16_4To1_17.java:27–29` (commit `27033e929`); minecraft-data 1.16 has `0x12 transaction`, 1.17 does not.
|
||
|
||
**Removed: MOVE_ENTITY (0x2A in 1.16 → absent in 1.17)**
|
||
|
||
The parent abstract packet `MOVE_ENTITY` (0x2A, used as a no-op stand-in for the position-only move that was never actually used) was removed from the ID list. `MOVE_ENTITY_POS` (0x29), `MOVE_ENTITY_POS_ROT` (0x2A), and `MOVE_ENTITY_ROT` (0x2B) remain.
|
||
|
||
Sources: `v1_16_4to1_17/rewriter/EntityPacketRewriter1_17.java:167` ("The parent class of the other entity move packets that is never actually used has finally been removed from the id list"); VV comment `cancelClientbound(ClientboundPackets1_16_2.MOVE_ENTITY)`.
|
||
|
||
**Removed/renamed: REMOVE_ENTITIES → REMOVE_ENTITY (0x3A)**
|
||
|
||
In 1.16 `REMOVE_ENTITIES` (0x36) sent a `VarInt`-prefixed array of entity IDs in a single packet. In 1.17 this was replaced by `REMOVE_ENTITY` (0x3A) which carries a **single `VarInt` entity ID** per packet — one remove packet per entity.
|
||
|
||
Sources: `v1_16_4to1_17/rewriter/EntityPacketRewriter1_17.java:73–86` (sends one `REMOVE_ENTITY` per ID from old array); `v1_16_4to1_17/packet/ClientboundPackets1_17.java:84`.
|
||
|
||
**Field changes: RESOURCE_PACK (0x3C)**
|
||
|
||
Two new fields added at the end: `Required` (Boolean) and `Prompt` (Optional Chat, nullable). ViaVersion injects these from config when downgrading.
|
||
|
||
Sources: `v1_16_4to1_17/Protocol1_16_4To1_17.java:87–92`.
|
||
|
||
**Field changes: MAP_ITEM_DATA (0x27)**
|
||
|
||
`Tracking position` boolean removed. Marker array now encoded as optional (Boolean prefix then count if true) instead of a simple VarInt count.
|
||
|
||
Sources: `v1_16_4to1_17/Protocol1_16_4To1_17.java:94–108`.
|
||
|
||
**Field changes: EXPLODE (0x1C)**
|
||
|
||
`Collection length` (count of blocks affected) changed from `Int` to `VarInt`.
|
||
|
||
Sources: `v1_16_4to1_17/Protocol1_16_4To1_17.java:136–145`.
|
||
|
||
**Field changes: SET_DEFAULT_SPAWN_POSITION (0x4B)**
|
||
|
||
New `Angle` field (Float) added after the block position. Mojang initially forgot to write this to the buffer, so ViaVersion hard-codes `0f` when downgrading.
|
||
|
||
Sources: `v1_16_4to1_17/Protocol1_16_4To1_17.java:147–153` (comment: "which Mojang just forgot to write to the buffer, lol").
|
||
|
||
**Field changes: UPDATE_ATTRIBUTES (0x63)**
|
||
|
||
Collection length changed from `Int` to `VarInt`.
|
||
|
||
Sources: `v1_16_4to1_17/rewriter/EntityPacketRewriter1_17.java:126–132`.
|
||
|
||
**Field changes: PLAYER_POSITION (0x38)**
|
||
|
||
New `Dismount vehicle` Boolean field appended.
|
||
|
||
Sources: `v1_16_4to1_17/rewriter/EntityPacketRewriter1_17.java:134–146`.
|
||
|
||
---
|
||
|
||
### Play state — Serverbound (new / removed)
|
||
|
||
| Change | 1.16 (0x__) | 1.17 (0x__) | Notes |
|
||
|--------|-------------|-------------|-------|
|
||
| Removed | TRANSACTION 0x07 | — | Client-side ACK for inventory transactions; removed with CONTAINER_ACK |
|
||
| Removed | CRAFTING_BOOK_DATA 0x1E | — | Collapsed into two packets below |
|
||
| Added | — | PONG 0x1D | Echo for server-sent PING |
|
||
| Added | — | RECIPE_BOOK 0x1E | Recipe book settings (replaces part of crafting_book_data) |
|
||
| Added | — | DISPLAYED_RECIPE 0x1F | "Display recipe" action (replaces part of crafting_book_data) |
|
||
|
||
Sources: minecraft-data `1.16/protocol.json` SB vs `1.17/protocol.json` SB; `v1_16_4to1_17/packet/ServerboundPackets1_17.java:53/58/59`.
|
||
|
||
**Field changes: CLIENT_INFORMATION (0x05)**
|
||
|
||
`Text filtering` Boolean field removed (client to server).
|
||
|
||
Sources: `v1_16_4to1_17/Protocol1_16_4To1_17.java:155–166` (`read(Types.BOOLEAN)` — drops the field when translating down).
|
||
|
||
---
|
||
|
||
### Login (JOIN_GAME / LOGIN packet, 0x26 C→client)
|
||
|
||
The `LOGIN` packet gained two new top-level fields compared to 1.16:
|
||
|
||
- **`isHardcore`** (Boolean) — added as the second field after `Entity ID`. Absent in the 1.16 LOGIN packet (confirmed: `minecraft-data/data/pc/1.16/loginPacket.json` has no `isHardcore` key; `1.17/loginPacket.json` has it). ViaVersion maps it at `EntityPacketRewriter1_17.java:92`.
|
||
- **`Simulation Distance`** — added in 1.18, not 1.17. Confirmed: `minecraft-data/data/pc/1.17/loginPacket.json` lists `viewDistance` but has no `simulationDistance` field; `data/pc/1.18/loginPacket.json` adds it immediately after `viewDistance`. ViaVersion `EntityPacketRewriter1_18.java:57-58` injects it as a copy of `viewDistance` when a 1.17.1-era server does not supply it.
|
||
|
||
More significantly, the **dimension codec NBT** structure changed:
|
||
|
||
| Field | 1.16 | 1.17 |
|
||
|-------|------|------|
|
||
| Codec registry key | `"dimension"` (flat list) | `"minecraft:dimension_type"` (named registry) + `"minecraft:worldgen/biome"` |
|
||
| Dimension element `"name"` | present | removed |
|
||
| Dimension element `"shrunk"` | present | removed |
|
||
| Dimension element `"coordinate_scale"` | absent | added |
|
||
| Dimension element `"effects"` | absent | added (sky/fog rendering type) |
|
||
| Dimension element `"min_y"` | absent | added (always 0 in 1.17; expanded to -64 in 1.18) |
|
||
| Dimension element `"height"` | absent | added (always 256 in 1.17; expanded to 384 in 1.18) |
|
||
|
||
The **biome registry** (`minecraft:worldgen/biome`) is now part of the codec compound, transmitted inline in LOGIN. In 1.16 it was not present in the codec.
|
||
|
||
Sources: minecraft-data `1.17/loginPacket.json` vs `1.16/loginPacket.json` (deep diff, path `.dimensionCodec.value.*`); `v1_16_4to1_17/rewriter/EntityPacketRewriter1_17.java:196–199` (`addNewDimensionData` adds `min_y=0`, `height=256`).
|
||
|
||
---
|
||
|
||
### Chunk format (LEVEL_CHUNK, 0x22)
|
||
|
||
1.17 eliminated partial-chunk ("non-full chunk") packets. All chunks are now sent as full chunks. The chunk section bitmask changed from a plain `Int` to a `BitSet` (serialized as `Long[]`). This is groundwork for the expanded world height in 1.18 — a BitSet can represent more than 16 sections.
|
||
|
||
ViaVersion: non-full chunks arriving from a 1.16 server are converted into `SECTION_BLOCKS_UPDATE` packets because the chunk payload cannot be retransmitted without full section data.
|
||
|
||
Sources: `v1_16_4to1_17/rewriter/WorldPacketRewriter1_17.java:102–122` (chunk type switch `ChunkType1_16_2` → `ChunkType1_17`, BitSet mask).
|
||
|
||
---
|
||
|
||
### Light update format (LIGHT_UPDATE, 0x25)
|
||
|
||
Light section masks changed from `VarInt` bitmasks to `Long[]` BitSets (same direction as chunk masks). Each sky/block light mask is now serialized as a long array. Each light array is now preceded by its count (as a VarInt) before the byte arrays.
|
||
|
||
Sources: `v1_16_4to1_17/rewriter/WorldPacketRewriter1_17.java:58–99` (converts VarInt bitmasks to `long[]` BitSets, writes count prefix for light array lists).
|
||
|
||
---
|
||
|
||
### Tags (UPDATE_TAGS, 0x66)
|
||
|
||
Tags are now **generically written with resource location keys**. In 1.16 the server sent 4 fixed tag types (block, item, fluid, entity) with no type identifier. In 1.17 each tag group is prefixed with its registry resource location (e.g. `"minecraft:block"`, `"minecraft:item"`, `"minecraft:fluid"`, `"minecraft:entity_type"`, `"minecraft:game_event"`), and the count of registry types is sent first as a VarInt. A fifth **Game Event** tag type (`minecraft:game_event`) was added.
|
||
|
||
Sources: `v1_16_4to1_17/Protocol1_16_4To1_17.java:66–85`; `v1_16_4to1_17/Protocol1_16_4To1_17.java:181` (`addEmptyTags(RegistryType.GAME_EVENT, ...)`).
|
||
|
||
---
|
||
|
||
### Entity data (metadata)
|
||
|
||
**New index 7 — Ticks Frozen** added to the `ENTITY` base class (all entities). Index 7 is a new VarInt field representing how many ticks the entity has been in powder snow.
|
||
|
||
**Pose enum** gained a new value `LONG_JUMP` at index 6 (shifting `FALL_FLYING` from 6 to 7).
|
||
|
||
**Shulker** lost entity data index 17 (`Attachment position`, an optional BlockPos).
|
||
|
||
Sources: `v1_16_4to1_17/rewriter/EntityPacketRewriter1_17.java:171–188`.
|
||
|
||
---
|
||
|
||
### Entity type IDs (ADD_ENTITY / ADD_MOB)
|
||
|
||
Five entities were added, inserted alphabetically, shifting most existing entity type IDs upward:
|
||
|
||
| Entity | New ID (1.17) | Notes |
|
||
|--------|---------------|-------|
|
||
| `axolotl` | 3 | New mob; inserted before `bat` (formerly 3) |
|
||
| `glow_item_frame` | 32 | New entity; subtype of item_frame |
|
||
| `glow_squid` | 33 | New mob; subtype of squid |
|
||
| `goat` | 34 | New mob |
|
||
| `marker` | 49 | New marker entity for command/datapack use |
|
||
|
||
All entities formerly with ID ≥ 3 shift; e.g. `bat` 3→4, `player` 106→111, `fishing_bobber` 107→112. Total entity types: 108 (1.16.2) → 113 (1.17).
|
||
|
||
Sources: minecraft-data `1.17/entities.json` vs `1.16.2/entities.json` (ID diff); `ViaVersion/api/.../entities/EntityTypes1_17.java:144/127/128/154/43`.
|
||
|
||
**Item frame rotation encoding change**
|
||
|
||
The `ADD_ENTITY` packet for item frames changed: 1.16 clients read rotation from the `data` field; 1.17 clients read it from `yaw`/`pitch`. ViaVersion sends a follow-up `MOVE_ENTITY_ROT` packet after `ADD_ENTITY` to supply the rotation when downgrading.
|
||
|
||
Sources: `v1_16_4to1_17/rewriter/EntityPacketRewriter1_17.java:49–71`.
|
||
|
||
---
|
||
|
||
## 1.17.1 — Protocol 755 → 756 (2021-07-06)
|
||
|
||
1.17.1 was a small bug-fix release. Only a handful of protocol changes:
|
||
|
||
### REMOVE_ENTITY → REMOVE_ENTITIES (0x3A)
|
||
|
||
**Reverted.** 1.17 (755) changed the entity-remove packet from an array (1.16) to single-entity (1.17). 1.17.1 reverted this: the packet at 0x3A now carries a **`VarInt[]` array** of entity IDs again (same logical shape as 1.16's array, but with `VarInt` prefix length rather than `Int`).
|
||
|
||
This is reflected in the minecraft-data names: 1.17 has `destroy_entity` (0x3A), 1.17.1 has `entity_destroy` (0x3A). The ViaVersion translator converts the single-ID 1.17 server packet into the array wrapper for 1.17.1 clients.
|
||
|
||
Sources: `v1_17to1_17_1/Protocol1_17To1_17_1.java:47–51` ("Aaaaand back to an array again!"); `v1_17to1_17_1/packet/ClientboundPackets1_17_1.java:82` (`REMOVE_ENTITIES`); minecraft-data `1.17/protocol.json` vs `1.17.1/protocol.json` (0x3A name diff).
|
||
|
||
### CONTAINER_SET_SLOT and CONTAINER_SET_CONTENT — State ID added
|
||
|
||
Both `CONTAINER_SET_SLOT` (0x16) and `CONTAINER_SET_CONTENT` (0x14) gained a new `State ID` field (`VarInt`). The client echoes this value in `CONTAINER_CLICK` to let the server detect desync.
|
||
|
||
- `CONTAINER_SET_SLOT`: state ID inserted between container ID and slot ID.
|
||
- `CONTAINER_SET_CONTENT`: state ID inserted after container ID; item array length encoding changed from `Short` to `VarInt`; a new `Carried item` field (the cursor item, `Slot`) was appended.
|
||
|
||
Sources: `v1_17to1_17_1/rewriter/ItemPacketRewriter1_17_1.java:47–65` (writes `Types.VAR_INT, 0` as placeholder state ID); commit `ddbe8ef0f`.
|
||
|
||
### CONTAINER_CLICK — State ID consumed
|
||
|
||
Serverbound `CONTAINER_CLICK` (0x08) gained a `State ID` VarInt field (read and discarded by ViaVersion when forwarding to older servers).
|
||
|
||
Sources: `v1_17to1_17_1/rewriter/ItemPacketRewriter1_17_1.java:67–83`.
|
||
|
||
### EDIT_BOOK — Format restructured
|
||
|
||
Serverbound `EDIT_BOOK` (0x0B) changed format: previously an item (writable book with NBT pages), now sends pages as a raw `VarInt` count + `String[]` list plus an optional `Boolean`-gated title. ViaVersion reconstructs the old NBT item format from the new wire format.
|
||
|
||
Sources: `v1_17to1_17_1/Protocol1_17To1_17_1.java:53–95`; commit `ddbe8ef0f`.
|
||
|
||
### Enchantment level cap exposed
|
||
|
||
Items with enchantment levels outside [0, 255] were crashing 1.17 clients. 1.17.1 caps display. ViaVersion's downgrade handler hides out-of-range enchantments in lore when translating to older clients.
|
||
|
||
Sources: `v1_17to1_17_1/rewriter/ItemPacketRewriter1_17_1.java:88–103`; commit `2c30a2748`.
|
||
|
||
---
|
||
|
||
## Proxy / Translation Impact
|
||
|
||
**For ViaVersion (older client → 1.17+ server):**
|
||
|
||
1. **Entity type ID remapping** — every `ADD_ENTITY`/`ADD_MOB` entity type ID must be remapped. Proxies must maintain a full 1.16↔1.17 entity type translation table. All IDs ≥ 3 shifted.
|
||
2. **Packet fan-out** — `SET_TITLES`, `SET_BORDER`, `PLAYER_COMBAT` must be split from the old multiplexed format on downgrade (1.17 server → 1.16 client) or collapsed on upgrade.
|
||
3. **REMOVE_ENTITIES ↔ REMOVE_ENTITY** — single-ID vs array format must be translated in both directions. Additionally 1.17.1 reverted back to array, so the proxy must handle three forms across the 755→756 boundary.
|
||
4. **Dimension codec injection** — `min_y` and `height` fields must be injected for 1.17-aware clients even when the server runs 1.16. ViaVersion injects `{min_y: 0, height: 256}` unconditionally.
|
||
5. **Chunk format** — 1.17 chunk type uses BitSet masks; a proxy bridging a 1.16 server must rewrite the chunk bitmask from `Int` to `Long[]` and vice versa. Non-full chunks from 1.16 servers must be converted to multi-block-change sequences.
|
||
6. **Light update** — mask encoding (VarInt → Long[] BitSet) must be translated.
|
||
7. **Tags** — the generic resource-location prefix and game-event registry type must be stripped/injected when bridging 1.16↔1.17.
|
||
8. **RESOURCE_PACK** — `Required` + `Prompt` fields must be added (or stripped) at the boundary.
|
||
9. **Entity data index 7 (Ticks Frozen)** — must be injected (as 0) for all entities when serving 1.17 clients from a 1.16 source, and stripped in the other direction.
|
||
10. **State IDs (1.17.1)** — `CONTAINER_SET_SLOT` / `CONTAINER_SET_CONTENT` / `CONTAINER_CLICK` all carry an extra VarInt state ID in 1.17.1 that must be stripped (downstream) or injected as 0 (upstream) when crossing the 755/756 boundary.
|
||
|
||
ViaVersion commit highlights for this boundary:
|
||
- `aa22ca1d5` — item-frame pitch/yaw→data rotation change
|
||
- `27033e929` — drop CONTAINER_ACK (transaction) tracking
|
||
- `501f65e21` — Mojang-mapped packet/entity type renames
|
||
- `ddbe8ef0f` — CONTAINER_SET_CONTENT/SLOT state IDs (1.17.1)
|
||
- `2c30a2748` — out-of-bounds enchantment lore display (1.17.1)
|