Skip to content

Commit 86ddd7d

Browse files
chore: object synchronization distributed authority mode when scene management disabled (#3135)
* fix This fixes most of the synchronization issues with using a distributed authority network topology and scene management is disabled. (There still is some form of issue with changing ownership when distributing objects) * update A better way to handle object redistribution and NetworkObject synchronization when scene management is disabled,
1 parent 1845a33 commit 86ddd7d

File tree

7 files changed

+101
-35
lines changed

7 files changed

+101
-35
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,14 @@ internal NetworkClient AddClient(ulong clientId)
10011001
}
10021002

10031003
var distributedAuthority = NetworkManager.DistributedAuthorityMode;
1004+
1005+
// If not using DA return early or if using DA and scene management is disabled then exit early Since we use NetworkShow to spawn
1006+
// objects on the newly connected client side.
1007+
if (!distributedAuthority || distributedAuthority && !NetworkManager.NetworkConfig.EnableSceneManagement)
1008+
{
1009+
return networkClient;
1010+
}
1011+
10041012
var sessionOwnerId = NetworkManager.CurrentSessionOwner;
10051013
var isSessionOwner = NetworkManager.LocalClient.IsSessionOwner;
10061014
foreach (var networkObject in NetworkManager.SpawnManager.SpawnedObjectsList)

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ private void NetworkBehaviourUpdater_Tick()
141141

142142
// Then show any NetworkObjects queued to be made visible/shown
143143
m_NetworkManager.SpawnManager.HandleNetworkObjectShow();
144+
145+
// Handle object redistribution (DA + disabled scene management only)
146+
m_NetworkManager.HandleRedistributionToClients();
144147
}
145148
}
146149
}

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

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,30 @@ public bool DAHost
162162
}
163163
}
164164

165-
// DANGO-TODO-MVP: Remove these properties once the service handles object distribution
166-
internal ulong ClientToRedistribute;
167-
internal bool RedistributeToClient;
168-
internal int TickToRedistribute;
165+
// DANGO-TODO: Determine if this needs to be removed once the service handles object distribution
166+
internal List<ulong> ClientsToRedistribute = new List<ulong>();
167+
internal bool RedistributeToClients;
168+
169+
/// <summary>
170+
/// Handles object redistribution when scene management is disabled.
171+
/// <see cref="NetworkBehaviourUpdater.NetworkBehaviourUpdater_Tick"/>
172+
/// DANGO-TODO: Determine if this needs to be removed once the service handles object distribution
173+
/// </summary>
174+
internal void HandleRedistributionToClients()
175+
{
176+
if (!DistributedAuthorityMode || !RedistributeToClients || NetworkConfig.EnableSceneManagement || ShutdownInProgress)
177+
{
178+
return;
179+
}
180+
181+
foreach (var clientId in ClientsToRedistribute)
182+
{
183+
SpawnManager.DistributeNetworkObjects(clientId);
184+
}
185+
RedistributeToClients = false;
186+
ClientsToRedistribute.Clear();
187+
}
188+
169189

170190
internal List<NetworkObject> DeferredDespawnObjects = new List<NetworkObject>();
171191

@@ -393,16 +413,6 @@ public void NetworkUpdate(NetworkUpdateStage updateStage)
393413
// This is "ok" to invoke when not processing messages since it is just cleaning up messages that never got handled within their timeout period.
394414
DeferredMessageManager.CleanupStaleTriggers();
395415

