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. The NGO framework works well with many low-level transports, including the Unity Transport Package (UTP).

Note: Binding, and other interactions done through a Relay server, are handled using a networking solution such as UTP or NGO. Although the recommended best practice is to use Relay with NGO, you can also use other netcode libraries, such as the Mirror Networking API. Visit Relay and UTP to learn how to use Relay with UTP and another netcode library.

Configure the Relay SDK

You must configure your Unity project for Unity before using Relay with NGO. Check out Get started with Relay. After you’ve enabled the Relay service and linked your Unity Project ID through the Unity Editor, you can import the requirements, set up the NetworkManager, authenticate the player with Unity services, and start working with the Relay SDK.

After setting up the Relay SDK, configure the game client to perform the tasks required to join a Relay game session as a host player and as a connecting player.

Note: The samples in the document use NGO 1.1.0.

Import the requirements

Before using the Relay service, you must import the Relay SDK and UTP along with other namespaces. Use the code snippet you generated from the Packages and SDK Download Center.

  1. Sign in to the Unity Dashboard.

  2. Navigate to the Packages and SDK Download Center.

  3. Select the following packages:

    • Relay

    • Netcode for GameObjects

  4. Select Generate Code Snippet, then follow the instructions.

The following code sample demonstrates an example of requirement imports.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
using Unity.Services.Core;
using Unity.Services.Authentication;
using Unity.Services.Relay;
using Unity.Services.Relay.Http;
using Unity.Services.Relay.Models;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using Unity.Networking.Transport;
using Unity.Networking.Transport.Relay;
using NetworkEvent = Unity.Networking.Transport.NetworkEvent;

Set up the NetworkManager

After installing the packages from the Unity Dashboard, set up the NetworkManager for Relay and NGO in your project from the Unity Editor.

Note: If you notice any missing options, ensure you’ve installed all the packages listed in Install packages from the Unity Dashboard.

  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.

Set variables and utility functions

You’ll also need to initialize some variables, such as the maximum number of connections and the join code.

const int m_MaxConnections = 4;

		public string RelayJoinCode;

Authenticate a player

You must authenticate both the host player and the connecting players. The simplest way to authenticate players is with the Authentication service's SignInAnonymouslyAsync() method. See How to use Anonymous sign-in and How to use platform-specific sign-in.

For more information, see About Unity Authentication and Unity Authentication use cases.

async void Example_AuthenticatingAPlayer()
{
    try
    {
        await UnityServices.InitializeAsync();
        await AuthenticationService.Instance.SignInAnonymouslyAsync();
        var playerID = AuthenticationService.Instance.PlayerId;
    }
    catch (Exception e)
    {
        Debug.Log(e);
    }
}

Host player

When your game client functions as a host player, it must be able to create an allocation, request a join code, configure the connection type, and create a Singleton instance of the NetworkDriver to bind the Relay server and listen for connection requests from joining players.

Warning: You won't be able to connect to the Relay server if there's a mismatch between the information provided through SetRelayServerData / SetRelayClientData and the information obtained from the allocation. For example, you'll receive a "Failed to connect to server" error message if the isSecure parameter doesn't match.

One of the easiest ways to prevent this from happening is to build the RelayServerData directly from the allocation. However, you must use Netcode for GameObjects (NGO) version 1.1.0 or later.

Create an allocation and request a join code

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

public static async Task<RelayServerData> AllocateRelayServerAndGetJoinCode(int maxConnections, string region = null)
{
    Allocation allocation;
    string createJoinCode;
    try
    {
        allocation = await RelayService.Instance.CreateAllocationAsync(maxConnections, region);
    }
    catch (Exception e)
    {
        Debug.LogError($"Relay create allocation request failed {e.Message}");
        throw;
    }

    Debug.Log($"server: {allocation.ConnectionData[0]} {allocation.ConnectionData[1]}");
    Debug.Log($"server: {allocation.AllocationId}");

    try
    {
        createJoinCode = await RelayService.Instance.GetJoinCodeAsync(allocation.AllocationId);
    }
    catch
    {
        Debug.LogError("Relay create join code request failed");
        throw;
    }

    return new RelayServerData(allocation, "dtls");
}

Configure The transport and start NGO

The following code snippet has a function, ConfigureTransportAndStartNgoAsHost, that shows how to use the Relay SDK and NGO SDK to configure the transport and start NGO as a host player.

Note: When starting a Relay server as a host player, both instances of connection data are identical to one another.

IEnumerator Example_ConfigureTransportAndStartNgoAsHost()
{
    var serverRelayUtilityTask = AllocateRelayServerAndGetJoinCode(m_MaxConnections);
    while (!serverRelayUtilityTask.IsCompleted)
    {
        yield return null;
    }
    if (serverRelayUtilityTask.IsFaulted)
    {
        Debug.LogError("Exception thrown when attempting to start Relay Server. Server not started. Exception: " + serverRelayUtilityTask.Exception.Message);
        yield break;
    }

    var relayServerData = serverRelayUtilityTask.Result;

    // Display the joinCode to the user.

    NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(relayServerData);
    NetworkManager.Singleton.StartHost();
    yield return null;
}

Joining player

When your game client functions as a joining player, it must be able to join an allocation, configure the connection type, and create a singleton instance of the NetworkDriver to bind to the Relay server and send a connection request to the host player.

Warning: You won't be able to connect to the Relay server if there's a mismatch between the information provided through SetRelayServerData / SetRelayClientData and the information obtained from the allocation. For example, you'll receive a "Failed to connect to server" error message if the isSecure parameter doesn't match.

One of the easiest ways to prevent this from happening is to build the RelayServerData directly from the allocation. However, you must use Netcode for GameObjects (NGO) version 1.1.0 or later.

Join An allocation

The following code snippet has a function, JoinRelayServerFromJoinCode, that shows how to use the Relay SDK to join an allocation with a join code and configure the connection type as DTLS.

public static async Task<RelayServerData> JoinRelayServerFromJoinCode(string joinCode)
{
    JoinAllocation allocation;
    try
    {
        allocation = await RelayService.Instance.JoinAllocationAsync(joinCode);
    }
    catch
    {
        Debug.LogError("Relay create join code request failed");
        throw;
    }

    Debug.Log($"client: {allocation.ConnectionData[0]} {allocation.ConnectionData[1]}");
    Debug.Log($"host: {allocation.HostConnectionData[0]} {allocation.HostConnectionData[1]}");
    Debug.Log($"client: {allocation.AllocationId}");

    return new RelayServerData(allocation, "dtls");
}

Configure the transport and start NGO as a joining player

The following sample code demonstrates how to configure the transport and start Netcode for GameObjects (NGO) as a joining player.

Note: When starting a Relay server as a joining player, the host and the joining player each have distinct connection data.

IEnumerator Example_ConfigureTransportAndStartNgoAsConnectingPlayer()
{
    // Populate RelayJoinCode beforehand through the UI
    var clientRelayUtilityTask = JoinRelayServerFromJoinCode(RelayJoinCode);

    while (!clientRelayUtilityTask.IsCompleted)
    {
        yield return null;
    }

    if (clientRelayUtilityTask.IsFaulted)
    {
        Debug.LogError("Exception thrown when attempting to connect to Relay Server. Exception: " + clientRelayUtilityTask.Exception.Message);
        yield break;
    }

    var relayServerData = clientRelayUtilityTask.Result;

    NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(relayServerData);

    NetworkManager.Singleton.StartClient();
    yield return null;
}