LocalConnectionToServer.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  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. // see caller for comments on why we need this
  14. bool connectedEventPending;
  15. bool disconnectedEventPending;
  16. internal void QueueConnectedEvent() => connectedEventPending = true;
  17. internal void QueueDisconnectedEvent() => disconnectedEventPending = true;
  18. // Send stage two: serialized NetworkMessage as ArraySegment<byte>
  19. internal override void Send(ArraySegment<byte> segment, int channelId = Channels.Reliable)
  20. {
  21. if (segment.Count == 0)
  22. {
  23. Debug.LogError("LocalConnection.SendBytes cannot send zero bytes");
  24. return;
  25. }
  26. // instead of invoking it directly, we enqueue and process next update.
  27. // this way we can simulate a similar call flow as with remote clients.
  28. // the closer we get to simulating host as remote, the better!
  29. // both directions do this, so [Command] and [Rpc] behave the same way.
  30. //Debug.Log($"Enqueue {BitConverter.ToString(segment.Array, segment.Offset, segment.Count)}");
  31. NetworkWriterPooled writer = NetworkWriterPool.Get();
  32. writer.WriteBytes(segment.Array, segment.Offset, segment.Count);
  33. connectionToClient.queue.Enqueue(writer);
  34. }
  35. internal override void Update()
  36. {
  37. base.Update();
  38. // should we still process a connected event?
  39. if (connectedEventPending)
  40. {
  41. connectedEventPending = false;
  42. NetworkClient.OnConnectedEvent?.Invoke();
  43. }
  44. // process internal messages so they are applied at the correct time
  45. while (queue.Count > 0)
  46. {
  47. // call receive on queued writer's content, return to pool
  48. NetworkWriterPooled writer = queue.Dequeue();
  49. ArraySegment<byte> message = writer.ToArraySegment();
  50. // OnTransportData assumes a proper batch with timestamp etc.
  51. // let's make a proper batch and pass it to OnTransportData.
  52. Batcher batcher = GetBatchForChannelId(Channels.Reliable);
  53. batcher.AddMessage(message, NetworkTime.localTime);
  54. using (NetworkWriterPooled batchWriter = NetworkWriterPool.Get())
  55. {
  56. // make a batch with our local time (double precision)
  57. if (batcher.GetBatch(batchWriter))
  58. {
  59. NetworkClient.OnTransportData(batchWriter.ToArraySegment(), Channels.Reliable);
  60. }
  61. }
  62. NetworkWriterPool.Return(writer);
  63. }
  64. // should we still process a disconnected event?
  65. if (disconnectedEventPending)
  66. {
  67. disconnectedEventPending = false;
  68. NetworkClient.OnDisconnectedEvent?.Invoke();
  69. }
  70. }
  71. /// <summary>Disconnects this connection.</summary>
  72. internal void DisconnectInternal()
  73. {
  74. // set not ready and handle clientscene disconnect in any case
  75. // (might be client or host mode here)
  76. // TODO remove redundant state. have one source of truth for .ready!
  77. isReady = false;
  78. NetworkClient.ready = false;
  79. }
  80. /// <summary>Disconnects this connection.</summary>
  81. public override void Disconnect()
  82. {
  83. connectionToClient.DisconnectInternal();
  84. DisconnectInternal();
  85. // simulate what a true remote connection would do:
  86. // first, the server should remove it:
  87. // TODO should probably be in connectionToClient.DisconnectInternal
  88. // because that's the NetworkServer's connection!
  89. NetworkServer.RemoveLocalConnection();
  90. // then call OnTransportDisconnected for proper disconnect handling,
  91. // callbacks & cleanups.
  92. // => otherwise OnClientDisconnected() is never called!
  93. // => see NetworkClientTests.DisconnectCallsOnClientDisconnect_HostMode()
  94. NetworkClient.OnTransportDisconnected();
  95. }
  96. // true because local connections never timeout
  97. internal override bool IsAlive(float timeout) => true;
  98. }
  99. }