NetworkServer.cs 84 KB

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