194 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			6.3 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;
 | 
						||
        public Action OnDisConnected;
 | 
						||
 | 
						||
        private KcpClient _kcpClient;
 | 
						||
        public IMessageSender sender { get; private set; } = new MessageSender();
 | 
						||
        private IMessageReceiver _receiver;
 | 
						||
        private bool _running;
 | 
						||
		private int? _timeoutMillis;
 | 
						||
 | 
						||
        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);
 | 
						||
			if(_timeoutMillis.HasValue)
 | 
						||
            	channelConfig.TimeoutMillis = _timeoutMillis.Value;
 | 
						||
 | 
						||
            _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)
 | 
						||
        {
 | 
						||
            Debug.Log("[ProcessMessage]");
 | 
						||
            if (serverMessage.PlayerEntered != null)
 | 
						||
            {
 | 
						||
                //Debug.Log("[ProcessMessage]PlayerEntered");
 | 
						||
                var cid = serverMessage.PlayerEntered.Cid;
 | 
						||
                sender.Cid = cid;
 | 
						||
                _receiver.OnPlayerEntered(cid);
 | 
						||
            }
 | 
						||
            else if (serverMessage.GameStart != null)
 | 
						||
            {
 | 
						||
                //Debug.Log("[ProcessMessage]GameStart");
 | 
						||
                _receiver.OnGameStart(serverMessage.GameStart);
 | 
						||
            }
 | 
						||
            else if (serverMessage.LevelStart != null)
 | 
						||
            {
 | 
						||
                //Debug.Log("[ProcessMessage]LevelStart");
 | 
						||
                _receiver.OnLevelStart(serverMessage.LevelStart);
 | 
						||
            }
 | 
						||
            else if (serverMessage.PointFound != null)
 | 
						||
            {
 | 
						||
                //Debug.Log("[ProcessMessage]PointFound");
 | 
						||
                _receiver.OnPointFound(serverMessage.PointFound);
 | 
						||
            }
 | 
						||
            else if (serverMessage.GameFinish != null)
 | 
						||
            {
 | 
						||
                //Debug.Log("[ProcessMessage]GameFinish");
 | 
						||
                _receiver.OnGameFinish(serverMessage.GameFinish);
 | 
						||
            }
 | 
						||
            else if (serverMessage.Heartbeat != null)
 | 
						||
            {
 | 
						||
                //Debug.Log("[ProcessMessage]Heartbeat");
 | 
						||
                _receiver.OnHeartbeat(serverMessage.Heartbeat);
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        /// <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");
 | 
						||
            if (OnDisConnected != null)
 | 
						||
            {
 | 
						||
                Loom.QueueOnMainThread(() =>
 | 
						||
                {
 | 
						||
                    OnDisConnected.Invoke();
 | 
						||
                });
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
		public void setTimeoutMillis(int timeoutMillis)
 | 
						||
		{
 | 
						||
			_timeoutMillis = timeoutMillis;
 | 
						||
		}
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 关闭 Client,应该在游戏结束时调用
 | 
						||
        /// </summary>
 | 
						||
        public void Close()
 | 
						||
        {
 | 
						||
            _kcpClient?.stop();
 | 
						||
            _running = false;
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
} |