Transport Layer
Hytale primarily uses QUIC over UDP for client-server communication, with TCP as a fallback option. Both transports use the same packet protocol on top.
QUIC Transport
Section titled “QUIC Transport”QUIC (Quick UDP Internet Connections) is the primary transport protocol, providing:
- Low latency: 0-RTT or 1-RTT connection establishment
- Multiplexing: Multiple streams without head-of-line blocking
- Built-in encryption: TLS 1.3 integrated into the protocol
- Connection migration: Survives IP/port changes
- Congestion control: BBR algorithm for optimal throughput
ALPN Protocol
Section titled “ALPN Protocol”The Application-Layer Protocol Negotiation identifier is:
hytale/1TLS Requirements
Section titled “TLS Requirements”| Setting | Value | Notes |
|---|---|---|
| Client Auth | Required | Mutual TLS (mTLS) |
| Early Data (0-RTT) | Disabled | Security measure |
| Min TLS Version | 1.3 | Via QUIC |
Certificate
Section titled “Certificate”The server generates a self-signed certificate at startup. The certificate’s SHA-256 fingerprint is sent to the session service during authentication and used by clients to verify the server’s identity.
TCP Transport
Section titled “TCP Transport”TCP is available as a fallback for environments that block UDP. It provides:
- Compatibility with restrictive firewalls
- Reliable ordered delivery
- Standard TLS encryption
TCP lacks QUIC’s multiplexing and connection migration benefits.
Dual-Stack Support
Section titled “Dual-Stack Support”Both IPv4 and IPv6 are supported. The server binds to both protocol families with:
| Option | Value | Purpose |
|---|---|---|
SO_REUSEADDR | true | Allow port reuse after restart |
IP_DONTFRAGMENT | true | Prevent IP-level fragmentation (IPv4) |
Connection Lifecycle
Section titled “Connection Lifecycle”Timeouts
Section titled “Timeouts”| Phase | Timeout | Behavior |
|---|---|---|
| Auth grant | 30s | Disconnect if no response |
| Auth token | 30s | Disconnect if client doesn’t respond |
| Server token exchange | 15s | Disconnect on failure |
| Idle (playing) | Configurable | Ping/pong keeps alive |
Disconnect
Section titled “Disconnect”Connections can be closed gracefully or forcefully:
| Type | Value | Description |
|---|---|---|
Disconnect | 0 | Normal disconnect with reason message |
Crash | 1 | Client crashed |
A graceful disconnect sends a Disconnect packet (ID 1) with a reason string before closing the connection.
Channel Pipeline
Section titled “Channel Pipeline”The server uses a Netty channel pipeline with these handlers:
Inbound: Network -> timeout -> decoder -> handlerOutbound: handler -> encoder -> Network| Handler | Class | Purpose |
|---|---|---|
timeout | ReadTimeoutHandler | Disconnects idle connections |
decoder | PacketDecoder | Parses framed bytes to Packet objects |
encoder | PacketEncoder | Serializes Packet objects to framed bytes |
handler | PacketHandler | Protocol logic (auth, game, etc.) |
Mods can insert custom handlers into the pipeline to intercept, modify, or inject packets.
Example: Packet Filtering
Section titled “Example: Packet Filtering”Hytale provides a PacketAdapters API for intercepting packets without modifying the pipeline directly:
public class PacketFilterPlugin extends PluginBase { private PacketFilter filter;
@Override public void setup() { // register inbound packet filter filter = PacketAdapters.registerInbound((handler, packet) -> { // return true to DROP the packet, false to allow if (packet instanceof SomePacket p) { return !isValid(p); // drop invalid packets } return false; }); }
@Override public void shutdown() { // clean up on plugin unload if (filter != null) { PacketAdapters.deregisterInbound(filter); } }}For player-specific filtering:
PacketAdapters.registerInbound((PlayerPacketFilter) (player, packet) -> { // access player context if (player.hasPermission("bypass.filter")) { return false; // allow } return shouldDrop(packet);});Filter types:
PacketFilter- Filter any packetPacketWatcher- Observe packets without filteringPlayerPacketFilter- Filter with player contextPlayerPacketWatcher- Observe with player context
Directions:
PacketAdapters.registerInbound(...)- client to server packetsPacketAdapters.registerOutbound(...)- server to client packets