LocalConnectionToServer.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace Mirror
  5. {
  6. // a localClient's connection TO a server.
  7. // send messages on this connection causes the server's handler function to be invoked directly.
  8. public class LocalConnectionToServer : NetworkConnectionToServer
  9. {
  10. internal LocalConnectionToClient connectionToClient;
  11. // packet queue
  12. internal readonly Queue<NetworkWriterPooled> queue = new Queue<NetworkWriterPooled>();
  13. // Deprecated 2023-02-23
  14. [Obsolete("Use LocalConnectionToClient.address instead.")]
  15. public string address => "localhost";
  16. // see caller for comments on why we need this
  17. bool connectedEventPending;
  18. bool disconnectedEventPending;
  19. internal void QueueConnectedEvent() => connectedEventPending = true;
  20. internal void QueueDisconnectedEvent() => disconnectedEventPending = true;
  21. // Send stage two: serialized NetworkMessage as ArraySegment<byte>
  22. internal override void Send(ArraySegment<byte> segment, int channelId = Channels.Reliable)
  23. {
  24. if (segment.Count == 0)
  25. {
  26. Debug.LogError("LocalConnection.SendBytes cannot send zero bytes");
  27. return;
  28. }
  29. // OnTransportData assumes batching.
  30. // so let's make a batch with proper timestamp prefix.
  31. Batcher batcher = GetBatchForChannelId(channelId);
  32. batcher.AddMessage(segment, NetworkTime.localTime);
  33. // flush it to the server's OnTransportData immediately.
  34. // local connection to server always invokes immediately.
  35. using (NetworkWriterPooled writer = NetworkWriterPool.Get())
  36. {
  37. // make a batch with our local time (double precision)
  38. if (batcher.GetBatch(writer))
  39. {
  40. NetworkServer.OnTransportData(connectionId, writer.ToArraySegment(), channelId);
  41. }
  42. else Debug.LogError("Local connection failed to make batch. This should never happen.");
  43. }
  44. }
  45. internal override void Update()
  46. {
  47. base.Update();
  48. // should we still process a connected event?
  49. if (connectedEventPending)
  50. {
  51. connectedEventPending = false;
  52. NetworkClient.OnConnectedEvent?.Invoke();
  53. }
  54. // process internal messages so they are applied at the correct time
  55. while (queue.Count > 0)
  56. {
  57. // call receive on queued writer's content, return to pool
  58. NetworkWriterPooled writer = queue.Dequeue();
  59. ArraySegment<byte> message = writer.ToArraySegment();
  60. // OnTransportData assumes a proper batch with timestamp etc.
  61. // let's make a proper batch and pass it to OnTransportData.
  62. Batcher batcher = GetBatchForChannelId(Channels.Reliable);
  63. batcher.AddMessage(message, NetworkTime.localTime);
  64. using (NetworkWriterPooled batchWriter = NetworkWriterPool.Get())
  65. {
  66. // make a batch with our local time (double precision)
  67. if (batcher.GetBatch(batchWriter))
  68. {
  69. NetworkClient.OnTransportData(batchWriter.ToArraySegment(), Channels.Reliable);
  70. }
  71. }
  72. NetworkWriterPool.Return(writer);
  73. }
  74. // should we still process a disconnected event?
  75. if (disconnectedEventPending)
  76. {
  77. disconnectedEventPending = false;
  78. NetworkClient.OnDisconnectedEvent?.Invoke();
  79. }
  80. }
  81. /// <summary>Disconnects this connection.</summary>
  82. internal void DisconnectInternal()
  83. {
  84. // set not ready and handle clientscene disconnect in any case
  85. // (might be client or host mode here)
  86. // TODO remove redundant state. have one source of truth for .ready!
  87. isReady = false;
  88. NetworkClient.ready = false;
  89. }
  90. /// <summary>Disconnects this connection.</summary>
  91. public override void Disconnect()
  92. {
  93. connectionToClient.DisconnectInternal();
  94. DisconnectInternal();
  95. // simulate what a true remote connection would do:
  96. // first, the server should remove it:
  97. // TODO should probably be in connectionToClient.DisconnectInternal
  98. // because that's the NetworkServer's connection!
  99. NetworkServer.RemoveLocalConnection();
  100. // then call OnTransportDisconnected for proper disconnect handling,
  101. // callbacks & cleanups.
  102. // => otherwise OnClientDisconnected() is never called!
  103. // => see NetworkClientTests.DisconnectCallsOnClientDisconnect_HostMode()
  104. NetworkClient.OnTransportDisconnected();
  105. }
  106. // true because local connections never timeout
  107. internal override bool IsAlive(float timeout) => true;
  108. }
  109. }