diff --git a/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs b/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs index 37358f16a1..56c0f8c3e1 100644 --- a/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs +++ b/com.unity.multiplayer.transport.utp/Runtime/UTPTransport.cs @@ -4,12 +4,6 @@ using System.Threading.Tasks; using Unity.Networking.Transport; using Unity.Networking.Transport.Relay; -#if ENABLE_RELAY_SERVICE -using Unity.Services.Relay; -using Unity.Services.Relay.Allocations; -using Unity.Services.Relay.Models; -using Unity.Services.Core; -#endif using MLAPI.Transports.Tasks; using UnityEngine; @@ -42,14 +36,11 @@ private enum State [SerializeField] private int m_MessageBufferSize = MaximumMessageLength; [SerializeField] private string m_ServerAddress = "127.0.0.1"; [SerializeField] private ushort m_ServerPort = 7777; - [SerializeField] private int m_RelayMaxPlayers = 10; - [SerializeField] private string m_RelayServer = "https://relay-allocations.cloud.unity3d.com"; private State m_State = State.Disconnected; private NetworkDriver m_Driver; private List m_NetworkParameters; private byte[] m_MessageBuffer; - private string m_RelayJoinCode; private ulong m_ServerClientId; private NetworkPipeline m_UnreliableSequencedPipeline; @@ -58,16 +49,20 @@ private enum State public override ulong ServerClientId => m_ServerClientId; - public string RelayJoinCode => m_RelayJoinCode; - public ProtocolType Protocol => m_ProtocolType; + private RelayServerData m_RelayServerData; + private void InitDriver() { if (m_NetworkParameters.Count > 0) + { m_Driver = NetworkDriver.Create(m_NetworkParameters.ToArray()); + } else + { m_Driver = NetworkDriver.Create(); + } m_UnreliableSequencedPipeline = m_Driver.CreatePipeline(typeof(UnreliableSequencedPipelineStage)); m_ReliableSequencedPipeline = m_Driver.CreatePipeline(typeof(ReliableSequencedPipelineStage)); @@ -79,39 +74,8 @@ private void InitDriver() private void DisposeDriver() { if (m_Driver.IsCreated) - m_Driver.Dispose(); - } - - private static RelayAllocationId ConvertFromAllocationIdBytes(byte[] allocationIdBytes) - { - unsafe { - fixed (byte* ptr = allocationIdBytes) - { - return RelayAllocationId.FromBytePointer(ptr, allocationIdBytes.Length); - } - } - } - - private static RelayHMACKey ConvertFromHMAC(byte[] hmac) - { - unsafe - { - fixed (byte* ptr = hmac) - { - return RelayHMACKey.FromBytePointer(ptr, RelayHMACKey.k_Length); - } - } - } - - private static RelayConnectionData ConvertConnectionData(byte[] connectionData) - { - unsafe - { - fixed (byte* ptr = connectionData) - { - return RelayConnectionData.FromBytePointer(ptr, RelayConnectionData.k_Length); - } + m_Driver.Dispose(); } } @@ -134,7 +98,9 @@ private NetworkPipeline SelectSendPipeline(NetworkChannel channel, int size) case NetworkDelivery.ReliableFragmentedSequenced: // No need to send on the fragmented pipeline if data is smaller than MTU. if (size < NetworkParameterConstants.MTU) + { return m_ReliableSequencedPipeline; + } return m_ReliableSequencedFragmentedPipeline; @@ -150,43 +116,17 @@ private IEnumerator ClientBindAndConnect(SocketTask task) if (m_ProtocolType == ProtocolType.RelayUnityTransport) { -#if !ENABLE_RELAY_SERVICE - Debug.LogError("You must have Relay SDK installed via the UDash in order to use the relay transport"); - yield return null; -#else - var joinTask = RelayService.AllocationsApiClient.JoinRelayAsync(new JoinRelayRequest(new JoinRequest(m_RelayJoinCode))); - - while(!joinTask.IsCompleted) - yield return null; - - if (joinTask.IsFaulted) + //This comparison is currently slow since RelayServerData does not implement a custom comparison operator that doesn't use + //reflection, but this does not live in the context of a performance-critical loop, it runs once at initial connection time. + if(m_RelayServerData.Equals(default(RelayServerData))) { - Debug.LogError("Join Relay request failed"); + Debug.LogError("You must call SetRelayServerData() at least once before calling StartRelayServer."); task.IsDone = true; task.Success = false; yield break; } - var allocation = joinTask.Result.Result.Data.Allocation; - - serverEndpoint = NetworkEndPoint.Parse(allocation.RelayServer.IpV4, (ushort)allocation.RelayServer.Port); - - var allocationId = ConvertFromAllocationIdBytes(allocation.AllocationIdBytes); - - var connectionData = ConvertConnectionData(allocation.ConnectionData); - var hostConnectionData = ConvertConnectionData(allocation.HostConnectionData); - var key = ConvertFromHMAC(allocation.Key); - - Debug.Log($"client: {allocation.ConnectionData[0]} {allocation.ConnectionData[1]}"); - Debug.Log($"host: {allocation.HostConnectionData[0]} {allocation.HostConnectionData[1]}"); - - Debug.Log($"client: {allocation.AllocationId}"); - - var relayServerData = new RelayServerData(ref serverEndpoint, 0, ref allocationId, ref connectionData, ref hostConnectionData, ref key); - relayServerData.ComputeNewNonce(); - - m_NetworkParameters.Add(new RelayNetworkParameter{ ServerData = relayServerData }); -#endif + m_NetworkParameters.Add(new RelayNetworkParameter{ ServerData = m_RelayServerData }); } else { @@ -223,8 +163,6 @@ private IEnumerator ClientBindAndConnect(SocketTask task) { Debug.LogError("Client failed to connect to server"); } - - } task.IsDone = true; @@ -256,69 +194,82 @@ private IEnumerator ServerBindAndListen(SocketTask task, NetworkEndPoint endPoin { Debug.LogError("Server failed to listen"); } - - } task.IsDone = true; } - - private IEnumerator StartRelayServer(SocketTask task) + private static RelayAllocationId ConvertFromAllocationIdBytes(byte[] allocationIdBytes) { -#if !ENABLE_RELAY_SERVICE - Debug.LogError("You must have Relay SDK installed via the UDash in order to use the relay transport"); - yield return null; -#else - var allocationTask = RelayService.AllocationsApiClient.CreateAllocationAsync(new CreateAllocationRequest(new AllocationRequest(m_RelayMaxPlayers))); - - while(!allocationTask.IsCompleted) + unsafe { - yield return null; + fixed (byte* ptr = allocationIdBytes) + { + return RelayAllocationId.FromBytePointer(ptr, allocationIdBytes.Length); + } } + } - if (allocationTask.IsFaulted) + private static RelayHMACKey ConvertFromHMAC(byte[] hmac) + { + unsafe { - Debug.LogError("Create allocation request failed"); - task.IsDone = true; - task.Success = false; - yield break; + fixed (byte* ptr = hmac) + { + return RelayHMACKey.FromBytePointer(ptr, RelayHMACKey.k_Length); + } } + } - var allocation = allocationTask.Result.Result.Data.Allocation; - - var joinCodeTask = RelayService.AllocationsApiClient.CreateJoincodeAsync(new CreateJoincodeRequest(new JoinCodeRequest(allocation.AllocationId))); + private static RelayConnectionData ConvertConnectionData(byte[] connectionData) + { + unsafe + { + fixed (byte* ptr = connectionData) + { + return RelayConnectionData.FromBytePointer(ptr, RelayConnectionData.k_Length); + } + } + } - while(!joinCodeTask.IsCompleted) + public void SetRelayServerData(string ipv4address, ushort port, byte[] allocationIdBytes, byte[] keyBytes, byte[] connectionDataBytes, byte[] hostConnectionDataBytes = null) + { + RelayConnectionData hostConnectionData; + + var serverEndpoint = NetworkEndPoint.Parse(ipv4address, port); + var allocationId = ConvertFromAllocationIdBytes(allocationIdBytes); + var key = ConvertFromHMAC(keyBytes); + var connectionData = ConvertConnectionData(connectionDataBytes); + + if (hostConnectionDataBytes != null) + { + hostConnectionData = ConvertConnectionData(hostConnectionDataBytes); + } + else { - yield return null; + hostConnectionData = connectionData; } + m_RelayServerData = new RelayServerData(ref serverEndpoint, 0, ref allocationId, ref connectionData, ref hostConnectionData, ref key); + m_RelayServerData.ComputeNewNonce(); + } - if (joinCodeTask.IsFaulted) + private IEnumerator StartRelayServer(SocketTask task) + { + //This comparison is currently slow since RelayServerData does not implement a custom comparison operator that doesn't use + //reflection, but this does not live in the context of a performance-critical loop, it runs once at initial connection time. + if (m_RelayServerData.Equals(default(RelayServerData))) { - Debug.LogError("Create join code request failed"); + Debug.LogError("You must call SetRelayServerData() at least once before calling StartRelayServer."); task.IsDone = true; task.Success = false; yield break; } + else + { + m_NetworkParameters.Add(new RelayNetworkParameter { ServerData = m_RelayServerData }); - m_RelayJoinCode = joinCodeTask.Result.Result.Data.JoinCode; - - var serverEndpoint = NetworkEndPoint.Parse(allocation.RelayServer.IpV4, (ushort)allocation.RelayServer.Port); - // Debug.Log($"Relay Server endpoint: {allocation.RelayServer.IpV4}:{(ushort)allocation.RelayServer.Port}"); - - var allocationId = ConvertFromAllocationIdBytes(allocation.AllocationIdBytes); - var connectionData = ConvertConnectionData(allocation.ConnectionData); - var key = ConvertFromHMAC(allocation.Key); - - - var relayServerData = new RelayServerData(ref serverEndpoint, 0, ref allocationId, ref connectionData, ref connectionData, ref key); - relayServerData.ComputeNewNonce(); - - m_NetworkParameters.Add(new RelayNetworkParameter{ ServerData = relayServerData }); - - yield return ServerBindAndListen(task, NetworkEndPoint.AnyIpv4); -#endif + yield return ServerBindAndListen(task, NetworkEndPoint.AnyIpv4); + } } private bool AcceptConnection() @@ -396,8 +347,15 @@ private void Update() if (m_Driver.IsCreated) { m_Driver.ScheduleUpdate().Complete(); - while(AcceptConnection() && m_Driver.IsCreated); - while(ProcessEvent() && m_Driver.IsCreated); + while(AcceptConnection() && m_Driver.IsCreated) + { + ; + } + + while (ProcessEvent() && m_Driver.IsCreated) + { + ; + } } } @@ -417,14 +375,6 @@ private static unsafe NetworkConnection ParseClientId(ulong mlapiConnectionId) return *(NetworkConnection*)&mlapiConnectionId; } - public void SetRelayJoinCode(string value) - { - if (m_State == State.Disconnected) - { - m_RelayJoinCode = value; - } - } - public override void DisconnectLocalClient() { Debug.Assert(m_State == State.Connected, "DisconnectLocalClient should be called on a connected client"); @@ -462,7 +412,6 @@ public override void Init() m_NetworkParameters = new List(); - // If we want to be able to actually handle messages MaximumMessageLength bytes in // size, we need to allow a bit more than that in FragmentationUtility since this needs // to account for headers and such. 128 bytes is plenty enough for such overhead. @@ -470,12 +419,6 @@ public override void Init() m_NetworkParameters.Add(new FragmentationUtility.Parameters(){PayloadCapacity = maxFragmentationCapacity}); m_MessageBuffer = new byte[m_MessageBufferSize]; -#if ENABLE_RELAY_SERVICE - if (m_ProtocolType == ProtocolType.RelayUnityTransport) { - Unity.Services.Relay.RelayService.Configuration.BasePath = m_RelayServer; - UnityServices.Initialize(); - } -#endif } public override NetworkEvent PollEvent(out ulong clientId, out NetworkChannel networkChannel, out ArraySegment payload, out float receiveTime) @@ -510,7 +453,9 @@ public override void Send(ulong clientId, ArraySegment data, NetworkChanne } if (m_Driver.EndSend(writer) == size) + { return; + } } Debug.LogError("Error sending the message"); @@ -519,7 +464,9 @@ public override void Send(ulong clientId, ArraySegment data, NetworkChanne public override SocketTasks StartClient() { if (m_Driver.IsCreated) + { return SocketTask.Fault.AsTasks(); + } var task = SocketTask.Working; StartCoroutine(ClientBindAndConnect(task)); @@ -529,7 +476,9 @@ public override SocketTasks StartClient() public override SocketTasks StartServer() { if (m_Driver.IsCreated) + { return SocketTask.Fault.AsTasks(); + } var task = SocketTask.Working; switch (m_ProtocolType) diff --git a/com.unity.multiplayer.transport.utp/Runtime/com.unity.multiplayer.transport.utp.asmdef b/com.unity.multiplayer.transport.utp/Runtime/com.unity.multiplayer.transport.utp.asmdef index 696ebfb440..622b00484c 100644 --- a/com.unity.multiplayer.transport.utp/Runtime/com.unity.multiplayer.transport.utp.asmdef +++ b/com.unity.multiplayer.transport.utp/Runtime/com.unity.multiplayer.transport.utp.asmdef @@ -6,9 +6,7 @@ "Unity.Jobs", "Unity.Burst", "Unity.Multiplayer.MLAPI.Runtime", - "Unity.Networking.Transport", - "Unity.Services.Relay", - "Unity.Services.Core" + "Unity.Networking.Transport" ], "includePlatforms": [], "excludePlatforms": [], @@ -17,12 +15,6 @@ "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], - "versionDefines": [ - { - "name": "com.unity.services.relay", - "expression": "0.0.1-preview.3", - "define": "ENABLE_RELAY_SERVICE" - } - ], + "versionDefines": [], "noEngineReferences": false } \ No newline at end of file diff --git a/testproject/Assets/Scenes/SampleScene.unity b/testproject/Assets/Scenes/SampleScene.unity index d62a9ab0e6..392afb240b 100644 --- a/testproject/Assets/Scenes/SampleScene.unity +++ b/testproject/Assets/Scenes/SampleScene.unity @@ -219,6 +219,18 @@ MeshFilter: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 19899154} m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!114 &102484700 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 4850072633501053442, guid: d725b5588e1b956458798319e6541d84, + type: 3} + m_PrefabInstance: {fileID: 1928839749} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 50623966c8d88ab40982cc2b0e4c2d2e, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1 &225870858 GameObject: m_ObjectHideFlags: 0 @@ -586,6 +598,7 @@ MonoBehaviour: GlobalObjectIdHash: 3604669530 AlwaysReplicateAsRoot: 0 DontDestroyWithOwner: 0 + AutoObjectParentSync: 1 --- !u!114 &402668304 MonoBehaviour: m_ObjectHideFlags: 0 @@ -815,7 +828,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 903872102732f5c4cbdd3863de5dbc97, type: 3} m_Name: m_EditorClassIdentifier: - Transport: {fileID: 620561613} + ConnectionScript: {fileID: 102484700} --- !u!114 &509741759 MonoBehaviour: m_ObjectHideFlags: 0 @@ -1097,7 +1110,7 @@ MonoBehaviour: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 620561609} - m_Enabled: 1 + m_Enabled: 0 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: b84c2d8dfe509a34fb59e2b81f8e1319, type: 3} m_Name: @@ -1140,7 +1153,7 @@ MonoBehaviour: type: 3} NetworkPrefabs: - Override: 0 - Prefab: {fileID: 442217489085244684, guid: 5eca8a21314fe4278ba2571c289a9773, + Prefab: {fileID: 8133991607019124060, guid: 421bcf732fe69486d8abecfa5eee63bb, type: 3} SourcePrefabToOverride: {fileID: 0} SourceHashToOverride: 0 @@ -1195,8 +1208,6 @@ MonoBehaviour: m_MessageBufferSize: 1024 m_ServerAddress: 127.0.0.1 m_ServerPort: 7777 - m_RelayMaxPlayers: 10 - m_RelayServer: https://relay-allocations-stg.cloud.unity3d.com --- !u!1001 &627808638 PrefabInstance: m_ObjectHideFlags: 0 @@ -2179,6 +2190,7 @@ MonoBehaviour: GlobalObjectIdHash: 3972363333 AlwaysReplicateAsRoot: 0 DontDestroyWithOwner: 0 + AutoObjectParentSync: 1 --- !u!65 &963826007 BoxCollider: m_ObjectHideFlags: 0 @@ -2270,7 +2282,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 05037a80244af4174806bc7f242e4432, type: 3} m_Name: m_EditorClassIdentifier: - UnityChanPrefab: {fileID: 442217489085244684, guid: 5eca8a21314fe4278ba2571c289a9773, + UnityChanPrefab: {fileID: 8133991607019124060, guid: 421bcf732fe69486d8abecfa5eee63bb, type: 3} --- !u!4 &1202924674 Transform: @@ -2672,6 +2684,7 @@ MonoBehaviour: GlobalObjectIdHash: 1445980162 AlwaysReplicateAsRoot: 0 DontDestroyWithOwner: 0 + AutoObjectParentSync: 1 --- !u!54 &1397037320 Rigidbody: m_ObjectHideFlags: 0 @@ -2935,6 +2948,7 @@ MonoBehaviour: GlobalObjectIdHash: 1148320762 AlwaysReplicateAsRoot: 0 DontDestroyWithOwner: 0 + AutoObjectParentSync: 1 --- !u!54 &1402467447 Rigidbody: m_ObjectHideFlags: 0 @@ -3345,6 +3359,7 @@ MonoBehaviour: GlobalObjectIdHash: 2710131580 AlwaysReplicateAsRoot: 0 DontDestroyWithOwner: 0 + AutoObjectParentSync: 1 --- !u!114 &1475593096 MonoBehaviour: m_ObjectHideFlags: 0 @@ -3589,11 +3604,46 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 1333567166} m_Modifications: + - target: {fileID: 2956145122089128464, guid: d725b5588e1b956458798319e6541d84, + type: 3} + propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_MethodName + value: OnStartServerButton + objectReference: {fileID: 0} + - target: {fileID: 2956145122089128464, guid: d725b5588e1b956458798319e6541d84, + type: 3} + propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName + value: ConnectionModeScript, TestProject + objectReference: {fileID: 0} + - target: {fileID: 2956145122546206394, guid: d725b5588e1b956458798319e6541d84, + type: 3} + propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_MethodName + value: OnStartClientButton + objectReference: {fileID: 0} + - target: {fileID: 2956145122546206394, guid: d725b5588e1b956458798319e6541d84, + type: 3} + propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName + value: ConnectionModeScript, TestProject + objectReference: {fileID: 0} + - target: {fileID: 2956145122624039697, guid: d725b5588e1b956458798319e6541d84, + type: 3} + propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_MethodName + value: OnStartHostButton + objectReference: {fileID: 0} + - target: {fileID: 2956145122624039697, guid: d725b5588e1b956458798319e6541d84, + type: 3} + propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName + value: ConnectionModeScript, TestProject + objectReference: {fileID: 0} - target: {fileID: 4850072633501053442, guid: d725b5588e1b956458798319e6541d84, type: 3} propertyPath: m_JoinCodeInput value: objectReference: {fileID: 509741756} + - target: {fileID: 4850072633501053442, guid: d725b5588e1b956458798319e6541d84, + type: 3} + propertyPath: m_RelayAllocationBasePath + value: https://relay-allocations-stg.services.api.unity.com + objectReference: {fileID: 0} - target: {fileID: 6633621479308595792, guid: d725b5588e1b956458798319e6541d84, type: 3} propertyPath: m_Pivot.x @@ -3802,4 +3852,3 @@ MeshFilter: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2036456027} m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} - \ No newline at end of file diff --git a/testproject/Assets/Scripts/CommandLineHandler.cs b/testproject/Assets/Scripts/CommandLineHandler.cs index 6687a82f46..16f71d1678 100644 --- a/testproject/Assets/Scripts/CommandLineHandler.cs +++ b/testproject/Assets/Scripts/CommandLineHandler.cs @@ -163,7 +163,7 @@ private void StartServer() m_CommandLineArguments.Remove("-m"); if (m_ConnectionModeScript) { - m_ConnectionModeScript.OnStartServer(); + m_ConnectionModeScript.OnStartServerButton(); } else { @@ -175,7 +175,7 @@ private void StartHost() { if (m_ConnectionModeScript) { - m_ConnectionModeScript.OnStartHost(); + m_ConnectionModeScript.OnStartHostButton(); } else { @@ -187,7 +187,7 @@ private void StartClient() { if (m_ConnectionModeScript) { - m_ConnectionModeScript.OnStartClient(); + m_ConnectionModeScript.OnStartClientButton(); } else { diff --git a/testproject/Assets/Scripts/ConnectionModeScript.cs b/testproject/Assets/Scripts/ConnectionModeScript.cs index 47f0cfdd30..185f1d9042 100644 --- a/testproject/Assets/Scripts/ConnectionModeScript.cs +++ b/testproject/Assets/Scripts/ConnectionModeScript.cs @@ -3,6 +3,7 @@ using UnityEngine; using MLAPI; using MLAPI.Transports; + #if ENABLE_RELAY_SERVICE using Unity.Services.Core; using Unity.Services.Authentication; @@ -22,7 +23,19 @@ public class ConnectionModeScript : MonoBehaviour [SerializeField] private GameObject m_JoinCodeInput; + [SerializeField] + private int m_MaxConnections = 10; + private CommandLineProcessor m_CommandLineProcessor; + +#if ENABLE_RELAY_SERVICE + [SerializeField] + private string m_RelayAllocationBasePath = "https://relay-allocations-stg.services.api.unity.com"; + + [HideInInspector] + public string RelayJoinCode { get; set; } +#endif + internal void SetCommandLineHandler(CommandLineProcessor commandLineProcessor) { m_CommandLineProcessor = commandLineProcessor; @@ -38,7 +51,6 @@ internal void SetCommandLineHandler(CommandLineProcessor commandLineProcessor) public event OnNotifyConnectionEventDelegateHandler OnNotifyConnectionEventHost; public event OnNotifyConnectionEventDelegateHandler OnNotifyConnectionEventClient; - private IEnumerator WaitForNetworkManager() { while(true) @@ -68,8 +80,10 @@ private void Start() if (NetworkManager.Singleton.GetComponent().Protocol == UTPTransport.ProtocolType.RelayUnityTransport) { m_JoinCodeInput.SetActive(true); - m_ConnectionModeButtons.SetActive(false || AuthenticationService.Instance.IsSignedIn); - m_AuthenticationButtons.SetActive(NetworkManager.Singleton && !NetworkManager.Singleton.IsListening && !AuthenticationService.Instance.IsSignedIn); + //If Start() is called on the first frame update, it's not likely that the AuthenticationService is going to be instantiated yet + //Moved old logic for this out to OnServicesInitialized + m_ConnectionModeButtons.SetActive(false); + m_AuthenticationButtons.SetActive(true); } else #endif @@ -81,54 +95,158 @@ private void Start() } } + private void OnServicesInitialized() + { +#if ENABLE_RELAY_SERVICE + if (NetworkManager.Singleton.GetComponent().Protocol == UTPTransport.ProtocolType.RelayUnityTransport) + { + m_JoinCodeInput.SetActive(true); + m_ConnectionModeButtons.SetActive(false || AuthenticationService.Instance.IsSignedIn); + m_AuthenticationButtons.SetActive(NetworkManager.Singleton && !NetworkManager.Singleton.IsListening && !AuthenticationService.Instance.IsSignedIn); + } +#endif + } + /// /// Handles starting MLAPI in server mode /// - public void OnStartServer() + public void OnStartServerButton() { if (NetworkManager.Singleton && !NetworkManager.Singleton.IsListening && m_ConnectionModeButtons) { - NetworkManager.Singleton.StartServer(); - OnNotifyConnectionEventServer?.Invoke(); - m_ConnectionModeButtons.SetActive(false); +#if ENABLE_RELAY_SERVICE + StartCoroutine(StartRelayServer(StartServer)); +#else + StartServer(); +#endif + } + } + + private void StartServer() + { + NetworkManager.Singleton.StartServer(); + OnNotifyConnectionEventServer?.Invoke(); + m_ConnectionModeButtons.SetActive(false); + } +#if ENABLE_RELAY_SERVICE + /// + /// Coroutine that handles starting MLAPI in server mode if Relay is enabled + /// + private IEnumerator StartRelayServer(Action postAllocationAction) + { + m_ConnectionModeButtons.SetActive(false); + + var serverRelayUtilityTask = RelayUtility.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 (ipv4address, port, allocationIdBytes, connectionData, key, joinCode) = serverRelayUtilityTask.Result; + + RelayJoinCode = joinCode; + + //When starting a relay server, both instances of connection data are identical. + NetworkManager.Singleton.GetComponent().SetRelayServerData(ipv4address, port, allocationIdBytes, key, connectionData); + + postAllocationAction(); } +#endif /// /// Handles starting MLAPI in host mode /// - public void OnStartHost() + public void OnStartHostButton() { if (NetworkManager.Singleton && !NetworkManager.Singleton.IsListening && m_ConnectionModeButtons) { - NetworkManager.Singleton.StartHost(); - OnNotifyConnectionEventHost?.Invoke(); - m_ConnectionModeButtons.SetActive(false); +#if ENABLE_RELAY_SERVICE + StartCoroutine(StartRelayServer(StartHost)); +#else + StartHost(); +#endif } } + private void StartHost() + { + NetworkManager.Singleton.StartHost(); + OnNotifyConnectionEventHost?.Invoke(); + m_ConnectionModeButtons.SetActive(false); + } + /// /// Handles starting MLAPI in client mode /// - public void OnStartClient() + public void OnStartClientButton() { if (NetworkManager.Singleton && !NetworkManager.Singleton.IsListening && m_ConnectionModeButtons) { - NetworkManager.Singleton.StartClient(); - OnNotifyConnectionEventClient?.Invoke(); - m_ConnectionModeButtons.SetActive(false); +#if ENABLE_RELAY_SERVICE + StartCoroutine(StartRelayClient()); +#else + StartClient(); +#endif } } + private void StartClient() + { + NetworkManager.Singleton.StartClient(); + OnNotifyConnectionEventClient?.Invoke(); + m_ConnectionModeButtons.SetActive(false); + } + +#if ENABLE_RELAY_SERVICE + /// + /// Coroutine that kicks off Relay SDK calls to join a Relay Server instance with a join code + /// + /// + private IEnumerator StartRelayClient() + { + m_ConnectionModeButtons.SetActive(false); + + //assumes that RelayJoinCodeInput populated RelayJoinCode prior to this + var clientRelayUtilityTask = RelayUtility.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 (ipv4address, port, allocationIdBytes, connectionData, hostConnectionData, key) = clientRelayUtilityTask.Result; + + //When connecting as a client to a relay server, connectionData and hostConnectionData are different. + NetworkManager.Singleton.GetComponent().SetRelayServerData(ipv4address, port, allocationIdBytes, key, connectionData, hostConnectionData); + + NetworkManager.Singleton.StartClient(); + OnNotifyConnectionEventClient?.Invoke(); + } +#endif /// - /// Handles autenticating UnityServices, needed for Relay + /// Handles authenticating UnityServices, needed for Relay /// public async void OnSignIn() { #if ENABLE_RELAY_SERVICE - await UnityServices.Initialize(); + Unity.Services.Relay.RelayService.Configuration.BasePath = m_RelayAllocationBasePath; + + await UnityServices.InitializeAsync(); + OnServicesInitialized(); await AuthenticationService.Instance.SignInAnonymouslyAsync(); + Debug.Log($"Logging in with PlayerID {AuthenticationService.Instance.PlayerId}"); if (AuthenticationService.Instance.IsSignedIn) diff --git a/testproject/Assets/Scripts/RelayJoinCodeInput.cs b/testproject/Assets/Scripts/RelayJoinCodeInput.cs index 34b3a31e85..ea4aa8815d 100644 --- a/testproject/Assets/Scripts/RelayJoinCodeInput.cs +++ b/testproject/Assets/Scripts/RelayJoinCodeInput.cs @@ -4,7 +4,7 @@ public class RelayJoinCodeInput : MonoBehaviour { - public UTPTransport Transport; + public ConnectionModeScript ConnectionScript; private InputField m_TextInput; private void Start() @@ -15,8 +15,8 @@ private void Start() private void Update() { if (m_TextInput.IsInteractable()) { - if (!string.IsNullOrEmpty(Transport.RelayJoinCode)) { - m_TextInput.text = Transport.RelayJoinCode; + if (!string.IsNullOrEmpty(ConnectionScript.RelayJoinCode)) { + m_TextInput.text = ConnectionScript.RelayJoinCode; m_TextInput.readOnly = true; } } @@ -24,6 +24,6 @@ private void Update() public void SetJoinCode() { - Transport.SetRelayJoinCode(m_TextInput.text); + ConnectionScript.RelayJoinCode = m_TextInput.text; } } diff --git a/testproject/Assets/Scripts/RelayUtility.cs b/testproject/Assets/Scripts/RelayUtility.cs new file mode 100644 index 0000000000..9bf63bce77 --- /dev/null +++ b/testproject/Assets/Scripts/RelayUtility.cs @@ -0,0 +1,62 @@ +using System.Threading.Tasks; +using UnityEngine; +using Unity.Services.Relay; +using Unity.Services.Relay.Allocations; +using Unity.Services.Relay.Models; + +public class RelayUtility +{ + async public static Task<(string ipv4address, ushort port, byte[] allocationIdBytes, byte[] connectionData, byte[] key, string joinCode)> AllocateRelayServerAndGetJoinCode(int maxConnections, string region = null) + { + Response allocationResponse; + Response createJoinCodeResponse; + try + { + allocationResponse = await RelayService.AllocationsApiClient.CreateAllocationAsync(new CreateAllocationRequest(new AllocationRequest(maxConnections, region))); + } + catch + { + Debug.LogError("Relay create allocation request failed"); + throw; + } + + var allocation = allocationResponse.Result.Data.Allocation; + + Debug.Log($"server: {allocation.ConnectionData[0]} {allocation.ConnectionData[1]}"); + Debug.Log($"server: {allocation.AllocationId}"); + + try + { + createJoinCodeResponse = await RelayService.AllocationsApiClient.CreateJoincodeAsync(new CreateJoincodeRequest(new JoinCodeRequest(allocationResponse.Result.Data.Allocation.AllocationId))); + } + catch + { + Debug.LogError("Relay create join code request failed"); + throw; + } + + return (allocation.RelayServer.IpV4, (ushort)allocation.RelayServer.Port, allocation.AllocationIdBytes, allocation.ConnectionData, allocation.Key, createJoinCodeResponse.Result.Data.JoinCode); + } + + async public static Task<(string ipv4address, ushort port, byte[] allocationIdBytes, byte[] connectionData, byte[] hostConnectionData, byte[] key)> JoinRelayServerFromJoinCode(string joinCode) + { + Response joinResponse; + try + { + joinResponse = await RelayService.AllocationsApiClient.JoinRelayAsync(new JoinRelayRequest(new JoinRequest(joinCode))); + } + catch + { + Debug.LogError("Relay create join code request failed"); + throw; + } + + var allocation = joinResponse.Result.Data.Allocation; + + Debug.Log($"client: {allocation.ConnectionData[0]} {allocation.ConnectionData[1]}"); + Debug.Log($"host: {allocation.HostConnectionData[0]} {allocation.HostConnectionData[1]}"); + Debug.Log($"client: {allocation.AllocationId}"); + + return (allocation.RelayServer.IpV4, (ushort)allocation.RelayServer.Port, allocation.AllocationIdBytes, allocation.ConnectionData, allocation.HostConnectionData, allocation.Key); + } +} diff --git a/testproject/Assets/Scripts/RelayUtility.cs.meta b/testproject/Assets/Scripts/RelayUtility.cs.meta new file mode 100644 index 0000000000..b7879fb3a2 --- /dev/null +++ b/testproject/Assets/Scripts/RelayUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 821a03e0e4496574c8ca6a558047e944 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject/Assets/Scripts/UIController.cs b/testproject/Assets/Scripts/UIController.cs index 3a5969d3e1..29752e65b8 100644 --- a/testproject/Assets/Scripts/UIController.cs +++ b/testproject/Assets/Scripts/UIController.cs @@ -52,7 +52,7 @@ private void HideButtons() public async void OnSignIn() { #if ENABLE_RELAY_SERVICE - await UnityServices.Initialize(); + await UnityServices.InitializeAsync(); Debug.Log("OnSignIn"); await AuthenticationService.Instance.SignInAnonymouslyAsync(); Debug.Log($"Logging in with PlayerID {AuthenticationService.Instance.PlayerId}"); diff --git a/testproject/Assets/Scripts/testproject.asmdef b/testproject/Assets/Scripts/testproject.asmdef index d4191ebbdd..20d772ff3d 100644 --- a/testproject/Assets/Scripts/testproject.asmdef +++ b/testproject/Assets/Scripts/testproject.asmdef @@ -7,7 +7,8 @@ "Unity.Multiplayer.MLAPI.Prototyping", "Unity.Multiplayer.Transport.UTP", "Unity.Services.Authentication", - "Unity.Services.Core" + "Unity.Services.Core", + "Unity.Services.Relay" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/testproject/Packages/manifest.json b/testproject/Packages/manifest.json index b188cc61ff..0b493d2cbf 100644 --- a/testproject/Packages/manifest.json +++ b/testproject/Packages/manifest.json @@ -1,19 +1,21 @@ { "dependencies": { - "com.unity.collab-proxy": "1.5.7", - "com.unity.ide.rider": "3.0.5", - "com.unity.ide.visualstudio": "2.0.9", + "com.unity.collab-proxy": "1.7.1", + "com.unity.ide.rider": "3.0.7", + "com.unity.ide.visualstudio": "2.0.11", "com.unity.ide.vscode": "1.2.3", + "com.unity.mathematics": "1.2.1", "com.unity.multiplayer.mlapi": "file:../../com.unity.multiplayer.mlapi", "com.unity.multiplayer.transport.utp": "file:../../com.unity.multiplayer.transport.utp", - "com.unity.package-validation-suite": "0.19.2-preview", - "com.unity.services.authentication": "0.5.0-preview", - "com.unity.services.core": "1.1.0-pre.2", - "com.unity.services.relay": "0.0.1-preview.5", + "com.unity.package-validation-suite": "0.21.0-preview", + "com.unity.services.authentication": "1.0.0-pre.4", + "com.unity.services.core": "1.1.0-pre.8", + "com.unity.services.relay": "1.0.0-preview.1", "com.unity.test-framework": "1.1.27", - "com.unity.test-framework.performance": "2.3.1-preview", + "com.unity.test-framework.performance": "2.8.0-preview", "com.unity.textmeshpro": "3.0.6", - "com.unity.timeline": "1.5.2", + "com.unity.timeline": "1.5.6", + "com.unity.transport": "1.0.0-pre.1", "com.unity.ugui": "1.0.0", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", diff --git a/testproject/Packages/packages-lock.json b/testproject/Packages/packages-lock.json index b5cc63a745..f2acdb609d 100644 --- a/testproject/Packages/packages-lock.json +++ b/testproject/Packages/packages-lock.json @@ -2,7 +2,7 @@ "dependencies": { "com.unity.burst": { "version": "1.5.3", - "depth": 3, + "depth": 2, "source": "registry", "dependencies": { "com.unity.mathematics": "1.2.1" @@ -10,7 +10,7 @@ "url": "https://packages.unity.com" }, "com.unity.collab-proxy": { - "version": "1.5.7", + "version": "1.7.1", "depth": 0, "source": "registry", "dependencies": { @@ -20,7 +20,7 @@ }, "com.unity.collections": { "version": "1.0.0-pre.3", - "depth": 2, + "depth": 1, "source": "registry", "dependencies": { "com.unity.burst": "1.5.3", @@ -36,14 +36,16 @@ "url": "https://packages.unity.com" }, "com.unity.ide.rider": { - "version": "3.0.5", + "version": "3.0.7", "depth": 0, "source": "registry", - "dependencies": {}, + "dependencies": { + "com.unity.ext.nunit": "1.0.6" + }, "url": "https://packages.unity.com" }, "com.unity.ide.visualstudio": { - "version": "2.0.9", + "version": "2.0.11", "depth": 0, "source": "registry", "dependencies": { @@ -70,7 +72,7 @@ }, "com.unity.mathematics": { "version": "1.2.1", - "depth": 2, + "depth": 0, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" @@ -110,7 +112,7 @@ "url": "https://packages.unity.com" }, "com.unity.package-validation-suite": { - "version": "0.19.2-preview", + "version": "0.21.0-preview", "depth": 0, "source": "registry", "dependencies": { @@ -119,32 +121,31 @@ "url": "https://packages.unity.com" }, "com.unity.services.authentication": { - "version": "0.5.0-preview", + "version": "1.0.0-pre.4", "depth": 0, "source": "registry", "dependencies": { "com.unity.nuget.newtonsoft-json": "2.0.0", - "com.unity.services.core": "1.1.0-pre.2", + "com.unity.services.core": "1.1.0-pre.8", "com.unity.modules.unitywebrequest": "1.0.0" }, "url": "https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-candidates" }, "com.unity.services.core": { - "version": "1.1.0-pre.2", + "version": "1.1.0-pre.8", "depth": 0, "source": "registry", "dependencies": { - "com.unity.modules.unitywebrequest": "1.0.0", - "com.unity.nuget.newtonsoft-json": "2.0.0" + "com.unity.modules.unitywebrequest": "1.0.0" }, "url": "https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-candidates" }, "com.unity.services.relay": { - "version": "0.0.1-preview.5", + "version": "1.0.0-preview.1", "depth": 0, "source": "registry", "dependencies": { - "com.unity.services.core": "1.1.0-pre.2", + "com.unity.services.core": "1.1.0-pre.4", "com.unity.modules.unitywebrequest": "1.0.0", "com.unity.modules.unitywebrequestassetbundle": "1.0.0", "com.unity.modules.unitywebrequestaudio": "1.0.0", @@ -166,12 +167,12 @@ "url": "https://packages.unity.com" }, "com.unity.test-framework.performance": { - "version": "2.3.1-preview", + "version": "2.8.0-preview", "depth": 0, "source": "registry", "dependencies": { "com.unity.test-framework": "1.1.0", - "com.unity.nuget.newtonsoft-json": "2.0.0-preview" + "com.unity.modules.jsonserialize": "1.0.0" }, "url": "https://packages.unity.com" }, @@ -185,7 +186,7 @@ "url": "https://packages.unity.com" }, "com.unity.timeline": { - "version": "1.5.2", + "version": "1.5.6", "depth": 0, "source": "registry", "dependencies": { @@ -197,8 +198,8 @@ "url": "https://packages.unity.com" }, "com.unity.transport": { - "version": "0.9.0-preview.3", - "depth": 1, + "version": "1.0.0-pre.1", + "depth": 0, "source": "registry", "dependencies": { "com.unity.collections": "1.0.0-pre.3", diff --git a/testproject/ProjectSettings/ProjectSettings.asset b/testproject/ProjectSettings/ProjectSettings.asset index 96699ff538..8dd731d6ee 100644 --- a/testproject/ProjectSettings/ProjectSettings.asset +++ b/testproject/ProjectSettings/ProjectSettings.asset @@ -555,6 +555,7 @@ PlayerSettings: ps4videoRecordingFeaturesUsed: 0 ps4contentSearchFeaturesUsed: 0 ps4CompatibilityPS5: 0 + ps4AllowPS5Detection: 0 ps4GPU800MHz: 1 ps4attribEyeToEyeDistanceSettingVR: 0 ps4IncludedModules: [] @@ -580,7 +581,7 @@ PlayerSettings: webGLThreadsSupport: 0 webGLDecompressionFallback: 0 scriptingDefineSymbols: - 1: AUTHENTICATION_TESTING_STAGING_UAS; + 1: AUTHENTICATION_TESTING_STAGING_UAS additionalCompilerArguments: {} platformArchitecture: {} scriptingBackend: {} @@ -656,7 +657,14 @@ PlayerSettings: XboxOneOverrideIdentityPublisher: vrEditorSettings: {} cloudServicesEnabled: + Analytics: 0 + Build: 0 + Collab: 0 + Game Performance: 0 + Purchasing: 0 + UDP: 0 UNet: 1 + Unity Ads: 0 luminIcon: m_Name: m_ModelFolderPath: @@ -670,11 +678,11 @@ PlayerSettings: m_VersionName: apiCompatibilityLevel: 6 activeInputHandler: 0 - cloudProjectId: 29e7e6bb-3cf4-46ea-bdc9-b9581a9d0b47 + cloudProjectId: 41b4b759-38bb-46fb-9eb2-b233a90bade7 framebufferDepthMemorylessMode: 0 qualitySettingsNames: [] - projectName: testproject - organizationId: mlapi-test + projectName: relay-stg + organizationId: relay-stg cloudEnabled: 0 legacyClampBlendShapeWeights: 0 virtualTexturingSupportEnabled: 0 diff --git a/testproject/ProjectSettings/ProjectVersion.txt b/testproject/ProjectSettings/ProjectVersion.txt index 79c71bce82..5ac0724b15 100644 --- a/testproject/ProjectSettings/ProjectVersion.txt +++ b/testproject/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2020.3.12f1 -m_EditorVersionWithRevision: 2020.3.12f1 (b3b2c6512326) +m_EditorVersion: 2020.3.15f2 +m_EditorVersionWithRevision: 2020.3.15f2 (6cf78cb77498)