LocalConnections.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace Mirror
  5. {
  6. // a server's connection TO a LocalClient.
  7. // sending messages on this connection causes the client's handler function to be invoked directly
  8. public class LocalConnectionToClient : NetworkConnectionToClient
  9. {
  10. internal LocalConnectionToServer connectionToServer;
  11. public LocalConnectionToClient() : base(LocalConnectionId) {}
  12. public override string address => "localhost";
  13. // Send stage two: serialized NetworkMessage as ArraySegment<byte>
  14. internal override void Send(ArraySegment<byte> segment, int channelId = Channels.Reliable)
  15. {
  16. // get a writer to copy the message into since the segment is only
  17. // valid until returning.
  18. // => pooled writer will be returned to pool when dequeuing.
  19. // => WriteBytes instead of WriteArraySegment because the latter
  20. // includes a 4 bytes header. we just want to write raw.
  21. //Debug.Log("Enqueue " + BitConverter.ToString(segment.Array, segment.Offset, segment.Count));
  22. PooledNetworkWriter writer = NetworkWriterPool.GetWriter();
  23. writer.WriteBytes(segment.Array, segment.Offset, segment.Count);
  24. connectionToServer.queue.Enqueue(writer);
  25. }
  26. // true because local connections never timeout
  27. internal override bool IsAlive(float timeout) => true;
  28. internal void DisconnectInternal()
  29. {
  30. // set not ready and handle clientscene disconnect in any case
  31. // (might be client or host mode here)
  32. isReady = false;
  33. RemoveFromObservingsObservers();
  34. }
  35. /// <summary>Disconnects this connection.</summary>
  36. public override void Disconnect()
  37. {
  38. DisconnectInternal();
  39. connectionToServer.DisconnectInternal();
  40. }
  41. }
  42. // a localClient's connection TO a server.
  43. // send messages on this connection causes the server's handler function to be invoked directly.
  44. public class LocalConnectionToServer : NetworkConnectionToServer
  45. {
  46. internal LocalConnectionToClient connectionToClient;
  47. // packet queue
  48. internal readonly Queue<PooledNetworkWriter> queue = new Queue<PooledNetworkWriter>();
  49. public override string address => "localhost";
  50. // see caller for comments on why we need this
  51. bool connectedEventPending;
  52. bool disconnectedEventPending;
  53. internal void QueueConnectedEvent() => connectedEventPending = true;
  54. internal void QueueDisconnectedEvent() => disconnectedEventPending = true;
  55. // Send stage two: serialized NetworkMessage as ArraySegment<byte>
  56. internal override void Send(ArraySegment<byte> segment, int channelId = Channels.Reliable)
  57. {
  58. if (segment.Count == 0)
  59. {
  60. Debug.LogError("LocalConnection.SendBytes cannot send zero bytes");
  61. return;
  62. }
  63. // OnTransportData assumes batching.
  64. // so let's make a batch with proper timestamp prefix.
  65. Batcher batcher = GetBatchForChannelId(channelId);
  66. batcher.AddMessage(segment);
  67. // flush it to the server's OnTransportData immediately.
  68. // local connection to server always invokes immediately.
  69. using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
  70. {
  71. // make a batch with our local time (double precision)
  72. if (batcher.MakeNextBatch(writer, NetworkTime.localTime))
  73. {
  74. NetworkServer.OnTransportData(connectionId, writer.ToArraySegment(), channelId);
  75. }
  76. else Debug.LogError("Local connection failed to make batch. This should never happen.");
  77. }
  78. }
  79. internal override void Update()
  80. {
  81. base.Update();
  82. // should we still process a connected event?
  83. if (connectedEventPending)
  84. {
  85. connectedEventPending = false;
  86. NetworkClient.OnConnectedEvent?.Invoke();
  87. }
  88. // process internal messages so they are applied at the correct time
  89. while (queue.Count > 0)
  90. {
  91. // call receive on queued writer's content, return to pool
  92. PooledNetworkWriter writer = queue.Dequeue();
  93. ArraySegment<byte> message = writer.ToArraySegment();
  94. // OnTransportData assumes a proper batch with timestamp etc.
  95. // let's make a proper batch and pass it to OnTransportData.
  96. Batcher batcher = GetBatchForChannelId(Channels.Reliable);
  97. batcher.AddMessage(message);
  98. using (PooledNetworkWriter batchWriter = NetworkWriterPool.GetWriter())
  99. {
  100. // make a batch with our local time (double precision)
  101. if (batcher.MakeNextBatch(batchWriter, NetworkTime.localTime))
  102. {
  103. NetworkClient.OnTransportData(batchWriter.ToArraySegment(), Channels.Reliable);
  104. }
  105. }
  106. NetworkWriterPool.Recycle(writer);
  107. }
  108. // should we still process a disconnected event?
  109. if (disconnectedEventPending)
  110. {
  111. disconnectedEventPending = false;
  112. NetworkClient.OnDisconnectedEvent?.Invoke();
  113. }
  114. }
  115. /// <summary>Disconnects this connection.</summary>
  116. internal void DisconnectInternal()
  117. {
  118. // set not ready and handle clientscene disconnect in any case
  119. // (might be client or host mode here)
  120. // TODO remove redundant state. have one source of truth for .ready!
  121. isReady = false;
  122. NetworkClient.ready = false;
  123. }
  124. /// <summary>Disconnects this connection.</summary>
  125. public override void Disconnect()
  126. {
  127. connectionToClient.DisconnectInternal();
  128. DisconnectInternal();
  129. // simulate what a true remote connection would do:
  130. // first, the server should remove it:
  131. // TODO should probably be in connectionToClient.DisconnectInternal
  132. // because that's the NetworkServer's connection!
  133. NetworkServer.RemoveLocalConnection();
  134. // then call OnTransportDisconnected for proper disconnect handling,
  135. // callbacks & cleanups.
  136. // => otherwise OnClientDisconnected() is never called!
  137. // => see NetworkClientTests.DisconnectCallsOnClientDisconnect_HostMode()
  138. NetworkClient.OnTransportDisconnected();
  139. }
  140. // true because local connections never timeout
  141. internal override bool IsAlive(float timeout) => true;
  142. }
  143. }