NetworkManager.cs 58 KB

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