Skip to content

Commit dbe455f

Browse files
Merge branch 'develop-2.0.0' into fix/bufferedlinearinterpolator-jitter
2 parents 1175088 + c754a2c commit dbe455f

File tree

14 files changed

+409
-34
lines changed

14 files changed

+409
-34
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ Additional documentation and release notes are available at [Multiplayer Documen
1818

1919
### Fixed
2020

21+
- Fixed issue when using a distributed authority network topology and many clients attempt to connect simultaneously the session owner could max-out the maximum in-flight reliable messages allowed, start dropping packets, and some of the connecting clients would fail to fully synchronize. (#3350)
22+
- Fixed issue when using a distributed authority network topology and scene management was disabled clients would not be able to spawn any new network prefab instances until synchronization was complete. (#3350)
23+
- Fixed issue where an owner that changes ownership, when using a distributed authority network topology, could yield identical previous and current owner identifiers. This could also cause `NetworkTransform` to fail to change ownership which would leave the previous owner still subscribed to network tick events. (#3347)
2124
- Fixed issue where the `MaximumInterpolationTime` could not be modified from within the inspector view or runtime. (#3337)
2225
- Fixed `ChangeOwnership` changing ownership to clients that are not observers. This also happened with automated object distribution. (#3323)
2326
- Fixed issue where `AnticipatedNetworkVariable` previous value returned by `AnticipatedNetworkVariable.OnAuthoritativeValueChanged` is updated correctly on the non-authoritative side. (#3306)

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1185,14 +1185,23 @@ internal void MarkVariablesDirty(bool dirty)
11851185
}
11861186
}
11871187

1188-
internal void MarkOwnerReadVariablesDirty()
1188+
/// <summary>
1189+
/// For owner read permissions, when changing ownership we need to do a full synchronization
1190+
/// of all NetworkVariables that are owner read permission based since the owner is the only
1191+
/// instance that knows what the most current values are.
1192+
/// </summary>
1193+
internal void MarkOwnerReadDirtyAndCheckOwnerWriteIsDirty()
11891194
{
11901195
for (int j = 0; j < NetworkVariableFields.Count; j++)
11911196
{
11921197
if (NetworkVariableFields[j].ReadPerm == NetworkVariableReadPermission.Owner)
11931198
{
11941199
NetworkVariableFields[j].SetDirty(true);
11951200
}
1201+
if (NetworkVariableFields[j].WritePerm == NetworkVariableWritePermission.Owner)
1202+
{
1203+
NetworkVariableFields[j].OnCheckIsDirtyState();
1204+
}
11961205
}
11971206
}
11981207

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,6 @@ internal void NetworkBehaviourUpdate(bool forceSend = false)
108108
foreach (var dirtyobj in m_DirtyNetworkObjects)
109109
{
110110
dirtyobj.PostNetworkVariableWrite(forceSend);
111-
// Once done processing, we set the previous owner id to the current owner id
112-
dirtyobj.PreviousOwnerId = dirtyobj.OwnerClientId;
113111
}
114112
m_DirtyNetworkObjects.Clear();
115113
}

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

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2567,12 +2567,39 @@ internal void MarkVariablesDirty(bool dirty)
25672567
}
25682568
}
25692569

2570-
internal void MarkOwnerReadVariablesDirty()
2570+
/// <summary>
2571+
/// Used when changing ownership, this will mark any owner read permission base NetworkVariables as dirty
2572+
/// and will check if any owner write permission NetworkVariables are dirty (primarily for collections) so
2573+
/// the new owner will get a full state update prior to changing ownership.
2574+
/// </summary>
2575+
/// <remarks>
2576+
/// We have to pass in the original owner and previous owner to "reset" back to the current state of this
2577+
/// NetworkObject in order to preserve the same ownership change flow. By the time this is invoked, the
2578+
/// new and previous owner ids have already been set.
2579+
/// </remarks>
2580+
/// <param name="originalOwnerId">the owner prior to beginning the change in ownership change.</param>
2581+
/// <param name="originalPreviousOwnerId">the previous owner prior to beginning the change in ownership change.</param>
2582+
internal void SynchronizeOwnerNetworkVariables(ulong originalOwnerId, ulong originalPreviousOwnerId)
25712583
{
2584+
var currentOwnerId = OwnerClientId;
2585+
OwnerClientId = originalOwnerId;
2586+
PreviousOwnerId = originalPreviousOwnerId;
25722587
for (int i = 0; i < ChildNetworkBehaviours.Count; i++)
25732588
{
2574-
ChildNetworkBehaviours[i].MarkOwnerReadVariablesDirty();
2589+
ChildNetworkBehaviours[i].MarkOwnerReadDirtyAndCheckOwnerWriteIsDirty();
25752590
}
2591+
2592+
// Now set the new owner and previous owner identifiers back to their original new values
2593+
// before we run the NetworkBehaviourUpdate. For owner read only permissions this order of
2594+
// operations is **particularly important** as we need to first (above) mark things as dirty
2595+
// from the context of the original owner and then second (below) we need to send the messages
2596+
// which requires the new owner to be set for owner read permission NetworkVariables.
2597+
OwnerClientId = currentOwnerId;
2598+
PreviousOwnerId = originalOwnerId;
2599+
2600+
// Force send a state update for all owner read NetworkVariables and any currently dirty
2601+
// owner write NetworkVariables.
2602+
NetworkManager.BehaviourUpdater.NetworkBehaviourUpdate(true);
25762603
}
25772604

25782605
// NGO currently guarantees that the client will receive spawn data for all objects in one network tick.

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -381,11 +381,8 @@ private void HandleOwnershipChange(ref NetworkContext context)
381381

382382
if (originalOwner == networkManager.LocalClientId && !networkManager.DistributedAuthorityMode)
383383
{
384-
// Mark any owner read variables as dirty
385-
networkObject.MarkOwnerReadVariablesDirty();
386-
// Immediately queue any pending deltas and order the message before the
387-
// change in ownership message.
388-
networkManager.BehaviourUpdater.NetworkBehaviourUpdate(true);
384+
// Fully synchronize NetworkVariables with either read or write ownership permissions.
385+
networkObject.SynchronizeOwnerNetworkVariables(originalOwner, networkObject.PreviousOwnerId);
389386
}
390387

391388
// Always invoke ownership change notifications

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ public void Handle(ref NetworkContext context)
7373
/// DANGO-TODO: Determine if this needs to be removed once the service handles object distribution
7474
networkManager.RedistributeToClients = true;
7575
networkManager.ClientsToRedistribute.Add(ClientId);
76+
77+
// TODO: We need a client synchronized message or something like that here
7678
}
7779
}
7880
}

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,13 @@ public void Handle(ref NetworkContext context)
270270
// Only if scene management is disabled do we handle NetworkObject synchronization at this point
271271
if (!networkManager.NetworkConfig.EnableSceneManagement)
272272
{
273+
/// Mark the client being connected before running through the spawning synchronization so we
274+
/// can assure that if a user attempts to spawn something when an already spawned NetworkObject
275+
/// is spawned (during the initial synchronization just below) it will not error out complaining
276+
/// about the player not being connected.
277+
/// The check for this is done within <see cref="NetworkObject.SpawnInternal(bool, ulong, bool)"/>
278+
networkManager.IsConnectedClient = true;
279+
273280
// DANGO-TODO: This is a temporary fix for no DA CMB scene event handling.
274281
// We will either use this same concept or provide some way for the CMB state plugin to handle it.
275282
if (networkManager.DistributedAuthorityMode && networkManager.LocalClient.IsSessionOwner)
@@ -292,9 +299,6 @@ public void Handle(ref NetworkContext context)
292299
NetworkObject.AddSceneObject(sceneObject, m_ReceivedSceneObjectData, networkManager);
293300
}
294301

