Skip to content

fix(MHPL-518): Hytale 0.6.5 support (hytale/3 ALPN, FormattedMessage strikethrough) - #6

Open
alepaez wants to merge 2 commits into
mainfrom
alexandresequeira/mhpl-518-hytale-0.6.5-alpn
Open

alepaez wants to merge 2 commits into
mainfrom
alexandresequeira/mhpl-518-hytale-0.6.5-alpn

Conversation

@alepaez

@alepaez alepaez commented Sep 10, 2026 •

Copy link
Copy Markdown

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 ProtocolSettings from version 2 / build 100 to version 3 / build 209, and the QUIC ALPN from hytale/2 to hytale/3. The 0.6.5 server jar lists hytale/3 first and keeps hytale/2 only alongside an ALPN_REJECT_ERROR_CODE. hyproxy offered only hytale/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 ServerMessage from the lobby crashed the decoder (readerIndex: -215). Protocol 3 added a nullable strikethrough boolean to FormattedMessage between underlined and link. Fixed block 7 -> 8 bytes, variable block 39 -> 40, and every null bit after underlined shifts by one. Layout read from the 0.6.5 class's get*/has* bytecode; documented in the class javadoc.

What else changed in 0.6.5?

Compared with javap -constants between the previous server jar and 0.6.5:

Result
Packets hyproxy decodes: Connect, ConnectAccept, AuthGrant, AuthToken, ServerAuthToken, ClientReferral, ClientDisconnect, ServerDisconnect, ServerInfo, ServerMessage, ChatMessage, InsecurePlayerOptions, RequestInsecurePlayerOptions same ID and layout
Structs hyproxy decodes: ParamValue family, HostAddress, FormattedMessageImage, PlayerSkin same
FormattedMessage changed, fixed here
Ping, Pong, UpdateServerAccess one byte smaller, forwarded raw
NetworkTick, ConfigureIcePeer new, forwarded raw

Verification

Ran a harness inside the 0.6.5 lobby pod with the real HytaleServer.jar on the classpath: built a FormattedMessage with every field set (nested children, params, messageParams, image, strikethrough=true), serialized it with the official serialize(MemorySegment,int), decoded with this class: all fields match and the reader consumed exactly the 213 bytes. Then the reverse: hyproxy serialize(ByteBuf) output is byte-identical to the official encoding and toObject returns an object equals to the original.

Deployable jar (this on top of #5) is in Minehut/hytale-proxy#9.

https://claude.ai/code/session_01XtwsBnpBmDn6HWnHh1kNuL

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
@alepaez alepaez changed the title fix(MHPL-518): negotiate hytale/3 ALPN for Hytale 0.6.5 clients fix(MHPL-518): Hytale 0.6.5 support (hytale/3 ALPN, FormattedMessage strikethrough) Sep 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants