mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-14 16:51:28 +00:00
同步网络框架到Asset目录下
同步网络框架到Asset目录下
This commit is contained in:
8
Assets/TEngine/Runtime/Net.meta
Normal file
8
Assets/TEngine/Runtime/Net.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e800972100523f14ebc6cae9f2fd6644
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
166
Assets/TEngine/Runtime/Net/ClientConnectWatcher.cs
Normal file
166
Assets/TEngine/Runtime/Net/ClientConnectWatcher.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47c4d87ce2ebe82469c001812ba48857
|
||||
guid: c3a6f66c5fcbf4b4db89a4a9405d329d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
8
Assets/TEngine/Runtime/Net/ClientSocket.meta
Normal file
8
Assets/TEngine/Runtime/Net/ClientSocket.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76c964bcca9c1b141aa222e9ad6000e0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
118
Assets/TEngine/Runtime/Net/ClientSocket/IClientSocket.cs
Normal file
118
Assets/TEngine/Runtime/Net/ClientSocket/IClientSocket.cs
Normal 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);
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c37e3056155a5ee4c96dc8d42b1709e5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
117
Assets/TEngine/Runtime/Net/ClientSocket/Message.cs
Normal file
117
Assets/TEngine/Runtime/Net/ClientSocket/Message.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/TEngine/Runtime/Net/ClientSocket/Message.cs.meta
Normal file
11
Assets/TEngine/Runtime/Net/ClientSocket/Message.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2a6d378c8d029a4886da7ea14125b90
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
121
Assets/TEngine/Runtime/Net/ClientSocket/TcpConnection.cs
Normal file
121
Assets/TEngine/Runtime/Net/ClientSocket/TcpConnection.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 997699216368d574cbc53511506d77f8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
94
Assets/TEngine/Runtime/Net/ClientSocket/UdpConnection.cs
Normal file
94
Assets/TEngine/Runtime/Net/ClientSocket/UdpConnection.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c63997a8d0569346945dbb31cfb6ce7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
59
Assets/TEngine/Runtime/Net/DataCenterSys.cs
Normal file
59
Assets/TEngine/Runtime/Net/DataCenterSys.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/TEngine/Runtime/Net/DataCenterSys.cs.meta
Normal file
11
Assets/TEngine/Runtime/Net/DataCenterSys.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 637ccf86c9ad9c34a866fe2b8556e96d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/TEngine/Runtime/Net/Demo.meta
Normal file
8
Assets/TEngine/Runtime/Net/Demo.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c5415c6c1796e4d46a895770f5ed37cc
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
57
Assets/TEngine/Runtime/Net/Demo/TEngineLoginUI.cs
Normal file
57
Assets/TEngine/Runtime/Net/Demo/TEngineLoginUI.cs
Normal 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
|
||||
|
||||
}
|
||||
}
|
11
Assets/TEngine/Runtime/Net/Demo/TEngineLoginUI.cs.meta
Normal file
11
Assets/TEngine/Runtime/Net/Demo/TEngineLoginUI.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71f5f66a7f8111144af95af151ddf080
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
596
Assets/TEngine/Runtime/Net/GameClient.cs
Normal file
596
Assets/TEngine/Runtime/Net/GameClient.cs
Normal 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
|
||||
}
|
||||
}
|
11
Assets/TEngine/Runtime/Net/GameClient.cs.meta
Normal file
11
Assets/TEngine/Runtime/Net/GameClient.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 626e38f9746ce274a898dab6420ec284
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
48
Assets/TEngine/Runtime/Net/IDataCenterModule.cs
Normal file
48
Assets/TEngine/Runtime/Net/IDataCenterModule.cs
Normal 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()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/TEngine/Runtime/Net/IDataCenterModule.cs.meta
Normal file
11
Assets/TEngine/Runtime/Net/IDataCenterModule.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8018a083c1db8244c84deee97365d954
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/TEngine/Runtime/Net/NetEventId.cs
Normal file
9
Assets/TEngine/Runtime/Net/NetEventId.cs
Normal 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");
|
||||
}
|
||||
}
|
11
Assets/TEngine/Runtime/Net/NetEventId.cs.meta
Normal file
11
Assets/TEngine/Runtime/Net/NetEventId.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 974dfabe252d1984291d86de88f52261
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
52
Assets/TEngine/Runtime/Net/ProtoUtils.cs
Normal file
52
Assets/TEngine/Runtime/Net/ProtoUtils.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/TEngine/Runtime/Net/ProtoUtils.cs.meta
Normal file
11
Assets/TEngine/Runtime/Net/ProtoUtils.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd6ea983cec305b48a5aa4309c159038
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -116,7 +116,7 @@ namespace TEngine
|
||||
}
|
||||
}
|
||||
|
||||
public static Thread RunAsync(string actionName,Action action)
|
||||
public static Thread RunAsync(Action action)
|
||||
{
|
||||
Initialize();
|
||||
while (_numThreads >= MaxThreads)
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user