NetworkManager.cs 58 KB

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