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>
18 KiB
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 afterEntity ID. Absent in the 1.16 LOGIN packet (confirmed:minecraft-data/data/pc/1.16/loginPacket.jsonhas noisHardcorekey;1.17/loginPacket.jsonhas it). ViaVersion maps it atEntityPacketRewriter1_17.java:92.Simulation Distance— added in 1.18, not 1.17. Confirmed:minecraft-data/data/pc/1.17/loginPacket.jsonlistsviewDistancebut has nosimulationDistancefield;data/pc/1.18/loginPacket.jsonadds it immediately afterviewDistance. ViaVersionEntityPacketRewriter1_18.java:57-58injects it as a copy ofviewDistancewhen 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 fromShorttoVarInt; a newCarried itemfield (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):
- Entity type ID remapping — every
ADD_ENTITY/ADD_MOBentity type ID must be remapped. Proxies must maintain a full 1.16↔1.17 entity type translation table. All IDs ≥ 3 shifted. - Packet fan-out —
SET_TITLES,SET_BORDER,PLAYER_COMBATmust be split from the old multiplexed format on downgrade (1.17 server → 1.16 client) or collapsed on upgrade. - 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.
- Dimension codec injection —
min_yandheightfields must be injected for 1.17-aware clients even when the server runs 1.16. ViaVersion injects{min_y: 0, height: 256}unconditionally. - Chunk format — 1.17 chunk type uses BitSet masks; a proxy bridging a 1.16 server must rewrite the chunk bitmask from
InttoLong[]and vice versa. Non-full chunks from 1.16 servers must be converted to multi-block-change sequences. - Light update — mask encoding (VarInt → Long[] BitSet) must be translated.
- Tags — the generic resource-location prefix and game-event registry type must be stripped/injected when bridging 1.16↔1.17.
- RESOURCE_PACK —
Required+Promptfields must be added (or stripped) at the boundary. - 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.
- State IDs (1.17.1) —
CONTAINER_SET_SLOT/CONTAINER_SET_CONTENT/CONTAINER_CLICKall 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 change27033e929— drop CONTAINER_ACK (transaction) tracking501f65e21— Mojang-mapped packet/entity type renamesddbe8ef0f— CONTAINER_SET_CONTENT/SLOT state IDs (1.17.1)2c30a2748— out-of-bounds enchantment lore display (1.17.1)