Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions com.unity.netcode.gameobjects/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Additional documentation and release notes are available at [Multiplayer Documen

### Fixed

- Fixed issue where scenes additively loaded before a session started were tracked as loaded on the server but had no scene handle entries, which caused `NetworkSceneManager.UnloadScene` to log an error and leave the scene registered as loaded even though it unloaded on all peers. (#4146)
- Issue with not being able to spawn initially disabled in-scene placed objects. (#4093)
- Issue with pre-instantiated network prefab instances being marked as in-scene placed. Now pre-instantiated network prefabs are dynamically spawned. (#4093)
- Issue where a user could spawn runtime created `NetworkObject` that has a GlobalObjectIdHash of zero. These are not valid instances and will no longer be allowed to spawn. (#4093)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ internal NetworkSceneManager(NetworkManager networkManager)
for (int i = 0; i < SceneManager.sceneCount; i++)
{
var loadedScene = SceneManager.GetSceneAt(i);
ScenesLoaded.Add(loadedScene.handle, loadedScene);
UpdateServerClientSceneHandle(loadedScene.handle, loadedScene.handle, loadedScene);
}
SceneManagerHandler.PopulateLoadedScenes(ref ScenesLoaded, NetworkManager);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,9 @@ private static void SceneManagerValidationAndTestRunnerInitialization(NetworkMan
}
return;
}
networkManager.SceneManager.ServerSceneHandleToClientSceneHandle.Add(scene.handle, scene.handle);

// The server already registers every scene loaded prior to startup, so only add the test runner scene if it is not already there.
networkManager.SceneManager.ServerSceneHandleToClientSceneHandle.TryAdd(scene.handle, scene.handle);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ internal class NetworkSceneManagerStartupTests : NetcodeIntegrationTest
{
private const string k_ActiveScene = "SessionSynchronize";
private const string k_AdditionalScene = "InSceneNetworkObjectMovesToDDOL";
private const string k_PreLoadedScene = "EmptyScene1";

private readonly List<NetworkObject> m_ObjectsInScenes = new List<NetworkObject>();
private Scene m_OriginalActiveScene;
Expand Down Expand Up @@ -141,6 +142,35 @@ public IEnumerator AllExistingObjectsAreSpawnedAtStartup([Values] LoadSceneMode
AssertOnTimeout("Timed out waiting for objects to spawn on all clients!");
}

/// <summary>
/// Validates that a scene additively loaded before the session started is tracked well enough
/// to be unloaded through <see cref="NetworkSceneManager"/> without error.
/// </summary>
[UnityTest]
public IEnumerator UnloadPreLoadedScene()
{
yield return PreLoadScene(k_PreLoadedScene);
var preLoadedScene = m_SceneLoaded;

m_CanStart = true;
yield return StartServerAndClients();

// Scenes loaded before the session started are registered in both the loaded scenes and the
// scene handle tables, otherwise unloading them fails part way through and leaks the entry.
var sceneManager = GetAuthorityNetworkManager().SceneManager;
Assert.IsTrue(sceneManager.ScenesLoaded.ContainsKey(preLoadedScene.handle), $"{k_PreLoadedScene} is not in {nameof(NetworkSceneManager.ScenesLoaded)}!");
Assert.IsTrue(sceneManager.ServerSceneHandleToClientSceneHandle.ContainsKey(preLoadedScene.handle), $"{k_PreLoadedScene} is not in {nameof(NetworkSceneManager.ServerSceneHandleToClientSceneHandle)}!");

var status = sceneManager.UnloadScene(preLoadedScene);
Assert.AreEqual(SceneEventProgressStatus.Started, status, $"{nameof(NetworkSceneManager.UnloadScene)} returned {status}!");

yield return WaitForConditionOrTimeOut(() => !preLoadedScene.isLoaded);
AssertOnTimeout($"Timed out waiting for {k_PreLoadedScene} to unload!");

Assert.IsFalse(sceneManager.ScenesLoaded.ContainsKey(preLoadedScene.handle), $"{k_PreLoadedScene} was unloaded but is still in {nameof(NetworkSceneManager.ScenesLoaded)}!");
Assert.IsFalse(sceneManager.ServerSceneHandleToClientSceneHandle.ContainsKey(preLoadedScene.handle), $"{k_PreLoadedScene} was unloaded but is still in {nameof(NetworkSceneManager.ServerSceneHandleToClientSceneHandle)}!");
}

#region Scene loading and related methods

/// <summary>
Expand Down