Lobbies and Matchmaking
Lobby Basics
Lobbies are the matchmaking layer of the Photon Cloud. Every visible room is listed in exactly one lobby, and every matchmaking operation (room lists, random joins, filters) runs against the lobby you address. A lobby only organizes rooms; players in a lobby do not see or interact with each other.
The client automatically joins the default lobby when the connection is established, so simple games never need an explicit lobby call. Turn automatic lobby joining off before connecting to opt out, for example when the game always targets a named lobby anyway.
Lobby Types
A lobby of the default type matches rooms by exact equality on their lobby-visible custom properties. A SQL lobby replaces equality matching with query-style filters over indexed properties and has its own page: SQL Lobby Matchmaking.
| Lobby Type | C++ | C | JavaScript |
|---|---|---|---|
| Default | LobbyType::Default |
0 |
'default' |
| SQL | LobbyType::SqlLobby |
2 |
'sqlLobby' |
Joining and Leaving a Lobby
Joining a lobby takes the lobby's name and type, and leaving it takes no arguments; both complete asynchronously once the server answers. Joining without arguments targets the default lobby, and the client reports whether it is in a lobby at any time.
| Operation | C++ | C | JavaScript |
|---|---|---|---|
| Join a lobby | JoinLobby() |
realtime_join_lobby() |
joinLobby() |
| Leave the lobby | LeaveLobby() |
realtime_leave_lobby() |
leaveLobby() |
| Check lobby membership | IsInLobby() |
realtime_is_in_lobby() |
isInLobby |
| Turn automatic lobby joining on or off | SetAutoJoinLobby() |
realtime_set_auto_join_lobby() |
setAutoJoinLobby() |
Joining a lobby while the client is already in one switches lobbies: the server removes the client from its current lobby and joins it to the requested one. A single join is therefore enough to move between lobbies, including right after connecting, when the client is in the auto-joined default lobby. Leaving is only needed to end up in no lobby at all.
Switch from the default lobby to a named one:
C++
Task<Result<void>> EnterRankedLobby(RealtimeClient& client)
{
co_return co_await client.JoinLobby(PHOTON_STR("ranked"), LobbyType::Default);
}
C
/* One join switches lobbies; leaving the current one first is not needed. */
realtime_join_lobby(client, "ranked", 0); /* lobbyType 0 = Default */
/* The result arrives as a RealtimeEventType_JoinLobbyResult event.
lobbyType takes the numeric LobbyType, and only 0 and 2 are valid, so
any other value falls back to Default.
realtime_set_auto_join_lobby(client, 0) before connecting opts out of
the automatic default-lobby join. */
JavaScript
// One join switches lobbies; leaving the current one first is not needed.
await client.joinLobby('ranked', 'default');
Room Lists
While the client is in a lobby the server pushes room list updates to it, and the client caches the most recent list. Reading the cached list needs no round trip, which is usually all a room browser needs between updates.
| C++ | C | JavaScript | |
|---|---|---|---|
| Room list updates | OnRoomListUpdated |
RealtimeEventType_RoomListUpdated |
roomListUpdated event |
| Cached room list | GetCachedRoomList() |
realtime_get_cached_room_list() |
cachedRoomList |
Each entry of a room list describes one room:
| C++ | JavaScript | Description |
|---|---|---|
Name |
name |
Unique room name. |
PlayerCount |
playerCount |
Players in the room. |
MaxPlayers |
maxPlayers |
Player limit from 0 to 255, 0 when unlimited. |
IsOpen |
isOpen |
Whether the room accepts joins. |
DirectMessaging |
directMessaging |
The room's direct messaging mode. |
CustomProperties |
customProperties |
The room's lobby-visible custom properties. |
Random Matchmaking
A random join asks the server to drop the player into a room matching the given matchmaking options.
When no room matches, the join fails with the no-match-found error (JoinRoomError::NoMatchFound in C++, RealtimeJoinRoomError_NoMatchFound in C, 'noMatchFound' in JavaScript) instead of waiting for one to appear.
Join-random-or-create closes the classic race between "no match found" and "create a room": when nothing matches, the server creates the room described by the create options in the same operation. This makes it the recommended default flow for drop-in multiplayer.
| Operation | C++ | C | JavaScript |
|---|---|---|---|
| Join a random matching room | JoinRandomRoom() |
realtime_join_random_room() |
joinRandomRoom() |
| Join a random matching room or create one | JoinRandomOrCreateRoom() |
realtime_join_random_or_create_room() |
joinRandomOrCreateRoom() |
Match on a game mode and cap the room at eight players:
C++
Task<Result<Room>> EnterDeathmatch(RealtimeClient& client)
{
MatchmakingOptions matchmaking;
matchmaking.Filter.Set(PHOTON_STR("mode"), PHOTON_STR("deathmatch"));
matchmaking.MaxPlayers = 8;
CreateRoomOptions create;
create.MaxPlayers = 8;
create.CustomProperties.Set(PHOTON_STR("mode"), PHOTON_STR("deathmatch"));
create.LobbyProperties = {PHOTON_STR("mode")};
co_return co_await client.JoinRandomOrCreateRoom(create, matchmaking);
}
C
/* The rt_* blob helpers, copied from "Blob Helpers" on the C API page. */
#include "photon_blob.h"
/* Search: the filter travels as a SQL filter string, and the lobby to match in
is a parameter of the search itself. */
realtime_join_random_room(client,
8, /* maxPlayers */
0, /* matchmakingMode: FillRoom */
NULL, /* lobbyName: the default lobby */
0, /* lobbyType: Default */
NULL); /* sqlFilter: SQL lobbies only */
/* Fall back to creating a matching room when nothing was found. */
if (e->type == RealtimeEventType_JoinRandomRoomResult && e->mode == RealtimeJoinRoomError_NoMatchFound)
{
rt_blob props = {0};
rt_blob keys = {0};
rt_begin(&props);
rt_put_str(&props, "mode", "deathmatch");
rt_end(&props);
realtime_create_room(client, NULL, 8, 1, 1, 0, 0, NULL, props.data, props.len);
rt_free(&props);
/* LobbyProperties are applied after the join, once in the room. */
rt_begin(&keys);
rt_add_str(&keys, "mode");
rt_end(&keys);
/* ... in the CreateRoomResult handler: */
realtime_room_set_lobby_properties(client, keys.data, keys.len);
rt_free(&keys);
}
/* Matchmaking Options Are Partly Available: realtime_join_random_room
covers MaxPlayers, Mode, LobbyName, Lobby and SqlFilter, but not the
equality Filter map or ExpectedUsers. Exact-equality matching on
lobby-visible properties is therefore only reachable from C++; from C,
express the same intent as a SqlFilter against a SQL lobby.
realtime_join_random_or_create_room takes no matchmaking parameters at
all - only the room it would create - so a filtered search plus fallback
has to be written as the two-step flow above. */
JavaScript
const room = await client.joinRandomOrCreateRoom(
{ maxPlayers: 8, customProperties: { mode: 'deathmatch' }, lobbyProperties: ['mode'] },
{ filter: { mode: 'deathmatch' }, maxPlayers: 8 },
);
The first argument describes the room to create, the second the room to search for. The promise resolves with the room the client joined or created.
Matchmaking Options
| C++ | C | JavaScript | Default | Description |
|---|---|---|---|---|
Filter |
Not available | filter |
empty | Custom properties a room must match exactly. |
MaxPlayers |
maxPlayers |
maxPlayers |
0 |
Only match rooms created with this player limit; 0 matches any. |
Mode |
matchmakingMode |
mode |
Fill room | The fill strategy. |
LobbyName |
lobbyName |
lobbyName |
empty | The lobby to match in; empty targets the default lobby. |
Lobby |
lobbyType |
lobby |
Default | The type of the addressed lobby. |
SqlFilter |
sqlFilter |
sqlFilter |
empty | Query filter for the SQL lobby. |
ExpectedUsers |
Not available | expectedUsers |
empty | User ids to reserve slots for in the matched room. |
The C column names the parameters of realtime_join_random_room().
The filter compares exactly: a room matches only when every property in the filter equals the room's lobby-visible custom property of the same key. Range or combination queries are not expressible here; that is what the SQL lobby is for.
The matchmaking mode picks the fill strategy:
| C++ | C | JavaScript | Behavior |
|---|---|---|---|
MatchmakingMode::FillRoom |
0 |
'fillRoom' |
The default. Fills rooms one after another, which gets players into full matches fastest. |
MatchmakingMode::SerialMatching |
1 |
'serialMatching' |
Distributes players over the matching rooms in order. |
MatchmakingMode::RandomMatching |
2 |
'randomMatching' |
Spreads players over the matching rooms randomly. |
Serial and random matching keep room populations even at high player counts.
Lobby Statistics
Lobby statistics report the current player and room counts of each lobby. Request them on demand, or construct the client with automatic lobby statistics turned on (off by default) to have the server push updates. Each entry carries the lobby name, its type, the peer count and the room count.
| C++ | JavaScript | |
|---|---|---|
| Request statistics on demand | GetLobbyStats() |
getLobbyStats() |
| Turn on pushed updates | ClientConstructOptions.AutoLobbyStats |
autoLobbyStats option of createRealtimeClient() |
| Pushed updates | OnLobbyStats |
lobbyStats event |
| Entry fields | Name, Type, PeerCount, RoomCount |
name, type, peerCount, roomCount |
The push is independent of lobby membership and of the automatic lobby joining setting.
Last updated on
Back to top