#if UNITY_2022_3_OR_NEWER && (RELAY_SDK_INSTALLED && !UNITY_WEBGL ) || (RELAY_SDK_INSTALLED && UNITY_WEBGL && UTP_TRANSPORT_2_0_ABOVE)
using System;
using System.Threading.Tasks;
using Unity.Netcode.Transports.UTP;
using Unity.Networking.Transport.Relay;
using Unity.Services.Authentication;
using Unity.Services.Core;
using Unity.Services.Relay;
using Unity.Services.Relay.Models;
namespace Unity.Netcode.Editor
{
///
/// Integration with Unity Relay SDK and Unity Transport that support the additional buttons in the NetworkManager inspector.
/// This code could theoretically be used at runtime, but we would like to avoid the additional dependencies in the runtime assembly of netcode for gameobjects.
///
public static class NetworkManagerRelayIntegration
{
#if UNITY_WEBGL
private const string k_DefaultConnectionType = "wss";
#else
private const string k_DefaultConnectionType = "dtls";
#endif
///
/// Easy relay integration (host): it will initialize the unity services, sign in anonymously and start the host with a new relay allocation.
/// Note that this will force the use of Unity Transport.
///
/// The network manager that will start the connection
/// Maximum number of connections to the created relay.
/// The connection type of the (wss, ws, dtls or udp)
/// The join code that a potential client can use and the allocation
/// Exception when there's an error during services initialization
/// Exception when the project is not linked to a cloud project id
/// Exception when two registered depend on the other
/// The task fails with the exception when the task cannot complete successfully due to Authentication specific errors.
/// See
/// Thrown when the maxConnections argument fails validation in Relay Service SDK.
/// Thrown when the request successfully reach the Relay Allocation Service but results in an error.
internal static async Task<(string, Allocation)> StartHostWithRelay(this NetworkManager networkManager, int maxConnections = 5)
{
var codeAndAllocation = await InitializeAndCreateAllocAsync(networkManager, maxConnections, k_DefaultConnectionType);
return networkManager.StartHost() ? codeAndAllocation : (null, null);
}
///
/// Easy relay integration (server): it will initialize the unity services, sign in anonymously and start the server with a new relay allocation.
/// Note that this will force the use of Unity Transport.
///
/// The network manager that will start the connection
/// Maximum number of connections to the created relay.
/// The join code that a potential client can use and the allocation.
/// Exception when there's an error during services initialization
/// Exception when the project is not linked to a cloud project id
/// Exception when two registered depend on the other
/// The task fails with the exception when the task cannot complete successfully due to Authentication specific errors.
/// See
/// Thrown when the maxConnections argument fails validation in Relay Service SDK.
/// Thrown when the request successfully reach the Relay Allocation Service but results in an error.
internal static async Task<(string, Allocation)> StartServerWithRelay(this NetworkManager networkManager, int maxConnections = 5)
{
var codeAndAllocation = await InitializeAndCreateAllocAsync(networkManager, maxConnections, k_DefaultConnectionType);
return networkManager.StartServer() ? codeAndAllocation : (null, null);
}
///
/// Easy relay integration (client): it will initialize the unity services, sign in anonymously, join the relay with the given join code and start the client.
/// Note that this will force the use of Unity Transport.
///
/// The network manager that will start the connection
/// The join code of the allocation
/// Exception when there's an error during services initialization
/// Exception when the project is not linked to a cloud project id
/// Exception when two registered depend on the other
/// The task fails with the exception when the task cannot complete successfully due to Authentication specific errors.
/// Thrown when the request does not reach the Relay Allocation Service.
/// Thrown if the joinCode has the wrong format.
/// Thrown when the request successfully reach the Relay Allocation Service but results in an error.
/// True if starting the client was successful
internal static async Task StartClientWithRelay(this NetworkManager networkManager, string joinCode)
{
await UnityServices.InitializeAsync();
if (!AuthenticationService.Instance.IsSignedIn)
{
await AuthenticationService.Instance.SignInAnonymouslyAsync();
}
var joinAllocation = await RelayService.Instance.JoinAllocationAsync(joinCode: joinCode);
GetUnityTransport(networkManager, k_DefaultConnectionType).SetRelayServerData(new RelayServerData(joinAllocation, k_DefaultConnectionType));
return networkManager.StartClient() ? joinAllocation : null;
}
private static async Task<(string, Allocation)> InitializeAndCreateAllocAsync(NetworkManager networkManager, int maxConnections, string connectionType)
{
await UnityServices.InitializeAsync();
if (!AuthenticationService.Instance.IsSignedIn)
{
await AuthenticationService.Instance.SignInAnonymouslyAsync();
}
Allocation allocation = await RelayService.Instance.CreateAllocationAsync(maxConnections);
GetUnityTransport(networkManager, connectionType).SetRelayServerData(new RelayServerData(allocation, connectionType));
var joinCode = await RelayService.Instance.GetJoinCodeAsync(allocation.AllocationId);
return (joinCode, allocation);
}
private static UnityTransport GetUnityTransport(NetworkManager networkManager, string connectionType)
{
if (!networkManager.TryGetComponent(out var transport))
{
transport = networkManager.gameObject.AddComponent();
}
#if UTP_TRANSPORT_2_0_ABOVE
transport.UseWebSockets = connectionType.StartsWith("ws"); // Probably should be part of SetRelayServerData, but not possible at this point
#endif
networkManager.NetworkConfig.NetworkTransport = transport; // Force using UnityTransport
return transport;
}
}
}
#endif