2using System.Collections.Generic;
6using UnityEngine.SceneManagement;
7using UnityEngine.Serialization;
11 public enum PlayerSpawnMethod { Random, RoundRobin }
12 public enum NetworkManagerMode { Offline, ServerOnly, ClientOnly, Host }
14 [DisallowMultipleComponent]
15 [AddComponentMenu(
"Network/Network Manager")]
16 [HelpURL(
"https://mirror-networking.gitbook.io/docs/components/network-manager")]
21 [Header(
"Configuration")]
22 [FormerlySerializedAs(
"m_DontDestroyOnLoad")]
23 [Tooltip(
"Should the Network Manager object be persisted through scene changes?")]
27 [FormerlySerializedAs(
"m_RunInBackground")]
28 [Tooltip(
"Multiplayer games should always run in the background so the network doesn't time out.")]
32 [Tooltip(
"Should the server auto-start when 'Server Build' is checked in build settings")]
33 [FormerlySerializedAs(
"startOnHeadless")]
37 [Tooltip(
"Server Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE.")]
41 [Header(
"Scene Management")]
43 [FormerlySerializedAs(
"m_OfflineScene")]
44 [Tooltip(
"Scene that Mirror will switch to when the client or server is stopped")]
49 [FormerlySerializedAs(
"m_OnlineScene")]
50 [Tooltip(
"Scene that Mirror will switch to when the server is started. Clients will recieve a Scene Message to load the server's current scene when they connect.")]
54 [Header(
"Network Info")]
55 [Tooltip(
"Transport component attached to this object that server and client will use to connect")]
60 [FormerlySerializedAs(
"m_NetworkAddress")]
61 [Tooltip(
"Network Address where the client should connect to the server. Server does not use this for anything.")]
65 [FormerlySerializedAs(
"m_MaxConnections")]
66 [Tooltip(
"Maximum number of concurrent connections.")]
69 [Header(
"Authentication")]
70 [Tooltip(
"Authentication component attached to this object")]
76 [Header(
"Player Object")]
77 [FormerlySerializedAs(
"m_PlayerPrefab")]
78 [Tooltip(
"Prefab of the player object. Prefab must have a Network Identity component. May be an empty game object or a full avatar.")]
82 [FormerlySerializedAs(
"m_AutoCreatePlayer")]
83 [Tooltip(
"Should Mirror automatically spawn the player after scene change?")]
87 [FormerlySerializedAs(
"m_PlayerSpawnMethod")]
88 [Tooltip(
"Round Robin or Random order of Start Position selection")]
92 [FormerlySerializedAs(
"m_SpawnPrefabs"), HideInInspector]
97 public static int startPositionIndex;
123 public NetworkManagerMode mode {
get;
private set; }
126 public virtual void OnValidate()
133 Debug.LogError(
"NetworkManager - Player Prefab must have a NetworkIdentity.");
140 Debug.LogWarning(
"NetworkManager - Player Prefab should not be added to Registered Spawnable Prefabs list...removed it.");
149 public virtual void Reset()
154 foreach (NetworkManager manager
in transform.root.GetComponentsInChildren<NetworkManager>())
158 Debug.LogError($
"{name} detected another component of type {typeof(NetworkManager)} in its hierarchy on {manager.name}. There can only be one, please remove one of them.");
166 if (transport ==
null)
170 UnityEditor.Undo.RecordObject(gameObject,
"Added default Transport");
173 transport = GetComponent<Transport>();
176 if (transport ==
null)
178 transport = gameObject.AddComponent<KcpTransport>();
179 Debug.Log(
"NetworkManager: added default Transport because there was none yet.");
185 public virtual void Awake()
188 if (!InitializeSingleton())
return;
190 Debug.Log(
"Mirror | mirror-networking.com | discord.gg/N9QVxbM");
197 SceneManager.sceneLoaded += OnSceneLoaded;
201 public virtual void Start()
217 public virtual void LateUpdate()
223 bool IsServerOnlineSceneChangeNeeded()
229 public static bool IsSceneActive(
string scene)
231 Scene activeScene = SceneManager.GetActiveScene();
232 return activeScene.path == scene || activeScene.name == scene;
239 InitializeSingleton();
242 Application.runInBackground =
true;
244 if (authenticator !=
null)
266 RegisterServerMessages();
274 Debug.LogWarning(
"Server already started.");
278 mode = NetworkManagerMode.ServerOnly;
299 if (IsServerOnlineSceneChangeNeeded())
315 Debug.LogWarning(
"Client already started.");
319 mode = NetworkManagerMode.ClientOnly;
321 InitializeSingleton();
324 Application.runInBackground =
true;
326 if (authenticator !=
null)
335 RegisterClientMessages();
339 Debug.LogError(
"Must set the Network Address field in the manager");
354 Debug.LogWarning(
"Client already started.");
358 mode = NetworkManagerMode.ClientOnly;
360 InitializeSingleton();
363 Application.runInBackground =
true;
365 if (authenticator !=
null)
371 RegisterClientMessages();
386 Debug.LogWarning(
"Server or Client already started.");
390 mode = NetworkManagerMode.Host;
425 if (IsServerOnlineSceneChangeNeeded())
428 finishStartHostPending =
true;
439 bool finishStartHostPending;
447 void FinishStartHost()
488 void StartHostClient()
492 if (authenticator !=
null)
499 NetworkServer.ActivateHostScene();
500 RegisterClientMessages();
504 NetworkClient.ConnectLocalServer();
532 if (authenticator !=
null)
542 if (gameObject !=
null
543 && gameObject.scene.name ==
"DontDestroyOnLoad"
546 SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene());
555 mode = NetworkManagerMode.Offline;
562 startPositionIndex = 0;
570 if (mode == NetworkManagerMode.Offline)
573 if (authenticator !=
null)
583 if (gameObject !=
null
584 && gameObject.scene.name ==
"DontDestroyOnLoad"
587 SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene());
597 mode = NetworkManagerMode.Offline;
617 public virtual void OnApplicationQuit()
629 if (NetworkServer.active)
650 bool InitializeSingleton()
659 Debug.LogWarning(
"Multiple NetworkManagers detected in the scene. Only one NetworkManager can exist at a time. The duplicate NetworkManager will be destroyed.");
667 if (Application.isPlaying)
671 transform.SetParent(
null);
672 DontDestroyOnLoad(gameObject);
683 Transport.activeTransport = transport;
687 void RegisterServerMessages()
689 NetworkServer.OnConnectedEvent = OnServerConnectInternal;
691 NetworkServer.OnErrorEvent = OnServerError;
692 NetworkServer.RegisterHandler<AddPlayerMessage>(OnServerAddPlayerInternal);
695 NetworkServer.ReplaceHandler<ReadyMessage>(OnServerReadyMessageInternal);
698 void RegisterClientMessages()
700 NetworkClient.OnConnectedEvent = OnClientConnectInternal;
701 NetworkClient.OnDisconnectedEvent = OnClientDisconnectInternal;
702 NetworkClient.OnErrorEvent = OnClientError;
703 NetworkClient.RegisterHandler<NotReadyMessage>(OnClientNotReadyMessageInternal);
704 NetworkClient.RegisterHandler<SceneMessage>(OnClientSceneInternal,
false);
709 foreach (GameObject prefab
in spawnPrefabs.Where(t => t !=
null))
710 NetworkClient.RegisterPrefab(prefab);
715 [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
716 public static void ResetStatics()
724 startPositionIndex = 0;
725 clientReadyConnection =
null;
726 loadingSceneAsync =
null;
734 public virtual void OnDestroy()
745 public static AsyncOperation loadingSceneAsync;
754 if (
string.IsNullOrWhiteSpace(newSceneName))
756 Debug.LogError(
"ServerChangeScene empty scene name");
762 Debug.LogError($
"Scene change is already in progress for {newSceneName}");
775 NetworkServer.isLoadingScene =
true;
777 loadingSceneAsync = SceneManager.LoadSceneAsync(newSceneName);
787 startPositionIndex = 0;
794 SceneOperation clientSceneOperation = SceneOperation.Normal;
796 internal void ClientChangeScene(
string newSceneName, SceneOperation sceneOperation = SceneOperation.Normal,
bool customHandling =
false)
798 if (
string.IsNullOrWhiteSpace(newSceneName))
800 Debug.LogError(
"ClientChangeScene empty scene name");
811 if (NetworkServer.active)
820 NetworkClient.isLoadingScene =
true;
824 clientSceneOperation = sceneOperation;
832 switch (sceneOperation)
834 case SceneOperation.Normal:
835 loadingSceneAsync = SceneManager.LoadSceneAsync(newSceneName);
837 case SceneOperation.LoadAdditive:
840 if (!SceneManager.GetSceneByName(newSceneName).IsValid() && !SceneManager.GetSceneByPath(newSceneName).IsValid())
841 loadingSceneAsync = SceneManager.LoadSceneAsync(newSceneName, LoadSceneMode.Additive);
844 Debug.LogWarning($
"Scene {newSceneName} is already loaded");
847 NetworkClient.isLoadingScene =
false;
850 case SceneOperation.UnloadAdditive:
853 if (SceneManager.GetSceneByName(newSceneName).IsValid() || SceneManager.GetSceneByPath(newSceneName).IsValid())
854 loadingSceneAsync = SceneManager.UnloadSceneAsync(newSceneName, UnloadSceneOptions.UnloadAllEmbeddedSceneObjects);
857 Debug.LogWarning($
"Cannot unload {newSceneName} with UnloadAdditive operation");
860 NetworkClient.isLoadingScene =
false;
866 if (sceneOperation == SceneOperation.Normal)
879 void OnSceneLoaded(Scene scene, LoadSceneMode mode)
881 if (mode == LoadSceneMode.Additive)
883 if (NetworkServer.active)
886 NetworkServer.SpawnObjects();
889 if (NetworkClient.active)
891 NetworkClient.PrepareToSpawnSceneObjects();
899 if (loadingSceneAsync !=
null && loadingSceneAsync.isDone)
913 loadingSceneAsync.allowSceneActivation =
true;
914 loadingSceneAsync =
null;
919 protected void FinishLoadScene()
925 NetworkServer.isLoadingScene =
false;
926 NetworkClient.isLoadingScene =
false;
929 if (mode == NetworkManagerMode.Host)
931 FinishLoadSceneHost();
934 else if (mode == NetworkManagerMode.ServerOnly)
936 FinishLoadSceneServerOnly();
939 else if (mode == NetworkManagerMode.ClientOnly)
941 FinishLoadSceneClientOnly();
950 void FinishLoadSceneHost()
956 if (clientReadyConnection !=
null)
960 clientReadyConnection =
null;
965 if (finishStartHostPending)
967 finishStartHostPending =
false;
986 NetworkServer.SpawnObjects();
991 if (NetworkClient.isConnected)
998 void FinishLoadSceneServerOnly()
1004 NetworkServer.SpawnObjects();
1010 void FinishLoadSceneClientOnly()
1016 if (clientReadyConnection !=
null)
1020 clientReadyConnection =
null;
1023 if (NetworkClient.isConnected)
1071 startPositionIndex = (startPositionIndex + 1) %
startPositions.Count;
1072 return startPosition;
1080 if (authenticator !=
null)
1088 OnServerAuthenticated(conn);
1094 void OnServerAuthenticated(NetworkConnectionToClient conn)
1099 conn.isAuthenticated =
true;
1111 void OnServerReadyMessageInternal(NetworkConnectionToClient conn, ReadyMessage msg)
1117 void OnServerAddPlayerInternal(NetworkConnectionToClient conn, AddPlayerMessage msg)
1123 Debug.LogError(
"The PlayerPrefab is empty on the NetworkManager. Please setup a PlayerPrefab object.");
1129 Debug.LogError(
"The PlayerPrefab does not have a NetworkIdentity. Please add a NetworkIdentity to the player prefab.");
1133 if (conn.identity !=
null)
1135 Debug.LogError(
"There is already a player for this connection.");
1142 void OnClientConnectInternal()
1146 if (authenticator !=
null)
1154 OnClientAuthenticated();
1159 void OnClientAuthenticated()
1164 NetworkClient.connection.isAuthenticated =
true;
1176 clientReadyConnection = NetworkClient.connection;
1180 void OnClientDisconnectInternal()
1186 void OnClientNotReadyMessageInternal(NotReadyMessage msg)
1189 NetworkClient.ready =
false;
1195 void OnClientSceneInternal(SceneMessage msg)
1200 if (NetworkClient.isConnected)
1202 ClientChangeScene(msg.sceneName, msg.sceneOperation, msg.customHandling);
1236 GameObject player = startPos !=
null
1237 ? Instantiate(
playerPrefab, startPos.position, startPos.rotation)
1242 player.name = $
"{playerPrefab.name} [connId={conn.connectionId}]";
1247 [Obsolete(
"OnServerError(conn, Exception) was changed to OnServerError(conn, TransportError, string)")]
1252#pragma warning disable CS0618
1253 OnServerError(conn,
new Exception(reason));
1254#pragma warning restore CS0618
1284 if (mode == NetworkManagerMode.Offline)
1291 [Obsolete(
"OnClientError(Exception) was changed to OnClientError(TransportError, string)")]
1292 public virtual void OnClientError(Exception exception) {}
1296#pragma warning disable CS0618
1297 OnClientError(
new Exception(reason));
1298#pragma warning restore CS0618
1306 public virtual void OnClientChangeScene(
string newSceneName, SceneOperation sceneOperation,
bool customHandling) {}
Base class for implementing component-based authentication during the Connect phase
virtual void OnClientAuthenticate()
Called on client from OnClientConnectInternal when a client needs to authenticate
UnityEvent OnClientAuthenticated
Notify subscribers on the client when the client is authenticated
virtual void OnServerAuthenticate(NetworkConnectionToClient conn)
Called on server from OnServerConnectInternal when a client needs to authenticate
virtual void OnStartClient()
Called when client starts, used to register message handlers if needed.
virtual void OnStopClient()
Called when client stops, used to unregister message handlers if needed.
UnityEventNetworkConnection OnServerAuthenticated
Notify subscribers on the server when a client is authenticated
virtual void OnStopServer()
Called when server stops, used to unregister message handlers if needed.
virtual void OnStartServer()
Called when server starts, used to register message handlers if needed.
NetworkClient with connection to server.
static bool active
active is true while a client is connecting/connected
static void Connect(string address)
Connect client to a NetworkServer by address.
static bool ready
True if client is ready (= joined world).
static void Shutdown()
Shutdown the client.
static bool Ready()
Sends Ready message to server, indicating that we loaded the scene, ready to enter the game.
static void Disconnect()
Disconnect from server.
static bool AddPlayer()
Sends AddPlayer message to the server, indicating that we want to join the world.
static bool isConnected
Check if client is connected (after connecting).
static NetworkIdentity localPlayer
NetworkIdentity of the localPlayer
Base NetworkConnection class for server-to-client and client-to-server connection.
NetworkIdentity identity
This connection's main object (usually the player object).
NetworkIdentity identifies objects across the network.
virtual void OnClientConnect()
Called on the client when connected to a server. By default it sets client as ready and adds a player...
virtual void OnStartServer()
This is invoked when a server is started - including when a host is started.
virtual void OnStopHost()
This is called when a host is stopped.
List< GameObject > spawnPrefabs
Prefabs that can be spawned over the network need to be registered here.
static NetworkManager singleton
The one and only NetworkManager
virtual void OnClientChangeScene(string newSceneName, SceneOperation sceneOperation, bool customHandling)
Called from ClientChangeScene immediately before SceneManager.LoadSceneAsync is executed
bool isNetworkActive
True if the server is running or client is connected/connecting.
void StartClient()
Starts the client, connects it to the server with networkAddress.
virtual void OnStartHost()
This is invoked when a host is started.
virtual void OnServerChangeScene(string newSceneName)
Called from ServerChangeScene immediately before SceneManager.LoadSceneAsync is executed
void StopHost()
This stops both the client and the server that the manager is using.
void StopServer()
Stops the server from listening and simulating the game.
void StartHost()
Starts a network "host" - a server and client in the same application.
virtual void OnStopClient()
This is called when a client is stopped.
static void RegisterStartPosition(Transform start)
Registers the transform of a game object as a player spawn location.
Transform GetStartPosition()
Get the next NetworkStartPosition based on the selected PlayerSpawnMethod.
virtual void ConfigureHeadlessFrameRate()
Set the frame rate for a headless builds. Override to disable or modify.
virtual void OnServerDisconnect(NetworkConnectionToClient conn)
Called on the server when a client disconnects.
string networkAddress
Server's address for clients to connect to.
virtual void OnClientError(TransportError error, string reason)
Called on client when transport raises an exception.
bool autoCreatePlayer
Enable to automatically create player objects on connect and on scene change.
virtual void OnStopServer()
This is called when a server is stopped - including when a host is stopped.
int maxConnections
The maximum number of concurrent network connections to support.
bool autoStartServerBuild
Should the server auto-start when 'Server Build' is checked in build settings
void StopClient()
Stops and disconnects the client.
bool clientLoadedScene
True if the client loaded a new scene when connecting to the server.
virtual void OnClientSceneChanged()
Called on clients when a scene has completed loaded, when the scene load was initiated by the server.
virtual void OnServerError(NetworkConnectionToClient conn, TransportError error, string reason)
Called on server when transport raises an exception. NetworkConnection may be null.
GameObject playerPrefab
The default prefab to be used to create player objects on the server.
static string networkSceneName
The name of the current network scene.
virtual void OnServerSceneChanged(string sceneName)
Called on server after a scene load with ServerChangeScene() is completed.
string onlineScene
Automatically switch to this scene upon going online (after connect/startserver).
virtual void OnClientDisconnect()
Called on clients when disconnected from a server.
virtual void OnStartClient()
This is invoked when the client is started.
bool dontDestroyOnLoad
Enable to keep NetworkManager alive when changing scenes.
static List< Transform > startPositions
List of transforms populated by NetworkStartPositions
virtual void OnServerReady(NetworkConnectionToClient conn)
Called on the server when a client is ready (= loaded the scene)
static void UnRegisterStartPosition(Transform start)
Unregister a Transform from start positions.
bool runInBackground
Multiplayer games should always run in the background so the network doesn't time out.
void StartServer()
Starts the server, listening for incoming connections.
virtual void OnServerAddPlayer(NetworkConnectionToClient conn)
Called on server when a client requests to add the player. Adds playerPrefab by default....
virtual void OnServerConnect(NetworkConnectionToClient conn)
Called on the server when a new client connects.
virtual void OnClientNotReady()
Called on clients when a servers tells the client it is no longer ready, e.g. when switching scenes.
void StartClient(Uri uri)
Starts the client, connects it to the server via Uri
virtual void ServerChangeScene(string newSceneName)
Change the server scene and all client's scenes across the network.
int serverTickRate
Server Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to mini...
PlayerSpawnMethod playerSpawnMethod
Where to spawn players.
int numPlayers
Number of active player objects across all connections on the server.
string offlineScene
Automatically switch to this scene upon going offline (on start / on disconnect / on shutdown).
NetworkServer handles remote connections and has a local connection for a local client.
static bool SpawnObjects()
Spawns NetworkIdentities in the scene on the server.
static void SetClientReady(NetworkConnectionToClient conn)
Flags client connection as ready (=joined world).
static Dictionary< int, NetworkConnectionToClient > connections
Dictionary of all server connections, with connectionId as key
static bool AddPlayerForConnection(NetworkConnectionToClient conn, GameObject player)
Called by server after AddPlayer message to add the player for the connection.
static bool active
active checks if the server has been started
static void DestroyPlayerForConnection(NetworkConnectionToClient conn)
Destroys all of the connection's owned objects on the server.
static void Shutdown()
Shuts down the server and disconnects all clients
static void SetAllClientsNotReady()
Marks all connected clients as no longer ready.
Abstract transport layer component