diff --git a/Assets/TEngine/Runtime/Net.meta b/Assets/TEngine/Runtime/Net.meta new file mode 100644 index 00000000..8bb6ec89 --- /dev/null +++ b/Assets/TEngine/Runtime/Net.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e800972100523f14ebc6cae9f2fd6644 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Net/ClientConnectWatcher.cs b/Assets/TEngine/Runtime/Net/ClientConnectWatcher.cs new file mode 100644 index 00000000..c8202a69 --- /dev/null +++ b/Assets/TEngine/Runtime/Net/ClientConnectWatcher.cs @@ -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(); + //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; + } + } +} diff --git a/Assets/TEngine/Runtime/Unitity/TypeUtility.cs.meta b/Assets/TEngine/Runtime/Net/ClientConnectWatcher.cs.meta similarity index 83% rename from Assets/TEngine/Runtime/Unitity/TypeUtility.cs.meta rename to Assets/TEngine/Runtime/Net/ClientConnectWatcher.cs.meta index 43e18818..ef847c6d 100644 --- a/Assets/TEngine/Runtime/Unitity/TypeUtility.cs.meta +++ b/Assets/TEngine/Runtime/Net/ClientConnectWatcher.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 47c4d87ce2ebe82469c001812ba48857 +guid: c3a6f66c5fcbf4b4db89a4a9405d329d MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/TEngine/Runtime/Net/ClientSocket.meta b/Assets/TEngine/Runtime/Net/ClientSocket.meta new file mode 100644 index 00000000..e63a0718 --- /dev/null +++ b/Assets/TEngine/Runtime/Net/ClientSocket.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 76c964bcca9c1b141aa222e9ad6000e0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Net/ClientSocket/IClientSocket.cs b/Assets/TEngine/Runtime/Net/ClientSocket/IClientSocket.cs new file mode 100644 index 00000000..03596d2d --- /dev/null +++ b/Assets/TEngine/Runtime/Net/ClientSocket/IClientSocket.cs @@ -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 + { + /// + /// 是否连接了 + /// + bool IsConnected { get; } + + /// + /// 是否是流协议 + /// + bool IsStream { get; } + + /// + /// 心跳间隔 + /// + int HeartBeatInterval { get; } + + /// + /// 本地绑定地址 + /// + EndPoint LocalAddr { get; } + + SocketError LastSockError { get; } + + string LastErrDesc { get; } + + /// + /// 注册系统事件 + /// + /// + void RegEventHandle(Action handler); + + /// + /// 连接请求 + /// + /// + /// + /// + /// + /// + bool Connect(string server, int port, int iTimeout, int retryNum); + + /// + /// 关闭连接 + /// + void Close(); + + /// + /// 关闭连接 + /// + void Shutdown(); + + /// + /// 发送数据 + /// + /// + bool Send(byte[] data, int offset, int len); + + /// + /// 发送快捷数据,不用保证丢包 + /// + /// + /// + /// + /// + bool SendUdpTypeData(byte[] data, int offset, int len); + + /// + /// 是否支持udp的包 + /// + /// + bool IsSupportUdpType(); + + /// + /// 收包处理 + /// + /// + /// + /// + /// + int Recv(byte[] buf, int iOffset, int maxSize); + + /// + /// 循环调用 + /// + void Update(); + + /// + /// 最后一帧,保证肯定要包发出去,减少延迟 + /// + void LateUpdate(); + + /// + /// 获取写队列的个数 + /// + /// + int GetSendQueueCount(); + + /// + /// 像底层注册错误打印,当缓冲区满之类的,调用上层的统计来打印 + /// + /// + void RegDebugCmdHandle(Action debugCmd); + } +} diff --git a/Assets/TEngine/Runtime/Net/ClientSocket/IClientSocket.cs.meta b/Assets/TEngine/Runtime/Net/ClientSocket/IClientSocket.cs.meta new file mode 100644 index 00000000..2f5aa52c --- /dev/null +++ b/Assets/TEngine/Runtime/Net/ClientSocket/IClientSocket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c37e3056155a5ee4c96dc8d42b1709e5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Net/ClientSocket/Message.cs b/Assets/TEngine/Runtime/Net/ClientSocket/Message.cs new file mode 100644 index 00000000..d24900b7 --- /dev/null +++ b/Assets/TEngine/Runtime/Net/ClientSocket/Message.cs @@ -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 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 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(); + } + } +} \ No newline at end of file diff --git a/Assets/TEngine/Runtime/Net/ClientSocket/Message.cs.meta b/Assets/TEngine/Runtime/Net/ClientSocket/Message.cs.meta new file mode 100644 index 00000000..0901859e --- /dev/null +++ b/Assets/TEngine/Runtime/Net/ClientSocket/Message.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e2a6d378c8d029a4886da7ea14125b90 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Net/ClientSocket/TcpConnection.cs b/Assets/TEngine/Runtime/Net/ClientSocket/TcpConnection.cs new file mode 100644 index 00000000..51e3ce32 --- /dev/null +++ b/Assets/TEngine/Runtime/Net/ClientSocket/TcpConnection.cs @@ -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; + } + } +} diff --git a/Assets/TEngine/Runtime/Net/ClientSocket/TcpConnection.cs.meta b/Assets/TEngine/Runtime/Net/ClientSocket/TcpConnection.cs.meta new file mode 100644 index 00000000..682e1f2c --- /dev/null +++ b/Assets/TEngine/Runtime/Net/ClientSocket/TcpConnection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 997699216368d574cbc53511506d77f8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Net/ClientSocket/UdpConnection.cs b/Assets/TEngine/Runtime/Net/ClientSocket/UdpConnection.cs new file mode 100644 index 00000000..9a92fee2 --- /dev/null +++ b/Assets/TEngine/Runtime/Net/ClientSocket/UdpConnection.cs @@ -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); + } + } + } +} diff --git a/Assets/TEngine/Runtime/Net/ClientSocket/UdpConnection.cs.meta b/Assets/TEngine/Runtime/Net/ClientSocket/UdpConnection.cs.meta new file mode 100644 index 00000000..d7001736 --- /dev/null +++ b/Assets/TEngine/Runtime/Net/ClientSocket/UdpConnection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c63997a8d0569346945dbb31cfb6ce7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Net/DataCenterSys.cs b/Assets/TEngine/Runtime/Net/DataCenterSys.cs new file mode 100644 index 00000000..43846aa2 --- /dev/null +++ b/Assets/TEngine/Runtime/Net/DataCenterSys.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TEngine.Net +{ + /// + /// 数据中心系统 + /// + public class DataCenterSys : BaseLogicSys + { + private List m_listModule = new List(); + + 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); + } + } + } +} diff --git a/Assets/TEngine/Runtime/Net/DataCenterSys.cs.meta b/Assets/TEngine/Runtime/Net/DataCenterSys.cs.meta new file mode 100644 index 00000000..a3266ae7 --- /dev/null +++ b/Assets/TEngine/Runtime/Net/DataCenterSys.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 637ccf86c9ad9c34a866fe2b8556e96d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Net/Demo.meta b/Assets/TEngine/Runtime/Net/Demo.meta new file mode 100644 index 00000000..6736a3c6 --- /dev/null +++ b/Assets/TEngine/Runtime/Net/Demo.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c5415c6c1796e4d46a895770f5ed37cc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Net/Demo/TEngineLoginUI.cs b/Assets/TEngine/Runtime/Net/Demo/TEngineLoginUI.cs new file mode 100644 index 00000000..5aef5f11 --- /dev/null +++ b/Assets/TEngine/Runtime/Net/Demo/TEngineLoginUI.cs @@ -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("m_imgbg"); + m_textTittle = FindChildComponent("m_textTittle"); + m_textVer = FindChildComponent("m_textVer"); + m_imgLogo = FindChildComponent("m_imgLogo"); + m_goLoading = FindChild("m_goLoading").gameObject; + m_goLoginRoot = FindChild("m_goLoginRoot").gameObject; + m_inputName = FindChildComponent("m_goLoginRoot/m_inputName"); + m_inputPassword = FindChildComponent("m_goLoginRoot/m_inputPassword"); + m_btnLogin = FindChildComponent