123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.SceneManagement;
- namespace Mirror.Examples.MultipleAdditiveScenes
- {
- [AddComponentMenu("")]
- public class MultiSceneNetManager : NetworkManager
- {
- [Header("Spawner Setup")]
- [Tooltip("Reward Prefab for the Spawner")]
- public GameObject rewardPrefab;
- [Header("MultiScene Setup")]
- public int instances = 3;
- [Scene]
- public string gameScene;
- // This is set true after server loads all subscene instances
- bool subscenesLoaded;
- // subscenes are added to this list as they're loaded
- readonly List<Scene> subScenes = new List<Scene>();
- // Sequential index used in round-robin deployment of players into instances and score positioning
- int clientIndex;
- #region Server System Callbacks
- /// <summary>
- /// Called on the server when a client adds a new player with NetworkClient.AddPlayer.
- /// <para>The default implementation for this function creates a new player object from the playerPrefab.</para>
- /// </summary>
- /// <param name="conn">Connection from client.</param>
- public override void OnServerAddPlayer(NetworkConnection conn)
- {
- StartCoroutine(OnServerAddPlayerDelayed(conn));
- }
- // This delay is mostly for the host player that loads too fast for the
- // server to have subscenes async loaded from OnStartServer ahead of it.
- IEnumerator OnServerAddPlayerDelayed(NetworkConnection conn)
- {
- // wait for server to async load all subscenes for game instances
- while (!subscenesLoaded)
- yield return null;
- // Send Scene message to client to additively load the game scene
- conn.Send(new SceneMessage { sceneName = gameScene, sceneOperation = SceneOperation.LoadAdditive });
- // Wait for end of frame before adding the player to ensure Scene Message goes first
- yield return new WaitForEndOfFrame();
- base.OnServerAddPlayer(conn);
- PlayerScore playerScore = conn.identity.GetComponent<PlayerScore>();
- playerScore.playerNumber = clientIndex;
- playerScore.scoreIndex = clientIndex / subScenes.Count;
- playerScore.matchIndex = clientIndex % subScenes.Count;
- clientIndex++;
- // Do this only on server, not on clients
- // This is what allows the NetworkSceneChecker on player and scene objects
- // to isolate matches per scene instance on server.
- if (subScenes.Count > 0)
- SceneManager.MoveGameObjectToScene(conn.identity.gameObject, subScenes[clientIndex % subScenes.Count]);
- }
- #endregion
- #region Start & Stop Callbacks
- /// <summary>
- /// This is invoked when a server is started - including when a host is started.
- /// <para>StartServer has multiple signatures, but they all cause this hook to be called.</para>
- /// </summary>
- public override void OnStartServer()
- {
- StartCoroutine(ServerLoadSubScenes());
- }
- // We're additively loading scenes, so GetSceneAt(0) will return the main "container" scene,
- // therefore we start the index at one and loop through instances value inclusively.
- // If instances is zero, the loop is bypassed entirely.
- IEnumerator ServerLoadSubScenes()
- {
- for (int index = 1; index <= instances; index++)
- {
- yield return SceneManager.LoadSceneAsync(gameScene, new LoadSceneParameters { loadSceneMode = LoadSceneMode.Additive, localPhysicsMode = LocalPhysicsMode.Physics3D });
- Scene newScene = SceneManager.GetSceneAt(index);
- subScenes.Add(newScene);
- Spawner.InitialSpawn(newScene);
- }
- subscenesLoaded = true;
- }
- /// <summary>
- /// This is called when a server is stopped - including when a host is stopped.
- /// </summary>
- public override void OnStopServer()
- {
- NetworkServer.SendToAll(new SceneMessage { sceneName = gameScene, sceneOperation = SceneOperation.UnloadAdditive });
- StartCoroutine(ServerUnloadSubScenes());
- clientIndex = 0;
- }
- // Unload the subScenes and unused assets and clear the subScenes list.
- IEnumerator ServerUnloadSubScenes()
- {
- for (int index = 0; index < subScenes.Count; index++)
- yield return SceneManager.UnloadSceneAsync(subScenes[index]);
- subScenes.Clear();
- subscenesLoaded = false;
- yield return Resources.UnloadUnusedAssets();
- }
- /// <summary>
- /// This is called when a client is stopped.
- /// </summary>
- public override void OnStopClient()
- {
- // make sure we're not in host mode
- if (mode == NetworkManagerMode.ClientOnly)
- StartCoroutine(ClientUnloadSubScenes());
- }
- // Unload all but the active scene, which is the "container" scene
- IEnumerator ClientUnloadSubScenes()
- {
- for (int index = 0; index < SceneManager.sceneCount; index++)
- {
- if (SceneManager.GetSceneAt(index) != SceneManager.GetActiveScene())
- yield return SceneManager.UnloadSceneAsync(SceneManager.GetSceneAt(index));
- }
- }
- #endregion
- }
- }
|