Game and matchmaking example
A practical pattern for multiplayer games on Xshathra's data plane: one realtime channel per match, an authoritative game server that publishes state, and a matchmaking flow that moves players from queue → lobby → match. Pairs with Client integration and Chat example.
What you will have at the end
- Match channel — subscribers receive ticks or snapshots from your simulation.
- Lobby / queue channels — lightweight realtime for ready checks and “match found” without spamming the match channel.
- Clear handoff — matchmaking service tells clients which channel to join and issues the right subscription tokens.
Before you start
- Same baseline as other examples: a console project with
server_api_key/client_api_key, clients using your app's/realtime/connection/websocketURL, and a backend that mints connection and (optionally) subscription JWTs. - A game server process (or fleet) that owns simulation: physics, hit validation, win conditions. Clients are never the source of truth for outcomes.
Part A — In-match realtime (authoritative server)
Step 1 — Name the match channel
Use a unique id per match session. Include project (or environment) id to avoid collisions.
# Pattern
match:{projectId}:{matchId}
# Example
match:proj_01HZZZZZZZZZZZZZZZZZZZZZZ:01HMATCHZZZZZZZZZZZZZZZZZStep 2 — Who may publish?
Recommended: only your game server publishes to match:… using Xshathra publish API on your app origin, e.g. POST https://your-app.example/api/realtime/publish with project server_api_key. Clients subscribe read-only; they send inputs to your game server over your existing transport (UDP/TCP, another WebSocket, or HTTP).
Alternative (small games): clients publish intent messages (e.g. “move request”) to a channel the server also reads — still validate every frame server-side before updating authoritative state.
Step 3 — Message shapes
Keep a small set of event types. Serialize compactly for high tick rates if needed (binary on the wire is optional; JSON is fine to start).
// Snapshot (low frequency or on join)
{
"type": "match.snapshot",
"matchId": "01HMATCH...",
"tick": 18402,
"state": { /* your compact world state */ }
}
// Delta / event (between snapshots)
{
"type": "match.event",
"matchId": "01HMATCH...",
"tick": 18403,
"name": "player.eliminated",
"payload": { "playerId": "p1" }
}Part B — Matchmaking flow (step by step)
Step 1 — Player enters queue
Client calls your REST API (not the realtime gateway directly): e.g. POST /matchmaking/queue with playlist id, party id, skill bucket. Your service records the ticket in Redis or a database.
Step 2 — Optional: queue / party channel
For party games, a channel like party:{projectId}:{partyId} lets members see invites and ready state. Subscription tokens should only include party members.
party:proj_01HZ...:party_7xk2
Step 3 — Matcher forms a match
A worker pulls compatible tickets, assigns a matchId, starts (or reserves) a game server instance, and persists the roster.
Step 4 — Tell players “match found”
Two common patterns (you can combine):
- HTTP response — client polls or uses long-polling / SSE until the ticket resolves; response body includes
matchId, server address, and any join secret. - Per-user notify channel — e.g.
user:{projectId}:{userId}:notify— server publishesmatch.readywith match id and connection hints. Client stays subscribed while in menus.
Step 5 — Subscribe to the match channel
Client requests a subscription token for match:{projectId}:{matchId} only after the ticket is accepted. Then connect to Xshathra Realtime (if not already) and subscribe. Game server begins publishing snapshots/events when the session starts.
Step 6 — End of match
Publish a final match.ended event, stop the simulation, and let subscription tokens expire. Clients unsubscribe; you may archive history via realtime stream history if enabled.
Anti-patterns to avoid
- Trusting client-published damage or scores on a shared channel without server validation.
- Guessable match ids — use opaque ids and private channels + subscription JWTs.
- Publishing high-rate physics to every viewer worldwide— scope channels per match; consider interest management in your sim before fan-out.
Related
- Chat application example — room channels and message envelopes.
- Client integration — tokens, channels, and patterns.
- Centrifugo — realtime engine usage summary.
