Skip to content

Commit 7db429f

Browse files
fix: OnClientDisconnected client identifier is incorrect when pending client connection is denied [MTT-6376] (#2569)
* fix When connection approval is enabled and a client is not approved, the OnClientDisconnected callback handler was not being invoked. (It was when a client terminates the connection but not when the server does) * test The test to validate the fix for the server-host not receiving the correct client identifier when denied approval for its pending connection. Added additional functionality to NetcodeIntegrationTest that allows you to ignore waiting for a newly created client (i.e. not the default defined NumberOfClients) to connect. Adding additional validation to assure we don't get multiple disconnect notifications on the server-host side when a client is disconnected. * Update CHANGELOG.md * style renaming NetcodeIntegrationTest.WaitForNewClientToConnect to NetcodeIntegrationTest.ShouldWaitForNewClientToConnect
1 parent 99a1b94 commit 7db429f

File tree

5 files changed

+120
-11
lines changed

5 files changed

+120
-11
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
1515

1616
### Fixed
1717

18+
- Fixed issue where the `OnClientDisconnected` client identifier was incorrect after a pending client connection was denied. (#2569)
1819
- Fixed warning "Runtime Network Prefabs was not empty at initialization time." being erroneously logged when no runtime network prefabs had been added (#2565)
1920
- Fixed issue where some temporary debug console logging was left in a merged PR. (#2562)
2021
- Fixed the "Generate Default Network Prefabs List" setting not loading correctly and always reverting to being checked. (#2545)

com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,16 @@ internal void OnClientDisconnectFromServer(ulong clientId)
844844
{
845845
var transportId = ClientIdToTransportId(clientId);
846846
NetworkManager.NetworkConfig.NetworkTransport.DisconnectRemoteClient(transportId);
847+
848+
try
849+
{
850+
OnClientDisconnectCallback?.Invoke(clientId);
851+
}
852+
catch (Exception exception)
853+
{
854+
Debug.LogException(exception);
855+
}
856+
847857
// Clean up the transport to client (and vice versa) mappings
848858
TransportIdCleanUp(transportId);
849859
}

com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,18 @@ protected virtual void OnNewClientStartedAndConnected(NetworkManager networkMana
431431
{
432432
}
433433

434+
/// <summary>
435+
/// CreateAndStartNewClient Only
436+
/// Override this method to bypass the waiting for a client to connect.
437+
/// </summary>
438+
/// <remarks>
439+
/// Use this for testing connection and disconnection scenarios
440+
/// </remarks>
441+
protected virtual bool ShouldWaitForNewClientToConnect(NetworkManager networkManager)
442+
{
443+
return true;
444+
}
445+
434446
/// <summary>
435447
/// This will create, start, and connect a new client while in the middle of an
436448
/// integration test.
@@ -455,19 +467,22 @@ protected IEnumerator CreateAndStartNewClient()
455467

456468
OnNewClientStarted(networkManager);
457469

458-
// Wait for the new client to connect
459-
yield return WaitForClientsConnectedOrTimeOut();
460-
461-
OnNewClientStartedAndConnected(networkManager);
462-
if (s_GlobalTimeoutHelper.TimedOut)
470+
if (ShouldWaitForNewClientToConnect(networkManager))
463471
{
464-
AddRemoveNetworkManager(networkManager, false);
465-
Object.DestroyImmediate(networkManager.gameObject);
466-
}
472+
// Wait for the new client to connect
473+
yield return WaitForClientsConnectedOrTimeOut();
467474

468-
AssertOnTimeout($"{nameof(CreateAndStartNewClient)} timed out waiting for the new client to be connected!");
469-
ClientNetworkManagerPostStart(networkManager);
470-
VerboseDebug($"[{networkManager.name}] Created and connected!");
475+
OnNewClientStartedAndConnected(networkManager);
476+
if (s_GlobalTimeoutHelper.TimedOut)
477+
{
478+
AddRemoveNetworkManager(networkManager, false);
479+
Object.DestroyImmediate(networkManager.gameObject);
480+
}
481+
482+
AssertOnTimeout($"{nameof(CreateAndStartNewClient)} timed out waiting for the new client to be connected!");
483+
ClientNetworkManagerPostStart(networkManager);
484+
VerboseDebug($"[{networkManager.name}] Created and connected!");
485+
}
471486
}
472487

473488
/// <summary>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using NUnit.Framework;
4+
using Unity.Netcode.TestHelpers.Runtime;
5+
using UnityEngine.TestTools;
6+
7+
8+
namespace Unity.Netcode.RuntimeTests
9+
{
10+
public class ClientApprovalDenied : NetcodeIntegrationTest
11+
{
12+
protected override int NumberOfClients => 2;
13+
private bool m_ApproveConnection = true;
14+
private ulong m_PendingClientId = 0;
15+
private ulong m_DisconnectedClientId = 0;
16+
17+
private List<ulong> m_DisconnectedClientIdentifiers = new List<ulong>();
18+
19+
private void ConnectionApproval(NetworkManager.ConnectionApprovalRequest connectionApprovalRequest, NetworkManager.ConnectionApprovalResponse connectionApprovalResponse)
20+
{
21+
connectionApprovalResponse.Approved = m_ApproveConnection;
22+
connectionApprovalResponse.CreatePlayerObject = true;
23+
// When denied, store the client identifier to use for validating the client disconnected notification identifier matches
24+
if (!m_ApproveConnection)
25+
{
26+
m_PendingClientId = connectionApprovalRequest.ClientNetworkId;
27+
}
28+
}
29+
30+
protected override void OnNewClientCreated(NetworkManager networkManager)
31+
{
32+
networkManager.NetworkConfig.ConnectionApproval = true;
33+
base.OnNewClientCreated(networkManager);
34+
}
35+
36+
protected override bool ShouldWaitForNewClientToConnect(NetworkManager networkManager)
37+
{
38+
return false;
39+
}
40+
41+
/// <summary>
42+
/// Validates that when a pending client is denied approval the server-host
43+
/// OnClientDisconnected method will return the valid pending client identifier.
44+
/// </summary>
45+
[UnityTest]
46+
public IEnumerator ClientDeniedAndDisconnectionNotificationTest()
47+
{
48+
m_ServerNetworkManager.NetworkConfig.ConnectionApproval = true;
49+
m_ServerNetworkManager.ConnectionApprovalCallback = ConnectionApproval;
50+
m_ApproveConnection = false;
51+
m_ServerNetworkManager.OnClientDisconnectCallback += OnClientDisconnectCallback;
52+
yield return CreateAndStartNewClient();
53+
yield return WaitForConditionOrTimeOut(() => m_PendingClientId == m_DisconnectedClientId);
54+
AssertOnTimeout($"Timed out waiting for disconnect notification for pending Client-{m_PendingClientId}!");
55+
56+
// Validate that we don't get multiple disconnect notifications for clients being disconnected
57+
// Have a client disconnect remotely
58+
m_ClientNetworkManagers[0].Shutdown();
59+
60+
// Have the server disconnect a client
61+
m_ServerNetworkManager.DisconnectClient(m_ClientNetworkManagers[1].LocalClientId);
62+
m_ServerNetworkManager.OnClientDisconnectCallback -= OnClientDisconnectCallback;
63+
}
64+
65+
private void OnClientDisconnectCallback(ulong clientId)
66+
{
67+
Assert.False(m_DisconnectedClientIdentifiers.Contains(clientId), $"Received two disconnect notifications from Client-{clientId}!");
68+
m_DisconnectedClientIdentifiers.Add(clientId);
69+
m_DisconnectedClientId = clientId;
70+
}
71+
}
72+
}

com.unity.netcode.gameobjects/Tests/Runtime/ClientApprovalDenied.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)