| 
									
										
										
										
											2023-08-30 12:26:51 +00:00
										 |  |  |  | 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; | 
					
						
							| 
									
										
										
										
											2023-09-04 10:48:51 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 12:26:51 +00:00
										 |  |  |  |         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) | 
					
						
							|  |  |  |  |         { | 
					
						
							| 
									
										
										
										
											2023-09-04 10:48:51 +00:00
										 |  |  |  |             Debug.Log("[ProcessMessage]"); | 
					
						
							| 
									
										
										
										
											2023-08-30 12:26:51 +00:00
										 |  |  |  |             if (serverMessage.PlayerEntered != null) | 
					
						
							|  |  |  |  |             { | 
					
						
							| 
									
										
										
										
											2023-09-04 10:48:51 +00:00
										 |  |  |  |                 //Debug.Log("[ProcessMessage]PlayerEntered"); | 
					
						
							| 
									
										
										
										
											2023-08-30 12:26:51 +00:00
										 |  |  |  |                 var cid = serverMessage.PlayerEntered.Cid; | 
					
						
							|  |  |  |  |                 sender.Cid = cid; | 
					
						
							|  |  |  |  |                 _receiver.OnPlayerEntered(cid); | 
					
						
							|  |  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-09-04 10:48:51 +00:00
										 |  |  |  |             else if (serverMessage.GameStart != null) | 
					
						
							| 
									
										
										
										
											2023-08-30 12:26:51 +00:00
										 |  |  |  |             { | 
					
						
							| 
									
										
										
										
											2023-09-04 10:48:51 +00:00
										 |  |  |  |                 //Debug.Log("[ProcessMessage]GameStart"); | 
					
						
							| 
									
										
										
										
											2023-08-30 12:26:51 +00:00
										 |  |  |  |                 _receiver.OnGameStart(serverMessage.GameStart); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             else if (serverMessage.LevelStart != null) | 
					
						
							|  |  |  |  |             { | 
					
						
							| 
									
										
										
										
											2023-09-04 10:48:51 +00:00
										 |  |  |  |                 //Debug.Log("[ProcessMessage]LevelStart"); | 
					
						
							| 
									
										
										
										
											2023-08-30 12:26:51 +00:00
										 |  |  |  |                 _receiver.OnLevelStart(serverMessage.LevelStart); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             else if (serverMessage.PointFound != null) | 
					
						
							|  |  |  |  |             { | 
					
						
							| 
									
										
										
										
											2023-09-04 10:48:51 +00:00
										 |  |  |  |                 //Debug.Log("[ProcessMessage]PointFound"); | 
					
						
							| 
									
										
										
										
											2023-08-30 12:26:51 +00:00
										 |  |  |  |                 _receiver.OnPointFound(serverMessage.PointFound); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             else if (serverMessage.GameFinish != null) | 
					
						
							|  |  |  |  |             { | 
					
						
							| 
									
										
										
										
											2023-09-04 10:48:51 +00:00
										 |  |  |  |                 //Debug.Log("[ProcessMessage]GameFinish"); | 
					
						
							| 
									
										
										
										
											2023-08-30 12:26:51 +00:00
										 |  |  |  |                 _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; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | } |