2023-06-29 14:57:11 +08:00
|
|
|
using System;
|
2024-06-08 10:07:40 +08:00
|
|
|
using System.Collections.Concurrent;
|
2023-08-23 01:59:26 +08:00
|
|
|
using System.Collections.Generic;
|
|
|
|
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 Newtonsoft.Json;
|
|
|
|
using Timer = System.Timers.Timer;
|
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Net;
|
2024-06-08 15:12:48 +08:00
|
|
|
using System.Net.Sockets;
|
2024-06-12 16:01:56 +08:00
|
|
|
using System.Reflection;
|
2025-01-24 10:36:58 +08:00
|
|
|
using System.Threading;
|
2024-06-08 15:12:48 +08:00
|
|
|
using System.Threading.Tasks;
|
2024-07-06 16:14:29 +08:00
|
|
|
using System.Windows.Markup;
|
2023-08-23 01:59:26 +08:00
|
|
|
using BITKit.Net.Examples;
|
2025-01-24 10:36:58 +08:00
|
|
|
using Microsoft.Extensions.Logging;
|
2023-06-29 14:57:11 +08:00
|
|
|
|
|
|
|
namespace BITKit.Net
|
|
|
|
{
|
|
|
|
public class KCPNetServer:INetServer,INetProvider
|
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
private readonly NetProviderCommon _common = new();
|
|
|
|
private readonly ILogger<KCPNetServer> _logger;
|
2024-06-20 17:28:56 +08:00
|
|
|
public string Name { get; set; } = "Default";
|
2025-01-24 10:36:58 +08:00
|
|
|
public uint TickRate { get; set; } = 8;
|
2024-03-31 23:31:00 +08:00
|
|
|
public bool ManualTick { get; set; }
|
2023-10-06 23:43:19 +08:00
|
|
|
public event Action<int> OnClientConnected;
|
2023-06-29 14:57:11 +08:00
|
|
|
public event Action<int> OnClientDisconnected;
|
|
|
|
public event Action OnStartServer;
|
|
|
|
public event Action OnStopServer;
|
|
|
|
private readonly KcpServer server;
|
2025-01-24 10:36:58 +08:00
|
|
|
|
2024-08-08 23:07:50 +08:00
|
|
|
private bool _isStarted;
|
2023-08-23 01:59:26 +08:00
|
|
|
private readonly Timer _timer = new(100)
|
|
|
|
{
|
|
|
|
AutoReset = true
|
|
|
|
};
|
2024-03-31 23:31:00 +08:00
|
|
|
|
2024-06-08 10:07:40 +08:00
|
|
|
private int _index = 1001;
|
2024-06-20 10:04:18 +08:00
|
|
|
|
2025-01-24 10:36:58 +08:00
|
|
|
private DateTime _now=DateTime.UtcNow;
|
2024-06-20 17:28:56 +08:00
|
|
|
|
2024-08-06 10:27:59 +08:00
|
|
|
[NetRpc]
|
|
|
|
public event Action<int, float, bool> OnNetRpcTest;
|
2025-01-24 10:36:58 +08:00
|
|
|
public KCPNetServer(ILogger<KCPNetServer> logger)
|
2023-06-29 14:57:11 +08:00
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_logger = logger;
|
2023-06-29 14:57:11 +08:00
|
|
|
server = new KcpServer(
|
|
|
|
OnConnected,
|
|
|
|
OnData,
|
|
|
|
OnDisconnect,
|
|
|
|
OnError,
|
|
|
|
KCPNet.Config
|
|
|
|
);
|
2023-08-23 01:59:26 +08:00
|
|
|
_timer.Elapsed += Tick;
|
2025-01-12 11:13:19 +08:00
|
|
|
//BIT4Log.Log<KCPNetServer>("已创建KCP服务器");
|
2024-06-08 10:07:40 +08:00
|
|
|
|
2024-06-08 15:12:48 +08:00
|
|
|
AddCommandListener<SimplePing>(F);
|
2024-06-12 16:49:42 +08:00
|
|
|
|
|
|
|
AddRpcHandle(this);
|
2024-08-06 10:27:59 +08:00
|
|
|
|
|
|
|
OnNetRpcTest += (_int, _float, _bool) =>
|
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_logger.LogInformation($"已收到Rpc测试:{_int},{_float},{_bool}");
|
2024-08-06 10:27:59 +08:00
|
|
|
};
|
|
|
|
|
2024-06-08 15:12:48 +08:00
|
|
|
return;
|
|
|
|
UniTask<SimplePing> F(SimplePing p)
|
2024-06-08 10:07:40 +08:00
|
|
|
{
|
2024-06-08 15:12:48 +08:00
|
|
|
p.EndTime = DateTime.Now;
|
|
|
|
return UniTask.FromResult(p);
|
|
|
|
}
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
2023-08-23 01:59:26 +08:00
|
|
|
|
|
|
|
private void Tick(object sender, ElapsedEventArgs e)
|
|
|
|
{
|
2024-06-20 10:55:18 +08:00
|
|
|
_now = DateTime.UtcNow;
|
2024-06-12 17:57:35 +08:00
|
|
|
try
|
|
|
|
{
|
2024-08-08 23:07:50 +08:00
|
|
|
if (_isStarted && IsRunningServer is false)
|
|
|
|
{
|
|
|
|
StartServer(_port);
|
|
|
|
}
|
|
|
|
|
2024-06-20 17:28:56 +08:00
|
|
|
foreach (var id in Connections.Keys.ToArray())
|
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
server.Send(id,_common.HeartBeat , KcpChannel.Unreliable);
|
|
|
|
if (!_common.LastHeartbeat.TryGetValue(id, out var time)) continue;
|
2024-07-27 14:55:18 +08:00
|
|
|
if (!((_now - time).TotalSeconds > 3)) continue;
|
2024-06-20 17:28:56 +08:00
|
|
|
server.Disconnect(id);
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.LastHeartbeat.TryRemove(id);
|
|
|
|
_logger.LogInformation($"{Name}:链接{id}超时,已断开");
|
2024-06-20 17:28:56 +08:00
|
|
|
}
|
|
|
|
|
2024-11-03 16:38:17 +08:00
|
|
|
if (server.IsActive() is false) return;
|
2024-06-20 17:28:56 +08:00
|
|
|
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.DropCount.Clear();
|
|
|
|
while (_common.SendQueue.TryDequeue(out var value))
|
2024-06-20 10:04:18 +08:00
|
|
|
{
|
2024-06-20 17:28:56 +08:00
|
|
|
|
2024-06-20 10:04:18 +08:00
|
|
|
if (server.connections.ContainsKey(value.id))
|
|
|
|
{
|
2024-06-20 17:28:56 +08:00
|
|
|
server.Send(value.id, value.bytes, KcpChannel.Reliable);
|
2024-06-20 10:04:18 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-06-22 17:58:05 +08:00
|
|
|
int UpdateValueFactory(int i, int i1) => i1 + value.bytes.Length;
|
|
|
|
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.DropCount.AddOrUpdate(value.id,value.bytes.Length,UpdateValueFactory);
|
2024-06-20 10:04:18 +08:00
|
|
|
}
|
|
|
|
}
|
2025-01-24 10:36:58 +08:00
|
|
|
foreach (var (id,length) in _common.DropCount)
|
2024-06-22 17:58:05 +08:00
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_logger.LogInformation($"未找到链接:{id},已丢弃字节数量:{length}");
|
2024-06-22 17:58:05 +08:00
|
|
|
}
|
2025-01-24 10:36:58 +08:00
|
|
|
|
|
|
|
server.Tick();
|
2024-06-12 17:57:35 +08:00
|
|
|
}
|
2024-06-14 16:16:13 +08:00
|
|
|
catch (SocketException)
|
|
|
|
{
|
|
|
|
//丢失链接,有用户断开连接,通常是正常现象
|
|
|
|
}
|
2024-06-12 17:57:35 +08:00
|
|
|
catch (Exception exception)
|
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_logger.LogCritical(exception,exception.Message);
|
2024-06-12 17:57:35 +08:00
|
|
|
}
|
2023-08-23 01:59:26 +08:00
|
|
|
}
|
|
|
|
|
2024-06-22 17:58:05 +08:00
|
|
|
|
2024-08-08 23:07:50 +08:00
|
|
|
private ushort _port;
|
2023-06-29 14:57:11 +08:00
|
|
|
public void StartServer(ushort port = 27014)
|
|
|
|
{
|
2024-08-08 23:07:50 +08:00
|
|
|
_port = port;
|
2024-03-31 23:31:00 +08:00
|
|
|
if (IsRunningServer is false)
|
|
|
|
{
|
2024-06-14 17:50:29 +08:00
|
|
|
if (TickRate > 0)
|
|
|
|
{
|
|
|
|
_timer.Interval = 1000f / TickRate;
|
|
|
|
}
|
2024-11-03 16:38:17 +08:00
|
|
|
|
2024-03-31 23:31:00 +08:00
|
|
|
OnStartServer?.Invoke();
|
|
|
|
server.Start(port);
|
2024-11-03 16:38:17 +08:00
|
|
|
if (ManualTick is false)
|
|
|
|
_timer.Start();
|
2024-08-08 23:07:50 +08:00
|
|
|
_isStarted = true;
|
2025-01-24 10:36:58 +08:00
|
|
|
_logger.LogInformation($"已启动KCP服务器:{port}");
|
2024-03-31 23:31:00 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BIT4Log.Warning<KCPNetServer>($"KCP服务器已经启动,忽略此次请求");
|
|
|
|
}
|
|
|
|
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
|
|
|
public void StopServer(bool dispose = false)
|
|
|
|
{
|
2024-03-31 23:31:00 +08:00
|
|
|
if (IsRunningServer)
|
|
|
|
{
|
2024-08-08 23:07:50 +08:00
|
|
|
_isStarted = false;
|
2024-03-31 23:31:00 +08:00
|
|
|
server.Stop();
|
|
|
|
OnStopServer?.Invoke();
|
|
|
|
_timer.Stop();
|
2025-01-24 10:36:58 +08:00
|
|
|
_logger.LogInformation($"已停止KCP服务器");
|
2024-03-31 23:31:00 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BIT4Log.Warning<KCPNetServer>($"KCP服务器未运行,忽略此次请求");
|
|
|
|
}
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
|
|
|
public bool IsRunningServer => server.IsActive();
|
2023-08-23 01:59:26 +08:00
|
|
|
public void SendMessageToClient(int id, string message)
|
|
|
|
{
|
2024-06-20 10:04:18 +08:00
|
|
|
using var ms = new MemoryStream();
|
|
|
|
using var writer = new BinaryWriter(ms);
|
|
|
|
writer.Write((byte)NetCommandType.Message);
|
|
|
|
writer.Write(message);
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.SendQueue.Enqueue((id,ms.ToArray()));
|
2023-08-23 01:59:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public void SendMessageToAll(string message)
|
|
|
|
{
|
|
|
|
foreach (var Id in server.connections.Keys)
|
|
|
|
{
|
2023-10-24 23:38:22 +08:00
|
|
|
SendMessageToClient(Id,message);
|
2023-08-23 01:59:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public IDictionary<int, EndPoint> Connections =>
|
|
|
|
new Dictionary<int, EndPoint>(
|
|
|
|
server.connections.Select(x => new KeyValuePair<int, EndPoint>(x.Key, x.Value.remoteEndPoint)
|
|
|
|
));
|
2023-10-06 23:43:19 +08:00
|
|
|
|
|
|
|
|
2024-06-08 15:12:48 +08:00
|
|
|
public void Tick()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2024-06-20 17:28:56 +08:00
|
|
|
Tick(null,null);
|
2024-06-08 15:12:48 +08:00
|
|
|
}
|
|
|
|
catch (SocketException)
|
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_logger.LogInformation("有用户断开连接,如有异常请检查");
|
2024-06-08 15:12:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-23 01:59:26 +08:00
|
|
|
public void HandShake()
|
|
|
|
{
|
2024-06-20 17:28:56 +08:00
|
|
|
foreach (var id in server.connections.Keys)
|
2023-08-23 01:59:26 +08:00
|
|
|
{
|
2024-06-20 17:28:56 +08:00
|
|
|
server.Send(id, new byte[]{0x03, 0x04}, KcpChannel.Reliable);
|
2023-08-23 01:59:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-20 17:28:56 +08:00
|
|
|
private void OnConnectedInternel(int id)
|
2023-06-29 14:57:11 +08:00
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
//server.connections[id].peer.kcp.SetInterval(TickRate);
|
2024-06-20 17:28:56 +08:00
|
|
|
OnClientConnected?.Invoke(id);
|
|
|
|
ClientCommand(id,new NetClientAllocateIdCommand
|
2023-08-23 01:59:26 +08:00
|
|
|
{
|
2024-06-20 17:28:56 +08:00
|
|
|
Id = id,
|
|
|
|
Ip = server.connections[id].remoteEndPoint.ToString()
|
2023-08-23 01:59:26 +08:00
|
|
|
});
|
2025-01-24 10:36:58 +08:00
|
|
|
_logger.LogInformation($"{id}已连接到:{Name}");
|
2024-06-20 17:28:56 +08:00
|
|
|
SendMessageToClient(id, $"成功连接到服务器:{Name}");
|
|
|
|
}
|
|
|
|
private void OnConnected(int Id)
|
|
|
|
{
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
|
|
|
private void OnDisconnect(int Id)
|
|
|
|
{
|
|
|
|
OnClientDisconnected?.Invoke(Id);
|
2025-01-24 10:36:58 +08:00
|
|
|
_logger.LogInformation($"{Id}已断开");
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
2024-06-12 16:01:56 +08:00
|
|
|
|
|
|
|
private void OnData(int Id, ArraySegment<byte> bytes, KcpChannel channel)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
OnDataInternel(Id, bytes, channel);
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
BIT4Log.LogException(e);
|
|
|
|
}
|
|
|
|
}
|
2024-06-20 10:04:18 +08:00
|
|
|
|
2024-06-12 16:01:56 +08:00
|
|
|
private async void OnDataInternel(int Id, 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);
|
2024-06-20 10:04:18 +08:00
|
|
|
|
|
|
|
try
|
2023-08-23 01:59:26 +08:00
|
|
|
{
|
2024-06-20 10:04:18 +08:00
|
|
|
var type = (NetCommandType)ms.ReadByte();
|
|
|
|
|
|
|
|
switch (type)
|
2024-06-11 15:39:09 +08:00
|
|
|
{
|
2024-06-20 10:04:18 +08:00
|
|
|
case NetCommandType.Message:
|
2025-01-24 10:36:58 +08:00
|
|
|
_logger.LogInformation($"已收到消息,{Id}:{reader.ReadString()}");
|
2024-06-20 10:04:18 +08:00
|
|
|
break;
|
|
|
|
case NetCommandType.Command:
|
|
|
|
var command = BITBinary.Read(reader);
|
|
|
|
if (command is object[] { Length: 1 } objs) command = objs[0];
|
|
|
|
//BIT4Log.Log<KCPNetServer>($"已收到指令:{command},值:\n{JsonConvert.SerializeObject(command, Formatting.Indented)}");
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.Events.Invoke(command.GetType().FullName, command);
|
2024-06-20 10:04:18 +08:00
|
|
|
|
|
|
|
(int Id, object Command) tuple = (Id, command);
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.Events.InvokeDirect(command.GetType().FullName, tuple);
|
2024-06-20 10:04:18 +08:00
|
|
|
break;
|
|
|
|
case NetCommandType.Heartbeat:
|
2024-06-20 17:28:56 +08:00
|
|
|
if (Connections.ContainsKey(Id))
|
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
if (_common.LastHeartbeat.ContainsKey(Id))
|
|
|
|
{
|
|
|
|
_common.LastHeartbeat[Id] = _now;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_common.LastHeartbeat.TryAdd(Id, _now);
|
|
|
|
OnConnectedInternel(Id);
|
|
|
|
}
|
2024-06-20 17:28:56 +08:00
|
|
|
}
|
2025-01-24 10:36:58 +08:00
|
|
|
|
2024-06-20 10:04:18 +08:00
|
|
|
break;
|
|
|
|
case NetCommandType.AllClientCommand:
|
|
|
|
foreach (var id in server.connections.Keys.ToArray())
|
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.SendQueue.Enqueue((id,bytes.ToArray()));
|
2024-06-20 10:04:18 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NetCommandType.TargetCommand:
|
|
|
|
var targetId = reader.ReadInt32();
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.SendQueue.Enqueue((targetId,bytes.ToArray()));
|
2024-06-20 10:04:18 +08:00
|
|
|
break;
|
|
|
|
case NetCommandType.Ping:
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.SendQueue.Enqueue((Id,new byte[] { (byte)NetCommandType.Ping }));
|
2024-06-20 10:04:18 +08:00
|
|
|
break;
|
|
|
|
case NetCommandType.GetFromServer:
|
|
|
|
{
|
|
|
|
var requestId = reader.ReadInt32();
|
2024-06-11 15:39:09 +08:00
|
|
|
|
2024-06-20 10:04:18 +08:00
|
|
|
using var returnMS = new MemoryStream();
|
|
|
|
await using var returnWriter = new BinaryWriter(returnMS);
|
|
|
|
returnWriter.Write((byte)NetCommandType.ReturnToClient);
|
|
|
|
returnWriter.Write(requestId);
|
2024-06-11 15:39:09 +08:00
|
|
|
|
2024-06-20 10:04:18 +08:00
|
|
|
if (reader.ReadBoolean())
|
2024-06-12 16:01:56 +08:00
|
|
|
{
|
2024-06-20 10:04:18 +08:00
|
|
|
var path = reader.ReadString();
|
|
|
|
var pars = BITBinary.Read(reader).As<object[]>();
|
2024-08-06 10:27:59 +08:00
|
|
|
object value = null;
|
2024-06-12 16:49:42 +08:00
|
|
|
|
2025-01-24 10:36:58 +08:00
|
|
|
if (_common.RpcMethods.TryGetValue(path, out var methodInfo))
|
2024-06-20 10:04:18 +08:00
|
|
|
{
|
|
|
|
var isAwaitable = methodInfo.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null;
|
2025-01-24 10:36:58 +08:00
|
|
|
var handle = _common.RpcHandles[path];
|
2024-08-06 10:27:59 +08:00
|
|
|
|
2024-06-20 10:04:18 +08:00
|
|
|
if (methodInfo.GetParameters().Length is 0)
|
|
|
|
{
|
|
|
|
pars = new object[] { };
|
|
|
|
}
|
|
|
|
|
2024-07-17 17:06:45 +08:00
|
|
|
try
|
2024-06-20 10:04:18 +08:00
|
|
|
{
|
2024-07-17 17:06:45 +08:00
|
|
|
if (isAwaitable)
|
2024-07-06 16:14:29 +08:00
|
|
|
{
|
2024-07-17 17:06:45 +08:00
|
|
|
dynamic result = methodInfo.Invoke(handle, pars)!;
|
|
|
|
|
2024-08-05 09:53:22 +08:00
|
|
|
if (methodInfo.ReturnType == typeof(void)
|
|
|
|
||
|
|
|
|
methodInfo.ReturnType == typeof(UniTask)
|
|
|
|
||
|
|
|
|
methodInfo.ReturnType == typeof(UniTask<>)
|
|
|
|
)
|
2024-07-17 17:06:45 +08:00
|
|
|
{
|
|
|
|
await result;
|
|
|
|
value = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
value = await result;
|
|
|
|
}
|
2024-07-06 16:14:29 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-07-17 17:06:45 +08:00
|
|
|
value = methodInfo.Invoke(handle, pars);
|
2024-07-06 16:14:29 +08:00
|
|
|
}
|
2024-06-20 10:04:18 +08:00
|
|
|
}
|
2024-07-17 17:06:45 +08:00
|
|
|
catch (Exception e)
|
2024-06-20 10:04:18 +08:00
|
|
|
{
|
2024-07-17 17:06:45 +08:00
|
|
|
if(e is TargetInvocationException tie)
|
|
|
|
e = tie.InnerException;
|
|
|
|
|
|
|
|
returnWriter.Write(false);
|
|
|
|
returnWriter.Write(e.Message);
|
2024-06-20 10:04:18 +08:00
|
|
|
|
2024-07-17 17:06:45 +08:00
|
|
|
var _bytes = returnMS.ToArray();
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.SendQueue.Enqueue((Id,_bytes));
|
2024-07-29 17:53:08 +08:00
|
|
|
|
|
|
|
if (e is InGameException inGameException)
|
|
|
|
{
|
|
|
|
BIT4Log.Warning<KCPNetServer>(inGameException.Message);
|
|
|
|
return;
|
|
|
|
}
|
2024-07-17 17:06:45 +08:00
|
|
|
BIT4Log.LogException(e);
|
|
|
|
return;
|
|
|
|
}
|
2024-06-20 10:04:18 +08:00
|
|
|
returnWriter.Write(true);
|
2024-08-06 10:27:59 +08:00
|
|
|
|
2025-01-24 10:36:58 +08:00
|
|
|
}else if (_common.RpcEvents.TryGetValue(path, out var eventInfo))
|
2024-08-06 10:27:59 +08:00
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
var handle = _common.RpcHandles[path];
|
2024-08-06 10:27:59 +08:00
|
|
|
var fieldInfo = handle.GetType().GetField(eventInfo.Name,ReflectionHelper.Flags)!;
|
|
|
|
|
|
|
|
var eventDelegate = fieldInfo.GetValue(handle) as MulticastDelegate;
|
|
|
|
|
|
|
|
foreach (var del in eventDelegate!.GetInvocationList())
|
2024-07-06 16:14:29 +08:00
|
|
|
{
|
2024-08-06 10:27:59 +08:00
|
|
|
del.Method.Invoke(del.Target, pars);
|
2024-07-06 16:14:29 +08:00
|
|
|
}
|
2024-06-12 16:49:42 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-06-20 10:04:18 +08:00
|
|
|
throw new Exception($"未找到对应的Rpc方法:{path}");
|
2024-06-12 16:49:42 +08:00
|
|
|
}
|
2024-08-06 10:27:59 +08:00
|
|
|
if (value is not null)
|
|
|
|
{
|
2024-08-13 18:42:51 +08:00
|
|
|
BITBinary.Write(returnWriter, value);
|
2024-08-06 10:27:59 +08:00
|
|
|
}
|
2024-06-12 16:01:56 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
var commandObjs = BITBinary.Read(reader);
|
|
|
|
|
|
|
|
var commandObj = commandObjs.As<object[]>()[0];
|
2024-06-20 10:04:18 +08:00
|
|
|
var funcName = commandObj.GetType()!.FullName!;
|
2025-01-24 10:36:58 +08:00
|
|
|
if (_common.Rpc.TryGetValue(funcName, out var func))
|
2024-06-20 10:04:18 +08:00
|
|
|
{
|
|
|
|
var value = await func.As<Func<object, UniTask<object>>>().Invoke(commandObj);
|
|
|
|
returnWriter.Write(true);
|
|
|
|
BITBinary.Write(returnWriter, value);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw new Exception($"未找到对应的Rpc方法:{funcName}");
|
|
|
|
}
|
2024-06-12 16:01:56 +08:00
|
|
|
}
|
|
|
|
|
2024-06-11 15:39:09 +08:00
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.SendQueue.Enqueue((Id,returnMS.ToArray()));
|
2024-06-11 15:39:09 +08:00
|
|
|
}
|
2024-07-17 17:06:45 +08:00
|
|
|
|
2024-06-08 10:07:40 +08:00
|
|
|
}
|
2024-06-20 10:04:18 +08:00
|
|
|
break;
|
|
|
|
case NetCommandType.ReturnToServer:
|
2024-06-11 15:39:09 +08:00
|
|
|
{
|
2024-06-20 10:04:18 +08:00
|
|
|
var id = reader.ReadInt32();
|
2025-01-24 10:36:58 +08:00
|
|
|
|
|
|
|
if (_common.P2P.TryRemove(id, out var source))
|
2024-06-20 10:04:18 +08:00
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
if (reader.ReadBoolean())
|
|
|
|
{
|
|
|
|
var value = BITBinary.Read(reader);
|
|
|
|
source.TrySetResult(value);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
var message = reader.ReadString();
|
|
|
|
source.TrySetException(new Exception(message));
|
|
|
|
}
|
2024-06-20 10:04:18 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_logger.LogWarning($"ID为{id}的请求未注册回调");
|
2024-06-20 10:04:18 +08:00
|
|
|
}
|
2025-01-24 10:36:58 +08:00
|
|
|
|
|
|
|
|
2024-06-11 15:39:09 +08:00
|
|
|
}
|
2024-06-20 10:04:18 +08:00
|
|
|
break;
|
|
|
|
default:
|
2025-01-24 10:36:58 +08:00
|
|
|
_logger.LogInformation($"未知消息类型:{type},字节:{(byte)type}");
|
|
|
|
_logger.LogInformation(
|
2024-06-20 10:04:18 +08:00
|
|
|
$"已收到:({Id}, {BitConverter.ToString(bytes.Array, bytes.Offset, bytes.Count)} @ {channel})");
|
|
|
|
break;
|
2024-06-08 15:12:48 +08:00
|
|
|
}
|
2024-06-20 10:04:18 +08:00
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
ms.Close();
|
|
|
|
reader.Close();
|
|
|
|
BIT4Log.LogException(e);
|
2023-08-23 01:59:26 +08:00
|
|
|
}
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
2024-06-20 10:04:18 +08:00
|
|
|
|
2024-06-20 17:28:56 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
2023-06-29 14:57:11 +08:00
|
|
|
private void OnError(int Id, ErrorCode errorCode, string message)
|
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_logger.LogInformation($"异常:{errorCode},{message}");
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public void ServerCommand<T>(T command = default)
|
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_common. Events.Invoke<T>(command);
|
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
|
|
|
{
|
2023-08-23 01:59:26 +08:00
|
|
|
foreach (var id in server.connections.Keys.ToArray())
|
|
|
|
{
|
|
|
|
ClientCommand(id, command);
|
|
|
|
}
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public void ClientCommand<T>(int id, T command)
|
|
|
|
{
|
2024-06-20 17:28:56 +08:00
|
|
|
using var ms = new MemoryStream();
|
|
|
|
using var writer = new BinaryWriter(ms);
|
|
|
|
writer.Write((byte)NetCommandType.Command);
|
|
|
|
BITBinary.Write(writer,command);
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.SendQueue.Enqueue((id,ms.ToArray()));
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
|
|
|
|
2024-06-12 16:49:42 +08:00
|
|
|
public UniTask<T> GetFromServer<T>(string path=default,params object[] pars)
|
2023-06-29 14:57:11 +08:00
|
|
|
{
|
|
|
|
throw new NotImplementedException();
|
|
|
|
}
|
|
|
|
|
2024-06-12 16:49:42 +08:00
|
|
|
public async UniTask<T> GetFromClient<T>(int id,string path=default, params object[] pars)
|
2023-06-29 14:57:11 +08:00
|
|
|
{
|
2024-06-20 10:55:18 +08:00
|
|
|
await UniTask.SwitchToThreadPool();
|
2024-06-08 15:12:48 +08:00
|
|
|
var index = _index++;
|
2024-06-20 17:28:56 +08:00
|
|
|
var ms = new MemoryStream();
|
|
|
|
var writer = new BinaryWriter(ms);
|
2024-06-08 15:12:48 +08:00
|
|
|
writer.Write((byte)NetCommandType.GetFromClient);
|
|
|
|
writer.Write(index);
|
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 15:12:48 +08:00
|
|
|
|
|
|
|
var bytes = ms.ToArray();
|
2024-06-20 17:28:56 +08:00
|
|
|
|
|
|
|
await ms.DisposeAsync();
|
|
|
|
await writer.DisposeAsync();
|
|
|
|
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.SendQueue.Enqueue((id,bytes));
|
2024-06-08 15:12:48 +08:00
|
|
|
|
2025-01-24 10:36:58 +08:00
|
|
|
var source = new UniTaskCompletionSource<object>();
|
|
|
|
|
|
|
|
|
|
|
|
_common.P2P.TryAdd(index, source);
|
|
|
|
|
|
|
|
var timeoutCts = new CancellationTokenSource();
|
|
|
|
timeoutCts.CancelAfter(5000); // 设置超时时间
|
|
|
|
|
|
|
|
|
|
|
|
var value =await source.Task.AttachExternalCancellation(timeoutCts.Token);
|
|
|
|
|
2024-06-20 17:28:56 +08:00
|
|
|
//await BITApp.SwitchToMainThread();
|
2024-06-11 15:39:09 +08:00
|
|
|
if (value is Exception e)
|
|
|
|
{
|
|
|
|
throw e;
|
|
|
|
}
|
2024-06-17 10:40:01 +08:00
|
|
|
if (UniTask.CompletedTask is T t)
|
|
|
|
{
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
if (typeof(T) == typeof(UniTaskVoid))
|
|
|
|
{
|
|
|
|
return default;
|
|
|
|
}
|
2024-06-08 15:12:48 +08:00
|
|
|
return (T)value;
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public void AddRpcHandle(object rpcHandle)
|
|
|
|
{
|
2024-06-12 16:49:42 +08:00
|
|
|
foreach (var methodInfo in rpcHandle.GetType().GetMethods())
|
|
|
|
{
|
2024-11-03 16:38:17 +08:00
|
|
|
var att = methodInfo.GetCustomAttribute<NetRpcAttribute>(true);
|
2024-06-12 16:49:42 +08:00
|
|
|
if(att is null)continue;
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.RpcMethods.TryAdd(methodInfo.Name, methodInfo);
|
|
|
|
_common.RpcHandles.TryAdd(methodInfo.Name, rpcHandle);
|
2024-06-12 16:49:42 +08:00
|
|
|
}
|
2024-06-24 17:30:44 +08:00
|
|
|
foreach (var eventInfo in rpcHandle.GetType().GetEvents())
|
|
|
|
{
|
2024-11-03 16:38:17 +08:00
|
|
|
var att = eventInfo.GetCustomAttribute<NetRpcAttribute>(true);
|
2024-06-24 17:30:44 +08:00
|
|
|
if(att is null)continue;
|
2024-08-06 10:27:59 +08:00
|
|
|
|
2025-01-24 10:36:58 +08:00
|
|
|
_common. RpcEvents.TryAdd(eventInfo.Name, eventInfo);
|
|
|
|
_common. RpcHandles.TryAdd(eventInfo.Name, rpcHandle);
|
2024-06-24 17:30:44 +08:00
|
|
|
}
|
|
|
|
|
2024-06-12 16:49:42 +08:00
|
|
|
}
|
|
|
|
[NetRpc]
|
|
|
|
public string MyRpcTest(string hello)
|
|
|
|
{
|
|
|
|
return "Hello World";
|
|
|
|
}
|
|
|
|
[NetRpc]
|
|
|
|
public async UniTask<string> MyRpcTestAsync(string hello)
|
|
|
|
{
|
|
|
|
await Task.Delay(1000);
|
|
|
|
return $"{hello} World";
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public void AddCommandListener<T>(Action<T> handle)
|
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.Events.AddListener<T>(handle);
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
2024-06-08 10:07:40 +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
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.Rpc.TryAdd(typeof(T).FullName, F);
|
2024-06-08 10:07:40 +08:00
|
|
|
return;
|
|
|
|
|
2024-06-08 15:12:48 +08:00
|
|
|
async UniTask<object> F(object o)
|
2024-06-08 10:07:40 +08:00
|
|
|
{
|
2024-06-08 15:12:48 +08:00
|
|
|
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
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_common. Rpc.TryRemove(typeof(T).FullName, out _);
|
2024-06-08 10:07:40 +08:00
|
|
|
}
|
2023-10-06 23:43:19 +08:00
|
|
|
public void AddCommandListenerWithId<T>(Action<int, T> handle)
|
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.Events.AddListenerDirect(typeof(T).FullName, Callback);
|
2023-10-24 23:38:22 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
void Callback(object value)
|
2023-10-06 23:43:19 +08:00
|
|
|
{
|
2023-10-24 23:38:22 +08:00
|
|
|
if (value is ValueTuple<int, object> tuple && tuple.Item2 is T)
|
2023-10-06 23:43:19 +08:00
|
|
|
{
|
2023-10-24 23:38:22 +08:00
|
|
|
handle.Invoke(tuple.Item1, (T)tuple.Item2);
|
2023-10-06 23:43:19 +08:00
|
|
|
}
|
2023-10-24 23:38:22 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
Console.WriteLine(value);
|
|
|
|
}
|
|
|
|
}
|
2023-10-06 23:43:19 +08:00
|
|
|
}
|
2023-06-29 14:57:11 +08:00
|
|
|
|
2024-06-08 15:12:48 +08:00
|
|
|
public void KickClient(int id)
|
|
|
|
{
|
|
|
|
server.Disconnect(id);
|
|
|
|
}
|
|
|
|
|
2023-06-29 14:57:11 +08:00
|
|
|
public void RemoveCommandListener<T>(Action<T> handle)
|
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_common. Events.RemoveListener<T>(handle);
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
|
|
|
|
2024-06-08 10:07:40 +08:00
|
|
|
public void RemoveCommandListener<T>(Func<string, T> func)
|
|
|
|
{
|
|
|
|
throw new NotImplementedException();
|
|
|
|
}
|
|
|
|
|
2023-06-29 14:57:11 +08:00
|
|
|
public void SendRT(string rpcName, params object[] pars)
|
|
|
|
{
|
2024-06-20 17:28:56 +08:00
|
|
|
throw new NotImplementedException("服务端不支持此方法");
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public void SendTargetRT(int id, string rpcName, params object[] pars)
|
|
|
|
{
|
2024-06-20 17:28:56 +08:00
|
|
|
using var ms = new MemoryStream();
|
|
|
|
using var writer = new BinaryWriter(ms);
|
|
|
|
writer.Write((byte)NetCommandType.TargetRpc);
|
|
|
|
writer.Write(rpcName);
|
|
|
|
BITBinary.Write(writer,pars);
|
|
|
|
var bytes = ms.ToArray();
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.SendQueue.Enqueue((id,bytes));
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public void SendAllRT(string rpcName, params object[] pars)
|
|
|
|
{
|
2024-06-20 17:28:56 +08:00
|
|
|
using var ms = new MemoryStream();
|
|
|
|
using var writer = new BinaryWriter(ms);
|
|
|
|
writer.Write((byte)NetCommandType.AllRpc);
|
|
|
|
writer.Write(rpcName);
|
|
|
|
BITBinary.Write(writer,pars);
|
|
|
|
var bytes = ms.ToArray();
|
|
|
|
foreach (var id in server.connections.Keys)
|
|
|
|
{
|
2025-01-24 10:36:58 +08:00
|
|
|
_common.SendQueue.Enqueue((id,bytes));
|
2024-06-20 17:28:56 +08:00
|
|
|
}
|
2023-08-23 01:59:26 +08:00
|
|
|
}
|
2023-06-29 14:57:11 +08:00
|
|
|
}
|
|
|
|
}
|