Files
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

29 KiB
Raw Permalink Blame History

Java Edition 1.9.x — Protocol Deep-Dive

Release Protocol # Release date minecraft-data dir
1.9 107 2016-02-29 data/pc/1.9
1.9.1 108 2016-03-30 data/pc/1.9.1-pre2
1.9.2 109 2016-03-30 data/pc/1.9.2
1.9.3 110 2016-05-10 (no separate mc-data dir; same packets as 1.9.4)
1.9.4 110 2016-05-10 data/pc/1.9.4

Sources: minecraft.wiki release articles (1.9 fetched 2026-06-19, 1.9.1, 1.9.2, 1.9.3, 1.9.4); ViaVersion source at /tmp/mcproto-refs/ViaVersion/; minecraft-data at /tmp/mcproto-refs/minecraft-data/data/pc/.


Headline — the Combat Update

1.9 is the Combat Update, shipping 2016-02-29 after a development stretch that touched nearly every Play-state subsystem. The protocol impact was the largest single-version Play-packet reorganisation since the Netty rewrite in 1.7:

  • 77 Play clientbound packets in 1.9 vs 74 in 1.8 (net +3; the real story is that almost all IDs shifted).
  • 30 Play serverbound packets in 1.9 vs 26 in 1.8 (net +4).
  • The entire CB packet list was renumbered wholesale — no packet kept its 1.8 ID except by coincidence.
  • Four major protocol subsystems arrived at once: dual-hand (off-hand slot), Boss Bar promoted to dedicated packets, teleport-confirm handshake, and vehicle movement packets.

The patch line (108 / 109 / 110) is comparatively quiet: a Login dimension-type fix (108), a connectivity hotfix (109), and a chunk-format extension bundling block-entity NBT into the chunk packet (110 / 1.9.31.9.4).


Protocol changes vs 1.8 — Play state

All IDs below are Play state only. Handshake / Status / Login state packets were unchanged structurally between 1.8 and 1.9 (the Login state SET_COMPRESSION 0x03 packet was moved exclusively into the Play path — see below).

Sources for this section:

  • ViaVersion packet enums: common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/packet/ClientboundPackets1_8.java and ClientboundPackets1_9.java, ServerboundPackets1_8.java, ServerboundPackets1_9.java.
  • minecraft-data data/pc/1.8/protocol.json and data/pc/1.9/protocol.json (cross-check).

Clientbound Play — 1.8 vs 1.9

The table below lists every 1.8 packet by name, its 1.8 ID, and what happened to it in 1.9.

