Lobby
The Lobby Service works together with custom Room Servers to provide multi-user experiences (i.e. online games, shared streaming, etc.) to groups of participants.
It is available to apps that have brainCloud RTT enabled.
You configure Lobby Types in the portal under Design | Multiplayer | Lobbies.
Key concepts
Lobbies are used to gather up users prior to launching shared experiences via Room Servers. Users can be added to teams, indicate their ready status, and adjust personal and room settings before the experience starts.
The Lobby Service also offers highly configurable Online Matchmaking - to quickly and efficiently pair users up together.
For more information on Lobby Concepts, see the Lobby Overview page.
API Summary
DISBANDED
event example
{
"service": "lobby",
"operation": "DISBANDED",
"data": {
"lobbyId": "22819:unranked:406",
"reason": {
"code": 80101,
"desc": "Room successfully launched"
}
}
}
JOIN_FAIL
event example
{
"service": "lobby",
"operation": "JOIN_FAIL",
"data": {
"lobbyType": "4v4",
"reason": {
"code": 80200,
"desc": "No lobbies found matching criteria"
}
}
}
MEMBER_JOIN
event example
{
"service": "lobby",
"operation": "MEMBER_JOIN",
"data": {
"lobbyId": "13469:CustomGame:11",
"currentTime": 1747412422839,
"lobby": {
"state": "setup",
"rating": 0,
"ownerCxId": "13469:48844593-6e01-464f-bc13-565ee536a46b:1kslkorpivpa68bhf21q1avi9q",
"lobbyTypeDef": {
"roomConfig": null,
"lobbyTypeId": "CustomGame",
"teams": {
"all": {
"minUsers": 1,
"maxUsers": 8,
"autoAssign": true,
"code": "all"
}
},
"rules": {
"allowEarlyStartWithoutMax": false,
"forceOnTimeStartWithoutReady": true,
"allowJoinInProgress": false,
"onTimeStartSecs": 1,
"disbandOnStart": true,
"everyReadyMinPercent": 50,
"everyReadyMinNum": 1,
"earliestStartSecs": 1,
"tooLateSecs": 300
},
"desc": "for example -- custom multiplayer server with unity"
},
"settings": {},
"version": 1,
"timetable": {
"createdAt": 1747412422839,
"early": 1747412423839,
"onTime": 1747412423839,
"tooLate": 1747412722839,
"dropDead": 1747413322839,
"ignoreDropDeadUntil": 0
},
"cRegions": [],
"round": 1,
"isRoomReady": false,
"keepAliveRateSeconds": 0,
"isAvailable": true,
"shardId": 0,
"legacyLobbyOwnerEnabled": true,
"owner": "48844593-6e01-464f-bc13-565ee536a46b",
"numMembers": 1,
"members": [
{
"profileId": "48844593-6e01-464f-bc13-565ee536a46b",
"name": "",
"pic": "",
"rating": 0,
"team": "all",
"isReady": true,
"extra": {},
"ipAddress": "174.112.74.185",
"cxId": "13469:48844593-6e01-464f-bc13-565ee536a46b:1kslkorpivpa68bhf21q1avi9q"
}
]
},
"member": {
"profileId": "48844593-6e01-464f-bc13-565ee536a46b",
"name": "",
"pic": "",
"rating": 0,
"team": "all",
"isReady": true,
"extra": {},
"ipAddress": "174.112.74.185",
"cxId": "13469:48844593-6e01-464f-bc13-565ee536a46b:1kslkorpivpa68bhf21q1avi9q"
}
}
}
MEMBER_LEFT
event example
{
"service": "lobby",
"operation": "MEMBER_LEFT",
"data": {
"lobbyId": "22979:4v4:1387",
"lobby": {
"owner": "d8297230-6e7b-4bad-9c66-5371eb5c101b",
"version": 1,
"numMembers": 1,
"members": []
},
"member": {
"profileId": "24da7a7a-8e78-45a2-8350-30ad41c5372b",
"name": "Daivuk",
"pic": "",
"rating": 0,
"team": "green",
"isReady": false,
"extra": {
"loadout": "tank"
},
"cxId": "22979:24da7a7a-8e78-45a2-8350-30ad41c5372b:a4nto6vb672qtq1rpa1pecba48"
},
"reason": {
"code": 80000,
"desc": "Left by choice"
}
}
}
MEMBER_UPDATE
event example
{
"service": "lobby",
"operation": "MEMBER_UPDATE",
"data": {
"lobbyId": "22979:4v4:662",
"member": {
"profileId": "841cf9fa-1a93-4a7a-a36b-e5833f7e239b",
"name": "ste123",
"pic": "",
"rating": 0,
"team": "red",
"isReady": true,
"extra": {
"loadout": "scout"
},
"cxId": "22979:841cf9fa-1a93-4a7a-a36b-e5833f7e239b:acturqk5p5qaenvio8msecob9d"
}
}
}
ROOM_ASSIGNED
event example
{
"service": "lobby",
"operation": "ROOM_ASSIGNED",
"data": {
"lobbyId": "22819:unranked:406",
"connectData": {
"roomId": "22819:unranked:406",
"url": "207.219.200.99",
"port": 9307,
"wsPort": 9308
},
"passcode": "978b63"
}
}
ROOM_READY
event example
{
"service": "lobby",
"operation": "ROOM_READY",
"data": {
"lobbyId": "22819:unranked:406",
"connectData": {
"roomId": "22819:unranked:406",
"url": "207.219.200.99",
"port": 9307,
"wsPort": 9308
},
"passcode": "978b63"
}
}
SETTINGS_UPDATE
event example
{
"service": "lobby",
"operation": "SETTINGS_UPDATE",
"data": {
"lobbyId": "22979:4v4:662",
"lobby": {
"settings": {
"gameTime": 300
},
"version": 1
},
"currentTime": 1549916254804
}
}
STARTING
event example
{
"service": "lobby",
"operation": "STARTING",
"data": {
"lobbyId": "22819:unranked:406",
"lobby": {
"state": "starting",
"owner": "f6fa3e0e-6aac-497a-84e1-c8db6f545c12",
"settings": {},
"version": 1,
"numMembers": 2,
"members": []
}
}
}
STATUS_UPDATE
event example
{
"service": "lobby",
"operation": "STATUS_UPDATE",
"data": {
"lobbyId": "22819:unranked:406",
"lobby": {
"state": "early",
"owner": "f6fa3e0e-6aac-497a-84e1-c8db6f545c12",
"version": 1,
"numMembers": 2,
"members": []
}
}
}
ROOM_PROGRESS
event example
{
{
"service": "lobby",
"operation": "ROOM_PROGRESS",
"data": {
"lobbyId": "23649:CursorPartyV2:4186",
"curStep": 1,
"ofStep": 5,
"msg": "Host lookup",
"variation": "no-host-found"
}
},
{
"service": "lobby",
"operation": "ROOM_PROGRESS",
"data": {
"lobbyId": "23649:CursorPartyV2:4186",
"curStep": 2,
"ofStep": 5,
"msg": "New host started"
}
},
{
"service": "lobby",
"operation": "ROOM_PROGRESS",
"data": {
"lobbyId": "23649:CursorPartyV2:4186",
"curStep": 3,
"ofStep": 5,
"msg": "Host docker init"
}
},
{
"service": "lobby",
"operation": "ROOM_PROGRESS",
"data": {
"lobbyId": "23649:CursorPartyV2:4186",
"curStep": 4,
"ofStep": 5,
"msg": "Pulling container image"
}
},
{
"service": "lobby",
"operation": "ROOM_PROGRESS",
"data": {
"lobbyId": "23649:CursorPartyV2:4186",
"curStep": 5,
"ofStep": 5,
"msg": "Starting container"
}
}
}
The Lobby Service provides APIs for Online Matchmaking, Lobby Experience and Room Server Integration.
Online Matchmaking
The Online Matchmaking APIs allow users to find and/or create lobbies:
FindLobby - Find a lobby to meet the provided specs.
CreateLobby - Create a lobby.
FindOrCreateLobby - Search for lobby; create one if nothing suitable is found.
JoinLobby - Adds the caller to the given lobby instance.
GetRegionsForLobbies - Retrieves the region settings for each of the given lobby types.
PingRegions - Retrieves associated PingData averages to be used with all associated WithPingData APIs.
FindLobbyWithPingData - Adds the caller to the lobby entry queue.
FindOrCreateLobbyPingData - Creates an instance of a lobby.
FindOrCreateLobbyWithPingData - Adds the caller to the lobby entry queue and will create a lobby if none are found.
JoinLobbyWithPingData - Adds the caller to the given lobby instance.
Lobby Experience
The following APIs allow users to interact with lobby's once they have joined:
- GetLobbyData - request info about the lobby
- UpdateReady - update the user's ready-status
- UpdateSettings - update the lobby's setting data (owner only)
- SwitchTeam - switch teams
- SendSignal - send an event to all other lobby members
- LeaveLobby - leave the lobby
- RemoveMember - kicks another member from the lobby
Room Service Integration
The following APIs are called by Room Service providers:
- SysRoomReady - the room experience is ready to launch
- SysRoomCancelled - the room server request cannot be fulfilled
Lobby Events
These APIs can result in the following events being sent to lobby members.
Event | Data | Description |
---|---|---|
MATCHMAKING_IN_PROGRESS | lobbyType, step, maxSteps, minRating, maxRating, lobbiesInRange | Start provisioning lobby. Sent to everyone as they are being processed for each marchmaking round. |
MEMBER_JOIN | lobbyId, currentTime, lobby, memeber | A new member has joined the lobby. Sent to everyone, including the user who joined. |
JOIN_FAIL | lobbyType, reason | Could not locate a lobby that satisfies the filter criteria in the specified timeframe. The returned reason is mapped with code (including NO_LOBBIES_FOUND , FIND_REQUEST_CANCELLED ) and desc . |
MEMBER_LEFT | lobbyId, lobby, member, reason | A member has left the lobby. Sent to everyone, including the user who left. The returned reason is mapped with code (including LEFT_BY_CHOICE , EVICTED , LOST_CONNECTION ) and desc . |
MEMBER_UPDATE | lobbyId, lobby, member | A member has updated their data, which may include switching teams, thus why all of lobbyData is returned. |
SIGNAL | lobbyId, from (optional), signalData | This message allows players in lobbies to send messages to all other players. |
SETTINGS_UPDATE | lobbyId, currentTime, lobby | Changes to the settings that will be used to start the room. |
STATUS_UPDATE | lobbyId, lobby | The status of the overall lobby has changed. |
STARTING | lobbyId, lobby | This message is sent once all the hosted server launch conditions have been met and a server instance is being started. |
ROOM_PROGRESS | lobbyId, curStep, ofStep, msg | The configurable Room-Progress messages are transmitted between the events of STARTING and ROOM_READY , serving to indicate the progress of the provisioning of the room server. In the case of a new host being initiated, there are a total of 5 progress steps, whereas if this is not the case, there are 4 steps. See the following example for more details. |
ROOM_ASSIGNED | lobbyId, connectData, passcode | A room has been allocated for this lobby. connectData is likely incompolete. Each lobby member receives a random alphanumeric passcode for use in connecting to the room server to guard against impersonation. |
ROOM_READY | lobbyId, connectData, passcode | Go connect to the specified room. Will normally be immediately followed by DISBANDED. The same passcode as sent in ROOM_ASSIGNED will be repeated here as well. |
DISBANDED | lobbyId, reason, msg (optional) | The lobby has been terminated. The returned reason is mapped with code (including TIMEOUT , ROOM_READY , ROOM_READY_TIMEOUT , ROOM_CANCELLED , ERROR_ASSIGNING_ROOM , ERROR_LAUNCHING_ROOM , HOSTING_NOT_ENABLED , SERVER_MAX_REACHED , BY_REQUEST ) and desc . |
An example of using the returned reason code
of DISBANDED:
if (result.data.reason.code != this.bc.reasonCodes.RTT_ROOM_READY)
{
// Disbanded for any other reason than ROOM_READY, means we failed to launch the game.
this.onGameScreenClose()
}
An example of ROOM_PROGRESS messages when a host is found:
{
{
"service": "lobby",
"operation": "ROOM_PROGRESS",
"data": {
"lobbyId": "23649:CursorPartyV2:4186",
"curStep": 1,
"ofStep": 4,
"msg": "Host lookup",
"variation": "host-found"
}
},
{
"service": "lobby",
"operation": "ROOM_PROGRESS",
"data": {
"lobbyId": "23649:CursorPartyV2:4186",
"curStep": 2,
"ofStep": 4,
"msg": "Host docker init"
}
},
{
"service": "lobby",
"operation": "ROOM_PROGRESS",
"data": {
"lobbyId": "23649:CursorPartyV2:4186",
"curStep": 3,
"ofStep": 4,
"msg": "Pulling container image"
}
},
{
"service": "lobby",
"operation": "ROOM_PROGRESS",
"data": {
"lobbyId": "23649:CursorPartyV2:4186",
"curStep": 4,
"ofStep": 4,
"msg": "Starting container"
}
}
}
// an example of the `acture "progress" events being sent out to lobby members
{"service":"lobby","operation":"STARTING","data":{"lobbyId":"23649:CursorPartyV2:4186","lobby":{"state":"starting","settings":{},"version":1,"cRegions":[],"round":1,"isRoomReady":false,"keepAliveRateSeconds":72,"isAvailable":true,"ownerCxId":"23649:37e60799-468d-4440-8fce-5d8eabade18d:4s26gha7bhmiottrn3v38d8l0o","legacyLobbyOwnerEnabled":false,"numMembers":1,"members":[{"profileId":"37e60799-468d-4440-8fce-5d8eabade18d","name":"greg@bitheads.com","pic":"","rating":0,"team":"all","isReady":true,"extra":{"colorIndex":6,"presentSinceStart":false},"ipAddress":"184.148.127.43","cxId":"23649:37e60799-468d-4440-8fce-5d8eabade18d:4s26gha7bhmiottrn3v38d8l0o"}]}}}
{"service":"lobby","operation":"ROOM_PROGRESS","data":{"lobbyId":"23649:CursorPartyV2:4186","curStep":1,"ofStep":5,"msg":"Host lookup","variation":"no-host-found"}}
{"service":"lobby","operation":"ROOM_PROGRESS","data":{"lobbyId":"23649:CursorPartyV2:4186","curStep":2,"ofStep":5,"msg":"New host started"}}
{"service":"lobby","operation":"ROOM_PROGRESS","data":{"lobbyId":"23649:CursorPartyV2:4186","curStep":3,"ofStep":5,"msg":"Host docker init"}}
{"service":"lobby","operation":"ROOM_ASSIGNED","data":{"lobbyId":"23649:CursorPartyV2:4186","connectData":{"address":"3.96.222.126","ports":{"udp":9000,"tcp":9000,"ws":9001}},"passcode":"fda606"}}
{"service":"lobby","operation":"ROOM_PROGRESS","data":{"lobbyId":"23649:CursorPartyV2:4186","curStep":4,"ofStep":5,"msg":"Pulling container image"}}
{"service":"lobby","operation":"ROOM_PROGRESS","data":{"lobbyId":"23649:CursorPartyV2:4186","curStep":5,"ofStep":5,"msg":"Starting container"}}
{"service":"lobby","operation":"ROOM_READY","data":{"lobbyId":"23649:CursorPartyV2:4186","connectData":{"address":"3.96.222.126","ports":{"udp":9000,"tcp":9000,"ws":9001}},"passcode":"fda606"}}
Common Event Structures
The following structures are common to multiple event types:
lobbyTypeDef
The configured meta-data for the lobby type:
{
"lobbyTypeDef": {
"roomConfig": null,
"lobbyTypeId": "unranked",
"teams": {
"player1": {
"minUsers": 1,
"maxUsers": 1,
"autoAssign": true,
"code": "player1"
},
"player2": {
"minUsers": 1,
"maxUsers": 1,
"autoAssign": true,
"code": "player2"
}
},
"rules": {
"allowEarlyStartWithoutMax": false,
"forceOnTimeStartWithoutReady": true,
"onTimeStartSecs": 90,
"everyReadyMinPercent": 100,
"everyReadyMinNum": 2,
"earliestStartSecs": 0,
"tooLateSecs": 180
},
"desc": "Unranked match"
}
}
members
The list of members in the lobby, and their status:
{
"members": [
{
"profileId": "f6fa3e0e-6aac-497a-84e1-c8db6f545c12",
"name": "david",
"pic": "",
"rating": 0,
"team": "player2",
"isReady": true,
"extra": {},
"cxId": "22819:f6fa3e0e-6aac-497a-84e1-c8db6f545c12:vn0vnr7li5ll6t7gc0om18hksg"
},
{
"profileId": "1dab1250-facb-419a-80cf-3d2de4e91e0b",
"name": "david2",
"pic": "",
"rating": 0,
"team": "player1",
"isReady": true,
"extra": {},
"cxId": "22819:1dab1250-facb-419a-80cf-3d2de4e91e0b:bkr44a0ssbd0q3ae3r2i2refjh"
}
]
}
settings
The developer-defined, dynamic settings for this lobby instance:
{
"settings": {
"gameTime": 300,
"isPlaying": 0,
"mapLayout": 0,
"mapSize": 1,
"gameName": "ste123's Room",
"maxPlayers": 8,
"lightPosition": 0,
"minLevel": 0,
"maxLevel": 50
}
}
The json above is just an example - it can be whatever the developer decides.
Search Algorithms
When looking for a lobby.
ranged-percent
Ranges provided are interpreted as percentages to be applied to the user's rating for matchmaking.
{
"algo": {
"strategy": "ranged-percent",
"alignment": "center",
"ranges": [10, 20, 80]
}
}
ranged-absolute
Ranges provided are interpreted as absolute values to add/subtract from the user's rating when calculating the range for matchmaking
{
"algo": {
"strategy": "ranged-absolute",
"alignment": "center",
"ranges": [5, 7.5, 10]
}
}
compound
The compound algorithm allows multiple criteria to be used as the matchmaking filter. This is the approach to use when doing geo-matchmaking using the WithPingData()
calls.
{
"strategy": "compound",
"algos": [
{ "criteria": "ping", "strategy": "absolute", "alignment": "absolute" },
{
"criteria": "rating",
"strategy": "ranged-absolute",
"alignment": "center"
}
],
"compound-ranges": [
[30, [5, 10]],
[50, [10, 15]]
]
}
In the example above, matchmaking will look for matches as follows:
- step 1: matches in regions with < 30ms ping and lobby rating within +/- 5 of player's rating
- step 2: matches in regions with < 30ms ping and lobby rating within +/- 5 of player's rating
- step 3: matches in regions with < 50ms ping and lobby rating within +/- 10 of player's rating
- step 4: matches in regions with < 50ms ping and lobby rating within +/- 15 of player's rating
alignment
The following alignment options are available, and show how they would affect a range of +/- 10 range for a ranking of 80.
Alignment | Min | Max | Description |
---|---|---|---|
high | 80 | 100 | Ensures that lobbies must have skill rating >= to the candidate. Leaves the min equal to player rating, and adds 200% of the range to the max. |
mid-high | 75 | 95 | Subtracks 50% of the range for the min, and adds 150% of the range to the max. |
center | 70 | 90 | Centers the range around the candidate's rating. |
mid-low | 65 | 85 | Subtracts 150% of the range for the min, and adds 50% of the range to the max. |
low | 60 | 80 | Ensures that lobbies will have skill rating <= to the candidate. Subtracts 200% of the range from the rating to calculate min, and leaves max as the player rating. |
📄️ CancelFindRequest
Cancels any FindLobby or FindOrCreateLobby requests that have been previously submitted by the caller for the given lobbyType.
📄️ CreateLobby
Creates a new lobby.
📄️ CreateLobbyWithPingData
Creates an instance of a lobby.
📄️ FindLobby
Finds a lobby matching the specified parameters. Asynchronous - returns 200 to indicate that matchmaking has started.
📄️ FindLobbyWithPingData
Adds the caller to the lobby entry queue.
📄️ FindOrCreateLobby
Finds a lobby matching the specified parameters, or creates one. Asynchronous - returns 200 to indicate that matchmaking has started.
📄️ FindOrCreateLobbyWithPingData
Adds the caller to the lobby entry queue and will create a lobby if none are found.
📄️ GetLobbyData
Returns the data for the specified lobby, including member data.
📄️ GetLobbyInstances
Gets a map keyed by rating of the visible lobby instances matching the given type and rating range.
📄️ GetLobbyInstancesWithPingData
Gets a map keyed by rating of the lobby instances matching the given type, rating range, and ping threshold.
📄️ GetRegionsForLobbies
Retrieves the region settings for each of the given lobby types.
📄️ JoinLobby
Adds the caller to the given lobby instance.
📄️ JoinLobbyWithPingData
Adds the caller to the given lobby instance.
📄️ LeaveLobby
Causes the caller to leave the specified lobby. If the user was the owner, a new owner will be chosen. If user was the last member, the lobby will be deleted.
📄️ PingRegions
Retrieves associated PingData averages to be used with all associated WithPingData APIs.
📄️ RemoveMember
Evicts the specified user from the specified lobby. The caller must be the owner of the lobby.
📄️ SendSignal
Sends LOBBYSIGNALDATA message to all lobby members.
📄️ SwitchTeam
Switches to the specified team (if allowed.)
📄️ SysAddMember
Adds the given member to the given lobby instance.
📄️ SysAddMemberWithPingData
Adds the given member to the given lobby instance.
📄️ SysCreateLobby
Creates an instance of a lobby. Will return the newly created lobby id in the event of a successful creation.
📄️ SysCreateLobbyWithPingData
Creates an instance of a lobby. Will return the newly created lobby id in the event of a successful creation.
📄️ SysDisbandLobby
Disbands the given lobby. msg and details are optional values.
📄️ SysGetLobbyData
Gets data for the given lobby instance ``.
📄️ SysGetLobbyMember
Retrieves lobby membership details for the specified user.
📄️ SysMemberLeft
Informs brainCloud that the specified user has left the specified lobby.
📄️ SysRemoveMember
Evicts the specified user from the specified lobby.
📄️ SysRoomCancelled
Tells the lobby system that creation of the room experience failed.
📄️ SysRoomKeepAlive
Indicates that a room is still running and the associated lobby instance should be kept alive.
📄️ SysRoomReady
Tells the lobby system that a room server is ready to go.
📄️ SysRoomStopped
Indicates that the gameplay for the room associated with the given lobby has completed. The lobby can be returned to the 'setup' state.
📄️ SysSendSignal
Send the given data to all members of the given lobby.
📄️ SysUpdateSettings
Updates the settings for the given lobby instance.
📄️ UpdateReady
Updates the ready status and extra json for the given lobby member.
📄️ UpdateSettings
Updates the settings for the given lobby instance. The caller must be the owner of the lobby.