Skip to content

Commit e24c2e5

Browse files
EmandMunity-renovate[bot]NoelStephensUnity
authored
fix: DA client connection flow (#3459)
<!-- Replace this block with what this PR does and why. Describe what you'd like reviewers to know, how you applied the engineering principles, and any interesting tradeoffs made. Delete bullet points below that don't apply, and update the changelog section as appropriate. --> <!-- Add short version of the JIRA ticket to the PR title (e.g. "feat: new shiny feature [MTT-123]") --> [MTT-12308](https://jira.unity3d.com/browse/MTT-12308) ## Changelog - Fixed: Initial connection flow with CMB Service and scene management enabled ## Testing and Documentation - Includes unit tests. <!-- Uncomment and mark items off with a * if this PR deprecates any API: ### Deprecated API - [ ] An `[Obsolete]` attribute was added along with a `(RemovedAfter yyyy-mm-dd)` entry. - [ ] An [api updater] was added. - [ ] Deprecation of the API is explained in the CHANGELOG. - [ ] The users can understand why this API was removed and what they should use instead. --> ## Backport <!-- If this is a backport: - Add the following to the PR title: "\[Backport\] ..." . - Link to the original PR. If this needs a backport - state this here If a backport is not needed please provide the reason why. If the "Backports" section is not present it will lead to a CI test failure. --> Not needed. Fixes an issue with CMB Service so this is 2.0 only functionality. --------- Co-authored-by: unity-renovate[bot] <120015202+unity-renovate[bot]@users.noreply.github.com> Co-authored-by: Noel Stephens <[email protected]>
1 parent 144adee commit e24c2e5

File tree

10 files changed

+334
-80
lines changed

10 files changed

+334
-80
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
1818
- Fixed issue where non-authority `NetworkTransform` instances would not allow non-synchronized axis values to be updated locally. (#3471)
1919
- Fixed issue where invoking `NetworkObject.NetworkShow` and `NetworkObject.ChangeOwnership` consecutively within the same call stack location could result in an unnecessary change in ownership error message generated on the target client side. (#3468)
2020
- Fixed issue where `NetworkVariable`s on a `NetworkBehaviour` could fail to synchronize changes if one has `NetworkVariableUpdateTraits` set and is dirty but is not ready to send. (#3466)
21+
- Fixed issue with the Distributed Authority connection sequence with scene management enabled where the `ClientConnected` event was fired before the client was synchronized. (#3459)
2122
- Fixed inconsistencies in the `OnSceneEvent` callback. (#3458)
2223
- Fixed issues with the `NetworkBehaviour` and `NetworkVariable` length safety checks. (#3405)
2324
- Fixed memory leaks when domain reload is disabled. (#3427)

com.unity.netcode.gameobjects/Runtime/Configuration/SessionConfig.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ internal class SessionConfig
1010
public const uint ServerDistributionCompatible = 2;
1111
public const uint SessionStateToken = 3;
1212
public const uint NetworkBehaviourSerializationSafety = 4;
13+
public const uint FixConnectionFlow = 5;
1314

1415
// The most current session version (!!!!set this when you increment!!!!!)
15-
public static uint PackageSessionVersion => NetworkBehaviourSerializationSafety;
16+
public static uint PackageSessionVersion => FixConnectionFlow;
1617

1718
internal uint SessionVersion;
1819

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

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -133,48 +133,49 @@ internal void InvokeOnClientConnectedCallback(ulong clientId)
133133
Debug.LogException(exception);
134134
}
135135

136-
if (!NetworkManager.IsServer)
136+
if (NetworkManager.IsServer || NetworkManager.LocalClient.IsSessionOwner)
137137
{
138-
var peerClientIds = new NativeArray<ulong>(Math.Max(NetworkManager.ConnectedClientsIds.Count - 1, 0), Allocator.Temp);
139-
// `using var peerClientIds` or `using(peerClientIds)` renders it immutable...
140-
using var sentinel = peerClientIds;
141-
142-
var idx = 0;
143-
foreach (var peerId in NetworkManager.ConnectedClientsIds)
144-
{
145-
if (peerId == NetworkManager.LocalClientId)
146-
{
147-
continue;
148-
}
149-
150-
// This assures if the server has not timed out prior to the client synchronizing that it doesn't exceed the allocated peer count.
151-
if (peerClientIds.Length > idx)
152-
{
153-
peerClientIds[idx] = peerId;
154-
++idx;
155-
}
156-
}
157-
158138
try
159139
{
160-
OnConnectionEvent?.Invoke(NetworkManager, new ConnectionEventData { ClientId = NetworkManager.LocalClientId, EventType = ConnectionEvent.ClientConnected, PeerClientIds = peerClientIds });
140+
OnConnectionEvent?.Invoke(NetworkManager, new ConnectionEventData { ClientId = clientId, EventType = ConnectionEvent.ClientConnected });
161141
}
162142
catch (Exception exception)
163143
{
164144
Debug.LogException(exception);
165145
}
146+
147+
return;
166148
}
167-
else
149+
150+
// Invoking connection event on non-authority local client. Need to calculate PeerIds.
151+
var peerClientIds = new NativeArray<ulong>(Math.Max(NetworkManager.ConnectedClientsIds.Count - 1, 0), Allocator.Temp);
152+
// `using var peerClientIds` or `using(peerClientIds)` renders it immutable...
153+
using var sentinel = peerClientIds;
154+
155+
var idx = 0;
156+
foreach (var peerId in NetworkManager.ConnectedClientsIds)
168157
{
169-
try
158+
if (peerId == NetworkManager.LocalClientId)
170159
{
171-
OnConnectionEvent?.Invoke(NetworkManager, new ConnectionEventData { ClientId = clientId, EventType = ConnectionEvent.ClientConnected });
160+
continue;
172161
}
173-
catch (Exception exception)
162+
163+
// This assures if the server has not timed out prior to the client synchronizing that it doesn't exceed the allocated peer count.
164+
if (peerClientIds.Length > idx)
174165
{
175-
Debug.LogException(exception);
166+
peerClientIds[idx] = peerId;
167+
++idx;
176168
}
177169
}
170+
171+
try
172+
{
173+
OnConnectionEvent?.Invoke(NetworkManager, new ConnectionEventData { ClientId = NetworkManager.LocalClientId, EventType = ConnectionEvent.ClientConnected, PeerClientIds = peerClientIds });
174+
}
175+
catch (Exception exception)
176+
{
177+
Debug.LogException(exception);
178+
}
178179
}
179180

180181
internal void InvokeOnClientDisconnectCallback(ulong clientId)

com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ClientConnectedMessage.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int
3131
public void Handle(ref NetworkContext context)
3232
{
3333
var networkManager = (NetworkManager)context.SystemOwner;
34-
if (ShouldSynchronize && networkManager.NetworkConfig.EnableSceneManagement && networkManager.DistributedAuthorityMode && networkManager.LocalClient.IsSessionOwner)
34+
if (ShouldSynchronize && networkManager.NetworkConfig.EnableSceneManagement && networkManager.DistributedAuthorityMode && !networkManager.CMBServiceConnection && networkManager.LocalClient.IsSessionOwner)
3535
{
3636
networkManager.SceneManager.SynchronizeNetworkObjects(ClientId);
3737
}

com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ClientDisconnectedMessage.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int
2525
public void Handle(ref NetworkContext context)
2626
{
2727
var networkManager = (NetworkManager)context.SystemOwner;
28+
if (networkManager.DistributedAuthorityMode && networkManager.CMBServiceConnection && networkManager.LocalClient.IsSessionOwner && networkManager.NetworkConfig.EnableSceneManagement)
29+
{
30+
networkManager.SceneManager.ClientConnectionQueue.Remove(ClientId);
31+
}
2832
// All modes support removing NetworkClients
2933
networkManager.ConnectionManager.RemoveClient(ClientId);
3034
networkManager.ConnectionManager.ConnectedClientIds.Remove(ClientId);

com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,30 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int
246246
public void Handle(ref NetworkContext context)
247247
{
248248
var networkManager = (NetworkManager)context.SystemOwner;
249+
250+
if (networkManager.CMBServiceConnection && networkManager.LocalClient.IsSessionOwner && networkManager.NetworkConfig.EnableSceneManagement)
251+
{
252+
if (networkManager.LocalClientId != OwnerClientId)
253+
{
254+
if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
255+
{
256+
NetworkLog.LogInfo($"[Session Owner] Received connection approved for Client-{OwnerClientId}! Synchronizing...");
257+
}
258+
259+
networkManager.SceneManager.SynchronizeNetworkObjects(OwnerClientId);
260+
}
261+
else
262+
{
263+
NetworkLog.LogWarning($"[Client-{OwnerClientId}] Receiving duplicate connection approved. Client is already connected!");
264+
}
265+
return;
266+
}
267+
249268
if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
250269
{
251270
NetworkLog.LogInfo($"[Client-{OwnerClientId}] Connection approved! Synchronizing...");
252271
}
272+
253273
networkManager.LocalClientId = OwnerClientId;
254274
networkManager.MessageManager.SetLocalClientId(networkManager.LocalClientId);
255275
networkManager.NetworkMetrics.SetConnectionId(networkManager.LocalClientId);

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ public bool OnVerifyCanReceive(ulong senderId, Type messageType, FastBufferReade
9898
return false;
9999
}
100100

101-
if (m_NetworkManager.IsConnectedClient && messageType == typeof(ConnectionApprovedMessage))
101+
if (m_NetworkManager.IsConnectedClient && messageType == typeof(ConnectionApprovedMessage) &&
102+
!(m_NetworkManager.CMBServiceConnection && m_NetworkManager.LocalClient.IsSessionOwner && m_NetworkManager.NetworkConfig.EnableSceneManagement))
102103
{
103104
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
104105
{

com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs

Lines changed: 15 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1925,6 +1925,10 @@ private void OnClientLoadedScene(uint sceneEventId, Scene scene)
19251925
/// when many clients attempt to connect at the same time they will be
19261926
/// handled sequentially so as to not saturate the session owner's maximum
19271927
/// reliable messages.
1928+
/// DANGO-TODO: Get clients to track their synchronization status (if they haven't finished synchronizing)
1929+
/// - pending clients can listen to SessionOwnerChanged messages
1930+
/// - If the session owner changes, fire "some sort of event" to the service
1931+
/// - service can fire ConnectionApproved at new session owner
19281932
/// </summary>
19291933
internal List<ulong> ClientConnectionQueue = new List<ulong>();
19301934

@@ -2332,37 +2336,15 @@ private void HandleClientSceneEvent(uint sceneEventId)
23322336
sceneEventData.SceneEventType = SceneEventType.SynchronizeComplete;
23332337
if (NetworkManager.DistributedAuthorityMode)
23342338
{
2335-
if (NetworkManager.CMBServiceConnection)
2339+
sceneEventData.TargetClientId = NetworkManager.CurrentSessionOwner;
2340+
sceneEventData.SenderClientId = NetworkManager.LocalClientId;
2341+
var message = new SceneEventMessage
23362342
{
2337-
foreach (var clientId in NetworkManager.ConnectedClientsIds)
2338-
{
2339-
if (clientId == NetworkManager.LocalClientId)
2340-
{
2341-
continue;
2342-
}
2343-
sceneEventData.TargetClientId = clientId;
2344-
sceneEventData.SenderClientId = NetworkManager.LocalClientId;
2345-
var message = new SceneEventMessage
2346-
{
2347-
EventData = sceneEventData,
2348-
};
2349-
var target = NetworkManager.DAHost ? NetworkManager.CurrentSessionOwner : NetworkManager.ServerClientId;
2350-
var size = NetworkManager.ConnectionManager.SendMessage(ref message, k_DeliveryType, target);
2351-
NetworkManager.NetworkMetrics.TrackSceneEventSent(target, (uint)sceneEventData.SceneEventType, SceneNameFromHash(sceneEventData.SceneHash), size);
2352-
}
2353-
}
2354-
else
2355-
{
2356-
sceneEventData.TargetClientId = NetworkManager.CurrentSessionOwner;
2357-
sceneEventData.SenderClientId = NetworkManager.LocalClientId;
2358-
var message = new SceneEventMessage
2359-
{
2360-
EventData = sceneEventData,
2361-
};
2362-
var target = NetworkManager.DAHost ? NetworkManager.CurrentSessionOwner : NetworkManager.ServerClientId;
2363-
var size = NetworkManager.ConnectionManager.SendMessage(ref message, k_DeliveryType, target);
2364-
NetworkManager.NetworkMetrics.TrackSceneEventSent(target, (uint)sceneEventData.SceneEventType, SceneNameFromHash(sceneEventData.SceneHash), size);
2365-
}
2343+
EventData = sceneEventData,
2344+
};
2345+
var target = NetworkManager.DAHost ? NetworkManager.CurrentSessionOwner : NetworkManager.ServerClientId;
2346+
var size = NetworkManager.ConnectionManager.SendMessage(ref message, k_DeliveryType, target);
2347+
NetworkManager.NetworkMetrics.TrackSceneEventSent(target, (uint)sceneEventData.SceneEventType, SceneNameFromHash(sceneEventData.SceneHash), size);
23662348
}
23672349
else
23682350
{
@@ -2485,13 +2467,13 @@ private void HandleSessionOwnerEvent(uint sceneEventId, ulong clientId)
24852467
// Mark this client as being connected
24862468
NetworkManager.ConnectedClients[clientId].IsConnected = true;
24872469

2488-
// Notify the local server that a client has finished synchronizing
2470+
// Notify that a client has finished synchronizing
24892471
OnSceneEvent?.Invoke(new SceneEvent()
24902472
{
24912473
SceneEventType = sceneEventData.SceneEventType,
2492-
SceneName = string.Empty,
24932474
ClientId = clientId
24942475
});
2476+
OnSynchronizeComplete?.Invoke(clientId);
24952477

24962478
// For non-authority clients in a distributed authority session, we show hidden objects,
24972479
// we distribute NetworkObjects, and then we end the scene event.
@@ -2511,9 +2493,6 @@ private void HandleSessionOwnerEvent(uint sceneEventId, ulong clientId)
25112493
return;
25122494
}
25132495

2514-
// All scenes are synchronized, let the server know we are done synchronizing
2515-
OnSynchronizeComplete?.Invoke(clientId);
2516-
25172496
// At this time the client is fully synchronized with all loaded scenes and
25182497
// NetworkObjects and should be considered "fully connected". Send the
25192498
// notification that the client is connected.
@@ -2555,26 +2534,12 @@ private void HandleSessionOwnerEvent(uint sceneEventId, ulong clientId)
25552534
// Remove the client that just synchronized
25562535
ClientConnectionQueue.Remove(clientId);
25572536

2558-
// If we have pending clients to synchronize, then make sure they are still connected
2559-
while (ClientConnectionQueue.Count > 0)
2560-
{
2561-
// If the next client is no longer connected then remove it from the list
2562-
if (!NetworkManager.ConnectedClientsIds.Contains(ClientConnectionQueue[0]))
2563-
{
2564-
ClientConnectionQueue.RemoveAt(0);
2565-
}
2566-
else
2567-
{
2568-
break;
2569-
}
2570-
}
2571-
25722537
// If we still have any pending clients waiting, then synchronize the next one
25732538
if (ClientConnectionQueue.Count > 0)
25742539
{
25752540
if (NetworkManager.LogLevel <= LogLevel.Developer)
25762541
{
2577-
Debug.Log($"Synchronizing Client-{ClientConnectionQueue[0]}...");
2542+
Debug.Log($"Synchronizing deferred Client-{ClientConnectionQueue[0]}...");
25782543
}
25792544
SynchronizeNetworkObjects(ClientConnectionQueue[0]);
25802545
}

0 commit comments

Comments
 (0)