Mirror/Assets/Scenery/Bootstrap.cs

99 lines
3.6 KiB
C#
Raw Normal View History

2021-05-16 09:28:05 +00:00
// Bootstrap ServerWorld, ClientWorld just like in ECS.
using UnityEngine;
2021-05-16 07:55:39 +00:00
using UnityEngine.SceneManagement;
2021-05-16 07:10:31 +00:00
2021-05-16 09:28:05 +00:00
public class Bootstrap : MonoBehaviour
2021-05-16 07:10:31 +00:00
{
2021-05-16 07:55:39 +00:00
// Server/Client worlds for easy access
public const string ClientWorldName = "ClientWorld";
public const string ServerWorldName = "ServerWorld";
2021-05-16 09:28:52 +00:00
2021-05-16 09:27:27 +00:00
public static Scene ClientWorld;
public static Scene ServerWorld;
2021-05-16 09:28:52 +00:00
2021-05-16 09:31:01 +00:00
// original scene is not public. it will become the server scene after merge.
2021-05-16 09:27:27 +00:00
static Scene originalScene;
2021-05-16 09:31:01 +00:00
// this will always be the original scene's path.
public static string originalScenePath;
2021-05-16 09:28:52 +00:00
static bool initialized;
2021-05-16 07:55:39 +00:00
void Awake()
{
2021-05-16 09:27:27 +00:00
// we only do world initialization ONCE
// duplicating a scene would call Awake here again.
if (initialized) return;
initialized = true;
2021-05-16 07:55:39 +00:00
// remember the original scene
originalScene = SceneManager.GetActiveScene();
2021-05-16 09:27:27 +00:00
originalScenePath = originalScene.path;
2021-05-16 07:55:39 +00:00
// let's create a ServerWorld and ClientWorld like in DOTSNET
// so that even if we connect client 1 hour after starting server,
// the client still starts with a fresh client scene like everyone else.
SceneManager.CreateScene(ClientWorldName);
SceneManager.CreateScene(ServerWorldName);
ClientWorld = SceneManager.GetSceneByName(ClientWorldName);
ServerWorld = SceneManager.GetSceneByName(ServerWorldName);
// can't merge any scenes yet because not loaded in Awake() yet.
// setup OnSceneLoaded callback and continue there.
SceneManager.sceneLoaded += OnSceneLoaded;
2021-05-16 09:27:27 +00:00
// duplicate original scene. we'll move it into ClientWorld
// -> additive, otherwise we would just reload it
SceneManager.LoadScene(originalScene.path, LoadSceneMode.Additive);
2021-05-16 07:55:39 +00:00
}
2021-05-16 09:42:25 +00:00
// remove audio listener and main camera from server world
static void StripServerWorld()
{
// backup active scene
Scene backup = SceneManager.GetActiveScene();
// load server scene
if (SceneManager.SetActiveScene(ServerWorld))
{
Debug.Log($"Bootstrap: stripping {ServerWorldName}");
// remove all audio listeners
foreach (AudioListener audio in FindObjectsOfType<AudioListener>())
Destroy(audio);
// remove all cameras
foreach (Camera cam in FindObjectsOfType<Camera>())
Destroy(cam);
// restore active scene
if (!SceneManager.SetActiveScene(backup))
Debug.LogError($"Bootstrap: failed to restore active scene {backup.path}");
}
else Debug.LogError($"Bootstrap: failed to activate {ServerWorldName}");
}
2021-05-16 07:55:39 +00:00
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
2021-05-16 09:29:21 +00:00
//Debug.Log($"OnSceneLoaded: {scene.name} {scene.path}");
2021-05-16 09:27:27 +00:00
2021-05-16 07:55:39 +00:00
// is this for the original scene?
if (scene == originalScene)
{
2021-05-16 09:42:25 +00:00
// merge original into ServerWorld & strip it
2021-05-16 09:29:21 +00:00
//Debug.Log($"original scene loaded");
2021-05-16 09:27:27 +00:00
SceneManager.MergeScenes(scene, ServerWorld);
2021-05-16 09:42:25 +00:00
Debug.Log($"Bootstrap: original scene merged into {ServerWorldName}!");
StripServerWorld();
2021-05-16 09:27:27 +00:00
}
// not the same scene, but same path. so it's the duplicate.
else if (scene.path == originalScenePath)
{
// merge duplicate into serverworld
2021-05-16 09:29:21 +00:00
//Debug.Log($"duplicated scene loaded");
2021-05-16 09:27:27 +00:00
SceneManager.MergeScenes(scene, ClientWorld);
2021-05-16 09:42:25 +00:00
Debug.Log($"Bootstrap: original scene merged into {ClientWorldName}!");
2021-05-16 07:55:39 +00:00
}
}
2021-05-16 07:10:31 +00:00
}