NetworkManager.cs 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using kcp2k;
  5. using UnityEngine;
  6. using UnityEngine.SceneManagement;
  7. using UnityEngine.Serialization;
  8. namespace Mirror
  9. {
  10. public enum PlayerSpawnMethod { Random, RoundRobin }
  11. public enum NetworkManagerMode { Offline, ServerOnly, ClientOnly, Host }
  12. [DisallowMultipleComponent]
  13. [AddComponentMenu("Network/Network Manager")]
  14. [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-manager")]
  15. public class NetworkManager : MonoBehaviour
  16. {
  17. /// <summary>Enable to keep NetworkManager alive when changing scenes.</summary>
  18. // This should be set if your game has a single NetworkManager that exists for the lifetime of the process. If there is a NetworkManager in each scene, then this should not be set.</para>
  19. [Header("Configuration")]
  20. [FormerlySerializedAs("m_DontDestroyOnLoad")]
  21. [Tooltip("Should the Network Manager object be persisted through scene changes?")]
  22. public bool dontDestroyOnLoad = true;
  23. /// <summary>Multiplayer games should always run in the background so the network doesn't time out.</summary>
  24. [FormerlySerializedAs("m_RunInBackground")]
  25. [Tooltip("Multiplayer games should always run in the background so the network doesn't time out.")]
  26. public bool runInBackground = true;
  27. /// <summary>Should the server auto-start when 'Server Build' is checked in build settings</summary>
  28. [Tooltip("Should the server auto-start when 'Server Build' is checked in build settings")]
  29. [FormerlySerializedAs("startOnHeadless")]
  30. public bool autoStartServerBuild = true;
  31. /// <summary>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.</summary>
  32. [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.")]
  33. public int serverTickRate = 30;
  34. /// <summary>Automatically switch to this scene upon going offline (on start / on disconnect / on shutdown).</summary>
  35. [Header("Scene Management")]
  36. [Scene]
  37. [FormerlySerializedAs("m_OfflineScene")]
  38. [Tooltip("Scene that Mirror will switch to when the client or server is stopped")]
  39. public string offlineScene = "";
  40. /// <summary>Automatically switch to this scene upon going online (after connect/startserver).</summary>
  41. [Scene]
  42. [FormerlySerializedAs("m_OnlineScene")]
  43. [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.")]
  44. public string onlineScene = "";
  45. // transport layer
  46. [Header("Network Info")]
  47. [Tooltip("Transport component attached to this object that server and client will use to connect")]
  48. [SerializeField]
  49. protected Transport transport;
  50. /// <summary>Server's address for clients to connect to.</summary>
  51. [FormerlySerializedAs("m_NetworkAddress")]
  52. [Tooltip("Network Address where the client should connect to the server. Server does not use this for anything.")]
  53. public string networkAddress = "localhost";
  54. /// <summary>The maximum number of concurrent network connections to support.</summary>
  55. [FormerlySerializedAs("m_MaxConnections")]
  56. [Tooltip("Maximum number of concurrent connections.")]
  57. public int maxConnections = 100;
  58. [Header("Authentication")]
  59. [Tooltip("Authentication component attached to this object")]
  60. public NetworkAuthenticator authenticator;
  61. /// <summary>The default prefab to be used to create player objects on the server.</summary>
  62. // Player objects are created in the default handler for AddPlayer() on
  63. // the server. Implementing OnServerAddPlayer overrides this behaviour.
  64. [Header("Player Object")]
  65. [FormerlySerializedAs("m_PlayerPrefab")]
  66. [Tooltip("Prefab of the player object. Prefab must have a Network Identity component. May be an empty game object or a full avatar.")]
  67. public GameObject playerPrefab;
  68. /// <summary>Enable to automatically create player objects on connect and on scene change.</summary>
  69. [FormerlySerializedAs("m_AutoCreatePlayer")]
  70. [Tooltip("Should Mirror automatically spawn the player after scene change?")]
  71. public bool autoCreatePlayer = true;
  72. /// <summary>Where to spawn players.</summary>
  73. [FormerlySerializedAs("m_PlayerSpawnMethod")]
  74. [Tooltip("Round Robin or Random order of Start Position selection")]
  75. public PlayerSpawnMethod playerSpawnMethod;
  76. /// <summary>Prefabs that can be spawned over the network need to be registered here.</summary>
  77. [FormerlySerializedAs("m_SpawnPrefabs"), HideInInspector]
  78. public List<GameObject> spawnPrefabs = new List<GameObject>();
  79. /// <summary>List of transforms populated by NetworkStartPositions</summary>
  80. public static List<Transform> startPositions = new List<Transform>();
  81. public static int startPositionIndex;
  82. /// <summary>The one and only NetworkManager</summary>
  83. public static NetworkManager singleton { get; internal set; }
  84. /// <summary>Number of active player objects across all connections on the server.</summary>
  85. public int numPlayers => NetworkServer.connections.Count(kv => kv.Value.identity != null);
  86. /// <summary>True if the server is running or client is connected/connecting.</summary>
  87. public bool isNetworkActive => NetworkServer.active || NetworkClient.active;
  88. // TODO remove this
  89. // internal for tests
  90. internal static NetworkConnection clientReadyConnection;
  91. /// <summary>True if the client loaded a new scene when connecting to the server.</summary>
  92. // This is set before OnClientConnect is called, so it can be checked
  93. // there to perform different logic if a scene load occurred.
  94. protected bool clientLoadedScene;
  95. // helper enum to know if we started the networkmanager as server/client/host.
  96. // -> this is necessary because when StartHost changes server scene to
  97. // online scene, FinishLoadScene is called and the host client isn't
  98. // connected yet (no need to connect it before server was fully set up).
  99. // in other words, we need this to know which mode we are running in
  100. // during FinishLoadScene.
  101. public NetworkManagerMode mode { get; private set; }
  102. // virtual so that inheriting classes' OnValidate() can call base.OnValidate() too
  103. public virtual void OnValidate()
  104. {
  105. // always >= 0
  106. maxConnections = Mathf.Max(maxConnections, 0);
  107. if (playerPrefab != null && playerPrefab.GetComponent<NetworkIdentity>() == null)
  108. {
  109. Debug.LogError("NetworkManager - Player Prefab must have a NetworkIdentity.");
  110. playerPrefab = null;
  111. }
  112. // This avoids the mysterious "Replacing existing prefab with assetId ... Old prefab 'Player', New prefab 'Player'" warning.
  113. if (playerPrefab != null && spawnPrefabs.Contains(playerPrefab))
  114. {
  115. Debug.LogWarning("NetworkManager - Player Prefab should not be added to Registered Spawnable Prefabs list...removed it.");
  116. spawnPrefabs.Remove(playerPrefab);
  117. }
  118. }
  119. // virtual so that inheriting classes' Reset() can call base.Reset() too
  120. // Reset only gets called when the component is added or the user resets the component
  121. // Thats why we validate these things that only need to be validated on adding the NetworkManager here
  122. // If we would do it in OnValidate() then it would run this everytime a value changes
  123. public virtual void Reset()
  124. {
  125. // make sure someone doesn't accidentally add another NetworkManager
  126. // need transform.root because when adding to a child, the parent's
  127. // Reset isn't called.
  128. foreach (NetworkManager manager in transform.root.GetComponentsInChildren<NetworkManager>())
  129. {
  130. if (manager != this)
  131. {
  132. 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.");
  133. // return early so that transport component isn't auto-added
  134. // to the duplicate NetworkManager.
  135. return;
  136. }
  137. }
  138. // add transport if there is none yet. makes upgrading easier.
  139. if (transport == null)
  140. {
  141. #if UNITY_EDITOR
  142. // RecordObject needs to be called before we make the change
  143. UnityEditor.Undo.RecordObject(gameObject, "Added default Transport");
  144. #endif
  145. transport = GetComponent<Transport>();
  146. // was a transport added yet? if not, add one
  147. if (transport == null)
  148. {
  149. transport = gameObject.AddComponent<KcpTransport>();
  150. Debug.Log("NetworkManager: added default Transport because there was none yet.");
  151. }
  152. }
  153. }
  154. // virtual so that inheriting classes' Awake() can call base.Awake() too
  155. public virtual void Awake()
  156. {
  157. // Don't allow collision-destroyed second instance to continue.
  158. if (!InitializeSingleton()) return;
  159. Debug.Log("Mirror | mirror-networking.com | discord.gg/N9QVxbM");
  160. // Set the networkSceneName to prevent a scene reload
  161. // if client connection to server fails.
  162. networkSceneName = offlineScene;
  163. // setup OnSceneLoaded callback
  164. SceneManager.sceneLoaded += OnSceneLoaded;
  165. }
  166. // virtual so that inheriting classes' Start() can call base.Start() too
  167. public virtual void Start()
  168. {
  169. // headless mode? then start the server
  170. // can't do this in Awake because Awake is for initialization.
  171. // some transports might not be ready until Start.
  172. //
  173. // (tick rate is applied in StartServer!)
  174. #if UNITY_SERVER
  175. if (autoStartServerBuild)
  176. {
  177. StartServer();
  178. }
  179. #endif
  180. }
  181. // virtual so that inheriting classes' LateUpdate() can call base.LateUpdate() too
  182. public virtual void LateUpdate()
  183. {
  184. UpdateScene();
  185. }
  186. // keep the online scene change check in a separate function
  187. bool IsServerOnlineSceneChangeNeeded()
  188. {
  189. // Only change scene if the requested online scene is not blank, and is not already loaded
  190. return !string.IsNullOrWhiteSpace(onlineScene) && !IsSceneActive(onlineScene) && onlineScene != offlineScene;
  191. }
  192. public static bool IsSceneActive(string scene)
  193. {
  194. Scene activeScene = SceneManager.GetActiveScene();
  195. return activeScene.path == scene || activeScene.name == scene;
  196. }
  197. // full server setup code, without spawning objects yet
  198. void SetupServer()
  199. {
  200. // Debug.Log("NetworkManager SetupServer");
  201. InitializeSingleton();
  202. if (runInBackground)
  203. Application.runInBackground = true;
  204. if (authenticator != null)
  205. {
  206. authenticator.OnStartServer();
  207. authenticator.OnServerAuthenticated.AddListener(OnServerAuthenticated);
  208. }
  209. ConfigureHeadlessFrameRate();
  210. // start listening to network connections
  211. NetworkServer.Listen(maxConnections);
  212. // call OnStartServer AFTER Listen, so that NetworkServer.active is
  213. // true and we can call NetworkServer.Spawn in OnStartServer
  214. // overrides.
  215. // (useful for loading & spawning stuff from database etc.)
  216. //
  217. // note: there is no risk of someone connecting after Listen() and
  218. // before OnStartServer() because this all runs in one thread
  219. // and we don't start processing connects until Update.
  220. OnStartServer();
  221. // this must be after Listen(), since that registers the default message handlers
  222. RegisterServerMessages();
  223. }
  224. /// <summary>Starts the server, listening for incoming connections.</summary>
  225. public void StartServer()
  226. {
  227. if (NetworkServer.active)
  228. {
  229. Debug.LogWarning("Server already started.");
  230. return;
  231. }
  232. mode = NetworkManagerMode.ServerOnly;
  233. // StartServer is inherently ASYNCHRONOUS (=doesn't finish immediately)
  234. //
  235. // Here is what it does:
  236. // Listen
  237. // if onlineScene:
  238. // LoadSceneAsync
  239. // ...
  240. // FinishLoadSceneServerOnly
  241. // SpawnObjects
  242. // else:
  243. // SpawnObjects
  244. //
  245. // there is NO WAY to make it synchronous because both LoadSceneAsync
  246. // and LoadScene do not finish loading immediately. as long as we
  247. // have the onlineScene feature, it will be asynchronous!
  248. SetupServer();
  249. // scene change needed? then change scene and spawn afterwards.
  250. if (IsServerOnlineSceneChangeNeeded())
  251. {
  252. ServerChangeScene(onlineScene);
  253. }
  254. // otherwise spawn directly
  255. else
  256. {
  257. NetworkServer.SpawnObjects();
  258. }
  259. }
  260. /// <summary>Starts the client, connects it to the server with networkAddress.</summary>
  261. public void StartClient()
  262. {
  263. if (NetworkClient.active)
  264. {
  265. Debug.LogWarning("Client already started.");
  266. return;
  267. }
  268. mode = NetworkManagerMode.ClientOnly;
  269. InitializeSingleton();
  270. if (runInBackground)
  271. Application.runInBackground = true;
  272. if (authenticator != null)
  273. {
  274. authenticator.OnStartClient();
  275. authenticator.OnClientAuthenticated.AddListener(OnClientAuthenticated);
  276. }
  277. // In case this is a headless client...
  278. ConfigureHeadlessFrameRate();
  279. RegisterClientMessages();
  280. if (string.IsNullOrWhiteSpace(networkAddress))
  281. {
  282. Debug.LogError("Must set the Network Address field in the manager");
  283. return;
  284. }
  285. // Debug.Log($"NetworkManager StartClient address:{networkAddress}");
  286. NetworkClient.Connect(networkAddress);
  287. OnStartClient();
  288. }
  289. /// <summary>Starts the client, connects it to the server via Uri</summary>
  290. public void StartClient(Uri uri)
  291. {
  292. if (NetworkClient.active)
  293. {
  294. Debug.LogWarning("Client already started.");
  295. return;
  296. }
  297. mode = NetworkManagerMode.ClientOnly;
  298. InitializeSingleton();
  299. if (runInBackground)
  300. Application.runInBackground = true;
  301. if (authenticator != null)
  302. {
  303. authenticator.OnStartClient();
  304. authenticator.OnClientAuthenticated.AddListener(OnClientAuthenticated);
  305. }
  306. RegisterClientMessages();
  307. // Debug.Log($"NetworkManager StartClient address:{uri}");
  308. networkAddress = uri.Host;
  309. NetworkClient.Connect(uri);
  310. OnStartClient();
  311. }
  312. /// <summary>Starts a network "host" - a server and client in the same application.</summary>
  313. public void StartHost()
  314. {
  315. if (NetworkServer.active || NetworkClient.active)
  316. {
  317. Debug.LogWarning("Server or Client already started.");
  318. return;
  319. }
  320. mode = NetworkManagerMode.Host;
  321. // StartHost is inherently ASYNCHRONOUS (=doesn't finish immediately)
  322. //
  323. // Here is what it does:
  324. // Listen
  325. // ConnectHost
  326. // if onlineScene:
  327. // LoadSceneAsync
  328. // ...
  329. // FinishLoadSceneHost
  330. // FinishStartHost
  331. // SpawnObjects
  332. // StartHostClient <= not guaranteed to happen after SpawnObjects if onlineScene is set!
  333. // ClientAuth
  334. // success: server sends changescene msg to client
  335. // else:
  336. // FinishStartHost
  337. //
  338. // there is NO WAY to make it synchronous because both LoadSceneAsync
  339. // and LoadScene do not finish loading immediately. as long as we
  340. // have the onlineScene feature, it will be asynchronous!
  341. // setup server first
  342. SetupServer();
  343. // call OnStartHost AFTER SetupServer. this way we can use
  344. // NetworkServer.Spawn etc. in there too. just like OnStartServer
  345. // is called after the server is actually properly started.
  346. OnStartHost();
  347. // scene change needed? then change scene and spawn afterwards.
  348. // => BEFORE host client connects. if client auth succeeds then the
  349. // server tells it to load 'onlineScene'. we can't do that if
  350. // server is still in 'offlineScene'. so load on server first.
  351. if (IsServerOnlineSceneChangeNeeded())
  352. {
  353. // call FinishStartHost after changing scene.
  354. finishStartHostPending = true;
  355. ServerChangeScene(onlineScene);
  356. }
  357. // otherwise call FinishStartHost directly
  358. else
  359. {
  360. FinishStartHost();
  361. }
  362. }
  363. // This may be set true in StartHost and is evaluated in FinishStartHost
  364. bool finishStartHostPending;
  365. // FinishStartHost is guaranteed to be called after the host server was
  366. // fully started and all the asynchronous StartHost magic is finished
  367. // (= scene loading), or immediately if there was no asynchronous magic.
  368. //
  369. // note: we don't really need FinishStartClient/FinishStartServer. the
  370. // host version is enough.
  371. void FinishStartHost()
  372. {
  373. // ConnectHost needs to be called BEFORE SpawnObjects:
  374. // https://github.com/vis2k/Mirror/pull/1249/
  375. // -> this sets NetworkServer.localConnection.
  376. // -> localConnection needs to be set before SpawnObjects because:
  377. // -> SpawnObjects calls OnStartServer in all NetworkBehaviours
  378. // -> OnStartServer might spawn an object and set [SyncVar(hook="OnColorChanged")] object.color = green;
  379. // -> this calls SyncVar.set (generated by Weaver), which has
  380. // a custom case for host mode (because host mode doesn't
  381. // get OnDeserialize calls, where SyncVar hooks are usually
  382. // called):
  383. //
  384. // if (!SyncVarEqual(value, ref color))
  385. // {
  386. // if (NetworkServer.localClientActive && !getSyncVarHookGuard(1uL))
  387. // {
  388. // setSyncVarHookGuard(1uL, value: true);
  389. // OnColorChangedHook(value);
  390. // setSyncVarHookGuard(1uL, value: false);
  391. // }
  392. // SetSyncVar(value, ref color, 1uL);
  393. // }
  394. //
  395. // -> localClientActive needs to be true, otherwise the hook
  396. // isn't called in host mode!
  397. //
  398. // TODO call this after spawnobjects and worry about the syncvar hook fix later?
  399. NetworkClient.ConnectHost();
  400. // server scene was loaded. now spawn all the objects
  401. NetworkServer.SpawnObjects();
  402. // connect client and call OnStartClient AFTER server scene was
  403. // loaded and all objects were spawned.
  404. // DO NOT do this earlier. it would cause race conditions where a
  405. // client will do things before the server is even fully started.
  406. //Debug.Log("StartHostClient called");
  407. StartHostClient();
  408. }
  409. void StartHostClient()
  410. {
  411. //Debug.Log("NetworkManager ConnectLocalClient");
  412. if (authenticator != null)
  413. {
  414. authenticator.OnStartClient();
  415. authenticator.OnClientAuthenticated.AddListener(OnClientAuthenticated);
  416. }
  417. networkAddress = "localhost";
  418. NetworkServer.ActivateHostScene();
  419. RegisterClientMessages();
  420. // ConnectLocalServer needs to be called AFTER RegisterClientMessages
  421. // (https://github.com/vis2k/Mirror/pull/1249/)
  422. NetworkClient.ConnectLocalServer();
  423. OnStartClient();
  424. }
  425. /// <summary>This stops both the client and the server that the manager is using.</summary>
  426. public void StopHost()
  427. {
  428. OnStopHost();
  429. // calling OnTransportDisconnected was needed to fix
  430. // https://github.com/vis2k/Mirror/issues/1515
  431. // so that the host client receives a DisconnectMessage
  432. // TODO reevaluate if this is still needed after all the disconnect
  433. // fixes, and try to put this into LocalConnection.Disconnect!
  434. NetworkServer.OnTransportDisconnected(NetworkConnection.LocalConnectionId);
  435. StopClient();
  436. StopServer();
  437. }
  438. /// <summary>Stops the server from listening and simulating the game.</summary>
  439. public void StopServer()
  440. {
  441. // return if already stopped to avoid recursion deadlock
  442. if (!NetworkServer.active)
  443. return;
  444. if (authenticator != null)
  445. {
  446. authenticator.OnServerAuthenticated.RemoveListener(OnServerAuthenticated);
  447. authenticator.OnStopServer();
  448. }
  449. // Get Network Manager out of DDOL before going to offline scene
  450. // to avoid collision and let a fresh Network Manager be created.
  451. // IMPORTANT: .gameObject can be null if StopClient is called from
  452. // OnApplicationQuit or from tests!
  453. if (gameObject != null
  454. && gameObject.scene.name == "DontDestroyOnLoad"
  455. && !string.IsNullOrWhiteSpace(offlineScene)
  456. && SceneManager.GetActiveScene().path != offlineScene)
  457. SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene());
  458. OnStopServer();
  459. //Debug.Log("NetworkManager StopServer");
  460. NetworkServer.Shutdown();
  461. // set offline mode BEFORE changing scene so that FinishStartScene
  462. // doesn't think we need initialize anything.
  463. mode = NetworkManagerMode.Offline;
  464. if (!string.IsNullOrWhiteSpace(offlineScene))
  465. {
  466. ServerChangeScene(offlineScene);
  467. }
  468. startPositionIndex = 0;
  469. networkSceneName = "";
  470. }
  471. /// <summary>Stops and disconnects the client.</summary>
  472. public void StopClient()
  473. {
  474. if (mode == NetworkManagerMode.Offline)
  475. return;
  476. if (authenticator != null)
  477. {
  478. authenticator.OnClientAuthenticated.RemoveListener(OnClientAuthenticated);
  479. authenticator.OnStopClient();
  480. }
  481. // Get Network Manager out of DDOL before going to offline scene
  482. // to avoid collision and let a fresh Network Manager be created.
  483. // IMPORTANT: .gameObject can be null if StopClient is called from
  484. // OnApplicationQuit or from tests!
  485. if (gameObject != null
  486. && gameObject.scene.name == "DontDestroyOnLoad"
  487. && !string.IsNullOrWhiteSpace(offlineScene)
  488. && SceneManager.GetActiveScene().path != offlineScene)
  489. SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene());
  490. OnStopClient();
  491. //Debug.Log("NetworkManager StopClient");
  492. // set offline mode BEFORE changing scene so that FinishStartScene
  493. // doesn't think we need initialize anything.
  494. // set offline mode BEFORE NetworkClient.Disconnect so StopClient
  495. // only runs once.
  496. mode = NetworkManagerMode.Offline;
  497. // shutdown client
  498. NetworkClient.Disconnect();
  499. NetworkClient.Shutdown();
  500. // If this is the host player, StopServer will already be changing scenes.
  501. // Check loadingSceneAsync to ensure we don't double-invoke the scene change.
  502. // Check if NetworkServer.active because we can get here via Disconnect before server has started to change scenes.
  503. if (!string.IsNullOrWhiteSpace(offlineScene) && !IsSceneActive(offlineScene) && loadingSceneAsync == null && !NetworkServer.active)
  504. {
  505. ClientChangeScene(offlineScene, SceneOperation.Normal);
  506. }
  507. networkSceneName = "";
  508. }
  509. // called when quitting the application by closing the window / pressing
  510. // stop in the editor. virtual so that inheriting classes'
  511. // OnApplicationQuit() can call base.OnApplicationQuit() too
  512. public virtual void OnApplicationQuit()
  513. {
  514. // stop client first
  515. // (we want to send the quit packet to the server instead of waiting
  516. // for a timeout)
  517. if (NetworkClient.isConnected)
  518. {
  519. StopClient();
  520. //Debug.Log("OnApplicationQuit: stopped client");
  521. }
  522. // stop server after stopping client (for proper host mode stopping)
  523. if (NetworkServer.active)
  524. {
  525. StopServer();
  526. //Debug.Log("OnApplicationQuit: stopped server");
  527. }
  528. // Call ResetStatics to reset statics and singleton
  529. ResetStatics();
  530. }
  531. /// <summary>Set the frame rate for a headless builds. Override to disable or modify.</summary>
  532. // useful for dedicated servers.
  533. // useful for headless benchmark clients.
  534. public virtual void ConfigureHeadlessFrameRate()
  535. {
  536. #if UNITY_SERVER
  537. Application.targetFrameRate = serverTickRate;
  538. // Debug.Log($"Server Tick Rate set to {Application.targetFrameRate} Hz.");
  539. #endif
  540. }
  541. bool InitializeSingleton()
  542. {
  543. if (singleton != null && singleton == this)
  544. return true;
  545. if (dontDestroyOnLoad)
  546. {
  547. if (singleton != null)
  548. {
  549. Debug.LogWarning("Multiple NetworkManagers detected in the scene. Only one NetworkManager can exist at a time. The duplicate NetworkManager will be destroyed.");
  550. Destroy(gameObject);
  551. // Return false to not allow collision-destroyed second instance to continue.
  552. return false;
  553. }
  554. //Debug.Log("NetworkManager created singleton (DontDestroyOnLoad)");
  555. singleton = this;
  556. if (Application.isPlaying)
  557. {
  558. // Force the object to scene root, in case user made it a child of something
  559. // in the scene since DDOL is only allowed for scene root objects
  560. transform.SetParent(null);
  561. DontDestroyOnLoad(gameObject);
  562. }
  563. }
  564. else
  565. {
  566. //Debug.Log("NetworkManager created singleton (ForScene)");
  567. singleton = this;
  568. }
  569. // set active transport AFTER setting singleton.
  570. // so only if we didn't destroy ourselves.
  571. Transport.activeTransport = transport;
  572. return true;
  573. }
  574. void RegisterServerMessages()
  575. {
  576. NetworkServer.OnConnectedEvent = OnServerConnectInternal;
  577. NetworkServer.OnDisconnectedEvent = OnServerDisconnect;
  578. NetworkServer.OnErrorEvent = OnServerError;
  579. NetworkServer.RegisterHandler<AddPlayerMessage>(OnServerAddPlayerInternal);
  580. // Network Server initially registers its own handler for this, so we replace it here.
  581. NetworkServer.ReplaceHandler<ReadyMessage>(OnServerReadyMessageInternal);
  582. }
  583. void RegisterClientMessages()
  584. {
  585. NetworkClient.OnConnectedEvent = OnClientConnectInternal;
  586. NetworkClient.OnDisconnectedEvent = OnClientDisconnectInternal;
  587. NetworkClient.OnErrorEvent = OnClientError;
  588. NetworkClient.RegisterHandler<NotReadyMessage>(OnClientNotReadyMessageInternal);
  589. NetworkClient.RegisterHandler<SceneMessage>(OnClientSceneInternal, false);
  590. if (playerPrefab != null)
  591. NetworkClient.RegisterPrefab(playerPrefab);
  592. foreach (GameObject prefab in spawnPrefabs.Where(t => t != null))
  593. NetworkClient.RegisterPrefab(prefab);
  594. }
  595. // This is the only way to clear the singleton, so another instance can be created.
  596. // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload
  597. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
  598. public static void ResetStatics()
  599. {
  600. // call StopHost if we have a singleton
  601. if (singleton)
  602. singleton.StopHost();
  603. // reset all statics
  604. startPositions.Clear();
  605. startPositionIndex = 0;
  606. clientReadyConnection = null;
  607. loadingSceneAsync = null;
  608. networkSceneName = string.Empty;
  609. // and finally (in case it isn't null already)...
  610. singleton = null;
  611. }
  612. // virtual so that inheriting classes' OnDestroy() can call base.OnDestroy() too
  613. public virtual void OnDestroy()
  614. {
  615. //Debug.Log("NetworkManager destroyed");
  616. }
  617. /// <summary>The name of the current network scene.</summary>
  618. // set by NetworkManager when changing the scene.
  619. // new clients will automatically load this scene.
  620. // Loading a scene manually won't set it.
  621. public static string networkSceneName { get; protected set; } = "";
  622. public static AsyncOperation loadingSceneAsync;
  623. /// <summary>Change the server scene and all client's scenes across the network.</summary>
  624. // Called automatically if onlineScene or offlineScene are set, but it
  625. // can be called from user code to switch scenes again while the game is
  626. // in progress. This automatically sets clients to be not-ready during
  627. // the change and ready again to participate in the new scene.
  628. public virtual void ServerChangeScene(string newSceneName)
  629. {
  630. if (string.IsNullOrWhiteSpace(newSceneName))
  631. {
  632. Debug.LogError("ServerChangeScene empty scene name");
  633. return;
  634. }
  635. if (NetworkServer.isLoadingScene && newSceneName == networkSceneName)
  636. {
  637. Debug.LogError($"Scene change is already in progress for {newSceneName}");
  638. return;
  639. }
  640. // Debug.Log($"ServerChangeScene {newSceneName}");
  641. NetworkServer.SetAllClientsNotReady();
  642. networkSceneName = newSceneName;
  643. // Let server prepare for scene change
  644. OnServerChangeScene(newSceneName);
  645. // set server flag to stop processing messages while changing scenes
  646. // it will be re-enabled in FinishLoadScene.
  647. NetworkServer.isLoadingScene = true;
  648. loadingSceneAsync = SceneManager.LoadSceneAsync(newSceneName);
  649. // ServerChangeScene can be called when stopping the server
  650. // when this happens the server is not active so does not need to tell clients about the change
  651. if (NetworkServer.active)
  652. {
  653. // notify all clients about the new scene
  654. NetworkServer.SendToAll(new SceneMessage { sceneName = newSceneName });
  655. }
  656. startPositionIndex = 0;
  657. startPositions.Clear();
  658. }
  659. // This is only set in ClientChangeScene below...never on server.
  660. // We need to check this in OnClientSceneChanged called from FinishLoadSceneClientOnly
  661. // to prevent AddPlayer message after loading/unloading additive scenes
  662. SceneOperation clientSceneOperation = SceneOperation.Normal;
  663. internal void ClientChangeScene(string newSceneName, SceneOperation sceneOperation = SceneOperation.Normal, bool customHandling = false)
  664. {
  665. if (string.IsNullOrWhiteSpace(newSceneName))
  666. {
  667. Debug.LogError("ClientChangeScene empty scene name");
  668. return;
  669. }
  670. //Debug.Log($"ClientChangeScene newSceneName: {newSceneName} networkSceneName{networkSceneName}");
  671. // Let client prepare for scene change
  672. OnClientChangeScene(newSceneName, sceneOperation, customHandling);
  673. // After calling OnClientChangeScene, exit if server since server is already doing
  674. // the actual scene change, and we don't need to do it for the host client
  675. if (NetworkServer.active)
  676. return;
  677. // set client flag to stop processing messages while loading scenes.
  678. // otherwise we would process messages and then lose all the state
  679. // as soon as the load is finishing, causing all kinds of bugs
  680. // because of missing state.
  681. // (client may be null after StopClient etc.)
  682. // Debug.Log("ClientChangeScene: pausing handlers while scene is loading to avoid data loss after scene was loaded.");
  683. NetworkClient.isLoadingScene = true;
  684. // Cache sceneOperation so we know what was requested by the
  685. // Scene message in OnClientChangeScene and OnClientSceneChanged
  686. clientSceneOperation = sceneOperation;
  687. // scene handling will happen in overrides of OnClientChangeScene and/or OnClientSceneChanged
  688. // Do not call FinishLoadScene here. Custom handler will assign loadingSceneAsync and we need
  689. // to wait for that to finish. UpdateScene already checks for that to be not null and isDone.
  690. if (customHandling)
  691. return;
  692. switch (sceneOperation)
  693. {
  694. case SceneOperation.Normal:
  695. loadingSceneAsync = SceneManager.LoadSceneAsync(newSceneName);
  696. break;
  697. case SceneOperation.LoadAdditive:
  698. // Ensure additive scene is not already loaded on client by name or path
  699. // since we don't know which was passed in the Scene message
  700. if (!SceneManager.GetSceneByName(newSceneName).IsValid() && !SceneManager.GetSceneByPath(newSceneName).IsValid())
  701. loadingSceneAsync = SceneManager.LoadSceneAsync(newSceneName, LoadSceneMode.Additive);
  702. else
  703. {
  704. Debug.LogWarning($"Scene {newSceneName} is already loaded");
  705. // Reset the flag that we disabled before entering this switch
  706. NetworkClient.isLoadingScene = false;
  707. }
  708. break;
  709. case SceneOperation.UnloadAdditive:
  710. // Ensure additive scene is actually loaded on client by name or path
  711. // since we don't know which was passed in the Scene message
  712. if (SceneManager.GetSceneByName(newSceneName).IsValid() || SceneManager.GetSceneByPath(newSceneName).IsValid())
  713. loadingSceneAsync = SceneManager.UnloadSceneAsync(newSceneName, UnloadSceneOptions.UnloadAllEmbeddedSceneObjects);
  714. else
  715. {
  716. Debug.LogWarning($"Cannot unload {newSceneName} with UnloadAdditive operation");
  717. // Reset the flag that we disabled before entering this switch
  718. NetworkClient.isLoadingScene = false;
  719. }
  720. break;
  721. }
  722. // don't change the client's current networkSceneName when loading additive scene content
  723. if (sceneOperation == SceneOperation.Normal)
  724. networkSceneName = newSceneName;
  725. }
  726. // support additive scene loads:
  727. // NetworkScenePostProcess disables all scene objects on load, and
  728. // * NetworkServer.SpawnObjects enables them again on the server when
  729. // calling OnStartServer
  730. // * NetworkClient.PrepareToSpawnSceneObjects enables them again on the
  731. // client after the server sends ObjectSpawnStartedMessage to client
  732. // in SpawnObserversForConnection. this is only called when the
  733. // client joins, so we need to rebuild scene objects manually again
  734. // TODO merge this with FinishLoadScene()?
  735. void OnSceneLoaded(Scene scene, LoadSceneMode mode)
  736. {
  737. if (mode == LoadSceneMode.Additive)
  738. {
  739. if (NetworkServer.active)
  740. {
  741. // TODO only respawn the server objects from that scene later!
  742. NetworkServer.SpawnObjects();
  743. // Debug.Log($"Respawned Server objects after additive scene load: {scene.name}");
  744. }
  745. if (NetworkClient.active)
  746. {
  747. NetworkClient.PrepareToSpawnSceneObjects();
  748. // Debug.Log($"Rebuild Client spawnableObjects after additive scene load: {scene.name}");
  749. }
  750. }
  751. }
  752. void UpdateScene()
  753. {
  754. if (loadingSceneAsync != null && loadingSceneAsync.isDone)
  755. {
  756. //Debug.Log($"ClientChangeScene done readyConn {clientReadyConnection}");
  757. // try-finally to guarantee loadingSceneAsync being cleared.
  758. // fixes https://github.com/vis2k/Mirror/issues/2517 where if
  759. // FinishLoadScene throws an exception, loadingSceneAsync would
  760. // never be cleared and this code would run every Update.
  761. try
  762. {
  763. FinishLoadScene();
  764. }
  765. finally
  766. {
  767. loadingSceneAsync.allowSceneActivation = true;
  768. loadingSceneAsync = null;
  769. }
  770. }
  771. }
  772. protected void FinishLoadScene()
  773. {
  774. // NOTE: this cannot use NetworkClient.allClients[0] - that client may be for a completely different purpose.
  775. // process queued messages that we received while loading the scene
  776. //Debug.Log("FinishLoadScene: resuming handlers after scene was loading.");
  777. NetworkServer.isLoadingScene = false;
  778. NetworkClient.isLoadingScene = false;
  779. // host mode?
  780. if (mode == NetworkManagerMode.Host)
  781. {
  782. FinishLoadSceneHost();
  783. }
  784. // server-only mode?
  785. else if (mode == NetworkManagerMode.ServerOnly)
  786. {
  787. FinishLoadSceneServerOnly();
  788. }
  789. // client-only mode?
  790. else if (mode == NetworkManagerMode.ClientOnly)
  791. {
  792. FinishLoadSceneClientOnly();
  793. }
  794. // otherwise we called it after stopping when loading offline scene.
  795. // do nothing then.
  796. }
  797. // finish load scene part for host mode. makes code easier and is
  798. // necessary for FinishStartHost later.
  799. // (the 3 things have to happen in that exact order)
  800. void FinishLoadSceneHost()
  801. {
  802. // debug message is very important. if we ever break anything then
  803. // it's very obvious to notice.
  804. //Debug.Log("Finished loading scene in host mode.");
  805. if (clientReadyConnection != null)
  806. {
  807. #pragma warning disable 618
  808. // obsolete method calls new method because it's not empty
  809. OnClientConnect(clientReadyConnection);
  810. #pragma warning restore 618
  811. clientLoadedScene = true;
  812. clientReadyConnection = null;
  813. }
  814. // do we need to finish a StartHost() call?
  815. // then call FinishStartHost and let it take care of spawning etc.
  816. if (finishStartHostPending)
  817. {
  818. finishStartHostPending = false;
  819. FinishStartHost();
  820. // call OnServerSceneChanged
  821. OnServerSceneChanged(networkSceneName);
  822. // DO NOT call OnClientSceneChanged here.
  823. // the scene change happened because StartHost loaded the
  824. // server's online scene. it has nothing to do with the client.
  825. // this was not meant as a client scene load, so don't call it.
  826. //
  827. // otherwise AddPlayer would be called twice:
  828. // -> once for client OnConnected
  829. // -> once in OnClientSceneChanged
  830. }
  831. // otherwise we just changed a scene in host mode
  832. else
  833. {
  834. // spawn server objects
  835. NetworkServer.SpawnObjects();
  836. // call OnServerSceneChanged
  837. OnServerSceneChanged(networkSceneName);
  838. if (NetworkClient.isConnected)
  839. {
  840. // let client know that we changed scene
  841. #pragma warning disable 618
  842. // obsolete method calls new method because it's not empty
  843. OnClientSceneChanged(NetworkClient.connection);
  844. #pragma warning restore 618
  845. }
  846. }
  847. }
  848. // finish load scene part for server-only. . makes code easier and is
  849. // necessary for FinishStartServer later.
  850. void FinishLoadSceneServerOnly()
  851. {
  852. // debug message is very important. if we ever break anything then
  853. // it's very obvious to notice.
  854. //Debug.Log("Finished loading scene in server-only mode.");
  855. NetworkServer.SpawnObjects();
  856. OnServerSceneChanged(networkSceneName);
  857. }
  858. // finish load scene part for client-only. makes code easier and is
  859. // necessary for FinishStartClient later.
  860. void FinishLoadSceneClientOnly()
  861. {
  862. // debug message is very important. if we ever break anything then
  863. // it's very obvious to notice.
  864. //Debug.Log("Finished loading scene in client-only mode.");
  865. if (clientReadyConnection != null)
  866. {
  867. #pragma warning disable 618
  868. // obsolete method calls new method because it's not empty
  869. OnClientConnect(clientReadyConnection);
  870. #pragma warning restore 618
  871. clientLoadedScene = true;
  872. clientReadyConnection = null;
  873. }
  874. if (NetworkClient.isConnected)
  875. {
  876. #pragma warning disable 618
  877. // obsolete method calls new method because it's not empty
  878. OnClientSceneChanged(NetworkClient.connection);
  879. #pragma warning restore 618
  880. }
  881. }
  882. /// <summary>
  883. /// Registers the transform of a game object as a player spawn location.
  884. /// <para>This is done automatically by NetworkStartPosition components, but can be done manually from user script code.</para>
  885. /// </summary>
  886. /// <param name="start">Transform to register.</param>
  887. // Static because it's called from NetworkStartPosition::Awake
  888. // and singleton may not exist yet
  889. public static void RegisterStartPosition(Transform start)
  890. {
  891. // Debug.Log($"RegisterStartPosition: {start.gameObject.name} {start.position}");
  892. startPositions.Add(start);
  893. // reorder the list so that round-robin spawning uses the start positions
  894. // in hierarchy order. This assumes all objects with NetworkStartPosition
  895. // component are siblings, either in the scene root or together as children
  896. // under a single parent in the scene.
  897. startPositions = startPositions.OrderBy(transform => transform.GetSiblingIndex()).ToList();
  898. }
  899. /// <summary>Unregister a Transform from start positions.</summary>
  900. // Static because it's called from NetworkStartPosition::OnDestroy
  901. // and singleton may not exist yet
  902. public static void UnRegisterStartPosition(Transform start)
  903. {
  904. //Debug.Log($"UnRegisterStartPosition: {start.name} {start.position}");
  905. startPositions.Remove(start);
  906. }
  907. /// <summary>Get the next NetworkStartPosition based on the selected PlayerSpawnMethod.</summary>
  908. public Transform GetStartPosition()
  909. {
  910. // first remove any dead transforms
  911. startPositions.RemoveAll(t => t == null);
  912. if (startPositions.Count == 0)
  913. return null;
  914. if (playerSpawnMethod == PlayerSpawnMethod.Random)
  915. {
  916. return startPositions[UnityEngine.Random.Range(0, startPositions.Count)];
  917. }
  918. else
  919. {
  920. Transform startPosition = startPositions[startPositionIndex];
  921. startPositionIndex = (startPositionIndex + 1) % startPositions.Count;
  922. return startPosition;
  923. }
  924. }
  925. void OnServerConnectInternal(NetworkConnectionToClient conn)
  926. {
  927. //Debug.Log("NetworkManager.OnServerConnectInternal");
  928. if (authenticator != null)
  929. {
  930. // we have an authenticator - let it handle authentication
  931. authenticator.OnServerAuthenticate(conn);
  932. }
  933. else
  934. {
  935. // authenticate immediately
  936. OnServerAuthenticated(conn);
  937. }
  938. }
  939. // called after successful authentication
  940. // TODO do the NetworkServer.OnAuthenticated thing from x branch
  941. void OnServerAuthenticated(NetworkConnectionToClient conn)
  942. {
  943. //Debug.Log("NetworkManager.OnServerAuthenticated");
  944. // set connection to authenticated
  945. conn.isAuthenticated = true;
  946. // proceed with the login handshake by calling OnServerConnect
  947. if (networkSceneName != "" && networkSceneName != offlineScene)
  948. {
  949. SceneMessage msg = new SceneMessage() { sceneName = networkSceneName };
  950. conn.Send(msg);
  951. }
  952. OnServerConnect(conn);
  953. }
  954. void OnServerReadyMessageInternal(NetworkConnectionToClient conn, ReadyMessage msg)
  955. {
  956. //Debug.Log("NetworkManager.OnServerReadyMessageInternal");
  957. OnServerReady(conn);
  958. }
  959. void OnServerAddPlayerInternal(NetworkConnectionToClient conn, AddPlayerMessage msg)
  960. {
  961. //Debug.Log("NetworkManager.OnServerAddPlayer");
  962. if (autoCreatePlayer && playerPrefab == null)
  963. {
  964. Debug.LogError("The PlayerPrefab is empty on the NetworkManager. Please setup a PlayerPrefab object.");
  965. return;
  966. }
  967. if (autoCreatePlayer && playerPrefab.GetComponent<NetworkIdentity>() == null)
  968. {
  969. Debug.LogError("The PlayerPrefab does not have a NetworkIdentity. Please add a NetworkIdentity to the player prefab.");
  970. return;
  971. }
  972. if (conn.identity != null)
  973. {
  974. Debug.LogError("There is already a player for this connection.");
  975. return;
  976. }
  977. OnServerAddPlayer(conn);
  978. }
  979. void OnClientConnectInternal()
  980. {
  981. //Debug.Log("NetworkManager.OnClientConnectInternal");
  982. if (authenticator != null)
  983. {
  984. // we have an authenticator - let it handle authentication
  985. authenticator.OnClientAuthenticate();
  986. }
  987. else
  988. {
  989. // authenticate immediately
  990. OnClientAuthenticated();
  991. }
  992. }
  993. // called after successful authentication
  994. void OnClientAuthenticated()
  995. {
  996. //Debug.Log("NetworkManager.OnClientAuthenticated");
  997. // set connection to authenticated
  998. NetworkClient.connection.isAuthenticated = true;
  999. // proceed with the login handshake by calling OnClientConnect
  1000. if (string.IsNullOrWhiteSpace(onlineScene) || onlineScene == offlineScene || IsSceneActive(onlineScene))
  1001. {
  1002. clientLoadedScene = false;
  1003. #pragma warning disable 618
  1004. // obsolete method calls new method because it's not empty
  1005. OnClientConnect(NetworkClient.connection);
  1006. #pragma warning restore 618
  1007. }
  1008. else
  1009. {
  1010. // will wait for scene id to come from the server.
  1011. clientLoadedScene = true;
  1012. clientReadyConnection = NetworkClient.connection;
  1013. }
  1014. }
  1015. void OnClientDisconnectInternal()
  1016. {
  1017. //Debug.Log("NetworkManager.OnClientDisconnectInternal");
  1018. #pragma warning disable 618
  1019. // obsolete method calls new method because it's not empty
  1020. OnClientDisconnect(NetworkClient.connection);
  1021. #pragma warning restore 618
  1022. }
  1023. void OnClientNotReadyMessageInternal(NotReadyMessage msg)
  1024. {
  1025. //Debug.Log("NetworkManager.OnClientNotReadyMessageInternal");
  1026. NetworkClient.ready = false;
  1027. #pragma warning disable 618
  1028. OnClientNotReady(NetworkClient.connection);
  1029. #pragma warning restore 618
  1030. OnClientNotReady();
  1031. // NOTE: clientReadyConnection is not set here! don't want OnClientConnect to be invoked again after scene changes.
  1032. }
  1033. void OnClientSceneInternal(SceneMessage msg)
  1034. {
  1035. //Debug.Log("NetworkManager.OnClientSceneInternal");
  1036. // This needs to run for host client too. NetworkServer.active is checked there
  1037. if (NetworkClient.isConnected)
  1038. {
  1039. ClientChangeScene(msg.sceneName, msg.sceneOperation, msg.customHandling);
  1040. }
  1041. }
  1042. /// <summary>Called on the server when a new client connects.</summary>
  1043. public virtual void OnServerConnect(NetworkConnectionToClient conn) {}
  1044. /// <summary>Called on the server when a client disconnects.</summary>
  1045. // Called by NetworkServer.OnTransportDisconnect!
  1046. public virtual void OnServerDisconnect(NetworkConnectionToClient conn)
  1047. {
  1048. // by default, this function destroys the connection's player.
  1049. // can be overwritten for cases like delayed logouts in MMOs to
  1050. // avoid players escaping from PvP situations by logging out.
  1051. NetworkServer.DestroyPlayerForConnection(conn);
  1052. //Debug.Log("OnServerDisconnect: Client disconnected.");
  1053. }
  1054. /// <summary>Called on the server when a client is ready (= loaded the scene)</summary>
  1055. public virtual void OnServerReady(NetworkConnectionToClient conn)
  1056. {
  1057. if (conn.identity == null)
  1058. {
  1059. // this is now allowed (was not for a while)
  1060. //Debug.Log("Ready with no player object");
  1061. }
  1062. NetworkServer.SetClientReady(conn);
  1063. }
  1064. /// <summary>Called on server when a client requests to add the player. Adds playerPrefab by default. Can be overwritten.</summary>
  1065. // The default implementation for this function creates a new player object from the playerPrefab.
  1066. public virtual void OnServerAddPlayer(NetworkConnectionToClient conn)
  1067. {
  1068. Transform startPos = GetStartPosition();
  1069. GameObject player = startPos != null
  1070. ? Instantiate(playerPrefab, startPos.position, startPos.rotation)
  1071. : Instantiate(playerPrefab);
  1072. // instantiating a "Player" prefab gives it the name "Player(clone)"
  1073. // => appending the connectionId is WAY more useful for debugging!
  1074. player.name = $"{playerPrefab.name} [connId={conn.connectionId}]";
  1075. NetworkServer.AddPlayerForConnection(conn, player);
  1076. }
  1077. /// <summary>Called on server when transport raises an exception. NetworkConnection may be null.</summary>
  1078. public virtual void OnServerError(NetworkConnectionToClient conn, Exception exception) {}
  1079. /// <summary>Called from ServerChangeScene immediately before SceneManager.LoadSceneAsync is executed</summary>
  1080. public virtual void OnServerChangeScene(string newSceneName) {}
  1081. /// <summary>Called on server after a scene load with ServerChangeScene() is completed.</summary>
  1082. public virtual void OnServerSceneChanged(string sceneName) {}
  1083. /// <summary>Called on the client when connected to a server. By default it sets client as ready and adds a player.</summary>
  1084. public virtual void OnClientConnect()
  1085. {
  1086. // OnClientConnect by default calls AddPlayer but it should not do
  1087. // that when we have online/offline scenes. so we need the
  1088. // clientLoadedScene flag to prevent it.
  1089. if (!clientLoadedScene)
  1090. {
  1091. // Ready/AddPlayer is usually triggered by a scene load completing.
  1092. // if no scene was loaded, then Ready/AddPlayer it here instead.
  1093. if (!NetworkClient.ready)
  1094. NetworkClient.Ready();
  1095. if (autoCreatePlayer)
  1096. NetworkClient.AddPlayer();
  1097. }
  1098. }
  1099. // Deprecated 2021-12-11
  1100. [Obsolete("Remove the NetworkConnection parameter in your override and use NetworkClient.connection instead.")]
  1101. public virtual void OnClientConnect(NetworkConnection conn) => OnClientConnect();
  1102. /// <summary>Called on clients when disconnected from a server.</summary>
  1103. public virtual void OnClientDisconnect()
  1104. {
  1105. if (mode == NetworkManagerMode.Offline)
  1106. return;
  1107. StopClient();
  1108. }
  1109. // Deprecated 2021-12-11
  1110. [Obsolete("Remove the NetworkConnection parameter in your override and use NetworkClient.connection instead.")]
  1111. public virtual void OnClientDisconnect(NetworkConnection conn) => OnClientDisconnect();
  1112. /// <summary>Called on client when transport raises an exception.</summary>
  1113. public virtual void OnClientError(Exception exception) {}
  1114. /// <summary>Called on clients when a servers tells the client it is no longer ready, e.g. when switching scenes.</summary>
  1115. public virtual void OnClientNotReady() {}
  1116. // Deprecated 2021-12-11
  1117. [Obsolete("Remove the NetworkConnection parameter in your override and use NetworkClient.connection instead.")]
  1118. public virtual void OnClientNotReady(NetworkConnection conn) {}
  1119. /// <summary>Called from ClientChangeScene immediately before SceneManager.LoadSceneAsync is executed</summary>
  1120. // customHandling: indicates if scene loading will be handled through overrides
  1121. public virtual void OnClientChangeScene(string newSceneName, SceneOperation sceneOperation, bool customHandling) {}
  1122. /// <summary>Called on clients when a scene has completed loaded, when the scene load was initiated by the server.</summary>
  1123. // Scene changes can cause player objects to be destroyed. The default
  1124. // implementation of OnClientSceneChanged in the NetworkManager is to
  1125. // add a player object for the connection if no player object exists.
  1126. public virtual void OnClientSceneChanged()
  1127. {
  1128. // always become ready.
  1129. if (!NetworkClient.ready) NetworkClient.Ready();
  1130. // Only call AddPlayer for normal scene changes, not additive load/unload
  1131. if (clientSceneOperation == SceneOperation.Normal && autoCreatePlayer && NetworkClient.localPlayer == null)
  1132. {
  1133. // add player if existing one is null
  1134. NetworkClient.AddPlayer();
  1135. }
  1136. }
  1137. // Deprecated 2021-12-11
  1138. [Obsolete("Remove the NetworkConnection parameter in your override and use NetworkClient.connection instead.")]
  1139. public virtual void OnClientSceneChanged(NetworkConnection conn) => OnClientSceneChanged();
  1140. // Since there are multiple versions of StartServer, StartClient and
  1141. // StartHost, to reliably customize their functionality, users would
  1142. // need override all the versions. Instead these callbacks are invoked
  1143. // from all versions, so users only need to implement this one case.
  1144. /// <summary>This is invoked when a host is started.</summary>
  1145. public virtual void OnStartHost() {}
  1146. /// <summary>This is invoked when a server is started - including when a host is started.</summary>
  1147. public virtual void OnStartServer() {}
  1148. /// <summary>This is invoked when the client is started.</summary>
  1149. public virtual void OnStartClient() {}
  1150. /// <summary>This is called when a server is stopped - including when a host is stopped.</summary>
  1151. public virtual void OnStopServer() {}
  1152. /// <summary>This is called when a client is stopped.</summary>
  1153. public virtual void OnStopClient() {}
  1154. /// <summary>This is called when a host is stopped.</summary>
  1155. public virtual void OnStopHost() {}
  1156. }
  1157. }