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;
|
2023-09-18 03:02:00 +00:00
|
|
|
|
public Action OnDisConnected;
|
2023-08-30 12:26:51 +00:00
|
|
|
|
|
|
|
|
|
|
private KcpClient _kcpClient;
|
|
|
|
|
|
public IMessageSender sender { get; private set; } = new MessageSender();
|
|
|
|
|
|
private IMessageReceiver _receiver;
|
|
|
|
|
|
private bool _running;
|
2023-09-18 07:08:25 +00:00
|
|
|
|
private int? _timeoutMillis;
|
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);
|
2023-09-18 07:10:43 +00:00
|
|
|
|
if(_timeoutMillis.HasValue)
|
2023-09-18 07:08:25 +00:00
|
|
|
|
channelConfig.TimeoutMillis = _timeoutMillis.Value;
|
2023-08-30 12:26:51 +00:00
|
|
|
|
|
|
|
|
|
|
_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-11-08 03:19:02 +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);
|
|
|
|
|
|
}
|
2023-09-18 07:55:06 +00:00
|
|
|
|
else if (serverMessage.Heartbeat != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
//Debug.Log("[ProcessMessage]Heartbeat");
|
|
|
|
|
|
_receiver.OnHeartbeat(serverMessage.Heartbeat);
|
|
|
|
|
|
}
|
2023-08-30 12:26:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <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");
|
2023-09-18 03:02:00 +00:00
|
|
|
|
if (OnDisConnected != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Loom.QueueOnMainThread(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
OnDisConnected.Invoke();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2023-08-30 12:26:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-09-18 07:08:25 +00:00
|
|
|
|
public void setTimeoutMillis(int timeoutMillis)
|
|
|
|
|
|
{
|
|
|
|
|
|
_timeoutMillis = timeoutMillis;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-08-30 12:26:51 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 关闭 Client,应该在游戏结束时调用
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Close()
|
|
|
|
|
|
{
|
|
|
|
|
|
_kcpClient?.stop();
|
|
|
|
|
|
_running = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|