168 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C#
		
	
	
		
		
			
		
	
	
			168 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C#
		
	
	
|  | using System; | |||
|  | using System.Net; | |||
|  | using System.IO; | |||
|  | using dotNetty_kcp; | |||
|  | using DotNetty.Buffers; | |||
|  | using UnityEngine; | |||
|  | using Guru; | |||
|  | using Dof; | |||
|  | 
 | |||
|  | namespace DofLibrary | |||
|  | { | |||
|  | 
 | |||
|  |     public class GameKcpClient : KcpListener | |||
|  |     { | |||
|  |         public Action OnConnected; | |||
|  | 
 | |||
|  |         private KcpClient _kcpClient; | |||
|  |         public IMessageSender sender { get; private set; } = new MessageSender(); | |||
|  |         private IMessageReceiver _receiver; | |||
|  |         private bool _running; | |||
|  |          | |||
|  |         public GameKcpClient(DotNetty.Unity.Level level = DotNetty.Unity.Level.ALL) | |||
|  |         { | |||
|  |             // 指定DotNetty日志的显示级别 | |||
|  |             DotNetty.Unity.UnityLoggerFactory.Default.Level = level; | |||
|  |         } | |||
|  | 
 | |||
|  |         /// <summary> | |||
|  |         /// 当前 Client 是否处于连接状态 | |||
|  |         /// </summary> | |||
|  |         public bool Running => _running; | |||
|  | 
 | |||
|  |         /// <summary> | |||
|  |         /// 创建一个到 Dof GameServer 的连接 | |||
|  |         /// </summary> | |||
|  |         /// <param name="serverAddress">Dof GameServer 的地址,形如 xxx.xxx.xxx.xxx</param> | |||
|  |         /// <param name="port">房间ID</param> | |||
|  |         /// <param name="receiver">事件回调接口</param> | |||
|  |         public async void Connect(string serverAddress, int port, IMessageReceiver receiver) | |||
|  |         { | |||
|  |             _receiver = receiver; | |||
|  |             _receiver.MessageSender = sender; | |||
|  |             _running = true; | |||
|  | 
 | |||
|  |             var channelConfig = new ChannelConfig(); | |||
|  |             channelConfig.initNodelay(true, 40, 2, true); | |||
|  |             channelConfig.Sndwnd = 512; | |||
|  |             channelConfig.Rcvwnd = 512; | |||
|  |             channelConfig.Mtu = 512; | |||
|  |             channelConfig.FecDataShardCount = 10; | |||
|  |             channelConfig.FecParityShardCount = 3; | |||
|  |             channelConfig.AckNoDelay = true; | |||
|  |             channelConfig.Crc32Check = false; | |||
|  |             channelConfig.UseConvChannel = true; | |||
|  |             //channelConfig.Conv = UnityEngine.Random.Range(1, int.MaxValue); | |||
|  |             channelConfig.TimeoutMillis = 10000; | |||
|  | 
 | |||
|  |             _kcpClient = new KcpClient(); | |||
|  |             _kcpClient.init(channelConfig); | |||
|  | 
 | |||
|  |             var remoteAddress = new IPEndPoint(IPAddress.Parse(serverAddress), port); | |||
|  |             var task = _kcpClient.BindLocal(); | |||
|  |             await task; | |||
|  |             var channel = task.Result; | |||
|  |             _kcpClient.connect(channel, remoteAddress, channelConfig, this); | |||
|  |         } | |||
|  | 
 | |||
|  |         private void ProcessMessage(ServerMessage serverMessage) | |||
|  |         { | |||
|  |             if (serverMessage.PlayerEntered != null) | |||
|  |             { | |||
|  |                 var cid = serverMessage.PlayerEntered.Cid; | |||
|  |                 sender.Cid = cid; | |||
|  |                 _receiver.OnPlayerEntered(cid); | |||
|  |             } | |||
|  |             else if(serverMessage.GameStart != null) | |||
|  |             { | |||
|  |                 _receiver.OnGameStart(serverMessage.GameStart); | |||
|  |             } | |||
|  |             else if (serverMessage.LevelStart != null) | |||
|  |             { | |||
|  |                 _receiver.OnLevelStart(serverMessage.LevelStart); | |||
|  |             } | |||
|  |             else if (serverMessage.PointFound != null) | |||
|  |             { | |||
|  |                 _receiver.OnPointFound(serverMessage.PointFound); | |||
|  |             } | |||
|  |             else if (serverMessage.GameFinish != null) | |||
|  |             { | |||
|  |                 _receiver.OnGameFinish(serverMessage.GameFinish); | |||
|  |             } | |||
|  |         } | |||
|  | 
 | |||
|  |         /// <summary> | |||
|  |         /// kcp 连接后的回调函数 | |||
|  |         /// </summary> | |||
|  |         /// <param name="ukcp">kcp连接</param> | |||
|  |         public void onConnected(Ukcp ukcp) | |||
|  |         { | |||
|  |             Debug.Log($"[GameKcpClient]onConnected: conv = {ukcp.getConv()}"); | |||
|  |             sender.Client = ukcp; | |||
|  | 
 | |||
|  |             if (OnConnected != null) | |||
|  |             { | |||
|  |                 Loom.QueueOnMainThread(() => | |||
|  |                 { | |||
|  |                     OnConnected.Invoke(); | |||
|  |                 }); | |||
|  |             } | |||
|  |         } | |||
|  | 
 | |||
|  |         /// <summary> | |||
|  |         /// kcp 接收到消息的回调函数 | |||
|  |         /// </summary> | |||
|  |         /// <param name="byteBuf">接收到的消息buffer</param> | |||
|  |         /// <param name="ukcp">kcp连接</param> | |||
|  |         public void handleReceive(IByteBuffer byteBuf, Ukcp ukcp) | |||
|  |         { | |||
|  |             Debug.Log("[GameKcpClient]handleReceive"); | |||
|  | 
 | |||
|  |             var ms = new MemoryStream(1024 * 1024 * 1); | |||
|  |             var data_len = byteBuf.ReadableBytes; | |||
|  |             byteBuf.ReadBytes(ms, data_len); | |||
|  |             var msg = ProtobufHelper.FromBytes(typeof(ServerMessage), ms.GetBuffer(), 0, data_len); | |||
|  | 
 | |||
|  |             if (msg is ServerMessage server_msg) | |||
|  |             { | |||
|  |                 Loom.QueueOnMainThread(() => | |||
|  |                 { | |||
|  |                     ProcessMessage(server_msg); | |||
|  |                 }); | |||
|  |             } | |||
|  |             else | |||
|  |             { | |||
|  |                 Debug.LogError("[GameKcpClient]handleReceive: Fail to Deserialize ServerMessage"); | |||
|  |             } | |||
|  |         } | |||
|  | 
 | |||
|  |         /// <summary> | |||
|  |         /// kcp 连接或者接收消息出错的回调函数 | |||
|  |         /// </summary> | |||
|  |         /// <param name="ex">异常</param> | |||
|  |         /// <param name="ukcp">kcp连接</param> | |||
|  |         public void handleException(Exception ex, Ukcp ukcp) | |||
|  |         { | |||
|  |             Debug.LogError($"[GameKcpClient]handleException: {ex}"); | |||
|  |         } | |||
|  | 
 | |||
|  |         /// <summary> | |||
|  |         /// kcp 连接关闭时的回调函数 | |||
|  |         /// </summary> | |||
|  |         /// <param name="ukcp">kcp连接</param> | |||
|  |         public void handleClose(Ukcp ukcp) | |||
|  |         { | |||
|  |             Debug.Log("[GameKcpClient]: Connection closed"); | |||
|  |         } | |||
|  | 
 | |||
|  |         /// <summary> | |||
|  |         /// 关闭 Client,应该在游戏结束时调用 | |||
|  |         /// </summary> | |||
|  |         public void Close() | |||
|  |         { | |||
|  |             _kcpClient?.stop(); | |||
|  |             _running = false; | |||
|  |         } | |||
|  |     } | |||
|  | 
 | |||
|  | } |