From c577a013e5003158ea72af3d8ef93a18ac0f6ca7 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Fri, 14 Mar 2025 19:45:48 -0500 Subject: [PATCH 1/9] update fixing the issue when scene management is disabled a client cannot spawn objects during the synchronization process. --- .../Messages/ConnectionApprovedMessage.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs index 4f9e0f5453..c5580ae339 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs @@ -270,6 +270,13 @@ public void Handle(ref NetworkContext context) // Only if scene management is disabled do we handle NetworkObject synchronization at this point if (!networkManager.NetworkConfig.EnableSceneManagement) { + /// Mark the client being connected before running through the spawning synchronization so we + /// can assure that if a user attempts to spawn something when an already spawned NetworkObject + /// is spawned (during the initial synchronization just below) it will not error out complaining + /// about the player not being connected. + /// The check for this is done within + networkManager.IsConnectedClient = true; + // DANGO-TODO: This is a temporary fix for no DA CMB scene event handling. // We will either use this same concept or provide some way for the CMB state plugin to handle it. if (networkManager.DistributedAuthorityMode && networkManager.LocalClient.IsSessionOwner) @@ -292,9 +299,6 @@ public void Handle(ref NetworkContext context) NetworkObject.AddSceneObject(sceneObject, m_ReceivedSceneObjectData, networkManager); } - // Mark the client being connected - networkManager.IsConnectedClient = true; - if (networkManager.AutoSpawnPlayerPrefabClientSide) { networkManager.ConnectionManager.CreateAndSpawnPlayer(OwnerClientId); @@ -315,14 +319,14 @@ public void Handle(ref NetworkContext context) if (networkManager.DistributedAuthorityMode && networkManager.CMBServiceConnection && networkManager.LocalClient.IsSessionOwner && networkManager.NetworkConfig.EnableSceneManagement) { // Mark the client being connected - networkManager.IsConnectedClient = true; + networkManager.IsConnectedClient = networkManager.ConnectionManager.LocalClient.IsApproved; networkManager.SceneManager.IsRestoringSession = GetIsSessionRestor(); if (!networkManager.SceneManager.IsRestoringSession) { // Synchronize the service with the initial session owner's loaded scenes and spawned objects - networkManager.SceneManager.SynchronizeNetworkObjects(NetworkManager.ServerClientId); + networkManager.SceneManager.SynchronizeNetworkObjects(NetworkManager.ServerClientId, true); // Spawn any in-scene placed NetworkObjects networkManager.SpawnManager.ServerSpawnSceneObjectsOnStartSweep(); @@ -334,7 +338,7 @@ public void Handle(ref NetworkContext context) } // Synchronize the service with the initial session owner's loaded scenes and spawned objects - networkManager.SceneManager.SynchronizeNetworkObjects(NetworkManager.ServerClientId); + networkManager.SceneManager.SynchronizeNetworkObjects(NetworkManager.ServerClientId, true); // With scene management enabled and since the session owner doesn't send a Synchronize scene event synchronize itself, // we need to notify the session owner that everything should be synchronized/spawned at this time. From 443a93cd8b61234bd8e0fc6d1520ff4bd556afdf Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Fri, 14 Mar 2025 19:47:13 -0500 Subject: [PATCH 2/9] fix - wip First pass POC of deferring synchronization when more than one client is wanting to be synchronized in a very small period of time. --- .../Messages/ClientConnectedMessage.cs | 2 ++ .../SceneManagement/NetworkSceneManager.cs | 24 ++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ClientConnectedMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ClientConnectedMessage.cs index 0234bc8b67..2d01389cd0 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ClientConnectedMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ClientConnectedMessage.cs @@ -73,6 +73,8 @@ public void Handle(ref NetworkContext context) /// DANGO-TODO: Determine if this needs to be removed once the service handles object distribution networkManager.RedistributeToClients = true; networkManager.ClientsToRedistribute.Add(ClientId); + + // TODO: We need a client synchronized message or something like that here } } } diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs index 1d87687e6d..f5fa8da1b9 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs @@ -1986,6 +1986,8 @@ private void OnClientLoadedScene(uint sceneEventId, Scene scene) /// internal Func ExcludeSceneFromSychronization; + internal List ClientConnectionQueue = new List(); + /// /// Server Side: /// This is used for players that have just had their connection approved and will assure they are synchronized @@ -1994,8 +1996,21 @@ private void OnClientLoadedScene(uint sceneEventId, Scene scene) /// synchronized. /// /// newly joined client identifier - internal void SynchronizeNetworkObjects(ulong clientId) + internal void SynchronizeNetworkObjects(ulong clientId, bool synchronizingService = false) { + // If this is a newly connecting client, add it to the connecting client queue + if (!synchronizingService && !ClientConnectionQueue.Contains(clientId)) + { + ClientConnectionQueue.Add(clientId); + // If we are already synchronizing a client, then add this client to the queue and exit. + if (ClientConnectionQueue.Count > 1) + { + Debug.Log($"Deferring Client-{clientId} synchrnization."); + return; + } + } + + // Update the clients NetworkManager.SpawnManager.UpdateObservedNetworkObjects(clientId); @@ -2623,6 +2638,13 @@ private void HandleSessionOwnerEvent(uint sceneEventId, ulong clientId) // DANGO-EXP TODO: Remove this once service distributes objects NetworkManager.SpawnManager.DistributeNetworkObjects(clientId); EndSceneEvent(sceneEventId); + ClientConnectionQueue.Remove(clientId); + Debug.Log($"Client-{clientId} synchronized."); + if (ClientConnectionQueue.Count > 0) + { + Debug.Log($"Synchronizing Client-{ClientConnectionQueue[0]}..."); + SynchronizeNetworkObjects(ClientConnectionQueue[0]); + } break; } default: From 8b2970006df4e1c65f668d15eeb4e347c321dda5 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Sun, 16 Mar 2025 17:10:48 -0500 Subject: [PATCH 3/9] fix Updating the fix with some additional checks to make sure the next client is still connected before attempting to synchronize. --- .../SceneManagement/NetworkSceneManager.cs | 65 +++++++++++++++---- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs index f5fa8da1b9..42926f4014 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs @@ -1998,18 +1998,26 @@ private void OnClientLoadedScene(uint sceneEventId, Scene scene) /// newly joined client identifier internal void SynchronizeNetworkObjects(ulong clientId, bool synchronizingService = false) { - // If this is a newly connecting client, add it to the connecting client queue - if (!synchronizingService && !ClientConnectionQueue.Contains(clientId)) + // If we are connected to a live service hosted session and we are not doing the initial synchronization for the service... + if (NetworkManager.CMBServiceConnection && !synchronizingService) { - ClientConnectionQueue.Add(clientId); - // If we are already synchronizing a client, then add this client to the queue and exit. - if (ClientConnectionQueue.Count > 1) + // then as long as this is a newly connecting client add it to the connecting client queue. + // Otherwise, if this is not a newly connecting client (i.e. it is already in the queue), then go ahead and synchronize + // that client. + if (!ClientConnectionQueue.Contains(clientId)) { - Debug.Log($"Deferring Client-{clientId} synchrnization."); - return; + ClientConnectionQueue.Add(clientId); + // If we are already synchronizing one or more clients, then add this client to the queue and exit. + if (ClientConnectionQueue.Count > 1) + { + if (NetworkManager.LogLevel <= LogLevel.Developer) + { + Debug.Log($"Deferring Client-{clientId} synchrnization."); + } + return; + } } } - // Update the clients NetworkManager.SpawnManager.UpdateObservedNetworkObjects(clientId); @@ -2638,12 +2646,43 @@ private void HandleSessionOwnerEvent(uint sceneEventId, ulong clientId) // DANGO-EXP TODO: Remove this once service distributes objects NetworkManager.SpawnManager.DistributeNetworkObjects(clientId); EndSceneEvent(sceneEventId); - ClientConnectionQueue.Remove(clientId); - Debug.Log($"Client-{clientId} synchronized."); - if (ClientConnectionQueue.Count > 0) + + // Exit early if not a distributed authority session or this is a DAHost + // (DAHost has a unique connection per client, so no need to queue synchronization) + if (!NetworkManager.DistributedAuthorityMode || NetworkManager.DAHost) { - Debug.Log($"Synchronizing Client-{ClientConnectionQueue[0]}..."); - SynchronizeNetworkObjects(ClientConnectionQueue[0]); + return; + } + + // Otherwise, this is a session owner that could have pending clients to synchronize + if (NetworkManager.DistributedAuthorityMode && NetworkManager.CMBServiceConnection) + { + // Remove the client that just synchronized + ClientConnectionQueue.Remove(clientId); + + // If we have pending clients to synchronize, then make sure they are still connected + while (ClientConnectionQueue.Count > 0) + { + // If the next client is no longer connected then remove it from the list + if (!NetworkManager.ConnectedClientsIds.Contains(ClientConnectionQueue[0])) + { + ClientConnectionQueue.RemoveAt(0); + } + else + { + break; + } + } + + // If we still have any pending clients waiting, then synchronize the next one + if (ClientConnectionQueue.Count > 0) + { + if (NetworkManager.LogLevel <= LogLevel.Developer) + { + Debug.Log($"Synchronizing Client-{ClientConnectionQueue[0]}..."); + } + SynchronizeNetworkObjects(ClientConnectionQueue[0]); + } } break; } From 82c3057779e954b705e03a82d2451852caacc71c Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Sun, 16 Mar 2025 19:51:19 -0500 Subject: [PATCH 4/9] fix When building the NetworkObject distribution table, don't add a NetworkObject to the table if the target client is not an observer. --- .../Runtime/Spawning/NetworkSpawnManager.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs index 7b390547a4..0c8b8d74bd 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs @@ -1815,7 +1815,7 @@ internal void Shutdown() /// /// the table to populate /// the total number of the specific object type to distribute - internal void GetObjectDistribution(ref Dictionary>> objectByTypeAndOwner, ref Dictionary objectTypeCount) + internal void GetObjectDistribution(ulong clientId, ref Dictionary>> objectByTypeAndOwner, ref Dictionary objectTypeCount) { // DANGO-TODO-MVP: Remove this once the service handles object distribution var onlyIncludeOwnedObjects = NetworkManager.CMBServiceConnection; @@ -1844,6 +1844,11 @@ internal void GetObjectDistribution(ref Dictionary(); // Get all spawned objects by type and then by client owner that are spawned and can be distributed - GetObjectDistribution(ref distributedNetworkObjects, ref objectTypeCount); + GetObjectDistribution(clientId, ref distributedNetworkObjects, ref objectTypeCount); var clientCount = NetworkManager.ConnectedClientsIds.Count; @@ -1951,7 +1956,6 @@ internal void DistributeNetworkObjects(ulong clientId) var maxDistributeCount = Mathf.Max(ownerList.Value.Count - objPerClient, 1); var distributed = 0; - // For now when we have more players then distributed NetworkObjects that // a specific client owns, just assign half of the NetworkObjects to the new client var offsetCount = Mathf.Max((int)Math.Round((float)(ownerList.Value.Count / objPerClient)), 1); @@ -1964,11 +1968,6 @@ internal void DistributeNetworkObjects(ulong clientId) { if ((i % offsetCount) == 0) { - while (!ownerList.Value[i].Observers.Contains(clientId)) - { - i++; - } - var children = ownerList.Value[i].GetComponentsInChildren(); // Since the ownerList.Value[i] has to be distributable, then transfer all child NetworkObjects // with the same owner clientId and are marked as distributable also to the same client to keep @@ -2011,7 +2010,7 @@ internal void DistributeNetworkObjects(ulong clientId) var builder = new StringBuilder(); distributedNetworkObjects.Clear(); objectTypeCount.Clear(); - GetObjectDistribution(ref distributedNetworkObjects, ref objectTypeCount); + GetObjectDistribution(clientId, ref distributedNetworkObjects, ref objectTypeCount); builder.AppendLine($"Client Relative Distributed Object Count: (distribution follows)"); // Cycle through each prefab type foreach (var objectTypeEntry in distributedNetworkObjects) @@ -2026,7 +2025,6 @@ internal void DistributeNetworkObjects(ulong clientId) } Debug.Log(builder.ToString()); } - } internal struct DeferredDespawnObject From f6f6658c844334328c62a3fb7efa270f0b16f22b Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Sun, 16 Mar 2025 19:51:40 -0500 Subject: [PATCH 5/9] style Fixing the gammar of a comment --- .../Runtime/Messaging/Messages/ConnectionApprovedMessage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs index c5580ae339..cb1de9356f 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs @@ -340,7 +340,7 @@ public void Handle(ref NetworkContext context) // Synchronize the service with the initial session owner's loaded scenes and spawned objects networkManager.SceneManager.SynchronizeNetworkObjects(NetworkManager.ServerClientId, true); - // With scene management enabled and since the session owner doesn't send a Synchronize scene event synchronize itself, + // With scene management enabled and since the session owner doesn't send a scene event synchronize to itself, // we need to notify the session owner that everything should be synchronized/spawned at this time. networkManager.SpawnManager.NotifyNetworkObjectsSynchronized(); From 45a3715d0832b01d9daf4d6ec4c6569f7bce317f Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Sun, 16 Mar 2025 19:53:03 -0500 Subject: [PATCH 6/9] test Adding a test to validate spawning a NetworkObject during OnNetworkSpawn, OnNetworkPostSpawn, and OnNetworkSessionSynchronized when using a distributed authority network topology. --- .../SpawnDuringSynchronizationTests.cs | 147 ++++++++++++++++++ .../SpawnDuringSynchronizationTests.cs.meta | 2 + 2 files changed, 149 insertions(+) create mode 100644 com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SpawnDuringSynchronizationTests.cs create mode 100644 com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SpawnDuringSynchronizationTests.cs.meta diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SpawnDuringSynchronizationTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SpawnDuringSynchronizationTests.cs new file mode 100644 index 0000000000..6c91112259 --- /dev/null +++ b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SpawnDuringSynchronizationTests.cs @@ -0,0 +1,147 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; +using NUnit.Framework; +using Unity.Netcode.TestHelpers.Runtime; +using UnityEngine; +using UnityEngine.TestTools; + +namespace Unity.Netcode.RuntimeTests +{ + [TestFixture(NetworkBehaviourSpawnTimes.OnNetworkSpawn, SceneManagement.Enabled)] + [TestFixture(NetworkBehaviourSpawnTimes.OnNetworkPostSpawn, SceneManagement.Enabled)] + [TestFixture(NetworkBehaviourSpawnTimes.OnSynchronized, SceneManagement.Enabled)] + [TestFixture(NetworkBehaviourSpawnTimes.OnNetworkSpawn, SceneManagement.Disabled)] + [TestFixture(NetworkBehaviourSpawnTimes.OnNetworkPostSpawn, SceneManagement.Disabled)] + [TestFixture(NetworkBehaviourSpawnTimes.OnSynchronized, SceneManagement.Disabled)] + internal class SpawnDuringSynchronizationTests : NetcodeIntegrationTest + { + protected override int NumberOfClients => 2; + + private List m_AllNetworkManagers = new List(); + private StringBuilder m_ErrorLog = new StringBuilder(); + + private NetworkBehaviourSpawnTimes m_SpawnTime; + private bool m_EnableSceneManagement; + internal enum NetworkBehaviourSpawnTimes + { + OnNetworkSpawn, + OnNetworkPostSpawn, + OnSynchronized + } + + internal enum SceneManagement + { + Enabled, + Disabled, + } + + internal class SpawnTestComponent : NetworkBehaviour + { + public GameObject PrefabToSpawn; + public NetworkObject SpawnedObject { get; private set; } + public NetworkBehaviourSpawnTimes SpawnTime; + + private void SpawnObject(NetworkBehaviourSpawnTimes spawnTime) + { + if (IsOwner && SpawnTime == spawnTime) + { + SpawnedObject = NetworkObject.InstantiateAndSpawn(PrefabToSpawn, NetworkManager, OwnerClientId); + } + } + + public override void OnNetworkSpawn() + { + SpawnObject(NetworkBehaviourSpawnTimes.OnNetworkSpawn); + base.OnNetworkSpawn(); + } + + protected override void OnNetworkPostSpawn() + { + SpawnObject(NetworkBehaviourSpawnTimes.OnNetworkPostSpawn); + base.OnNetworkPostSpawn(); + } + + protected override void OnNetworkSessionSynchronized() + { + SpawnObject(NetworkBehaviourSpawnTimes.OnSynchronized); + base.OnNetworkSessionSynchronized(); + } + } + + + public SpawnDuringSynchronizationTests(NetworkBehaviourSpawnTimes spawnTime, SceneManagement sceneManagement) : base(NetworkTopologyTypes.DistributedAuthority, HostOrServer.DAHost) + { + m_SpawnTime = spawnTime; + m_EnableSceneManagement = sceneManagement == SceneManagement.Enabled; + } + + protected override void OnCreatePlayerPrefab() + { + var spawnTestComponent = m_PlayerPrefab.AddComponent(); + spawnTestComponent.SpawnTime = m_SpawnTime; + spawnTestComponent.NetworkObject.SetOwnershipStatus(NetworkObject.OwnershipStatus.None); + base.OnCreatePlayerPrefab(); + } + + protected override void OnServerAndClientsCreated() + { + var spawnTestComponent = m_PlayerPrefab.GetComponent(); + spawnTestComponent.PrefabToSpawn = CreateNetworkObjectPrefab("ObjToSpawn"); + spawnTestComponent.PrefabToSpawn.GetComponent().SetOwnershipStatus(NetworkObject.OwnershipStatus.Transferable); + if (!UseCMBService()) + { + m_ServerNetworkManager.NetworkConfig.EnableSceneManagement = m_EnableSceneManagement; + } + foreach (var networkManager in m_ClientNetworkManagers) + { + networkManager.NetworkConfig.EnableSceneManagement = m_EnableSceneManagement; + } + base.OnServerAndClientsCreated(); + } + + private bool AllClientsSpawnedObject() + { + m_ErrorLog.Clear(); + var spawnTestComponent = (SpawnTestComponent)null; + foreach (var networkManager in m_AllNetworkManagers) + { + spawnTestComponent = networkManager.LocalClient.PlayerObject.GetComponent(); + if (spawnTestComponent.SpawnedObject == null || !spawnTestComponent.SpawnedObject.IsSpawned) + { + m_ErrorLog.AppendLine($"{networkManager.name}'s player failed to spawn the network prefab!"); + break; + } + foreach (var networkManagerToCheck in m_AllNetworkManagers) + { + if (networkManagerToCheck == networkManager) + { + continue; + } + if (!networkManagerToCheck.SpawnManager.SpawnedObjects.ContainsKey(spawnTestComponent.NetworkObjectId)) + { + m_ErrorLog.AppendLine($"{networkManager.name}'s player failed to spawn the network prefab!"); + } + } + } + return m_ErrorLog.Length == 0; + } + + /// + /// Validates that a client can spawn network prefabs during OnNetworkSpawn, OnNetworkPostSpawn, and OnNetworkSessionSynchronized. + /// + [UnityTest] + public IEnumerator SpawnDuringSynchronization() + { + m_AllNetworkManagers.Clear(); + m_AllNetworkManagers.AddRange(m_ClientNetworkManagers); + if (!UseCMBService()) + { + m_AllNetworkManagers.Add(m_ServerNetworkManager); + } + + yield return WaitForConditionOrTimeOut(AllClientsSpawnedObject); + AssertOnTimeout(m_ErrorLog.ToString()); + } + } +} diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SpawnDuringSynchronizationTests.cs.meta b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SpawnDuringSynchronizationTests.cs.meta new file mode 100644 index 0000000000..415940bde8 --- /dev/null +++ b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SpawnDuringSynchronizationTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3535334da619ee944a73ca56e2e76d22 \ No newline at end of file From bf01a43f090c01f8d01cdfa21cc3c61b7d9f36a3 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Sun, 16 Mar 2025 20:05:52 -0500 Subject: [PATCH 7/9] update Adding change log entries. --- com.unity.netcode.gameobjects/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 1bffdbce19..18ea7b717e 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -18,6 +18,8 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Fixed +- 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) +- 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) - Fixed issue where the `MaximumInterpolationTime` could not be modified from within the inspector view or runtime. (#3337) - Fixed `ChangeOwnership` changing ownership to clients that are not observers. This also happened with automated object distribution. (#3323) - Fixed issue where `AnticipatedNetworkVariable` previous value returned by `AnticipatedNetworkVariable.OnAuthoritativeValueChanged` is updated correctly on the non-authoritative side. (#3306) From cb7bd9a672025586b1fc5adf3b665f3b19955482 Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Thu, 20 Mar 2025 21:39:22 -0500 Subject: [PATCH 8/9] Update com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs Co-authored-by: Emma --- .../Runtime/SceneManagement/NetworkSceneManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs index 42926f4014..8c2cb2c1ba 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs @@ -2007,7 +2007,7 @@ internal void SynchronizeNetworkObjects(ulong clientId, bool synchronizingServic if (!ClientConnectionQueue.Contains(clientId)) { ClientConnectionQueue.Add(clientId); - // If we are already synchronizing one or more clients, then add this client to the queue and exit. + // If we are already synchronizing one or more clients, exit early. This client will be synchronized later. if (ClientConnectionQueue.Count > 1) { if (NetworkManager.LogLevel <= LogLevel.Developer) From 23c494dc3187be5f75b679ca9dc2cbaf1274300e Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Mon, 24 Mar 2025 18:33:56 -0500 Subject: [PATCH 9/9] style Update some comments. --- .../Runtime/SceneManagement/NetworkSceneManager.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs index 8c2cb2c1ba..331d5ff112 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs @@ -1986,6 +1986,12 @@ private void OnClientLoadedScene(uint sceneEventId, Scene scene) /// internal Func ExcludeSceneFromSychronization; + /// + /// This is used for distributed authority sessions only and assures that + /// when many clients attempt to connect at the same time they will be + /// handled sequentially so as to not saturate the session owner's maximum + /// reliable messages. + /// internal List ClientConnectionQueue = new List(); /// @@ -1996,6 +2002,7 @@ private void OnClientLoadedScene(uint sceneEventId, Scene scene) /// synchronized. /// /// newly joined client identifier + /// true only when invoked on a newly connected and approved client. internal void SynchronizeNetworkObjects(ulong clientId, bool synchronizingService = false) { // If we are connected to a live service hosted session and we are not doing the initial synchronization for the service...