From c9ee891dc60378a5e2113af0c4fca0aef76209c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C5=A0vec?= Date: Fri, 30 Aug 2024 20:27:27 +0200 Subject: [PATCH] Implement multiplayer scene loading --- .../GlobalBoostrap/SceneManager.prefab | 11 +- Assets/Scripts/Components/PlayerComponent.cs | 14 +- Assets/Scripts/Managers/SceneManager.cs | 171 ++++++++++++++++-- 3 files changed, 174 insertions(+), 22 deletions(-) diff --git a/Assets/Prefabs/GlobalBoostrap/SceneManager.prefab b/Assets/Prefabs/GlobalBoostrap/SceneManager.prefab index c5d113ae..60f7c02d 100644 --- a/Assets/Prefabs/GlobalBoostrap/SceneManager.prefab +++ b/Assets/Prefabs/GlobalBoostrap/SceneManager.prefab @@ -44,4 +44,13 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 324a182340742c54cbdb3967f1916e29, type: 3} m_Name: m_EditorClassIdentifier: - playerController: {fileID: 0} + LobbyScene: {fileID: 102900000, guid: eaec6d3575cfd2d42a5f87b082c898c8, type: 3} + EntranceScene: {fileID: 102900000, guid: 07047a8cc3efe2043ad21378467317ee, type: 3} + ForgeScene: {fileID: 102900000, guid: 0850bb9b948948349b83e3612aa421af, type: 3} + lobbySceneName: Lobby + entranceSceneName: Entrance + forgeSceneName: Forge + gameManager: {fileID: 0} + fadeDuration: 2 + loadedScene: + m_Handle: 0 diff --git a/Assets/Scripts/Components/PlayerComponent.cs b/Assets/Scripts/Components/PlayerComponent.cs index a1a26a65..a0e0e2ee 100644 --- a/Assets/Scripts/Components/PlayerComponent.cs +++ b/Assets/Scripts/Components/PlayerComponent.cs @@ -65,6 +65,8 @@ public class PlayerComponent : NetworkBehaviour private void Start() { + StartCoroutine(AddDontDestroyToDependencies()); + if (!isSoloRig) return; audioListener.enabled = true; @@ -108,6 +110,16 @@ public class PlayerComponent : NetworkBehaviour } } + private IEnumerator AddDontDestroyToDependencies() + { + yield return new WaitForEndOfFrame(); + + foreach (var d in dependencies) + { + DontDestroyOnLoad(d); + } + } + public void DestroyDependencies() { foreach (var d in dependencies) @@ -121,7 +133,7 @@ public class PlayerComponent : NetworkBehaviour public void Toggle(bool active) { // Only toggle solo rig components, not multiplayer one - if (isSoloRig) + if (networkObject == null || isSoloRig) { foreach (var d in dependencies) { diff --git a/Assets/Scripts/Managers/SceneManager.cs b/Assets/Scripts/Managers/SceneManager.cs index c53fde16..79a4288d 100644 --- a/Assets/Scripts/Managers/SceneManager.cs +++ b/Assets/Scripts/Managers/SceneManager.cs @@ -9,13 +9,40 @@ using Zenject; public class SceneManager : NetworkBehaviour { - enum Scene +#if UNITY_EDITOR + + public UnityEditor.SceneAsset LobbyScene; + public UnityEditor.SceneAsset EntranceScene; + public UnityEditor.SceneAsset ForgeScene; + + private void OnValidate() { - Lobby = 0, - Entrance = 1, - Forge = 2 + lobbySceneName = LobbyScene?.name; + entranceSceneName = EntranceScene?.name; + forgeSceneName = ForgeScene?.name; } +#endif + + [SerializeField] + [ReadOnly] + private string lobbySceneName; + + [SerializeField] + [ReadOnly] + private string entranceSceneName; + + [SerializeField] + [ReadOnly] + private string forgeSceneName; + + //enum Scene + //{ + // Lobby = 0, + // Entrance = 1, + // Forge = 2 + //} + [Inject] [ReadOnly] [SerializeField] @@ -27,35 +54,139 @@ public class SceneManager : NetworkBehaviour [ReadOnly] [SerializeField] - private Scene scene; + private Scene loadedScene; + + public override void OnNetworkSpawn() + { + NetworkManager.SceneManager.OnSceneEvent += OnSceneEvent; + + base.OnNetworkSpawn(); + } + + private void OnSceneEvent(SceneEvent sceneEvent) + { + var clientOrServer = sceneEvent.ClientId == NetworkManager.ServerClientId ? "server" : "client"; + + switch (sceneEvent.SceneEventType) + { + case SceneEventType.LoadComplete: + { + // We want to handle this for only the server-side + if (sceneEvent.ClientId == NetworkManager.ServerClientId) + { + // Keep track of the loaded scene, you need this to unload it + loadedScene = sceneEvent.Scene; + } + + Debug.Log($"Loaded the {sceneEvent.SceneName} scene on " + + $"{clientOrServer}-({sceneEvent.ClientId})."); + + break; + } + case SceneEventType.UnloadComplete: + { + Debug.Log($"Unloaded the {sceneEvent.SceneName} scene on " + + $"{clientOrServer}-({sceneEvent.ClientId})."); + + break; + } + case SceneEventType.LoadEventCompleted: + case SceneEventType.UnloadEventCompleted: + { + var loadUnload = sceneEvent.SceneEventType == SceneEventType.LoadEventCompleted ? "Load" : "Unload"; + + Debug.Log($"{loadUnload} event completed for the following client " + + $"identifiers:({sceneEvent.ClientsThatCompleted})"); + + if (sceneEvent.ClientsThatTimedOut.Count > 0) + { + Debug.LogWarning($"{loadUnload} event timed out for the following client " + + $"identifiers:({sceneEvent.ClientsThatTimedOut})"); + } + + break; + } + } + } + + private void CheckStatus(SceneEventProgressStatus status, bool isLoading = true) + { + var sceneEventAction = isLoading ? "load" : "unload"; + if (status != SceneEventProgressStatus.Started) + { + Debug.LogWarning($"Failed to {sceneEventAction} with" + + $" a {nameof(SceneEventProgressStatus)}: {status}"); + } + } + + private void UnloadScene() + { + // Assure only the server calls this when the NetworkObject is + // spawned and the scene is loaded. + if (!IsServer || !IsSpawned || !loadedScene.IsValid() || !loadedScene.isLoaded) + { + return; + } + + var status = NetworkManager.SceneManager.UnloadScene(loadedScene); + CheckStatus(status, false); + } [Button] public void SwitchToEntranceLevel() { - StartCoroutine(SwitchToScene(Scene.Entrance)); + StartCoroutine(SwitchToSceneMultiplayer(entranceSceneName)); } - private IEnumerator SwitchToScene(Scene scene) + private IEnumerator SwitchToSceneMultiplayer(string scene) { - gameManager.LocalPlayer.FadeScreen(1, fadeDuration); + //gameManager.LocalPlayer.FadeScreen(1, fadeDuration); - var operation = UnityEngine.SceneManagement.SceneManager - .LoadSceneAsync((int)scene); + NetworkManager.SceneManager.LoadScene(scene, LoadSceneMode.Single); - operation.allowSceneActivation = false; - - float timer = 0; + //var operation = UnityEngine.SceneManagement.SceneManager + // .LoadSceneAsync((int)scene); - while (timer <= fadeDuration && !operation.isDone) - { - timer += Time.deltaTime; + //operation.allowSceneActivation = false; + + //float timer = 0; + + //while (timer <= fadeDuration && !operation.isDone) + //{ + // timer += Time.deltaTime; yield return null; - } + //} - operation.allowSceneActivation = true; + //operation.allowSceneActivation = true; - this.scene = scene; + //this.scene = scene; - gameManager.LocalPlayer.FadeScreen(0, fadeDuration); + //gameManager.LocalPlayer.FadeScreen(0, fadeDuration); } + + //private IEnumerator SwitchToSceneSolo(Scene scene) + //{ + // gameManager.LocalPlayer.FadeScreen(1, fadeDuration); + + // //NetworkManager.SceneManager.LoadScene() + + // var operation = UnityEngine.SceneManagement.SceneManager + // .LoadSceneAsync((int)scene); + + // operation.allowSceneActivation = false; + + // float timer = 0; + + // while (timer <= fadeDuration && !operation.isDone) + // { + // timer += Time.deltaTime; + // yield return null; + // } + + // operation.allowSceneActivation = true; + + // this.scene = scene; + + // gameManager.LocalPlayer.FadeScreen(0, fadeDuration); + //} }