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 OnClientConnected; public event Action 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("已创建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 Connections => new Dictionary( server.connections.Select(x => new KeyValuePair(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($"{Id}已加入"); SendMessageToClient(Id, "成功连接到服务器"); } private void OnDisconnect(int Id) { OnClientDisconnected?.Invoke(Id); BIT4Log.Log($"{Id}已断开"); } private void OnData(int Id, ArraySegment bytes, KcpChannel channel) { using var ms = new MemoryStream(bytes.ToArray()); using var reader = new BinaryReader(ms); //BIT4Log.Log(Id); var type = (NetCommandType)ms.ReadByte(); //BIT4Log.Log(type); switch (type) { case NetCommandType.Message: BIT4Log.Log($"已收到消息,{Id}:{reader.ReadString()}"); break; case NetCommandType.Command: var command = BITBinary.Read(reader); if (command is object[] { Length: 1 } objs) command = objs[0]; //BIT4Log.Log($"已收到指令:{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($"未知消息类型:{type},字节:{(byte)type}"); BIT4Log.Log($"已收到:({Id}, {BitConverter.ToString(bytes.Array, bytes.Offset, bytes.Count)} @ {channel})"); break; } } private void OnError(int Id, ErrorCode errorCode, string message) { BIT4Log.Log($"异常:{errorCode},{message}"); } public void ServerCommand(T command = default) { _events.Invoke(command); } public void AllClientCommand(T command = default) { foreach (var id in server.connections.Keys.ToArray()) { ClientCommand(id, command); } } public void ClientCommand(int id, T command) { Send(id,NetCommandType.Command,command); } public UniTask GetFromServer(string addressablePath = Constant.System.Internal) { throw new NotImplementedException(); } public UniTask GetFromClient(int id, string addressablePath = Constant.System.Internal) { throw new NotImplementedException(); } public void AddRpcHandle(object rpcHandle) { throw new NotImplementedException(); } public void AddCommandListener(Action handle) { _events.AddListener(handle); } public void AddCommandListenerWithId(Action handle) { _events.AddListenerDirect(typeof(T).FullName, Callback); return; void Callback(object value) { if (value is ValueTuple tuple && tuple.Item2 is T) { handle.Invoke(tuple.Item1, (T)tuple.Item2); } else { Console.WriteLine(value); } } } public void RemoveCommandListener(Action handle) { _events.RemoveListener(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); } } }