mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-07 16:45:10 +00:00
[+] UpdateNetwork Module
[+] UpdateNetwork Module
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
using TEngine;
|
||||
|
||||
namespace GameLogic
|
||||
{
|
||||
public enum ClientConnectWatcherStatus
|
||||
{
|
||||
StatusInit,
|
||||
StatusReconnectAuto,
|
||||
StatusReconnectConfirm,
|
||||
StatusWaitExit
|
||||
}
|
||||
|
||||
public class ClientConnectWatcher
|
||||
{
|
||||
private readonly GameClient _client;
|
||||
private ClientConnectWatcherStatus _status;
|
||||
private float _statusTime;
|
||||
private int _reconnectCnt = 0;
|
||||
private int _disconnectReason = 0;
|
||||
|
||||
private bool _enable = false;
|
||||
|
||||
public bool Enable
|
||||
{
|
||||
get => _enable;
|
||||
set
|
||||
{
|
||||
if (_enable != value)
|
||||
{
|
||||
_enable = value;
|
||||
if (_enable)
|
||||
{
|
||||
OnEnable();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnDisable();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ClientConnectWatcherStatus Status
|
||||
{
|
||||
get => _status;
|
||||
set
|
||||
{
|
||||
if (_status == value) return;
|
||||
_status = value;
|
||||
_statusTime = NowTime;
|
||||
}
|
||||
}
|
||||
|
||||
private float NowTime => GameTime.unscaledTime;
|
||||
|
||||
public ClientConnectWatcher(GameClient client)
|
||||
{
|
||||
_client = client;
|
||||
_statusTime = NowTime;
|
||||
_status = ClientConnectWatcherStatus.StatusInit;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (!_enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_client.IsEntered)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (_status)
|
||||
{
|
||||
case ClientConnectWatcherStatus.StatusInit:
|
||||
UpdateOnInitStatus();
|
||||
break;
|
||||
case ClientConnectWatcherStatus.StatusReconnectAuto:
|
||||
UpdateOnReconnectAuto();
|
||||
break;
|
||||
case ClientConnectWatcherStatus.StatusReconnectConfirm:
|
||||
UpdateOnReconnectConfirm();
|
||||
break;
|
||||
case ClientConnectWatcherStatus.StatusWaitExit:
|
||||
UpdateOnWaitExit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnReConnect()
|
||||
{
|
||||
if (_status == ClientConnectWatcherStatus.StatusReconnectConfirm)
|
||||
{
|
||||
Status = ClientConnectWatcherStatus.StatusReconnectAuto;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateOnInitStatus()
|
||||
{
|
||||
int autoReconnectMaxCount = 4;
|
||||
if (_reconnectCnt <= autoReconnectMaxCount)
|
||||
{
|
||||
if (_reconnectCnt == 0)
|
||||
{
|
||||
_disconnectReason = _client.LastNetErrCode;
|
||||
}
|
||||
|
||||
Status = ClientConnectWatcherStatus.StatusReconnectAuto;
|
||||
_reconnectCnt++;
|
||||
|
||||
//重连
|
||||
_client.Reconnect();
|
||||
}
|
||||
else
|
||||
{
|
||||
Status = ClientConnectWatcherStatus.StatusReconnectConfirm;
|
||||
_reconnectCnt++;
|
||||
// UISys.Mgr.ShowUI(GAME_UI_TYPE.Tip_NetDisconn, UISys.Mgr.GetUIWindowParam().SetParam("errCode", m_disconnectReason));
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateOnReconnectAuto()
|
||||
{
|
||||
if (_client.IsEntered)
|
||||
{
|
||||
Status = ClientConnectWatcherStatus.StatusInit;
|
||||
_reconnectCnt = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
float nowTime = NowTime;
|
||||
var timeoutTime = 10f;
|
||||
|
||||
if (_statusTime + timeoutTime < nowTime)
|
||||
{
|
||||
Log.Error("UpdateOnReconnectAuto timeout: {0}", timeoutTime);
|
||||
|
||||
//切换到默认的,下一帧继续判断是否需要自动还是手动
|
||||
Status = ClientConnectWatcherStatus.StatusInit;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateOnReconnectConfirm()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void UpdateOnWaitExit()
|
||||
{
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
Status = ClientConnectWatcherStatus.StatusInit;
|
||||
_reconnectCnt = 0;
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
Status = ClientConnectWatcherStatus.StatusInit;
|
||||
_reconnectCnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e4e637f3da340dd9512150c3e2ff087
|
||||
timeCreated: 1684334948
|
374
Assets/GameScripts/HotFix/GameLogic/Network/GameClient.cs
Normal file
374
Assets/GameScripts/HotFix/GameLogic/Network/GameClient.cs
Normal file
@@ -0,0 +1,374 @@
|
||||
using GameBase;
|
||||
using GameProto;
|
||||
using TEngine;
|
||||
using CSPkg = GameProto.CSPkg;
|
||||
|
||||
namespace GameLogic
|
||||
{
|
||||
public enum GameClientStatus
|
||||
{
|
||||
StatusInit, //初始化
|
||||
StatusReconnect, //重新连接
|
||||
StatusClose, //断开连接
|
||||
StatusLogin, //登录中
|
||||
StatusEnter, //AccountLogin成功,进入服务器了
|
||||
}
|
||||
|
||||
public enum CsMsgResult
|
||||
{
|
||||
NoError = 0,
|
||||
NetworkError = 1,
|
||||
InternalError = 2,
|
||||
MsgTimeOut = 3,
|
||||
PingTimeOut = 4,
|
||||
}
|
||||
|
||||
//定义消息回报的回调接口
|
||||
public delegate void CsMsgDelegate(CsMsgResult result, CSPkg msg);
|
||||
|
||||
/// <summary>
|
||||
/// 统计网络协议的接口
|
||||
/// </summary>
|
||||
public delegate void CsMsgStatDelegate(int cmdID, int pkgSize);
|
||||
|
||||
public class GameClient : Singleton<GameClient>
|
||||
{
|
||||
public INetworkChannel Channel;
|
||||
|
||||
private GameClientStatus m_status = GameClientStatus.StatusInit;
|
||||
|
||||
private MsgDispatcher m_dispatcher;
|
||||
|
||||
private ClientConnectWatcher m_connectWatcher;
|
||||
|
||||
private float m_lastLogDisconnectErrTime = 0f;
|
||||
|
||||
private int m_lastNetErrCode = 0;
|
||||
|
||||
public int LastNetErrCode => m_lastNetErrCode;
|
||||
|
||||
public GameClientStatus Status
|
||||
{
|
||||
get => m_status;
|
||||
set => m_status = value;
|
||||
}
|
||||
|
||||
public bool IsEntered => m_status == GameClientStatus.StatusEnter;
|
||||
|
||||
/// <summary>
|
||||
/// 连续心跳超时
|
||||
/// </summary>
|
||||
private int m_heatBeatTimeoutNum = 0;
|
||||
|
||||
private int m_ping = -1;
|
||||
|
||||
private float NowTime => GameTime.unscaledTime;
|
||||
|
||||
private string _lastHost = null;
|
||||
private int _lastPort = 0;
|
||||
|
||||
public GameClient()
|
||||
{
|
||||
m_connectWatcher = new ClientConnectWatcher(this);
|
||||
m_dispatcher = new MsgDispatcher();
|
||||
m_dispatcher.SetTimeout(5f);
|
||||
}
|
||||
|
||||
public void Connect(string host, int port, bool reconnect = false)
|
||||
{
|
||||
ResetParam();
|
||||
if (!reconnect)
|
||||
{
|
||||
SetWatchReconnect(false);
|
||||
}
|
||||
|
||||
if (reconnect)
|
||||
{
|
||||
// GameEvent.Get<ICommUI>().ShowWaitUITip(WaitUISeq.LOGINWORLD_SEQID, G.R(TextDefine.ID_TIPS_RECONNECTING));
|
||||
}
|
||||
else
|
||||
{
|
||||
// GameEvent.Get<ICommUI>().ShowWaitUI(WaitUISeq.LOGINWORLD_SEQID);
|
||||
}
|
||||
|
||||
_lastHost = host;
|
||||
_lastPort = port;
|
||||
|
||||
Channel = TEngine.Network.CreateNetworkChannel("GameClient", ServiceType.Tcp, new NetworkChannelHelper());
|
||||
Channel.Connect(host, port);
|
||||
}
|
||||
|
||||
public void Reconnect()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_lastHost) || _lastPort <= 0)
|
||||
{
|
||||
// GameModule.UI.ShowTipMsg("Invalid reconnect param");
|
||||
return;
|
||||
}
|
||||
|
||||
m_connectWatcher.OnReConnect();
|
||||
Connect(_lastHost, _lastPort, true);
|
||||
}
|
||||
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
Channel.Close();
|
||||
m_status = GameClientStatus.StatusInit;
|
||||
}
|
||||
|
||||
public bool SendCsMsg(CSPkg reqPkg)
|
||||
{
|
||||
if (!IsStatusCanSendMsg(reqPkg.Head.MsgId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return DoSendData(reqPkg);
|
||||
}
|
||||
|
||||
public bool IsStatusCanSendMsg(uint msgId)
|
||||
{
|
||||
bool canSend = false;
|
||||
if (m_status == GameClientStatus.StatusLogin)
|
||||
{
|
||||
canSend = (msgId == (uint)CSMsgID.CsCmdActLoginReq);
|
||||
}
|
||||
|
||||
if (m_status == GameClientStatus.StatusEnter)
|
||||
{
|
||||
canSend = true;
|
||||
}
|
||||
|
||||
if (!canSend)
|
||||
{
|
||||
float nowTime = NowTime;
|
||||
if (m_lastLogDisconnectErrTime + 5 < nowTime)
|
||||
{
|
||||
Log.Error("GameClient not connected, send msg failed, msgId[{0}]", msgId);
|
||||
m_lastLogDisconnectErrTime = nowTime;
|
||||
}
|
||||
|
||||
//UISys.Mgr.ShowTipMsg(TextDefine.ID_ERR_NETWORKD_DISCONNECT);
|
||||
}
|
||||
|
||||
return canSend;
|
||||
}
|
||||
|
||||
public bool SendCsMsg(CSPkg reqPkg, uint resCmd, CsMsgDelegate resHandler = null, bool needShowWaitUI = true)
|
||||
{
|
||||
if (!IsStatusCanSendMsg(reqPkg.Head.MsgId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var ret = DoSendData(reqPkg);
|
||||
if (!ret)
|
||||
{
|
||||
if (resHandler != null)
|
||||
{
|
||||
resHandler(CsMsgResult.InternalError, null);
|
||||
}
|
||||
|
||||
m_dispatcher.NotifyCmdError(resCmd, CsMsgResult.InternalError);
|
||||
}
|
||||
else
|
||||
{
|
||||
//注册消息
|
||||
if (resHandler != null)
|
||||
{
|
||||
m_dispatcher.RegSeqHandle(reqPkg.Head.Echo, resCmd, resHandler);
|
||||
if (reqPkg.Head.Echo > 0 && IsWaitingCmd(resCmd) && needShowWaitUI)
|
||||
{
|
||||
// TODO
|
||||
// GameEvent.Get<ICommUI>().ShowWaitUI(reqPkg.Head.Echo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool DoSendData(CSPkg reqPkg)
|
||||
{
|
||||
if (!IsIgnoreLog(reqPkg.Head.MsgId))
|
||||
{
|
||||
Log.Debug("[c-s] CmdId[{0}]\n{1}", reqPkg.Head.MsgId, reqPkg.Body.ToString());
|
||||
}
|
||||
var sendRet = Channel.Send(reqPkg);
|
||||
return sendRet;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsIgnoreLog(uint msgId)
|
||||
{
|
||||
bool ignoreLog = false;
|
||||
switch (msgId)
|
||||
{
|
||||
case (uint)CSMsgID.CsCmdHeatbeatReq:
|
||||
case (uint)CSMsgID.CsCmdHeatbeatRes:
|
||||
ignoreLog = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return ignoreLog;
|
||||
}
|
||||
|
||||
public static bool IsWaitingCmd(uint msgId)
|
||||
{
|
||||
//心跳包不需要读条等待
|
||||
if (msgId == (uint)CSMsgID.CsCmdHeatbeatRes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ResetParam()
|
||||
{
|
||||
m_lastLogDisconnectErrTime = 0f;
|
||||
m_heatBeatTimeoutNum = 0;
|
||||
_lastHbTime = 0f;
|
||||
m_ping = -1;
|
||||
m_lastNetErrCode = 0;
|
||||
}
|
||||
|
||||
public void OnUpdate()
|
||||
{
|
||||
m_dispatcher.Update();
|
||||
TickHeartBeat();
|
||||
CheckHeatBeatTimeout();
|
||||
m_connectWatcher.Update();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置加密密钥
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
public void SetEncryptKey(string key)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置是否需要监控网络重连。
|
||||
/// 登录成功后,开启监控,可以自动重连或者提示玩家重连。
|
||||
/// </summary>
|
||||
/// <param name="needWatch"></param>
|
||||
public void SetWatchReconnect(bool needWatch)
|
||||
{
|
||||
m_connectWatcher.Enable = needWatch;
|
||||
}
|
||||
|
||||
public bool IsNetworkOkAndLogin()
|
||||
{
|
||||
return m_status == GameClientStatus.StatusEnter;
|
||||
}
|
||||
|
||||
#region 心跳处理
|
||||
|
||||
/// <summary>
|
||||
/// 最近一次心跳的时间
|
||||
/// </summary>
|
||||
private float _lastHbTime = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// 心跳间隔
|
||||
/// </summary>
|
||||
private readonly float _heartBeatDurTime = 5;
|
||||
|
||||
/// <summary>
|
||||
/// 心跳超时的最大次数
|
||||
/// </summary>
|
||||
private const int HeatBeatTimeoutMaxCount = 2;
|
||||
|
||||
private bool CheckHeatBeatTimeout()
|
||||
{
|
||||
if (m_heatBeatTimeoutNum >= HeatBeatTimeoutMaxCount)
|
||||
{
|
||||
//断开连接
|
||||
Shutdown();
|
||||
|
||||
//准备重连
|
||||
m_heatBeatTimeoutNum = 0;
|
||||
Status = GameClientStatus.StatusClose;
|
||||
Log.Error("heat beat detect timeout");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TickHeartBeat()
|
||||
{
|
||||
if (Status != GameClientStatus.StatusEnter)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var nowTime = NowTime;
|
||||
if (_lastHbTime + _heartBeatDurTime < nowTime)
|
||||
{
|
||||
_lastHbTime = nowTime;
|
||||
|
||||
CSPkg heatPkg = ProtobufUtility.BuildCsMsg((int)CSMsgID.CsCmdHeatbeatReq);
|
||||
heatPkg.Body.HeatBeatReq = new CSHeatBeatReq { HeatEchoTime = _lastHbTime };
|
||||
SendCsMsg(heatPkg, (int)CSMsgID.CsCmdHeatbeatRes, HandleHeatBeatRes);
|
||||
}
|
||||
}
|
||||
|
||||
void HandleHeatBeatRes(CsMsgResult result, CSPkg msg)
|
||||
{
|
||||
if (result != CsMsgResult.NoError)
|
||||
{
|
||||
//如果是超时了,则标记最近收到包的次数
|
||||
if (result == CsMsgResult.MsgTimeOut)
|
||||
{
|
||||
m_heatBeatTimeoutNum++;
|
||||
Log.Warning("heat beat timeout: {0}", m_heatBeatTimeoutNum);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var resBody = msg.Body.HeatBeatRes;
|
||||
float diffTime = NowTime - resBody.HeatEchoTime;
|
||||
m_ping = (int)(diffTime * 1000);
|
||||
m_heatBeatTimeoutNum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Ping值
|
||||
|
||||
/// <summary>
|
||||
/// ping值
|
||||
/// </summary>
|
||||
public int Ping
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsPingValid())
|
||||
{
|
||||
return m_ping / 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsPingValid()
|
||||
{
|
||||
if (IsNetworkOkAndLogin())
|
||||
{
|
||||
return m_ping >= 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8c5441725c9f4d98a7790dc76a6a0c48
|
||||
timeCreated: 1684331687
|
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using ProtoBuf;
|
||||
|
||||
namespace GameLogic
|
||||
{
|
||||
[Serializable, ProtoContract(Name = @"HeartBeat")]
|
||||
public class HeartBeat : PacketBase
|
||||
{
|
||||
public HeartBeat()
|
||||
{
|
||||
}
|
||||
|
||||
public override int Id => 1;
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8b9b60d2abf409ca9dd2ce00506ac79
|
||||
timeCreated: 1682046644
|
264
Assets/GameScripts/HotFix/GameLogic/Network/MsgDispatcher.cs
Normal file
264
Assets/GameScripts/HotFix/GameLogic/Network/MsgDispatcher.cs
Normal file
@@ -0,0 +1,264 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GameProto;
|
||||
using TEngine;
|
||||
using CSPkg = GameProto.CSPkg;
|
||||
|
||||
namespace GameLogic
|
||||
{
|
||||
internal class MsgHandleDataToRmv
|
||||
{
|
||||
public uint m_msgCmd;
|
||||
public CsMsgDelegate m_handle;
|
||||
};
|
||||
|
||||
class MsgDispatcher
|
||||
{
|
||||
const int CHECK_TIMEOUT_PERFRAME = 10;
|
||||
const int MAX_MSG_HANDLE = 256;
|
||||
|
||||
CsMsgDelegate[] m_aMsgHandles = new CsMsgDelegate[MAX_MSG_HANDLE];
|
||||
float[] m_fMsgRegTime = new float[MAX_MSG_HANDLE];
|
||||
UInt32[] m_adwMsgRegSeq = new UInt32[MAX_MSG_HANDLE]; //因为m_aMsgHandles存储的是hash,不能保证一定seqid一样,所以这儿存储下,用来校验
|
||||
private uint[] m_aiMsgRegResCmdID = new uint[MAX_MSG_HANDLE];
|
||||
|
||||
UInt32 m_dwLastCheckIndex = 0;
|
||||
|
||||
Dictionary<uint, List<CsMsgDelegate>> m_mapCmdHandle = new Dictionary<uint, List<CsMsgDelegate>>();
|
||||
List<CsMsgStatDelegate> m_listStatHandle = new List<CsMsgStatDelegate>();
|
||||
|
||||
//防止在处理消息的时候又删除了消息映射,所以这儿加了个队列来做个保护
|
||||
private List<MsgHandleDataToRmv> m_rmvList = new List<MsgHandleDataToRmv>();
|
||||
private bool m_isInHandleLoop = false;
|
||||
|
||||
private float m_timeout = 5;
|
||||
|
||||
// 清理所有的网络消息
|
||||
public void CleanAllNetMsg()
|
||||
{
|
||||
m_mapCmdHandle.Clear();
|
||||
}
|
||||
|
||||
public void SetTimeout(float timeout)
|
||||
{
|
||||
m_timeout = timeout;
|
||||
}
|
||||
|
||||
public void RegSeqHandle(UInt32 dwMsgSeqID, uint iResCmdID, CsMsgDelegate msgDelegate)
|
||||
{
|
||||
UInt32 hashIndex = dwMsgSeqID % MAX_MSG_HANDLE;
|
||||
if (m_aMsgHandles[hashIndex] != null)
|
||||
{
|
||||
OnCallSeqHandle(m_adwMsgRegSeq[hashIndex], m_aiMsgRegResCmdID[hashIndex]);
|
||||
NotifyTimeout(m_aMsgHandles[hashIndex]);
|
||||
RmvReg((int)hashIndex);
|
||||
}
|
||||
|
||||
m_aMsgHandles[hashIndex] = msgDelegate;
|
||||
m_fMsgRegTime[hashIndex] = NowTime;
|
||||
m_adwMsgRegSeq[hashIndex] = dwMsgSeqID;
|
||||
m_aiMsgRegResCmdID[hashIndex] = iResCmdID;
|
||||
}
|
||||
|
||||
public void RegCmdHandle(uint iCmdID, CsMsgDelegate msgDelegate)
|
||||
{
|
||||
List<CsMsgDelegate> listHandle;
|
||||
if (!m_mapCmdHandle.TryGetValue(iCmdID, out listHandle))
|
||||
{
|
||||
listHandle = new List<CsMsgDelegate>();
|
||||
m_mapCmdHandle[iCmdID] = listHandle;
|
||||
}
|
||||
|
||||
if (listHandle != null)
|
||||
{
|
||||
if (listHandle.Contains(msgDelegate))
|
||||
{
|
||||
Log.Error("-------------repeat RegCmdHandle:{0}-----------", iCmdID);
|
||||
}
|
||||
|
||||
listHandle.Add(msgDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册统计处理接口
|
||||
/// </summary>
|
||||
/// <param name="handler"></param>
|
||||
public void RegCmdStatHandle(CsMsgStatDelegate handler)
|
||||
{
|
||||
m_listStatHandle.Add(handler);
|
||||
}
|
||||
|
||||
public void DispatchCmdStat(int cmdID, int pkgSize)
|
||||
{
|
||||
foreach (CsMsgStatDelegate handle in m_listStatHandle)
|
||||
{
|
||||
handle(cmdID, pkgSize);
|
||||
}
|
||||
}
|
||||
|
||||
public void RmvCmdHandle(uint iCmdID, CsMsgDelegate msgDelegate)
|
||||
{
|
||||
if (m_isInHandleLoop)
|
||||
{
|
||||
MsgHandleDataToRmv toRmvData = new MsgHandleDataToRmv();
|
||||
toRmvData.m_msgCmd = iCmdID;
|
||||
toRmvData.m_handle = msgDelegate;
|
||||
|
||||
m_rmvList.Add(toRmvData);
|
||||
return;
|
||||
}
|
||||
|
||||
List<CsMsgDelegate> listHandle;
|
||||
if (!m_mapCmdHandle.TryGetValue(iCmdID, out listHandle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (listHandle != null)
|
||||
{
|
||||
listHandle.Remove(msgDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
public void NotifyCmdError(uint iCmdID, CsMsgResult result)
|
||||
{
|
||||
NotifyCmdHandle(iCmdID, result, default(CSPkg));
|
||||
}
|
||||
|
||||
protected bool NotifyCmdHandle(uint cmdID, CsMsgResult result, CSPkg pkg)
|
||||
{
|
||||
bool ret = false;
|
||||
if (m_mapCmdHandle.TryGetValue(cmdID, out var listHandle))
|
||||
{
|
||||
m_isInHandleLoop = true;
|
||||
|
||||
var rmvList = m_rmvList;
|
||||
rmvList.Clear();
|
||||
foreach (CsMsgDelegate handle in listHandle)
|
||||
{
|
||||
ret = true;
|
||||
|
||||
TProfiler.BeginSample("handle");
|
||||
handle(result, pkg);
|
||||
TProfiler.EndSample();
|
||||
}
|
||||
|
||||
m_isInHandleLoop = false;
|
||||
|
||||
//再统一删除掉
|
||||
int rmvCnt = rmvList.Count;
|
||||
for (int i = 0; i < rmvCnt; i++)
|
||||
{
|
||||
var rmvItem = rmvList[i];
|
||||
Log.Error("-------------remove cmd handle on loop:{0}-----------", rmvItem.m_msgCmd);
|
||||
RmvCmdHandle(rmvItem.m_msgCmd, rmvItem.m_handle);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected void OnCallSeqHandle(UInt32 echoSeq, uint resCmdID)
|
||||
{
|
||||
if (echoSeq > 0)
|
||||
{
|
||||
// TODO
|
||||
// GameEvent.Get<ICommUI>().FinWaitUI(echoSeq);
|
||||
}
|
||||
}
|
||||
|
||||
protected void NotifyTimeout(CsMsgDelegate msgHandler)
|
||||
{
|
||||
msgHandler(CsMsgResult.MsgTimeOut, default(CSPkg));
|
||||
}
|
||||
|
||||
public void NotifySeqError(UInt32 dwSeqID, CsMsgResult result)
|
||||
{
|
||||
UInt32 hashIndex = dwSeqID % MAX_MSG_HANDLE;
|
||||
|
||||
//先判断是否有注册的指定消息
|
||||
if (m_aMsgHandles[hashIndex] != null &&
|
||||
m_adwMsgRegSeq[hashIndex] == dwSeqID)
|
||||
{
|
||||
OnCallSeqHandle(dwSeqID, m_aiMsgRegResCmdID[hashIndex]);
|
||||
m_aMsgHandles[hashIndex](result, null);
|
||||
|
||||
RmvReg((int)hashIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCmdFilterNoLog(int cmdID)
|
||||
{
|
||||
// TODO
|
||||
/*switch (cmdID)
|
||||
{
|
||||
case netMacros.CS_CMD_HEATBEAT_RES:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void NotifyMsg(CSPkg msg)
|
||||
{
|
||||
UInt32 dwSeq = msg.Head.Echo;
|
||||
UInt32 hashIndex = dwSeq % MAX_MSG_HANDLE;
|
||||
//判断是否有固定的消息处理流程
|
||||
bool bHaveHandle = NotifyCmdHandle(msg.Head.MsgId, CsMsgResult.NoError, msg);
|
||||
|
||||
//再判断是否有注册的指定消息
|
||||
if (m_aMsgHandles[hashIndex] != null &&
|
||||
m_adwMsgRegSeq[hashIndex] == dwSeq &&
|
||||
m_aiMsgRegResCmdID[hashIndex] == (int)msg.Head.MsgId)
|
||||
{
|
||||
OnCallSeqHandle(m_adwMsgRegSeq[hashIndex], m_aiMsgRegResCmdID[hashIndex]);
|
||||
m_aMsgHandles[hashIndex](CsMsgResult.NoError, msg);
|
||||
RmvReg((int)hashIndex);
|
||||
bHaveHandle = true;
|
||||
}
|
||||
|
||||
if (!bHaveHandle)
|
||||
{
|
||||
//todo..临时改为debug
|
||||
Log.Debug("there is no handle for Msg[{0}]", msg.Head.MsgId);
|
||||
}
|
||||
}
|
||||
|
||||
private float NowTime => GameTime.unscaledTime;
|
||||
|
||||
//定时检查是否请求超时了
|
||||
public void Update()
|
||||
{
|
||||
float timeout = m_timeout;
|
||||
float nowTime = NowTime;
|
||||
for (int i = 0; i < CHECK_TIMEOUT_PERFRAME; i++)
|
||||
{
|
||||
m_dwLastCheckIndex = (m_dwLastCheckIndex + 1) % MAX_MSG_HANDLE;
|
||||
if (m_aMsgHandles[m_dwLastCheckIndex] != null)
|
||||
{
|
||||
if (m_fMsgRegTime[m_dwLastCheckIndex] + timeout < nowTime)
|
||||
{
|
||||
Log.Error("msg timeout, resCmdID[{0}], reqSeq[{1}]", m_aiMsgRegResCmdID[m_dwLastCheckIndex],
|
||||
m_adwMsgRegSeq[m_dwLastCheckIndex]);
|
||||
|
||||
OnCallSeqHandle(m_adwMsgRegSeq[m_dwLastCheckIndex], m_aiMsgRegResCmdID[m_dwLastCheckIndex]);
|
||||
NotifyTimeout(m_aMsgHandles[m_dwLastCheckIndex]);
|
||||
|
||||
RmvReg((int)m_dwLastCheckIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RmvReg(int index)
|
||||
{
|
||||
m_aMsgHandles[index] = null;
|
||||
m_adwMsgRegSeq[index] = 0;
|
||||
m_aiMsgRegResCmdID[index] = 0;
|
||||
m_fMsgRegTime[index] = 0;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d667fb84fed4c5f93a06c464585512f
|
||||
timeCreated: 1684333223
|
@@ -1,10 +1,9 @@
|
||||
using ProtoBuf;
|
||||
using ProtoBuf.Meta;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using GameProto;
|
||||
using TEngine;
|
||||
|
||||
namespace GameLogic
|
||||
@@ -29,31 +28,6 @@ namespace GameLogic
|
||||
{
|
||||
_networkChannel = networkChannel;
|
||||
|
||||
// 反射注册包和包处理函数。
|
||||
Type packetBaseType = typeof(ProtoPacket);
|
||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
Type[] types = assembly.GetTypes();
|
||||
for (int i = 0; i < types.Length; i++)
|
||||
{
|
||||
if (!types[i].IsClass || types[i].IsAbstract)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (types[i].BaseType == packetBaseType)
|
||||
{
|
||||
PacketBase packetBase = (PacketBase)Activator.CreateInstance(types[i]);
|
||||
Type packetType = GetServerToClientPacketType(packetBase.Id);
|
||||
if (packetType != null)
|
||||
{
|
||||
Log.Warning("Already exist packet type '{0}', check '{1}' or '{2}'?.", packetBase.Id.ToString(), packetType.Name, packetBase.GetType().Name);
|
||||
continue;
|
||||
}
|
||||
|
||||
_serverToClientPacketTypes.Add(packetBase.Id, types[i]);
|
||||
}
|
||||
}
|
||||
|
||||
GameEvent.AddEventListener<INetworkChannel, object>(NetworkEvent.NetworkConnectedEvent, OnNetworkConnected);
|
||||
GameEvent.AddEventListener<INetworkChannel>(NetworkEvent.NetworkClosedEvent, OnNetworkClosed);
|
||||
GameEvent.AddEventListener<INetworkChannel, int>(NetworkEvent.NetworkMissHeartBeatEvent, OnNetworkMissHeartBeat);
|
||||
@@ -84,13 +58,16 @@ namespace GameLogic
|
||||
_networkChannel.Socket.SendBufferSize = 1024 * 64;
|
||||
}
|
||||
|
||||
public CSPkg HeartBeatPack = new CSPkg { Head = new CSPkgHead(), Body = new CSPkgBody() };
|
||||
|
||||
/// <summary>
|
||||
/// 发送心跳消息包。
|
||||
/// </summary>
|
||||
/// <returns>是否发送心跳消息包成功。</returns>
|
||||
public bool SendHeartBeat()
|
||||
{
|
||||
_networkChannel.Send(MemoryPool.Acquire<HeartBeat>());
|
||||
HeartBeatPack.Head.MsgId = (uint)CSMsgID.CsCmdHeatbeatReq;
|
||||
_networkChannel.Send(HeartBeatPack);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -101,10 +78,9 @@ namespace GameLogic
|
||||
/// <param name="packet">要序列化的消息包。</param>
|
||||
/// <param name="destination">要序列化的目标流。</param>
|
||||
/// <returns>是否序列化成功。</returns>
|
||||
public bool Serialize<T>(T packet, Stream destination) where T : Packet
|
||||
public bool Serialize(CSPkg packet, Stream destination)
|
||||
{
|
||||
PacketBase packetImpl = packet as PacketBase;
|
||||
if (packetImpl == null)
|
||||
if (packet == null)
|
||||
{
|
||||
Log.Warning("Packet is invalid.");
|
||||
return false;
|
||||
@@ -113,12 +89,7 @@ namespace GameLogic
|
||||
_cachedStream.SetLength(_cachedStream.Capacity); // 此行防止 Array.Copy 的数据无法写入
|
||||
_cachedStream.Position = 0L;
|
||||
|
||||
PacketHeader packetHeader = MemoryPool.Acquire<PacketHeader>();
|
||||
Serializer.Serialize(_cachedStream, packetHeader);
|
||||
MemoryPool.Release(packetHeader);
|
||||
|
||||
Serializer.SerializeWithLengthPrefix(_cachedStream, packet, PrefixStyle.Fixed32);
|
||||
MemoryPool.Release((IMemory)packet);
|
||||
global::ProtobufUtility.ToStream(packet,destination);
|
||||
|
||||
_cachedStream.WriteTo(destination);
|
||||
return true;
|
||||
@@ -132,9 +103,10 @@ namespace GameLogic
|
||||
/// <returns>反序列化后的消息包头。</returns>
|
||||
public IPacketHeader DeserializePacketHeader(Stream source, out object customErrorData)
|
||||
{
|
||||
// TODO
|
||||
// 注意:此函数并不在主线程调用!
|
||||
customErrorData = null;
|
||||
return (IPacketHeader)RuntimeTypeModel.Default.Deserialize(source, MemoryPool.Acquire<PacketHeader>(), typeof(PacketHeader));
|
||||
return null; //(IPacketHeader)RuntimeTypeModel.Default.Deserialize(source, MemoryPool.Acquire<PacketHeader>(), typeof(PacketHeader));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -144,7 +116,7 @@ namespace GameLogic
|
||||
/// <param name="source">要反序列化的来源流。</param>
|
||||
/// <param name="customErrorData">用户自定义错误数据。</param>
|
||||
/// <returns>反序列化后的消息包。</returns>
|
||||
public Packet DeserializePacket(IPacketHeader packetHeader, Stream source, out object customErrorData)
|
||||
public CSPkg DeserializePacket(IPacketHeader packetHeader, Stream source, out object customErrorData)
|
||||
{
|
||||
// 注意:此函数并不在主线程调用!
|
||||
customErrorData = null;
|
||||
@@ -156,13 +128,13 @@ namespace GameLogic
|
||||
return null;
|
||||
}
|
||||
|
||||
Packet packet = null;
|
||||
CSPkg csPkg = null;
|
||||
if (scPacketHeader.IsValid)
|
||||
{
|
||||
Type packetType = GetServerToClientPacketType(scPacketHeader.Id);
|
||||
if (packetType != null)
|
||||
{
|
||||
packet = (Packet)RuntimeTypeModel.Default.DeserializeWithLengthPrefix(source, MemoryPool.Acquire(packetType), packetType, PrefixStyle.Fixed32, 0);
|
||||
csPkg = global::ProtobufUtility.Deserialize<CSPkg>(((MemoryStream)source).GetBuffer());;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -175,7 +147,7 @@ namespace GameLogic
|
||||
}
|
||||
|
||||
MemoryPool.Release(scPacketHeader);
|
||||
return packet;
|
||||
return csPkg;
|
||||
}
|
||||
|
||||
private Type GetServerToClientPacketType(int id)
|
||||
|
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using GameProto;
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
@@ -163,7 +165,7 @@ namespace TEngine
|
||||
/// <typeparam name="T">消息包类型。</typeparam>
|
||||
/// <param name="packet">要发送的消息包。</param>
|
||||
/// <returns>消息包是否发送成功。</returns>
|
||||
bool Send<T>(T packet) where T : Packet;
|
||||
bool Send(CSPkg packet);
|
||||
|
||||
/// <summary>
|
||||
/// 向远程主机发送消息包并注册消息回调。
|
||||
@@ -173,6 +175,6 @@ namespace TEngine
|
||||
/// <param name="resHandler">要注册的回调。</param>
|
||||
/// <param name="needShowWaitUI">是否需要等待UI。</param>
|
||||
/// <returns>消息包是否发送成功。</returns>
|
||||
bool Send<T>(T packet, CsMsgDelegate resHandler, bool needShowWaitUI = false) where T : Packet;
|
||||
bool Send(CSPkg packet, CsMsgDelegate resHandler, bool needShowWaitUI = false);
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using GameProto;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
@@ -44,7 +45,7 @@ namespace TEngine
|
||||
/// <param name="packet">要序列化的消息包。</param>
|
||||
/// <param name="destination">要序列化的目标流。</param>
|
||||
/// <returns>是否序列化成功。</returns>
|
||||
bool Serialize<T>(T packet, Stream destination) where T : Packet;
|
||||
bool Serialize(CSPkg packet, Stream destination);
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化消息包头。
|
||||
@@ -61,6 +62,6 @@ namespace TEngine
|
||||
/// <param name="source">要反序列化的来源流。</param>
|
||||
/// <param name="customErrorData">用户自定义错误数据。</param>
|
||||
/// <returns>反序列化后的消息包。</returns>
|
||||
Packet DeserializePacket(IPacketHeader packetHeader, Stream source, out object customErrorData);
|
||||
CSPkg DeserializePacket(IPacketHeader packetHeader, Stream source, out object customErrorData);
|
||||
}
|
||||
}
|
@@ -2,6 +2,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using GameProto;
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
@@ -15,7 +17,7 @@ namespace TEngine
|
||||
private const float DefaultHeartBeatInterval = 30f;
|
||||
|
||||
private readonly string _name;
|
||||
protected readonly Queue<Packet> SendPacketPool;
|
||||
protected readonly Queue<CSPkg> SendPacketPool;
|
||||
protected readonly INetworkChannelHelper NetworkChannelHelper;
|
||||
protected AddressFamily MAddressFamily;
|
||||
protected bool MResetHeartBeatElapseSecondsWhenReceivePacket;
|
||||
@@ -48,7 +50,7 @@ namespace TEngine
|
||||
/// <summary>
|
||||
/// 消息包缓存堆栈。
|
||||
/// </summary>
|
||||
private readonly Queue<Packet> _packsQueue = new Queue<Packet>();
|
||||
private readonly Queue<CSPkg> _packsQueue = new Queue<CSPkg>();
|
||||
|
||||
/// <summary>
|
||||
/// 初始化网络频道基类的新实例。
|
||||
@@ -58,7 +60,7 @@ namespace TEngine
|
||||
public NetworkChannelBase(string name, INetworkChannelHelper networkChannelHelper)
|
||||
{
|
||||
_name = name ?? string.Empty;
|
||||
SendPacketPool = new Queue<Packet>();
|
||||
SendPacketPool = new Queue<CSPkg>();
|
||||
NetworkChannelHelper = networkChannelHelper;
|
||||
MAddressFamily = AddressFamily.Unknown;
|
||||
MResetHeartBeatElapseSecondsWhenReceivePacket = false;
|
||||
@@ -411,9 +413,8 @@ namespace TEngine
|
||||
/// <summary>
|
||||
/// 向远程主机发送消息包。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">消息包类型。</typeparam>
|
||||
/// <param name="packet">要发送的消息包。</param>
|
||||
public bool Send<T>(T packet) where T : Packet
|
||||
public bool Send(CSPkg packet)
|
||||
{
|
||||
if (MSocket == null)
|
||||
{
|
||||
@@ -466,9 +467,9 @@ namespace TEngine
|
||||
/// <param name="resHandler">要注册的回调。</param>
|
||||
/// <param name="needShowWaitUI">是否需要等待UI。</param>
|
||||
/// <returns>消息包是否发送成功。</returns>
|
||||
public bool Send<T>(T packet, CsMsgDelegate resHandler, bool needShowWaitUI = false) where T : Packet
|
||||
public bool Send(CSPkg packet, CsMsgDelegate resHandler, bool needShowWaitUI = false)
|
||||
{
|
||||
RegisterMsgHandler(packet.Id,resHandler,false);
|
||||
RegisterMsgHandler((int)packet.Head.MsgId,resHandler,false);
|
||||
return Send(packet);
|
||||
}
|
||||
|
||||
@@ -511,16 +512,16 @@ namespace TEngine
|
||||
|
||||
while (SendPacketPool.Count > 0)
|
||||
{
|
||||
Packet packet = null;
|
||||
CSPkg csPkg = null;
|
||||
lock (SendPacketPool)
|
||||
{
|
||||
packet = SendPacketPool.Dequeue();
|
||||
csPkg = SendPacketPool.Dequeue();
|
||||
}
|
||||
|
||||
bool serializeResult = false;
|
||||
try
|
||||
{
|
||||
serializeResult = NetworkChannelHelper.Serialize(packet, MSendState.Stream);
|
||||
serializeResult = NetworkChannelHelper.Serialize(csPkg, MSendState.Stream);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
@@ -614,22 +615,22 @@ namespace TEngine
|
||||
|
||||
try
|
||||
{
|
||||
Packet packet = NetworkChannelHelper.DeserializePacket(MReceiveState.PacketHeader, MReceiveState.Stream, out var customErrorData);
|
||||
CSPkg csPkg = NetworkChannelHelper.DeserializePacket(MReceiveState.PacketHeader, MReceiveState.Stream, out var customErrorData);
|
||||
|
||||
if (customErrorData != null && NetworkChannelCustomError != null)
|
||||
{
|
||||
NetworkChannelCustomError(this, customErrorData);
|
||||
}
|
||||
|
||||
if (packet != null)
|
||||
if (csPkg != null)
|
||||
{
|
||||
lock (_cacheHandlerQueue)
|
||||
{
|
||||
if (_msgHandlerMap.TryGetValue((int)packet.Id, out var listHandle))
|
||||
if (_msgHandlerMap.TryGetValue((int)csPkg.Head.MsgId, out var listHandle))
|
||||
{
|
||||
_cacheHandlerQueue.Enqueue(listHandle);
|
||||
|
||||
_packsQueue.Enqueue(packet);
|
||||
_packsQueue.Enqueue(csPkg);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,21 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using GameBase;
|
||||
using GameProto;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息委托。
|
||||
/// </summary>
|
||||
public delegate void CsMsgDelegate(Packet packet);
|
||||
|
||||
public delegate void CsMsgDelegate(CSPkg csPkg);
|
||||
|
||||
/// <summary>
|
||||
/// 网络管理器。
|
||||
/// </summary>
|
||||
internal sealed partial class NetworkManager : GameFrameworkModule, INetworkManager
|
||||
internal sealed partial class NetworkManager : Singleton<NetworkManager>, INetworkManager
|
||||
{
|
||||
private readonly Dictionary<string, NetworkChannelBase> _networkChannels;
|
||||
|
||||
|
||||
private Action<INetworkChannel, object> _networkConnectedEventHandler;
|
||||
private Action<INetworkChannel> _networkClosedEventHandler;
|
||||
private Action<INetworkChannel, int> _networkMissHeartBeatEventHandler;
|
||||
@@ -90,7 +92,7 @@ namespace TEngine
|
||||
/// </summary>
|
||||
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
|
||||
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
|
||||
internal override void Update(float elapseSeconds, float realElapseSeconds)
|
||||
public void Update(float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
foreach (KeyValuePair<string, NetworkChannelBase> networkChannel in _networkChannels)
|
||||
{
|
||||
@@ -101,7 +103,7 @@ namespace TEngine
|
||||
/// <summary>
|
||||
/// 关闭并清理网络管理器。
|
||||
/// </summary>
|
||||
internal override void Shutdown()
|
||||
public void Shutdown()
|
||||
{
|
||||
foreach (KeyValuePair<string, NetworkChannelBase> networkChannel in _networkChannels)
|
||||
{
|
||||
@@ -183,7 +185,8 @@ namespace TEngine
|
||||
/// <param name="serviceType">网络服务类型。</param>
|
||||
/// <param name="networkChannelHelper">网络频道辅助器。</param>
|
||||
/// <returns>要创建的网络频道。</returns>
|
||||
public INetworkChannel CreateNetworkChannel(string name, ServiceType serviceType, INetworkChannelHelper networkChannelHelper)
|
||||
public INetworkChannel CreateNetworkChannel(string name, ServiceType serviceType,
|
||||
INetworkChannelHelper networkChannelHelper)
|
||||
{
|
||||
if (networkChannelHelper == null)
|
||||
{
|
||||
@@ -197,7 +200,8 @@ namespace TEngine
|
||||
|
||||
if (HasNetworkChannel(name))
|
||||
{
|
||||
throw new GameFrameworkException(Utility.Text.Format("Already exist network channel '{0}'.", name ?? string.Empty));
|
||||
throw new GameFrameworkException(Utility.Text.Format("Already exist network channel '{0}'.",
|
||||
name ?? string.Empty));
|
||||
}
|
||||
|
||||
NetworkChannelBase networkChannel = null;
|
||||
@@ -210,17 +214,18 @@ namespace TEngine
|
||||
case ServiceType.TcpWithSyncReceive:
|
||||
networkChannel = new TcpWithSyncReceiveNetworkChannel(name, networkChannelHelper);
|
||||
break;
|
||||
|
||||
|
||||
case ServiceType.Udp:
|
||||
networkChannel = new UdpNetworkChannel(name, networkChannelHelper);
|
||||
break;
|
||||
|
||||
|
||||
case ServiceType.Kcp:
|
||||
networkChannel = new KcpNetworkChannel(name, networkChannelHelper);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new GameFrameworkException(Utility.Text.Format("Not supported service type '{0}'.", serviceType));
|
||||
throw new GameFrameworkException(Utility.Text.Format("Not supported service type '{0}'.",
|
||||
serviceType));
|
||||
}
|
||||
|
||||
networkChannel.NetworkChannelConnected += OnNetworkChannelConnected;
|
||||
@@ -249,6 +254,7 @@ namespace TEngine
|
||||
networkChannel.Shutdown();
|
||||
return name != null && _networkChannels.Remove(name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -285,7 +291,8 @@ namespace TEngine
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNetworkChannelError(NetworkChannelBase networkChannel, NetworkErrorCode errorCode, SocketError socketErrorCode, string errorMessage)
|
||||
private void OnNetworkChannelError(NetworkChannelBase networkChannel, NetworkErrorCode errorCode,
|
||||
SocketError socketErrorCode, string errorMessage)
|
||||
{
|
||||
if (_networkErrorEventHandler != null)
|
||||
{
|
||||
@@ -307,4 +314,4 @@ namespace TEngine
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
using TEngine;
|
||||
|
||||
namespace GameLogic
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息包基类。
|
||||
/// </summary>
|
||||
public abstract class PacketBase : Packet
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息包Id。
|
||||
/// </summary>
|
||||
public int ProtoId;
|
||||
|
||||
/// <summary>
|
||||
/// 网络消息包包体。
|
||||
/// </summary>
|
||||
public byte[] ProtoBody;
|
||||
|
||||
public void Close()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: acea4283f57644b6b4452354d23f2803
|
||||
timeCreated: 1682045887
|
@@ -1,15 +0,0 @@
|
||||
namespace GameLogic
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息包。
|
||||
/// </summary>
|
||||
public partial class ProtoPacket : PacketBase
|
||||
{
|
||||
public override int Id => 1;
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da70995486db4799baba570b1767ab86
|
||||
timeCreated: 1682045865
|
@@ -18,6 +18,16 @@ public partial class ProtobufUtility
|
||||
{
|
||||
((IMessage)message).WriteTo(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消息压入内存流。
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="stream"></param>
|
||||
public static void ToStream(object message, Stream stream)
|
||||
{
|
||||
((IMessage)message).WriteTo(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 比特流解析。
|
||||
|
@@ -1,3 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 972ca4545003463d8710de956f0fde66
|
||||
guid: 26e2c268a764bad4eb7412ad65f822e2
|
||||
timeCreated: 1682047511
|
@@ -1,18 +0,0 @@
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息包基类。
|
||||
/// </summary>
|
||||
public abstract class Packet : IMemory
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取类型编号。
|
||||
/// </summary>
|
||||
public abstract int Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 清理引用。
|
||||
/// </summary>
|
||||
public abstract void Clear();
|
||||
}
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b840df90fc73484d94cf06e87190f9e2
|
||||
timeCreated: 1681994166
|
Reference in New Issue
Block a user