Files
minecraft_protocol/versions/1.17.md
T
claude-timemachine a3d5f64ef5 verify pass: resolve VERIFY flags (corrections + citations + honest UNCONFIRMED)
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>
2026-06-19 15:03:44 +02:00

18 KiB
Raw Blame History

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:110134; v1_16_4to1_17/packet/ClientboundPackets1_17.java:88114; 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:4256; v1_16_4to1_17/packet/ClientboundPackets1_17.java:56/9096.

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:148164; v1_16_4to1_17/packet/ClientboundPackets1_17.java:7577.

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:2729 (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:7386 (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:8792.

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:94108.

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:136145.

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:147153 (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:126132.

Field changes: PLAYER_POSITION (0x38)

New Dismount vehicle Boolean field appended.

Sources: v1_16_4to1_17/rewriter/EntityPacketRewriter1_17.java:134146.


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:155166 (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:196199 (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:102122 (chunk type switch ChunkType1_16_2ChunkType1_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:5899 (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:6685; 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:171188.


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:4971.


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:4751 ("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:4765 (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:6783.

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:5395; 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:88103; 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-outSET_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 injectionmin_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_PACKRequired + 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)