Use Relay with Netcode for GameObjects (NGO)

Relay works seamlessly with Netcode for GameObjects (NGO), which is a Unity package that provides networking capabilities to GameObject and MonoBehavior workflows.

This tutorial shows how to use Relay with NGO and the Unity Transport Package (UTP).

Installation and configuration

Use the Unity package manager to install the following packages:

You must first configure your Unity project for Unity before using Relay with NGO. Refer to Get started with Relay to learn how to link your project in the project settings.

Note: The samples in this document use NGO 1.6.0. and Unity Transport 1.3.4 on Unity 2022.3

Set up the NetworkManager

After installing the packages, you can now set up the NetworkManager:

  1. Add a new GameObject to your scene.
  2. Add the NetworkManager MonoBehavior.
  3. In the MonoBehavior Properties, select the UnityTransport transport. After selecting UnityTransport, you’ll see a MonoBehavior called Unity Transport (script) at the bottom of the components list.
  4. Set the Protocol Type of the new component to Relay Unity Transport.

Host player

The following function, StartHostWithRelay, shows how to use the Relay SDK to create an allocation, request a join code, and configure the connection type as DTLS.

/// <summary>
/// Starts a game host with a relay allocation: it initializes the Unity services, signs in anonymously and starts the host with a new relay allocation.
/// </summary>
/// <param name="maxConnections">Maximum number of connections to the created relay.</param>
/// <returns>The join code that a client can use.</returns>
/// <exception cref="ServicesInitializationException"> Exception when there's an error during services initialization </exception>
/// <exception cref="UnityProjectNotLinkedException"> Exception when the project is not linked to a cloud project id </exception>
/// <exception cref="CircularDependencyException"> Exception when two registered <see cref="IInitializablePackage"/> depend on the other </exception>
/// <exception cref="AuthenticationException"> The task fails with the exception when the task cannot complete successfully due to Authentication specific errors. </exception>
/// <exception cref="RequestFailedException"> See <see cref="IAuthenticationService.SignInAnonymouslyAsync"/></exception>
/// <exception cref="ArgumentException">Thrown when the maxConnections argument fails validation in Relay Service SDK.</exception>
/// <exception cref="RelayServiceException">Thrown when the request successfully reach the Relay Allocation service but results in an error.</exception>
/// <exception cref="ArgumentNullException">Thrown when the UnityTransport component cannot be found.</exception>
public async Task<string> StartHostWithRelay(int maxConnections=5)
{
    await UnityServices.InitializeAsync();
    if (!AuthenticationService.Instance.IsSignedIn)
    {
        await AuthenticationService.Instance.SignInAnonymouslyAsync();
    }
    Allocation allocation = await RelayService.Instance.CreateAllocationAsync(maxConnections);
    NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(new RelayServerData(allocation, "dtls"));
    var joinCode = await RelayService.Instance.GetJoinCodeAsync(allocation.AllocationId);
    return NetworkManager.Singleton.StartHost() ? joinCode : null;
}

This code should be adapted to your needs to use a different authentication mechanism, a different error handling, or to use a different connection type. Similarly, you can call StartServer instead of StartHost to start a server instead of a host.

Joining player

When your game client functions as a joining player, the relay join code must be passed to find the allocation. The following code sample shows how to use the Relay SDK to join an allocation with a join code and configure the connection type as DTLS.

/// <summary>
/// Joins a game with relay: it will initialize the Unity services, sign in anonymously, join the relay with the given join code and start the client.
/// </summary>
/// <param name="joinCode">The join code of the allocation</param>
/// <returns>True if starting the client was successful</returns>
/// <exception cref="ServicesInitializationException"> Exception when there's an error during services initialization </exception>
/// <exception cref="UnityProjectNotLinkedException"> Exception when the project is not linked to a cloud project id </exception>
/// <exception cref="CircularDependencyException"> Exception when two registered <see cref="IInitializablePackage"/> depend on the other </exception>
/// <exception cref="AuthenticationException"> The task fails with the exception when the task cannot complete successfully due to Authentication specific errors. </exception>
/// <exception cref="RequestFailedException">Thrown when the request does not reach the Relay Allocation service.</exception>
/// <exception cref="ArgumentException">Thrown if the joinCode has the wrong format.</exception>
/// <exception cref="RelayServiceException">Thrown when the request successfully reach the Relay Allocation service but results in an error.</exception>
/// <exception cref="ArgumentNullException">Thrown when the UnityTransport component cannot be found.</exception>
public async Task<bool> StartClientWithRelay(string joinCode)
{
    await UnityServices.InitializeAsync();
    if (!AuthenticationService.Instance.IsSignedIn)
    {
        await AuthenticationService.Instance.SignInAnonymouslyAsync();
    }

    var joinAllocation = await RelayService.Instance.JoinAllocationAsync(joinCode: joinCode);
    NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(new RelayServerData(joinAllocation, "dtls"));
    return !string.IsNullOrEmpty(joinCode) && NetworkManager.Singleton.StartClient();
}

Note about WebGL support

To use Relay with NGO in WebGL, you must upgrade the Unity Transport Package to 2.0.0 or later and configure the Unity transport component to use Web Sockets.

var unityTransport = NetworkManager.Singleton.GetComponent<UnityTransport>();
unityTransport.SetRelayServerData(new RelayServerData(allocation, "wss"));
unityTransport.UseWebSockets = true;