182 lines
5.9 KiB
C#
182 lines
5.9 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;
|
||
|
||
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)
|
||
{
|
||
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);
|
||
}
|
||
}
|
||
|
||
/// <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();
|
||
});
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关闭 Client,应该在游戏结束时调用
|
||
/// </summary>
|
||
public void Close()
|
||
{
|
||
_kcpClient?.stop();
|
||
_running = false;
|
||
}
|
||
}
|
||
|
||
} |