๐๏ธLobby
Understanding what a Steam lobby is and is not, getting started with Steam Lobby
Last updated
Understanding what a Steam lobby is and is not, getting started with Steam Lobby
Last updated
Support us as a GitHub Sponsor and get instant access to all our assets, exclusive tools and assets, escalated support and issue tracking and our gratitude. These articles are made possible by our GitHub Sponsors ... become a sponsor today!
While Steam Lobby is not a true multiplayer feature ... it is in reality nothing but a chat room with metadata ... even called "Chat" on Valve's backend. It is nonetheless most commonly used for player parties and session matchmaking for we have listed it under the Multiplayer guides section.
Steam Matchmaking is driven primarily through the Steam Lobby feature. In a nutshell, the concept is that players will create a "lobby". You can think of this a bit like a chat room. This lobby has "metadata" associated with it which can be used to search for lobbies, filtering the results to just those the player cares about.โ
The metadata concept of Steam Lobby is where most of the functionality comes into play. The owner or "host" of a lobby can set the metadata on a lobby and anyone else can read that data, and the Steam Lobby search system can use that data to refine search results. In addition, each member within a lobby has a set of metadata associated with them. Lobby member metadata can only be set by the member it is related to and can only be read by other members of that lobby.โ
In summary lobby metadata is for stating the intent of the session or the status of the session and is accessible by everyone. Member metadata is for stating the intent of a member or the status of a member and is writable only by that member and readable only by fellow members of the same lobby.โ
You can read more about Steam's Matchmaking system in Valve's developer documentation.
The first and most important thing to understand is that a lobby is not a network feature or concept. That is being in a lobby does not require a network connection, a network connection does not require a lobby. Lobby and Networking are two completely independent concepts.
Please do not confuse a lobby with anything to do with a network or network connection.
The following explains; as clearly as Steam documentation allows, the available lobby types and when and how you might use them.
Private
Classified as a "Normal" lobby by Steam.
The only way to join a private lobby is to be invited to it via the Lobby.InvitePlayer feature. This can be useful in coop games when your player wants to play with a specific friend but doesn't want to be bothered by requests to join or public searches.
This lobby will not appear in searches, it will not appear on the user's friends list or rich presence data.
Friends Only
Classified as a "Normal" lobby by Steam.
This lobby can only be joined by friends of the owner or by people directly invited to it. This lobby does appear on the user's friends list but does not appear in lobby lists or searches. This is useful when the player wants friends to be able to drop in / out but doesn't want to be bothered by random players.
Public
Classified as a "Normal" lobby by Steam.
This is the typical lobby you will see used in most games. It's the classic "Matchmaking" lobby that appears on the user's friends list and can be searched for and joined by any matching player.
Invisible
This is the lobby type that Valve/Steam allows a user to be a member of 2 of this type.
This lobby is not visible in the friends list but can be searched for. That might be confusing at first read.
A random user can search for this lobby as you would a public lobby but this lobby will not show up on the Steam Friends list hence "invisible"
Every user that has joined the lobby is identified as a LobbyMember. Each member in a lobby has its own set of metadata which all other members can read but only the member itself can set. To clarify that means you can only set your lobby member metadata but you can read everyone else's data. You cannot however read lobby member metadata if you are not a member of the lobby.
Metadata refers to data stored in the lobby or on a lobby member. Put simply it's a collection of key-value pairs where the key and value are a simple string. So you can think of it much like a
The metadata stored on the lobby can be seen by anyone able to see the lobby and can be used to filter results when searching for a lobby using Steam's matchmaking system.
In contrast, metadata stored on a lobby member can only be seen by members of the lobby and is used only to share for example user configuration.
When metadata is changed the Steam API will raise the lobby data changed event ... that event will indicate what object's data changed not what data field changed so for example if the event indicates the lobby data changed you should check all the lobby metadata whereas if it indicated a members data changed you should check that members metadata.
The event in question is exposed on the Lobby Manager as evtDataUpdated and in the Matchmaking API as EventLobbyDataUpdate.
As far as setting metadata you can use the indexers to set metadata for example if you have a Lobby
in memory such as from the lobby manager.
Then you can set a metadata field on it such as
Similarly if you have a LobbyMember
in memory you can do the same thus
To learn more check out the Lobby and LobbyMember articles describing the features of the lobby and lobbyMember structures.
While the developer-facing part of the Steam API calls it a "Lobby" the backend developer-facing calls it a chat, this is because in reality a "Lobby" is just a chat room. This chat room has its own metadata as noted above and each member within it has its own metadata and you can send and receive messages containing byte[] data between all members without a network connection. Our Lobby Chat Director can help you get started.
You can invite friends to join a lobby you are a member of This works rather or not the friend is currently in the game. The general workflow for this process is
When User B clicks "Accept" That DOES NOT join User B to the lobby That simply notifies the game that User B has indicated they would like to join that lobby. It is up to you as a game developer to handle that event appropreatly for your game. Understand that the player could already be in a lobby, they could already be in a match, they could be in the process of exiting. The user that invited them might have invited a ton of other users and now the lobby is full, the user might have clicked Accept hours after the invite was sent ... there are SO MANY reasons why you do not just blindly join the lobby when you get that event.
User A joins or creates a lobby
User A Invites User B to join the lobby
User B clicks the Accept button in the Steam Friends Chat panel (overlay)
Your game client invokes the GameLobbyJoinRequest event
Your game client handles the event validating the lobby and navigating to the appropriate location in the game
Your game client joins the indicated lobby
User A joins or creates a lobby
User A Invites User B to join the lobby
User B's clicks the Accept button in the Steam Friends Chat panel (overlay)
Steam launches the game passing the Lobby ID in on the command line
Your bootstrap scene loads first and is the place to detect command line arguments such as lobby ID.
Your game client handles the event validating the lobby and navigating to the appropriate location in the game
Your game client joins the indicated lobby
When the user has accepted a lobby invite the ID of the lobby will be made available to them but the lobby's data will not be updated in the local cash.
You should Request Lobby Data for the invited lobby before attempting to read any of its metadata. You can join the lobby without reading the data however if you are properly validating the lobby you will need to read its data before joining.
Bobsi has a quick setup tutorial that goes through a basic simple setup using Heathen's Toolkit for Steamworks. The Working with Lobbies entry below goes into more details and other options you have available.
You can work with Lobby in one of 3 main ways; (from lowest level to highest)
All of the functionality of lobby is defined in the Matchmaking API. No matter how you choose to work with Steam lobbies, it's this API that will be doing the real work. Using the Matchmaking API requires that you have a level of understanding of the underlying Steam API but it does still simplify working with the API by making it Unity-centric, handling boilerplate concepts such as the callbacks and simplifying common concepts in a Unity manager e.g. UnityEvents and Actions, simpler calls, etc..
LobbyData as in the object in Steamworks Complete is a struct which wraps around ulong and CSteamID. Fundamentally it acts as a lobby ID and is implicitly convertible between ulong and CSteamID meaning you can pass it along as if it were a ulong value or a CSteamID and you can assign it from a ulong value or a CSteamID. Beyond being a fancy wrapper around ulong it also has accessors and methods that make working with a specific lobby very easy. Using the lobby object you very likely won't need to touch the raw API at all.
As the name suggests this is a tool for managing a lobby. The lobby manager is the easiest way to manage a lobby and is a Unity component ... that is you can add it to a GameObject and configure it in Unity editor. The Lobby Manager does more than simply expose Matchmaking events to the Unity editor it handles common concepts for you and makes it easier to work with a lobby through designer-friendly tools such as Bolt and other visual scripting assets.
Your first question when managing a lobby is how to know when the user joins or leaves a lobby and what lobby it was that they joined or left. From low level to high here are the notes!
EventLobbyEnterSuccess and EventLobbyEventFailed are raised when the local user tries and succeeds or fails respectively to enter a lobby. Both events return the LobbyEnter structure provided by Steam API.
The lobby object Join method takes a callback so for example
So we do a bit more work here so we can understand if it was a success or not, and if not why not. The EChatRoomEnterResponce tells us why.
In our example above we used expression to create an anon method. This is a style choice you can learn more about expression and anon methods in our other articles.
Lobby manager makes this super easy. Using Lobby Manager you don't need to use any code at all if you don't want. You will see right in the inspector an evtEnterSuccess and an evtEnterFailed event. These work just like the ones on Matchmaking API but of course are accessible from the Unity Editor and only raise for lobbies that were joined through this Lobby Manager.
The fact that Lobby Manager filters its events to only the events that were run through it makes it much easier when driving UI elements. Most games will have 2 lobbies, 1 for the session aka "matchmaking" and 1 for a player friend group or party. The Matchmaking API events raise for any event on any lobby that the local user is a member of so if a user is in a session lobby and a party lobby the events will raise for both leaving it up to you to sort out which lobby the event goes to.
Lobby Manager only handles events for the lobby that it is "managing" so it is filtering the events down for you. Thus when the "evtEnterSuccess" triggers on your MatchmakingObject's LobbyManagaer component you know it's related to the matchmaking lobby.
Yes, you can of course use the Lobby Manager from code as much or as little as you would like. Doing so is no different than using any other Unity component from code.
This is how do you know when some other player joins or leaves the lobby that your in. In other words, how do you know when new "peers" come in or go out of the lobby?
This is actually handled via the EventLobbyChatUpdate event which is raised any time a chat event occurs ... including when members join or leave.
The handler for this event would look something like this, note the work is done in the EChatMemberStateChange data
There is no way to do this from the lobby object as the lobby object is a struct and doesn't define events.
As always the Lobby Manager makes it easier not just by filtering on the lobby for you but also by splitting the event into two. evtUserJoined and evtUserLeft invoke when someone joins or leaves respectively. These events are UserData events meaning they hand you the UserData of the member that joined or left.
Gets data about a lobby, if you have been invited to a lobby you will probably want to get data about it before attempting to join it. This can be useful when preparing the lobby UI or to confirm that the lobby is a valid lobby for the local player.
This is the event that Valve's Steam will invoke when the user is currently in your game and accepts an invite to a lobby for your game. The event can be found on the Overlay.Client and on the Overlay Manager.
In the event the user accepts an invite to a lobby in your game and is not currently playing your game then Steam will launch your game with the lobby ID on the command line. We have provided you with tools to make detecting this easy.
Our Steamworks Behaviour script checks for this case on initialization and raises an event if found.
CommandLine is a tool available in the HeathenEngineering namespace. It can read common command line arguments for you including a Steam Lobby ID.
You often need to know when data on the lobby or a given member has changed.
The EventLobbyDataUpdate event is raised when any sort of data is updated for the lobby or a member.
This cannot be done from the Lobby object alone as it is an event and the struct doesn't have any of the events.
Lobby Manager is much like the Matchmaking API for this one and uses the evtDataUpdated method to know when any kind of data has changed.
Metadata Read/Write
Writing lobby metadata data can only be done by the owner of the lobby. Metadata on the lobby is what is used when searching for a lobby and is what you would use to express configuration and settings of the session the lobby deals with. For example if you wanted to let all users know what map the session will be on then you would set a lobby metadata data field map = X.
Use the SetLobbyData method to apply lobby data. This can only be done if the user is the owner of the lobby.
Using the lobby object its a step easier and you have a few options
Simple indexer
and we have exposed several common fields as fields on the struct
The lobby manager lets you use both approaches
We are often asked how do you "get" the lobby your in as in once you joined or created a lobby how to do you get to its LobbyData so you can use it for whatever it is you need to use it for.
The answer differs depending on context so here are some common cases.
or for that matter, Quick Match Lobby Control or Party Lobby Control or any similar lobby management tool.
In all cases these tools have a field on them named Lobby that returns the lobby they are managing ... similarly you can set the lobby you want them to manage by writing a value to this field.
If you use our tools we will mark lobby's by their type ... that is we will mark the lobby as the "group" lobby when you use the Party Lobby Control and we will mark it as the "session" lobby when you use the Quick Match Lobby Control. Note you can configure the Lobby Manager to set this for you if using it. And you can set this yourself if your creating lobby manually.
To set this your self after the creation of your lobby call
or
Note there should only be 1 group and 1 session lobby at a time, you can then get these special use case lobbies from anywhere in code
or
Our system tracks every lobby the local user is a member of, a user cannot be a member of more than 3 lobbies and so it's trivial to just iterate over the lobbies they are a member of to choose the one you want.
or if you prefer Linq (we do)
For more information on lobby types see Valve's documentation https://partner.steamgames.com/doc/api/ISteamMatchmaking#typedefs
See the API.Matchmaking interface for details on creating a lobby. In addition the Lobby Manager, tools can help you create, join and manage a lobby for a specific function in your game.
Let's say for example you use 2 types of lobbies in your game
Party
This would be where you have your player gather a group of friends together to play together i.e. a group or party as seen in MMOs, MOBA or any game with a coop feature
Session Lobby
This would be where you have your players configure a gameplay session and wait for competitors to join or similar. This is the most typical use of a lobby and what drives matchmaking in your game.
In the above use case, you would attach a Lobby Manager to your Party UI and another to your Session UI. You would configure each accordingly and each can manage its own chat and metadata features. This helps you split functionality across concepts unique to your game.
The easiest way to search for and join lobbies is through the Lobby Manager tool. Alternatively, you can use Heathen's API.Matchmaking directly to easily search for and join lobbies.
Aside from browsing for a lobby you can handle invites and joining of lobby invites. Inviting friends to Lobby can be done in several ways including from outside of your game via the Steam Friends list.
Internally to you're game you can use the User Data object to invite a specific player. You would have access to this object from various tools and interfaces including Friends, Clans and their related chat systems. When you send an invite it is up to that user to accept it and there are multiple use cases for how they might accept the invite
In this case, the accepting user is already in-game so the Game Lobby Join Invite event will be raised on the Overlay Manger and its related API.Overlay interface.
In this case, the accepting user is not yet in the game so the Steam client will launch the game and pass as an argument on the command line the lobby connection information. It is up to you to handle this argument, navigate to the appropriate place in your game e.g. the lobby UI and then join the lobby ID indicated on that argument.
A crude example follows
Steam's Lobby system includes a simple chat system able to handle text or data. The easiest way to interact with lobby chat is via the Lobby Chat Director which needs to be added to the same object as your Lobby Manager.
You can also interact with lobby chat manually through the API.Matchmaking interface.
This will set the Game Server information on the lobby and can be done in a number of ways. You are required to have either a Steam ID (which a UserData is) or an IP and Port or both, when you call the SetGameServer method with no input parameters it will assume the owner of the lobby is the Listen Server.
The typical purpose of a lobby is to gather players and settle on the rules and conditions of the multiplayer session. In most cases, you will at some point want to notify players that they should connect to a particular server be that a Peer in a P2P game or a dedicated server on the net.
The lobby system provides tools for this via the SetGameServer
method on the lobby
The SetGameServer method can only be called by the "Owner" of the lobby
When called Valve will record the information on the Steam Lobby metadata as shown below
Each member of the lobby (other than the owner) will be notified by a callback which raises the EventLobbyGameCreated
event located on the API.Matchmaking interface and exposed through the Lobby Manager.
All members of a lobby should upon joining the lobby register an event handler on the Lobby.evtGameServerSet
event
Hopefully, you have read the above so you understand the fundamentals of a lobby and what features it has including how to notify the other members when it's time to connect to the network.
So your question then is how do you know when to transition from being in the lobby to starting the network session, and we can't answer that for you. This is entirely up to your game design but here are a couple of common use cases.
In this case, you are simply assuming it is time to play when the lobby gets full e.g.
In this case, you were assuming it is time to play when the lobby is full and all players have indicated they are ready. Note this requires you to provide the players with a means to set
This sets the metadata on that user indicating it is ready to play, we use that in the following test
Once you know when you want to start the network session it's time to ... start the network session ... exactly what you need to do to do that depends on the networking tool you chose to use but here is the usual workflow with the code snippets relevant to Steam lobby.
First, you probably want to set the lobby joinable as false. This will prevent newcomers from joining while you transition players over to the network session. Of course, if your game supports "drop-in/drop-out" you don't want to do this ... use your judgment with regards to your design.
You would then have the owner do whatever it is your networking tool needs you to do to start up the network session. Don't know what that is? consult your networking tool of choice ... it is usually something like loading up the appropriate scene and using the network manager to call StartHost() or similar.
Once the network session is ready you have the owner notify the other members that it's time to connect to the network session.
Notice in this case we do not provide any parameters to the SetGameServer call ... this is assuming your session will be P2P and that the owner is the host ... for more information please consult the article on LobbyData.
This will cause the GameServerSet event to be triggered as noted in the Notify "Connect to network" entry.
When users see that event they will use the GameServer information in the lobby to know who to connect to. You have options here and which you would use depends again on your game and your design. The following code simply highlights what's available in the LobbyGameServer information you read on the GameServer field of the lobby.
Once your members connect they would typically then leave the lobby ... this is not a requirement simply typical. You do not need the lobby once you have the network session going unless, of course, you're doing the classic "Drop-In/Drop-Out" style gameplay in which case the lobby should persist for the duration of the session.
A common question asked is how to know the user Joins or Leaves a lobby. A player will not join or leave a lobby if you do not call Join Lobby or Leave Lobby respectively so you define when this will happen.
This is how you know when some other player joins or leaves the lobby that you are in. In other words, how do you know when new "peers" come in or go out of the lobby?
This event is executed when a user enters or exits. The event tells you the ID of the lobby that was effected, what user it was that was effected, who caused the change if that is different and what change was made.
Note that while "Kicked" is an option for state change that is an internal feature of Steam ... you cannot kick a user out of a lobby at least not with a feature built-in by Valve.
When your player is invited to a lobby they will not have a view of that lobby's data which you may want to check before joining such as to validate that the lobby is suitable for the player's current state.
The Lobby Join Requested event is executed when the user accepts a lobby invite and is currently in-game.
Note the player is not automatically joined to the lobby, it's up to you to validate that the lobby is fit for purpose given the user and state of the game. To then navigate to an appropriate place in the game and join the lobby through the normal means of Join Lobby.
If the player accepts an invite but is not currently in the game, then Steam will launch the game with the lobby ID passed in on the command line.
Above we are fetching the command line, checking it for the +connect_lobby
argument and if found we parse that value to an int64 which we can use as a Lobby ID for other operations such as Requesting the Lobby Data or Joining the Lobby.
To detect when metadata has changed on the lobby or a member of the lobby you can use the Lobby Data Update event.
This event is executed when any data changes on a lobby be it data for the lobby itself or a member of the lobby.
You can get or set data on a player's lobby member using Set Lobby Member Data
Only the members themselves can set their data but any member of the lobby can read it. This is useful for setting things such as player selection, map votes, etc.
The owner of a lobby can do the same on the lobby itself, the data on a lobby can be used to search for and filter lobbies and can be read by anyone not just members of the lobby.
Creating a lobby is a simple function call, once the lobby is created you can then update its data, change its type, mark it as joinable or not, etc.
A lobby is simply an ID, all lobbies will have 1 or more members, you do not "destroy" or "close" a lobby, they simply cease to exist when there are no members in them.
1 user is always said to "own" the lobby, by default, this is the user that created it but that can be changed after e.g. the owner can set a different user as owner.
To find a lobby to join you set up a request by adding filters, then making the request. When you make a request it clears the filters so you will need to set up the filters again to make a subsequent request.
In the above example, we set up a search to find a lobby where map = Some Cool Map Name
We then iterate over the results and get the Lobby by index for each.
The above is not functional but shows you the important nodes to work with. In functional logic, you would build out a more complete search filter, check the result count was greater than zero, and then handle each result as required.
For example, a quick match would simply join the first lobby found. As the Steam Lobby system is a Matchmaking query the first lobby found is the "best" lobby to join.
A Steam Lobby is little more than a fancy chat room, Steam API even refers to a Lobby ID as a CSteamID of type Chat. You can use a lobby as a chat room sending and receiving data messages without needing a network session. Note that this is a chat, so it's not suitable for real-time data such as Voice Streaming but can handle simple text messages or even send serialized data such as authentication tickets.
The Lobby Chat Msg event is executed when a chat message is received and can be used with the Get Lobby Chat Entry node to read the message
This will set the Game Server information on the lobby and can be done in a number of ways. You are required to have either a Steam ID (which a UserData is) or an IP and Port or both, when you call the SetGameServer method with no input parameters it will assume the owner of the lobby is the Listen Server.
Steam provides a built-in way to notify members of a lobby when the network is ready for them to connect. This is done by the owner of the lobby calling Set Game Server or its variants.
This has several variations for Peer to Peer (where the lobby owner is the server), Steam Game Server (where the server is addressed by an ID) as well as traditional IP/Port-based connection addressing.
When the owner of the lobby calls this all members will receive the Lobby Game Created event.
This event provides the connection details for the server to all members