Steam's peer-to-peer matchmaking is built around the concept of a lobby. A lobby is a entity that lives on the Steam back-end servers that is a lot like a chat room. Users can create a new lobby; associate data with a lobby; search for lobbies based on that data; join lobbies; and share information with other users in the lobby. A single lobby can have up to 250 users in it, although typically most games have at most 2-16 players. Skill-based matchmaking is built on top of this system.
The Steam peer-to-peer matchmaking API is a set of functions that enable users to find other users to play a game with. The matchmaking functions all live in ISteamMatchmaking
, which contains more details on the parameters for each function. Lobbies are uniquely identified by Steam ID, like users or game servers. The Steamworks Example has a full working implementation of lobbies.
The Steamworks Matchmaking API must be manually enabled by Valve for free to play titles
! You can request this for your app by contacting Steam Publishing
Matchmaking process flow
The usual model for getting groups together to play is as follows:
- User selects in the game that they want to play multiplayer, and what kind of multiplayer they want (rules, scenario, etc.)
- The game searches for lobbies that have a similar same set of rules, using the lobby search API.
- If a lobby is found, then the game joins that lobby; if no lobby is found, then it creates a new lobby
- Users stay in a lobby until there are enough players ready to launch the game. Data is communicated between the lobby members about which character they want to play, or other per-user settings. If there are some rules that need to be enforced in the lobby (for example, only one user can play as a certain character), there is one and only one lobby owner who you can use to arbitrate that.
- There may or may not be a user interface associated with the lobby; if there is, the lobby data communications functions can be used to send chat messages between lobby members. Voice data can also be sent, but needs to be sent using the Steam Networking API.
- Once the game is ready to launch, the users all join the game server, or connect to the user nominated to host the game, and then leave the lobby. Once all users have left a lobby, it is automatically destroyed.
Searching for lobbies
To have your game search for a lobby, you need to call: ISteamMatchmaking::RequestLobbyList
This function is asynchronous, returning a SteamAPICall_t handle which you can use to track the state of the request. Depending on the users connection to the Steam back-end, this call can take from 300ms to 5 seconds to complete, and has a timeout of 20 seconds.
The number of results returned is in the LobbyMatchList_t
call result, which you can then use ISteamMatchmaking::GetLobbyByIndex
to iterate over them all and get their IDs.
Up to 50 results may be returned, but usually it's no more than a couple. The results are returned ordered by geographical distance and based on any near filters set. By default, we will not return lobbies that are already full, and the distance filter is set to k_ELobbyDistanceFilterDefault
(nearby). To add filters, before you call
you need to call one or more of the filtering functions:
Creating a lobby
If you can't find an existing lobby for a user to join, this is when you'd typically create a lobby. Just callISteamMatchmaking::CreateLobby
and wait for it to complete. The call result indicates whether or not it succeeded, and if it did, it will return the steamID of the lobby in a LobbyCreated_t
struct, which can be used to set metadata on the lobby. The first thing you'll want to do after you create a lobby is set a data on the lobby, that other game clients can use to search for it (see below).
Joining a lobby
If you've found a good lobby, either from a search or from a friend, you can use ISteamMatchmaking::JoinLobby
and wait for the LobbyEnter_t
call result. Once in the lobby, you'll want to use the lobby data API to get details about the lobby to work out what to display (if there is any display).
When a user joins or leaves a lobby, a LobbyChatUpdate_t
callback is posted to all members of that lobby, including the owner.
To iterate which users are currently in a lobby, use:
To get more information about another user in the lobby, you'll need to use the friends API, see Friends, invites, and lobbies
for more information.
Lobby Metadata allows you to set the arbitrary state of the lobby, including the lobbies name, current map, game mode, current state of the game, or anything else you can think of.
A user will automatically have the latest lobby data for any lobby they are a member of. For lobbies returned via search results, the user will have lobby data for at the point in time as to when they did the search. If it's a friends' lobby, there will be no lobby data available to look at until ISteamMatchmaking::RequestLobbyData
is called and has successfully completed.
If lobby data is changed on a lobby, all lobby members will receive a LobbyDataUpdate_t
callback (this callback is the same way you know a ISteamMatchmaking::RequestLobbyData
call has completed).
These are the set of functions you can use to get and set lobby data. Only the lobby owner can set or delete the lobby data.
Functions which allow you to iterate over the metadata, (this is typically only used for debugging purposes):
Lobbies also allow members to set their own metadata that other members can receive updates for with the following functions.
Communication within a lobby
To send information around within a lobby (chat messages, game start signals, etc.) you need to call ISteamMatchmaking::SendLobbyChatMsg
, this sends a simple binary message to all users in the lobby. Lobby members need to listen for the callback ISteamMatchmaking::LobbyChatMsg_t
. After receiving the callback you then can use ISteamMatchmaking::GetLobbyChatEntry
to retrieve the contents of the message.
Friends, invites, and lobbies
You can find out all the lobbies a user's friends are in with the friends API:
int cFriends = SteamFriends()->GetFriendCount( k_EFriendFlagImmediate );
for ( int i = 0; i < cFriends; i++ )
CSteamID steamIDFriend = SteamFriends()->GetFriendByIndex( i, k_EFriendFlagImmediate );
if ( SteamFriends()->GetFriendGamePlayed( steamIDFriend, &friendGameInfo ) && friendGameInfo.m_steamIDLobby.IsValid() )
// friendGameInfo.m_steamIDLobby is a valid lobby, you can join it or use RequestLobbyData() get it's metadata
You can invite a friend to a lobby with ISteamMatchmaking::InviteUserToLobby
That user will receive a chat dialog with a link to join the game. If the user clicks the link, and they are not currently running the game, it will launch the game with the command-line:
+connect_lobby <64-bit lobby id>
If the user is already in a game, a ISteamFriends::GameLobbyJoinRequested_t
callback will be posted, which contains the Steam ID of the lobby the user wishes to join. It's up to your game to decide to obey it or not.
If you want the user to select from a list of friends to invite to a lobby, you can call ISteamFriends::ActivateGameOverlayInviteDialog
This will activate the Steam in-game overlay to a dialog designed for inviting friends to the current lobby.
Any user in a Steam lobby is already fully authenticated with the Steam back-end. There is no need for the game to do any more authentication steps with lobby users, unless it's looking to see if they're VAC banned (see Valve Anti-Cheat Technology). If a user tries to log in from a second location with the same account, their prior login will automatically be removed from any existing lobbies.
Once the game has started, each user can just leave the lobby with:ISteamMatchmaking::LeaveLobby
Once all the users have left, the lobby is automatically destroyed on the back-end.
Ask questions on the Steam Matchmaking & Lobbies discussion forum