Game Server Hosting
Last updated: 15 September 2026
A game server is a program you write that holds one or more live rooms — an authoritative instance of your game where players actually play. The server SDK gives you a Room base class for your game logic and a RoomHost that runs your rooms, registers them with PlayServ, keeps them alive with a heartbeat, and retires them when they end. Getting a player to a room is the client's job (Matchmaking & Rooms, Connecting to a Game); this page is about the server that owns the room.
This is the server-side SDK (PlayServ.Sdk.Rooms), used by a program you deploy as a game server — not the game client. It authenticates as a server, so it isn't limited by client-facing table permissions. A game server can be a managed instance the platform launches for you, or an external process you run yourself; both use the same SDK.
The shape of a game server
Two types do the work: a Room subclass holds your game, and a RoomHost runs rooms of that type.
A minimal room
You subclass Room<TPlayer, TConfig> with your own player and config types. The base class manages the roster (AddPlayer, RemovePlayer, Players) and exposes lifecycle hooks you override.
using PlayServ.Sdk.Rooms;
public sealed class MyPlayer : RoomPlayer { }
public sealed record MyConfig;
public sealed class MyRoom : Room<MyPlayer, MyConfig>
{
protected override void OnPlayerJoined(MyPlayer p) { /* seat them */ }
protected override void OnPlayerLeft(MyPlayer p) { /* free the seat */ }
protected override void OnTick(float dt) { /* advance the room */ }
}
A RoomHost runs rooms of that type from a factory:
var host = new RoomHost<MyRoom, MyPlayer, MyConfig>(name => new MyRoom());
var room = host.GetOrCreate("lobby-1");
That's a working authoritative server: the host wires the heartbeat, registers the room, applies the room configuration it pulls from the platform, and enforces the room's lifetime for you.
Self-registration and heartbeat
You don't tell the platform about your rooms with a separate call — the host registers each room automatically and keeps it current with a periodic heartbeat that reports the room's occupancy and capacity. This is the exact signal the client room browser reads, so a room is discoverable the moment it's running and disappears from browsing shortly after the server stops beating for it.
Room configuration is platform-owned
Room settings — capacity, reservation lifetime, room lifetime, idle timeout, and the per-server max_rooms quota — are owned by the platform and edited in the Backoffice, not shipped in your code or a manifest. The host pulls the live configuration down and applies it as it changes, so an operator can retune a room type without a redeploy.
// capacity and limits come from the platform, not the constructor —
// read them off the room rather than assuming a value you set in code
Because config is pulled, changing capacity or a timeout in the Backoffice takes effect on the running server within a heartbeat. Don't hard-code these values; treat what the platform hands down as the source of truth.
Reporting where the room is
A client needs to know how to reach the room. Your server declares its connect details — host, port, transport, and optionally a connect string and region — with DeclareConnect, and the platform returns them to the client on its reservation.
DeclareConnect(new RoomConnect { Host = publicHost, Port = port, Transport = "udp" }, region: "eu");
When the platform launched the server for you (a managed instance), the connect details can be filled in from the orchestrator's environment automatically; when you run your own process, you declare them.
The room lifecycle
A room moves through a small, well-defined lifecycle. The host drives most of it; you influence it through the hooks and a few declarations.
| Stage | What happens |
|---|---|
| Open | The room accepts new players; the browser can show it. |
| Occupied | Players join and leave; OnPlayerJoined / OnPlayerLeft fire; the heartbeat reports the live count. |
| Idle | Everyone has left. OnIdle fires; you can pause simulation or let idle cleanup retire the room. |
| Draining | Near end-of-life the room stops taking new players while current ones finish. |
| Closed | The room is retired. Closing marks the room closed rather than deleting it, and voids reservation tickets pointing at it. |
Two cleanups run without any work from you: idle cleanup retires rooms nobody is in, and lifetime cleanup enforces the room's maximum age. Both honour the platform-owned config above.
A player who drops keeps their seat for a short reconnect grace before the room reports them gone, so a brief network blip doesn't cost the player their place. Declare it with DeclareReconnect(...).
Accepting players
A player reaches your server carrying a reservation they got from the client SDK. The host validates that reservation before the player counts as present: it must be valid, unspent, and issued for this room. Only then does OnPlayerJoined fire.
- A valid reservation → the player is seated;
OnPlayerJoined(player)runs. - A missing, expired, wrong-room, or already-spent reservation → entry is refused.
This is why the client and server are two halves of one system: the client reserves and connects, and the host you write redeems the reservation. You don't validate tickets by hand — the host does — but you decide what happens on OnPlayerJoined / OnPlayerLeft: assign a spawn, add them to the roster you broadcast, start their timers.
Where the server runs
A game server can run in a few ways, and the platform shows which for each room:
- Managed — the platform launches the server instance for you through a managed orchestrator (PlayServ integrates with Edgegap). The orchestrator token is your studio's own, held per project and environment.
- External — you run the server yourself (your own fleet or machine). You declare it to PlayServ with
playserv functions declareas a game server, and it registers its rooms like any other. It never needs to be deployed as a cloud function. - Pooled — a room served from a pre-provisioned pool.
Either way the room model is identical: register, heartbeat, accept reservations, report presence.