1.8 name 1.8 ID 1.9 name 1.9 ID Notes
keep_alive 0x00 keep_alive 0x1F renumbered
login 0x01 login 0x23 renumbered
chat 0x02 chat 0x0F renumbered
update_time 0x03 update_time 0x44 renumbered
entity_equipment 0x04 entity_equipment 0x3C renumbered; slot field changed: 1.8 used Short (0=hand, 14=armor); 1.9 uses VarInt with expanded enum (0=main hand, 1=off hand, 25=armor)
spawn_position 0x05 spawn_position 0x43 renumbered
update_health 0x06 update_health 0x3E renumbered
respawn 0x07 respawn 0x33 renumbered
position 0x08 position 0x2E renumbered; +VarInt teleport ID appended — the new teleport-confirm field (see below)
held_item_slot 0x09 held_item_slot 0x37 renumbered
bed 0x0A bed 0x2F renumbered
animation 0x0B animation 0x06 renumbered
named_entity_spawn 0x0C named_entity_spawn 0x05 renumbered; +UUID field inserted after entity ID
collect 0x0D collect 0x49 renumbered
spawn_entity 0x0E spawn_entity 0x00 renumbered; +UUID after entity ID; position coords changed from fixed-point Int×(1/32) to Double
spawn_entity_living 0x0F spawn_entity_living 0x03 renumbered; +UUID; coords to Double
spawn_entity_painting 0x10 spawn_entity_painting 0x04 renumbered; +UUID
spawn_entity_experience_orb 0x11 spawn_entity_experience_orb 0x01 renumbered
entity_velocity 0x12 entity_velocity 0x3B renumbered
entity_destroy 0x13 entity_destroy 0x30 renumbered
entity (no-move) 0x14 entity 0x28 renumbered
rel_entity_move 0x15 rel_entity_move 0x25 renumbered; delta values changed from Byte to Short (larger range)
entity_look 0x16 entity_look 0x27 renumbered
entity_move_look 0x17 entity_move_look 0x26 renumbered; delta values Byte→Short
entity_teleport 0x18 entity_teleport 0x4A renumbered; position changed from Int×(1/32) to Double; +on-ground Boolean
entity_head_rotation 0x19 entity_head_rotation 0x34 renumbered
entity_status 0x1A entity_status 0x1B renumbered
attach_entity 0x1B attach_entity 0x3A renumbered; leash Boolean field removed in 1.9 (1.7/1.8 had leash:bool; 1.9 attach_entity has only entityId:i32 + vehicleId:i32); riding now handled by set_passengers (0x40). (Confirmed from packet_attach_entity in minecraft-data/data/pc/1.8/protocol.json vs data/pc/1.9/protocol.json.)
entity_metadata 0x1C entity_metadata 0x39 renumbered; metadata format revised (new EntityDataTypes1_9)
entity_effect 0x1D entity_effect 0x4C renumbered
remove_entity_effect 0x1E remove_entity_effect 0x31 renumbered
experience 0x1F experience 0x3D renumbered
update_attributes 0x20 entity_update_attributes 0x4B renumbered
map_chunk 0x21 map_chunk 0x20 renumbered; chunk wire format changed to ChunkType1_9_1 (direct length-prefixed sections, no bulk; light separate)
multi_block_change 0x22 multi_block_change 0x10 renumbered
block_change 0x23 block_change 0x0B renumbered
block_action 0x24 block_action 0x0A renumbered
block_break_animation 0x25 block_break_animation 0x08 renumbered
map_chunk_bulk 0x26 (removed) eliminated; servers send individual map_chunk per column instead
explosion 0x27 explosion 0x1C renumbered
world_event 0x28 world_event 0x21 renumbered; effect ID values remapped
named_sound_effect 0x29 named_sound_effect 0x19 renumbered; +sound category VarInt inserted after name; position encoding changed to Int×8
world_particles 0x2A world_particles 0x22 renumbered
game_state_change 0x2B game_state_change 0x1E renumbered
spawn_entity_weather 0x2C spawn_entity_weather 0x02 renumbered (lightning bolt)
open_window 0x2D open_window 0x13 renumbered
close_window 0x2E close_window 0x12 renumbered
set_slot 0x2F set_slot 0x16 renumbered
window_items 0x30 window_items 0x14 renumbered
craft_progress_bar 0x31 craft_progress_bar 0x15 renumbered
transaction 0x32 transaction 0x11 renumbered
update_sign 0x33 update_sign 0x46 renumbered (removed in 1.9.4 — replaced by block entity data; see §110)
map 0x34 map 0x24 renumbered
tile_entity_data 0x35 tile_entity_data 0x09 renumbered
open_sign_entity 0x36 open_sign_entity 0x2A renumbered
statistics 0x37 statistics 0x07 renumbered
player_info 0x38 player_info 0x2D renumbered; display name field type changed String→optional JSON component
abilities 0x39 abilities 0x2B renumbered
tab_complete 0x3A tab_complete 0x0E renumbered
scoreboard_objective 0x3B scoreboard_objective 0x3F renumbered
scoreboard_score 0x3C scoreboard_score 0x42 renumbered
scoreboard_display_objective 0x3D scoreboard_display_objective 0x38 renumbered
scoreboard_team 0x3E teams 0x41 renumbered; +collision rule field added to mode 0/2
custom_payload 0x3F custom_payload 0x18 renumbered
kick_disconnect 0x40 kick_disconnect 0x1A renumbered; reason field changed String→JSON component
difficulty 0x41 difficulty 0x0D renumbered
combat_event 0x42 combat_event 0x2C renumbered
camera 0x43 camera 0x36 renumbered
world_border 0x44 world_border 0x35 renumbered
title 0x45 title 0x45 same ID
set_compression 0x46 (removed from Play) absorbed: 1.9 handles compression entirely in Login state; 1.8 servers sent this during Play, ViaVersion intercepts and discards it
playerlist_header 0x47 playerlist_header 0x48 renumbered
resource_pack_send 0x48 resource_pack_send 0x32 renumbered
update_entity_nbt 0x49 (removed) dropped; ViaVersion cancels it

New in 1.9 (no 1.8 equivalent):

