Matchmaking API
- Introduction
- Glossary
- Creating And Joining A Game Session
- Getting And Updating The Game Session Information
- Joining A Game Session From A Lobby
- Examples Of API Usage
Introduction
One key requirement while creating a multiplayer game is to easily be able to match together players with similar skills, level, or that wants to play the same game type or map, making the overall experience in-game as enjoyable as possible. For this purpose, Photon Fusion exposes a set of API calls that can be used to create the best experience for players looking for the perfect match.
Photon Fusion works with the Photon Cloud transparently, so most of the interactions with the Photon backend services are done automatically internally.
On this page it is described the Fusion Matchmaking API, which is used to create/update a Game Session
with custom properties that can be used by players to filter/join the best Session
based on their desired game play experience.
Glossary
Below are described some terms used along this document that are directly related to the correct usage of the Matchmaking API
.
Game Session
: or justSession
is where Players meet to play a match or communicate. This is what gets published in the Photon Cloud and made available so other clients can search, filter, and join a particular match. Communication outside of anySession
is not possible and any client can only be active in one room.Game Sessions
have the following properties and methods: can be created and joined by name,Custom Properties
, has a maximum amount of players, can be hidden (do not show inLobby
) or visible, can be closed (no one can enter) or opened,Lobby
: is a virtual container or "list" ofSessions
. It is possible to use multiple lobbies to split the sessions between different game types, for example. In Fusion, when aSession
is created inClientServer Mode
(Server
,Host
,Client
), theSession
is created in a specificLobby
calledClientServer
, if theSession
is created inShared Mode
, it will be created in aLobby
calledShared
. Players can't communicate in theLobby
and they never know that another client is also in the lobby. A client can only be in aLobby
, aSession
or neither.
Creating And Joining A Game Session
The Game Session
creation and joining are two parts of the same procedure, and the rule is simple:
1. if there is no Session
with the specified SessionName
, a new one will be created (not in all cases as explained below) with that SessionName
; and,
2. the peer joins the Session with that SessionName
.
In terms of API, all of this is done automatically when a new Fusion Simulation is started, and below are listed the main arguments that can be used to customize the Session when creating a new one:
NetworkRunner.StartGame(new StartGameArgs {
// other args...
SessionName = [string]
SessionProperties = [Dictionary<string, SessionProperty>],
CustomLobbyName = [string],
PlayerCount = [int],
DisableNATPunchthrough = [bool],
CustomSTUNServer = [string],
AuthValues = [AuthenticationValues],
DisableClientSessionCreation = [bool]
});
All Game Session
related arguments are optional and the default values each will take are described below:
- SessionName: the
Game Session
'sName
, it will identify the session on thePhoton Cloud
and it must be unique within a Region. By default, if noName
is set, Fusion will generate a randomGUID
to identify the Session, which leads to two possible cases:- when starting with a specific
SessionName
, Fusion will always try to create/join aSession
with thatName
. That is an important fact about Fusion, aClient
peer is able to create sessions - that is called late-join-server, where aServer
can join aSession
created by aClient
beforehand; and, - when not specifying a
SessionName
, Fusion will create/join a new Session only if you are starting inHost
,Server
, orShared
game modes, and will try to join a RandomSession
if you are starting inClient
mode.
- when starting with a specific
- SessionProperties: the
Session
'sCustom Properties
are the way to include metadata about yourGame Session
, like the game mode/type or the currently loaded map. Keep in mind that the properties are always published to theSession Lobby
when creating theSession
. Another use of this argument is as matching filters when aClient
is joining a RandomSession
. As a suggestion, always try to keep theProperties Keys
strings as short as possible in order to minimize traffic. By default, theSession Custom Properties
are empty and no extra information is included. - CustomLobbyName: a
Lobby
is nothing more than a way to aggregate similarGame Sessions
, which can be used to segregate sessions with different game types, for example. This argument is used to set customLobby Name
with which theSession
will be associated with. By default, Fusion already separates aSession
based on theGameMode
, either on theClientServer Lobby
if theSession
was created inHost
,Server
, orClient
game modes or theShared Lobby
when created inShared
game mode. - PlayerCount: defines the max number of clients that can connect to this
Session
. This parameter is only used when creating a newSession
and by default, it takes the value set on theDefault Players
settings on theNetworkProjectConfig/Simulation
. - DisableNATPunchthrough: a boolean flag that can be used to disable the NAT Punchthrough System implemented on Photon Fusion. This will enforce a relayed connection between clients and servers. If set to
true
on theGame Server
, all clients will connect via relay, if set on aClient
, only this particular peer will connect using a relayed connection. - CustomSTUNServer: specify a Custom STUN Server used to Resolve the peer Reflexive Addresses.
- AuthValues: custom Authentication Values used to authenticate the peer using an external service. The authentication is done using a pre-configured service on the
Photon Dashboard
for your specificApplication ID
. - DisableClientSessionCreation: a boolean flag used to enforce that peers starting as a
Client
will not create a newSession
even if aSessionName
is specified. By default,Clients
are able to createSessions
and wait for aServer
to join, using this flag you can disable this behavior.
With this API it is possible to create and join a Game Session
, either at random or with a specific SessionName
, that can be used when receiving a Game Invitation, for example, but also enables Session
filtering using custom properties, in order to only join games with specific configurations.
This already provides a lot of flexibility when managing the sessions.
The following table summarizes how Fusion handles the Game Session
creation and joining, as it depends on the SessionName
and GameMode
when starting the simulation.
Valid Session Name | GameMode | Behavior |
---|---|---|
Yes | Host/Server | Create the Session |
Client | Join the Session or fail if not found | |
Shared | Join the Session or Create it if not found | |
No | Host/Server | Create a Session with a Random name |
Client | Join a random Session or fail if not found | |
Shared | Join a random Session or Create a Session with a Random name if not found |
Getting And Updating The Game Session Information
Fusion provides a lot of information about the currently connected Game Session
like its Name
and Region
.
These data are directly available in NetworkRunner
through the SessionInfo
property.
Below are listed all available fields of the SessionInfo
type:
IsValid [bool{get}]
: signal if theSessionInfo
is ready for read/write.Name [string{get}]
: theSession Name
.Region [string{get}]
: the currently connectedRegion
.Properties [Dictionary<string, SessionProperty>{get}]
: a read only dictionary with the currentSession Custom Properties
. In order to update these properties, just use theSessionInfo.UpdateCustomProperties(Dictionary<string, SessionProperty>)
method and pass the a new set of properties.IsVisible [bool{get,set}]
: signal if theSession
isVisible
onLobby
. Making aSession
invisible is just a matter of changing this property.IsOpen [bool{get,set}]
: signal if theSession
isOpen
to join. In order to close or open aSesion
, just alter this property.PlayerCount [int{get}]
: the current number ofPlayers
in theSession
. Only available in the Lobby.MaxPlayers [int{get}]
:Max Number
of peers hat can join theSession
, this value also includes a slot of theServer/Host
peer. Only available in the Lobby.
Keep in mind that the Session
information and mainly the Custom Properties
, should be used for Matchmaking purposes only and never to synchronize game state information with the game clients, for example. We highly discourage such uses.
If you need to exchange information session-wide that is related to gameplay, Fusion offers plenty of options, like having a global NetworkObject
s or using RPC
s for one-shot data.
The NetworkRunner
also provides some other Session
and Photon Cloud
related properties that can be used in-game, like:
NetworkRunner.IsCloudReady
: signal if the Local Peer is connected toPhoton Cloud
and is able to Create/Join a Room or join a Lobby.NetworkRunner.UserId
: holds theUserId
associated with the Local Peer after it gets authenticated. This information comes from Authentication Service used by your application.NetworkRunner.AuthenticationValues
: holds the reference of theAuthenticationValues
used to authenticate the local peer when starting Fusion.NetworkRunner.CurrentConnectionType
: describes the current Connection Type used by the peer, either aDirect
orRelayed
connection with the remoteServer
. Keep in mind that inSharedMode
, the clients always connect via relay.NetworkRunner.NATType
: when the NAT Punchthrough System is enabled, Fusion will try to determine the current NAT Type of the current network where the local peer is running, this property exposes this information. NAT Types can be:Invalid
,UdpBlocked
,OpenInternet
,FullCone
orSymmetric
.NetworkRunner.IsSharedModeMasterClient
: boolean flag that describes if the local peer is also theMaster Client
of aShared Game Session
. This is only valid when running inSharedMode
and can be used to determine in which peer certain actions should happen based on the differentiation between other clients and theMaster Client
.
Joining A Game Session From A Lobby
Another way to find the right Game Session
is to provide a list of Sessions
, allowing the player to choose one to join.
Joining a Lobby
is the way to go in this case, although we suggest avoiding this method if it is really not necessary.
For most game types, joining a Session
based on property filters is the best way, but Fusion makes Session Listing
pretty easy too.
Instead of using the usual flow and starting Fusion as described above, the Session
listing follows a slightly different flow:
- Join a Lobby: using a Fusion Runner reference, just call
NetworkRunner.JoinSessionLobby(SessionLobby, [string])
in order to make the local peer connect to the Photon Cloud and enter a specificLobby
. This method receives two arguments:SessionLobby
: which can be one of the following values:ClientServer
to join the defaultClientServer Lobby
;Shared
to join the defaultShared Lobby
; and,Custom
, used in conjunction of aCustom Lobby Name
.
LobbyName
: this should be aCustom Lobby Name
used when creating a previousGame Session
.
- Get a list of Game Sessions: when working with Fusion, one of the main API entrypoints is the
INetworkRunnerCallbacks
, a special interface that Fusion uses to surface a series of different events, including the list of sessions from aLobby
. TheOnSessionListUpdated(NetworkRunner runner, List<SessionInfo> sessionList)
callback will be invoked every time the list of sessions has changed, either by the creation/removal of sessions or when the properties of a session are updated. TheSessionInfo
is of the same type described above. The list can then be shown, filtered, ordered, etc. - Join a Session: with a selected
Session
to join, Fusion can be started using the usualNetworkRunner.StartGame()
, but in this case, theSessionName
used to start the client must be the one from the Session. That way theClient
will join this particularGame Session
.- Select the right
GameMode
as usual, as the peer is joining theSession
it must be eitherGameMode.Client
orGameMode.Shared
modes. - The
SessionName
field must be set toSessionInfo.Name
, as this is the identifier of theGame Session
. - All other parameters are optional and should be initialized accordingly, like the
SceneObjectProvider
for example.
- Select the right
Examples Of API Usage
Starting A New Game Session With Custom Properties
In this example a Host
will create a Game Session
with some custom properties, so later, Clients
can filter the Sessions
using those properties.
// Some predefined types used as values for the Game Session Properties
public enum GameType : int {
FreeForAll,
Team,
Timed
}
public enum GameMap : int {
Forest,
City,
Desert
}
// Utility method to start a Host using a defined GameMap and GameType
public async Task StartHost(NetworkRunner runner, GameMap gameMap, GameType gameType) {
var customProps = new Dictionary<string, SessionProperty>();
customProps["map"] = (int)gameMap;
customProps["type"] = (int)gameType;
var result = await runner.StartGame(new StartGameArgs() {
GameMode = GameMode.Host,
SessionProperties = customProps,
});
if (result.Ok) {
// all good
} else {
Debug.LogError($"Failed to Start: {result.ShutdownReason}");
}
}
The sample code shows the use of Enums
for the Custom Properties
values of the Game Session
, but this is just one way to add meaning to the values.
Calling the runner.StartGame
as a Host
(GameMode = GameMode.Host
) is enough to start a new session with a Random Name
(as the SessionName
argument was not passed) and by using the SessionProperties
argument, Fusion will include those properties in the Session
.
Join A Random Session With Filters
Considering the example code above, here it is shown how to start a Client
that will join any Game Session
on any GameMap
, but with a specific GameType
.
The startup code is basically the same, just the GameMode
that is now set to GameMode.Client
, and the customProps
contains only the type
key with the desired gameType
value.
public async Task StartClient(NetworkRunner runner, GameType gameType) {
var customProps = new Dictionary<string, SessionProperty>() {
{ "type", (int)gameType }
};
var result = await runner.StartGame(new StartGameArgs() {
GameMode = GameMode.Client,
SessionProperties = customProps,
});
if (result.Ok) {
// all good
} else {
Debug.LogError($"Failed to Start: {result.ShutdownReason}");
}
}
That is enough to make your client join a random Session
with that specific GameType
.
Join A Session From A Lobby
Instead of starting Fusion right away, getting the Sessions
from the Lobby
requires another set of methods.
The sample code below makes the Fusion Runner connect to the Photon Cloud and join the pre-defined ClientServer
Lobby.
// Utility method to Join the ClientServer Lobby
public async Task JoinLobby(NetworkRunner runner) {
var result = await runner.JoinSessionLobby(SessionLobby.ClientServer);
if (result.Ok) {
// all good
} else {
Debug.LogError($"Failed to Start: {result.ShutdownReason}");
}
}
And as described before, it is possible for a Client
to join the ClientServer
, Shared
or Custom
lobbies this way.
In the case of the Server/Host is creating a Session
in a Custom
Lobby, as shown below:
public async Task StartHost(NetworkRunner runner) {
var result = await runner.StartGame(new StartGameArgs() {
GameMode = GameMode.Host,
CustomLobbyName = "MyCustomLobby"
});
if (result.Ok) {
// all good
} else {
Debug.LogError($"Failed to Start: {result.ShutdownReason}");
}
}
The join Lobby
request on the Client
need to change to:
// Utility method to Join a Custom Lobby
public async Task JoinLobby(NetworkRunner runner) {
var result = await runner.JoinSessionLobby(SessionLobby.Custom, "MyCustomLobby");
if (result.Ok) {
// all good
} else {
Debug.LogError($"Failed to Start: {result.ShutdownReason}");
}
}
Once the connection is established, the Fusion Runner will invoke the OnSessionListUpdated
callback on all registered INetworkRunnerCallbacks
.
Below, there is an example code showing how to join the first Session
in the list.
public class MyBehaviour : Fusion.Behaviour, INetworkRunnerCallbacks {
// other callbacks...
// Receive the List of Sessions from the current Lobby
public void OnSessionListUpdated(NetworkRunner runner, List<SessionInfo> sessionList) {
Debug.Log($"Session List Updated with {sessionList.Count} session(s)");
foreach (var session in sessionList) {
Debug.Log($"Joining {session.Name}");
// This call will make Fusion join the first session as a Client
runner.StartGame(new StartGameArgs() {
GameMode = GameMode.Client, // Client GameMode
SessionName = session.Name, // Session to Join
SceneObjectProvider = GetSceneProvider(runner), // Scene Provider
DisableClientSessionCreation = true, // Make sure the client will never create a Session
});
return;
}
}
}