This document is about: FUSION 2
SWITCH TO

Custom Realtime Client

Overview

Starting with Fusion 2.1, it is possible to use a custom Realtime Client with Fusion, enabling advanced use cases not yet covered by the Fusion API. This allows:

  1. Complete control over the matchmaking process even before starting Fusion.
  2. Make use of new features directly from the Realtime SDK that are not exposed yet via Fusion APIs.

This allows Fusion clients to use entirely custom matchmaking processes that are not yet supported by Fusion API, like the usage of SQL Lobbies or the new Ticket System. Along with that, Fusion 2.1 comes with the new Realtime v5 SDK, which includes a lot of extra features.

Custom Realtime Client

In order to connect to the Photon Cloud, the Fusion SDK always makes use of a Realtime Client instance, which is used to connect the peer to a Photon Region and eventually to a Game Session.

With Fusion 2.1, it is now possible to pass along with the other StartGameArgs a custom instance of a RealtimeClient, which will be used by the peer to connect to the Photon Cloud.

C#

var startResult = await networkRunner.StartGame(new StartGameArgs {
  // Other arguments
  RealtimeClient = [RealtimeClient]
});

This parameter is completely optional, and by default, if that argument is not passed, Fusion will create and manage the lifecycle of an internal Realtime client instance.

If an instance is passed when starting a NetworkRunner, Fusion will:

  1. Check if it has not yet connected to the Photon Cloud, and connect if necessary.
  2. Check if it has not yet joined a Session, and join if necessary.
  3. Start the Fusion simulation as usual.

This means that a custom Realtime client instance can be used for any prior task (especially matchmaking), before starting any Fusion-related code.

Basic Example

Here, a simple matchmaking script using a custom Realtime Client will be described, which will handle:

  1. Connecting to the Photon Cloud;
  2. Creating/Joining a Session by ID and at random;
  3. Join a Lobby and join an already created Session.

C#

using System.Threading.Tasks;
using Fusion;
using Fusion.Matchmaking;
using Fusion.Photon.Realtime;
using Photon.Realtime;
using UnityEngine;

public class SimpleMatchmaker : MonoBehaviour
{

    // NetworkRunner Prefab Reference
    public NetworkRunner runnerPrefab;

    // Internal references
    private RealtimeClient _client;
    private NetworkRunner _runner;

    // Setup Realtime Client if necessary
    private void SetupRealtimeClient()
    {
        if (_client != null) return;

        // Create a Realtime Client and set it up for Fusion usage
        _client = new RealtimeClient().SetupForFusion(); // must be invoked, see below
        _client.AddCallbackTarget(this);
    }

    private void Start()
    {
        // Keep it around
        DontDestroyOnLoad(this.gameObject);
    }

    private void Update()
    {
        // Check if NetworkRunner is valid
        if (_runner == false)
        {
            // Run updates
            _client?.Service();
        }
    }

    // Join a Lobby to look for a Session to Join
    private async Task JoinSessionLobby()
    {
        Debug.Log("Join Session Lobby...");

        SetupRealtimeClient();

        // Connect to the Photon Cloud
        await _client.ConnectUsingSettingsAsync(PhotonAppSettings.Global.AppSettings);

        // Join Lobby
        await _client.JoinLobbyAsync();

        if (_client.InLobby)
        {
            Debug.Log($"Joined Lobby: {_client.CurrentLobby.Name} [{_client.CurrentLobby.Type}]");
        }
    }

    // Connect to a given Room Name or join a random one
    // if no roomName is passed
    private async Task ConnectToRoom(string roomName = null)
    {
        Debug.Log($"ConnectToRoom: {roomName}");

        SetupRealtimeClient();

        // Setup Matchmaking 
        var matchmakingArguments = new MatchmakingArguments
        {
            RoomName = roomName // if null, a random name will be generated by the Photon Cloud
        }.SetupForFusion(); // must be invoked, see below

        await _client.ConnectToRoomAsync(matchmakingArguments);

        if (_client.InRoom)
        {
            Debug.Log($"Client is in room: {_client.CurrentRoom.Name} [{_client.CurrentRegion}]");
        }
        else
        {
            Debug.LogError($"Unable to join Room");
        }
    }

    // Disconnect the client from the Photon Cloud
    private async Task DisconnectFromCloud()
    {
        Debug.Log("Disconnecting...");

        if (_client != null)
        {
            await _client.DisconnectAsync();
        }

        _client = null;
    }
}

Important points to observe:

  1. When creating a new RealtimeClient instance that is going to be used with Fusion, it is required to call the SetupForFusion() utility method. This will set up some of the client parameters to work with the Fusion SDK properly.
  2. When creating an instance of MatchmakingArguments to be used with the Realtime Async API, it is required to call the SetupForFusion() utility method. This will copy some of the settings from Fusion into Realtime's MatchmakingArguments, which must be set before connecting to the Photon Cloud.

The script above just wraps some utility methods around a RealtimeClient instance.
To know more about how to handle the RealtimeClient instance, please follow the Realtime SDK documentation page here.

It can be extended with the following:

C#

private async Task StartGame(GameMode gameMode)
{
    Debug.Log("Starting game...");

    _runner = Instantiate(runnerPrefab);

    var sceneInfo = new NetworkSceneInfo();
    var sceneRef = SceneRef.FromIndex(0);
    if (sceneRef.IsValid)
    {
        sceneInfo.AddSceneRef(sceneRef, LoadSceneMode.Additive);
    }

    var result = await _runner.StartGame(new StartGameArgs()
    {
        GameMode = gameMode,
        RealtimeClient = _client, // passing the custom Realtime Client
        Scene = sceneInfo
    });

    if (result.Ok)
    {
        Debug.Log($"Runner has started: {_runner.SessionInfo.Name}");
    }
}

This method just illustrates how to start a new NetworkRunner and pass the custom RealtimeClient instance via the StartGameArgs.RealtimeClient. By default, this variable is set to null, meaning that Fusion will handle its creation and management, but if an instance is passed, that one will be used internally.

One important detail to note is that, while the RealtimeClient is being used "outside" Fusion, it requires the RealtimeClient.Service() to be invoked regularly for all communication to be processed (observe the Update() method above). That is just how the Realtime SDK works, because up to this point, there is no interference of Fusion in its usage.
When that instance is passed via the StartGameArgs, the regular update requirement will be taken care of automatically by the Fusion SDK, as usual, and there is no need to call it again.

There is a dedicated page for the Realtime Async API.

Back to top