MLAPI/MLAPI/NetworkingManagerComponents/Core/NetworkSceneManager.cs

124 lines
4.9 KiB
C#

using MLAPI.MonoBehaviours.Core;
using MLAPI.NetworkingManagerComponents.Binary;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace MLAPI.NetworkingManagerComponents.Core
{
/// <summary>
/// Main class for managing network scenes
/// </summary>
public static class NetworkSceneManager
{
internal static HashSet<string> registeredSceneNames;
internal static Dictionary<string, uint> sceneNameToIndex;
internal static Dictionary<uint, string> sceneIndexToString;
private static Scene lastScene;
private static Scene nextScene;
private static bool isSwitching = false;
internal static uint CurrentSceneIndex = 0;
internal static void SetCurrentSceneIndex ()
{
if(!sceneNameToIndex.ContainsKey(SceneManager.GetActiveScene().name))
{
Debug.LogWarning("MLAPI: Scene switching is enabled but the current scene (" + SceneManager.GetActiveScene().name + ") is not regisered as a network scene.");
return;
}
CurrentSceneIndex = sceneNameToIndex[SceneManager.GetActiveScene().name];
}
/// <summary>
/// Switches to a scene with a given name. Can only be called from Server
/// </summary>
/// <param name="sceneName">The name of the scene to switch to</param>
public static void SwitchScene(string sceneName)
{
if(!NetworkingManager.singleton.NetworkConfig.EnableSceneSwitching)
{
Debug.LogWarning("MLAPI: Scene switching is not enabled");
return;
}
else if (isSwitching)
{
Debug.LogWarning("MLAPI: Scene switch already in progress");
return;
}
else if(!registeredSceneNames.Contains(sceneName))
{
Debug.LogWarning("MLAPI: The scene " + sceneName + " is not registered as a switchable scene.");
return;
}
SpawnManager.DestroySceneObjects(); //Destroy current scene objects before switching.
CurrentSceneIndex = sceneNameToIndex[sceneName];
isSwitching = true;
lastScene = SceneManager.GetActiveScene();
AsyncOperation sceneLoad = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
sceneLoad.completed += OnSceneLoaded;
using (BitWriter writer = new BitWriter())
{
writer.WriteUInt(sceneNameToIndex[sceneName]);
InternalMessageHandler.Send("MLAPI_SWITCH_SCENE", "MLAPI_INTERNAL", writer.Finalize());
}
}
/// <summary>
/// Called on client
/// </summary>
/// <param name="sceneIndex"></param>
internal static void OnSceneSwitch(uint sceneIndex)
{
if (!NetworkingManager.singleton.NetworkConfig.EnableSceneSwitching)
{
Debug.LogWarning("MLAPI: Scene switching is not enabled but was requested by the server");
return;
}
else if (!sceneIndexToString.ContainsKey(sceneIndex) || !registeredSceneNames.Contains(sceneIndexToString[sceneIndex]))
{
Debug.LogWarning("MLAPI: Server requested a scene switch to a non registered scene");
return;
}
else if(SceneManager.GetActiveScene().name == sceneIndexToString[sceneIndex])
{
return; //This scene is already loaded. This usually happends at first load
}
SpawnManager.DestroySceneObjects();
lastScene = SceneManager.GetActiveScene();
AsyncOperation sceneLoad = SceneManager.LoadSceneAsync(sceneIndexToString[sceneIndex], LoadSceneMode.Additive);
sceneLoad.completed += OnSceneLoaded;
}
private static void OnSceneLoaded(AsyncOperation operation)
{
List<NetworkedObject> objectsToKeep = SpawnManager.spawnedObjects.Values.ToList();
//The last loaded scene
nextScene = SceneManager.GetSceneAt(SceneManager.sceneCount - 1);
for (int i = 0; i < objectsToKeep.Count; i++)
{
SceneManager.MoveGameObjectToScene(objectsToKeep[i].gameObject, nextScene);
}
AsyncOperation sceneLoad = SceneManager.UnloadSceneAsync(lastScene);
sceneLoad.completed += OnSceneUnload;
}
private static void OnSceneUnload(AsyncOperation operation)
{
isSwitching = false;
if(NetworkingManager.singleton.isServer)
{
SpawnManager.MarkSceneObjects();
SpawnManager.FlushSceneObjects();
}
else
{
Debug.LogError("DESTROING OBJECTS");
SpawnManager.DestroySceneObjects();
}
}
}
}