This page is a work in progress and could be pending updates.

Matchmaking API

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.

Back To Top

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, int>],
  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's Name, it will identify the session on the Photon Cloud and it must be unique within a Region. By default, if no Name is set, Fusion will generate a random GUID to identify the Session, which leads to two possible cases:
    1. when starting with a specific SessionName, Fusion will always try to create/join a Session with that Name. That is an important fact about Fusion, a Client peer is able to create sessions - that is called late-join-server, where a Server can join a Session created by a Client beforehand; and,
    2. when not specifying a SessionName, Fusion will create/join a new Session only if you are starting in Host, Server, or Shared game modes, and will try to join a Random Session if you are starting in Client mode.
  • SessionProperties: the Session's Custom Properties are the way to include metadata about your Game Session, like the game mode/type or the currently loaded map. Keep in mind that the properties are always published to the Session Lobby when creating the Session. Another use if this argument is as matching filters when a Client is joining a Random Session. As a suggestion, always try to keep the Properties Keys strings as short as possible in order to minimize traffic. By default, the Session Custom Properties are empty and no extra information is included.
  • CustomLobbyName: a Lobby is nothing more than a way to aggregate similar Game Sessions, which can be used to segregate sessions with different game types, for example. This argument is used to set custom Lobby Name with which the Session will be associated with. By default, Fusion already separates a Session based on the GameMode, either on the ClientServer Lobby if the Session was created in Host, Server, or Client game modes or the Shared Lobby when created in Shared game mode.
  • PlayerCount: defines the max number of clients that can connect to this Session. This parameter is only used when creating a new Session and by default, it takes the value set on the Default Players settings on the NetworkProjectConfig/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 the Game Server, all clients will connect via relay, if set on a Client, 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 specific Application ID.
  • DisableClientSessionCreation: a boolean flag used to enforce that peers starting as a Client will not create a new Session even if a SessionName is specified. By default, Clients are able to create Sessions and wait for a Server 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

Back To Top

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 the SessionInfo is ready for read/write.
  • Name [string{get}]: the Session Name.
  • Region [string{get}]: the currently connected Region.
  • Properties [Dictionary<string, int>{get}]: a read only dictionary with the current Session Custom Properties. In order to update these properties, just use the SessionInfo.UpdateCustomProperties(Dictionary<string, int>) method and pass the a new set of properties.
  • IsVisible [bool{get,set}]: signal if the Session is Visible on Lobby. Making a Session invisible is just a matter of changing this property.
  • IsOpen [bool{get,set}]: signal if the Session is Open to join. In order to close or open a Sesion, just alter this property.
  • PlayerCount [int{get}]: the current number of Players in the Session. Only available in the Lobby.
  • MaxPlayers [int{get}]: Max Number of peers hat can join the Session, this value also includes a slot of the Server/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 NetworkObjects or using RPCs 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 to Photon Cloud and is able to Create/Join a Room or join a Lobby.
  • NetworkRunner.UserId: holds the UserId 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 the AuthenticationValues used to authenticate the local peer when starting Fusion.
  • NetworkRunner.CurrentConnectionType: describes the current Connection Type used by the peer, either a Direct or Relayed connection with the remote Server. Keep in mind that in SharedMode, 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 or Symmetric.
  • NetworkRunner.IsSharedModeMasterClient: boolean flag that describes if the local peer is also the Master Client of a Shared Game Session. This is only valid when running in SharedMode and can be used to determine in which peer certain actions should happen based on the differentiation between other clients and the Master Client.

Back To Top

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:

  1. 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 specific Lobby. This method receives two arguments:
    • SessionLobby: which can be one of the following values:
      1. ClientServer to join the default ClientServer Lobby;
      2. Shared to join the default Shared Lobby; and,
      3. Custom, used in conjunction of a Custom Lobby Name.
    • LobbyName: this should be a Custom Lobby Name used when creating a previous Game Session.
  2. 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 a Lobby. The OnSessionListUpdated(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. The SessionInfo is of the same type described above. The list can then be shown, filtered, ordered, etc.
  3. Join a Session: with a selected Session to join, Fusion can be started using the usual NetworkRunner.StartGame(), but in this case, the SessionName used to start the client must be the one from the Session. That way the Client will join this particular Game Session.
    • Select the right GameMode as usual, as the peer is joining the Session it must be either GameMode.Client or GameMode.Shared modes.
    • The SessionName field must be set to SessionInfo.Name, as this is the identifier of the Game Session.
    • All other parameters are optional and should be initialized accordingly, like the SceneObjectProvider for example.

Back To Top

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, int>();

  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.

Back To Top

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, int>() {
    { "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.

Back To Top

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,
        SessionName = session.Name,
        SceneObjectProvider = GetSceneProvider(runner),
      });

      return;
    }
  }
}


To Document Top