Ignorance.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. // Ignorance 1.4.x
  2. // Ignorance. It really kicks the Unity LLAPIs ass.
  3. // https://github.com/SoftwareGuy/Ignorance
  4. // -----------------
  5. // Copyright (c) 2019 - 2020 Matt Coburn (SoftwareGuy/Coburn64)
  6. // Ignorance Transport is licensed under the MIT license. Refer
  7. // to the LICENSE file for more information.
  8. // -----------------
  9. // Ignorance Experimental (New) Version
  10. // -----------------
  11. using ENet;
  12. using Mirror;
  13. using System;
  14. using System.Collections.Generic;
  15. using UnityEngine;
  16. namespace IgnoranceTransport
  17. {
  18. [DisallowMultipleComponent]
  19. public class Ignorance : Transport
  20. {
  21. #region Inspector options
  22. public int port = 7777;
  23. [Header("Debug & Logging Configuration")]
  24. [Tooltip("How verbose do you want Ignorance to be?")]
  25. public IgnoranceLogType LogType = IgnoranceLogType.Standard;
  26. [Tooltip("Uses OnGUI to present you with statistics for Server and Client backend instances.")]
  27. public bool DebugDisplay = false;
  28. [Header("Server Configuration")]
  29. [Tooltip("Should the server bind to all interfaces?")]
  30. public bool serverBindsAll = true;
  31. [Tooltip("This is only used if Server Binds All is unticked.")]
  32. public string serverBindAddress = string.Empty;
  33. [Tooltip("This tells ENet how many Peer slots to create. Helps performance, avoids looping over huge native arrays. Recommended: Max Mirror players, rounded to nearest 10. (Example: 16 -> 20).")]
  34. public int serverMaxPeerCapacity = 50;
  35. [Tooltip("How long ENet waits in native world. The higher this value, the more CPU usage. Lower values may/may not impact performance at high packet load.")]
  36. public int serverMaxNativeWaitTime = 1;
  37. [Header("Client Configuration")]
  38. [Tooltip("How long ENet waits in native world. The higher this value, the more CPU usage used. This is for the client, unlike the one above. Higher value probably trades CPU for more responsive networking.")]
  39. public int clientMaxNativeWaitTime = 3;
  40. [Tooltip("Interval between asking ENet for client status updates. Set to -1 to disable.")]
  41. public int clientStatusUpdateInterval = -1;
  42. [Header("Channel Configuration")]
  43. [Tooltip("You must define your channels in the array shown here, otherwise ENet will not know what channel delivery type to use.")]
  44. public IgnoranceChannelTypes[] Channels;
  45. [Header("Low-level Tweaking")]
  46. [Tooltip("Used internally to keep allocations to a minimum. This is how much memory will be consumed by the packet buffer on startup, and then reused.")]
  47. public int PacketBufferCapacity = 4096;
  48. [Tooltip("For UDP based protocols, it's best to keep your data under the safe MTU of 1200 bytes. You can increase this, however beware this may open you up to allocation attacks.")]
  49. public int MaxAllowedPacketSize = 33554432;
  50. #endregion
  51. #region Public Statistics
  52. public IgnoranceClientStats ClientStatistics;
  53. #endregion
  54. #if MIRROR_26_0_OR_NEWER
  55. public override bool Available()
  56. {
  57. // Ignorance is not available for Unity WebGL, the PS4 (no dev kit to confirm) or Switch (port exists but I have no access to said code).
  58. // Ignorance is available for most other operating systems.
  59. #if (UNITY_WEBGL || UNITY_PS4 || UNITY_SWITCH)
  60. return false;
  61. #else
  62. return true;
  63. #endif
  64. }
  65. public void Awake()
  66. {
  67. if (LogType != IgnoranceLogType.Nothing)
  68. Debug.Log($"Thanks for using Ignorance {IgnoranceInternals.Version}. Keep up to date, report bugs and support the developer at https://github.com/SoftwareGuy/Ignorance!");
  69. }
  70. public override string ToString()
  71. {
  72. return $"Ignorance v{IgnoranceInternals.Version}";
  73. }
  74. public override void ClientConnect(string address)
  75. {
  76. ClientState = ConnectionState.Connecting;
  77. cachedConnectionAddress = address;
  78. // Initialize.
  79. InitializeClientBackend();
  80. // Get going.
  81. ignoreDataPackets = false;
  82. // Start!
  83. Client.Start();
  84. }
  85. public override void ClientConnect(Uri uri)
  86. {
  87. if (uri.Scheme != IgnoranceInternals.Scheme)
  88. throw new ArgumentException($"You used an invalid URI: {uri}. Please use {IgnoranceInternals.Scheme}://host:port instead", nameof(uri));
  89. if (!uri.IsDefaultPort)
  90. // Set the communication port to the one specified.
  91. port = uri.Port;
  92. // Pass onwards to the proper handler.
  93. ClientConnect(uri.Host);
  94. }
  95. public override bool ClientConnected() => ClientState == ConnectionState.Connected;
  96. public override void ClientDisconnect()
  97. {
  98. if (Client != null)
  99. Client.Stop();
  100. // TODO: Figure this one out to see if it's related to a race condition.
  101. // Maybe experiment with a while loop to pause main thread when disconnecting,
  102. // since client might not stop on a dime.
  103. // while(Client.IsAlive) ;
  104. // v1.4.0b1: Probably fixed in IgnoranceClient.cs; need further testing.
  105. // ignoreDataPackets = true;
  106. ClientState = ConnectionState.Disconnected;
  107. }
  108. #if !MIRROR_37_0_OR_NEWER
  109. public override void ClientSend(int channelId, ArraySegment<byte> segment)
  110. #else
  111. // v1.4.0b6: Mirror rearranged the ClientSend params, so we need to apply a fix for that or
  112. // we end up using the obsoleted version. The obsolete version isn't a fatal error, but
  113. // it's best to stick with the new structures.
  114. public override void ClientSend(ArraySegment<byte> segment, int channelId)
  115. #endif
  116. {
  117. if (Client == null)
  118. {
  119. Debug.LogError("Client object is null, this shouldn't really happen but it did...");
  120. return;
  121. }
  122. if (channelId < 0 || channelId > Channels.Length)
  123. {
  124. Debug.LogError("Channel ID is out of bounds.");
  125. return;
  126. }
  127. // Create our struct...
  128. Packet clientOutgoingPacket = default;
  129. int byteCount = segment.Count;
  130. int byteOffset = segment.Offset;
  131. // Set our desired flags...
  132. PacketFlags desiredFlags = (PacketFlags)Channels[channelId];
  133. // Warn if over recommended MTU...
  134. bool flagsSet = (desiredFlags & ReliableOrUnreliableFragmented) > 0;
  135. if (LogType != IgnoranceLogType.Nothing && byteCount > 1200 && !flagsSet)
  136. Debug.LogWarning($"Warning: Client trying to send a Unreliable packet bigger than the recommended ENet 1200 byte MTU ({byteCount} > 1200). ENet will force Reliable Fragmented delivery.");
  137. // Create the packet.
  138. clientOutgoingPacket.Create(segment.Array, byteOffset, byteCount + byteOffset, desiredFlags);
  139. // byteCount
  140. // Enqueue the packet.
  141. IgnoranceOutgoingPacket dispatchPacket = new IgnoranceOutgoingPacket
  142. {
  143. Channel = (byte)channelId,
  144. Payload = clientOutgoingPacket
  145. };
  146. // Pass the packet onto the thread for dispatch.
  147. Client.Outgoing.Enqueue(dispatchPacket);
  148. }
  149. public override bool ServerActive()
  150. {
  151. // Very simple check.
  152. return Server != null && Server.IsAlive;
  153. }
  154. #if !MIRROR_37_0_OR_NEWER
  155. // Workaround for legacy Mirror versions.
  156. public override bool ServerDisconnect(int connectionId) => ServerDisconnectLegacy(connectionId);
  157. #else
  158. public override void ServerDisconnect(int connectionId)
  159. {
  160. if (Server == null)
  161. {
  162. Debug.LogError("Cannot enqueue kick packet; our Server object is null. Something has gone wrong.");
  163. // Return here because otherwise we will get a NRE when trying to enqueue the kick packet.
  164. return;
  165. }
  166. IgnoranceCommandPacket kickPacket = new IgnoranceCommandPacket
  167. {
  168. Type = IgnoranceCommandType.ServerKickPeer,
  169. PeerId = (uint)connectionId - 1 // ENet's native peer ID will be ConnID - 1
  170. };
  171. // Pass the packet onto the thread for dispatch.
  172. Server.Commands.Enqueue(kickPacket);
  173. }
  174. #endif
  175. public override string ServerGetClientAddress(int connectionId)
  176. {
  177. if (ConnectionLookupDict.TryGetValue(connectionId, out PeerConnectionData details))
  178. return $"{details.IP}:{details.Port}";
  179. return "(unavailable)";
  180. }
  181. #if !MIRROR_37_0_OR_NEWER
  182. public override void ServerSend(int connectionId, int channelId, ArraySegment<byte> segment)
  183. #else
  184. // v1.4.0b6: Mirror rearranged the ServerSend params, so we need to apply a fix for that or
  185. // we end up using the obsoleted version. The obsolete version isn't a fatal error, but
  186. // it's best to stick with the new structures.
  187. public override void ServerSend(int connectionId, ArraySegment<byte> segment, int channelId)
  188. #endif
  189. {
  190. // Debug.Log($"ServerSend({connectionId}, {channelId}, <{segment.Count} byte segment>)");
  191. if (Server == null)
  192. {
  193. Debug.LogError("Cannot enqueue data packet; our Server object is null. Something has gone wrong.");
  194. return;
  195. }
  196. if (channelId < 0 || channelId > Channels.Length)
  197. {
  198. Debug.LogError("Channel ID is out of bounds.");
  199. return;
  200. }
  201. // Packet Struct
  202. Packet serverOutgoingPacket = default;
  203. int byteCount = segment.Count;
  204. int byteOffset = segment.Offset;
  205. PacketFlags desiredFlags = (PacketFlags)Channels[channelId];
  206. // Warn if over recommended MTU
  207. bool flagsSet = (desiredFlags & ReliableOrUnreliableFragmented) > 0;
  208. if (LogType != IgnoranceLogType.Nothing && byteCount > 1200 && !flagsSet)
  209. Debug.LogWarning($"Warning: Server trying to send a Unreliable packet bigger than the recommended ENet 1200 byte MTU ({byteCount} > 1200). ENet will force Reliable Fragmented delivery.");
  210. // Create the packet.
  211. serverOutgoingPacket.Create(segment.Array, byteOffset, byteCount + byteOffset, (PacketFlags)Channels[channelId]);
  212. // Enqueue the packet.
  213. IgnoranceOutgoingPacket dispatchPacket = new IgnoranceOutgoingPacket
  214. {
  215. Channel = (byte)channelId,
  216. NativePeerId = (uint)connectionId - 1, // ENet's native peer ID will be ConnID - 1
  217. Payload = serverOutgoingPacket
  218. };
  219. Server.Outgoing.Enqueue(dispatchPacket);
  220. }
  221. public override void ServerStart()
  222. {
  223. if (LogType != IgnoranceLogType.Nothing)
  224. Debug.Log("Ignorance Server Instance starting up...");
  225. InitializeServerBackend();
  226. Server.Start();
  227. }
  228. public override void ServerStop()
  229. {
  230. if (Server != null)
  231. {
  232. if (LogType != IgnoranceLogType.Nothing)
  233. Debug.Log("Ignorance Server Instance shutting down...");
  234. Server.Stop();
  235. }
  236. ConnectionLookupDict.Clear();
  237. }
  238. public override Uri ServerUri()
  239. {
  240. UriBuilder builder = new UriBuilder
  241. {
  242. Scheme = IgnoranceInternals.Scheme,
  243. Host = serverBindAddress,
  244. Port = port
  245. };
  246. return builder.Uri;
  247. }
  248. public override void Shutdown()
  249. {
  250. // TODO: Nothing needed here?
  251. }
  252. // Check to ensure channels 0 and 1 mimic LLAPI. Override this at your own risk.
  253. private void OnValidate()
  254. {
  255. if (Channels != null && Channels.Length >= 2)
  256. {
  257. // Check to make sure that Channel 0 and 1 are correct.
  258. if (Channels[0] != IgnoranceChannelTypes.Reliable)
  259. {
  260. Debug.LogWarning("Please do not modify Ignorance Channel 0. The channel will be reset to Reliable delivery. If you need a channel with a different delivery, define and use it instead.");
  261. Channels[0] = IgnoranceChannelTypes.Reliable;
  262. }
  263. if (Channels[1] != IgnoranceChannelTypes.Unreliable)
  264. {
  265. Debug.LogWarning("Please do not modify Ignorance Channel 1. The channel will be reset to Unreliable delivery. If you need a channel with a different delivery, define and use it instead.");
  266. Channels[1] = IgnoranceChannelTypes.Unreliable;
  267. }
  268. }
  269. else
  270. {
  271. Debug.LogWarning("Invalid Channels setting, fixing. If you've just added Ignorance to your NetworkManager GameObject, seeing this message is normal.");
  272. Channels = new IgnoranceChannelTypes[2]
  273. {
  274. IgnoranceChannelTypes.Reliable,
  275. IgnoranceChannelTypes.Unreliable
  276. };
  277. }
  278. // ENet only supports a maximum of 32MB packet size.
  279. if (MaxAllowedPacketSize > 33554432)
  280. MaxAllowedPacketSize = 33554432;
  281. }
  282. private void InitializeServerBackend()
  283. {
  284. if (Server == null)
  285. {
  286. Debug.LogWarning("IgnoranceServer reference for Server mode was null. This shouldn't happen, but to be safe we'll reinitialize it.");
  287. Server = new IgnoranceServer();
  288. }
  289. // Set up the new IgnoranceServer reference.
  290. if (serverBindsAll)
  291. // MacOS is special. It's also a massive thorn in my backside.
  292. Server.BindAddress = IgnoranceInternals.BindAllMacs;
  293. else
  294. // Use the supplied bind address.
  295. Server.BindAddress = serverBindAddress;
  296. // Sets port, maximum peers, max channels, the server poll time, maximum packet size and verbosity.
  297. Server.BindPort = port;
  298. Server.MaximumPeers = serverMaxPeerCapacity;
  299. Server.MaximumChannels = Channels.Length;
  300. Server.PollTime = serverMaxNativeWaitTime;
  301. Server.MaximumPacketSize = MaxAllowedPacketSize;
  302. Server.Verbosity = (int)LogType;
  303. // Initializes the packet buffer.
  304. // Allocates once, that's it.
  305. if (InternalPacketBuffer == null)
  306. InternalPacketBuffer = new byte[PacketBufferCapacity];
  307. }
  308. private void InitializeClientBackend()
  309. {
  310. if (Client == null)
  311. {
  312. Debug.LogWarning("Ignorance: IgnoranceClient reference for Client mode was null. This shouldn't happen, but to be safe we'll reinitialize it.");
  313. Client = new IgnoranceClient();
  314. }
  315. // Sets address, port, channels to expect, verbosity, the server poll time and maximum packet size.
  316. Client.ConnectAddress = cachedConnectionAddress;
  317. Client.ConnectPort = port;
  318. Client.ExpectedChannels = Channels.Length;
  319. Client.PollTime = clientMaxNativeWaitTime;
  320. Client.MaximumPacketSize = MaxAllowedPacketSize;
  321. Client.Verbosity = (int)LogType;
  322. // Initializes the packet buffer.
  323. // Allocates once, that's it.
  324. if (InternalPacketBuffer == null)
  325. InternalPacketBuffer = new byte[PacketBufferCapacity];
  326. }
  327. private void ProcessServerPackets()
  328. {
  329. IgnoranceIncomingPacket incomingPacket;
  330. IgnoranceConnectionEvent connectionEvent;
  331. int adjustedConnectionId;
  332. Packet payload;
  333. // Incoming connection events.
  334. while (Server.ConnectionEvents.TryDequeue(out connectionEvent))
  335. {
  336. adjustedConnectionId = (int)connectionEvent.NativePeerId + 1;
  337. if (LogType == IgnoranceLogType.Verbose)
  338. Debug.Log($"Processing a server connection event from ENet native peer {connectionEvent.NativePeerId}. This peer would be Mirror ConnID {adjustedConnectionId}.");
  339. // TODO: Investigate ArgumentException: An item with the same key has already been added. Key: <id>
  340. ConnectionLookupDict.Add(adjustedConnectionId, new PeerConnectionData
  341. {
  342. NativePeerId = connectionEvent.NativePeerId,
  343. IP = connectionEvent.IP,
  344. Port = connectionEvent.Port
  345. });
  346. OnServerConnected?.Invoke(adjustedConnectionId);
  347. }
  348. // Handle incoming data packets.
  349. // Console.WriteLine($"Server Incoming Queue is {Server.Incoming.Count}");
  350. while (Server.Incoming.TryDequeue(out incomingPacket))
  351. {
  352. adjustedConnectionId = (int)incomingPacket.NativePeerId + 1;
  353. payload = incomingPacket.Payload;
  354. int length = payload.Length;
  355. ArraySegment<byte> dataSegment;
  356. // Copy to working buffer and dispose of it.
  357. if (length > InternalPacketBuffer.Length)
  358. {
  359. byte[] oneFreshNTastyGcAlloc = new byte[length];
  360. payload.CopyTo(oneFreshNTastyGcAlloc);
  361. dataSegment = new ArraySegment<byte>(oneFreshNTastyGcAlloc, 0, length);
  362. }
  363. else
  364. {
  365. payload.CopyTo(InternalPacketBuffer);
  366. dataSegment = new ArraySegment<byte>(InternalPacketBuffer, 0, length);
  367. }
  368. payload.Dispose();
  369. OnServerDataReceived?.Invoke(adjustedConnectionId, dataSegment, incomingPacket.Channel);
  370. // Some messages can disable the transport
  371. // If the transport was disabled by any of the messages, we have to break out of the loop and wait until we've been re-enabled.
  372. if (!enabled)
  373. break;
  374. }
  375. // Disconnection events.
  376. while (Server.DisconnectionEvents.TryDequeue(out IgnoranceConnectionEvent disconnectionEvent))
  377. {
  378. adjustedConnectionId = (int)disconnectionEvent.NativePeerId + 1;
  379. if (LogType == IgnoranceLogType.Verbose)
  380. Debug.Log($"ProcessServerPackets fired; handling disconnection event from native peer {disconnectionEvent.NativePeerId}.");
  381. ConnectionLookupDict.Remove(adjustedConnectionId);
  382. // Invoke Mirror handler.
  383. OnServerDisconnected?.Invoke(adjustedConnectionId);
  384. }
  385. }
  386. private void ProcessClientPackets()
  387. {
  388. IgnoranceIncomingPacket incomingPacket;
  389. IgnoranceCommandPacket commandPacket;
  390. IgnoranceClientStats clientStats;
  391. Packet payload;
  392. IgnoranceConnectionEvent connectionEvent;
  393. // Handle connection events.
  394. while (Client.ConnectionEvents.TryDequeue(out connectionEvent))
  395. {
  396. if (LogType == IgnoranceLogType.Verbose)
  397. Debug.Log($"ProcessClientConnectionEvents fired: processing a client ConnectionEvents queue item.");
  398. if (connectionEvent.WasDisconnect)
  399. {
  400. // Disconnected from server.
  401. ClientState = ConnectionState.Disconnected;
  402. if (LogType != IgnoranceLogType.Nothing)
  403. Debug.Log($"Ignorance Client has been disconnected from server.");
  404. ignoreDataPackets = true;
  405. OnClientDisconnected?.Invoke();
  406. }
  407. else
  408. {
  409. // Connected to server.
  410. ClientState = ConnectionState.Connected;
  411. if (LogType != IgnoranceLogType.Nothing)
  412. Debug.Log($"Ignorance Client successfully connected to server at address {connectionEvent.IP}:{connectionEvent.Port}");
  413. ignoreDataPackets = false;
  414. OnClientConnected?.Invoke();
  415. }
  416. }
  417. // Now handle the incoming messages.
  418. while (Client.Incoming.TryDequeue(out incomingPacket))
  419. {
  420. // Temporary fix: if ENet thread is too fast for Mirror, then ignore the packet.
  421. // This is seen sometimes if you stop the client and there's still stuff in the queue.
  422. if (ignoreDataPackets)
  423. {
  424. if (LogType == IgnoranceLogType.Verbose)
  425. Debug.Log("ProcessClientPackets cycle skipped; ignoring data packet");
  426. break;
  427. }
  428. // Otherwise client recieved data, advise Mirror.
  429. // print($"Byte array: {incomingPacket.RentedByteArray.Length}. Packet Length: {incomingPacket.Length}");
  430. payload = incomingPacket.Payload;
  431. int length = payload.Length;
  432. ArraySegment<byte> dataSegment;
  433. // Copy to working buffer and dispose of it.
  434. if (length > InternalPacketBuffer.Length)
  435. {
  436. // Unity's favourite: A fresh 'n' tasty GC Allocation!
  437. byte[] oneFreshNTastyGcAlloc = new byte[length];
  438. payload.CopyTo(oneFreshNTastyGcAlloc);
  439. dataSegment = new ArraySegment<byte>(oneFreshNTastyGcAlloc, 0, length);
  440. }
  441. else
  442. {
  443. payload.CopyTo(InternalPacketBuffer);
  444. dataSegment = new ArraySegment<byte>(InternalPacketBuffer, 0, length);
  445. }
  446. payload.Dispose();
  447. OnClientDataReceived?.Invoke(dataSegment, incomingPacket.Channel);
  448. // Some messages can disable the transport
  449. // If the transport was disabled by any of the messages, we have to break out of the loop and wait until we've been re-enabled.
  450. if (!enabled)
  451. break;
  452. }
  453. // Step 3: Handle other commands.
  454. while (Client.Commands.TryDequeue(out commandPacket))
  455. {
  456. switch (commandPacket.Type)
  457. {
  458. // ...
  459. default:
  460. break;
  461. }
  462. }
  463. // Step 4: Handle status updates.
  464. if (Client.StatusUpdates.TryDequeue(out clientStats))
  465. {
  466. ClientStatistics = clientStats;
  467. }
  468. }
  469. #region Main Thread Processing and Polling
  470. // Ignorance 1.4.0b5: To use Mirror's polling or not use Mirror's polling, that is up to the developer to decide
  471. #if !IGNORANCE_MIRROR_POLLING
  472. // IMPORTANT: Set Ignorance' execution order before everything else. Yes, that's -32000 !!
  473. // This ensures it has priority over other things.
  474. // FixedUpdate can be called many times per frame.
  475. // Once we've handled stuff, we set a flag so that we don't poll again for this frame.
  476. private bool fixedUpdateCompletedWork;
  477. public void FixedUpdate()
  478. {
  479. if (!enabled) return;
  480. if (fixedUpdateCompletedWork) return;
  481. ProcessAndExecuteAllPackets();
  482. // Flip the bool to signal we've done our work.
  483. fixedUpdateCompletedWork = true;
  484. }
  485. // Normally, Mirror blocks Update() due to poor design decisions...
  486. // But thanks to Vincenzo, we've found a way to bypass that block.
  487. // Update is called once per frame. We don't have to worry about this shit now.
  488. public new void Update()
  489. {
  490. if (!enabled) return;
  491. // Process what FixedUpdate missed, only if the boolean is not set.
  492. if (!fixedUpdateCompletedWork)
  493. ProcessAndExecuteAllPackets();
  494. // Flip back the bool, so it can be reset.
  495. fixedUpdateCompletedWork = false;
  496. }
  497. // Processes and Executes All Packets.
  498. private void ProcessAndExecuteAllPackets()
  499. {
  500. // Process Server Events...
  501. if (Server.IsAlive)
  502. ProcessServerPackets();
  503. // Process Client Events...
  504. if (Client.IsAlive)
  505. {
  506. ProcessClientPackets();
  507. if (ClientState == ConnectionState.Connected && clientStatusUpdateInterval > -1)
  508. {
  509. statusUpdateTimer += Time.deltaTime;
  510. if (statusUpdateTimer >= clientStatusUpdateInterval)
  511. {
  512. Client.Commands.Enqueue(new IgnoranceCommandPacket { Type = IgnoranceCommandType.ClientRequestsStatusUpdate });
  513. statusUpdateTimer = 0f;
  514. }
  515. }
  516. }
  517. }
  518. #else
  519. // This section will be compiled in instead if you enable IGNORANCE_MIRROR_POLLING.
  520. public override void ServerEarlyUpdate() {
  521. // This is used by Mirror to consume the incoming server packets.
  522. if (!enabled) return;
  523. // Process Server Events...
  524. if (Server.IsAlive)
  525. ProcessServerPackets();
  526. }
  527. public override void ClientEarlyUpdate() {
  528. // This is used by Mirror to consume the incoming client packets.
  529. if(!enabled) return;
  530. if(Client.IsAlive)
  531. {
  532. ProcessClientPackets();
  533. if (ClientState == ConnectionState.Connected && clientStatusUpdateInterval > -1)
  534. {
  535. statusUpdateTimer += Time.deltaTime;
  536. if (statusUpdateTimer >= clientStatusUpdateInterval)
  537. {
  538. Client.Commands.Enqueue(new IgnoranceCommandPacket { Type = IgnoranceCommandType.ClientRequestsStatusUpdate });
  539. statusUpdateTimer = 0f;
  540. }
  541. }
  542. }
  543. }
  544. /*
  545. public override void ClientLateUpdate() {
  546. // This is used by Mirror to send out the outgoing client packets.
  547. if (!enabled) return;
  548. }
  549. public override void ServerLateUpdate() {
  550. // This is used by Mirror to send out the outgoing server packets.
  551. if (!enabled) return;
  552. }
  553. */
  554. #endif
  555. #endregion
  556. #region Debug
  557. private void OnGUI()
  558. {
  559. if (DebugDisplay)
  560. GUI.Box(new Rect(
  561. new Vector2(32, Screen.height - 240), new Vector2(200, 160)),
  562. "-- CLIENT --\n" +
  563. $"State: {ClientState}\n" +
  564. $"Incoming Queue: {Client.Incoming.Count}\n" +
  565. $"Outgoing Queue: {Client.Outgoing.Count}\n\n" +
  566. "-- SERVER --\n" +
  567. $"Incoming Queue: {Server.Incoming.Count}\n" +
  568. $"Outgoing Queue: {Server.Outgoing.Count}\n" +
  569. $"ConnEvent Queue: {Server.ConnectionEvents.Count}"
  570. );
  571. }
  572. #endregion
  573. public override int GetMaxPacketSize(int channelId = 0) => MaxAllowedPacketSize;
  574. // UDP Recommended Max MTU = 1200.
  575. public override int GetMaxBatchSize(int channelId) {
  576. bool isFragmentedAlready = ((PacketFlags)Channels[channelId] & ReliableOrUnreliableFragmented) > 0;
  577. return isFragmentedAlready ? MaxAllowedPacketSize : 1200;
  578. }
  579. #region Internals
  580. private bool ignoreDataPackets;
  581. private string cachedConnectionAddress = string.Empty;
  582. private IgnoranceServer Server = new IgnoranceServer();
  583. private IgnoranceClient Client = new IgnoranceClient();
  584. private Dictionary<int, PeerConnectionData> ConnectionLookupDict = new Dictionary<int, PeerConnectionData>();
  585. private enum ConnectionState { Connecting, Connected, Disconnecting, Disconnected }
  586. private ConnectionState ClientState = ConnectionState.Disconnected;
  587. private byte[] InternalPacketBuffer;
  588. private const PacketFlags ReliableOrUnreliableFragmented = PacketFlags.Reliable | PacketFlags.UnreliableFragmented;
  589. private float statusUpdateTimer = 0f;
  590. #endregion
  591. #region Legacy Overrides
  592. #if !MIRROR_37_0_OR_NEWER
  593. public bool ServerDisconnectLegacy(int connectionId)
  594. {
  595. if (Server == null)
  596. {
  597. Debug.LogError("Cannot enqueue kick packet; our Server object is null. Something has gone wrong.");
  598. // Return here because otherwise we will get a NRE when trying to enqueue the kick packet.
  599. return false;
  600. }
  601. IgnoranceCommandPacket kickPacket = new IgnoranceCommandPacket
  602. {
  603. Type = IgnoranceCommandType.ServerKickPeer,
  604. PeerId = (uint)connectionId - 1 // ENet's native peer ID will be ConnID - 1
  605. };
  606. // Pass the packet onto the thread for dispatch.
  607. Server.Commands.Enqueue(kickPacket);
  608. return true;
  609. }
  610. #endif
  611. #endregion
  612. #endif
  613. }
  614. }