EdgegapKcpClient.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // overwrite RawSend/Receive
  2. using System;
  3. using System.Net.Sockets;
  4. using Mirror;
  5. using UnityEngine;
  6. using kcp2k;
  7. namespace Edgegap
  8. {
  9. public class EdgegapKcpClient : KcpClient
  10. {
  11. // need buffer larger than KcpClient.rawReceiveBuffer to add metadata
  12. readonly byte[] relayReceiveBuffer;
  13. // authentication
  14. public uint userId;
  15. public uint sessionId;
  16. public ConnectionState connectionState = ConnectionState.Disconnected;
  17. // ping
  18. double lastPingTime;
  19. public EdgegapKcpClient(
  20. Action OnConnected,
  21. Action<ArraySegment<byte>, KcpChannel> OnData,
  22. Action OnDisconnected,
  23. Action<ErrorCode, string> OnError,
  24. KcpConfig config)
  25. : base(OnConnected, OnData, OnDisconnected, OnError, config)
  26. {
  27. relayReceiveBuffer = new byte[config.Mtu + Protocol.Overhead];
  28. }
  29. // custom start function with relay parameters; connects udp client.
  30. public void Connect(string relayAddress, ushort relayPort, uint userId, uint sessionId)
  31. {
  32. // reset last state
  33. connectionState = ConnectionState.Checking;
  34. this.userId = userId;
  35. this.sessionId = sessionId;
  36. // reuse base connect
  37. base.Connect(relayAddress, relayPort);
  38. }
  39. // parse metadata, then pass to kcp
  40. protected override bool RawReceive(out ArraySegment<byte> segment)
  41. {
  42. segment = default;
  43. if (socket == null) return false;
  44. try
  45. {
  46. if (socket.ReceiveNonBlocking(relayReceiveBuffer, out ArraySegment<byte> content))
  47. {
  48. using (NetworkReaderPooled reader = NetworkReaderPool.Get(content))
  49. {
  50. // parse message type
  51. if (reader.Remaining == 0)
  52. {
  53. Debug.LogWarning($"EdgegapClient: message of {content.Count} is too small to parse.");
  54. return false;
  55. }
  56. byte messageType = reader.ReadByte();
  57. // handle message type
  58. switch (messageType)
  59. {
  60. case (byte)MessageType.Ping:
  61. {
  62. // parse state
  63. if (reader.Remaining < 1) return false;
  64. ConnectionState last = connectionState;
  65. connectionState = (ConnectionState)reader.ReadByte();
  66. // log state changes for debugging.
  67. if (connectionState != last) Debug.Log($"EdgegapClient: state updated to: {connectionState}");
  68. // return true indicates Mirror to keep checking
  69. // for further messages.
  70. return true;
  71. }
  72. case (byte)MessageType.Data:
  73. {
  74. segment = reader.ReadBytesSegment(reader.Remaining);
  75. return true;
  76. }
  77. // wrong message type. return false, don't throw.
  78. default: return false;
  79. }
  80. }
  81. }
  82. }
  83. catch (SocketException e)
  84. {
  85. Log.Info($"EdgegapClient: looks like the other end has closed the connection. This is fine: {e}");
  86. Disconnect();
  87. }
  88. return false;
  89. }
  90. protected override void RawSend(ArraySegment<byte> data)
  91. {
  92. using (NetworkWriterPooled writer = NetworkWriterPool.Get())
  93. {
  94. writer.WriteUInt(userId);
  95. writer.WriteUInt(sessionId);
  96. writer.WriteByte((byte)MessageType.Data);
  97. writer.WriteBytes(data.Array, data.Offset, data.Count);
  98. base.RawSend(writer);
  99. }
  100. }
  101. void SendPing()
  102. {
  103. using (NetworkWriterPooled writer = NetworkWriterPool.Get())
  104. {
  105. writer.WriteUInt(userId);
  106. writer.WriteUInt(sessionId);
  107. writer.WriteByte((byte)MessageType.Ping);
  108. base.RawSend(writer);
  109. }
  110. }
  111. public override void TickOutgoing()
  112. {
  113. if (connected)
  114. {
  115. // ping every interval for keepalive & handshake
  116. if (NetworkTime.localTime >= lastPingTime + Protocol.PingInterval)
  117. {
  118. SendPing();
  119. lastPingTime = NetworkTime.localTime;
  120. }
  121. }
  122. base.TickOutgoing();
  123. }
  124. }
  125. }