using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using Object = UnityEngine.Object; namespace Unity.Netcode.TestHelpers.Runtime { /// /// The default SceneManagerHandler used for all NetcodeIntegrationTest derived children. /// internal class IntegrationTestSceneHandler : ISceneManagerHandler, IDisposable { internal CoroutineRunner CoroutineRunner; // Default client simulated delay time protected const float k_ClientLoadingSimulatedDelay = 0.02f; // Controls the client simulated delay time protected float m_ClientLoadingSimulatedDelay = k_ClientLoadingSimulatedDelay; public delegate bool CanClientsLoadUnloadDelegateHandler(); public event CanClientsLoadUnloadDelegateHandler CanClientsLoad; public event CanClientsLoadUnloadDelegateHandler CanClientsUnload; internal List CoroutinesRunning = new List(); /// /// Used to control when clients should attempt to fake-load a scene /// Note: Unit/Integration tests that only use /// need to subscribe to the CanClientsLoad and CanClientsUnload events /// in order to control when clients can fake-load. /// Tests that derive from already have integrated /// support and you can override and /// . /// protected bool OnCanClientsLoad() { if (CanClientsLoad != null) { return CanClientsLoad.Invoke(); } return true; } /// /// Fake-Loads a scene for a client /// internal IEnumerator ClientLoadSceneCoroutine(string sceneName, ISceneManagerHandler.SceneEventAction sceneEventAction) { yield return new WaitForSeconds(m_ClientLoadingSimulatedDelay); while (!OnCanClientsLoad()) { yield return new WaitForSeconds(m_ClientLoadingSimulatedDelay); } sceneEventAction.Invoke(); } protected bool OnCanClientsUnload() { if (CanClientsUnload != null) { return CanClientsUnload.Invoke(); } return true; } /// /// Fake-Unloads a scene for a client /// internal IEnumerator ClientUnloadSceneCoroutine(ISceneManagerHandler.SceneEventAction sceneEventAction) { yield return new WaitForSeconds(m_ClientLoadingSimulatedDelay); while (!OnCanClientsUnload()) { yield return new WaitForSeconds(m_ClientLoadingSimulatedDelay); } sceneEventAction.Invoke(); } public AsyncOperation LoadSceneAsync(string sceneName, LoadSceneMode loadSceneMode, ISceneManagerHandler.SceneEventAction sceneEventAction) { CoroutinesRunning.Add(CoroutineRunner.StartCoroutine(ClientLoadSceneCoroutine(sceneName, sceneEventAction))); // This is OK to return a "nothing" AsyncOperation since we are simulating client loading return new AsyncOperation(); } public AsyncOperation UnloadSceneAsync(Scene scene, ISceneManagerHandler.SceneEventAction sceneEventAction) { CoroutinesRunning.Add(CoroutineRunner.StartCoroutine(ClientUnloadSceneCoroutine(sceneEventAction))); // This is OK to return a "nothing" AsyncOperation since we are simulating client loading return new AsyncOperation(); } public IntegrationTestSceneHandler() { if (CoroutineRunner == null) { CoroutineRunner = new GameObject("UnitTestSceneHandlerCoroutine").AddComponent(); } } public void Dispose() { foreach (var coroutine in CoroutinesRunning) { CoroutineRunner.StopCoroutine(coroutine); } CoroutineRunner.StopAllCoroutines(); Object.Destroy(CoroutineRunner.gameObject); } } }