OneQuery: Open-Source Server Query Plugin for Hytale

HytaleONE Team
· · 7 min read
OneQuery plugin logo and small description

If you run a Hytale server - or plan to - you’ll eventually need a way to expose your servers status to the outside (or maybe to your own internal applications). Player count, server name, MOTD, online players. Monitoring tools, server lists, and maybe Discord bots all need this data.

That is what OneQuery solves. It is an open-source Hytale server plugin that adds a lightweight UDP query protocol to your server, letting external applications fetch real-time status without HTTP overhead, extra ports, or external dependencies.

We built it, we use it to power the HytaleONE server list, and we’re giving it away for free.


In this article: Why Not HTTP? · How It Works · Network Mode · Installation · Server List Registration · Future · Source Code


Why Not Just Use HTTP?

Most game server query systems use HTTP or TCP. That works, but it comes with tradeoffs:

  • Connection overhead - TCP handshakes add latency for simple status checks
  • Port conflicts - Separate HTTP listeners need separate ports and firewall rules

OneQuery uses UDP on the same port as your game server (default 5520). No extra ports, no extra processes. A status query is a single request-response pair that completes in milliseconds.

How OneQuery Works

The plugin hooks into your Hytale server’s Netty pipeline and intercepts incoming UDP packets that match the OneQuery protocol signature. Everything else passes through untouched - your game traffic is never affected.

The Query Protocol (V2)

OneQuery V2 uses a compact binary protocol with a simple structure:

Request:  "ONEQUERY" magic (8 bytes) + version + flags + request ID + payload
Response: "ONEREPLY" magic (8 bytes) + version + flags + request ID + payload

Every response fits within a single UDP packet (max 1400 bytes) to avoid fragmentation issues across networks. Payloads use a Type-Length-Value (TLV) encoding, so the protocol is both compact and extensible.

Three query types are available:

QueryPurposeDefault Access
ChallengeRequest an authentication tokenPublic
BasicServer name, MOTD, player count, version, addressPublic
PlayersFull player list with UUIDs (paginated)Authenticated

Challenge-Response Authentication

OneQuery doesn’t just blindly respond to anyone (if you disabled legacy v1 protocol). A challenge-response mechanism prevents UDP amplification attacks - the same kind of attacks that have historically plagued game server query protocols.

Current flow:

  1. Client sends a 9-byte challenge request
  2. Server responds with a 32-byte token (HMAC-SHA256, IP-specific)
  3. Client includes the token in subsequent queries
  4. Token expires after 120 seconds

Tokens are bound to the clients IP address and verified with constant-time comparison to prevent timing attacks. This means a token issued to one IP address cannot be replayed from another.

Access Control

Every query endpoint can be independently configured as public or token-authenticated:

{
  "Authentication": {
    "Public": {
      "Basic": true,
      "Players": false
    },
    "Tokens": {
      "my-monitoring-token": {
        "Basic": true,
        "Players": true
      }
    }
  }
}

This lets you expose basic server info publicly (for server lists) while keeping your player list private or restricted to specific trusted applications.

Network Mode: Aggregate Multiple Servers

Running a Hytale server network with survival, PvP, and lobby servers? OneQuerys network mode connects your servers through Redis or Valkey (whatever you like more), so you can track players and status across the entire network.

There are three modes, each building on the previous:

Publish

Game servers push their state to Redis - heartbeats, player joins, player leaves - but don’t read anything back. This is the lightweight option for servers that just need to report in.

              Query --> Survival-1 (PUBLISH)
                        |
  Response:             |  pushes state
  local players only    v
                    +-------+
                    | Redis |  (data stored, nobody reading)
                    +-------+

Query result: Local server data only. Querying a PUBLISH server returns its own players and status - it has no awareness of the rest of the network.

Sync

Same as Publish, plus the server subscribes to the Redis event stream. It maintains a local cache of every server and player in the network - but still only returns its own data when queried externally.

              Query --> Proxy (SYNC)
                        |  ^
  Response:             |  |  subscribes to events
  local players only    |  |  (maintains internal cache)
                        v  |
                    +-------+
                    | Redis | <-- other servers push here
                    +-------+

