using System; using System.Threading.Tasks; using Unity.Services.Relay; using Unity.Services.Relay.Allocations; using Unity.Services.Relay.Models; using UnityEngine; namespace LobbyRelaySample.Relay { /// /// Wrapper for all the interaction with the Relay API. /// public static class RelayAPIInterface { /// /// API calls are asynchronous, but for debugging and other reasons we want to reify them as objects so that they can be monitored. /// private class InProgressRequest { public InProgressRequest(Task task, Action onComplete) { DoRequest(task, onComplete); } private async void DoRequest(Task task, Action onComplete) { T result = default; string currentTrace = System.Environment.StackTrace; // If we don't get the calling context here, it's lost once the async operation begins. try { result = await task; } catch (Exception e) { Exception eFull = new Exception($"Call stack before async call:\n{currentTrace}\n", e); throw eFull; } finally { onComplete?.Invoke(result); } } } /// /// A Relay Allocation represents a "server" for a new host. /// public static void AllocateAsync(int maxConnections, Action onComplete) { CreateAllocationRequest createAllocationRequest = new CreateAllocationRequest(new AllocationRequest(maxConnections)); var task = RelayService.AllocationsApiClient.CreateAllocationAsync(createAllocationRequest); new InProgressRequest>(task, OnResponse); void OnResponse(Response response) { if (response == null) Debug.LogError("Relay returned a null Allocation. It's possible the Relay service is currently down."); else if (response.Status >= 200 && response.Status < 300) onComplete?.Invoke(response.Result.Data.Allocation); else Debug.LogError($"Allocation returned a non Success code: {response.Status}"); }; } /// /// Only after an Allocation has been completed can a Relay join code be obtained. This code will be stored in the lobby's data as non-public /// such that players can retrieve the Relay join code only after connecting to the lobby. /// public static void GetJoinCodeAsync(Guid hostAllocationId, Action onComplete) { GetJoinCodeAsync(hostAllocationId, a => { if (a.Status >= 200 && a.Status < 300) onComplete.Invoke(a.Result.Data.JoinCode); else { Debug.LogError($"Relay GetJoinCodeAsync returned a non-success code: {a.Status}"); } }); } private static void GetJoinCodeAsync(Guid hostAllocationId, Action> onComplete) { CreateJoincodeRequest joinCodeRequest = new CreateJoincodeRequest(new JoinCodeRequest(hostAllocationId)); var task = RelayService.AllocationsApiClient.CreateJoincodeAsync(joinCodeRequest); new InProgressRequest>(task, onComplete); } /// /// Clients call this to retrieve the host's Allocation via a Relay join code. /// public static void JoinAsync(string joinCode, Action onComplete) { JoinAsync(joinCode, a => { if (a.Status >= 200 && a.Status < 300) onComplete.Invoke(a.Result.Data.Allocation); else { Debug.LogError($"Join Call returned a non Success code: {a.Status}"); } }); } public static void JoinAsync(string joinCode, Action> onComplete) { JoinRelayRequest joinRequest = new JoinRelayRequest(new JoinRequest(joinCode)); var task = RelayService.AllocationsApiClient.JoinRelayAsync(joinRequest); new InProgressRequest>(task, onComplete); } } }