1.9 name 1.9 ID Description
boss_bar 0x0C First-class boss bar packet with UUID + action enum (add/remove/update health/update title/update style/update flags). In 1.8 boss bar was emulated via entity data on WitherBoss/EnderDragon entities. ViaVersion provides a BossBarProvider to translate old entity-data-based bars to the new packet for downstream 1.9 clients.
set_cooldown 0x17 Item use cooldown — VarInt item ID + VarInt cooldown ticks. New with the attack-speed system.
sound_effect 0x47 Numeric sound ID (VarInt) + category + fixed-point position + volume + pitch. Complements named_sound_effect (0x19) which keeps the string-name form.
unload_chunk 0x1D Explicit chunk unload (Int chunkX, Int chunkZ). In 1.8 unload was signalled by a map_chunk with bitmask=0; ViaVersion converts the old form to this packet.
vehicle_move 0x29 Server→client vehicle position sync (Double x/y/z + Float yaw/pitch).
set_passengers 0x40 Replaces the old riding field in attach_entity; carries a VarInt[] of passenger entity IDs.

Sources: ViaVersion ClientboundPackets1_8.java and ClientboundPackets1_9.java (ordinal = packet ID); WorldPacketRewriter1_9.java:197 (MAP_BULK_CHUNK cancel), WorldPacketRewriter1_9.java:140 (unload-chunk emit), PlayerPacketRewriter1_9.java:332 (SET_COMPRESSION cancel), EntityPacketRewriter1_9.java:258 (UPDATE_ENTITY_NBT cancel), EntityPacketRewriter1_9.java:83 (SET_PASSENGERS emit).


Serverbound Play — 1.8 vs 1.9

1.8 name 1.8 ID 1.9 name 1.9 ID Notes
keep_alive 0x00 keep_alive 0x0B renumbered
chat 0x01 chat 0x02 renumbered
use_entity 0x02 use_entity 0x0A renumbered; +hand VarInt appended
flying 0x03 flying 0x0F renumbered
position 0x04 position 0x0C renumbered
look 0x05 look 0x0E renumbered
position_look 0x06 position_look 0x0D renumbered
block_dig 0x07 block_dig 0x13 renumbered
block_place 0x08 block_place / use_item 0x1C / 0x1D split into two packets: use_item_on (0x1C, block interaction) and use_item (0x1D, general item use in hand). Each now carries a hand VarInt (0=main, 1=off).
held_item_slot 0x09 held_item_slot 0x17 renumbered
arm_animation 0x0A arm_animation 0x1A renumbered; +hand VarInt
entity_action 0x0B entity_action 0x14 renumbered
steer_vehicle 0x0C steer_vehicle 0x15 renumbered
close_window 0x0D close_window 0x08 renumbered
window_click 0x0E window_click 0x07 renumbered
transaction 0x0F transaction 0x05 renumbered
set_creative_slot 0x10 set_creative_slot 0x18 renumbered
enchant_item 0x11 enchant_item 0x06 renumbered
update_sign 0x12 update_sign 0x19 renumbered
abilities 0x13 abilities 0x12 renumbered
tab_complete 0x14 tab_complete 0x01 renumbered; +Boolean "is command block" field removed in 1.9 (ViaVersion reads and discards it from 1.9 clients before forwarding to 1.8 servers)
settings 0x15 settings 0x04 renumbered; +hand VarInt appended (main-hand preference)
client_command 0x16 client_command 0x03 renumbered
custom_payload 0x17 custom_payload 0x09 renumbered
spectate 0x18 spectate 0x1B renumbered
resource_pack_receive 0x19 resource_pack_receive 0x16 renumbered

New in 1.9 (no 1.8 equivalent):

1.9 name 1.9 ID Description
teleport_confirm 0x00 Client acknowledges a PLAYER_POSITION (0x2E) by echoing its VarInt teleport ID. 1.8 servers do not send or expect this; ViaVersion cancels it when translating down. Source: PlayerPacketRewriter1_9.java:382 (protocol.cancelServerbound(ServerboundPackets1_9.ACCEPT_TELEPORTATION)).
vehicle_move 0x10 Client→server vehicle position update (Double x/y/z + Float yaw/pitch). Cancelled by ViaVersion when translating down to 1.8. Source: PlayerPacketRewriter1_9.java:383.
steer_boat 0x11 Two Booleans: left paddle turning, right paddle turning. New for boats redesign. Cancelled by ViaVersion. Source: PlayerPacketRewriter1_9.java:384 (cancelServerbound(PADDLE_BOAT)).
use_item 0x1D Use held item without targeting a block (e.g. eat food, throw ender pearl). Carries hand VarInt. ViaVersion translates to a synthetic block_place at position 1,1,1 face 255. Source: WorldPacketRewriter1_9.java:314.

