diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index fbef1d9d28..4561c80c24 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -10,6 +10,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Added +- Added a `WebSocketPath` field to `UnityTransport.ConnectionData` (which also shows up in the inspector if "Use WebSockets" is checked) that controls the path clients will connect to and servers/hosts will listen on when using WebSockets. (#3901) - `NetworkTransport.EarlyUpdate` and `NetworkTransport.PostLateUpdate` are now public. For the vast majority of users, there's really no point in ever calling those methods directly (the `NetworkManager` handles it). It's only useful if wrapping transports outside of NGO. (#3890) ### Changed diff --git a/com.unity.netcode.gameobjects/Editor/HiddenScriptEditor.cs b/com.unity.netcode.gameobjects/Editor/HiddenScriptEditor.cs index f9d18b8890..2311da1477 100644 --- a/com.unity.netcode.gameobjects/Editor/HiddenScriptEditor.cs +++ b/com.unity.netcode.gameobjects/Editor/HiddenScriptEditor.cs @@ -42,6 +42,7 @@ public class UnityTransportEditor : HiddenScriptEditor private SerializedProperty m_ServerAddressProperty; private SerializedProperty m_ServerPortProperty; + private SerializedProperty m_WebSocketPathProperty; private const string k_LoopbackIpv4 = "127.0.0.1"; private const string k_LoopbackIpv6 = "::1"; @@ -62,6 +63,7 @@ private void Initialize() m_ServerAddressProperty = connectionDataProperty.FindPropertyRelative(nameof(UnityTransport.ConnectionAddressData.Address)); m_ServerPortProperty = connectionDataProperty.FindPropertyRelative(nameof(UnityTransport.ConnectionAddressData.Port)); + m_WebSocketPathProperty = connectionDataProperty.FindPropertyRelative(nameof(UnityTransport.ConnectionAddressData.WebSocketPath)); } /// @@ -79,6 +81,11 @@ public override void OnInspectorGUI() EditorGUILayout.PropertyField(m_ServerAddressProperty); EditorGUILayout.PropertyField(m_ServerPortProperty); + if (m_UnityTransport.UseWebSockets) + { + EditorGUILayout.PropertyField(m_WebSocketPathProperty); + } + serializedObject.ApplyModifiedProperties(); EditorGUILayout.HelpBox("It's recommended to leave remote connections disabled for local testing to avoid exposing ports on your device.", MessageType.Info); diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs index 812ef7550d..b39fe2bc94 100644 --- a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs +++ b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs @@ -68,7 +68,7 @@ public enum ProtocolType // frame at 60 FPS. This will be a large over-estimation in any realistic scenario. private const int k_MaxReliableThroughput = (NetworkParameterConstants.MTU * 64 * 60) / 1000; // bytes per millisecond - private static ConnectionAddressData s_DefaultConnectionAddressData = new ConnectionAddressData { Address = "127.0.0.1", Port = 7777, ServerListenAddress = string.Empty }; + private static ConnectionAddressData s_DefaultConnectionAddressData = new ConnectionAddressData { Address = "127.0.0.1", Port = 7777, WebSocketPath = "/", ServerListenAddress = string.Empty }; #pragma warning disable IDE1006 // Naming Styles /// @@ -228,6 +228,13 @@ public struct ConnectionAddressData [SerializeField] public ushort Port; + /// + /// Path of the URL when using WebSockets. + /// + [Tooltip("Path to connect to or listen on when using WebSockets. Defaults to \"/\" if not set.")] + [SerializeField] + public string WebSocketPath; + /// /// IP address the server will listen on. If not provided, will use localhost. /// @@ -513,6 +520,12 @@ public NetworkSettings GetDefaultNetworkSettings() } } + // Set up the WebSocket path if configured and if using WebSockets. + if (m_UseWebSockets && m_ProtocolType != ProtocolType.RelayUnityTransport && !string.IsNullOrWhiteSpace(ConnectionData.WebSocketPath)) + { + settings.WithWebSocketParameters(path: ConnectionData.WebSocketPath); + } + #if UNITY_MP_TOOLS_NETSIM_IMPLEMENTATION_ENABLED // Latency, jitter and packet loss will be set by the network simulator in the tools // package. We just need to initialize the settings since otherwise these features will diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs index 47e9d610df..92e4beb906 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs @@ -79,6 +79,56 @@ public IEnumerator ConnectSingleClient_IPAddress() yield return null; } + // Check connection with a single WebSocket client (IP address). + [UnityTest] + public IEnumerator ConnectSingleClient_WebSocket_IPAddress() + { + InitializeTransport(out m_Server, out m_ServerEvents); + InitializeTransport(out m_Clients[0], out m_ClientsEvents[0]); + + m_Server.UseWebSockets = true; + m_Clients[0].UseWebSockets = true; + + m_Clients[0].SetConnectionData("127.0.0.1", 7777); + + m_Server.StartServer(); + m_Clients[0].StartClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Connect, m_ClientsEvents[0]); + + // Check we've received Connect event on server too. + Assert.AreEqual(1, m_ServerEvents.Count); + Assert.AreEqual(NetworkEvent.Connect, m_ServerEvents[0].Type); + + yield return null; + } + + // Check connection with a single WebSocket client (IP address and path). + [UnityTest] + public IEnumerator ConnectSingleClient_WebSocket_IPAddressAndPath() + { + InitializeTransport(out m_Server, out m_ServerEvents); + InitializeTransport(out m_Clients[0], out m_ClientsEvents[0]); + + m_Server.UseWebSockets = true; + m_Clients[0].UseWebSockets = true; + + m_Clients[0].SetConnectionData("127.0.0.1", 7777); + m_Clients[0].ConnectionData.WebSocketPath = "/test"; + m_Server.ConnectionData.WebSocketPath = "/test"; + + m_Server.StartServer(); + m_Clients[0].StartClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Connect, m_ClientsEvents[0]); + + // Check we've received Connect event on server too. + Assert.AreEqual(1, m_ServerEvents.Count); + Assert.AreEqual(NetworkEvent.Connect, m_ServerEvents[0].Type); + + yield return null; + } + #if HOSTNAME_RESOLUTION_AVAILABLE // Check connection with a single client (hostname). [UnityTest]