BITFALL/Assets/BITKit/Core/Kcp/KcpNetClient.cs

272 lines
9.0 KiB
C#
Raw Normal View History

2023-08-12 01:43:24 +08:00
using System;
2023-10-20 19:31:12 +08:00
using System.Collections.Generic;
2023-08-23 01:59:40 +08:00
using System.Timers;
2023-08-12 01:43:24 +08:00
using Cysharp.Threading.Tasks;
using kcp2k;
2023-08-23 01:59:40 +08:00
using Timer = System.Timers.Timer;
using System.Threading.Tasks;
using System.IO;
using System.Numerics;
using BITKit.Net.Examples;
using Newtonsoft.Json;
2023-08-12 01:43:24 +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;
public bool IsConnected => client.connected;
2023-08-23 01:59:40 +08:00
public int Ping => -1;
public int Id { get; private set; } = -1;
2023-08-12 01:43:24 +08:00
private readonly KcpClient client;
2023-10-20 19:31:12 +08:00
private readonly Queue<byte[]> commandQueue = new();
2023-08-23 01:59:40 +08:00
private readonly Timer _timer = new(100)
{
AutoReset = true
};
private readonly GenericEvent _events = new();
2023-08-12 01:43:24 +08:00
public KcpNetClient()
{
client = new KcpClient(
OnConnectedInternal,
OnData,
OnDisconnectInternal,
OnError,
KCPNet.Config
);
2023-08-23 01:59:40 +08:00
_timer.Elapsed += Tick;
BIT4Log.Log<KcpNetClient>("已创建KCP客户端");
AddCommandListener<NetClientAllocateIdCommand>(x =>
{
Id = x.Id;
});
2023-08-12 01:43:24 +08:00
}
2023-08-23 01:59:40 +08:00
private void Tick(object sender, ElapsedEventArgs e)
{
2023-10-20 19:31:12 +08:00
//await UniTask.SwitchToThreadPool();
while (commandQueue.TryDequeue(out var bytes))
{
client.Send(bytes, KcpChannel.Reliable);
}
//for (var i = 0; i < 32; i++)
{
client.Tick();
}
2023-08-23 01:59:40 +08:00
}
public async void Disconnect()
2023-08-12 01:43:24 +08:00
{
client.Disconnect();
2023-08-23 01:59:40 +08:00
try
{
await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext,BITApp.CancellationToken);
OnDisconnected?.Invoke();
}
catch (OperationCanceledException){}
2023-08-12 01:43:24 +08:00
}
2023-08-23 01:59:40 +08:00
public async UniTask<bool> Connect(string address = "127.0.0.1", ushort port = 27014)
2023-08-12 01:43:24 +08:00
{
2023-08-23 01:59:40 +08:00
if (BITApp.SynchronizationContext is not null)
await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext, BITApp.CancellationToken);
2023-08-12 01:43:24 +08:00
OnStartConnect?.Invoke();
await UniTask.SwitchToThreadPool();
try
{
client.Connect(address, port);
2023-08-23 01:59:40 +08:00
for (var i = 0; i < 5; i++)
{
client.Tick();
await Task.Delay(100);
}
_timer.Start();
client.Send(new[] { (byte)NetCommandType.Heartbeat }, KcpChannel.Reliable);
if (BITApp.SynchronizationContext is not null)
await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext);
2023-08-12 01:43:24 +08:00
OnConnected?.Invoke();
2023-10-20 19:31:12 +08:00
if (client.connected)
{
SendServerMessage(Environment.MachineName);
}
2023-08-23 01:59:40 +08:00
return client.connected;
2023-08-12 01:43:24 +08:00
}
catch (Exception e)
{
BIT4Log.LogException(e);
2023-08-23 01:59:40 +08:00
if (BITApp.SynchronizationContext is not null)
await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext);
2023-08-12 01:43:24 +08:00
OnConnectedFailed?.Invoke();
return false;
}
}
2023-08-23 01:59:40 +08:00
private async void OnData(ArraySegment<byte> bytes, KcpChannel channel)
2023-08-12 01:43:24 +08:00
{
2023-08-23 01:59:40 +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:
reader.ReadBoolean();
reader.ReadString();
BIT4Log.Log<KcpClient>($"已收到消息:{reader.ReadString()}");
break;
case NetCommandType.AllClientCommand:
case NetCommandType.Command:
var command = BITBinary.Read(reader);
if (command is object[] { Length: 1 } objs) command = objs[0];
2023-10-20 19:31:12 +08:00
//BIT4Log.Log<KcpClient>($"已收到指令:{command},值:\n{JsonConvert.SerializeObject(command, Formatting.Indented)}");
2023-08-23 01:59:40 +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:
client.Send(new[] { (byte)NetCommandType.Heartbeat }, KcpChannel.Reliable);
break;
default:
BIT4Log.Log<KcpClient>($"未知消息类型:{type},字节:{(byte)type}");
if (bytes.Array != null)
BIT4Log.Log<KcpClient>(
$"已收到:({Id}, {BitConverter.ToString(bytes.Array, bytes.Offset, bytes.Count)} @ {channel})");
break;
}
2023-08-12 01:43:24 +08:00
}
2023-08-23 01:59:40 +08:00
private async void OnConnectedInternal()
2023-08-12 01:43:24 +08:00
{
2023-08-23 01:59:40 +08:00
if (BITApp.SynchronizationContext is not null)
await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext);
2023-08-12 01:43:24 +08:00
OnConnected?.Invoke();
BIT4Log.Log<KcpNetClient>("已连接");
}
2023-08-23 01:59:40 +08:00
private async void OnDisconnectInternal()
2023-08-12 01:43:24 +08:00
{
BIT4Log.Log<KcpNetClient>("断开连接");
2023-08-23 01:59:40 +08:00
_timer.Stop();
try
{
if (BITApp.SynchronizationContext is not null)
await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext,
BITApp.CancellationToken);
OnDisconnected?.Invoke();
}
catch (OperationCanceledException)
{
}
2023-08-12 01:43:24 +08:00
}
private void OnError(ErrorCode errorCode, string message)
{
2023-08-23 01:59:40 +08:00
BIT4Log.Log<KCPNetServer>($"{client.remoteEndPoint}异常:{errorCode},{message}");
2023-08-12 01:43:24 +08:00
}
public void ServerCommand<T>(T command = default)
{
Send(NetCommandType.Command,command);
}
2023-08-23 01:59:40 +08:00
public void AllClientCommand<T>(T command = default)
2023-08-12 01:43:24 +08:00
{
Send(NetCommandType.AllClientCommand,command);
}
public void ClientCommand<T>(int id, T command)
{
Send(NetCommandType.TargetCommand,id,command);
}
public UniTask<T> GetFromServer<T>(string addressablePath = Constant.System.Internal)
{
throw new NotImplementedException();
}
public UniTask<T> GetFromClient<T>(int id, string addressablePath = Constant.System.Internal)
{
throw new NotImplementedException();
}
public void AddRpcHandle(object rpcHandle)
{
throw new NotImplementedException();
}
public void AddCommandListener<T>(Action<T> handle)
{
2023-08-23 01:59:40 +08:00
_events.AddListener<T>(handle);
2023-08-12 01:43:24 +08:00
}
public void RemoveCommandListener<T>(Action<T> handle)
{
throw new NotImplementedException();
}
public void SendRT(string rpcName, params object[] pars)
{
throw new NotImplementedException();
}
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:40 +08:00
public void SendServerMessage(string message)
{
var bytes = BinaryBuilder
.Create()
.Write(((byte)NetCommandType.Message))
.Write(message)
.Build();
client.Send(bytes, KcpChannel.Reliable);
}
public void Tick() => client.Tick();
public void HandShake()
{
// send client to server
client.Send(new byte[]{0x01, 0x02}, KcpChannel.Reliable);
}
2023-08-12 01:43:24 +08:00
private void Send(NetCommandType commandType,params object[] values)
{
var bytes = BinaryBuilder
.Create()
.Write((byte)commandType)
2023-08-23 01:59:40 +08:00
.WriteObject(values)
2023-08-12 01:43:24 +08:00
.Build();
2023-10-20 19:31:12 +08:00
commandQueue.Enqueue(bytes);
//client.Send(bytes, KcpChannel.Reliable);
2023-08-12 01:43:24 +08:00
}
2023-08-23 01:59:40 +08:00
2023-08-12 01:43:24 +08:00
}
}