BITKit/Src/Core/Kcp/KcpNetClient.cs

724 lines
26 KiB
C#
Raw Normal View History

2023-06-29 14:57:11 +08:00
using System;
2024-06-08 10:07:40 +08:00
using System.Collections.Concurrent;
2023-10-06 23:43:19 +08:00
using System.Collections.Generic;
2024-06-24 17:30:44 +08:00
using System.Diagnostics.Tracing;
2023-08-23 01:59:26 +08:00
using System.Timers;
2023-06-29 14:57:11 +08:00
using Cysharp.Threading.Tasks;
using kcp2k;
2023-08-23 01:59:26 +08:00
using Timer = System.Timers.Timer;
using System.Threading.Tasks;
using System.IO;
2024-06-24 17:30:44 +08:00
using System.Linq;
2024-07-29 17:53:08 +08:00
using System.Net;
2023-08-23 01:59:26 +08:00
using System.Numerics;
2024-06-12 16:01:56 +08:00
using System.Reflection;
2024-06-22 17:58:05 +08:00
using System.Text;
2023-08-23 01:59:26 +08:00
using BITKit.Net.Examples;
using Newtonsoft.Json;
2024-06-17 14:38:09 +08:00
using Unity.Mathematics;
2023-06-29 14:57:11 +08:00
namespace BITKit.Net
{
public class KcpNetClient:INetClient,INetProvider
{
public event Action OnStartConnect;
public event Action OnConnected;
public event Action OnDisconnected;
public event Action OnConnectedFailed;
2024-06-17 16:29:39 +08:00
public bool IsConnected => _isConnected;
2024-06-20 17:28:56 +08:00
public bool IsConnecting { get; private set; }
2024-07-29 14:37:00 +08:00
public double RpcTimeOut { get; set; } = 5;
2024-07-29 09:39:22 +08:00
public bool AutoReconnect { get; set; } = true;
2024-06-17 14:38:09 +08:00
public float2 Traffic { get; set; }
2024-03-31 23:31:00 +08:00
public bool ManualTick { get; set; }
2024-07-29 09:39:22 +08:00
private readonly IntervalUpdate _reconnectInterval = new(1);
2024-07-29 14:37:00 +08:00
2024-03-31 23:31:00 +08:00
public int Ping { get; private set; }
2023-08-23 01:59:26 +08:00
public int Id { get; private set; } = -1;
2023-06-29 14:57:11 +08:00
private readonly KcpClient client;
2023-10-06 23:43:19 +08:00
2024-06-20 10:04:18 +08:00
private readonly ConcurrentQueue<byte[]> _commandQueue = new();
2023-10-06 23:43:19 +08:00
2024-03-31 23:31:00 +08:00
private DateTime _lastPingTime = DateTime.Now;
2023-08-23 01:59:26 +08:00
private readonly Timer _timer = new(100)
{
AutoReset = true
};
private readonly GenericEvent _events = new();
2024-03-31 23:31:00 +08:00
2024-06-07 12:56:34 +08:00
private readonly ValidHandle _isConnected = new();
2024-06-08 10:07:40 +08:00
2024-06-08 15:12:48 +08:00
private int _index = int.MinValue;
2024-06-08 10:07:40 +08:00
private readonly ConcurrentDictionary<int, object> _p2p = new();
2024-06-08 15:12:48 +08:00
private readonly ConcurrentDictionary<string,Func<object,UniTask<object>>> _rpc = new();
2024-06-12 16:01:56 +08:00
private readonly ConcurrentDictionary<string,MethodInfo> _rpcMethods = new();
2024-08-06 10:27:59 +08:00
private readonly ConcurrentDictionary<string,EventInfo> _rpcEvents = new();
2024-06-12 16:01:56 +08:00
private readonly ConcurrentDictionary<string,object> _rpcHandles = new();
2024-06-17 16:29:39 +08:00
private DateTime _lastHeartbeat = DateTime.Now;
2024-06-20 10:55:18 +08:00
private DateTime _now = DateTime.Now;
private TimeSpan _interval = TimeSpan.FromMilliseconds(100);
2024-07-29 09:39:22 +08:00
private string _connectedAddress = "127.0.0.1";
private ushort _connectedPort = 27014;
2024-06-20 10:55:18 +08:00
2024-06-20 17:28:56 +08:00
private readonly byte[] _heartBeat = new byte[] { (byte)NetCommandType.Heartbeat };
2023-06-29 14:57:11 +08:00
public KcpNetClient()
{
client = new KcpClient(
OnConnectedInternal,
OnData,
OnDisconnectInternal,
OnError,
KCPNet.Config
);
2023-08-23 01:59:26 +08:00
_timer.Elapsed += Tick;
BIT4Log.Log<KcpNetClient>("已创建KCP客户端");
AddCommandListener<NetClientAllocateIdCommand>(x =>
{
Id = x.Id;
});
2024-06-07 12:56:34 +08:00
_isConnected.AddListener(ConnectionCallback);
}
private async void ConnectionCallback(bool x)
{
await BITApp.SwitchToMainThread();
2024-06-16 09:34:17 +08:00
if (x)
{
OnConnected?.Invoke();
2024-06-17 16:29:39 +08:00
BIT4Log.Log<KcpNetClient>("连接成功");
2024-06-16 09:34:17 +08:00
}
else
{
OnDisconnected?.Invoke();
2024-06-20 17:28:56 +08:00
BIT4Log.Log<KcpNetClient>("连接已断开");
2024-06-16 09:34:17 +08:00
}
2023-06-29 14:57:11 +08:00
}
2023-08-23 01:59:26 +08:00
2023-10-24 23:38:22 +08:00
private void Tick(object sender, ElapsedEventArgs e)
2023-08-23 01:59:26 +08:00
{
2024-03-31 23:31:00 +08:00
if (!ManualTick)
Tick();
2023-08-23 01:59:26 +08:00
}
public async void Disconnect()
2023-06-29 14:57:11 +08:00
{
2024-07-29 09:39:22 +08:00
IsConnecting = false;
2023-06-29 14:57:11 +08:00
client.Disconnect();
2024-06-17 16:29:39 +08:00
_isConnected.RemoveElement(this);
2024-06-20 10:04:18 +08:00
_timer.Stop();
2023-08-23 01:59:26 +08:00
try
{
await BITApp.SwitchToMainThread();
2023-08-23 01:59:26 +08:00
OnDisconnected?.Invoke();
}
catch (OperationCanceledException){}
2023-06-29 14:57:11 +08:00
}
2023-08-23 01:59:26 +08:00
public async UniTask<bool> Connect(string address = "127.0.0.1", ushort port = 27014)
2023-06-29 14:57:11 +08:00
{
2024-08-05 09:53:22 +08:00
if (IsConnecting)
{
BIT4Log.Warning<KcpNetClient>("正在连接中");
return false;
}
2024-07-29 17:53:08 +08:00
//如果address是域名,解析为Ip
if (address.Contains("."))
{
var ip = await Dns.GetHostAddressesAsync(address);
if (ip.Length > 0)
{
address = ip[0].ToString();
BIT4Log.Log<KcpNetClient>($"解析域名:{address}");
}
}
2024-08-05 09:53:22 +08:00
if (address is not "127.0.0.1")
_connectedAddress = address;
if (port is not 27014)
_connectedPort = port;
2024-07-29 17:53:08 +08:00
2024-06-20 17:28:56 +08:00
IsConnecting = true;
if (client.connected) return false;
await BITApp.SwitchToMainThread();
2023-08-11 23:57:37 +08:00
OnStartConnect?.Invoke();
2023-06-29 14:57:11 +08:00
await UniTask.SwitchToThreadPool();
try
{
2024-06-20 10:04:18 +08:00
_lastHeartbeat = DateTime.Now;
client.Connect(address, port);
2023-08-23 01:59:26 +08:00
_timer.Start();
2024-06-20 10:55:18 +08:00
_interval = TimeSpan.FromMilliseconds(_timer.Interval);
2024-06-20 10:04:18 +08:00
2024-06-20 17:28:56 +08:00
HandShake();
await BITApp.SwitchToMainThread();
2024-06-20 17:28:56 +08:00
2024-06-07 12:56:34 +08:00
for (var i = 0; i < 5; i++)
{
client.Send(new[] { (byte)NetCommandType.Heartbeat }, KcpChannel.Reliable);
Traffic += new float2(1, 0);
2024-06-07 12:56:34 +08:00
client.Tick();
await Task.Delay(100);
}
2024-06-20 17:28:56 +08:00
if (client.connected)
2024-06-16 17:55:29 +08:00
{
2024-06-20 17:28:56 +08:00
SendServerMessage(Environment.MachineName);
IsConnecting = false;
2024-07-29 09:39:22 +08:00
_connectedAddress = address;
_connectedPort = port;
2024-06-20 17:28:56 +08:00
return client.connected;
2024-06-16 17:55:29 +08:00
}
2024-06-20 17:28:56 +08:00
OnConnectedFailed?.Invoke();
Disconnect();
IsConnecting = false;
return false;
2023-06-29 14:57:11 +08:00
}
catch (Exception e)
{
BIT4Log.LogException(e);
2023-08-23 01:59:26 +08:00
if (BITApp.SynchronizationContext is not null)
await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext);
2023-06-29 14:57:11 +08:00
OnConnectedFailed?.Invoke();
2024-06-20 10:04:18 +08:00
_timer.Stop();
2024-06-20 17:28:56 +08:00
IsConnecting = false;
2023-06-29 14:57:11 +08:00
return false;
}
}
2024-06-12 16:01:56 +08:00
private void OnData(ArraySegment<byte> bytes, KcpChannel channel)
{
try
{
2024-06-17 14:38:09 +08:00
Traffic+=new float2(0,bytes.Count);
2024-06-12 16:01:56 +08:00
OnDataInternel(bytes, channel);
}
catch (Exception e)
{
BIT4Log.LogException(e);
}
}
private async void OnDataInternel(ArraySegment<byte> bytes, KcpChannel channel)
2023-06-29 14:57:11 +08:00
{
2023-08-23 01:59:26 +08:00
using var ms = new MemoryStream(bytes.ToArray());
using var reader = new BinaryReader(ms);
var type = (NetCommandType)ms.ReadByte();
switch (type)
{
case NetCommandType.Message:
2024-07-29 14:37:00 +08:00
BIT4Log.Log<KcpNetClient>($"已收到消息:{reader.ReadString()}");
2023-08-23 01:59:26 +08:00
break;
case NetCommandType.AllClientCommand:
case NetCommandType.Command:
var command = BITBinary.Read(reader);
if (command is object[] { Length: 1 } objs) command = objs[0];
2023-10-06 23:43:19 +08:00
//BIT4Log.Log<KcpClient>($"已收到指令:{command},值:\n{JsonConvert.SerializeObject(command, Formatting.Indented)}");
2023-08-23 01:59:26 +08:00
try
{
if (BITApp.SynchronizationContext is not null)
await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext,
BITApp.CancellationToken);
_events.Invoke(command.GetType().FullName, command);
}
catch (OperationCanceledException)
{
}
catch (Exception e)
{
BIT4Log.LogException(e);
}
break;
case NetCommandType.Heartbeat:
2024-06-20 17:28:56 +08:00
if (Id is not -1)
{
_isConnected.AddElement(this);
}
2024-06-17 16:29:39 +08:00
_lastHeartbeat = DateTime.Now;
2023-08-23 01:59:26 +08:00
break;
2024-03-31 23:31:00 +08:00
case NetCommandType.Ping:
Ping = (int)(DateTime.Now - _lastPingTime).TotalMilliseconds;
break;
2024-06-08 10:07:40 +08:00
case NetCommandType.ReturnToClient:
var id = reader.ReadInt32();
2024-06-08 15:12:48 +08:00
try
{
2024-06-11 15:39:09 +08:00
if (reader.ReadBoolean())
{
var value = BITBinary.Read(reader);
_p2p.TryAdd(id,value);
}
else
{
var message = reader.ReadString();
_p2p.TryAdd(id,new Exception(message));
}
2024-06-08 15:12:48 +08:00
}
catch (Exception e)
{
BIT4Log.Warning<INetClient>($"请求返回失败:{id}");
BIT4Log.LogException(e);
}
break;
case NetCommandType.GetFromClient:
try
{
var requestId = reader.ReadInt32();
2024-06-12 16:01:56 +08:00
2024-06-12 16:49:42 +08:00
using var returnMS = new MemoryStream();
await using var returnWriter = new BinaryWriter(returnMS);
returnWriter.Write((byte)NetCommandType.ReturnToServer);
returnWriter.Write(requestId);
2024-06-11 15:39:09 +08:00
try
{
2024-06-12 16:01:56 +08:00
object value = null;
if (reader.ReadBoolean())
{
var path = reader.ReadString();
var pars = BITBinary.Read(reader).As<object[]>();
2024-08-06 10:27:59 +08:00
2024-06-12 16:49:42 +08:00
if (_rpcMethods.TryGetValue(path, out var methodInfo))
{
var isAwaitable = methodInfo.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null;
var handle = _rpcHandles[path];
2024-06-24 17:30:44 +08:00
try
{
if (isAwaitable)
{
dynamic result = methodInfo.Invoke(handle, pars)!;
value = await result;
}
else
{
value = methodInfo.Invoke(handle, pars);
}
2024-06-12 16:49:42 +08:00
}
2024-06-24 17:30:44 +08:00
catch (Exception e)
2024-06-12 16:49:42 +08:00
{
2024-06-24 17:30:44 +08:00
BIT4Log.Warning<KcpNetClient>(path);
throw;
2024-06-12 16:49:42 +08:00
}
2024-06-24 17:30:44 +08:00
2024-06-12 16:49:42 +08:00
returnWriter.Write(true);
BITBinary.Write(returnWriter, value);
}
2024-08-06 10:27:59 +08:00
else if (_rpcEvents.TryGetValue(path, out var eventInfo))
{
var handle = _rpcHandles[path];
var fieldInfo = handle.GetType().GetField(eventInfo.Name,ReflectionHelper.Flags)!;
var eventDelegate = fieldInfo.GetValue(handle) as MulticastDelegate;
foreach (var del in eventDelegate!.GetInvocationList())
{
del.Method.Invoke(del.Target, pars);
}
}
2024-06-12 16:49:42 +08:00
else
{
returnWriter.Write(false);
2024-06-14 16:16:13 +08:00
returnWriter.Write($"未找到对应的Rpc方法:{path}");
2024-06-12 16:49:42 +08:00
}
2024-06-12 16:01:56 +08:00
}
else
{
2024-06-12 16:49:42 +08:00
var commandObj = BITBinary.Read(reader)
.As<object[]>()[0];
2024-06-12 16:01:56 +08:00
var func = _rpc[commandObj.GetType()!.FullName!];
value = await func.As<Func<object, UniTask<object>>>().Invoke(commandObj);
}
2024-06-11 15:39:09 +08:00
2024-06-12 16:49:42 +08:00
returnWriter.Write(true);
BITBinary.Write(returnWriter, value);
2024-06-11 15:39:09 +08:00
}
catch (Exception e)
{
BIT4Log.LogException(e);
2024-06-12 16:49:42 +08:00
returnWriter.Write(false);
returnWriter.Write(e.Message);
2024-06-11 15:39:09 +08:00
}
2024-06-12 16:49:42 +08:00
var _bytes = returnMS.ToArray();
2024-06-20 10:04:18 +08:00
_commandQueue.Enqueue(_bytes);
2024-06-08 15:12:48 +08:00
}
catch(Exception e)
{
BIT4Log.LogException(e);
}
2024-06-08 10:07:40 +08:00
break;
2024-06-20 17:28:56 +08:00
case NetCommandType.AllRpc:
case NetCommandType.TargetRpc:
{
var rpcName = reader.ReadString();
2024-08-06 10:27:59 +08:00
var pars = BITBinary.Read(reader).As<object[]>();
2024-06-20 17:28:56 +08:00
if (_rpcMethods.TryGetValue(rpcName, out var methodInfo))
{
2024-06-24 17:30:44 +08:00
try
{
methodInfo.Invoke(_rpcHandles[rpcName], pars);
}
catch (TargetException targetException)
{
var reportBuilder = new StringBuilder();
reportBuilder.AppendLine("正在检查参数类型");
var parameterInfos = methodInfo.GetParameters();
if (parameterInfos.Length != pars.Length)
{
reportBuilder.AppendLine("参数数量不匹配,期望:" + parameterInfos.Length + ",实际:" + pars.Length);
}
for (var i = 0; i < pars.Length; i++)
{
var parameterInfo = parameterInfos[i];
var parameter = pars[i];
if (parameterInfo.ParameterType != parameter.GetType())
{
reportBuilder.AppendLine($"参数{i}类型不匹配,期望:{parameterInfo.ParameterType},实际:{parameter.GetType()}");
}
else
{
reportBuilder.AppendLine($"参数{parameter.GetType()}类型匹配:{parameterInfo.ParameterType}");
}
}
BIT4Log.Warning<KcpNetClient>(reportBuilder);
throw;
}
catch (Exception e)
{
BIT4Log.Warning<KcpNetClient>(rpcName);
throw;
}
2024-06-20 17:28:56 +08:00
}
2024-08-06 10:27:59 +08:00
else if (_rpcEvents.TryGetValue(rpcName, out var eventInfo))
{
var handle = _rpcHandles[rpcName];
var fieldInfo = handle.GetType().GetField(eventInfo.Name,ReflectionHelper.Flags)!;
var eventDelegate = fieldInfo.GetValue(handle) as MulticastDelegate;
2024-08-10 09:09:31 +08:00
if (eventDelegate is null)
2024-08-06 10:27:59 +08:00
{
2024-08-10 09:09:31 +08:00
BIT4Log.Warning<KcpNetClient>($"未找到对应的事件:{rpcName}");
}
else
{
foreach (var del in eventDelegate.GetInvocationList())
{
del.Method.Invoke(del.Target, pars);
}
2024-08-06 10:27:59 +08:00
}
}
2024-06-20 17:28:56 +08:00
else
{
2024-06-24 17:30:44 +08:00
2024-07-29 14:37:00 +08:00
BIT4Log.Warning<KcpNetClient>($"未找到对应的Rpc方法:{rpcName}");
2024-06-20 17:28:56 +08:00
}
}
break;
2023-08-23 01:59:26 +08:00
default:
2024-07-29 14:37:00 +08:00
BIT4Log.Log<KcpNetClient>($"未知消息类型:{type},字节:{(byte)type}");
2023-08-23 01:59:26 +08:00
if (bytes.Array != null)
2024-07-29 14:37:00 +08:00
BIT4Log.Log<KcpNetClient>(
2023-08-23 01:59:26 +08:00
$"已收到:({Id}, {BitConverter.ToString(bytes.Array, bytes.Offset, bytes.Count)} @ {channel})");
break;
}
2023-06-29 14:57:11 +08:00
}
2023-08-23 01:59:26 +08:00
private async void OnConnectedInternal()
2023-06-29 14:57:11 +08:00
{
2024-06-20 10:04:18 +08:00
// if (BITApp.SynchronizationContext is not null)
// await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext);
// OnConnected?.Invoke();
// BIT4Log.Log<KcpNetClient>("已连接");
2023-06-29 14:57:11 +08:00
}
2023-08-23 01:59:26 +08:00
private async void OnDisconnectInternal()
2023-06-29 14:57:11 +08:00
{
2024-06-20 17:28:56 +08:00
//BIT4Log.Log<KcpNetClient>("连接被断开");
2024-06-20 10:04:18 +08:00
Disconnect();
2023-06-29 14:57:11 +08:00
}
private void OnError(ErrorCode errorCode, string message)
{
2024-07-29 14:37:00 +08:00
BIT4Log.Log<KcpNetClient>($"{client.remoteEndPoint}异常:{errorCode},{message}");
2023-06-29 14:57:11 +08:00
}
2024-08-06 10:27:59 +08:00
2023-06-29 14:57:11 +08:00
public void ServerCommand<T>(T command = default)
{
2024-06-20 10:04:18 +08:00
using var ms = new MemoryStream();
using var writer = new BinaryWriter(ms);
writer.Write((byte)NetCommandType.Command);
BITBinary.Write(writer,command);
var bytes = ms.ToArray();
_commandQueue.Enqueue(bytes);
2023-06-29 14:57:11 +08:00
}
2023-08-23 01:59:26 +08:00
public void AllClientCommand<T>(T command = default)
2023-06-29 14:57:11 +08:00
{
2024-06-20 10:04:18 +08:00
using var ms = new MemoryStream();
using var writer = new BinaryWriter(ms);
writer.Write((byte)NetCommandType.AllClientCommand);
BITBinary.Write(writer,command);
var bytes = ms.ToArray();
2023-06-29 14:57:11 +08:00
}
public void ClientCommand<T>(int id, T command)
{
2024-06-20 10:04:18 +08:00
using var ms = new MemoryStream();
using var writer = new BinaryWriter(ms);
writer.Write((byte)NetCommandType.Command);
BITBinary.Write(writer,command);
var bytes = ms.ToArray();
_commandQueue.Enqueue(bytes);
2023-06-29 14:57:11 +08:00
}
2024-06-12 16:49:42 +08:00
public async UniTask<T> GetFromServer<T>(string path = default,params object[] pars)
2023-06-29 14:57:11 +08:00
{
2024-06-20 17:28:56 +08:00
//await UniTask.SwitchToThreadPool();
2024-06-08 10:07:40 +08:00
var id = _index++;
2024-06-20 17:28:56 +08:00
var ms = new MemoryStream();
var writer = new BinaryWriter(ms);
2024-06-08 10:07:40 +08:00
writer.Write((byte)NetCommandType.GetFromServer);
writer.Write(id);
2024-06-12 16:01:56 +08:00
if (string.IsNullOrEmpty(path))
{
writer.Write(false);
}
else
{
writer.Write(true);
writer.Write(path);
}
2024-06-12 16:49:42 +08:00
BITBinary.Write(writer,pars);
2024-06-08 10:07:40 +08:00
var bytes = ms.ToArray();
2024-06-20 17:28:56 +08:00
await ms.DisposeAsync();
await writer.DisposeAsync();
2024-06-20 10:04:18 +08:00
_commandQueue.Enqueue(bytes);
2024-06-20 10:55:18 +08:00
var startTime = _now;
2024-06-20 10:04:18 +08:00
2024-06-08 10:07:40 +08:00
while (true)
{
2024-07-29 14:37:00 +08:00
if ((_now - startTime).TotalSeconds > RpcTimeOut)
2024-06-20 17:28:56 +08:00
{
2024-07-27 14:55:18 +08:00
await BITApp.SwitchToMainThread();
2024-06-20 17:28:56 +08:00
if (string.IsNullOrEmpty(path))
{
throw new TimeoutException("请求超时或已断开连接");
}
throw new TimeoutException($"请求超时或已断开连接,请求为{path}");
}
2024-06-08 10:07:40 +08:00
if (_p2p.TryRemove(id, out var value))
{
2024-06-20 10:55:18 +08:00
await BITApp.SwitchToMainThread();
2024-06-11 15:39:09 +08:00
if (value is Exception e)
{
2024-07-17 17:06:45 +08:00
throw new InGameException(e.Message);
2024-06-11 15:39:09 +08:00
}
2024-06-17 10:40:01 +08:00
if (UniTask.CompletedTask is T t)
{
return t;
}
2024-06-13 16:02:49 +08:00
return value.As<T>();
2024-06-08 10:07:40 +08:00
}
2024-06-20 10:55:18 +08:00
await Task.Delay(_interval);
2024-06-08 10:07:40 +08:00
}
2023-06-29 14:57:11 +08:00
}
2024-07-29 14:37:00 +08:00
2024-06-12 16:49:42 +08:00
public UniTask<T> GetFromClient<T>(int id,string path, params object[] pars)
2023-06-29 14:57:11 +08:00
{
throw new NotImplementedException();
}
2024-06-08 10:07:40 +08:00
2023-06-29 14:57:11 +08:00
public void AddRpcHandle(object rpcHandle)
{
2024-06-22 17:58:05 +08:00
var reportBuilder = new StringBuilder();
reportBuilder.AppendLine($"正在通过反射注册{rpcHandle.GetType().Name}");
2024-06-12 16:49:42 +08:00
foreach (var methodInfo in rpcHandle.GetType().GetMethods())
{
var att = methodInfo.GetCustomAttribute<NetRpcAttribute>();
if(att is null)continue;
2024-06-20 10:04:18 +08:00
_rpcMethods.AddOrUpdate(methodInfo.Name, methodInfo, (s, info) => methodInfo);
_rpcHandles.AddOrUpdate(methodInfo.Name, rpcHandle, (s, o) => rpcHandle);
2024-06-22 17:58:05 +08:00
reportBuilder.AppendLine($"Add [{methodInfo.Name}] as MethodInfo");
2024-06-20 10:04:18 +08:00
}
foreach (var eventInfo in rpcHandle.GetType().GetEvents())
{
var att = eventInfo.GetCustomAttribute<NetRpcAttribute>();
if(att is null)continue;
2024-06-24 17:30:44 +08:00
2024-08-06 10:27:59 +08:00
_rpcEvents.TryAdd(eventInfo.Name, eventInfo);
_rpcHandles.TryAdd(eventInfo.Name, rpcHandle);
2024-06-24 17:30:44 +08:00
2024-08-06 10:27:59 +08:00
reportBuilder.AppendLine($"Add [{eventInfo.Name}] as EventInfo");
2024-06-12 16:49:42 +08:00
}
2024-06-22 17:58:05 +08:00
BIT4Log.Log<KcpNetClient>(reportBuilder);
2023-06-29 14:57:11 +08:00
}
public void AddCommandListener<T>(Action<T> handle)
{
2023-08-23 01:59:26 +08:00
_events.AddListener<T>(handle);
2023-06-29 14:57:11 +08:00
}
2024-06-08 15:12:48 +08:00
public void AddCommandListener<T>(Func<T,UniTask<T>> func)
2024-06-08 10:07:40 +08:00
{
2024-06-08 15:12:48 +08:00
_rpc.TryAdd(typeof(T).FullName, F);
return;
async UniTask<object> F(object o)
{
return await func.Invoke((T)o);
}
2024-06-08 10:07:40 +08:00
}
2024-06-08 15:12:48 +08:00
public void RemoveCommandListener<T>(Func<T,UniTask<T>> func)
2024-06-08 10:07:40 +08:00
{
_rpc.TryRemove(typeof(T).FullName, out _);
}
2023-06-29 14:57:11 +08:00
public void RemoveCommandListener<T>(Action<T> handle)
{
2024-06-08 10:07:40 +08:00
_events.RemoveListener<T>(handle);
2023-06-29 14:57:11 +08:00
}
public void SendRT(string rpcName, params object[] pars)
{
2024-06-20 10:04:18 +08:00
using var ms = new MemoryStream();
using var writer = new BinaryWriter(ms);
2024-08-06 10:27:59 +08:00
writer.Write((byte)NetCommandType.GetFromServer);
writer.Write(++_index);
writer.Write(true);
2024-06-20 10:04:18 +08:00
writer.Write(rpcName);
BITBinary.Write(writer,pars);
var bytes = ms.ToArray();
_commandQueue.Enqueue(bytes);
2023-06-29 14:57:11 +08:00
}
public void SendTargetRT(int id, string rpcName, params object[] pars)
{
throw new NotImplementedException();
}
public void SendAllRT(string rpcName, params object[] pars)
{
throw new NotImplementedException();
}
2023-08-23 01:59:26 +08:00
public void SendServerMessage(string message)
{
var bytes = BinaryBuilder
.Create()
.Write(((byte)NetCommandType.Message))
.Write(message)
.Build();
2024-06-17 14:38:09 +08:00
Traffic+=new float2(bytes.Length,0);
2023-08-23 01:59:26 +08:00
client.Send(bytes, KcpChannel.Reliable);
}
2024-03-31 23:31:00 +08:00
#if UNITY_EDITOR
private readonly IntervalUpdate _pingInterval = new(1);
#endif
public void Tick()
{
2024-06-12 17:57:35 +08:00
try
2024-03-31 23:31:00 +08:00
{
2024-06-20 10:55:18 +08:00
_now = DateTime.UtcNow;
2024-07-29 09:39:22 +08:00
2024-06-20 17:28:56 +08:00
if (client.connected)
2024-06-17 16:29:39 +08:00
{
if (DateTime.Now - _lastHeartbeat > TimeSpan.FromSeconds(5))
{
BIT4Log.Warning<KcpNetClient>("心跳超时,自动断开");
Disconnect();
2024-06-20 17:28:56 +08:00
_commandQueue.Clear();
return;
2024-06-17 16:29:39 +08:00
}
2024-06-20 17:28:56 +08:00
while (_commandQueue.TryDequeue(out var bytes))
{
Traffic += new float2(bytes.Length, 0);
client.Send(bytes, KcpChannel.Reliable);
}
2024-07-26 15:45:10 +08:00
Traffic+=new float2(1,0);
2024-06-20 17:28:56 +08:00
client.Send(_heartBeat, KcpChannel.Unreliable);
2024-06-17 16:29:39 +08:00
}
2024-06-20 17:28:56 +08:00
else
2024-06-12 17:57:35 +08:00
{
2024-07-29 09:39:22 +08:00
if (AutoReconnect && _reconnectInterval.AllowUpdate)
{
if (IsConnecting is false)
{
Connect(_connectedAddress,_connectedPort).Forget();
}
}
2024-06-20 17:28:56 +08:00
if (_commandQueue.Count > 0)
{
_commandQueue.Clear();
//BIT4Log.Warning<KcpNetClient>("连接已断开,清空指令队列");
}
2024-06-12 17:57:35 +08:00
}
2024-03-31 23:31:00 +08:00
#if UNITY_EDITOR
if (_pingInterval.AllowUpdate)
{
_lastPingTime = DateTime.Now;
client.Send(new[] { (byte)NetCommandType.Ping }, KcpChannel.Reliable);
}
#endif
2024-06-12 17:57:35 +08:00
client.Tick();
}
catch (Exception e)
{
BIT4Log.LogException(e);
}
2024-03-31 23:31:00 +08:00
}
2023-08-23 01:59:26 +08:00
public void HandShake()
{
// send client to server
2024-06-17 14:38:09 +08:00
Traffic+=new float2(2,0);
2023-08-23 01:59:26 +08:00
client.Send(new byte[]{0x01, 0x02}, KcpChannel.Reliable);
}
2023-06-29 14:57:11 +08:00
}
}