Sources: ViaVersion ServerboundPackets1_8.java, ServerboundPackets1_9.java; PlayerPacketRewriter1_9.java:375,382384; WorldPacketRewriter1_9.java:314,370.


Key data-format changes

Teleport-confirm round-trip

PLAYER_POSITION (CB 0x2E) gains a trailing VarInt teleportId field. The client must reply with ACCEPT_TELEPORTATION (SB 0x00) carrying the same ID before the server will accept further movement packets. This prevents the classic 1.8 rubber-band exploit where a lagging client could ignore server position corrections.

ViaVersion approach for 1.8 servers: inject a fake teleport ID of 0 into every PLAYER_POSITION sent downward; cancel all ACCEPT_TELEPORTATION packets from 1.9 clients (they mean nothing to a 1.8 server). Source: PlayerPacketRewriter1_9.java:102116 (add create(Types.VAR_INT, 0) to PLAYER_POSITION), line 382 (cancel ACCEPT_TELEPORTATION).

Dual-hand (off-hand slot)

Several packets gained a hand VarInt discriminator (0=main, 1=off):

  • SB use_entity — which hand interacted.
  • SB arm_animation — which arm swings.
  • SB use_item_on / use_item — which hand placed / used item.
  • SB settings (CLIENT_INFORMATION) — new VarInt for main-hand preference (0=left, 1=right).

CB entity_equipment slot encoding expanded: 1.8 Short (0=hand, 14=armor) → 1.9 VarInt (0=main hand, 1=off hand, 25=armor). ViaVersion translates the old Short to the new VarInt, remapping armor slots by +1 and handling the self-entity edge case. Source: EntityPacketRewriter1_9.java:157205.

Boss Bar

CB boss_bar (0x0C) is a new multiplexed packet with action=VarInt:

  • 0 = add (UUID + title JSON + health float + color VarInt + division VarInt + flags Byte)
  • 1 = remove (UUID)
  • 2 = update health
  • 3 = update title
  • 4 = update style
  • 5 = update flags

In 1.8, boss-bar appearance was achieved by spawning WitherBoss / EnderDragon entities whose health controlled the bar. ViaVersion's EntityTracker1_9.java (lines 243273) reverse-engineers entity metadata updates for those entity types and synthesises the new BOSS_EVENT packet for 1.9+ clients connecting to 1.8 servers, using the BossBarProvider abstraction.

Sound system split

1.9 introduces two parallel sound mechanisms:

  • CB named_sound_effect (0x19) — string name (namespaced resource location) + category VarInt + fixed-point position (Int×8) + volume + pitch. Wire format changed from 1.8 (no category, string-only position). ViaVersion injects category and reformats position. Source: WorldPacketRewriter1_9.java:96130.
  • CB sound_effect (0x47) — numeric sound ID (VarInt) + same remaining fields as named. New packet type absent from 1.8 entirely.

Chunk format — ChunkType1_9_1

The 1.8 map_chunk_bulk (0x26) packet is gone; all chunk data is sent as individual map_chunk (0x20) packets. The chunk data section encoding changed to ChunkType1_9_1:

  • Sections are length-prefixed in a single VAR_INT-prefixed byte array.
  • Block light and sky light are appended per section directly after palette+data.
  • Biome array (256 bytes) follows all sections for full-chunk packets.
  • No embedded block-entity NBT (confirmed: packet_map_chunk in minecraft-data/data/pc/1.9/protocol.json has fields x, z, groundUp, bitMap, chunkData only — no blockEntities array; that field was added in 1.9.4 / protocol 110 and is present in data/pc/1.9.4/protocol.json). Block entity data arrives via separate tile_entity_data (0x09) packets or is synthesised by ViaVersion's FakeTileEntities when translating 1.9 chunks for 1.9.3+ clients.

Source: ViaVersion/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkType1_9_1.java.

Entity coordinate precision

