Conversation
Hytale 0.6.5 bumped the protocol to version 3 (build 209) and the QUIC ALPN from "hytale/2" to "hytale/3". A 0.6.5 client cannot negotiate "hytale/2" with the proxy, fails the QUIC handshake, and reports the server as outdated before any packet is exchanged; the proxy and the lobby log nothing. Compared the 0.6.5 server jar against the previous one: every packet this proxy decodes (Connect, ConnectAccept, AuthGrant, AuthToken, ServerAuthToken, ClientReferral, ClientDisconnect, ServerDisconnect, ServerInfo, ServerMessage, ChatMessage, InsecurePlayerOptions, RequestInsecurePlayerOptions) has the same PACKET_ID and block layout. Only Ping/Pong/UpdateServerAccess shrank by a byte and NetworkTick is new; all of those are forwarded raw. So only the ALPN string changes, now a single constant used for both the client listener and the backend connection. Claude-Session: https://claude.ai/code/session_01XtwsBnpBmDn6HWnHh1kNuL
With the hytale/3 ALPN in place, the first ServerMessage from a 0.6.5 lobby crashed the decoder (readerIndex -215). Protocol 3 added a nullable strikethrough boolean to FormattedMessage between underlined and link: the fixed block grew from 7 to 8 bytes (variable block now at 40), strikethrough takes null bit 0x10 in byte 0, and every following null bit shifts by one (rawText 0x20, messageId 0x40, children 0x80; byte 1: params 0x1, messageParams 0x2, color 0x4, link 0x8, image 0x10). Layout taken from the 0.6.5 server's FormattedMessage getters/has* bytecode. Verified by serializing a message with the real 0.6.5 protocol classes (all fields set, nested children/params/messageParams/image) and decoding it with this class, then the reverse; every field matches and hyproxy's serialize output is byte-identical to the official encoder. All other structs this proxy decodes (ParamValue family, HostAddress, FormattedMessageImage, PlayerSkin) are unchanged in 0.6.5. Claude-Session: https://claude.ai/code/session_01XtwsBnpBmDn6HWnHh1kNuL
VictorLopess
approved these changes
Sep 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
After Hytale 0.6.5 shipped today, clients report the server as outdated. The lobby is on 0.6.5, and neither the proxy nor the lobby logged a single connection attempt, so the client gave up before the game handshake.
Cause 1: ALPN
0.6.5 bumped
ProtocolSettingsfrom version 2 / build 100 to version 3 / build 209, and the QUIC ALPN fromhytale/2tohytale/3. The 0.6.5 server jar listshytale/3first and keepshytale/2only alongside anALPN_REJECT_ERROR_CODE. hyproxy offered onlyhytale/2, so the QUIC handshake failed. Now one constant,ProtocolUtil.ALPN, used by the client listener and the backend connection.Cause 2: FormattedMessage grew a field
With the ALPN fixed, auth and forwarding worked, then the first
ServerMessagefrom the lobby crashed the decoder (readerIndex: -215). Protocol 3 added a nullablestrikethroughboolean toFormattedMessagebetweenunderlinedandlink. Fixed block 7 -> 8 bytes, variable block 39 -> 40, and every null bit afterunderlinedshifts by one. Layout read from the 0.6.5 class'sget*/has*bytecode; documented in the class javadoc.What else changed in 0.6.5?
Compared with
javap -constantsbetween the previous server jar and 0.6.5:Verification
Ran a harness inside the 0.6.5 lobby pod with the real
HytaleServer.jaron the classpath: built aFormattedMessagewith every field set (nested children, params, messageParams, image, strikethrough=true), serialized it with the officialserialize(MemorySegment,int), decoded with this class: all fields match and the reader consumed exactly the 213 bytes. Then the reverse: hyproxyserialize(ByteBuf)output is byte-identical to the official encoding andtoObjectreturns an objectequalsto the original.Deployable jar (this on top of #5) is in Minehut/hytale-proxy#9.
https://claude.ai/code/session_01XtwsBnpBmDn6HWnHh1kNuL