295-
// Mark the client being connected
296-
networkManager.IsConnectedClient = true;
297-
298302
if (networkManager.AutoSpawnPlayerPrefabClientSide)
299303
{
300304
networkManager.ConnectionManager.CreateAndSpawnPlayer(OwnerClientId);
@@ -315,14 +319,14 @@ public void Handle(ref NetworkContext context)
315319
if (networkManager.DistributedAuthorityMode && networkManager.CMBServiceConnection && networkManager.LocalClient.IsSessionOwner && networkManager.NetworkConfig.EnableSceneManagement)
316320
{
317321
// Mark the client being connected
318-
networkManager.IsConnectedClient = true;
322+
networkManager.IsConnectedClient = networkManager.ConnectionManager.LocalClient.IsApproved;
319323

320324
networkManager.SceneManager.IsRestoringSession = GetIsSessionRestor();
321325

322326
if (!networkManager.SceneManager.IsRestoringSession)
323327
{
324328
// Synchronize the service with the initial session owner's loaded scenes and spawned objects
325-
networkManager.SceneManager.SynchronizeNetworkObjects(NetworkManager.ServerClientId);
329+
networkManager.SceneManager.SynchronizeNetworkObjects(NetworkManager.ServerClientId, true);
326330

327331
// Spawn any in-scene placed NetworkObjects
328332
networkManager.SpawnManager.ServerSpawnSceneObjectsOnStartSweep();
@@ -334,9 +338,9 @@ public void Handle(ref NetworkContext context)
334338
}
335339

336340
// Synchronize the service with the initial session owner's loaded scenes and spawned objects
337-
networkManager.SceneManager.SynchronizeNetworkObjects(NetworkManager.ServerClientId);
341+
networkManager.SceneManager.SynchronizeNetworkObjects(NetworkManager.ServerClientId, true);
338342

339-
// With scene management enabled and since the session owner doesn't send a Synchronize scene event synchronize itself,
343+
// With scene management enabled and since the session owner doesn't send a scene event synchronize to itself,
340344
// we need to notify the session owner that everything should be synchronized/spawned at this time.
341345
networkManager.SpawnManager.NotifyNetworkObjectsSynchronized();
342346

com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariable.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,13 @@ public bool CheckDirtyState(bool forceCheck = false)
166166
return isDirty;
167167
}
168168

169+
/// <inheritdoc/>
170+
internal override void OnCheckIsDirtyState()
171+
{
172+
CheckDirtyState();
173+
base.OnCheckIsDirtyState();
174+
}
175+
169176
internal ref T RefValue()
170177
{
171178
return ref m_InternalValue;

com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariableBase.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,15 @@ internal ulong OwnerClientId()
373373
return m_NetworkBehaviour.NetworkObject.OwnerClientId;
374374
}
375375

376+
/// <summary>
377+
/// Primarily to check for collections dirty states when doing
378+
/// a fully owner read/write NetworkVariable update.
379+
/// </summary>
380+
internal virtual void OnCheckIsDirtyState()
381+
{
382+
383+
}
384+
376385
/// <summary>
377386
/// Writes the dirty changes, that is, the changes since the variable was last dirty, to the writer
378387
/// </summary>

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

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1986,6 +1986,14 @@ private void OnClientLoadedScene(uint sceneEventId, Scene scene)
19861986
/// </summary>
19871987
internal Func<Scene, bool> ExcludeSceneFromSychronization;
19881988

1989+
/// <summary>
1990+
/// This is used for distributed authority sessions only and assures that
1991+
/// when many clients attempt to connect at the same time they will be
1992+
/// handled sequentially so as to not saturate the session owner's maximum
1993+
/// reliable messages.
1994+
/// </summary>
1995+
internal List<ulong> ClientConnectionQueue = new List<ulong>();
1996+
19891997
/// <summary>
19901998
/// Server Side:
19911999
/// This is used for players that have just had their connection approved and will assure they are synchronized
@@ -1994,8 +2002,30 @@ private void OnClientLoadedScene(uint sceneEventId, Scene scene)
19942002
/// synchronized.
19952003
/// </summary>
19962004
/// <param name="clientId">newly joined client identifier</param>
1997-
internal void SynchronizeNetworkObjects(ulong clientId)
2005+
/// <param name="synchronizingService">true only when invoked on a newly connected and approved client.</param>
2006+
internal void SynchronizeNetworkObjects(ulong clientId, bool synchronizingService = false)
19982007
{
2008+
// If we are connected to a live service hosted session and we are not doing the initial synchronization for the service...
2009+
if (NetworkManager.CMBServiceConnection && !synchronizingService)
2010+
{
2011+
// then as long as this is a newly connecting client add it to the connecting client queue.
2012+
// Otherwise, if this is not a newly connecting client (i.e. it is already in the queue), then go ahead and synchronize
2013+
// that client.
2014+
if (!ClientConnectionQueue.Contains(clientId))
2015+
{
2016+
ClientConnectionQueue.Add(clientId);
2017+
// If we are already synchronizing one or more clients, exit early. This client will be synchronized later.
2018+
if (ClientConnectionQueue.Count > 1)
2019+
{
2020+
if (NetworkManager.LogLevel <= LogLevel.Developer)
2021+
{
2022+
Debug.Log($"Deferring Client-{clientId} synchrnization.");
2023+
}
2024+
return;
2025+
}
2026+
}
2027+
}
2028+
19992029
// Update the clients
20002030
NetworkManager.SpawnManager.UpdateObservedNetworkObjects(clientId);
20012031

@@ -2623,6 +2653,44 @@ private void HandleSessionOwnerEvent(uint sceneEventId, ulong clientId)
26232653
// DANGO-EXP TODO: Remove this once service distributes objects
26242654
NetworkManager.SpawnManager.DistributeNetworkObjects(clientId);
26252655
EndSceneEvent(sceneEventId);
2656+
2657+
// Exit early if not a distributed authority session or this is a DAHost
2658+
// (DAHost has a unique connection per client, so no need to queue synchronization)
2659+
if (!NetworkManager.DistributedAuthorityMode || NetworkManager.DAHost)
2660+
{
2661+
return;
2662+
}
2663+
2664+
// Otherwise, this is a session owner that could have pending clients to synchronize
2665+
if (NetworkManager.DistributedAuthorityMode && NetworkManager.CMBServiceConnection)
2666+
{
2667+
// Remove the client that just synchronized
2668+
ClientConnectionQueue.Remove(clientId);
2669+
2670+
// If we have pending clients to synchronize, then make sure they are still connected
2671+
while (ClientConnectionQueue.Count > 0)
2672+
{
2673+
// If the next client is no longer connected then remove it from the list
2674+
if (!NetworkManager.ConnectedClientsIds.Contains(ClientConnectionQueue[0]))
2675+
{
2676+
ClientConnectionQueue.RemoveAt(0);
2677+
}
2678+
else
2679+
{
2680+
break;
2681+
}
2682+
}
2683+
2684+
// If we still have any pending clients waiting, then synchronize the next one
2685+
if (ClientConnectionQueue.Count > 0)
2686+
{
2687+
if (NetworkManager.LogLevel <= LogLevel.Developer)
2688+
{
2689+
Debug.Log($"Synchronizing Client-{ClientConnectionQueue[0]}...");
2690+
}
2691+
SynchronizeNetworkObjects(ClientConnectionQueue[0]);
2692+
}
2693+
}
26262694
break;
26272695
}
26282696
default:

0 commit comments

Comments
 (0)