diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 489af4f446..0a1d33a57c 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -10,6 +10,23 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Added +- Added disconnection event notification handling capabilities where `NetworkTransport` derived custom transports can set the current disconnect event type (`NetworkTransport.DisconnectEvents`) that, if implemented, will provide more details on why the transport disconnected. (#3551) +- Added protected method `NetworkTransport.SetDisconnectEvent` that a `NetworkTransport` derived custom transport can use to provide the disconnect event type that occurred. (#3551) +- Added protected virtual method `NetworkTransport.OnGetDisconnectEventMessage` that, when overridden, a `NetworkTransport` derived custom transport can use to provide a customized extended message for each `NetworkTransport.DisconnectEvents` value. (#3551) + +### Fixed + +- Fixed issue where the disconnect event and provided message was too generic to know why the disconnect occurred. (#3551) +- Fixed issue where `SendTo.NotMe` could cause an RPC to be delivered to the sender when connected to a live distributed authority session. (#3551) + +### Changed + +- Changed `UnityTransport` now handles setting the current disconnect notification type, via internal `UnityTransportNotificationHandler` class, while also providing extended informational messages for each disconnect event type. (#3551) + +## [2.5.0] - 2025-08-01 + +### Added + - Added serializer for `Pose` (#3546) - Added methods `GetDefaultNetworkSettings` and `GetDefaultPipelineConfigurations` to `UnityTransport`. These can be used to retrieve the default settings and pipeline stages that are used by `UnityTransport`. This is useful when providing a custom driver constructor through `UnityTransport.s_DriverConstructor`, since it allows reusing or tuning the existing configuration instead of trying to recreate it. This means a transport with a custom driver can now easily benefit from most of the features of `UnityTransport`, like integration with the Network Simulator and Network Profiler from the multiplayer tools package. (#3501) - Added mappings between `ClientId` and `TransportId`. (#3516) diff --git a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs index 6514736f23..d3b899cb3c 100644 --- a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs @@ -373,10 +373,14 @@ private ulong GetServerTransportId() { if (NetworkManager != null) { - var transport = NetworkManager.NetworkConfig.NetworkTransport; - if (transport != null) + if (Transport == null && NetworkManager.NetworkConfig.NetworkTransport != null) + { + Transport = NetworkManager.NetworkConfig.NetworkTransport; + } + + if (Transport) { - return transport.ServerClientId; + return Transport.ServerClientId; } throw new NullReferenceException($"The transport in the active {nameof(NetworkConfig)} is null"); @@ -412,7 +416,7 @@ internal void PollAndHandleNetworkEvents() NetworkEvent networkEvent; do { - networkEvent = NetworkManager.NetworkConfig.NetworkTransport.PollEvent(out ulong transportClientId, out ArraySegment payload, out float receiveTime); + networkEvent = Transport.PollEvent(out ulong transportClientId, out ArraySegment payload, out float receiveTime); HandleNetworkEvent(networkEvent, transportClientId, payload, receiveTime); if (networkEvent == NetworkEvent.Disconnect || networkEvent == NetworkEvent.TransportFailure) { @@ -520,6 +524,27 @@ internal void DataEventHandler(ulong transportClientId, ref ArraySegment p #endif } + private void GenerateDisconnectInformation(ulong clientId, ulong transportClientId, string reason = null) + { + var header = $"[Disconnect Event][Client-{clientId}]"; + var existingDisconnectReason = DisconnectReason; + + var defaultMessage = Transport.DisconnectEventMessage; + if (reason != null) + { + defaultMessage = $"{reason} {defaultMessage}"; + } + // Just go ahead and set this whether client or server so any subscriptions to a disconnect event can check the DisconnectReason + // to determine why the client disconnected + DisconnectReason = $"{header}[{Transport.DisconnectEvent}] {defaultMessage}"; + DisconnectReason = $"{DisconnectReason}\n{existingDisconnectReason}"; + + if (NetworkLog.CurrentLogLevel <= LogLevel.Developer) + { + NetworkLog.LogInfo($"{DisconnectReason}"); + } + } + /// /// Handles a event. /// @@ -528,11 +553,8 @@ internal void DisconnectEventHandler(ulong transportClientId) #if DEVELOPMENT_BUILD || UNITY_EDITOR s_TransportDisconnect.Begin(); #endif - var clientId = TransportIdCleanUp(transportClientId); - if (NetworkLog.CurrentLogLevel <= LogLevel.Developer) - { - NetworkLog.LogInfo($"Disconnect Event From {clientId}"); - } + var clientId = TransportIdToClientId(transportClientId); + TransportIdCleanUp(transportClientId); // If we are a client and we have gotten the ServerClientId back, then use our assigned local id as the client that was // disconnected (either the user disconnected or the server disconnected, but the client that disconnected is the LocalClientId) @@ -541,6 +563,14 @@ internal void DisconnectEventHandler(ulong transportClientId) clientId = NetworkManager.LocalClientId; } + // If the disconnect is due to the transport being shutdown and we have received a notification + // from transport that we have disconnected, then we are a client that has shutdown the NetworkManager + // and there is no need to generate any disconnect information as all of that should already be set at this point. + if (Transport.DisconnectEvent != NetworkTransport.DisconnectEvents.TransportShutdown) + { + GenerateDisconnectInformation(clientId, transportClientId); + } + // Process the incoming message queue so that we get everything from the server disconnecting us or, if we are the server, so we got everything from that client. MessageManager.ProcessIncomingMessageQueue(); @@ -1327,7 +1357,7 @@ internal void OnClientDisconnectFromServer(ulong clientId) if (ClientIdToTransportIdMap.ContainsKey(clientId)) { var transportId = ClientIdToTransportId(clientId); - NetworkManager.NetworkConfig.NetworkTransport.DisconnectRemoteClient(transportId); + Transport.DisconnectRemoteClient(transportId); InvokeOnClientDisconnectCallback(clientId); @@ -1394,9 +1424,14 @@ internal void DisconnectClient(ulong clientId, string reason = null) SendMessage(ref disconnectReason, NetworkDelivery.Reliable, clientId); } + Transport.ClosingRemoteConnection(); + GenerateDisconnectInformation(clientId, ClientIdToTransportId(clientId), reason); DisconnectRemoteClient(clientId); } + internal NetworkTransport Transport; + internal NetworkTransport.DisconnectEvents DisconnectEvent => Transport ? Transport.DisconnectEvent : NetworkTransport.DisconnectEvents.Disconnected; + /// /// Should be invoked when starting a server-host or client /// @@ -1418,10 +1453,13 @@ internal void Initialize(NetworkManager networkManager) NetworkManager = networkManager; MessageManager = networkManager.MessageManager; - NetworkManager.NetworkConfig.NetworkTransport.NetworkMetrics = NetworkManager.MetricsManager.NetworkMetrics; - - NetworkManager.NetworkConfig.NetworkTransport.OnTransportEvent += HandleNetworkEvent; - NetworkManager.NetworkConfig.NetworkTransport.Initialize(networkManager); + Transport = NetworkManager.NetworkConfig.NetworkTransport; + if (Transport) + { + Transport.NetworkMetrics = NetworkManager.MetricsManager.NetworkMetrics; + Transport.OnTransportEvent += HandleNetworkEvent; + Transport.Initialize(networkManager); + } } /// @@ -1429,13 +1467,21 @@ internal void Initialize(NetworkManager networkManager) /// internal void Shutdown() { + if (Transport && IsListening) + { + Transport.ShuttingDown(); + var clientId = NetworkManager ? NetworkManager.LocalClientId : NetworkManager.ServerClientId; + var transportId = ClientIdToTransportId(clientId); + GenerateDisconnectInformation(clientId, transportId, $"{nameof(NetworkConnectionManager)} was shutdown."); + } + if (LocalClient.IsServer) { // Build a list of all client ids to be disconnected var disconnectedIds = new HashSet(); //Don't know if I have to disconnect the clients. I'm assuming the NetworkTransport does all the cleaning on shutdown. But this way the clients get a disconnect message from server (so long it does't get lost) - var serverTransportId = NetworkManager.NetworkConfig.NetworkTransport.ServerClientId; + var serverTransportId = GetServerTransportId(); foreach (KeyValuePair pair in ConnectedClients) { if (!disconnectedIds.Contains(pair.Key)) @@ -1478,7 +1524,7 @@ internal void Shutdown() // Client only, send disconnect and if transport throws and exception, log the exception and continue the shutdown sequence (or forever be shutting down) try { - NetworkManager.NetworkConfig.NetworkTransport.DisconnectLocalClient(); + Transport?.DisconnectLocalClient(); } catch (Exception ex) { @@ -1509,7 +1555,6 @@ internal void Shutdown() if (transport != null) { transport.Shutdown(); - if (NetworkManager.LogLevel <= LogLevel.Developer) { NetworkLog.LogInfo($"{nameof(NetworkConnectionManager)}.{nameof(Shutdown)}() -> {nameof(IsListening)} && {nameof(NetworkManager.NetworkConfig.NetworkTransport)} != null -> {nameof(NetworkTransport)}.{nameof(NetworkTransport.Shutdown)}()"); diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs index cff2768405..289d28a010 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Unity.Collections; using System.Linq; +using Unity.Netcode.Components; using UnityEngine; #if UNITY_EDITOR using UnityEditor; @@ -9,7 +10,6 @@ #endif using UnityEngine.SceneManagement; using Debug = UnityEngine.Debug; -using Unity.Netcode.Components; namespace Unity.Netcode { @@ -611,6 +611,16 @@ public ulong LocalClientId /// public string DisconnectReason => ConnectionManager.DisconnectReason; + /// + /// If supported by the , this property will be set for each disconnect event. + /// If not supported, then this remain as the default value. + /// + /// + /// A server/host will receive notifications for remote clients disconnecting and will update this property + /// upon each disconnect event.
+ ///
+ public NetworkTransport.DisconnectEvents DisconnectEvent => ConnectionManager.DisconnectEvent; + /// /// Is true when a server or host is listening for connections. /// Is true when a client is connecting or connected to a network session. @@ -1485,7 +1495,7 @@ private void HostServerInitialize() /// Disconnects the remote client. /// /// The ClientId to disconnect - public void DisconnectClient(ulong clientId) => ConnectionManager.DisconnectClient(clientId); + public void DisconnectClient(ulong clientId) => ConnectionManager.DisconnectClient(clientId, $"Client-{clientId} disconnected by server."); /// /// Disconnects the remote client. diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/NotMeRpcTarget.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/NotMeRpcTarget.cs index 5ea687101c..681c8909a4 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/NotMeRpcTarget.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/NotMeRpcTarget.cs @@ -49,8 +49,11 @@ internal override void Send(NetworkBehaviour behaviour, ref RpcMessage message, { continue; } - // In distributed authority mode, we send to target id 0 (which would be a DAHost) via the group - if (clientId == NetworkManager.ServerClientId && !m_NetworkManager.DistributedAuthorityMode) + // In distributed authority mode, we send to target id 0 (which would be a DAHost). + // We only add when there is a "DAHost" by + // - excluding the server id when using client-server (i.e. !m_NetworkManager.DistributedAuthorityMode ) + // - excluding if connected to the CMB backend service (i.e. we don't want to send to service as it will broadcast it back) + if (clientId == NetworkManager.ServerClientId && (!m_NetworkManager.DistributedAuthorityMode || m_NetworkManager.CMBServiceConnection)) { continue; } diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/NetworkTransport.cs b/com.unity.netcode.gameobjects/Runtime/Transports/NetworkTransport.cs index b8784fcfb3..bec51c0e76 100644 --- a/com.unity.netcode.gameobjects/Runtime/Transports/NetworkTransport.cs +++ b/com.unity.netcode.gameobjects/Runtime/Transports/NetworkTransport.cs @@ -164,6 +164,107 @@ internal NetworkTopologyTypes CurrentTopology() { return OnCurrentTopology(); } + + /// + /// The Netcode for GameObjects standardized disconnection event types. + /// + /// + /// provides you with the ability to register the transport's disconnect event types with the local equivalent. + /// + public enum DisconnectEvents + { + /// + /// If transport has mapped its disconnect events, this event signifies that the transport closed the connection due to a locally invoked shutdown. + /// + TransportShutdown, + /// + /// If transport has mapped its disconnect events, this event signifies a graceful disconnect. + /// + Disconnected, + /// + /// If transport has mapped its disconnect events, this event signifies that the transport's connection to the endpoint has timed out and the connection was closed. + /// + ProtocolTimeout, + /// + /// If transport has mapped its disconnect events, this event signifies that the disconnect is due to the maximum number of failed connection attempts has been reached. + /// + MaxConnectionAttempts, + /// + /// If transport has mapped its disconnect events, this event signifies that the remote endpoint closed the connection. + /// + ClosedByRemote, + /// + /// If transport has mapped its disconnect events, this event signifies the local transport closed the incoming remote endpoint connection. + /// + ClosedRemoteConnection, + /// + /// If transport has mapped its disconnect events, this event signifies that the connection was closed due to an authentication failure. + /// + AuthenticationFailure, + /// + /// If transport has mapped its disconnect events, this event signifies that a lower-level (unkown) transport error occurred. + /// + ProtocolError, + } + + /// + /// If the transport has implemented disconnection event mapping, then this will be set to the most recent disconnection event. + /// + public DisconnectEvents DisconnectEvent { get; private set; } + + /// + /// If the transport has implemented disconnection event mapping and disconnection event message mapping, then this will contain + /// the transport specific message associated with the disconnect event type. + /// + public string DisconnectEventMessage { get; private set; } + + /// + /// This should be invoked by the derived class when a transport level disconnect event occurs.
+ /// It is up to the derived class to create a map between the transport's disconnect events and the + /// pre-defined enum values. + ///
+ /// The type to set. + /// An optional message override. + protected void SetDisconnectEvent(DisconnectEvents disconnectEvent, string message = null) + { + DisconnectEvent = disconnectEvent; + DisconnectEventMessage = string.Empty; + + if (message != null) + { + DisconnectEventMessage = message; + } + else + { + DisconnectEventMessage = OnGetDisconnectEventMessage(disconnectEvent); + } + } + + /// + /// Override this method to provide additional information about the disconnection event. + /// + /// The disconnect event to get from the derived class. + /// as a default or if overridden the returned. + protected virtual string OnGetDisconnectEventMessage(DisconnectEvents disconnectEvent) + { + return string.Empty; + } + + /// + /// Invoked when the local forces the transport to close a remote connection. + /// + internal void ClosingRemoteConnection() + { + SetDisconnectEvent(DisconnectEvents.ClosedRemoteConnection); + } + + /// + /// Invoked just before the transport is shutdown. + /// + internal void ShuttingDown() + { + SetDisconnectEvent(DisconnectEvents.TransportShutdown); + } } /// diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/SinglePlayer/SinglePlayerTransport.cs b/com.unity.netcode.gameobjects/Runtime/Transports/SinglePlayer/SinglePlayerTransport.cs index 17a240b676..e113d48c06 100644 --- a/com.unity.netcode.gameobjects/Runtime/Transports/SinglePlayer/SinglePlayerTransport.cs +++ b/com.unity.netcode.gameobjects/Runtime/Transports/SinglePlayer/SinglePlayerTransport.cs @@ -28,7 +28,6 @@ private struct MessageData private static Dictionary> s_MessageQueue = new Dictionary>(); - private bool m_Initialized; private ulong m_TransportId = 0; private NetworkManager m_NetworkManager; diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs index 84513fde66..4100c0e4b4 100644 --- a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs +++ b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs @@ -15,6 +15,7 @@ using Unity.Collections.LowLevel.Unsafe; using Unity.Jobs; using Unity.Networking.Transport; +using Unity.Networking.Transport.Error; using Unity.Networking.Transport.Relay; using Unity.Networking.Transport.TLS; using Unity.Networking.Transport.Utilities; @@ -1056,6 +1057,10 @@ private bool ProcessEvent() Debug.LogError("Failed to connect to server."); } + // Set the disconnect event error code + var errorCode = m_UnityTransportNotificationHandler.GetDisconnectEvent(reader.ReadByte()); + SetDisconnectEvent(errorCode); + m_ServerClientId = default; m_ReliableReceiveQueues.Remove(clientId); ClearSendQueuesForClientId(clientId); @@ -1348,7 +1353,9 @@ public override void DisconnectRemoteClient(ulong clientId) } #endif - if (m_Driver.IsCreated) + var hasAuthority = m_NetworkManager ? m_NetworkManager.IsServer : true; + + if (hasAuthority && m_Driver.IsCreated) { FlushSendQueuesForClientId(clientId); @@ -1412,30 +1419,6 @@ public NetworkEndpoint GetEndpoint(ulong clientId) return new NetworkEndpoint(); } - /// - /// Initializes the transport - /// - /// The NetworkManager that initialized and owns the transport - public override void Initialize(NetworkManager networkManager = null) - { -#if DEBUG - if (sizeof(ulong) != UnsafeUtility.SizeOf()) - { - Debug.LogWarning($"Netcode connection id size {sizeof(ulong)} does not match UTP connection id size {UnsafeUtility.SizeOf()}!"); - return; - } -#endif - - m_NetworkManager = networkManager; - - if (m_NetworkManager && m_NetworkManager.PortOverride.Overidden) - { - ConnectionData.Port = m_NetworkManager.PortOverride.Value; - } - - m_RealTimeProvider = m_NetworkManager ? m_NetworkManager.RealTimeProvider : new RealTimeProvider(); - } - /// /// Polls for incoming events, with an extra output parameter to report the precise time the event was received. /// @@ -1589,6 +1572,39 @@ public override bool StartServer() return succeeded; } + private UnityTransportNotificationHandler m_UnityTransportNotificationHandler; + + /// + protected override string OnGetDisconnectEventMessage(DisconnectEvents disconnectEvent) + { + return m_UnityTransportNotificationHandler.GetDisconnectEventMessage(disconnectEvent); + } + + /// + /// Initializes the transport + /// + /// The NetworkManager that initialized and owns the transport + public override void Initialize(NetworkManager networkManager = null) + { +#if DEBUG + if (sizeof(ulong) != UnsafeUtility.SizeOf()) + { + Debug.LogWarning($"Netcode connection id size {sizeof(ulong)} does not match UTP connection id size {UnsafeUtility.SizeOf()}!"); + return; + } +#endif + + m_NetworkManager = networkManager; + + if (m_NetworkManager && m_NetworkManager.PortOverride.Overidden) + { + ConnectionData.Port = m_NetworkManager.PortOverride.Value; + } + + m_RealTimeProvider = m_NetworkManager ? m_NetworkManager.RealTimeProvider : new RealTimeProvider(); + m_UnityTransportNotificationHandler = new UnityTransportNotificationHandler(); + } + /// /// Shuts down the transport /// @@ -1626,6 +1642,8 @@ public override void Shutdown() // We must reset this to zero because UTP actually re-uses clientIds if there is a clean disconnect m_ServerClientId = default; + + m_UnityTransportNotificationHandler = null; } /// @@ -1812,4 +1830,67 @@ internal static FixedString128Bytes ErrorToFixedString(int error) } } } + + /// + /// Handles mapping to as well + /// as mapping additional disconnect event message information to each . + /// + internal class UnityTransportNotificationHandler + { + private const int k_ClosedRemoteConnection = 128; + private const int k_TransportShutdown = 129; + + internal const string DisconnectedMessage = "Gracefully disconnected."; + internal const string TimeoutMessage = "Connection closed due to timed out."; + internal const string MaxConnectionAttemptsMessage = "Connection closed due to maximum connection attempts reached."; + internal const string ClosedByRemoteMessage = "Connection was closed by remote endpoint."; + internal const string AuthenticationFailureMessage = "Connection closed due to authentication failure."; + internal const string ProtocolErrorMessage = "Gracefully disconnected."; + internal const string ClosedRemoteConnectionMessage = "Local transport closed the remote endpoint connection."; + internal const string TransportShutdownMessage = "The transport was shutdown."; + + private Dictionary m_DisconnectEventMap = new Dictionary(); + private Dictionary m_DisconnectEventMessageMap = new Dictionary(); + + internal NetworkTransport.DisconnectEvents GetDisconnectEvent(int disconnectEventId) + { + return m_DisconnectEventMap.ContainsKey(disconnectEventId) ? m_DisconnectEventMap[disconnectEventId] : NetworkTransport.DisconnectEvents.Disconnected; + } + + public string GetDisconnectEventMessage(NetworkTransport.DisconnectEvents disconnectEvent) + { + return string.Empty; + } + + public void ClosingRemoteConnection() + { + + } + + private void AddDisconnectEventMap(NetworkTransport.DisconnectEvents disconnectEvent, int disconnectReason, string message) + { + m_DisconnectEventMap.Add(disconnectReason, disconnectEvent); + m_DisconnectEventMessageMap.Add(disconnectEvent, message); + } + + private void AddDisconnectEventMap(NetworkTransport.DisconnectEvents disconnectEvent, DisconnectReason disconnectReason, string message) + { + AddDisconnectEventMap(disconnectEvent, (int)disconnectReason, message); + } + + public UnityTransportNotificationHandler() + { + // Implemented in UTP + AddDisconnectEventMap(NetworkTransport.DisconnectEvents.Disconnected, DisconnectReason.Default, DisconnectedMessage); + AddDisconnectEventMap(NetworkTransport.DisconnectEvents.ProtocolTimeout, DisconnectReason.Timeout, TimeoutMessage); + AddDisconnectEventMap(NetworkTransport.DisconnectEvents.MaxConnectionAttempts, DisconnectReason.MaxConnectionAttempts, MaxConnectionAttemptsMessage); + AddDisconnectEventMap(NetworkTransport.DisconnectEvents.ClosedByRemote, DisconnectReason.ClosedByRemote, ClosedByRemoteMessage); + AddDisconnectEventMap(NetworkTransport.DisconnectEvents.AuthenticationFailure, DisconnectReason.AuthenticationFailure, AuthenticationFailureMessage); + AddDisconnectEventMap(NetworkTransport.DisconnectEvents.ProtocolError, DisconnectReason.ProtocolError, ProtocolErrorMessage); + + // Not implemented in UTP + AddDisconnectEventMap(NetworkTransport.DisconnectEvents.ClosedRemoteConnection, k_ClosedRemoteConnection, ClosedRemoteConnectionMessage); + AddDisconnectEventMap(NetworkTransport.DisconnectEvents.TransportShutdown, k_TransportShutdown, TransportShutdownMessage); + } + } } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SessionVersionConnectionRequest.cs b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SessionVersionConnectionRequest.cs index d537903d8e..4a436457c0 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SessionVersionConnectionRequest.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SessionVersionConnectionRequest.cs @@ -96,7 +96,7 @@ public IEnumerator ValidateSessionVersion([Values] SessionVersionType type) { yield return WaitForConditionOrTimeOut(() => m_ClientWasDisconnected); AssertOnTimeout("Client was not disconnected when it should have been!"); - Assert.True(m_ClientNetworkManager.DisconnectReason == ConnectionRequestMessage.InvalidSessionVersionMessage, "Client did not receive the correct invalid session version message!"); + Assert.True(m_ClientNetworkManager.DisconnectReason.Contains(ConnectionRequestMessage.InvalidSessionVersionMessage), "Client did not receive the correct invalid session version message!"); } else { diff --git a/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs b/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs index cb85f0baa9..61a8a8d112 100644 --- a/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs +++ b/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs @@ -22,6 +22,8 @@ public class MultiClientConnectionApproval private bool m_DelayedApproval; private List m_ResponseToSet = new List(); + private const string k_DisconnectMessage = "Some valid reason"; + [OneTimeSetUp] public void OneTimeSetup() { @@ -180,7 +182,7 @@ private IEnumerator ConnectionApprovalHandler(int numClients, int failureTestCou foreach (var c in clientsToClean) { - Assert.AreEqual(c.DisconnectReason, "Some valid reason"); + Assert.IsTrue(c.DisconnectReason.Contains(k_DisconnectMessage), $"The disconnect message ({c.DisconnectReason}) does not contain the disconnect information ({k_DisconnectMessage})!"); } foreach (var client in clients) @@ -242,7 +244,7 @@ private void ConnectionApprovalCallback(NetworkManager.ConnectionApprovalRequest } if (!response.Approved) { - response.Reason = "Some valid reason"; + response.Reason = k_DisconnectMessage; } else {