Query result: Local server data only. The network cache is available internally to other plugins on the same server (e.g. for routing, friend lists, cross-server chat) but external queries still see only this server.

Aggregate

Same as Sync, but now external queries return the combined state of the entire network. This is the mode for your hub or lobby server - the single entry point that monitoring tools and server lists query.

  Survival-1       Survival-2       PvP-1
  (PUBLISH)        (PUBLISH)        (PUBLISH)
      |                |                |
      +----------------+----------------+
                       |
                       v
                   +-------+
                   | Redis |
                   +---+---+
                       |
                       v
                +--------------+
  Query ------> |    Lobby     |
                |  (AGGREGATE) |
                +--------------+
                       |
  Response:            v
  all 3 servers + all players combined

Query result: Network-wide. Player counts are summed across all servers. The player list includes every online player with their current server. The response flag IS_NETWORK is set so clients know they’re getting aggregated data.

Choosing a Mode

ModePublishes to RedisReads from RedisQuery returnsUse case
PublishYesNoLocal onlyGame servers
SyncYesYes (internal cache)Local onlyProxies, routers
AggregateYesYes (internal cache)Network-wideLobby, hub server

For a typical setup: put your game servers on Publish, and your lobby on Aggregate. Use Sync on proxy (does anyone have that atm?) or routing servers that need network awareness for internal decisions (like sending players to the least-full survival server) without exposing that data externally.

Player joins, leaves, and server migrations are tracked in real-time using Redis streams with Lua scripts for atomic operations. The lobby server caches a local snapshot and keeps it up to date through event-driven polling - no expensive full-refresh cycles.

Timing Configuration

{
  "Network": {
    "Timing": {
      "HeartbeatIntervalSeconds": 15,
      "CacheRefreshSeconds": 60
    }
  }
}

Servers send heartbeats every 15 seconds, each refreshing a 45-second TTL on their Redis keys. If a server stops sending heartbeats, its keys expire after 45 seconds and it’s automatically removed from the network snapshot. The local cache does a full refresh every 60 seconds as a safety net.

Installation

  1. Download onequery-*.*.*-SNAPSHOT.jar from the GitHub releases
  2. Drop it into your Hytale servers mods/ directory
  3. Start your server - the plugin generates a default config at mods/HytaleOne_OneQuery/config.json
  4. Configure authentication and network settings if needed, then restart

That’s it. With default settings, OneQuery responds to basic status queries immediately with no configuration required.

Server List Registration

OneQuery includes built-in integration with the HytaleONE server list. When enabled, the plugin automatically registers your server and keeps its status updated:

{
  "ServerList": {
    "Enabled": true,
    "ServerId": "hytaleone_abc123"
  }
}

This is how HytaleONE tracks server uptime, player counts, and availability across every listed server - through OneQuerys efficient UDP protocol rather than heavyweight HTTP polling.

Future

Even if Hytale eventually ships its own built-in query protocol, OneQuery’s network mode - aggregating player counts and status across multiple servers via Redis - isn’t something a per-server protocol can replace. If you’re running a network, you’ll still need a way to combine everything into a single query endpoint.

Beyond that, OneQuery doubles as cross-server infrastructure for other plugins. Its Java API lets any plugin on the same server tap into the network state - no extra Redis setup, no reinventing the wheel:

  • Player tracking - check if a player is online anywhere, find which server they’re on, subscribe to joins and leaves in real time
  • Server discovery - list all servers, filter by glob patterns (e.g. survival-*), check health and player counts, get notified when servers go up or down

That could make OneQuery a useful backbone for things like cross-server chat, friend lists, network-wide announcements, or custom load balancing - any plugin that needs to know what’s happening with players across the network can just hook into the API instead of building its own Redis layer.

Source Code

OneQuery is open-source under the MIT license. The full source code, protocol specification, and contribution guidelines are available on GitHub:

The plugin also exposes a Java API for other plugins and ships with client libraries for querying servers programmatically - see the GitHub README for details.