Entity spawn positions changed from 1.8 fixed-point integer (value/32 = world coord) to IEEE 754 Double. ViaVersion applies the /32 transform when translating ADD_ENTITY / ADD_MOB down to 1.8. Source: SpawnPacketRewriter1_9.java:6062 (map(Types.INT, toNewDouble) where toNewDouble = inputValue / 32D).

Entity metadata format

ENTITY_DATA_LIST1_8ENTITY_DATA_LIST1_9: the index/type packing changed, and the type tag set was revised (new types for optional UUID, VarInt enum, etc.). ViaVersion performs full metadata translation in EntityPacketRewriter1_9.java. The EntityDataTypes1_9 type set is referenced in SpawnPacketRewriter1_9.java:26.

Removed: update_entity_nbt (CB 0x49)

The 1.8 packet that sent arbitrary NBT for an entity (used by command blocks to sync state) was removed. ViaVersion cancels it: EntityPacketRewriter1_9.java:258. Functionality moved to the block-entity / custom-payload path.

Removed: Play-state set_compression

In 1.8, the server could send set_compression (0x46) during the Play state. In 1.9 compression is negotiated exclusively in Login state (as it had always been intended). ViaVersion intercepts the 1.8 Play-state set_compression, sets the compression threshold on the connection, and cancels the packet so the 1.9 client never sees it. Source: PlayerPacketRewriter1_9.java:332340.


Per-patch sub-sections

Protocol 107 — 1.9 (2016-02-29)

The full 1.8→1.9 translation lives in:

common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/
  Protocol1_8To1_9.java            — entry point; registers rewriters + providers
  rewriter/PlayerPacketRewriter1_9.java
  rewriter/EntityPacketRewriter1_9.java
  rewriter/ItemPacketRewriter1_9.java
  rewriter/SpawnPacketRewriter1_9.java
  rewriter/WorldPacketRewriter1_9.java
  packet/ClientboundPackets1_9.java
  packet/ServerboundPackets1_9.java

Selected ViaVersion commits for this package (from git -C /tmp/mcproto-refs/ViaVersion log --oneline -- common/…/v1_8to1_9):

Commit Subject
0b5fa37f9 Put title directly into component in 1.8→1.9 bossbar emulation
73286fd94 Send op permission level 4 in 1.8→1.9
08b921729 Fix entity defaults across all protocols
75c666266 Sword blocking: consumables for 1.21.4+, back to shields for 1.20.51.21.3
e0a7b70e3 Fix 1.8/1.9 thrown potion entity data handling
e436bbe37 Refactor dimension switch handling across all protocols
501f65e21 Packet and entity type renames (Mojang-mapped names)

Key protocol facts established at 107:

  • 77 CB / 30 SB Play packets.
  • Teleport-confirm round-trip mandatory.
  • boss_bar 0x0C, set_cooldown 0x17, sound_effect 0x47, unload_chunk 0x1D, vehicle_move 0x29, set_passengers 0x40 all new.
  • map_chunk_bulk, update_entity_nbt, Play-state set_compression all removed.

Protocol 108 — 1.9.1 (2016-03-30)

ViaVersion package: protocols/v1_9to1_9_1/Protocol1_9To1_9_1.java

This package is a single file with two packet handlers:

1. LOGIN — dimension field type change.

// Protocol1_9To1_9_1.java:4048
map(Types.INT);           // 0 - Player ID
map(Types.UNSIGNED_BYTE); // 1 - Player Gamemode
// 1.9.1 PRE 2 Changed this
map(Types.BYTE, Types.INT); // 2 - Player Dimension  ← Byte in 1.9, Int in 1.9.1

The LOGIN packet's dimension field widened from Byte to Int. ViaVersion automatically converts the Int sent by a 1.9.1 server back to a Byte for any 1.9 client still connecting. Source: Protocol1_9To1_9_1.java:4048.

2. SOUND — Elytra sound ID insertion.

// Protocol1_9To1_9_1.java:5163
if (sound >= 415) // Add 1 since there is no Elytra sound on a 1.9 server
    wrapper.set(Types.VAR_INT, 0, sound + 1);

1.9.1 inserted the Elytra wing-flap sound into the sound registry at ID 415, shifting all higher numeric IDs up by one. Any sound_effect packet from a 1.9.1+ server with ID ≥ 415 must have its ID decremented by one when sent to a 1.9 client, and incremented when the reverse applies. Source: Protocol1_9To1_9_1.java:5859.

