using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Threading; using BITKit; using Cysharp.Threading.Tasks; using ENet; using Microsoft.Extensions.Logging; namespace Net.BITKit.Teleport { public class ENetServer : IDisposable, INetServer, INetProvider { public const uint Offset = 2147483648; private readonly NetProviderService _netProviderService; private readonly IServiceProvider _serviceProvider; private readonly ILogger _logger; // ========== 事件 ========== public event Action? OnClientConnected; public event Action? OnClientDisconnected; public event Action? OnStartServer; public event Action? OnStopServer; public event Action? OnData; private readonly Dictionary> _packetQueue = new(); private readonly Dictionary _packetLossInterval = new(); // ========== 属性 ========== public bool IsRunningServer => _server is { IsSet: true }; public bool ManualTick { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public IDictionary Connections { get; } = new Dictionary(); // ========== 字段 ========== private Host? _server; // ========== 启动/关闭 ========== public ENetServer(ILogger logger, IServiceProvider serviceProvider, NetProviderService netProviderService) { _logger = logger; _serviceProvider = serviceProvider; _netProviderService = netProviderService; ENet.Library.Initialize(); } public void StartServer(ushort port = 27014) { if (_server is not null) return; _server = new Host(); var address = new Address { Port = port }; _server.Create(address, 64); OnStartServer?.Invoke(); _logger.LogInformation($"✅ Server started on port {port}"); } public void StopServer(bool dispose = false) { if (_server is null) return; _server.Flush(); _server.Dispose(); _server = null; OnStopServer?.Invoke(); _logger.LogInformation("🛑 Server stopped."); } public void Dispose() { StopServer(); } // ========== 主动轮询 ========== public int RpcCount { get; set; } public uint TickRate { get; set; } = 64; public void Tick() { if (_server is not { IsSet: true }) return; { var packet = (Packet)default; packet.Create(NetProviderService.Heartbeat, PacketFlags.Reliable); _server.Broadcast(0, ref packet); packet.Dispose(); } _netProviderService.Tick(); while (_server.CheckEvents(out var netEvent) > 0 || _server.Service(0, out netEvent) > 0) { var peerId = (int)(netEvent.Peer.ID - Offset); if (_packetQueue.TryGetValue(netEvent.Peer.ID, out var queue)) { _packetLossInterval.GetOrCreate(netEvent.Peer.ID).Reset(); while (queue.TryDequeue(out var bytes)) { var packet = (Packet)default; packet.Create(bytes); netEvent.Peer.Send(0, ref packet); packet.Dispose(); } } switch (netEvent.Type) { case EventType.Connect: netEvent.Peer.Timeout(3, 1000, 2000); Connections[peerId] = new IPEndPoint(IPAddress.Parse(netEvent.Peer.IP), netEvent.Peer.Port); _logger.LogInformation( $"✅ Client connected - ID: {peerId},UID:{netEvent.Peer.ID}, IP: {netEvent.Peer.IP}"); OnClientConnected?.Invoke(peerId); /* var heartbeatPacket = default(Packet); heartbeatPacket.Create(ENetCommon.Heartbeat,PacketFlags.Reliable); netEvent.Peer.Send(0, ref heartbeatPacket); heartbeatPacket.Dispose(); */ break; case EventType.Disconnect: Connections.Remove(peerId); _logger.LogInformation( $"❌ Client disconnected - ID: {peerId},UID:{netEvent.Peer.ID},IP: {netEvent.Peer.IP}"); OnClientDisconnected?.Invoke(peerId); break; case EventType.Timeout: Connections.Remove(peerId); _logger.LogWarning($"⏰ Client timeout - ID: {peerId}, IP: {netEvent.Peer.IP}"); OnClientDisconnected?.Invoke(peerId); break; case EventType.Receive: { var buffer = new byte[netEvent.Packet.Length]; netEvent.Packet.CopyTo(buffer); OnData?.Invoke(buffer, netEvent.ChannelID); if (netEvent.ChannelID is 0) { _netProviderService.OnData(peerId, buffer); } } break; } netEvent.Packet.Dispose(); } foreach (var (id, queue) in _packetQueue) { var packetLossInterval = _packetLossInterval.GetOrCreate(id); if (queue.Count > 0 && packetLossInterval.AllowUpdateWithoutReset) { _logger.LogWarning($"{id}丢包x{queue.Count}"); queue.Clear(); packetLossInterval.Reset(); } } _server.Flush(); } public void HandShake() { _logger.LogInformation("client called HandShake"); } public T GetRemoteInterface() => _netProviderService.GetRemoteInterface(); public void Invoke(int id, byte[] bytes) { var uid = (uint)(id + Offset); _packetQueue.GetOrCreate(uid).Enqueue(bytes); } public async UniTask InvokeAsync(int id, byte[] bytes) { Invoke(id, bytes); var task = _netProviderService.TaskCompletionSources[RpcCount] = new UniTaskCompletionSource(); var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(3)); return await task.Task.AttachExternalCancellation(timeout.Token); } // ========== 消息发送 ========== public void SendMessageToClient(int id, string message) { using var ms = new MemoryStream(); using var bw = new BinaryWriter(ms); bw.Write((byte)NetCommandType.Message); bw.Write(message); Invoke(id, ms.ToArray()); } public void SendMessageToAll(string message) { throw new NotImplementedException(); } // ========== 踢人 ========== public void KickClient(int id) { throw new NotImplementedException(); } public void TestFunc() { _logger.LogInformation("TestFunc called"); } public void TestFunc1(bool x) { _logger.LogInformation($"TestFunc1 called with parameter: {x}"); } public UniTask TestFuncAsync(bool x) { _logger.LogInformation($"TestFuncAsync called with parameter: {x}"); return UniTask.FromResult(true); } } }