SQL Lobby Matchmaking
When to Use the SQL Lobby
The default lobby matches rooms by exact property equality, which cannot express "close to my skill" or "any of these maps". The SQL lobby replaces equality matching with query-style filters, so clients can match on ranges, alternatives and combinations of room properties.
Typical cases are skill or ELO ranges, map-and-mode combinations and versioned or regional room buckets, anywhere a single equality comparison is not enough.
Publishing Rooms to a SQL Lobby
A room enters a SQL lobby at creation time.
Set CreateRoomOptions.Lobby = LobbyType::SqlLobby and a LobbyName, list the queryable keys in LobbyProperties and supply their values in CustomProperties.
The queryable keys use the reserved column names C0 to C9.
Only the properties named C0 to C9 are queryable, and only with string or integer values.
Every other custom property stays invisible to filters, no matter what it contains.
Publish the game mode and the room's ELO rating as queryable columns:
C++
Task<Result<MutableRoomView>> CreateRankedRoom(RealtimeClient& client)
{
CreateRoomOptions options;
options.MaxPlayers = 8;
options.Lobby = LobbyType::SqlLobby;
options.LobbyName = PHOTON_STR("ranked");
options.LobbyProperties = {PHOTON_STR("C0"), PHOTON_STR("C1")};
options.CustomProperties[PHOTON_STR("C0")] = PHOTON_STR("arena"); // game mode
options.CustomProperties[PHOTON_STR("C1")] = static_cast<int32_t>(1450); // room ELO
co_return co_await client.CreateRoom({}, options);
}
Filter Syntax
A filter is a SQL-like WHERE clause over the columns C0 to C9.
It supports the comparison operators, AND and OR combinations, BETWEEN for ranges and IN for alternatives.
| Operator | Sample Filter |
|---|---|
= / != |
C0 = 'arena' |
< / <= / > / >= |
C1 > 1000 |
BETWEEN |
C1 BETWEEN 100 AND 200 |
IN |
C0 IN ('ctf', 'tdm') |
AND / OR |
C0 = 'arena' AND C1 > 1000 |
Several filters can be chained with ; as ordered fallbacks.
The server evaluates them left to right and the first filter that matches a room wins, so a strict query can carry progressively wider alternatives in a single call.
Querying the Room List
GetRoomList(lobbyName, sqlFilter) returns the rooms matching the filter as RoomListing entries, the building block for a room browser.
Each listing carries the room name, player counts and lobby-visible custom properties; see Data Types for all fields.
Query the lobby and evaluate the listings:
C++
Task<Result<int>> CountOpenArenaRooms(RealtimeClient& client)
{
Result<std::vector<RoomListing>> rooms = co_await client.GetRoomList(
PHOTON_STR("ranked"), PHOTON_STR("C0 = 'arena' AND C1 BETWEEN 1000 AND 2000"));
if (rooms.IsErr())
{
co_return Result<int>::Err(rooms.GetError());
}
int openRooms = 0;
for (const RoomListing& listing : rooms.GetValue())
{
if (listing.IsOpen)
{
++openRooms;
}
}
co_return Result<int>::Ok(openRooms);
}
Joining with a Filter
JoinRandomRoom runs the same filters for matchmaking.
Set MatchmakingOptions.Lobby = LobbyType::SqlLobby, the LobbyName and the SqlFilter, and the server picks a random room satisfying the filter.
When no room satisfies the filter the Task resolves to ErrorCode::NoMatchFound.
Handle it by widening the filter in a follow-up attempt or by creating a room that satisfies the original query, so the next searcher finds it; JoinRandomOrCreateRoom combines both steps in one operation.
Search near the player's skill and create a matching room when nothing is found:
C++
Task<Result<MutableRoomView>> JoinNearSkill(RealtimeClient& client, int32_t elo)
{
MatchmakingOptions matchmaking;
matchmaking.Lobby = LobbyType::SqlLobby;
matchmaking.LobbyName = PHOTON_STR("ranked");
matchmaking.SqlFilter = PHOTON_STR("C1 BETWEEN ") + RealtimeCore::Common::ToStringType(elo - 200) +
PHOTON_STR(" AND ") + RealtimeCore::Common::ToStringType(elo + 200);
Result<MutableRoomView> joined = co_await client.JoinRandomRoom(matchmaking);
if (joined.IsOk() || joined.GetErrorCode() != ErrorCode::NoMatchFound)
{
co_return joined;
}
CreateRoomOptions create;
create.Lobby = LobbyType::SqlLobby;
create.LobbyName = PHOTON_STR("ranked");
create.LobbyProperties = {PHOTON_STR("C1")};
create.CustomProperties[PHOTON_STR("C1")] = elo;
co_return co_await client.CreateRoom({}, create);
}
Back to top