Skip to content

Commit 9a85d10

Browse files
committed
Merge branch 'develop-2.0.0' into fix/cap-maximum-disconnect-timeout
2 parents 487eada + 206b610 commit 9a85d10

File tree

12 files changed

+253
-171
lines changed

12 files changed

+253
-171
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ Additional documentation and release notes are available at [Multiplayer Documen
1919
### Changed
2020

2121
- First pass of CoreCLR engine API changes. (#3799)
22-
- Changed NetworkAnimator to use the `RpcAttribute` along with the appropriate `SendTo` parameter. (#3586)
22+
- Changed when a server is disconnecting a client with a reason it now defers the complete transport disconnect sequence until the end of the frame after the server's transport has sent all pending outbound messages. (#3786)
2323
- Improve performance of `NetworkTransformState`. (#3770)
24-
24+
- Changed NetworkAnimator to use the `RpcAttribute` along with the appropriate `SendTo` parameter. (#3586)
2525

2626
### Deprecated
2727

@@ -32,6 +32,8 @@ Additional documentation and release notes are available at [Multiplayer Documen
3232
### Fixed
3333

3434
- Fixed issues with the "Client-server quickstart for Netcode for GameObjects" script having static methods and properties. (#3787)
35+
- Fixed issue where a warning message was being logged upon a client disconnecting from a server when the log level is set to developer. (#3786)
36+
- Fixed issue where the server or host would no longer have access to the transport id to client id table when processing a transport level client disconnect event. (#3786)
3537
- Fixed issue where invoking an RPC, on another `NetworkBehaviour` associated with the same `NetworkObject` that is ordered before the `NetworkBehaviour` invoking the RPC, during `OnNetworkSpawn` could throw an exception if scene management is disabled. (#3782)
3638
- Fixed issue where the `Axis to Synchronize` toggles didn't work with multi object editing in `NetworkTransform`. (#3781)
3739
- Fixed issue where using the dedicated server package would override all attempts to change the port by code. (#3760)

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

Lines changed: 90 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -362,11 +362,6 @@ internal void RemovePendingClient(ulong clientId)
362362
return (clientId, true);
363363
}
364364

365-
if (NetworkLog.CurrentLogLevel == LogLevel.Developer)
366-
{
367-
NetworkLog.LogWarning($"Trying to get the NGO client ID map for the transport ID ({transportId}) but did not find the map entry! Returning default transport ID value.");
368-
}
369-
370365
return (default, false);
371366
}
372367

@@ -488,6 +483,15 @@ internal void HandleNetworkEvent(NetworkEvent networkEvent, ulong transportClien
488483
}
489484
}
490485

486+
/// <summary>
487+
/// Client's save their assigned transport id.
488+
/// </summary>
489+
/// <remarks>
490+
/// Added to be able to appropriately log the client's transport
491+
/// id when it is shutdown or disconnected.
492+
/// </remarks>
493+
private ulong m_LocalClientTransportId;
494+
491495
/// <summary>
492496
/// Handles a <see cref="NetworkEvent.Connect"/> event.
493497
/// </summary>
@@ -508,6 +512,8 @@ internal void ConnectEventHandler(ulong transportClientId)
508512
}
509513
else
510514
{
515+
// Cache the local client's transport id.
516+
m_LocalClientTransportId = transportClientId;
511517
clientId = NetworkManager.ServerClientId;
512518
}
513519

@@ -585,9 +591,14 @@ private void GenerateDisconnectInformation(ulong clientId, ulong transportClient
585591
/// </summary>
586592
internal void DisconnectEventHandler(ulong transportClientId)
587593
{
588-
var (clientId, wasConnectedClient) = TransportIdCleanUp(transportClientId);
589-
if (!wasConnectedClient)
594+
// Check to see if the client has already been removed from the table but
595+
// do not remove it just yet.
596+
var (clientId, isConnectedClient) = TransportIdToClientId(transportClientId);
597+
598+
// If the client is not registered and we are the server
599+
if (!isConnectedClient && NetworkManager.IsServer)
590600
{
601+
// Then exit early
591602
return;
592603
}
593604

@@ -622,17 +633,12 @@ internal void DisconnectEventHandler(ulong transportClientId)
622633
{
623634
// We need to process the disconnection before notifying
624635
OnClientDisconnectFromServer(clientId);
625-
626-
// Now notify the client has disconnected
627-
InvokeOnClientDisconnectCallback(clientId);
628-
629-
if (LocalClient.IsHost)
630-
{
631-
InvokeOnPeerDisconnectedCallback(clientId);
632-
}
633636
}
634637
else
635638
{
639+
// Client's clean up their transport id separately from the server.
640+
TransportIdCleanUp(transportClientId);
641+
636642
// Notify local client of disconnection
637643
InvokeOnClientDisconnectCallback(clientId);
638644

@@ -793,12 +799,15 @@ private IEnumerator ApprovalTimeout(ulong clientId)
793799
/// </summary>
794800
internal void ApproveConnection(ref ConnectionRequestMessage connectionRequestMessage, ref NetworkContext context)
795801
{
802+
if (ConnectionApprovalCallback == null)
803+
{
804+
return;
805+
}
796806
// Note: Delegate creation allocates.
797807
// Note: ToArray() also allocates. :(
798808
var response = new NetworkManager.ConnectionApprovalResponse();
799809
ClientsToApprove[context.SenderId] = response;
800-
801-
ConnectionApprovalCallback(
810+
ConnectionApprovalCallback?.Invoke(
802811
new NetworkManager.ConnectionApprovalRequest
803812
{
804813
Payload = connectionRequestMessage.ConnectionData,
@@ -852,13 +861,6 @@ internal void ProcessPendingApprovals()
852861
}
853862
}
854863

855-
/// <summary>
856-
/// Adding this because message hooks cannot happen fast enough under certain scenarios
857-
/// where the message is sent and responded to before the hook is in place.
858-
/// </summary>
859-
internal bool MockSkippingApproval;
860-
861-
862864
/// <summary>
863865
/// Server Side: Handles the denial of a client who sent a connection request
864866
/// </summary>
@@ -873,12 +875,36 @@ private void HandleConnectionDisconnect(ulong ownerClientId, string reason = "")
873875
{
874876
Reason = reason
875877
};
876-
SendMessage(ref disconnectReason, NetworkDelivery.Reliable, ownerClientId);
878+
SendMessage(ref disconnectReason, MessageDeliveryType<DisconnectReasonMessage>.DefaultDelivery, ownerClientId);
879+
m_ClientsToDisconnect.Add(ownerClientId);
880+
return;
877881
}
878882

879883
DisconnectRemoteClient(ownerClientId);
880884
}
881885

886+
private List<ulong> m_ClientsToDisconnect = new List<ulong>();
887+
888+
internal void ProcessClientsToDisconnect()
889+
{
890+
if (m_ClientsToDisconnect.Count == 0)
891+
{
892+
return;
893+
}
894+
foreach (var clientId in m_ClientsToDisconnect)
895+
{
896+
try
897+
{
898+
DisconnectRemoteClient(clientId);
899+
}
900+
catch (Exception ex)
901+
{
902+
Debug.LogException(ex);
903+
}
904+
}
905+
m_ClientsToDisconnect.Clear();
906+
}
907+
882908
/// <summary>
883909
/// Server Side: Handles the approval of a client
884910
/// </summary>
@@ -939,12 +965,6 @@ internal void HandleConnectionApproval(ulong ownerClientId, bool createPlayerObj
939965
// Server doesn't send itself the connection approved message
940966
if (ownerClientId != NetworkManager.ServerClientId)
941967
{
942-
if (MockSkippingApproval)
943-
{
944-
NetworkLog.LogInfo("Mocking server not responding with connection approved...");
945-
return;
946-
}
947-
948968
SendConnectionApprovedMessage(ownerClientId);
949969

950970
// If scene management is disabled, then we are done and notify the local host-server the client is connected
@@ -1040,7 +1060,7 @@ private void SendConnectionApprovedMessage(ulong approvedClientId)
10401060
}
10411061
}
10421062

1043-
SendMessage(ref message, NetworkDelivery.ReliableFragmentedSequenced, approvedClientId);
1063+
SendMessage(ref message, MessageDeliveryType<ConnectionApprovedMessage>.DefaultDelivery, approvedClientId);
10441064

10451065
message.MessageVersions.Dispose();
10461066
message.ConnectedClientIds.Dispose();
@@ -1111,13 +1131,9 @@ internal NetworkClient AddClient(ulong clientId)
11111131
return ConnectedClients[clientId];
11121132
}
11131133

1114-
var networkClient = LocalClient;
1115-
11161134
// If this is not the local client then create a new one
1117-
if (clientId != NetworkManager.LocalClientId)
1118-
{
1119-
networkClient = new NetworkClient();
1120-
}
1135+
var networkClient = clientId == NetworkManager.LocalClientId ? LocalClient : new NetworkClient();
1136+
11211137
networkClient.SetRole(clientId == NetworkManager.ServerClientId, isClient: true, NetworkManager);
11221138
networkClient.ClientId = clientId;
11231139
if (!ConnectedClients.ContainsKey(clientId))
@@ -1224,6 +1240,14 @@ internal void OnClientDisconnectFromServer(ulong clientId)
12241240
// clean up as everything that needs to be destroyed will be during shutdown.
12251241
if (NetworkManager.ShutdownInProgress && clientId == NetworkManager.ServerClientId)
12261242
{
1243+
// Now notify the client has disconnected.
1244+
// (transport id cleanup is handled within)
1245+
InvokeOnClientDisconnectCallback(clientId);
1246+
1247+
if (LocalClient.IsHost)
1248+
{
1249+
InvokeOnPeerDisconnectedCallback(clientId);
1250+
}
12271251
return;
12281252
}
12291253

@@ -1392,8 +1416,20 @@ internal void OnClientDisconnectFromServer(ulong clientId)
13921416
}
13931417

13941418
ConnectedClientIds.Remove(clientId);
1395-
var message = new ClientDisconnectedMessage { ClientId = clientId };
1396-
MessageManager?.SendMessage(ref message, MessageDeliveryType<ClientDisconnectedMessage>.DefaultDelivery, ConnectedClientIds);
1419+
1420+
if (MessageManager != null)
1421+
{
1422+
var message = new ClientDisconnectedMessage { ClientId = clientId };
1423+
foreach (var sendToId in ConnectedClientIds)
1424+
{
1425+
// Do not send a disconnect message to ourself
1426+
if (sendToId == NetworkManager.LocalClientId)
1427+
{
1428+
continue;
1429+
}
1430+
MessageManager.SendMessage(ref message, MessageDeliveryType<ClientDisconnectedMessage>.DefaultDelivery, sendToId);
1431+
}
1432+
}
13971433

13981434
// Used for testing/validation purposes only
13991435
// Promote a new session owner when the ENABLE_DAHOST_AUTOPROMOTE_SESSION_OWNER scripting define is set
@@ -1404,17 +1440,18 @@ internal void OnClientDisconnectFromServer(ulong clientId)
14041440
var (transportId, idExists) = ClientIdToTransportId(clientId);
14051441
if (idExists)
14061442
{
1407-
NetworkManager.NetworkConfig.NetworkTransport.DisconnectRemoteClient(transportId);
1408-
1409-
InvokeOnClientDisconnectCallback(clientId);
1410-
1411-
if (LocalClient.IsHost)
1443+
// Clean up the transport to client (and vice versa) mappings
1444+
var (transportIdDisconnected, wasRemoved) = TransportIdCleanUp(transportId);
1445+
if (wasRemoved)
14121446
{
1413-
InvokeOnPeerDisconnectedCallback(clientId);
1414-
}
1447+
NetworkManager.NetworkConfig.NetworkTransport.DisconnectRemoteClient(transportId);
1448+
InvokeOnClientDisconnectCallback(clientId);
14151449

1416-
// Clean up the transport to client (and vice versa) mappings
1417-
TransportIdCleanUp(transportId);
1450+
if (LocalClient.IsHost)
1451+
{
1452+
InvokeOnPeerDisconnectedCallback(clientId);
1453+
}
1454+
}
14181455
}
14191456

14201457
// Assure the client id is no longer in the pending clients list
@@ -1462,16 +1499,6 @@ internal void DisconnectClient(ulong clientId, string reason = null)
14621499
return;
14631500
}
14641501

1465-
if (!string.IsNullOrEmpty(reason))
1466-
{
1467-
var disconnectReason = new DisconnectReasonMessage
1468-
{
1469-
Reason = reason
1470-
};
1471-
SendMessage(ref disconnectReason, NetworkDelivery.Reliable, clientId);
1472-
}
1473-
1474-
Transport.ClosingRemoteConnection();
14751502
var transportId = ClientIdToTransportId(clientId);
14761503
if (transportId.Item2)
14771504
{
@@ -1491,6 +1518,7 @@ internal void DisconnectClient(ulong clientId, string reason = null)
14911518
internal void Initialize(NetworkManager networkManager)
14921519
{
14931520
// Prepare for a new session
1521+
m_LocalClientTransportId = 0;
14941522
LocalClient.IsApproved = false;
14951523
m_PendingClients.Clear();
14961524
ConnectedClients.Clear();
@@ -1524,8 +1552,9 @@ internal void Shutdown()
15241552
{
15251553
Transport.ShuttingDown();
15261554
var clientId = NetworkManager ? NetworkManager.LocalClientId : NetworkManager.ServerClientId;
1527-
var transportId = ClientIdToTransportId(clientId);
1528-
GenerateDisconnectInformation(clientId, transportId.Item1, $"{nameof(NetworkConnectionManager)} was shutdown.");
1555+
// Server and host just log 0 for their transport id while clients will log their cached m_LocalClientTransportId
1556+
var transportId = clientId == NetworkManager.ServerClientId ? 0 : m_LocalClientTransportId;
1557+
GenerateDisconnectInformation(clientId, transportId, $"{nameof(NetworkConnectionManager)} was shutdown.");
15291558
}
15301559

15311560
if (LocalClient.IsServer)

com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,6 @@ public void NetworkUpdate(NetworkUpdateStage updateStage)
346346
AnticipationSystem.SetupForUpdate();
347347
MessageManager.ProcessIncomingMessageQueue();
348348

349-
MessageManager.CleanupDisconnectedClients();
350349
AnticipationSystem.ProcessReanticipation();
351350
#if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D
352351
foreach (var networkObjectEntry in NetworkTransformFixedUpdate)
@@ -478,6 +477,18 @@ public void NetworkUpdate(NetworkUpdateStage updateStage)
478477
// This is "ok" to invoke when not processing messages since it is just cleaning up messages that never got handled within their timeout period.
479478
DeferredMessageManager.CleanupStaleTriggers();
480479

480+
if (IsServer)
481+
{
482+
// Process any pending clients that need to be disconnected.
483+
// This is typically a disconnect with reason scenario where
484+
// we want the disconnect reason message to be sent prior to
485+
// completely shutting down the endpoint.
486+
ConnectionManager.ProcessClientsToDisconnect();
487+
}
488+
489+
// Clean up disconnected clients last
490+
MessageManager.CleanupDisconnectedClients();
491+
481492
if (m_ShuttingDown)
482493
{
483494
// Host-server will disconnect any connected clients prior to finalizing its shutdown

com.unity.netcode.gameobjects/Runtime/Messaging/NetworkMessageManager.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,11 @@ private void CleanupDisconnectedClient(ulong clientId)
492492

493493
internal void CleanupDisconnectedClients()
494494
{
495+
if (m_DisconnectedClients.Count == 0)
496+
{
497+
return;
498+
}
499+
495500
foreach (var clientId in m_DisconnectedClients)
496501
{
497502
CleanupDisconnectedClient(clientId);

com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -357,18 +357,9 @@ private struct PacketLossCache
357357
public float PacketLoss;
358358
};
359359

360-
/// <summary>
361-
/// TODO-FIXME:
362-
/// Multiplayer Tools subscribes to this event and does not have the EntityId udpate.
363-
/// </summary>
364-
#if FIXED
365360
#if UNITY_6000_2_OR_NEWER
366-
internal static event Action<EntityId, NetworkDriver> TransportInitialized;
367-
internal static event Action<EntityId> TransportDisposed;
368-
#else
369-
internal static event Action<int, NetworkDriver> TransportInitialized;
370-
internal static event Action<int> TransportDisposed;
371-
#endif
361+
internal static event Action<EntityId, NetworkDriver> OnDriverInitialized;
362+
internal static event Action<EntityId> OnDisposingDriver;
372363
#endif
373364
internal static event Action<int, NetworkDriver> TransportInitialized;
374365
internal static event Action<int> TransportDisposed;
@@ -450,13 +441,8 @@ private void InitDriver()
450441
out m_ReliableSequencedPipeline);
451442
#if UNITY_6000_2_OR_NEWER
452443
var entityId = GetEntityId();
453-
#if UNITY_6000_3_0A6_OR_HIGHER
454-
// TODO-FIXME: Since multiplayer tools subscribes to this and we have to validate against any package that
455-
// might use this action, we have to cast it down temporarily to avoid being blocked from getting these fixes in place.
456-
TransportInitialized?.Invoke((int)entityId.GetRawData(), m_Driver);
457-
#else
458-
TransportInitialized?.Invoke(entityId, m_Driver);
459-
#endif
444+
OnDriverInitialized?.Invoke(entityId, m_Driver);
445+
TransportInitialized?.Invoke(entityId.GetHashCode(), m_Driver);
460446
#else
461447
TransportInitialized?.Invoke(GetInstanceID(), m_Driver);
462448
#endif
@@ -478,14 +464,8 @@ private void DisposeInternals()
478464

479465
#if UNITY_6000_2_OR_NEWER
480466
var entityId = GetEntityId();
481-
#if UNITY_6000_3_0A6_OR_HIGHER
482-
// TODO-FIXME: Since multiplayer tools subscribes to this and we have to validate against any package that
483-
// might use this action, we have to cast it down temporarily to avoid being blocked from getting these fixes in place.
484-
TransportDisposed?.Invoke((int)entityId.GetRawData());
485-
#else
486-
TransportDisposed?.Invoke(entityId, m_Driver);
487-
#endif
488-
467+
OnDisposingDriver?.Invoke(entityId);
468+
TransportDisposed?.Invoke(entityId.GetHashCode());
489469
#else
490470
TransportDisposed?.Invoke(GetInstanceID());
491471
#endif

0 commit comments

Comments
 (0)