diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index c4dabd9c37..8d9fda7706 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -14,6 +14,7 @@ Additional documentation and release notes are available at [Multiplayer Documen - Fixed issue where some temporary debug console logging was left in a merged PR. (#2562) - Fixed the "Generate Default Network Prefabs List" setting not loading correctly and always reverting to being checked. (#2545) +- Fixed issue where users could not use NetworkSceneManager.VerifySceneBeforeLoading to exclude runtime generated scenes from client synchronization. (#2550) - Fixed missing value on `NetworkListEvent` for `EventType.RemoveAt` events. (#2542,#2543) - Fixed issue where parenting a NetworkTransform under a transform with a scale other than Vector3.one would result in incorrect values on non-authoritative instances. (#2538) - Fixed issue where a server would include scene migrated and then despawned NetworkObjects to a client that was being synchronized. (#2532) diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs index 1443e334cf..91fd876187 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs @@ -786,9 +786,18 @@ private void SceneManager_ActiveSceneChanged(Scene current, Scene next) /// true (Valid) or false (Invalid) internal bool ValidateSceneBeforeLoading(uint sceneHash, LoadSceneMode loadSceneMode) { - var validated = true; var sceneName = SceneNameFromHash(sceneHash); var sceneIndex = SceneUtility.GetBuildIndexByScenePath(sceneName); + return ValidateSceneBeforeLoading(sceneIndex, sceneName, loadSceneMode); + } + + /// + /// Overloaded version that is invoked by and . + /// This specifically is to allow runtime generated scenes to be excluded by the server during synchronization. + /// + internal bool ValidateSceneBeforeLoading(int sceneIndex, string sceneName, LoadSceneMode loadSceneMode) + { + var validated = true; if (VerifySceneBeforeLoading != null) { validated = VerifySceneBeforeLoading.Invoke(sceneIndex, sceneName, loadSceneMode); @@ -1744,24 +1753,22 @@ internal void SynchronizeNetworkObjects(ulong clientId) continue; } - var sceneHash = SceneHashFromNameOrPath(scene.path); - // This would depend upon whether we are additive or not // If we are the base scene, then we set the root scene index; if (activeScene == scene) { - if (!ValidateSceneBeforeLoading(sceneHash, sceneEventData.LoadSceneMode)) + if (!ValidateSceneBeforeLoading(scene.buildIndex, scene.name, sceneEventData.LoadSceneMode)) { continue; } - sceneEventData.SceneHash = sceneHash; + sceneEventData.SceneHash = SceneHashFromNameOrPath(scene.path); sceneEventData.SceneHandle = scene.handle; } - else if (!ValidateSceneBeforeLoading(sceneHash, LoadSceneMode.Additive)) + else if (!ValidateSceneBeforeLoading(scene.buildIndex, scene.name, LoadSceneMode.Additive)) { continue; } - sceneEventData.AddSceneToSynchronize(sceneHash, scene.handle); + sceneEventData.AddSceneToSynchronize(SceneHashFromNameOrPath(scene.path), scene.handle); } sceneEventData.AddSpawnedNetworkObjects(); diff --git a/testproject/Assets/Tests/Runtime/NetworkSceneManager/ClientSynchronizationValidationTest.cs b/testproject/Assets/Tests/Runtime/NetworkSceneManager/ClientSynchronizationValidationTest.cs index 845a83bbbb..7ee9a4ecef 100644 --- a/testproject/Assets/Tests/Runtime/NetworkSceneManager/ClientSynchronizationValidationTest.cs +++ b/testproject/Assets/Tests/Runtime/NetworkSceneManager/ClientSynchronizationValidationTest.cs @@ -15,18 +15,69 @@ public class ClientSynchronizationValidationTest : NetcodeIntegrationTest private const string k_FirstSceneToLoad = "UnitTestBaseScene"; private const string k_SecondSceneToLoad = "InSceneNetworkObject"; private const string k_ThirdSceneToSkip = "EmptyScene"; + private Scene m_RuntimeGeneratedScene; + private bool m_IncludeSceneVerificationHandler; + private bool m_RuntimeSceneWasExcludedFromSynch; private List m_ClientSceneVerifiers = new List(); protected override void OnNewClientStarted(NetworkManager networkManager) { - m_ClientSceneVerifiers.Add(new ClientSceneVerificationHandler(networkManager)); + if (m_IncludeSceneVerificationHandler) + { + m_ClientSceneVerifiers.Add(new ClientSceneVerificationHandler(networkManager)); + } base.OnNewClientStarted(networkManager); } + /// + /// Handle excluding runtime scene from synchronization + /// + private bool OnServerVerifySceneBeforeLoading(int sceneIndex, string sceneName, LoadSceneMode loadSceneMode) + { + // exclude test runner scene + if (sceneName.StartsWith(NetcodeIntegrationTestHelpers.FirstPartOfTestRunnerSceneName)) + { + return false; + } + + // Exclude the runtime generated scene + if (sceneIndex == m_RuntimeGeneratedScene.buildIndex && m_RuntimeGeneratedScene.name == sceneName) + { + m_RuntimeSceneWasExcludedFromSynch = true; + return false; + } + + return true; + } + + /// + /// Test that validates users can exclude runtime generated scenes from the initial client synchronization + /// process using + /// + [UnityTest] + public IEnumerator ClientSynchWithServerSideRuntimeGeneratedScene() + { + m_IncludeSceneVerificationHandler = false; + m_ServerNetworkManager.SceneManager.VerifySceneBeforeLoading = OnServerVerifySceneBeforeLoading; + m_ServerNetworkManager.SceneManager.DisableValidationWarnings(true); + // For this test we want to disable the check for scenes in build list + m_ServerNetworkManager.SceneManager.ExcludeSceneFromSychronization = null; + // Create a runtime scene in the server side + m_RuntimeGeneratedScene = SceneManager.CreateScene("RuntimeGeneratedScene"); + yield return s_DefaultWaitForTick; + yield return CreateAndStartNewClient(); + + Assert.True(m_RuntimeSceneWasExcludedFromSynch, $"Server did not exclude the runtime generated scene when creating synchronization message data!"); + } + + /// + /// Validates that connecting clients will exclude scenes using + /// [UnityTest] public IEnumerator ClientVerifySceneBeforeLoading() { + m_IncludeSceneVerificationHandler = true; var scenesToLoad = new List() { k_FirstSceneToLoad, k_SecondSceneToLoad, k_ThirdSceneToSkip }; m_ServerNetworkManager.SceneManager.OnLoadComplete += OnLoadComplete; foreach (var sceneToLoad in scenesToLoad)