Matchmaking
One call routes a player to the right server - capacity-aware, start-aware, and grouped - across your whole network.
findServer asks the network for the best server of a given type and hands you a
target you can send the player to. The network tracks live presence and capacity
for you, so you never count players or pick a server by hand.
findServer
Give it a player and a server type. You get back a result with the matched server (and, for instanced games, the matched world). It’s a network call, so it’s async.
hive.matchmaking()
.findServer(player.uuid(), player.name(), "skywars")
.thenAccept(result -> {
if (result.isSuccess()) {
hive.transfer(player, result.matchedServer());
} else {
player.sendMessage("No game open right now - try again.");
}
}); The type string ("skywars", "lobby", …) is the serverType each server
announces in the Server registry. Anything that
registered with that type is a candidate.
How a server gets picked
Routing isn’t just “least full.” The network weighs two things in order, so games actually start and players land together rather than scattered one-per-server:
- Servers that still need players to start come first - and among those, the one that needs the fewest more to fire. This fills a waiting lobby to its minimum instead of seeding a second empty one.
- Otherwise, the most-populated joinable server - grouping players together so lobbies fill top-down.
A server is only ever a candidate if it’s joinable (accepting players, not full,
in a state that allows joins). The player’s current server is skipped, so
findServer never routes someone back to where they already are.
Instanced games: match a world
Minigames run many instances (worlds) inside one server. Ask for a world type and the network picks the best world across every matching server - same start-aware, group-first priority, one level deeper.
hive.matchmaking()
.findServerWithWorld(player.uuid(), player.name(), "skywars", "ranked")
.thenAccept(result -> {
if (result.isSuccess()) {
// matchedServer + matchedWorld - send the player to the instance
hive.transfer(player, result.matchedServer(), result.matchedWorld());
}
}); This is the call the Minigame SDK sits on: a lobby asks for
a skywars world, the network finds an instance that’s still filling, and the
player drops straight into it.
Direct join
Sometimes you want a specific server or world - a “join my friend” button, a party leader pulling their group along. Direct join validates the target and tells you precisely why if it can’t.
hive.matchmaking()
.joinServer(player.uuid(), player.name(), "lobby-2")
.thenAccept(result -> {
if (result.isSuccess()) hive.transfer(player, result.matchedServer());
else player.sendMessage(result.errorMessage());
}); joinServerWorld(uuid, name, serverId, worldId) does the same for a specific
instance.
Reading the result
Every call resolves to the same result object, success or not - you never get an
exception for an ordinary “lobby’s full.” Branch on isSuccess(), then use the
match; on failure, errorMessage() is human-readable and result() is a precise
enum you can switch on.
| Field | What it is |
|---|---|
isSuccess() | whether a target was found |
matchedServer() | the server to send the player to (ServerInfo) |
matchedWorld() | the instance, when matching by world (else null) |
transferId() | id tying this match to the resulting transfer |
errorMessage() | human-readable reason on failure |
result() | precise outcome enum (below) |
Outcomes
Successful matches return SUCCESS. The failure cases tell you exactly what
went wrong, so you can show the right message or fall back:
| Outcome | Meaning |
|---|---|
NO_SERVERS_AVAILABLE | nothing of that type is registered |
ALL_SERVERS_FULL | every server is full or not accepting players |
SERVER_NOT_FOUND / WORLD_NOT_FOUND | direct-join target doesn’t exist |
SERVER_FULL / WORLD_FULL | direct-join target is full |
SERVER_NOT_JOINABLE / WORLD_NOT_JOINABLE | target isn’t accepting joins (check its state) |
ALREADY_ON_SERVER / ALREADY_IN_WORLD | player is already there |
NO_WORLDS_AVAILABLE | no world of that type across any server |
ERROR | internal error during matchmaking |
Where the numbers come from
You don’t feed matchmaking any state. Capacity, player counts, joinable state and “needs N to start” all come from the heartbeats each server sends to the Server registry - so a match always reflects live presence, not a stale snapshot. Your job is one call and the transfer.
Queues and skill/party-aware matching are rolling out alongside the Hytale beta. Need something specific now? Ask us - we answer fast.