239 lines
7.6 KiB
C#
239 lines
7.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Timers;
|
|
using Cysharp.Threading.Tasks;
|
|
using kcp2k;
|
|
using Newtonsoft.Json;
|
|
using Timer = System.Timers.Timer;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using BITKit.Net.Examples;
|
|
|
|
namespace BITKit.Net
|
|
{
|
|
public class KCPNetServer:INetServer,INetProvider
|
|
{
|
|
public event Action<int> OnClientConnected;
|
|
public event Action<int> OnClientDisconnected;
|
|
public event Action OnStartServer;
|
|
public event Action OnStopServer;
|
|
private readonly KcpServer server;
|
|
private readonly GenericEvent _events = new();
|
|
private readonly Timer _timer = new(100)
|
|
{
|
|
AutoReset = true
|
|
};
|
|
|
|
public KCPNetServer()
|
|
{
|
|
server = new KcpServer(
|
|
OnConnected,
|
|
OnData,
|
|
OnDisconnect,
|
|
OnError,
|
|
KCPNet.Config
|
|
);
|
|
_timer.Elapsed += Tick;
|
|
BIT4Log.Log<KCPNetServer>("已创建KCP服务器");
|
|
}
|
|
|
|
private void Tick(object sender, ElapsedEventArgs e)
|
|
{
|
|
if (server.IsActive() is false) return;
|
|
server.Tick();
|
|
}
|
|
|
|
public void StartServer(ushort port = 27014)
|
|
{
|
|
OnStartServer?.Invoke();
|
|
server.Start(port);
|
|
_timer.Start();
|
|
}
|
|
public void StopServer(bool dispose = false)
|
|
{
|
|
server.Stop();
|
|
OnStopServer?.Invoke();
|
|
_timer.Stop();
|
|
}
|
|
public bool IsRunningServer => server.IsActive();
|
|
public void SendMessageToClient(int id, string message)
|
|
{
|
|
Send(id,NetCommandType.Message,message);
|
|
}
|
|
|
|
public void SendMessageToAll(string message)
|
|
{
|
|
foreach (var Id in server.connections.Keys)
|
|
{
|
|
SendMessageToClient(Id,message);
|
|
}
|
|
}
|
|
|
|
public IDictionary<int, EndPoint> Connections =>
|
|
new Dictionary<int, EndPoint>(
|
|
server.connections.Select(x => new KeyValuePair<int, EndPoint>(x.Key, x.Value.remoteEndPoint)
|
|
));
|
|
|
|
|
|
|
|
public void Tick() => server.Tick();
|
|
public void HandShake()
|
|
{
|
|
foreach (var Id in server.connections.Keys)
|
|
{
|
|
server.Send(Id, new byte[]{0x03, 0x04}, KcpChannel.Reliable);
|
|
}
|
|
}
|
|
|
|
private void OnConnected(int Id)
|
|
{
|
|
OnClientConnected?.Invoke(Id);
|
|
ClientCommand(Id,new NetClientAllocateIdCommand
|
|
{
|
|
Id = Id,
|
|
Ip = server.connections[Id].remoteEndPoint.ToString()
|
|
});
|
|
BIT4Log.Log<KCPNetServer>($"{Id}已加入");
|
|
SendMessageToClient(Id, "成功连接到服务器");
|
|
|
|
}
|
|
private void OnDisconnect(int Id)
|
|
{
|
|
OnClientDisconnected?.Invoke(Id);
|
|
BIT4Log.Log<KCPNetServer>($"{Id}已断开");
|
|
}
|
|
private void OnData(int Id, ArraySegment<byte> bytes, KcpChannel channel)
|
|
{
|
|
using var ms = new MemoryStream(bytes.ToArray());
|
|
using var reader = new BinaryReader(ms);
|
|
|
|
//BIT4Log.Log<INetServer>(Id);
|
|
|
|
var type = (NetCommandType)ms.ReadByte();
|
|
|
|
//BIT4Log.Log<INetServer>(type);
|
|
switch (type)
|
|
{
|
|
case NetCommandType.Message:
|
|
BIT4Log.Log<KCPNetServer>($"已收到消息,{Id}:{reader.ReadString()}");
|
|
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)}");
|
|
_events.Invoke(command.GetType().FullName, command);
|
|
|
|
(int Id,object Command) tuple = (Id,command);
|
|
_events.InvokeDirect(command.GetType().FullName,tuple);
|
|
break;
|
|
case NetCommandType.Heartbeat:
|
|
server.Send(Id,new byte[]{(byte)NetCommandType.Heartbeat}, KcpChannel.Reliable);
|
|
break;
|
|
case NetCommandType.AllClientCommand:
|
|
foreach (var id in server.connections.Keys.ToArray())
|
|
{
|
|
server.Send(id,bytes,channel);
|
|
}
|
|
break;
|
|
case NetCommandType.TargetCommand:
|
|
var targetId = reader.ReadInt32();
|
|
server.Send(targetId,bytes,channel);
|
|
break;
|
|
default:
|
|
BIT4Log.Log<KCPNetServer>($"未知消息类型:{type},字节:{(byte)type}");
|
|
BIT4Log.Log<KCPNetServer>($"已收到:({Id}, {BitConverter.ToString(bytes.Array, bytes.Offset, bytes.Count)} @ {channel})");
|
|
break;
|
|
}
|
|
}
|
|
private void OnError(int Id, ErrorCode errorCode, string message)
|
|
{
|
|
BIT4Log.Log<KCPNetServer>($"异常:{errorCode},{message}");
|
|
}
|
|
|
|
public void ServerCommand<T>(T command = default)
|
|
{
|
|
_events.Invoke<T>(command);
|
|
}
|
|
|
|
public void AllClientCommand<T>(T command = default)
|
|
{
|
|
foreach (var id in server.connections.Keys.ToArray())
|
|
{
|
|
ClientCommand(id, command);
|
|
}
|
|
}
|
|
|
|
public void ClientCommand<T>(int id, T command)
|
|
{
|
|
Send(id,NetCommandType.Command,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)
|
|
{
|
|
_events.AddListener<T>(handle);
|
|
}
|
|
|
|
public void AddCommandListenerWithId<T>(Action<int, T> handle)
|
|
{
|
|
_events.AddListenerDirect(typeof(T).FullName, Callback);
|
|
return;
|
|
|
|
void Callback(object value)
|
|
{
|
|
if (value is ValueTuple<int, object> tuple && tuple.Item2 is T)
|
|
{
|
|
handle.Invoke(tuple.Item1, (T)tuple.Item2);
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void RemoveCommandListener<T>(Action<T> handle)
|
|
{
|
|
_events.RemoveListener<T>(handle);
|
|
}
|
|
|
|
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();
|
|
}
|
|
private void Send(int id,NetCommandType commandType,params object[] values)
|
|
{
|
|
var bytes = BinaryBuilder
|
|
.Create()
|
|
.Write((byte)commandType)
|
|
.WriteObject(values)
|
|
.Build();
|
|
server.Send(id,bytes, KcpChannel.Reliable);
|
|
}
|
|
}
|
|
} |