396-
// DANGO-TODO-MVP: Remove this once the service handles object distribution
397-
// NOTE: This needs to be the last thing done and should happen exactly at this point
398-
// in the update
399-
if (RedistributeToClient && ServerTime.Tick <= TickToRedistribute)
400-
{
401-
RedistributeToClient = false;
402-
SpawnManager.DistributeNetworkObjects(ClientToRedistribute);
403-
ClientToRedistribute = 0;
404-
}
405-
406416
if (m_ShuttingDown)
407417
{
408418
// Host-server will disconnect any connected clients prior to finalizing its shutdown

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2894,7 +2894,7 @@ internal SceneObject GetMessageSceneObject(ulong targetClientId = NetworkManager
28942894
SyncObservers = syncObservers,
28952895
Observers = syncObservers ? Observers.ToArray() : null,
28962896
NetworkSceneHandle = NetworkSceneHandle,
2897-
Hash = HostCheckForGlobalObjectIdHashOverride(),
2897+
Hash = CheckForGlobalObjectIdHashOverride(),
28982898
OwnerObject = this,
28992899
TargetClientId = targetClientId
29002900
};
@@ -3246,14 +3246,14 @@ internal void UpdateForSceneChanges()
32463246
}
32473247

32483248
/// <summary>
3249-
/// Only applies to Host mode.
3249+
/// Only applies to Hosts or session owners (for now)
32503250
/// Will return the registered source NetworkPrefab's GlobalObjectIdHash if one exists.
32513251
/// Server and Clients will always return the NetworkObject's GlobalObjectIdHash.
32523252
/// </summary>
3253-
/// <returns></returns>
3254-
internal uint HostCheckForGlobalObjectIdHashOverride()
3253+
/// <returns>appropriate hash value</returns>
3254+
internal uint CheckForGlobalObjectIdHashOverride()
32553255
{
3256-
if (NetworkManager.IsServer)
3256+
if (NetworkManager.IsServer || (NetworkManager.DistributedAuthorityMode && NetworkManager.LocalClient.IsSessionOwner))
32573257
{
32583258
if (NetworkManager.PrefabHandler.ContainsHandler(this))
32593259
{

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,8 @@ private void HandleOwnershipChange(ref NetworkContext context)
332332
// Sanity check that we are not sending duplicated change ownership messages
333333
if (networkObject.OwnerClientId == OwnerClientId)
334334
{
335-
UnityEngine.Debug.LogError($"Unnecessary ownership changed message for {NetworkObjectId}.");
336-
// Ignore the message
335+
// Log error and then ignore the message
336+
UnityEngine.Debug.LogError($"Client-{context.SenderId} ({RequestClientId}) sent unnecessary ownership changed message for {NetworkObjectId}.");
337337
return;
338338
}
339339

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

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,19 +55,24 @@ public void Handle(ref NetworkContext context)
5555
// Don't redistribute for the local instance
5656
if (ClientId != networkManager.LocalClientId)
5757
{
58+
// Synchronize the client with spawned objects (relative to each client)
59+
networkManager.SpawnManager.SynchronizeObjectsToNewlyJoinedClient(ClientId);
60+
61+
// Keeping for reference in case the above doesn't resolve for hidden objects (theoretically it should)
5862
// Show any NetworkObjects that are:
5963
// - Hidden from the session owner
6064
// - Owned by this client
6165
// - Has NetworkObject.SpawnWithObservers set to true (the default)
62-
if (!networkManager.LocalClient.IsSessionOwner)
63-
{
64-
networkManager.SpawnManager.ShowHiddenObjectsToNewlyJoinedClient(ClientId);
65-
}
66+
//if (!networkManager.LocalClient.IsSessionOwner)
67+
//{
68+
// networkManager.SpawnManager.ShowHiddenObjectsToNewlyJoinedClient(ClientId);
69+
//}
6670

67-
// We defer redistribution to the end of the NetworkUpdateStage.PostLateUpdate
68-
networkManager.RedistributeToClient = true;
69-
networkManager.ClientToRedistribute = ClientId;
70-
networkManager.TickToRedistribute = networkManager.ServerTime.Tick + 20;
71+
/// We defer redistribution to happen after NetworkShow has been invoked
72+
/// <see cref="NetworkBehaviourUpdater.NetworkBehaviourUpdater_Tick"/>
73+
/// DANGO-TODO: Determine if this needs to be removed once the service handles object distribution
74+
networkManager.RedistributeToClients = true;
75+
networkManager.ClientsToRedistribute.Add(ClientId);
7176
}
7277
}
7378
}

com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,6 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId, bool
580580
{
581581
networkObject.ChildNetworkBehaviours[i].UpdateNetworkProperties();
582582
}
583-
584583
size = NetworkManager.ConnectionManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, NetworkManager.ServerClientId);
585584
NetworkManager.NetworkMetrics.TrackOwnershipChangeSent(NetworkManager.LocalClientId, networkObject, size);
586585
}
@@ -1982,14 +1981,14 @@ internal void NotifyNetworkObjectsSynchronized()
19821981
/// synchronizing in order to "show" (spawn) anything that might be currently hidden from
19831982
/// the session owner.
19841983
/// </summary>
1984+
/// <remarks>
1985+
/// Replacement is: SynchronizeObjectsToNewlyJoinedClient
1986+
/// </remarks>
19851987
internal void ShowHiddenObjectsToNewlyJoinedClient(ulong newClientId)
19861988
{
1987-
if (!NetworkManager.DistributedAuthorityMode)
1989+
if (NetworkManager == null || NetworkManager.ShutdownInProgress && NetworkManager.LogLevel <= LogLevel.Developer)
19881990
{
1989-
if (NetworkManager == null || !NetworkManager.ShutdownInProgress && NetworkManager.LogLevel <= LogLevel.Developer)
1990-
{
1991-
Debug.LogWarning($"[Internal Error] {nameof(ShowHiddenObjectsToNewlyJoinedClient)} invoked while !");
1992-
}
1991+
Debug.LogWarning($"[Internal Error] {nameof(ShowHiddenObjectsToNewlyJoinedClient)} invoked while shutdown is in progress!");
19931992
return;
19941993
}
19951994

@@ -2025,5 +2024,46 @@ internal void ShowHiddenObjectsToNewlyJoinedClient(ulong newClientId)
20252024
}
20262025
}
20272026
}
2027+
2028+
internal void SynchronizeObjectsToNewlyJoinedClient(ulong newClientId)
2029+
{
2030+
if (NetworkManager == null || NetworkManager.ShutdownInProgress && NetworkManager.LogLevel <= LogLevel.Developer)
2031+
{
2032+
Debug.LogWarning($"[Internal Error] {nameof(SynchronizeObjectsToNewlyJoinedClient)} invoked while shutdown is in progress!");
2033+
return;
2034+
}
2035+
2036+
if (!NetworkManager.DistributedAuthorityMode)
2037+
{
2038+
Debug.LogError($"[Internal Error] {nameof(SynchronizeObjectsToNewlyJoinedClient)} should only be invoked when using a distributed authority network topology!");
2039+
return;
2040+
}
2041+
2042+
if (NetworkManager.NetworkConfig.EnableSceneManagement)
2043+
{
2044+
Debug.LogError($"[Internal Error] {nameof(SynchronizeObjectsToNewlyJoinedClient)} should only be invoked when scene management is disabled!");
2045+
return;
2046+
}
2047+
2048+
var localClientId = NetworkManager.LocalClient.ClientId;
2049+
foreach (var networkObject in SpawnedObjectsList)
2050+
{
2051+
if (networkObject.SpawnWithObservers && networkObject.OwnerClientId == localClientId)
2052+
{
2053+
if (networkObject.Observers.Contains(newClientId))
2054+
{
2055+
if (NetworkManager.LogLevel <= LogLevel.Developer)
2056+
{
2057+
// Temporary tracking to make sure we are not showing something already visibile (should never be the case for this)
2058+
Debug.LogWarning($"[{nameof(SynchronizeObjectsToNewlyJoinedClient)}][{networkObject.name}] New client as already an observer!");
2059+
}
2060+
// For now, remove the client (impossible for the new client to have an instance since the session owner doesn't) to make sure newly added
2061+
// code to handle this edge case works.
2062+
networkObject.Observers.Remove(newClientId);
2063+
}
2064+
networkObject.NetworkShow(newClientId);
2065+
}
2066+
}
2067+
}
20282068
}
20292069
}

0 commit comments

Comments
 (0)