同步网络框架到Asset目录下

同步网络框架到Asset目录下
This commit is contained in:
ALEXTANG
2022-05-26 18:48:40 +08:00
parent bb87c7d34d
commit 718c7a683a
27 changed files with 1573 additions and 334 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e800972100523f14ebc6cae9f2fd6644
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,166 @@
namespace TEngine.Net
{
enum ClientConnectWatcherStatus
{
StatusInit,
StatusReconnectAuto,
StatusReconnectConfirm,
StatusWaitExit
}
class ClientConnectWatcher
{
#region Propreties
private GameClient m_client;
private float m_statusTime;
private int m_reconnetCnt = 0;
private int m_disconnectReason = 0;
private ClientConnectWatcherStatus m_status = ClientConnectWatcherStatus.StatusInit;
private bool m_enable = false;
public bool Enable
{
get { return m_enable; }
set
{
if (m_enable != value)
{
m_enable = value;
if (m_enable)
{
OnEnable();
}
else
{
OnDisable();
}
}
}
}
ClientConnectWatcherStatus Status
{
get { return m_status; }
set
{
if (m_status != value)
{
m_status = value;
m_statusTime = GameTime.time;
}
}
}
#endregion
public ClientConnectWatcher(GameClient client)
{
m_client = client;
m_statusTime = GameTime.time;
m_status = ClientConnectWatcherStatus.StatusInit;
}
public void Update()
{
if (!m_enable)
{
return;
}
if (m_client.IsEntered)
{
return;
}
switch (m_status)
{
case ClientConnectWatcherStatus.StatusInit:
UpdateOnInitStatus();
break;
case ClientConnectWatcherStatus.StatusReconnectAuto:
UpdateOnReconnectAuto();
break;
case ClientConnectWatcherStatus.StatusReconnectConfirm:
UpdateOnReconnectConfirm();
break;
case ClientConnectWatcherStatus.StatusWaitExit:
UpdateOnWaitExit();
break;
default:
break;
}
}
public void OnReConnect()
{
if (m_status == ClientConnectWatcherStatus.StatusReconnectConfirm)
{
Status = ClientConnectWatcherStatus.StatusReconnectAuto;
}
}
void UpdateOnInitStatus()
{
if (m_reconnetCnt <= 2)
{
if (m_reconnetCnt == 0)
{
m_disconnectReason = m_client.LastNetErrCode;
}
Status = ClientConnectWatcherStatus.StatusReconnectAuto;
m_reconnetCnt++;
//Reconnect
m_client.Reconnect();
}
else
{
Status = ClientConnectWatcherStatus.StatusReconnectConfirm;
m_reconnetCnt++;
//var window = UISys.Mgr.ShowWindow<Tip_NetError>();
//window.SetErrCode(m_disconnectReason);
}
}
void UpdateOnReconnectAuto()
{
if (m_client.IsEntered)
{
Status = ClientConnectWatcherStatus.StatusInit;
m_reconnetCnt = 0;
return;
}
float nowTime = GameTime.time;
if (m_statusTime + 5 < nowTime)
{
//切换到默认的,下一帧继续判断是否需要自动还是手动
Status = ClientConnectWatcherStatus.StatusInit;
return;
}
}
void UpdateOnReconnectConfirm()
{
}
void UpdateOnWaitExit()
{
}
private void OnDisable()
{
Status = ClientConnectWatcherStatus.StatusInit;
m_reconnetCnt = 0;
}
private void OnEnable()
{
Status = ClientConnectWatcherStatus.StatusInit;
m_reconnetCnt = 0;
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 47c4d87ce2ebe82469c001812ba48857
guid: c3a6f66c5fcbf4b4db89a4a9405d329d
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 76c964bcca9c1b141aa222e9ad6000e0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,118 @@
using System;
using System.Net;
using System.Net.Sockets;
namespace TEngine.Net
{
public enum ClientSocketEventType
{
EventConnected,
EventConnectFail,
EventDisconnected,
}
public interface IClientSocket
{
/// <summary>
/// 是否连接了
/// </summary>
bool IsConnected { get; }
/// <summary>
/// 是否是流协议
/// </summary>
bool IsStream { get; }
/// <summary>
/// 心跳间隔
/// </summary>
int HeartBeatInterval { get; }
/// <summary>
/// 本地绑定地址
/// </summary>
EndPoint LocalAddr { get; }
SocketError LastSockError { get; }
string LastErrDesc { get; }
/// <summary>
/// 注册系统事件
/// </summary>
/// <param name="handler"></param>
void RegEventHandle(Action<ClientSocketEventType> handler);
/// <summary>
/// 连接请求
/// </summary>
/// <param name="server"></param>
/// <param name="port"></param>
/// <param name="iTimeout"></param>
/// <param name="retryNum"></param>
/// <returns></returns>
bool Connect(string server, int port, int iTimeout, int retryNum);
/// <summary>
/// 关闭连接
/// </summary>
void Close();
/// <summary>
/// 关闭连接
/// </summary>
void Shutdown();
/// <summary>
/// 发送数据
/// </summary>
/// <returns></returns>
bool Send(byte[] data, int offset, int len);
/// <summary>
/// 发送快捷数据,不用保证丢包
/// </summary>
/// <param name="data"></param>
/// <param name="offset"></param>
/// <param name="len"></param>
/// <returns></returns>
bool SendUdpTypeData(byte[] data, int offset, int len);
/// <summary>
/// 是否支持udp的包
/// </summary>
/// <returns></returns>
bool IsSupportUdpType();
/// <summary>
/// 收包处理
/// </summary>
/// <param name="buf"></param>
/// <param name="iOffset"></param>
/// <param name="maxSize"></param>
/// <returns></returns>
int Recv(byte[] buf, int iOffset, int maxSize);
/// <summary>
/// 循环调用
/// </summary>
void Update();
/// <summary>
/// 最后一帧,保证肯定要包发出去,减少延迟
/// </summary>
void LateUpdate();
/// <summary>
/// 获取写队列的个数
/// </summary>
/// <returns></returns>
int GetSendQueueCount();
/// <summary>
/// 像底层注册错误打印,当缓冲区满之类的,调用上层的统计来打印
/// </summary>
/// <param name="debugCmd"></param>
void RegDebugCmdHandle(Action debugCmd);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c37e3056155a5ee4c96dc8d42b1709e5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,117 @@

using System;
using System.Linq;
using Google.Protobuf;
using TEngineProto;
namespace TEngine.Net
{
public class Message
{
private const int BufferHead = 4;
private static byte[] buffer = new byte[1024];
private int startindex;
public byte[] Buffer
{
get { return buffer; }
}
public int StartIndex
{
get { return startindex; }
}
public int Remsize
{
get { return buffer.Length - startindex; }
}
public void ReadBuffer(byte[] bufBytes, Action<MainPack> handleResponse = null)
{
var length = bufBytes.Length;
for (int i = 0; i < length; i++)
{
Buffer[i] = bufBytes[i];
}
startindex += length;
if (startindex <= BufferHead)
{
return;
}
int count = length - BufferHead;
while (true)
{
if (startindex >= (count + BufferHead))
{
MainPack pack = (MainPack)MainPack.Descriptor.Parser.ParseFrom(buffer, BufferHead, count);
if (handleResponse != null)
{
handleResponse(pack);
}
Array.Copy(buffer, length, buffer, 0, startindex - length);
startindex -= length;
}
else
{
break;
}
}
}
public void ReadBuffer(int length, Action<MainPack> handleResponse = null)
{
startindex += length;
if (startindex <= BufferHead)
{
return;
}
int count = length - BufferHead;
while (true)
{
if (startindex >= (count + BufferHead))
{
MainPack pack = (MainPack)MainPack.Descriptor.Parser.ParseFrom(buffer, BufferHead, count);
if (handleResponse != null)
{
handleResponse(pack);
}
Array.Copy(buffer, length, buffer, 0, startindex - length);
startindex -= length;
}
else
{
break;
}
}
}
public static byte[] PackData(MainPack pack)
{
byte[] data = pack.ToByteArray();
byte[] head = BitConverter.GetBytes(data.Length);
return head.Concat(data).ToArray();
}
public static byte[] PackDataUdp(MainPack pack)
{
return pack.ToByteArray();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e2a6d378c8d029a4886da7ea14125b90
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using TEngineProto;
namespace TEngine.Net
{
public class TcpConnection
{
private Socket socket;
private string m_Host;
private int m_Port;
private Message message;
private GameClient gameClient;
public TcpConnection(GameClient gameClient)
{
message = new Message();
this.gameClient = gameClient;
}
public bool Connect(string host, int port)
{
if (socket == null)
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
else
{
if (socket.Connected)
{
socket.Close();
}
}
TLogger.LogInfo("start connect server[{0}:{1}]...", host, port);
gameClient.Status = GameClientStatus.StatusInit;
try
{
socket.Connect(host, port);
StartReceive();
gameClient.Status = GameClientStatus.StatusConnect;
}
catch (Exception e)
{
TLogger.LogError(e.Message);
TLogger.LogError("socket connect {0}:{1} failed", host, port);
return false;
}
TLogger.LogInfoSuccessd("connect server[{0}:{1}] success!!!", host, port);
m_Host = host;
m_Port = port;
return true;
}
void StartReceive()
{
socket.BeginReceive(message.Buffer, message.StartIndex, message.Remsize, SocketFlags.None, ReceiveCallback, null);
}
void ReceiveCallback(IAsyncResult asyncResult)
{
try
{
if (socket == null || socket.Connected == false)
{
return;
}
int Length = socket.EndReceive(asyncResult);
if (Length == 0)
{
Close();
return;
}
message.ReadBuffer(Length, gameClient.HandleResponse);
StartReceive();
}
catch (Exception e)
{
TLogger.LogError("TcpConnection DisConnected: " + e);
Close();
}
}
public bool SendCsMsg(MainPack mainPack)
{
if (socket == null || socket.Connected == false)
{
return false;
}
try
{
socket.Send(Message.PackData(mainPack));
return true;
}
catch (Exception e)
{
TLogger.LogError("TcpConnection SendCsMsg: " + e);
return false;
}
}
public void Close()
{
if (socket != null && socket.Connected)
{
socket.Close();
}
gameClient.Status = GameClientStatus.StatusInit;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 997699216368d574cbc53511506d77f8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,94 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using TEngineProto;
namespace TEngine.Net
{
public enum UdpState
{
None,
Start,
Close,
}
public class UdpConnection
{
private Thread udpThread;
private Socket udpClient;
private EndPoint _ePoint;
private IPEndPoint ipEndPoint;
private Byte[] buffer = new Byte[2048];
private GameClient client;
private UdpState udpState = UdpState.None;
public UdpState State
{
get
{
return udpState;
}
set
{
udpState = value;
}
}
public UdpConnection(GameClient client)
{
this.client = client;
}
public void ConnectUdp(string host,int port)
{
udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
ipEndPoint = new IPEndPoint(IPAddress.Parse(host), port + 1);
_ePoint = ipEndPoint;
udpState = UdpState.Start;
try
{
TLogger.LogInfo("start connect udp server[{0}:{1}]...", host, port);
udpClient.Connect(_ePoint);
}
catch
{
TLogger.LogError("UDP connect failed!...".ToColor("FF0000"));
return;
}
TLogger.LogInfo("start connect udp server[{0}:{1}] successed...".ToColor("10FD00"), host, port);
Loom.RunAsync(() =>
{
udpThread = new Thread(ReceiveMsg);
udpThread.Start();
}
);
}
private void ReceiveMsg()
{
try
{
while (true)
{
if (client == null || udpState != UdpState.Start)
{
return;
}
int len = udpClient.ReceiveFrom(buffer, ref _ePoint);
MainPack pack = (MainPack)MainPack.Descriptor.Parser.ParseFrom(buffer, 0, len);
Loom.QueueOnMainThread((param) =>
{
client.UdpHandleResponse(pack);
}, null);
}
}
catch (Exception e)
{
TLogger.LogError(e.Message);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6c63997a8d0569346945dbb31cfb6ce7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TEngine.Net
{
/// <summary>
/// 数据中心系统
/// </summary>
public class DataCenterSys : BaseLogicSys<DataCenterSys>
{
private List<IDataCenterModule> m_listModule = new List<IDataCenterModule>();
public override bool OnInit()
{
RegCmdHandle();
InitModule();
return true;
}
public override void OnUpdate()
{
GameClient.Instance.OnUpdate();
var listModule = m_listModule;
for (int i = 0; i < listModule.Count; i++)
{
listModule[i].OnUpdate();
}
}
public override void OnDestroy()
{
GameClient.Instance.Shutdown();
base.OnDestroy();
}
private void RegCmdHandle()
{
var client = GameClient.Instance;
//client.RegActionHandle();
}
void InitModule()
{
//InitModule(LoginDataMgr.Instance);
}
public void InitModule(IDataCenterModule module)
{
if (!m_listModule.Contains(module))
{
module.Init();
m_listModule.Add(module);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 637ccf86c9ad9c34a866fe2b8556e96d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c5415c6c1796e4d46a895770f5ed37cc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,57 @@
using TEngineCore;
using TEngineCore.Net;
using TEngineProto;
using UnityEngine;
using UnityEngine.UI;
namespace TEngineCore
{
public class TEngineLoginUI : UIWindow
{
#region
private Image m_imgbg;
private Text m_textTittle;
private Text m_textVer;
private Image m_imgLogo;
private GameObject m_goLoading;
private GameObject m_goLoginRoot;
private InputField m_inputName;
private InputField m_inputPassword;
private Button m_btnLogin;
protected override void ScriptGenerator()
{
m_imgbg = FindChildComponent<Image>("m_imgbg");
m_textTittle = FindChildComponent<Text>("m_textTittle");
m_textVer = FindChildComponent<Text>("m_textVer");
m_imgLogo = FindChildComponent<Image>("m_imgLogo");
m_goLoading = FindChild("m_goLoading").gameObject;
m_goLoginRoot = FindChild("m_goLoginRoot").gameObject;
m_inputName = FindChildComponent<InputField>("m_goLoginRoot/m_inputName");
m_inputPassword = FindChildComponent<InputField>("m_goLoginRoot/m_inputPassword");
m_btnLogin = FindChildComponent<Button>("m_goLoginRoot/m_btnLogin");
m_btnLogin.onClick.AddListener(OnClickLoginBtn);
}
#endregion
#region
private void OnClickLoginBtn()
{
var loginPack = new MainPack();
loginPack.Requestcode = RequestCode.User;
loginPack.Actioncode = ActionCode.Login;
loginPack.LoginPack = new LoginPack
{
Username = m_inputName.text,
Password = m_inputName.text,
};
GameClient.Instance.SendCsMsg(loginPack, CallBack);
}
private void CallBack(MainPack pack)
{
TLogger.LogInfoSuccessd("MainPack" + pack);
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 71f5f66a7f8111144af95af151ddf080
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,596 @@
using System;
using System.Collections.Generic;
using TEngineProto;
using UnityEngine;
namespace TEngine.Net
{
/// <summary>
/// 客户端状态
/// </summary>
public enum GameClientStatus
{
StatusInit, //初始化
StatusReconnect, //重新连接
StatusClose, //断开连接
StatusConnect, //连接中
StatusEnter, //Login登录成功
}
public delegate void CsMsgDelegate(MainPack mainPack);
public class GameClient:TSingleton<GameClient>
{
#region Propriety
private string m_lastHost = null;
private int m_lastPort = 0;
private GameClientStatus m_status = GameClientStatus.StatusInit;
/// <summary>
/// GameClient状态
/// </summary>
public GameClientStatus Status
{
get
{
return m_status;
}
set
{
m_status = value;
}
}
/// <summary>
/// 最新连接错误的时间
/// </summary>
private float m_lastLogDisconnectErrTime = 0f;
/// <summary>
/// 最新的错误码
/// </summary>
private int m_lastNetErrCode = 0;
/// <summary>
/// 最近一次心跳的时间
/// </summary>
private float m_lastHbTime = 0f;
/// <summary>
/// 心跳间隔
/// </summary>
private const float m_heartBeatDurTime = 15;
/// <summary>
/// 连续心跳超时
/// </summary>
private int m_heatBeatTimeoutNum = 0;
private int m_ping = -1;
public bool IsEntered
{
get { return m_status == GameClientStatus.StatusEnter; }
}
public bool IsNetworkOkAndLogined
{
get
{
return m_status == GameClientStatus.StatusEnter;
}
}
public int LastNetErrCode
{
get { return m_lastNetErrCode; }
}
private ClientConnectWatcher m_connectWatcher;
private void ResetParam()
{
m_lastLogDisconnectErrTime = 0f;
m_heatBeatTimeoutNum = 0;
m_lastHbTime = 0f;
m_ping = -1;
m_lastNetErrCode = 0;
}
#endregion
private TcpConnection m_connect;
public GameClient()
{
m_connect = new TcpConnection(this);
m_connectWatcher = new ClientConnectWatcher(this);
}
~GameClient()
{
if (m_connect != null)
{
m_connect.Close();
}
m_connect = null;
}
public bool Connect(string host, int port, bool reconnect = false)
{
ResetParam();
if (!reconnect)
{
SetWatchReconnect(false);
}
//GameEventMgr.Instance.Send(ShowWaitingUI);
m_lastHost = host;
m_lastPort = port;
Status = reconnect ? GameClientStatus.StatusReconnect : GameClientStatus.StatusInit;
TLogger.LogInfo("Start connect server {0}:{1} Reconnect:{2}", host, port, reconnect);
return m_connect.Connect(host, port);
}
public void Shutdown()
{
m_connect.Close();
m_status = GameClientStatus.StatusInit;
TLogger.LogWarning("GameClient Shut Down");
}
#region
/// <summary>
/// 发送消息包
/// </summary>
/// <param name="reqPkg"></param>
/// <returns></returns>
public bool SendCsMsg(MainPack reqPkg)
{
if (!CheckPack(reqPkg))
{
return false;
}
return DoSendData(reqPkg);
}
/// <summary>
/// 发送消息包并注册回调
/// </summary>
/// <param name="pack"></param>
/// <param name="resHandler"></param>
/// <param name="needShowWaitUI"></param>
/// <returns></returns>
public bool SendCsMsg(MainPack pack, CsMsgDelegate resHandler = null, bool needShowWaitUI = true)
{
if (!CheckPack(pack))
{
return false;
}
var ret = DoSendData(pack);
if (!ret)
{
TLogger.LogError("SendCSMsg Error");
}
else
{
if (resHandler != null)
{
RegTimeOutHandle((uint)pack.Actioncode, resHandler);
RegActionHandle((int)pack.Actioncode, resHandler);
}
}
return ret;
}
private bool DoSendData(MainPack reqPkg)
{
var sendRet = m_connect.SendCsMsg(reqPkg);
return sendRet;
}
#endregion
#region 线
Dictionary<int, List<CsMsgDelegate>> m_mapCmdHandle = new Dictionary<int, List<CsMsgDelegate>>();
/// <summary>
/// 委托缓存堆栈
/// </summary>
private Queue<List<CsMsgDelegate>> cachelistHandle = new Queue<List<CsMsgDelegate>>();
/// <summary>
/// 消息包缓存堆栈
/// </summary>
private Queue<MainPack> queuepPacks = new Queue<MainPack>();
/// <summary>
/// 网络消息回调,非主线程
/// </summary>
/// <param name="pack"></param>
public void HandleResponse(MainPack pack)
{
lock (cachelistHandle)
{
List<CsMsgDelegate> listHandle;
if (m_mapCmdHandle.TryGetValue((int)pack.Actioncode, out listHandle))
{
cachelistHandle.Enqueue(listHandle);
queuepPacks.Enqueue(pack);
}
}
}
/// <summary>
/// Udp网络消息回调Loom多线程回调到此处主线程
/// </summary>
/// <param name="pack"></param>
public void UdpHandleResponse(MainPack pack)
{
List<CsMsgDelegate> listHandle;
if (m_mapCmdHandle.TryGetValue((int)pack.Actioncode, out listHandle))
{
foreach (CsMsgDelegate handle in listHandle)
{
handle(pack);
}
}
}
#endregion
#region
/// <summary>
/// 注册静态消息
/// </summary>
/// <param name="iCmdID"></param>
/// <param name="msgDelegate"></param>
public void RegActionHandle(int actionId, CsMsgDelegate msgDelegate)
{
List<CsMsgDelegate> listHandle;
if (!m_mapCmdHandle.TryGetValue(actionId, out listHandle))
{
listHandle = new List<CsMsgDelegate>();
m_mapCmdHandle[actionId] = listHandle;
}
if (listHandle != null)
{
if (!listHandle.Contains(msgDelegate))
{
listHandle.Add(msgDelegate);
}
else
{
//Debug.LogFormat("-------------repeat RegCmdHandle ActionCode:{0}-----------", (ActionCode)actionId);
}
}
}
/// <summary>
/// 注册Udp静态消息
/// </summary>
/// <param name="iCmdID"></param>
/// <param name="msgDelegate"></param>
public void UdpRegActionHandle(int actionId, CsMsgDelegate msgDelegate)
{
List<CsMsgDelegate> listHandle;
if (!m_mapCmdHandle.TryGetValue(actionId, out listHandle))
{
listHandle = new List<CsMsgDelegate>();
m_mapCmdHandle[actionId] = listHandle;
}
if (listHandle != null)
{
if (listHandle.Contains(msgDelegate))
{
Debug.LogFormat("-------------repeat RegCmdHandle ActionCode:{0}-----------", (ActionCode)actionId);
}
listHandle.Add(msgDelegate);
}
}
/// <summary>
/// 移除消息处理函数
/// </summary>
/// <param name="cmdId"></param>
/// <param name="msgDelegate"></param>
public void RmvCmdHandle(int actionId, CsMsgDelegate msgDelegate)
{
List<CsMsgDelegate> listHandle;
if (!m_mapCmdHandle.TryGetValue(actionId, out listHandle))
{
return;
}
if (listHandle != null)
{
listHandle.Remove(msgDelegate);
}
}
private bool CheckPack(MainPack pack)
{
if (pack == null)
{
return false;
}
if (pack.Actioncode == ActionCode.ActionNone)
{
return false;
}
if (pack.Requestcode == RequestCode.RequestNone)
{
return false;
}
return true;
}
#endregion
#region
protected bool CheckHeatBeatTimeout()
{
if (m_heatBeatTimeoutNum >= 2)
{
Shutdown();
m_heatBeatTimeoutNum = 0;
Status = GameClientStatus.StatusClose;
TLogger.LogError("heat beat detect timeout");
return false;
}
return true;
}
void TickHeartBeat()
{
if (Status != GameClientStatus.StatusEnter)
{
return;
}
var nowTime = GameTime.RealtimeSinceStartup;
if (m_lastHbTime + m_heartBeatDurTime < nowTime)
{
m_lastHbTime = nowTime;
MainPack pack = new MainPack
{
Actioncode = ActionCode.HeartBeat
};
GameClient.Instance.SendCsMsg(pack, HandleHeatBeatRes);
}
}
void HandleHeatBeatRes(MainPack mainPack)
{
if (mainPack.Returncode != ReturnCode.Success)
{
//如果是超时了,则标记最近收到包的次数
if (mainPack.Returncode == ReturnCode.MsgTimeOut)
{
m_heatBeatTimeoutNum++;
TLogger.LogError("heat beat timeout: {0}", m_heatBeatTimeoutNum);
}
}
else
{
float diffTime = GameTime.RealtimeSinceStartup - mainPack.HeatEchoTime;
m_ping = (int)(diffTime * 1000);
m_heatBeatTimeoutNum = 0;
}
}
#endregion
/// <summary>
/// 清理所有的网络消息
/// </summary>
public void CleanAllNetMsg()
{
m_mapCmdHandle.Clear();
}
public void Reconnect()
{
m_connectWatcher.OnReConnect();
Connect(m_lastHost, m_lastPort, true);
}
public void OnUpdate()
{
HandleCsMsgOnUpdate();
CheckCsMsgTimeOut();
TickHeartBeat();
CheckHeatBeatTimeout();
m_connectWatcher.Update();
}
#region
#region TimeOutCheck
private const int CHECK_TIMEOUT_PERFRAME = 10;
const int MAX_MSG_HANDLE = 256;
UInt32 m_dwLastCheckIndex = 0;
CsMsgDelegate[] m_aMsgHandles = new CsMsgDelegate[MAX_MSG_HANDLE];
float[] m_fMsgRegTime = new float[MAX_MSG_HANDLE];
private float m_timeout = 15;
#endregion
private readonly MainPack _timeOutPack = new MainPack { Returncode = ReturnCode.MsgTimeOut };
private void CheckCsMsgTimeOut()
{
float nowTime = GameTime.time;
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] + m_timeout < nowTime)
{
TLogger.LogError("msg timeout, resCmdID[{0}]", m_aMsgHandles[m_dwLastCheckIndex]);
NotifyTimeout(m_aMsgHandles[m_dwLastCheckIndex]);
RmvCheckCsMsg((int)m_dwLastCheckIndex);
}
}
}
}
public void RmvCheckCsMsg(int index)
{
m_aMsgHandles[index] = null;
m_fMsgRegTime[index] = 0;
}
private void RegTimeOutHandle(uint actionCode, CsMsgDelegate resHandler)
{
uint hashIndex = actionCode % MAX_MSG_HANDLE;
if (m_aMsgHandles[hashIndex] != null)
{
//NotifyTimeout(m_aMsgHandles[hashIndex]);
RmvCheckCsMsg((int)hashIndex);
}
m_aMsgHandles[hashIndex] = resHandler;
m_fMsgRegTime[hashIndex] = GameTime.time;
}
protected void NotifyTimeout(CsMsgDelegate msgHandler)
{
msgHandler(_timeOutPack);
}
#endregion
/// <summary>
/// 主线程从消息包缓存堆栈/委托缓存堆栈中出列
/// </summary>
private void HandleCsMsgOnUpdate()
{
if (cachelistHandle.Count <= 0 || queuepPacks.Count <= 0)
{
return;
}
try
{
foreach (CsMsgDelegate handle in cachelistHandle.Dequeue())
{
var pack = queuepPacks.Peek();
if (pack != null)
{
handle(pack);
UInt32 hashIndex = (uint)pack.Actioncode % MAX_MSG_HANDLE;
RmvCheckCsMsg((int)hashIndex);
}
}
queuepPacks.Dequeue();
}
catch (Exception e)
{
TLogger.LogError(e.Message);
}
}
protected override void Init()
{
base.Init();
}
public override void Active()
{
base.Active();
}
public override void Release()
{
if (m_connect != null)
{
m_connect.Close();
}
m_connect = null;
base.Release();
}
public bool IsStatusCanSendMsg()
{
if (m_status == GameClientStatus.StatusEnter)
{
return true;
}
float nowTime = GameTime.time;
if (m_lastLogDisconnectErrTime + 5 < nowTime)
{
TLogger.LogError("GameClient not connected, send msg failed");
m_lastLogDisconnectErrTime = nowTime;
}
return false;
}
/// <summary>
/// 设置是否需要监控网络重连
/// </summary>
/// <param name="needWatch"></param>
public void SetWatchReconnect(bool needWatch)
{
m_connectWatcher.Enable = needWatch;
}
#region Ping
/// <summary>
/// ping值
/// </summary>
public int Ping
{
get
{
if (IsPingValid())
{
return m_ping / 4;
}
else
{
return 0;
}
}
}
public bool IsPingValid()
{
if (IsNetworkOkAndLogined)
{
return m_ping >= 0;
}
return false;
}
#endregion
#region GetNetworkType
public static CsNetworkType GetNetworkType()
{
CsNetworkType csNetType = CsNetworkType.CSNETWORK_UNKNOWN;
NetworkReachability reachability = Application.internetReachability;
switch (reachability)
{
case NetworkReachability.NotReachable:
break;
case NetworkReachability.ReachableViaLocalAreaNetwork:
csNetType = CsNetworkType.CSNETWORK_WIFI;
break;
case NetworkReachability.ReachableViaCarrierDataNetwork:
csNetType = CsNetworkType.CSNETWORK_3G;
break;
}
return csNetType;
}
public enum CsNetworkType
{
CSNETWORK_UNKNOWN = 0, /*未知类型*/
CSNETWORK_WIFI = 1, /*Wifi类型*/
CSNETWORK_3G = 2, /*3G类型*/
CSNETWORK_2G = 3 /*2G类型*/
};
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 626e38f9746ce274a898dab6420ec284
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,48 @@
namespace TEngine.Net
{
public interface IDataCenterModule
{
void Init();
void OnRoleLogout();
void OnUpdate();
void OnMainPlayerMapChange();
}
public class DataCenterModule<T> : IDataCenterModule where T : new()
{
private static T instance;
public static T Instance
{
get
{
if (null == instance)
{
instance = new T();
}
return instance;
}
}
public virtual void Init()
{
}
public virtual void OnRoleLogout()
{
}
public virtual void OnUpdate()
{
}
public virtual void OnMainPlayerMapChange()
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8018a083c1db8244c84deee97365d954
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
namespace TEngine.Net
{
internal class NetEventId
{
public static int HeartBeat = StringId.StringToHash("NetEventId.HeartBeat");
public static int ConnectTcp = StringId.StringToHash("NetEventId.ConnectTcp");
public static int ConnectUdp = StringId.StringToHash("NetEventId.ConnectUdp");
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 974dfabe252d1984291d86de88f52261
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,52 @@
using System.IO;
using JetBrains.Annotations;
namespace TEngine.Net
{
public class ProtoUtils
{
/// <summary>
/// 序列化 MainPack -> byte[]
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="mainPack"></param>
/// <returns></returns>
[CanBeNull]
public static byte[] Serialize<T>(T mainPack) where T : class
{
try
{
using (var stream = new System.IO.MemoryStream())
{
ProtoBuf.Serializer.Serialize(stream, mainPack);
return stream.ToArray();
}
}
catch (IOException ex)
{
TLogger.LogError($"[Serialize] Error{ex.Message}, {ex.Data["StackTrace"]}");
return null;
}
}
/// <summary>
/// 反序列化
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="buffer"></param>
/// <returns></returns>
[CanBeNull]
public static T DeSerialize<T>(byte[] buffer) where T : class
{
try
{
return ProtoBuf.Serializer.Deserialize(typeof(T), new System.IO.MemoryStream(buffer)) as T;
}
catch (IOException ex)
{
TLogger.LogError(($"[DeSerialize] 错误:{ex.Message}, {ex.Data["StackTrace"]}"));
return null;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cd6ea983cec305b48a5aa4309c159038
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -116,7 +116,7 @@ namespace TEngine
}
}
public static Thread RunAsync(string actionName,Action action)
public static Thread RunAsync(Action action)
{
Initialize();
while (_numThreads >= MaxThreads)

View File

@@ -1,332 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace TEngine
{
public class TypeUtility
{
public static Type GetType(string typeName)
{
return GetType("", typeName, false);
}
public static Type GetTypeInEditor(string typeName)
{
return GetType("", typeName, true);
}
public static Type GetNestedType(Type inDelareType, string inStrTypeName)
{
Type type = inDelareType.GetNestedType(inStrTypeName,
BindingFlags.Public | BindingFlags.NonPublic);
if (type == null)
{
TLogger.LogError("GetNestedType failed: {0}.{1}", inDelareType, inStrTypeName);
}
return type;
}
private static Dictionary<string, Dictionary<string, Type>> _s_type_with_name_cache = null;
public static Type GetType(string inStrAssemblyName, string inStrTypeName, bool inIsEditor)
{
if (string.IsNullOrEmpty(inStrTypeName))
{
TLogger.LogError("GetType:typeName is null");
return null;
}
Type type = null;
if (_s_type_with_name_cache == null)
{
_s_type_with_name_cache = new Dictionary<string, Dictionary<string, Type>>();
}
if (_s_type_with_name_cache.ContainsKey(inStrAssemblyName) != true)
{
_s_type_with_name_cache.Add(inStrAssemblyName, new Dictionary<string, Type>());
}
else
{
if (_s_type_with_name_cache[inStrAssemblyName].ContainsKey(inStrTypeName))
{
type = _s_type_with_name_cache[inStrAssemblyName][inStrTypeName];
return type;
}
}
type = Type.GetType(inStrTypeName);
if (null != type)
{
_s_type_with_name_cache[inStrAssemblyName][inStrTypeName] = type;
return type;
}
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
{
if (!string.IsNullOrEmpty(inStrAssemblyName) && a.GetName().Name != inStrAssemblyName)
continue;
type = a.GetType(inStrTypeName);
if (type != null)
{
_s_type_with_name_cache[inStrAssemblyName][inStrTypeName] = type;
return type;
}
}
return null;
}
public static void ClearTypeCache()
{
if (_s_type_with_name_cache != null)
{
foreach (var kv in _s_type_with_name_cache)
{
if (kv.Value != null)
{
kv.Value.Clear();
}
}
_s_type_with_name_cache.Clear();
_s_type_with_name_cache = null;
}
}
public class TypeComparer : IComparer<Type>
{
public int Compare(Type x, Type y)
{
if (object.ReferenceEquals(x, y))
return 0;
else if (x == null)
return -1;
else if (y == null)
return 1;
else
{
return string.Compare(x.FullName, y.FullName);
}
}
}
private static Dictionary<Type, Type[]> msDerivedTypes = new Dictionary<Type, Type[]>();
public static bool InitStaticTypes(Type inBaseType, Type[] inTypes)
{
if (inTypes.Length == 0)
return true;
if (!msDerivedTypes.TryGetValue(inBaseType, out Type[] existingTypes))
{
existingTypes = inTypes;
msDerivedTypes[inBaseType] = inTypes;
}
else
{
int numRedefinedTypes = 0;
List<Type> tempTypes = new List<Type>(inTypes.Length + existingTypes.Length);
tempTypes.AddRange(existingTypes);
#if UNITY_EDITOR
TypeComparer comparer = new TypeUtility.TypeComparer();
for (int i = 0; i < inTypes.Length; ++i)
{
Type curType = inTypes[i];
int idx = Array.BinarySearch<Type>(existingTypes, 0, existingTypes.Length, curType, comparer);
if (idx < 0)
tempTypes.Add(curType);
else
numRedefinedTypes++;
}
if (numRedefinedTypes > 0)
{
TLogger.LogError("{0} Redefined type in static type list.", numRedefinedTypes);
}
existingTypes = tempTypes.ToArray();
Array.Sort(existingTypes, comparer);
#else
tempTypes.AddRange(inTypes);
existingTypes = tempTypes.ToArray();
#endif
msDerivedTypes[inBaseType] = existingTypes;
}
return true;
}
[ThreadStatic]
private static Dictionary<Type, Type[]> msDerivedTypesCurThread;
public static void GetDerivedTypes(Type inType, string inStrAssembly, out Type[] outTypes)
{
GetTypesImpl(inType, inStrAssembly, true, IsDerivedClass, out outTypes);
}
public static void GetTypesImpInterfaceNonGenericNonAbstract(Type inInterface, string inStrAssembly, out Type[] outTypes)
{
GetTypesImpl(inInterface, inStrAssembly, true, IsImplInterfaceNonGeneric, out outTypes);
}
public static bool IsImplInterfaceNonGeneric(Type inInterface, Type inType)
{
return !inType.IsAbstract && !inType.IsGenericType && inType.GetInterface(inInterface.Name) != null;
}
public static bool IsSubclassOf(Type src, Type dst)
{
return src.IsSubclassOf(dst);
}
public static bool Equals(Type src, Type dst)
{
return src.Equals(dst);
}
public static bool IsDerivedClass(Type inBaseType, Type inType)
{
return (inBaseType == inType) || (!inType.IsAbstract && inType.IsSubclassOf(inBaseType));
}
public static void GetTypesImpl(Type inParamType, string inStrAssembly, bool inIsUseCache,
Func<Type, Type, bool> inCriteria, out Type[] outTypes)
{
Type[] existingTypes = null;
if (inIsUseCache && msDerivedTypes.TryGetValue(inParamType, out existingTypes) && existingTypes != null)
{
#if !UNITY_EDITOR
outTypes = existingTypes;
return;
#endif
}
if (inIsUseCache)
{
if (msDerivedTypesCurThread == null)
msDerivedTypesCurThread = new Dictionary<Type, Type[]>();
else
{
if (msDerivedTypesCurThread.TryGetValue(inParamType, out Type[] threadExistingTypes)
&& existingTypes != null)
{
outTypes = existingTypes;
return;
}
}
}
if (existingTypes == null)
{
TLogger.LogWarning("TypeUtility: Getting {0} Derived Type by iterating assembly.", inParamType);
}
else
{
TLogger.LogInfo("TypeUtility: Checking {0} Derived Type with assembly iterating.", inParamType);
}
List<Type> derivedTypeList = new List<Type>();
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
for (int k = 0; k < assemblies.Length; ++k)
{
Assembly tAssemble = assemblies[k];
if (!string.IsNullOrEmpty(inStrAssembly)
&& !tAssemble.GetName().Name.Equals(inStrAssembly))
{
continue;
}
Type[] allTypes = null;
try
{
allTypes = tAssemble.GetTypes();
}
catch (Exception e)
{
TLogger.LogError("GetDerivedTypes: {0} , GetTypes error -> {1}", e.ToString(), tAssemble);
}
if (allTypes == null)
continue;
for (int i = 0; i < allTypes.Length; ++i)
{
Type type = allTypes[i];
try
{
if (inCriteria(inParamType, type))
{
derivedTypeList.Add(type);
}
}
catch (Exception e)
{
TLogger.LogError("GetDerivedTypes with exception {0}, Type error -> {1} ", e.ToString(), type);
}
}
}
#if UNITY_EDITOR
if (existingTypes != null)
{
TypeUtility.TypeComparer comparer = new TypeComparer();
derivedTypeList.Sort(comparer);
StringBuilder sb = new StringBuilder();
int numDiff = 0;
int numTypes;
numTypes = derivedTypeList.Count;
int i = 0;
for (; i < numTypes; ++i)
{
Type t = derivedTypeList[i];
int idx = Array.BinarySearch(existingTypes, t, comparer);
if (idx < 0)
{
if (t.Assembly.GetName().Name != "PMEditor")
{
sb.AppendFormat("{0}\n", t.Name);
numDiff++;
}
}
}
if (numDiff != 0)
{
TLogger.LogWarning("GetDerivedTypes {0} consistency check failed with differences,\n runtime = {1}, static list = {2}, re-export code! Diff: {3}",
inParamType, derivedTypeList.Count, existingTypes.Length, sb.ToString());
}
}
else
{
TLogger.LogWarning("GetDerivedTypes type \"{0}\" was not defined in generated code.", inParamType);
}
#endif
outTypes = derivedTypeList.ToArray();
if (inIsUseCache)
{
msDerivedTypesCurThread[inParamType] = outTypes;
}
}
}
}