NetworkServer.cs 85 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Mirror.RemoteCalls;
  5. using UnityEngine;
  6. namespace Mirror
  7. {
  8. /// <summary>NetworkServer handles remote connections and has a local connection for a local client.</summary>
  9. public static partial class NetworkServer
  10. {
  11. static bool initialized;
  12. public static int maxConnections;
  13. /// <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>
  14. // overwritten by NetworkManager (if any)
  15. public static int tickRate = 60;
  16. // tick rate is in Hz.
  17. // convert to interval in seconds for convenience where needed.
  18. //
  19. // send interval is 1 / sendRate.
  20. // but for tests we need a way to set it to exactly 0.
  21. // 1 / int.max would not be exactly 0, so handel that manually.
  22. public static float tickInterval => tickRate < int.MaxValue ? 1f / tickRate : 0; // for 30 Hz, that's 33ms
  23. // time & value snapshot interpolation are separate.
  24. // -> time is interpolated globally on NetworkClient / NetworkConnection
  25. // -> value is interpolated per-component, i.e. NetworkTransform.
  26. // however, both need to be on the same send interval.
  27. public static int sendRate => tickRate;
  28. public static float sendInterval => sendRate < int.MaxValue ? 1f / sendRate : 0; // for 30 Hz, that's 33ms
  29. static double lastSendTime;
  30. /// <summary>Connection to host mode client (if any)</summary>
  31. public static LocalConnectionToClient localConnection { get; private set; }
  32. /// <summary>Dictionary of all server connections, with connectionId as key</summary>
  33. public static Dictionary<int, NetworkConnectionToClient> connections =
  34. new Dictionary<int, NetworkConnectionToClient>();
  35. /// <summary>Message Handlers dictionary, with messageId as key</summary>
  36. internal static Dictionary<ushort, NetworkMessageDelegate> handlers =
  37. new Dictionary<ushort, NetworkMessageDelegate>();
  38. /// <summary>All spawned NetworkIdentities by netId.</summary>
  39. // server sees ALL spawned ones.
  40. public static readonly Dictionary<uint, NetworkIdentity> spawned =
  41. new Dictionary<uint, NetworkIdentity>();
  42. /// <summary>Single player mode can use dontListen to not accept incoming connections</summary>
  43. // see also: https://github.com/vis2k/Mirror/pull/2595
  44. public static bool dontListen;
  45. /// <summary>active checks if the server has been started either has standalone or as host server.</summary>
  46. public static bool active { get; internal set; }
  47. /// <summary>active checks if the server has been started in host mode.</summary>
  48. // naming consistent with NetworkClient.activeHost.
  49. public static bool activeHost => localConnection != null;
  50. // scene loading
  51. public static bool isLoadingScene;
  52. // interest management component (optional)
  53. // by default, everyone observes everyone
  54. public static InterestManagementBase aoi;
  55. // For security, it is recommended to disconnect a player if a networked
  56. // action triggers an exception\nThis could prevent components being
  57. // accessed in an undefined state, which may be an attack vector for
  58. // exploits.
  59. //
  60. // However, some games may want to allow exceptions in order to not
  61. // interrupt the player's experience.
  62. public static bool exceptionsDisconnect = true; // security by default
  63. // Mirror global disconnect inactive option, independent of Transport.
  64. // not all Transports do this properly, and it's easiest to configure this just once.
  65. // this is very useful for some projects, keep it.
  66. public static bool disconnectInactiveConnections;
  67. public static float disconnectInactiveTimeout = 60;
  68. // OnConnected / OnDisconnected used to be NetworkMessages that were
  69. // invoked. this introduced a bug where external clients could send
  70. // Connected/Disconnected messages over the network causing undefined
  71. // behaviour.
  72. // => public so that custom NetworkManagers can hook into it
  73. public static Action<NetworkConnectionToClient> OnConnectedEvent;
  74. public static Action<NetworkConnectionToClient> OnDisconnectedEvent;
  75. public static Action<NetworkConnectionToClient, TransportError, string> OnErrorEvent;
  76. // keep track of actual achieved tick rate.
  77. // might become lower under heavy load.
  78. // very useful for profiling etc.
  79. // measured over 1s each, same as frame rate. no EMA here.
  80. public static int actualTickRate;
  81. static double actualTickRateStart; // start time when counting
  82. static int actualTickRateCounter; // current counter since start
  83. // profiling
  84. // includes transport update time, because transport calls handlers etc.
  85. // averaged over 1s by passing 'tickRate' to constructor.
  86. public static TimeSample earlyUpdateDuration;
  87. public static TimeSample lateUpdateDuration;
  88. // capture full Unity update time from before Early- to after LateUpdate
  89. public static TimeSample fullUpdateDuration;
  90. /// <summary>Starts server and listens to incoming connections with max connections limit.</summary>
  91. public static void Listen(int maxConns)
  92. {
  93. Initialize();
  94. maxConnections = maxConns;
  95. // only start server if we want to listen
  96. if (!dontListen)
  97. {
  98. Transport.active.ServerStart();
  99. if (Transport.active is PortTransport portTransport)
  100. {
  101. if (Utils.IsHeadless())
  102. {
  103. #if !UNITY_EDITOR
  104. Console.ForegroundColor = ConsoleColor.Green;
  105. Console.WriteLine($"Server listening on port {portTransport.Port}");
  106. Console.ResetColor();
  107. #else
  108. Debug.Log($"Server listening on port {portTransport.Port}");
  109. #endif
  110. }
  111. }
  112. else
  113. Debug.Log("Server started listening");
  114. }
  115. active = true;
  116. RegisterMessageHandlers();
  117. }
  118. // initialization / shutdown ///////////////////////////////////////////
  119. static void Initialize()
  120. {
  121. if (initialized)
  122. return;
  123. // safety: ensure Weaving succeded.
  124. // if it silently failed, we would get lots of 'writer not found'
  125. // and other random errors at runtime instead. this is cleaner.
  126. if (!WeaverFuse.Weaved())
  127. {
  128. // if it failed, throw an exception to early exit all Listen calls.
  129. throw new Exception("NetworkServer won't start because Weaving failed or didn't run.");
  130. }
  131. // Debug.Log($"NetworkServer Created version {Version.Current}");
  132. //Make sure connections are cleared in case any old connections references exist from previous sessions
  133. connections.Clear();
  134. // reset Interest Management so that rebuild intervals
  135. // start at 0 when starting again.
  136. if (aoi != null) aoi.Reset();
  137. // reset NetworkTime
  138. NetworkTime.ResetStatics();
  139. Debug.Assert(Transport.active != null, "There was no active transport when calling NetworkServer.Listen, If you are calling Listen manually then make sure to set 'Transport.active' first");
  140. AddTransportHandlers();
  141. initialized = true;
  142. // profiling
  143. earlyUpdateDuration = new TimeSample(sendRate);
  144. lateUpdateDuration = new TimeSample(sendRate);
  145. fullUpdateDuration = new TimeSample(sendRate);
  146. }
  147. static void AddTransportHandlers()
  148. {
  149. // += so that other systems can also hook into it (i.e. statistics)
  150. Transport.active.OnServerConnected += OnTransportConnected;
  151. Transport.active.OnServerDataReceived += OnTransportData;
  152. Transport.active.OnServerDisconnected += OnTransportDisconnected;
  153. Transport.active.OnServerError += OnTransportError;
  154. }
  155. /// <summary>Shuts down the server and disconnects all clients</summary>
  156. // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload
  157. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
  158. public static void Shutdown()
  159. {
  160. if (initialized)
  161. {
  162. DisconnectAll();
  163. // stop the server.
  164. // we do NOT call Transport.Shutdown, because someone only
  165. // called NetworkServer.Shutdown. we can't assume that the
  166. // client is supposed to be shut down too!
  167. //
  168. // NOTE: stop no matter what, even if 'dontListen':
  169. // someone might enabled dontListen at runtime.
  170. // but we still need to stop the server.
  171. // fixes https://github.com/vis2k/Mirror/issues/2536
  172. Transport.active.ServerStop();
  173. // transport handlers are hooked into when initializing.
  174. // so only remove them when shutting down.
  175. RemoveTransportHandlers();
  176. initialized = false;
  177. }
  178. // Reset all statics here....
  179. dontListen = false;
  180. isLoadingScene = false;
  181. lastSendTime = 0;
  182. actualTickRate = 0;
  183. localConnection = null;
  184. connections.Clear();
  185. connectionsCopy.Clear();
  186. handlers.Clear();
  187. // destroy all spawned objects, _then_ set inactive.
  188. // make sure .active is still true before calling this.
  189. // otherwise modifying SyncLists in OnStopServer would throw
  190. // because .IsWritable() check checks if NetworkServer.active.
  191. // https://github.com/MirrorNetworking/Mirror/issues/3344
  192. CleanupSpawned();
  193. active = false;
  194. // sets nextNetworkId to 1
  195. // sets clientAuthorityCallback to null
  196. // sets previousLocalPlayer to null
  197. NetworkIdentity.ResetStatics();
  198. // clear events. someone might have hooked into them before, but
  199. // we don't want to use those hooks after Shutdown anymore.
  200. OnConnectedEvent = null;
  201. OnDisconnectedEvent = null;
  202. OnErrorEvent = null;
  203. if (aoi != null) aoi.Reset();
  204. }
  205. static void RemoveTransportHandlers()
  206. {
  207. // -= so that other systems can also hook into it (i.e. statistics)
  208. Transport.active.OnServerConnected -= OnTransportConnected;
  209. Transport.active.OnServerDataReceived -= OnTransportData;
  210. Transport.active.OnServerDisconnected -= OnTransportDisconnected;
  211. Transport.active.OnServerError -= OnTransportError;
  212. }
  213. // Note: NetworkClient.DestroyAllClientObjects does the same on client.
  214. static void CleanupSpawned()
  215. {
  216. // iterate a COPY of spawned.
  217. // DestroyObject removes them from the original collection.
  218. // removing while iterating is not allowed.
  219. foreach (NetworkIdentity identity in spawned.Values.ToList())
  220. {
  221. if (identity != null)
  222. {
  223. // scene object
  224. if (identity.sceneId != 0)
  225. {
  226. // spawned scene objects are unspawned and reset.
  227. // afterwards we disable them again.
  228. // (they always stay in the scene, we don't destroy them)
  229. DestroyObject(identity, DestroyMode.Reset);
  230. identity.gameObject.SetActive(false);
  231. }
  232. // spawned prefabs
  233. else
  234. {
  235. // spawned prefabs are unspawned and destroyed.
  236. DestroyObject(identity, DestroyMode.Destroy);
  237. }
  238. }
  239. }
  240. spawned.Clear();
  241. }
  242. internal static void RegisterMessageHandlers()
  243. {
  244. RegisterHandler<ReadyMessage>(OnClientReadyMessage);
  245. RegisterHandler<CommandMessage>(OnCommandMessage);
  246. RegisterHandler<NetworkPingMessage>(NetworkTime.OnServerPing, false);
  247. RegisterHandler<NetworkPongMessage>(NetworkTime.OnServerPong, false);
  248. RegisterHandler<EntityStateMessage>(OnEntityStateMessage, true);
  249. RegisterHandler<TimeSnapshotMessage>(OnTimeSnapshotMessage, true);
  250. }
  251. // remote calls ////////////////////////////////////////////////////////
  252. // Handle command from specific player, this could be one of multiple
  253. // players on a single client
  254. // default ready handler.
  255. static void OnClientReadyMessage(NetworkConnectionToClient conn, ReadyMessage msg)
  256. {
  257. // Debug.Log($"Default handler for ready message from {conn}");
  258. SetClientReady(conn);
  259. }
  260. static void OnCommandMessage(NetworkConnectionToClient conn, CommandMessage msg, int channelId)
  261. {
  262. if (!conn.isReady)
  263. {
  264. // Clients may be set NotReady due to scene change or other game logic by user, e.g. respawning.
  265. // Ignore commands that may have been in flight before client received NotReadyMessage message.
  266. // Unreliable messages may be out of order, so don't spam warnings for those.
  267. if (channelId == Channels.Reliable)
  268. Debug.LogWarning("Command received while client is not ready.\nThis may be ignored if client intentionally set NotReady.");
  269. return;
  270. }
  271. if (!spawned.TryGetValue(msg.netId, out NetworkIdentity identity))
  272. {
  273. // over reliable channel, commands should always come after spawn.
  274. // over unreliable, they might come in before the object was spawned.
  275. // for example, NetworkTransform.
  276. // let's not spam the console for unreliable out of order messages.
  277. if (channelId == Channels.Reliable)
  278. Debug.LogWarning($"Spawned object not found when handling Command message [netId={msg.netId}]");
  279. return;
  280. }
  281. // Commands can be for player objects, OR other objects with client-authority
  282. // -> so if this connection's controller has a different netId then
  283. // only allow the command if clientAuthorityOwner
  284. bool requiresAuthority = RemoteProcedureCalls.CommandRequiresAuthority(msg.functionHash);
  285. if (requiresAuthority && identity.connectionToClient != conn)
  286. {
  287. Debug.LogWarning($"Command for object without authority [netId={msg.netId}]");
  288. return;
  289. }
  290. // Debug.Log($"OnCommandMessage for netId:{msg.netId} conn:{conn}");
  291. using (NetworkReaderPooled networkReader = NetworkReaderPool.Get(msg.payload))
  292. identity.HandleRemoteCall(msg.componentIndex, msg.functionHash, RemoteCallType.Command, networkReader, conn);
  293. }
  294. // client to server broadcast //////////////////////////////////////////
  295. // for client's owned ClientToServer components.
  296. static void OnEntityStateMessage(NetworkConnectionToClient connection, EntityStateMessage message)
  297. {
  298. // need to validate permissions carefully.
  299. // an attacker may attempt to modify a not-owned or not-ClientToServer component.
  300. // valid netId?
  301. if (spawned.TryGetValue(message.netId, out NetworkIdentity identity) && identity != null)
  302. {
  303. // owned by the connection?
  304. if (identity.connectionToClient == connection)
  305. {
  306. using (NetworkReaderPooled reader = NetworkReaderPool.Get(message.payload))
  307. {
  308. // DeserializeServer checks permissions internally.
  309. // failure to deserialize disconnects to prevent exploits.
  310. if (!identity.DeserializeServer(reader))
  311. {
  312. Debug.LogWarning($"Server failed to deserialize client state for {identity.name} with netId={identity.netId}, Disconnecting.");
  313. connection.Disconnect();
  314. }
  315. }
  316. }
  317. // An attacker may attempt to modify another connection's entity
  318. // This could also be a race condition of message in flight when
  319. // RemoveClientAuthority is called, so not malicious.
  320. // Don't disconnect, just log the warning.
  321. else
  322. Debug.LogWarning($"EntityStateMessage from {connection} for {identity} without authority.");
  323. }
  324. // no warning. don't spam server logs.
  325. // else Debug.LogWarning($"Did not find target for sync message for {message.netId} . Note: this can be completely normal because UDP messages may arrive out of order, so this message might have arrived after a Destroy message.");
  326. }
  327. // client sends TimeSnapshotMessage every sendInterval.
  328. // batching already includes the remoteTimestamp.
  329. // we simply insert it on-message here.
  330. // => only for reliable channel. unreliable would always arrive earlier.
  331. static void OnTimeSnapshotMessage(NetworkConnectionToClient connection, TimeSnapshotMessage _)
  332. {
  333. // insert another snapshot for snapshot interpolation.
  334. // before calling OnDeserialize so components can use
  335. // NetworkTime.time and NetworkTime.timeStamp.
  336. // TODO validation?
  337. // maybe we shouldn't allow timeline to deviate more than a certain %.
  338. // for now, this is only used for client authority movement.
  339. // Unity 2019 doesn't have Time.timeAsDouble yet
  340. //
  341. // NetworkTime uses unscaled time and ignores Time.timeScale.
  342. // fixes Time.timeScale getting server & client time out of sync:
  343. // https://github.com/MirrorNetworking/Mirror/issues/3409
  344. connection.OnTimeSnapshot(new TimeSnapshot(connection.remoteTimeStamp, NetworkTime.localTime));
  345. }
  346. // connections /////////////////////////////////////////////////////////
  347. /// <summary>Add a connection and setup callbacks. Returns true if not added yet.</summary>
  348. public static bool AddConnection(NetworkConnectionToClient conn)
  349. {
  350. if (!connections.ContainsKey(conn.connectionId))
  351. {
  352. // connection cannot be null here or conn.connectionId
  353. // would throw NRE
  354. connections[conn.connectionId] = conn;
  355. return true;
  356. }
  357. // already a connection with this id
  358. return false;
  359. }
  360. /// <summary>Removes a connection by connectionId. Returns true if removed.</summary>
  361. public static bool RemoveConnection(int connectionId) =>
  362. connections.Remove(connectionId);
  363. // called by LocalClient to add itself. don't call directly.
  364. // TODO consider internal setter instead?
  365. internal static void SetLocalConnection(LocalConnectionToClient conn)
  366. {
  367. if (localConnection != null)
  368. {
  369. Debug.LogError("Local Connection already exists");
  370. return;
  371. }
  372. localConnection = conn;
  373. }
  374. // removes local connection to client
  375. internal static void RemoveLocalConnection()
  376. {
  377. if (localConnection != null)
  378. {
  379. localConnection.Disconnect();
  380. localConnection = null;
  381. }
  382. RemoveConnection(0);
  383. }
  384. /// <summary>True if we have external connections (that are not host)</summary>
  385. public static bool HasExternalConnections()
  386. {
  387. // any connections?
  388. if (connections.Count > 0)
  389. {
  390. // only host connection?
  391. if (connections.Count == 1 && localConnection != null)
  392. return false;
  393. // otherwise we have real external connections
  394. return true;
  395. }
  396. return false;
  397. }
  398. // send ////////////////////////////////////////////////////////////////
  399. /// <summary>Send a message to all clients, even those that haven't joined the world yet (non ready)</summary>
  400. public static void SendToAll<T>(T message, int channelId = Channels.Reliable, bool sendToReadyOnly = false)
  401. where T : struct, NetworkMessage
  402. {
  403. if (!active)
  404. {
  405. Debug.LogWarning("Can not send using NetworkServer.SendToAll<T>(T msg) because NetworkServer is not active");
  406. return;
  407. }
  408. // Debug.Log($"Server.SendToAll {typeof(T)}");
  409. using (NetworkWriterPooled writer = NetworkWriterPool.Get())
  410. {
  411. // pack message only once
  412. NetworkMessages.Pack(message, writer);
  413. ArraySegment<byte> segment = writer.ToArraySegment();
  414. // filter and then send to all internet connections at once
  415. // -> makes code more complicated, but is HIGHLY worth it to
  416. // avoid allocations, allow for multicast, etc.
  417. int count = 0;
  418. foreach (NetworkConnectionToClient conn in connections.Values)
  419. {
  420. if (sendToReadyOnly && !conn.isReady)
  421. continue;
  422. count++;
  423. conn.Send(segment, channelId);
  424. }
  425. NetworkDiagnostics.OnSend(message, channelId, segment.Count, count);
  426. }
  427. }
  428. /// <summary>Send a message to all clients which have joined the world (are ready).</summary>
  429. // TODO put rpcs into NetworkServer.Update WorldState packet, then finally remove SendToReady!
  430. public static void SendToReady<T>(T message, int channelId = Channels.Reliable)
  431. where T : struct, NetworkMessage
  432. {
  433. if (!active)
  434. {
  435. Debug.LogWarning("Can not send using NetworkServer.SendToReady<T>(T msg) because NetworkServer is not active");
  436. return;
  437. }
  438. SendToAll(message, channelId, true);
  439. }
  440. // this is like SendToReadyObservers - but it doesn't check the ready flag on the connection.
  441. // this is used for ObjectDestroy messages.
  442. static void SendToObservers<T>(NetworkIdentity identity, T message, int channelId = Channels.Reliable)
  443. where T : struct, NetworkMessage
  444. {
  445. // Debug.Log($"Server.SendToObservers {typeof(T)}");
  446. if (identity == null || identity.observers.Count == 0)
  447. return;
  448. using (NetworkWriterPooled writer = NetworkWriterPool.Get())
  449. {
  450. // pack message into byte[] once
  451. NetworkMessages.Pack(message, writer);
  452. ArraySegment<byte> segment = writer.ToArraySegment();
  453. foreach (NetworkConnectionToClient conn in identity.observers.Values)
  454. {
  455. conn.Send(segment, channelId);
  456. }
  457. NetworkDiagnostics.OnSend(message, channelId, segment.Count, identity.observers.Count);
  458. }
  459. }
  460. /// <summary>Send a message to only clients which are ready with option to include the owner of the object identity</summary>
  461. // TODO obsolete this later. it's not used anymore
  462. public static void SendToReadyObservers<T>(NetworkIdentity identity, T message, bool includeOwner = true, int channelId = Channels.Reliable)
  463. where T : struct, NetworkMessage
  464. {
  465. // Debug.Log($"Server.SendToReady {typeof(T)}");
  466. if (identity == null || identity.observers.Count == 0)
  467. return;
  468. using (NetworkWriterPooled writer = NetworkWriterPool.Get())
  469. {
  470. // pack message only once
  471. NetworkMessages.Pack(message, writer);
  472. ArraySegment<byte> segment = writer.ToArraySegment();
  473. int count = 0;
  474. foreach (NetworkConnectionToClient conn in identity.observers.Values)
  475. {
  476. bool isOwner = conn == identity.connectionToClient;
  477. if ((!isOwner || includeOwner) && conn.isReady)
  478. {
  479. count++;
  480. conn.Send(segment, channelId);
  481. }
  482. }
  483. NetworkDiagnostics.OnSend(message, channelId, segment.Count, count);
  484. }
  485. }
  486. /// <summary>Send a message to only clients which are ready including the owner of the NetworkIdentity</summary>
  487. // TODO obsolete this later. it's not used anymore
  488. public static void SendToReadyObservers<T>(NetworkIdentity identity, T message, int channelId)
  489. where T : struct, NetworkMessage
  490. {
  491. SendToReadyObservers(identity, message, true, channelId);
  492. }
  493. // transport events ////////////////////////////////////////////////////
  494. // called by transport
  495. static void OnTransportConnected(int connectionId)
  496. {
  497. // Debug.Log($"Server accepted client:{connectionId}");
  498. // connectionId needs to be != 0 because 0 is reserved for local player
  499. // note that some transports like kcp generate connectionId by
  500. // hashing which can be < 0 as well, so we need to allow < 0!
  501. if (connectionId == 0)
  502. {
  503. Debug.LogError($"Server.HandleConnect: invalid connectionId: {connectionId} . Needs to be != 0, because 0 is reserved for local player.");
  504. Transport.active.ServerDisconnect(connectionId);
  505. return;
  506. }
  507. // connectionId not in use yet?
  508. if (connections.ContainsKey(connectionId))
  509. {
  510. Transport.active.ServerDisconnect(connectionId);
  511. // Debug.Log($"Server connectionId {connectionId} already in use...kicked client");
  512. return;
  513. }
  514. // are more connections allowed? if not, kick
  515. // (it's easier to handle this in Mirror, so Transports can have
  516. // less code and third party transport might not do that anyway)
  517. // (this way we could also send a custom 'tooFull' message later,
  518. // Transport can't do that)
  519. if (connections.Count < maxConnections)
  520. {
  521. // add connection
  522. NetworkConnectionToClient conn = new NetworkConnectionToClient(connectionId);
  523. OnConnected(conn);
  524. }
  525. else
  526. {
  527. // kick
  528. Transport.active.ServerDisconnect(connectionId);
  529. // Debug.Log($"Server full, kicked client {connectionId}");
  530. }
  531. }
  532. internal static void OnConnected(NetworkConnectionToClient conn)
  533. {
  534. // Debug.Log($"Server accepted client:{conn}");
  535. // add connection and invoke connected event
  536. AddConnection(conn);
  537. OnConnectedEvent?.Invoke(conn);
  538. }
  539. static bool UnpackAndInvoke(NetworkConnectionToClient connection, NetworkReader reader, int channelId)
  540. {
  541. if (NetworkMessages.UnpackId(reader, out ushort msgType))
  542. {
  543. // try to invoke the handler for that message
  544. if (handlers.TryGetValue(msgType, out NetworkMessageDelegate handler))
  545. {
  546. handler.Invoke(connection, reader, channelId);
  547. connection.lastMessageTime = Time.time;
  548. return true;
  549. }
  550. else
  551. {
  552. // message in a batch are NOT length prefixed to save bandwidth.
  553. // every message needs to be handled and read until the end.
  554. // otherwise it would overlap into the next message.
  555. // => need to warn and disconnect to avoid undefined behaviour.
  556. // => WARNING, not error. can happen if attacker sends random data.
  557. Debug.LogWarning($"Unknown message id: {msgType} for connection: {connection}. This can happen if no handler was registered for this message.");
  558. // simply return false. caller is responsible for disconnecting.
  559. //connection.Disconnect();
  560. return false;
  561. }
  562. }
  563. else
  564. {
  565. // => WARNING, not error. can happen if attacker sends random data.
  566. Debug.LogWarning($"Invalid message header for connection: {connection}.");
  567. // simply return false. caller is responsible for disconnecting.
  568. //connection.Disconnect();
  569. return false;
  570. }
  571. }
  572. // called by transport
  573. internal static void OnTransportData(int connectionId, ArraySegment<byte> data, int channelId)
  574. {
  575. if (connections.TryGetValue(connectionId, out NetworkConnectionToClient connection))
  576. {
  577. // client might batch multiple messages into one packet.
  578. // feed it to the Unbatcher.
  579. // NOTE: we don't need to associate a channelId because we
  580. // always process all messages in the batch.
  581. if (!connection.unbatcher.AddBatch(data))
  582. {
  583. Debug.LogWarning($"NetworkServer: received Message was too short (messages should start with message id)");
  584. connection.Disconnect();
  585. return;
  586. }
  587. // process all messages in the batch.
  588. // only while NOT loading a scene.
  589. // if we get a scene change message, then we need to stop
  590. // processing. otherwise we might apply them to the old scene.
  591. // => fixes https://github.com/vis2k/Mirror/issues/2651
  592. //
  593. // NOTE: if scene starts loading, then the rest of the batch
  594. // would only be processed when OnTransportData is called
  595. // the next time.
  596. // => consider moving processing to NetworkEarlyUpdate.
  597. while (!isLoadingScene &&
  598. connection.unbatcher.GetNextMessage(out ArraySegment<byte> message, out double remoteTimestamp))
  599. {
  600. using (NetworkReaderPooled reader = NetworkReaderPool.Get(message))
  601. {
  602. // enough to read at least header size?
  603. if (reader.Remaining >= NetworkMessages.IdSize)
  604. {
  605. // make remoteTimeStamp available to the user
  606. connection.remoteTimeStamp = remoteTimestamp;
  607. // handle message
  608. if (!UnpackAndInvoke(connection, reader, channelId))
  609. {
  610. // warn, disconnect and return if failed
  611. // -> warning because attackers might send random data
  612. // -> messages in a batch aren't length prefixed.
  613. // failing to read one would cause undefined
  614. // behaviour for every message afterwards.
  615. // so we need to disconnect.
  616. // -> return to avoid the below unbatches.count error.
  617. // we already disconnected and handled it.
  618. Debug.LogWarning($"NetworkServer: failed to unpack and invoke message. Disconnecting {connectionId}.");
  619. connection.Disconnect();
  620. return;
  621. }
  622. }
  623. // otherwise disconnect
  624. else
  625. {
  626. // WARNING, not error. can happen if attacker sends random data.
  627. Debug.LogWarning($"NetworkServer: received Message was too short (messages should start with message id). Disconnecting {connectionId}");
  628. connection.Disconnect();
  629. return;
  630. }
  631. }
  632. }
  633. // if we weren't interrupted by a scene change,
  634. // then all batched messages should have been processed now.
  635. // otherwise batches would silently grow.
  636. // we need to log an error to avoid debugging hell.
  637. //
  638. // EXAMPLE: https://github.com/vis2k/Mirror/issues/2882
  639. // -> UnpackAndInvoke silently returned because no handler for id
  640. // -> Reader would never be read past the end
  641. // -> Batch would never be retired because end is never reached
  642. //
  643. // NOTE: prefixing every message in a batch with a length would
  644. // avoid ever not reading to the end. for extra bandwidth.
  645. //
  646. // IMPORTANT: always keep this check to detect memory leaks.
  647. // this took half a day to debug last time.
  648. if (!isLoadingScene && connection.unbatcher.BatchesCount > 0)
  649. {
  650. Debug.LogError($"Still had {connection.unbatcher.BatchesCount} batches remaining after processing, even though processing was not interrupted by a scene change. This should never happen, as it would cause ever growing batches.\nPossible reasons:\n* A message didn't deserialize as much as it serialized\n*There was no message handler for a message id, so the reader wasn't read until the end.");
  651. }
  652. }
  653. else Debug.LogError($"HandleData Unknown connectionId:{connectionId}");
  654. }
  655. // called by transport
  656. // IMPORTANT: often times when disconnecting, we call this from Mirror
  657. // too because we want to remove the connection and handle
  658. // the disconnect immediately.
  659. // => which is fine as long as we guarantee it only runs once
  660. // => which we do by removing the connection!
  661. internal static void OnTransportDisconnected(int connectionId)
  662. {
  663. // Debug.Log($"Server disconnect client:{connectionId}");
  664. if (connections.TryGetValue(connectionId, out NetworkConnectionToClient conn))
  665. {
  666. RemoveConnection(connectionId);
  667. // Debug.Log($"Server lost client:{connectionId}");
  668. // NetworkManager hooks into OnDisconnectedEvent to make
  669. // DestroyPlayerForConnection(conn) optional, e.g. for PvP MMOs
  670. // where players shouldn't be able to escape combat instantly.
  671. if (OnDisconnectedEvent != null)
  672. {
  673. OnDisconnectedEvent.Invoke(conn);
  674. }
  675. // if nobody hooked into it, then simply call DestroyPlayerForConnection
  676. else
  677. {
  678. DestroyPlayerForConnection(conn);
  679. }
  680. }
  681. }
  682. // transport errors are forwarded to high level
  683. static void OnTransportError(int connectionId, TransportError error, string reason)
  684. {
  685. // transport errors will happen. logging a warning is enough.
  686. // make sure the user does not panic.
  687. Debug.LogWarning($"Server Transport Error for connId={connectionId}: {error}: {reason}. This is fine.");
  688. // try get connection. passes null otherwise.
  689. connections.TryGetValue(connectionId, out NetworkConnectionToClient conn);
  690. OnErrorEvent?.Invoke(conn, error, reason);
  691. }
  692. /// <summary>Destroys all of the connection's owned objects on the server.</summary>
  693. // This is used when a client disconnects, to remove the players for
  694. // that client. This also destroys non-player objects that have client
  695. // authority set for this connection.
  696. public static void DestroyPlayerForConnection(NetworkConnectionToClient conn)
  697. {
  698. // destroy all objects owned by this connection, including the player object
  699. conn.DestroyOwnedObjects();
  700. // remove connection from all of its observing entities observers
  701. // fixes https://github.com/vis2k/Mirror/issues/2737
  702. // -> cleaning those up in NetworkConnection.Disconnect is NOT enough
  703. // because voluntary disconnects from the other end don't call
  704. // NetworkConnection.Disconnect()
  705. conn.RemoveFromObservingsObservers();
  706. conn.identity = null;
  707. }
  708. // message handlers ////////////////////////////////////////////////////
  709. /// <summary>Register a handler for message type T. Most should require authentication.</summary>
  710. // TODO obsolete this some day to always use the channelId version.
  711. // all handlers in this version are wrapped with 1 extra action.
  712. public static void RegisterHandler<T>(Action<NetworkConnectionToClient, T> handler, bool requireAuthentication = true)
  713. where T : struct, NetworkMessage
  714. {
  715. ushort msgType = NetworkMessageId<T>.Id;
  716. if (handlers.ContainsKey(msgType))
  717. {
  718. Debug.LogWarning($"NetworkServer.RegisterHandler replacing handler for {typeof(T).FullName}, id={msgType}. If replacement is intentional, use ReplaceHandler instead to avoid this warning.");
  719. }
  720. // register Id <> Type in lookup for debugging.
  721. NetworkMessages.Lookup[msgType] = typeof(T);
  722. handlers[msgType] = NetworkMessages.WrapHandler(handler, requireAuthentication, exceptionsDisconnect);
  723. }
  724. /// <summary>Register a handler for message type T. Most should require authentication.</summary>
  725. // This version passes channelId to the handler.
  726. public static void RegisterHandler<T>(Action<NetworkConnectionToClient, T, int> handler, bool requireAuthentication = true)
  727. where T : struct, NetworkMessage
  728. {
  729. ushort msgType = NetworkMessageId<T>.Id;
  730. if (handlers.ContainsKey(msgType))
  731. {
  732. Debug.LogWarning($"NetworkServer.RegisterHandler replacing handler for {typeof(T).FullName}, id={msgType}. If replacement is intentional, use ReplaceHandler instead to avoid this warning.");
  733. }
  734. // register Id <> Type in lookup for debugging.
  735. NetworkMessages.Lookup[msgType] = typeof(T);
  736. handlers[msgType] = NetworkMessages.WrapHandler(handler, requireAuthentication, exceptionsDisconnect);
  737. }
  738. /// <summary>Replace a handler for message type T. Most should require authentication.</summary>
  739. public static void ReplaceHandler<T>(Action<T> handler, bool requireAuthentication = true)
  740. where T : struct, NetworkMessage
  741. {
  742. ReplaceHandler<T>((_, value) => { handler(value); }, requireAuthentication);
  743. }
  744. /// <summary>Replace a handler for message type T. Most should require authentication.</summary>
  745. public static void ReplaceHandler<T>(Action<NetworkConnectionToClient, T> handler, bool requireAuthentication = true)
  746. where T : struct, NetworkMessage
  747. {
  748. ushort msgType = NetworkMessageId<T>.Id;
  749. handlers[msgType] = NetworkMessages.WrapHandler(handler, requireAuthentication, exceptionsDisconnect);
  750. }
  751. /// <summary>Unregister a handler for a message type T.</summary>
  752. public static void UnregisterHandler<T>()
  753. where T : struct, NetworkMessage
  754. {
  755. ushort msgType = NetworkMessageId<T>.Id;
  756. handlers.Remove(msgType);
  757. }
  758. /// <summary>Clears all registered message handlers.</summary>
  759. public static void ClearHandlers() => handlers.Clear();
  760. internal static bool GetNetworkIdentity(GameObject go, out NetworkIdentity identity)
  761. {
  762. if (!go.TryGetComponent(out identity))
  763. {
  764. Debug.LogError($"GameObject {go.name} doesn't have NetworkIdentity.");
  765. return false;
  766. }
  767. return true;
  768. }
  769. // disconnect //////////////////////////////////////////////////////////
  770. /// <summary>Disconnect all connections, including the local connection.</summary>
  771. // synchronous: handles disconnect events and cleans up fully before returning!
  772. public static void DisconnectAll()
  773. {
  774. // disconnect and remove all connections.
  775. // we can not use foreach here because if
  776. // conn.Disconnect -> Transport.ServerDisconnect calls
  777. // OnDisconnect -> NetworkServer.OnDisconnect(connectionId)
  778. // immediately then OnDisconnect would remove the connection while
  779. // we are iterating here.
  780. // see also: https://github.com/vis2k/Mirror/issues/2357
  781. // this whole process should be simplified some day.
  782. // until then, let's copy .Values to avoid InvalidOperationException.
  783. // note that this is only called when stopping the server, so the
  784. // copy is no performance problem.
  785. foreach (NetworkConnectionToClient conn in connections.Values.ToList())
  786. {
  787. // disconnect via connection->transport
  788. conn.Disconnect();
  789. // we want this function to be synchronous: handle disconnect
  790. // events and clean up fully before returning.
  791. // -> OnTransportDisconnected can safely be called without
  792. // waiting for the Transport's callback.
  793. // -> it has checks to only run once.
  794. // call OnDisconnected unless local player in host mod
  795. // TODO unnecessary check?
  796. if (conn.connectionId != NetworkConnection.LocalConnectionId)
  797. OnTransportDisconnected(conn.connectionId);
  798. }
  799. // cleanup
  800. connections.Clear();
  801. localConnection = null;
  802. // this used to set active=false.
  803. // however, then Shutdown can't properly destroy objects:
  804. // https://github.com/MirrorNetworking/Mirror/issues/3344
  805. // "DisconnectAll" should only disconnect all, not set inactive.
  806. // active = false;
  807. }
  808. // add/remove/replace player ///////////////////////////////////////////
  809. /// <summary>Called by server after AddPlayer message to add the player for the connection.</summary>
  810. // When a player is added for a connection, the client for that
  811. // connection is made ready automatically. The player object is
  812. // automatically spawned, so you do not need to call NetworkServer.Spawn
  813. // for that object. This function is used for "adding" a player, not for
  814. // "replacing" the player on a connection. If there is already a player
  815. // on this playerControllerId for this connection, this will fail.
  816. public static bool AddPlayerForConnection(NetworkConnectionToClient conn, GameObject player, uint assetId)
  817. {
  818. if (GetNetworkIdentity(player, out NetworkIdentity identity))
  819. {
  820. identity.assetId = assetId;
  821. }
  822. return AddPlayerForConnection(conn, player);
  823. }
  824. /// <summary>Called by server after AddPlayer message to add the player for the connection.</summary>
  825. // When a player is added for a connection, the client for that
  826. // connection is made ready automatically. The player object is
  827. // automatically spawned, so you do not need to call NetworkServer.Spawn
  828. // for that object. This function is used for "adding" a player, not for
  829. // "replacing" the player on a connection. If there is already a player
  830. // on this playerControllerId for this connection, this will fail.
  831. public static bool AddPlayerForConnection(NetworkConnectionToClient conn, GameObject player)
  832. {
  833. if (!player.TryGetComponent(out NetworkIdentity identity))
  834. {
  835. Debug.LogWarning($"AddPlayer: playerGameObject has no NetworkIdentity. Please add a NetworkIdentity to {player}");
  836. return false;
  837. }
  838. // cannot have a player object in "Add" version
  839. if (conn.identity != null)
  840. {
  841. Debug.Log("AddPlayer: player object already exists");
  842. return false;
  843. }
  844. // make sure we have a controller before we call SetClientReady
  845. // because the observers will be rebuilt only if we have a controller
  846. conn.identity = identity;
  847. // Set the connection on the NetworkIdentity on the server, NetworkIdentity.SetLocalPlayer is not called on the server (it is on clients)
  848. identity.SetClientOwner(conn);
  849. // special case, we are in host mode, set hasAuthority to true so that all overrides see it
  850. if (conn is LocalConnectionToClient)
  851. {
  852. identity.isOwned = true;
  853. NetworkClient.InternalAddPlayer(identity);
  854. }
  855. // set ready if not set yet
  856. SetClientReady(conn);
  857. // Debug.Log($"Adding new playerGameObject object netId: {identity.netId} asset ID: {identity.assetId}");
  858. Respawn(identity);
  859. return true;
  860. }
  861. /// <summary>Replaces connection's player object. The old object is not destroyed.</summary>
  862. // This does NOT change the ready state of the connection, so it can
  863. // safely be used while changing scenes.
  864. public static bool ReplacePlayerForConnection(NetworkConnectionToClient conn, GameObject player, bool keepAuthority = false)
  865. {
  866. if (!player.TryGetComponent(out NetworkIdentity identity))
  867. {
  868. Debug.LogError($"ReplacePlayer: playerGameObject has no NetworkIdentity. Please add a NetworkIdentity to {player}");
  869. return false;
  870. }
  871. if (identity.connectionToClient != null && identity.connectionToClient != conn)
  872. {
  873. Debug.LogError($"Cannot replace player for connection. New player is already owned by a different connection{player}");
  874. return false;
  875. }
  876. //NOTE: there can be an existing player
  877. //Debug.Log("NetworkServer ReplacePlayer");
  878. NetworkIdentity previousPlayer = conn.identity;
  879. conn.identity = identity;
  880. // Set the connection on the NetworkIdentity on the server, NetworkIdentity.SetLocalPlayer is not called on the server (it is on clients)
  881. identity.SetClientOwner(conn);
  882. // special case, we are in host mode, set hasAuthority to true so that all overrides see it
  883. if (conn is LocalConnectionToClient)
  884. {
  885. identity.isOwned = true;
  886. NetworkClient.InternalAddPlayer(identity);
  887. }
  888. // add connection to observers AFTER the playerController was set.
  889. // by definition, there is nothing to observe if there is no player
  890. // controller.
  891. //
  892. // IMPORTANT: do this in AddPlayerForConnection & ReplacePlayerForConnection!
  893. SpawnObserversForConnection(conn);
  894. //Debug.Log($"Replacing playerGameObject object netId:{player.GetComponent<NetworkIdentity>().netId} asset ID {player.GetComponent<NetworkIdentity>().assetId}");
  895. Respawn(identity);
  896. if (keepAuthority)
  897. {
  898. // This needs to be sent to clear isLocalPlayer on
  899. // client while keeping hasAuthority true
  900. SendChangeOwnerMessage(previousPlayer, conn);
  901. }
  902. else
  903. {
  904. // This clears both isLocalPlayer and hasAuthority on client
  905. previousPlayer.RemoveClientAuthority();
  906. }
  907. return true;
  908. }
  909. /// <summary>Replaces connection's player object. The old object is not destroyed.</summary>
  910. // This does NOT change the ready state of the connection, so it can
  911. // safely be used while changing scenes.
  912. public static bool ReplacePlayerForConnection(NetworkConnectionToClient conn, GameObject player, uint assetId, bool keepAuthority = false)
  913. {
  914. if (GetNetworkIdentity(player, out NetworkIdentity identity))
  915. {
  916. identity.assetId = assetId;
  917. }
  918. return ReplacePlayerForConnection(conn, player, keepAuthority);
  919. }
  920. /// <summary>Removes the player object from the connection</summary>
  921. // destroyServerObject: Indicates whether the server object should be destroyed
  922. public static void RemovePlayerForConnection(NetworkConnection conn, bool destroyServerObject)
  923. {
  924. if (conn.identity != null)
  925. {
  926. if (destroyServerObject)
  927. Destroy(conn.identity.gameObject);
  928. else
  929. UnSpawn(conn.identity.gameObject);
  930. conn.identity = null;
  931. }
  932. //else Debug.Log($"Connection {conn} has no identity");
  933. }
  934. // ready ///////////////////////////////////////////////////////////////
  935. /// <summary>Flags client connection as ready (=joined world).</summary>
  936. // When a client has signaled that it is ready, this method tells the
  937. // server that the client is ready to receive spawned objects and state
  938. // synchronization updates. This is usually called in a handler for the
  939. // SYSTEM_READY message. If there is not specific action a game needs to
  940. // take for this message, relying on the default ready handler function
  941. // is probably fine, so this call wont be needed.
  942. public static void SetClientReady(NetworkConnectionToClient conn)
  943. {
  944. // Debug.Log($"SetClientReadyInternal for conn:{conn}");
  945. // set ready
  946. conn.isReady = true;
  947. // client is ready to start spawning objects
  948. if (conn.identity != null)
  949. SpawnObserversForConnection(conn);
  950. }
  951. static void SpawnObserversForConnection(NetworkConnectionToClient conn)
  952. {
  953. //Debug.Log($"Spawning {spawned.Count} objects for conn {conn}");
  954. if (!conn.isReady)
  955. {
  956. // client needs to finish initializing before we can spawn objects
  957. // otherwise it would not find them.
  958. return;
  959. }
  960. // let connection know that we are about to start spawning...
  961. conn.Send(new ObjectSpawnStartedMessage());
  962. // add connection to each nearby NetworkIdentity's observers, which
  963. // internally sends a spawn message for each one to the connection.
  964. foreach (NetworkIdentity identity in spawned.Values)
  965. {
  966. // try with far away ones in ummorpg!
  967. if (identity.gameObject.activeSelf) //TODO this is different
  968. {
  969. //Debug.Log($"Sending spawn message for current server objects name:{identity.name} netId:{identity.netId} sceneId:{identity.sceneId:X}");
  970. // we need to support three cases:
  971. // - legacy system (identity has .visibility)
  972. // - new system (networkserver has .aoi)
  973. // - default case: no .visibility and no .aoi means add all
  974. // connections by default)
  975. //
  976. // ForceHidden/ForceShown overwrite all systems so check it
  977. // first!
  978. // ForceShown: add no matter what
  979. if (identity.visible == Visibility.ForceShown)
  980. {
  981. identity.AddObserver(conn);
  982. }
  983. // ForceHidden: don't show no matter what
  984. else if (identity.visible == Visibility.ForceHidden)
  985. {
  986. // do nothing
  987. }
  988. // default: legacy system / new system / no system support
  989. else if (identity.visible == Visibility.Default)
  990. {
  991. // aoi system
  992. if (aoi != null)
  993. {
  994. // call OnCheckObserver
  995. if (aoi.OnCheckObserver(identity, conn))
  996. identity.AddObserver(conn);
  997. }
  998. // no system: add all observers by default
  999. else
  1000. {
  1001. identity.AddObserver(conn);
  1002. }
  1003. }
  1004. }
  1005. }
  1006. // let connection know that we finished spawning, so it can call
  1007. // OnStartClient on each one (only after all were spawned, which
  1008. // is how Unity's Start() function works too)
  1009. conn.Send(new ObjectSpawnFinishedMessage());
  1010. }
  1011. /// <summary>Marks the client of the connection to be not-ready.</summary>
  1012. // Clients that are not ready do not receive spawned objects or state
  1013. // synchronization updates. They client can be made ready again by
  1014. // calling SetClientReady().
  1015. public static void SetClientNotReady(NetworkConnectionToClient conn)
  1016. {
  1017. conn.isReady = false;
  1018. conn.RemoveFromObservingsObservers();
  1019. conn.Send(new NotReadyMessage());
  1020. }
  1021. /// <summary>Marks all connected clients as no longer ready.</summary>
  1022. // All clients will no longer be sent state synchronization updates. The
  1023. // player's clients can call ClientManager.Ready() again to re-enter the
  1024. // ready state. This is useful when switching scenes.
  1025. public static void SetAllClientsNotReady()
  1026. {
  1027. foreach (NetworkConnectionToClient conn in connections.Values)
  1028. {
  1029. SetClientNotReady(conn);
  1030. }
  1031. }
  1032. // show / hide for connection //////////////////////////////////////////
  1033. internal static void ShowForConnection(NetworkIdentity identity, NetworkConnection conn)
  1034. {
  1035. if (conn.isReady)
  1036. SendSpawnMessage(identity, conn);
  1037. }
  1038. internal static void HideForConnection(NetworkIdentity identity, NetworkConnection conn)
  1039. {
  1040. ObjectHideMessage msg = new ObjectHideMessage
  1041. {
  1042. netId = identity.netId
  1043. };
  1044. conn.Send(msg);
  1045. }
  1046. // spawning ////////////////////////////////////////////////////////////
  1047. internal static void SendSpawnMessage(NetworkIdentity identity, NetworkConnection conn)
  1048. {
  1049. if (identity.serverOnly) return;
  1050. //Debug.Log($"Server SendSpawnMessage: name:{identity.name} sceneId:{identity.sceneId:X} netid:{identity.netId}");
  1051. // one writer for owner, one for observers
  1052. using (NetworkWriterPooled ownerWriter = NetworkWriterPool.Get(), observersWriter = NetworkWriterPool.Get())
  1053. {
  1054. bool isOwner = identity.connectionToClient == conn;
  1055. ArraySegment<byte> payload = CreateSpawnMessagePayload(isOwner, identity, ownerWriter, observersWriter);
  1056. SpawnMessage message = new SpawnMessage
  1057. {
  1058. netId = identity.netId,
  1059. isLocalPlayer = conn.identity == identity,
  1060. isOwner = isOwner,
  1061. sceneId = identity.sceneId,
  1062. assetId = identity.assetId,
  1063. // use local values for VR support
  1064. position = identity.transform.localPosition,
  1065. rotation = identity.transform.localRotation,
  1066. scale = identity.transform.localScale,
  1067. payload = payload
  1068. };
  1069. conn.Send(message);
  1070. }
  1071. }
  1072. static ArraySegment<byte> CreateSpawnMessagePayload(bool isOwner, NetworkIdentity identity, NetworkWriterPooled ownerWriter, NetworkWriterPooled observersWriter)
  1073. {
  1074. // Only call SerializeAll if there are NetworkBehaviours
  1075. if (identity.NetworkBehaviours.Length == 0)
  1076. {
  1077. return default;
  1078. }
  1079. // serialize all components with initialState = true
  1080. // (can be null if has none)
  1081. identity.SerializeServer(true, ownerWriter, observersWriter);
  1082. // convert to ArraySegment to avoid reader allocations
  1083. // if nothing was written, .ToArraySegment returns an empty segment.
  1084. ArraySegment<byte> ownerSegment = ownerWriter.ToArraySegment();
  1085. ArraySegment<byte> observersSegment = observersWriter.ToArraySegment();
  1086. // use owner segment if 'conn' owns this identity, otherwise
  1087. // use observers segment
  1088. ArraySegment<byte> payload = isOwner ? ownerSegment : observersSegment;
  1089. return payload;
  1090. }
  1091. internal static void SendChangeOwnerMessage(NetworkIdentity identity, NetworkConnectionToClient conn)
  1092. {
  1093. // Don't send if identity isn't spawned or only exists on server
  1094. if (identity.netId == 0 || identity.serverOnly) return;
  1095. // Don't send if conn doesn't have the identity spawned yet
  1096. // May be excluded from the client by interest management
  1097. if (!conn.observing.Contains(identity)) return;
  1098. //Debug.Log($"Server SendChangeOwnerMessage: name={identity.name} netid={identity.netId}");
  1099. conn.Send(new ChangeOwnerMessage
  1100. {
  1101. netId = identity.netId,
  1102. isOwner = identity.connectionToClient == conn,
  1103. isLocalPlayer = conn.identity == identity
  1104. });
  1105. }
  1106. // check NetworkIdentity parent before spawning it.
  1107. // - without parent, they are spawned
  1108. // - with parent, only if the parent is active in hierarchy
  1109. //
  1110. // note that active parents may have inactive parents of their own.
  1111. // we need to check .activeInHierarchy.
  1112. //
  1113. // fixes: https://github.com/MirrorNetworking/Mirror/issues/3330
  1114. // https://github.com/vis2k/Mirror/issues/2778
  1115. static bool ValidParent(NetworkIdentity identity) =>
  1116. identity.transform.parent == null ||
  1117. identity.transform.parent.gameObject.activeInHierarchy;
  1118. /// <summary>Spawns NetworkIdentities in the scene on the server.</summary>
  1119. // NetworkIdentity objects in a scene are disabled by default. Calling
  1120. // SpawnObjects() causes these scene objects to be enabled and spawned.
  1121. // It is like calling NetworkServer.Spawn() for each of them.
  1122. public static bool SpawnObjects()
  1123. {
  1124. // only if server active
  1125. if (!active)
  1126. return false;
  1127. // find all NetworkIdentities in the scene.
  1128. // all of them are disabled because of NetworkScenePostProcess.
  1129. NetworkIdentity[] identities = Resources.FindObjectsOfTypeAll<NetworkIdentity>();
  1130. // first pass: activate all scene objects
  1131. foreach (NetworkIdentity identity in identities)
  1132. {
  1133. // only spawn scene objects which haven't been spawned yet.
  1134. // SpawnObjects may be called multiple times for additive scenes.
  1135. // https://github.com/MirrorNetworking/Mirror/issues/3318
  1136. //
  1137. // note that we even activate objects under inactive parents.
  1138. // while they are not spawned, they do need to be activated
  1139. // in order to be spawned later. so here, we don't check parents.
  1140. // https://github.com/MirrorNetworking/Mirror/issues/3330
  1141. if (Utils.IsSceneObject(identity) && identity.netId == 0)
  1142. {
  1143. // Debug.Log($"SpawnObjects sceneId:{identity.sceneId:X} name:{identity.gameObject.name}");
  1144. identity.gameObject.SetActive(true);
  1145. }
  1146. }
  1147. // second pass: spawn all scene objects
  1148. foreach (NetworkIdentity identity in identities)
  1149. {
  1150. // scene objects may be children of inactive parents.
  1151. // users would put them under disabled parents to 'deactivate' them.
  1152. // those should not be used by Mirror at all.
  1153. // fixes: https://github.com/MirrorNetworking/Mirror/issues/3330
  1154. // https://github.com/vis2k/Mirror/issues/2778
  1155. if (Utils.IsSceneObject(identity) && identity.netId == 0 && ValidParent(identity))
  1156. {
  1157. // pass connection so that authority is not lost when server loads a scene
  1158. // https://github.com/vis2k/Mirror/pull/2987
  1159. Spawn(identity.gameObject, identity.connectionToClient);
  1160. }
  1161. }
  1162. return true;
  1163. }
  1164. /// <summary>Spawns an object and also assigns Client Authority to the specified client.</summary>
  1165. // This is the same as calling NetworkIdentity.AssignClientAuthority on the spawned object.
  1166. public static void Spawn(GameObject obj, GameObject ownerPlayer)
  1167. {
  1168. if (!ownerPlayer.TryGetComponent(out NetworkIdentity identity))
  1169. {
  1170. Debug.LogError("Player object has no NetworkIdentity");
  1171. return;
  1172. }
  1173. if (identity.connectionToClient == null)
  1174. {
  1175. Debug.LogError("Player object is not a player.");
  1176. return;
  1177. }
  1178. Spawn(obj, identity.connectionToClient);
  1179. }
  1180. static void Respawn(NetworkIdentity identity)
  1181. {
  1182. if (identity.netId == 0)
  1183. {
  1184. // If the object has not been spawned, then do a full spawn and update observers
  1185. Spawn(identity.gameObject, identity.connectionToClient);
  1186. }
  1187. else
  1188. {
  1189. // otherwise just replace his data
  1190. SendSpawnMessage(identity, identity.connectionToClient);
  1191. }
  1192. }
  1193. /// <summary>Spawn the given game object on all clients which are ready.</summary>
  1194. // This will cause a new object to be instantiated from the registered
  1195. // prefab, or from a custom spawn function.
  1196. public static void Spawn(GameObject obj, NetworkConnection ownerConnection = null)
  1197. {
  1198. SpawnObject(obj, ownerConnection);
  1199. }
  1200. /// <summary>Spawns an object and also assigns Client Authority to the specified client.</summary>
  1201. // This is the same as calling NetworkIdentity.AssignClientAuthority on the spawned object.
  1202. public static void Spawn(GameObject obj, uint assetId, NetworkConnection ownerConnection = null)
  1203. {
  1204. if (GetNetworkIdentity(obj, out NetworkIdentity identity))
  1205. {
  1206. identity.assetId = assetId;
  1207. }
  1208. SpawnObject(obj, ownerConnection);
  1209. }
  1210. static void SpawnObject(GameObject obj, NetworkConnection ownerConnection)
  1211. {
  1212. // verify if we can spawn this
  1213. if (Utils.IsPrefab(obj))
  1214. {
  1215. Debug.LogError($"GameObject {obj.name} is a prefab, it can't be spawned. Instantiate it first.", obj);
  1216. return;
  1217. }
  1218. if (!active)
  1219. {
  1220. Debug.LogError($"SpawnObject for {obj}, NetworkServer is not active. Cannot spawn objects without an active server.", obj);
  1221. return;
  1222. }
  1223. if (!obj.TryGetComponent(out NetworkIdentity identity))
  1224. {
  1225. Debug.LogError($"SpawnObject {obj} has no NetworkIdentity. Please add a NetworkIdentity to {obj}", obj);
  1226. return;
  1227. }
  1228. if (identity.SpawnedFromInstantiate)
  1229. {
  1230. // Using Instantiate on SceneObject is not allowed, so stop spawning here
  1231. // NetworkIdentity.Awake already logs error, no need to log a second error here
  1232. return;
  1233. }
  1234. // Spawn should only be called once per netId.
  1235. // calling it twice would lead to undefined behaviour.
  1236. // https://github.com/MirrorNetworking/Mirror/pull/3205
  1237. if (spawned.ContainsKey(identity.netId))
  1238. {
  1239. Debug.LogWarning($"{identity} with netId={identity.netId} was already spawned.", identity.gameObject);
  1240. return;
  1241. }
  1242. identity.connectionToClient = (NetworkConnectionToClient)ownerConnection;
  1243. // special case to make sure hasAuthority is set
  1244. // on start server in host mode
  1245. if (ownerConnection is LocalConnectionToClient)
  1246. identity.isOwned = true;
  1247. // only call OnStartServer if not spawned yet.
  1248. // check used to be in NetworkIdentity. may not be necessary anymore.
  1249. if (!identity.isServer && identity.netId == 0)
  1250. {
  1251. // configure NetworkIdentity
  1252. // this may be called in host mode, so we need to initialize
  1253. // isLocalPlayer/isClient flags too.
  1254. identity.isLocalPlayer = NetworkClient.localPlayer == identity;
  1255. identity.isClient = NetworkClient.active;
  1256. identity.isServer = true;
  1257. identity.netId = NetworkIdentity.GetNextNetworkId();
  1258. // add to spawned (after assigning netId)
  1259. spawned[identity.netId] = identity;
  1260. // callback after all fields were set
  1261. identity.OnStartServer();
  1262. }
  1263. // Debug.Log($"SpawnObject instance ID {identity.netId} asset ID {identity.assetId}");
  1264. if (aoi)
  1265. {
  1266. // This calls user code which might throw exceptions
  1267. // We don't want this to leave us in bad state
  1268. try
  1269. {
  1270. aoi.OnSpawned(identity);
  1271. }
  1272. catch (Exception e)
  1273. {
  1274. Debug.LogException(e);
  1275. }
  1276. }
  1277. RebuildObservers(identity, true);
  1278. }
  1279. /// <summary>This takes an object that has been spawned and un-spawns it.</summary>
  1280. // The object will be removed from clients that it was spawned on, or
  1281. // the custom spawn handler function on the client will be called for
  1282. // the object.
  1283. // Unlike when calling NetworkServer.Destroy(), on the server the object
  1284. // will NOT be destroyed. This allows the server to re-use the object,
  1285. // even spawn it again later.
  1286. public static void UnSpawn(GameObject obj) => DestroyObject(obj, DestroyMode.Reset);
  1287. // destroy /////////////////////////////////////////////////////////////
  1288. // sometimes we want to GameObject.Destroy it.
  1289. // sometimes we want to just unspawn on clients and .Reset() it on server.
  1290. // => 'bool destroy' isn't obvious enough. it's really destroy OR reset!
  1291. enum DestroyMode { Destroy, Reset }
  1292. /// <summary>Destroys this object and corresponding objects on all clients.</summary>
  1293. // In some cases it is useful to remove an object but not delete it on
  1294. // the server. For that, use NetworkServer.UnSpawn() instead of
  1295. // NetworkServer.Destroy().
  1296. public static void Destroy(GameObject obj) => DestroyObject(obj, DestroyMode.Destroy);
  1297. static void DestroyObject(GameObject obj, DestroyMode mode)
  1298. {
  1299. if (obj == null)
  1300. {
  1301. Debug.Log("NetworkServer DestroyObject is null");
  1302. return;
  1303. }
  1304. if (GetNetworkIdentity(obj, out NetworkIdentity identity))
  1305. {
  1306. DestroyObject(identity, mode);
  1307. }
  1308. }
  1309. static void DestroyObject(NetworkIdentity identity, DestroyMode mode)
  1310. {
  1311. // Debug.Log($"DestroyObject instance:{identity.netId}");
  1312. // NetworkServer.Destroy should only be called on server or host.
  1313. // on client, show a warning to explain what it does.
  1314. if (!active)
  1315. {
  1316. Debug.LogWarning("NetworkServer.Destroy() called without an active server. Servers can only destroy while active, clients can only ask the server to destroy (for example, with a [Command]), after which the server may decide to destroy the object and broadcast the change to all clients.");
  1317. return;
  1318. }
  1319. // only call OnRebuildObservers while active,
  1320. // not while shutting down
  1321. // (https://github.com/vis2k/Mirror/issues/2977)
  1322. if (active && aoi)
  1323. {
  1324. // This calls user code which might throw exceptions
  1325. // We don't want this to leave us in bad state
  1326. try
  1327. {
  1328. aoi.OnDestroyed(identity);
  1329. }
  1330. catch (Exception e)
  1331. {
  1332. Debug.LogException(e);
  1333. }
  1334. }
  1335. // remove from NetworkServer (this) dictionary
  1336. spawned.Remove(identity.netId);
  1337. identity.connectionToClient?.RemoveOwnedObject(identity);
  1338. // send object destroy message to all observers, clear observers
  1339. SendToObservers(identity, new ObjectDestroyMessage
  1340. {
  1341. netId = identity.netId
  1342. });
  1343. identity.ClearObservers();
  1344. // in host mode, call OnStopClient/OnStopLocalPlayer manually
  1345. if (NetworkClient.active && activeHost)
  1346. {
  1347. if (identity.isLocalPlayer)
  1348. identity.OnStopLocalPlayer();
  1349. identity.OnStopClient();
  1350. // The object may have been spawned with host client ownership,
  1351. // e.g. a pet so we need to clear hasAuthority and call
  1352. // NotifyAuthority which invokes OnStopAuthority if hasAuthority.
  1353. identity.isOwned = false;
  1354. identity.NotifyAuthority();
  1355. // remove from NetworkClient dictionary
  1356. NetworkClient.connection.owned.Remove(identity);
  1357. NetworkClient.spawned.Remove(identity.netId);
  1358. }
  1359. // we are on the server. call OnStopServer.
  1360. identity.OnStopServer();
  1361. // are we supposed to GameObject.Destroy() it completely?
  1362. if (mode == DestroyMode.Destroy)
  1363. {
  1364. identity.destroyCalled = true;
  1365. // Destroy if application is running
  1366. if (Application.isPlaying)
  1367. {
  1368. UnityEngine.Object.Destroy(identity.gameObject);
  1369. }
  1370. // Destroy can't be used in Editor during tests. use DestroyImmediate.
  1371. else
  1372. {
  1373. GameObject.DestroyImmediate(identity.gameObject);
  1374. }
  1375. }
  1376. // otherwise simply .Reset() and set inactive again
  1377. else if (mode == DestroyMode.Reset)
  1378. {
  1379. identity.Reset();
  1380. }
  1381. }
  1382. // interest management /////////////////////////////////////////////////
  1383. // Helper function to add all server connections as observers.
  1384. // This is used if none of the components provides their own
  1385. // OnRebuildObservers function.
  1386. // rebuild observers default method (no AOI) - adds all connections
  1387. static void RebuildObserversDefault(NetworkIdentity identity, bool initialize)
  1388. {
  1389. // only add all connections when rebuilding the first time.
  1390. // second time we just keep them without rebuilding anything.
  1391. if (initialize)
  1392. {
  1393. // not force hidden?
  1394. if (identity.visible != Visibility.ForceHidden)
  1395. {
  1396. AddAllReadyServerConnectionsToObservers(identity);
  1397. }
  1398. }
  1399. }
  1400. internal static void AddAllReadyServerConnectionsToObservers(NetworkIdentity identity)
  1401. {
  1402. // add all server connections
  1403. foreach (NetworkConnectionToClient conn in connections.Values)
  1404. {
  1405. // only if authenticated (don't send to people during logins)
  1406. if (conn.isReady)
  1407. identity.AddObserver(conn);
  1408. }
  1409. // add local host connection (if any)
  1410. if (localConnection != null && localConnection.isReady)
  1411. {
  1412. identity.AddObserver(localConnection);
  1413. }
  1414. }
  1415. // RebuildObservers does a local rebuild for the NetworkIdentity.
  1416. // This causes the set of players that can see this object to be rebuild.
  1417. //
  1418. // IMPORTANT:
  1419. // => global rebuild would be more simple, BUT
  1420. // => local rebuild is way faster for spawn/despawn because we can
  1421. // simply rebuild a select NetworkIdentity only
  1422. // => having both .observers and .observing is necessary for local
  1423. // rebuilds
  1424. //
  1425. // in other words, this is the perfect solution even though it's not
  1426. // completely simple (due to .observers & .observing)
  1427. //
  1428. // Mirror maintains .observing automatically in the background. best of
  1429. // both worlds without any worrying now!
  1430. public static void RebuildObservers(NetworkIdentity identity, bool initialize)
  1431. {
  1432. // if there is no interest management system,
  1433. // or if 'force shown' then add all connections
  1434. if (aoi == null || identity.visible == Visibility.ForceShown)
  1435. {
  1436. RebuildObserversDefault(identity, initialize);
  1437. }
  1438. // otherwise let interest management system rebuild
  1439. else
  1440. {
  1441. aoi.Rebuild(identity, initialize);
  1442. }
  1443. }
  1444. // broadcasting ////////////////////////////////////////////////////////
  1445. // helper function to get the right serialization for a connection
  1446. static NetworkWriter SerializeForConnection(NetworkIdentity identity, NetworkConnectionToClient connection)
  1447. {
  1448. // get serialization for this entity (cached)
  1449. // IMPORTANT: int tick avoids floating point inaccuracy over days/weeks
  1450. NetworkIdentitySerialization serialization = identity.GetServerSerializationAtTick(Time.frameCount);
  1451. // is this entity owned by this connection?
  1452. bool owned = identity.connectionToClient == connection;
  1453. // send serialized data
  1454. // owner writer if owned
  1455. if (owned)
  1456. {
  1457. // was it dirty / did we actually serialize anything?
  1458. if (serialization.ownerWriter.Position > 0)
  1459. return serialization.ownerWriter;
  1460. }
  1461. // observers writer if not owned
  1462. else
  1463. {
  1464. // was it dirty / did we actually serialize anything?
  1465. if (serialization.observersWriter.Position > 0)
  1466. return serialization.observersWriter;
  1467. }
  1468. // nothing was serialized
  1469. return null;
  1470. }
  1471. // helper function to broadcast the world to a connection
  1472. static void BroadcastToConnection(NetworkConnectionToClient connection)
  1473. {
  1474. // for each entity that this connection is seeing
  1475. foreach (NetworkIdentity identity in connection.observing)
  1476. {
  1477. // make sure it's not null or destroyed.
  1478. // (which can happen if someone uses
  1479. // GameObject.Destroy instead of
  1480. // NetworkServer.Destroy)
  1481. if (identity != null)
  1482. {
  1483. // get serialization for this entity viewed by this connection
  1484. // (if anything was serialized this time)
  1485. NetworkWriter serialization = SerializeForConnection(identity, connection);
  1486. if (serialization != null)
  1487. {
  1488. EntityStateMessage message = new EntityStateMessage
  1489. {
  1490. netId = identity.netId,
  1491. payload = serialization.ToArraySegment()
  1492. };
  1493. connection.Send(message);
  1494. }
  1495. }
  1496. // spawned list should have no null entries because we
  1497. // always call Remove in OnObjectDestroy everywhere.
  1498. // if it does have null then someone used
  1499. // GameObject.Destroy instead of NetworkServer.Destroy.
  1500. else Debug.LogWarning($"Found 'null' entry in observing list for connectionId={connection.connectionId}. Please call NetworkServer.Destroy to destroy networked objects. Don't use GameObject.Destroy.");
  1501. }
  1502. }
  1503. // helper function to check a connection for inactivity and disconnect if necessary
  1504. // returns true if disconnected
  1505. static bool DisconnectIfInactive(NetworkConnectionToClient connection)
  1506. {
  1507. // check for inactivity
  1508. if (disconnectInactiveConnections &&
  1509. !connection.IsAlive(disconnectInactiveTimeout))
  1510. {
  1511. Debug.LogWarning($"Disconnecting {connection} for inactivity!");
  1512. connection.Disconnect();
  1513. return true;
  1514. }
  1515. return false;
  1516. }
  1517. // NetworkLateUpdate called after any Update/FixedUpdate/LateUpdate
  1518. // (we add this to the UnityEngine in NetworkLoop)
  1519. // internal for tests
  1520. internal static readonly List<NetworkConnectionToClient> connectionsCopy =
  1521. new List<NetworkConnectionToClient>();
  1522. static void Broadcast()
  1523. {
  1524. // copy all connections into a helper collection so that
  1525. // OnTransportDisconnected can be called while iterating.
  1526. // -> OnTransportDisconnected removes from the collection
  1527. // -> which would throw 'can't modify while iterating' errors
  1528. // => see also: https://github.com/vis2k/Mirror/issues/2739
  1529. // (copy nonalloc)
  1530. // TODO remove this when we move to 'lite' transports with only
  1531. // socket send/recv later.
  1532. connectionsCopy.Clear();
  1533. connections.Values.CopyTo(connectionsCopy);
  1534. // go through all connections
  1535. foreach (NetworkConnectionToClient connection in connectionsCopy)
  1536. {
  1537. // check for inactivity. disconnects if necessary.
  1538. if (DisconnectIfInactive(connection))
  1539. continue;
  1540. // has this connection joined the world yet?
  1541. // for each READY connection:
  1542. // pull in UpdateVarsMessage for each entity it observes
  1543. if (connection.isReady)
  1544. {
  1545. // send time for snapshot interpolation every sendInterval.
  1546. // BroadcastToConnection() may not send if nothing is new.
  1547. //
  1548. // sent over unreliable.
  1549. // NetworkTime / Transform both use unreliable.
  1550. //
  1551. // make sure Broadcast() is only called every sendInterval,
  1552. // even if targetFrameRate isn't set in host mode (!)
  1553. // (done via AccurateInterval)
  1554. connection.Send(new TimeSnapshotMessage(), Channels.Unreliable);
  1555. // broadcast world state to this connection
  1556. BroadcastToConnection(connection);
  1557. }
  1558. // update connection to flush out batched messages
  1559. connection.Update();
  1560. }
  1561. // TODO this is way too slow because we iterate ALL spawned :/
  1562. // TODO this is way too complicated :/
  1563. // to understand what this tries to prevent, consider this example:
  1564. // monster has health=100
  1565. // we change health=200, dirty bit is set
  1566. // player comes in range, gets full serialization spawn packet.
  1567. // next Broadcast(), player gets the health=200 change because dirty bit was set.
  1568. //
  1569. // this code clears all dirty bits if no players are around to prevent it.
  1570. // BUT there are two issues:
  1571. // 1. what if a playerB was around the whole time?
  1572. // 2. why don't we handle broadcast and spawn packets both HERE?
  1573. // handling spawn separately is why we need this complex magic
  1574. //
  1575. // see test: DirtyBitsAreClearedForSpawnedWithoutObservers()
  1576. // see test: SyncObjectChanges_DontGrowWithoutObservers()
  1577. //
  1578. // PAUL: we also do this to avoid ever growing SyncList .changes
  1579. //ClearSpawnedDirtyBits();
  1580. //
  1581. // this was moved to NetworkIdentity.AddObserver!
  1582. // same result, but no more O(N) loop in here!
  1583. // TODO remove this comment after moving spawning into Broadcast()!
  1584. }
  1585. // update //////////////////////////////////////////////////////////////
  1586. // NetworkEarlyUpdate called before any Update/FixedUpdate
  1587. // (we add this to the UnityEngine in NetworkLoop)
  1588. internal static void NetworkEarlyUpdate()
  1589. {
  1590. // measure update time for profiling.
  1591. if (active)
  1592. {
  1593. earlyUpdateDuration.Begin();
  1594. fullUpdateDuration.Begin();
  1595. }
  1596. // process all incoming messages first before updating the world
  1597. if (Transport.active != null)
  1598. Transport.active.ServerEarlyUpdate();
  1599. // step each connection's local time interpolation in early update.
  1600. foreach (NetworkConnectionToClient connection in connections.Values)
  1601. connection.UpdateTimeInterpolation();
  1602. if (active) earlyUpdateDuration.End();
  1603. }
  1604. internal static void NetworkLateUpdate()
  1605. {
  1606. if (active)
  1607. {
  1608. // measure update time for profiling.
  1609. lateUpdateDuration.Begin();
  1610. // only broadcast world if active
  1611. // broadcast every sendInterval.
  1612. // AccurateInterval to avoid update frequency inaccuracy issues:
  1613. // https://github.com/vis2k/Mirror/pull/3153
  1614. //
  1615. // for example, host mode server doesn't set .targetFrameRate.
  1616. // Broadcast() would be called every tick.
  1617. // snapshots might be sent way too often, etc.
  1618. //
  1619. // during tests, we always call Broadcast() though.
  1620. //
  1621. // also important for syncInterval=0 components like
  1622. // NetworkTransform, so they can sync on same interval as time
  1623. // snapshots _but_ not every single tick.
  1624. // Unity 2019 doesn't have Time.timeAsDouble yet
  1625. if (!Application.isPlaying || AccurateInterval.Elapsed(NetworkTime.localTime, sendInterval, ref lastSendTime))
  1626. Broadcast();
  1627. }
  1628. // process all outgoing messages after updating the world
  1629. // (even if not active. still want to process disconnects etc.)
  1630. if (Transport.active != null)
  1631. Transport.active.ServerLateUpdate();
  1632. // measure actual tick rate every second.
  1633. if (active)
  1634. {
  1635. ++actualTickRateCounter;
  1636. // NetworkTime.localTime has defines for 2019 / 2020 compatibility
  1637. if (NetworkTime.localTime >= actualTickRateStart + 1)
  1638. {
  1639. // calculate avg by exact elapsed time.
  1640. // assuming 1s wouldn't be accurate, usually a few more ms passed.
  1641. float elapsed = (float)(NetworkTime.localTime - actualTickRateStart);
  1642. actualTickRate = Mathf.RoundToInt(actualTickRateCounter / elapsed);
  1643. actualTickRateStart = NetworkTime.localTime;
  1644. actualTickRateCounter = 0;
  1645. }
  1646. // measure total update time. including transport.
  1647. // because in early update, transport update calls handlers.
  1648. lateUpdateDuration.End();
  1649. fullUpdateDuration.End();
  1650. }
  1651. }
  1652. }
  1653. }