All other Play packets (IDs, fields, format) are identical between 107 and 108 — the packet enum used by Protocol1_9To1_9_1 is still ClientboundPackets1_9 / ServerboundPackets1_9 with no new packet types. Source: Protocol1_9To1_9_1.java:26.

mc-wiki: 1.9.1 was superseded by 1.9.2 the same day due to a multiplayer bug; historically short-lived. (minecraft.wiki/w/Java_Edition_1.9.1, fetched 2026-06-19.)

ViaVersion git log for v1_9to1_9_1 (shallow clone — limited history): cff9a8715 (copyright), 9f6e7fa4e (copyright), 75d86851c (IJ reformat + rewriter renames), 501f65e21 (packet/entity renames), e965e9713 (package renames).

Protocol 109 — 1.9.2 (2016-03-30)

1.9.2 was a same-day connectivity hotfix replacing 1.9.1. No new ViaVersion package exists for the 1.9.1→1.9.2 bump — Protocol1_9To1_9_1.java covers "1.9.1 and 1.9.2" (comment at line 34: "// Currently supports 1.9.1 and 1.9.2"). The packet set at protocol 109 is identical to 108: same 77 CB / 30 SB Play packets, same IDs.

minecraft-data: data/pc/1.9.2/version.json{"version":109,"minecraftVersion":"1.9.2","majorVersion":"1.9"}. Packet list identical to 1.9 (protocol.json diff produces no changes). Source: minecraft-data data/pc/1.9.2/.

mc-wiki notes a connectivity issue with 1.9.1 servers was fixed; 7 bugs resolved total. No wire-protocol changes. (minecraft.wiki/w/Java_Edition_1.9.2, fetched 2026-06-19.)

Protocol 110 — 1.9.3 and 1.9.4 (2016-05-10)

ViaVersion package: protocols/v1_9_1to1_9_3/

Protocol1_9_1To1_9_3.java
packet/ClientboundPackets1_9_3.java
packet/ServerboundPackets1_9_3.java

1.9.3 and 1.9.4 share protocol number 110. 1.9.3 shipped and was replaced on the same day because it incorrectly showed a "you're running a snapshot" warning for old world saves. The actual protocol changes are in 1.9.3/1.9.4 together.

Chunk format: ChunkType1_9_1 → ChunkType1_9_3

The single largest change: the map_chunk (0x20) payload now appends a CompoundTag[] (NBT array) of block entities after the existing section data. This means the receiver no longer needs to request separate tile_entity_data packets for blocks in newly loaded chunks.

// ChunkType1_9_3.java:89
List<CompoundTag> nbtData = new ArrayList<>(
    Arrays.asList(Types.NAMED_COMPOUND_TAG_ARRAY.read(input)));
return new BaseChunk(chunkX, chunkZ, fullChunk, false,
    primaryBitmask, sections, biomeData, nbtData);

// write side: ChunkType1_9_3.java:127
Types.NAMED_COMPOUND_TAG_ARRAY.write(output,
    chunk.getBlockEntities().toArray(new CompoundTag[0]));

ViaVersion's Protocol1_9_1To1_9_3.java:89113 translates this: when receiving a LEVEL_CHUNK from a 1.9/1.9.2 server (no embedded NBT), it walks the block palette looking for blocks that are tile entities (FakeTileEntities1_9_1.isTileEntity(id)) and synthesises placeholder CompoundTag entries so the 1.9.3+ client gets the required array. Source: Protocol1_9_1To1_9_3.java:89113; chunk type classes ChunkType1_9_1.java and ChunkType1_9_3.java.

update_sign removed from Play packet list

In 1.9 the CB update_sign packet existed at 0x46. In 1.9.3/1.9.4 it is absent from the packet list (76 CB packets vs 77 in 1.9). Sign data is instead conveyed via tile_entity_data (0x09) with action=9. ViaVersion Protocol1_9_1To1_9_3.java:6187 translates an UPDATE_SIGN from a 1.9 server into a BLOCK_ENTITY_DATA packet with the sign lines serialised as NBT Text1Text4 strings. Source: Protocol1_9_1To1_9_3.java:6187.

Sound pitch scaling change

The SOUND packet pitch field encoding changed:

