From c5b4512e63500b3d83e9b9558a5082b25c83fb72 Mon Sep 17 00:00:00 2001 From: Kitty Draper Date: Tue, 30 Jun 2026 15:16:25 -0500 Subject: [PATCH 1/2] Fix broken hybrid spawn tests --- .../Runtime/Core/NetworkObject.cs | 14 +++++++------- .../Runtime/Spawning/NetworkSpawnManager.cs | 8 ++++++++ .../Runtime/TestHelpers/NetcodeIntegrationTest.cs | 8 ++++++++ .../Support/NetworkObjectSpawnerForTests.cs | 11 +++++++++++ .../Tests/Runtime/TestProject.Runtime.Tests.asmdef | 3 ++- 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index e9c4fe4693..f15eec1583 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -3736,7 +3736,13 @@ private void Start() private void InitGhost() { - if (!NetworkManager.IsListening) + if (!HasGhost || !NetworkObjectBridge || GhostAdapter.IsPrefab()) + { + // Nothing to register + return; + } + + if (!NetworkManager || !NetworkManager.IsListening) { if (NetworkManager.LogLevel == LogLevel.Developer) { @@ -3745,12 +3751,6 @@ private void InitGhost() return; } - if (!HasGhost || !NetworkObjectBridge || GhostAdapter.IsPrefab()) - { - // Nothing to register - return; - } - // All instances with Ghosts are automatically registered if (NetworkManager.LogLevel == LogLevel.Developer) { diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs index b04d512a98..724e045f78 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs @@ -939,6 +939,14 @@ internal NetworkObject GetNetworkObjectToSpawn(uint globalObjectIdHash, ulong ow /// the instance of the internal NetworkObject InstantiateNetworkPrefab([NotNull] GameObject networkPrefab, uint prefabGlobalObjectIdHash, Vector3? position, Quaternion? rotation) { +#if UNIFIED_NETCODE + // TODO-FixMe: NetCode.Netcode.Instance is a singleton and might cause issues + // assigning this. + if (networkPrefab.GetComponent().HasGhost) + { + NetCode.Netcode.Instance.m_ActiveWorld = NetworkManager.NetcodeWorld; + } +#endif var gameObject = Object.Instantiate(networkPrefab); var networkObject = gameObject.GetComponent(); if (networkObject == null) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs index 82abbe2fd2..7153c5849a 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs @@ -2513,6 +2513,14 @@ protected void SpawnObjectInstance(NetworkObject networkObjectToSpawn, NetworkMa /// GameObject instance spawned private GameObject SpawnObject(NetworkObject prefabNetworkObject, NetworkManager owner, bool destroyWithScene = false, bool isPlayerObject = false) { +#if UNIFIED_NETCODE + // TODO-FixMe: NetCode.Netcode.Instance is a singleton and might cause issues + // assigning this. + if (prefabNetworkObject.HasGhost) + { + NetCode.Netcode.Instance.m_ActiveWorld = owner.NetcodeWorld; + } +#endif Assert.IsTrue(prefabNetworkObject.GlobalObjectIdHash > 0, $"{nameof(GameObject)} {prefabNetworkObject.name} has a {nameof(NetworkObject.GlobalObjectIdHash)} value of 0! Make sure to make it a valid prefab before trying to spawn!"); var newInstance = Object.Instantiate(prefabNetworkObject.gameObject); var networkObjectToSpawn = newInstance.GetComponent(); diff --git a/testproject/Assets/Tests/Runtime/Support/NetworkObjectSpawnerForTests.cs b/testproject/Assets/Tests/Runtime/Support/NetworkObjectSpawnerForTests.cs index f4102366fc..696304e67e 100644 --- a/testproject/Assets/Tests/Runtime/Support/NetworkObjectSpawnerForTests.cs +++ b/testproject/Assets/Tests/Runtime/Support/NetworkObjectSpawnerForTests.cs @@ -1,6 +1,9 @@ using System.Collections.Generic; using Unity.Netcode; using UnityEngine; +#if UNIFIED_NETCODE +using Unity.NetCode; +#endif namespace TestProject.RuntimeTests { @@ -75,6 +78,14 @@ private void SpawnRpc(RpcParams rpcParams = default) private void Spawn(ulong ownerId) { +#if UNIFIED_NETCODE + // TODO-FixMe: NetCode.Netcode.Instance is a singleton and might cause issues + // assigning this. + if (ObjectToSpawn.GetComponent().HasGhost) + { + Netcode.Instance.m_ActiveWorld = NetworkManager.NetcodeWorld; + } +#endif var instance = Instantiate(ObjectToSpawn); var networkObject = instance.GetComponent(); networkObject.SpawnWithOwnership(ownerId); diff --git a/testproject/Assets/Tests/Runtime/TestProject.Runtime.Tests.asmdef b/testproject/Assets/Tests/Runtime/TestProject.Runtime.Tests.asmdef index 51b61982a5..074cca9b5a 100644 --- a/testproject/Assets/Tests/Runtime/TestProject.Runtime.Tests.asmdef +++ b/testproject/Assets/Tests/Runtime/TestProject.Runtime.Tests.asmdef @@ -15,7 +15,8 @@ "Unity.Mathematics", "UnityEngine.TestRunner", "UnityEditor.TestRunner", - "Unity.Netcode.Runtime.Tests" + "Unity.Netcode.Runtime.Tests", + "Unity.NetCode" ], "includePlatforms": [], "excludePlatforms": [], From 10220e4706077a7311c182f3c41c987683c032fc Mon Sep 17 00:00:00 2001 From: Kitty Draper Date: Thu, 2 Jul 2026 13:14:29 -0500 Subject: [PATCH 2/2] - Ensure NetworkManager.Singleton is always the server when there are multiple NetworkManagers - Ensure UnifiedBootstrap doesn't get replaced when setting up a new NetworkManager, as that clears out the list of network worlds. --- .../Runtime/Core/NetworkManager.cs | 14 ++++++++++++-- .../Runtime/Spawning/NetworkSpawnManager.cs | 8 -------- .../TestHelpers/NetcodeIntegrationTest.cs | 16 ---------------- .../Support/NetworkObjectSpawnerForTests.cs | 8 -------- 4 files changed, 12 insertions(+), 34 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs index 1b702e76fc..192882f6a5 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs @@ -1092,7 +1092,10 @@ internal static void ResetSingleton() /// public void SetSingleton() { - Singleton = this; + if (!Singleton || !Singleton.IsServer) + { + Singleton = this; + } OnSingletonReady?.Invoke(); } @@ -1401,7 +1404,14 @@ internal void InitializeNetcodeWorld() /// !! Initialize worlds here !! /// Worlds are created here: UnifiedBootstrap.CurrentNetworkManagerForInitialization = this; - DefaultWorldInitialization.Initialize("Default World", false); + if (UnifiedBootstrap.Instance != null) + { + UnifiedBootstrap.Instance.Initialize("Default World"); + } + else + { + DefaultWorldInitialization.Initialize("Default World", false); + } } /// diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs index 724e045f78..b04d512a98 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs @@ -939,14 +939,6 @@ internal NetworkObject GetNetworkObjectToSpawn(uint globalObjectIdHash, ulong ow /// the instance of the internal NetworkObject InstantiateNetworkPrefab([NotNull] GameObject networkPrefab, uint prefabGlobalObjectIdHash, Vector3? position, Quaternion? rotation) { -#if UNIFIED_NETCODE - // TODO-FixMe: NetCode.Netcode.Instance is a singleton and might cause issues - // assigning this. - if (networkPrefab.GetComponent().HasGhost) - { - NetCode.Netcode.Instance.m_ActiveWorld = NetworkManager.NetcodeWorld; - } -#endif var gameObject = Object.Instantiate(networkPrefab); var networkObject = gameObject.GetComponent(); if (networkObject == null) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs index 7153c5849a..2c79ccab29 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs @@ -2449,14 +2449,6 @@ internal void SpawnInstanceWithOwnership(NetworkObject networkObjectToSpawn, Net } else { -#if UNIFIED_NETCODE - // TODO-FixMe: NetCode.Netcode.Instance is a singleton and might cause issues - // assigning this. - if (networkObjectToSpawn.HasGhost) - { - NetCode.Netcode.Instance.m_ActiveWorld = m_ServerNetworkManager.NetcodeWorld; - } -#endif networkObjectToSpawn.NetworkManagerOwner = m_ServerNetworkManager; // Required to assure the server does the spawning if (spawnAuthority == m_ServerNetworkManager) { @@ -2513,14 +2505,6 @@ protected void SpawnObjectInstance(NetworkObject networkObjectToSpawn, NetworkMa /// GameObject instance spawned private GameObject SpawnObject(NetworkObject prefabNetworkObject, NetworkManager owner, bool destroyWithScene = false, bool isPlayerObject = false) { -#if UNIFIED_NETCODE - // TODO-FixMe: NetCode.Netcode.Instance is a singleton and might cause issues - // assigning this. - if (prefabNetworkObject.HasGhost) - { - NetCode.Netcode.Instance.m_ActiveWorld = owner.NetcodeWorld; - } -#endif Assert.IsTrue(prefabNetworkObject.GlobalObjectIdHash > 0, $"{nameof(GameObject)} {prefabNetworkObject.name} has a {nameof(NetworkObject.GlobalObjectIdHash)} value of 0! Make sure to make it a valid prefab before trying to spawn!"); var newInstance = Object.Instantiate(prefabNetworkObject.gameObject); var networkObjectToSpawn = newInstance.GetComponent(); diff --git a/testproject/Assets/Tests/Runtime/Support/NetworkObjectSpawnerForTests.cs b/testproject/Assets/Tests/Runtime/Support/NetworkObjectSpawnerForTests.cs index 696304e67e..078d8ad107 100644 --- a/testproject/Assets/Tests/Runtime/Support/NetworkObjectSpawnerForTests.cs +++ b/testproject/Assets/Tests/Runtime/Support/NetworkObjectSpawnerForTests.cs @@ -78,14 +78,6 @@ private void SpawnRpc(RpcParams rpcParams = default) private void Spawn(ulong ownerId) { -#if UNIFIED_NETCODE - // TODO-FixMe: NetCode.Netcode.Instance is a singleton and might cause issues - // assigning this. - if (ObjectToSpawn.GetComponent().HasGhost) - { - Netcode.Instance.m_ActiveWorld = NetworkManager.NetcodeWorld; - } -#endif var instance = Instantiate(ObjectToSpawn); var networkObject = instance.GetComponent(); networkObject.SpawnWithOwnership(ownerId);