KcpClient.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // kcp client logic abstracted into a class.
  2. // for use in Mirror, DOTSNET, testing, etc.
  3. using System;
  4. namespace kcp2k
  5. {
  6. public class KcpClient
  7. {
  8. // events
  9. public Action OnConnected;
  10. public Action<ArraySegment<byte>, KcpChannel> OnData;
  11. public Action OnDisconnected;
  12. // state
  13. public KcpClientConnection connection;
  14. public bool connected;
  15. public KcpClient(Action OnConnected, Action<ArraySegment<byte>, KcpChannel> OnData, Action OnDisconnected)
  16. {
  17. this.OnConnected = OnConnected;
  18. this.OnData = OnData;
  19. this.OnDisconnected = OnDisconnected;
  20. }
  21. // CreateConnection can be overwritten for where-allocation:
  22. // https://github.com/vis2k/where-allocation
  23. protected virtual KcpClientConnection CreateConnection() =>
  24. new KcpClientConnection();
  25. public void Connect(string address,
  26. ushort port,
  27. bool noDelay,
  28. uint interval,
  29. int fastResend = 0,
  30. bool congestionWindow = true,
  31. uint sendWindowSize = Kcp.WND_SND,
  32. uint receiveWindowSize = Kcp.WND_RCV,
  33. int timeout = KcpConnection.DEFAULT_TIMEOUT,
  34. uint maxRetransmits = Kcp.DEADLINK,
  35. bool maximizeSendReceiveBuffersToOSLimit = false)
  36. {
  37. if (connected)
  38. {
  39. Log.Warning("KCP: client already connected!");
  40. return;
  41. }
  42. // create connection
  43. connection = CreateConnection();
  44. // setup events
  45. connection.OnAuthenticated = () =>
  46. {
  47. Log.Info($"KCP: OnClientConnected");
  48. connected = true;
  49. OnConnected.Invoke();
  50. };
  51. connection.OnData = (message, channel) =>
  52. {
  53. //Log.Debug($"KCP: OnClientData({BitConverter.ToString(message.Array, message.Offset, message.Count)})");
  54. OnData.Invoke(message, channel);
  55. };
  56. connection.OnDisconnected = () =>
  57. {
  58. Log.Info($"KCP: OnClientDisconnected");
  59. connected = false;
  60. connection = null;
  61. OnDisconnected.Invoke();
  62. };
  63. // connect
  64. connection.Connect(address,
  65. port,
  66. noDelay,
  67. interval,
  68. fastResend,
  69. congestionWindow,
  70. sendWindowSize,
  71. receiveWindowSize,
  72. timeout,
  73. maxRetransmits,
  74. maximizeSendReceiveBuffersToOSLimit);
  75. }
  76. public void Send(ArraySegment<byte> segment, KcpChannel channel)
  77. {
  78. if (connected)
  79. {
  80. connection.SendData(segment, channel);
  81. }
  82. else Log.Warning("KCP: can't send because client not connected!");
  83. }
  84. public void Disconnect()
  85. {
  86. // only if connected
  87. // otherwise we end up in a deadlock because of an open Mirror bug:
  88. // https://github.com/vis2k/Mirror/issues/2353
  89. if (connected)
  90. {
  91. // call Disconnect and let the connection handle it.
  92. // DO NOT set it to null yet. it needs to be updated a few more
  93. // times first. let the connection handle it!
  94. connection?.Disconnect();
  95. }
  96. }
  97. // process incoming messages. should be called before updating the world.
  98. public void TickIncoming()
  99. {
  100. // recv on socket first, then process incoming
  101. // (even if we didn't receive anything. need to tick ping etc.)
  102. // (connection is null if not active)
  103. connection?.RawReceive();
  104. connection?.TickIncoming();
  105. }
  106. // process outgoing messages. should be called after updating the world.
  107. public void TickOutgoing()
  108. {
  109. // process outgoing
  110. // (connection is null if not active)
  111. connection?.TickOutgoing();
  112. }
  113. // process incoming and outgoing for convenience
  114. // => ideally call ProcessIncoming() before updating the world and
  115. // ProcessOutgoing() after updating the world for minimum latency
  116. public void Tick()
  117. {
  118. TickIncoming();
  119. TickOutgoing();
  120. }
  121. }
  122. }