// Protocol1_9_1To1_9_3.java:4751
public static final ValueTransformer<Short, Short> ADJUST_PITCH =
    new ValueTransformer<>(Types.UNSIGNED_BYTE, Types.UNSIGNED_BYTE) {
        public Short transform(PacketWrapper wrapper, Short inputValue) {
            return (short) Math.round(inputValue / 63.5F * 63.0F);
        }
    };

Applied to every SOUND packet at Protocol1_9_1To1_9_3.java:143154. The denominator changed from 63.5 to 63.0 (a subtle range normalisation).

LOGIN and RESPAWN — dimension tracking

Both packets are handled to keep the proxy's ClientWorld dimension-tracking in sync, since dimension determines sky-light presence in chunk packets. No field changes. Source: Protocol1_9_1To1_9_3.java:115140.

Serverbound: no changes

ServerboundPackets1_9_3 is byte-for-byte identical to ServerboundPackets1_9 (same 30 packets, same IDs). Source: v1_9_1to1_9_3/packet/ServerboundPackets1_9_3.java.

ViaVersion git log for v1_9_1to1_9_3 (shallow): cff9a8715 (copyright), fd5dadbe0 (clean imports), e436bbe37 (dimension switch refactor), c5756fe45 (BlockPosition rename), 75d86851c (reformat), 501f65e21 (packet/entity renames), e965e9713 (package renames).

mc-wiki: 1.9.3 introduced Netty blockedservers check and memory-use fixes for pathfinding/biome caching; 1.9.4 fixed the snapshot warning and 5 additional bugs. (minecraft.wiki/w/Java_Edition_1.9.3, 1.9.4, fetched 2026-06-19.)


Proxy and translation impact

What a 1.9-aware proxy must handle at protocol 107 (largest workload)

  1. Full play-state packet ID remapping — every packet from a 1.8 server must be renumbered before forwarding to a 1.9 client, and vice versa.
  2. Teleport-confirm injection — proxy must synthesise a teleport ID (e.g. 0) and append it to every PLAYER_POSITION forwarded to 1.9 clients; must swallow all ACCEPT_TELEPORTATION from those clients before they reach a 1.8 server.
  3. Boss Bar emulation — for 1.9 clients on 1.8 servers: track Wither/EnderDragon entity metadata and synthesise BOSS_EVENT packets. Requires an entity tracker.
  4. Chunk format translation — 1.8 sends MAP_BULK_CHUNK; proxy must split into individual MAP_CHUNK packets encoded as ChunkType1_9_1. 1.8 unload-via-bitmask=0 must become FORGET_LEVEL_CHUNK.
  5. Dual-hand shimUSE_ITEM (SB 0x1D) has no 1.8 equivalent; proxy synthesises a BLOCK_PLACE at pos 1,1,1 face 255; off-hand USE_ITEM_ON packets are cancelled. SWING loses its hand argument.
  6. Sound category insertion — 1.8's NAMED_SOUND_EFFECT lacks the sound category field; proxy must inject a category VarInt.
  7. Entity coordinate conversion — Double → Int×32 for spawn packets going toward 1.8 servers; Int/32 → Double for spawn packets coming from 1.8 servers.
  8. Entity-equipment slot remapping — old Short (0=hand, 14=armor) ↔ new VarInt (0=main, 1=off, 25=armor).
  9. Component type upgrades — disconnect reason, title text, player_info display name, tab-list header/footer: String → JSON component.
  10. SET_COMPRESSION absorption — Play-state compression packet from 1.8 servers must not reach 1.9 clients.

Additional at protocol 108/109

  • Rewrite LOGIN dimension field: Int (1.9.1 server) ↔ Byte (1.9 client).
  • Remap SOUND IDs ≥ 415 (+1 when going server→1.9 client against a 1.9.1+ server).

Additional at protocol 110 (1.9.3/1.9.4)

  • Chunk format upgrade: strip embedded CompoundTag[] from incoming 1.9.3 chunk packets when forwarding to 1.9/1.9.2 clients; or synthesise fake tile-entity NBT when forwarding 1.9-server chunks to 1.9.3+ clients.
  • UPDATE_SIGNBLOCK_ENTITY_DATA: translate sign update packet in either direction depending on server/client version.
  • Sound pitch rescaling: apply round(p / 63.5 × 63.0) when bridging 1.9.1/1.9.2 ↔ 1.9.3/1.9.4.

ViaVersion handles all of the above via the three packages v1_8to1_9, v1_9to1_9_1, v1_9_1to1_9_3 described throughout this document.