using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using Cysharp.Threading.Tasks; public enum NetworkType { TCP, // 使用原有的 TCP Socket WebSocket // 使用 WebSocket(小游戏平台) } public class GameNetSystem : Singleton { //限制客户端的下一个包是登录包C0101_tagCPlayerLogin,如果不是登录包不允许发送 bool waitLogin = false; //等待发送登录包,如果有其他包直接屏蔽,避免断线重连的情况发了攻击包之类的 //等待服务端0403的包后才能发其他的功能包,只有C0123_tagCClientPackVersion 和 C0101_tagCPlayerLogin 可以发送 bool waitLoginMap = false; // 网络服务接口(统一支持 TCP 和 WebSocket) private INetworkService networkService; NetUpdateBehaviour m_NetUpdateBehaviour; NeverConnectState neverConnectState; AccountLoginState accountLoginState; // CreateOrSelectRoleState createOrSelectRoleState; RoleLoginState roleLoginState; ConnectedState connectedState; DisconnectState disconnectState; NetState m_NetState; public NetState netState { get { return this.m_NetState; } set { if (this.m_NetState != value) { switch (m_NetState) { case NetState.NerverConnect: neverConnectState.OnExit(); break; case NetState.AccountLogin: accountLoginState.OnExit(); break; // case NetState.CreateOrSelectRole: // // createOrSelectRoleState.OnExit(); // break; case NetState.RoleLogin: roleLoginState.OnExit(); break; case NetState.Connected: connectedState.OnExit(); break; case NetState.DisConnected: disconnectState.OnExit(); break; } this.m_NetState = value; switch (m_NetState) { case NetState.NerverConnect: neverConnectState.OnEnter(); break; case NetState.AccountLogin: accountLoginState.OnEnter(); break; // case NetState.CreateOrSelectRole: // // createOrSelectRoleState.OnEnter(); // break; case NetState.RoleLogin: roleLoginState.OnEnter(); break; case NetState.Connected: connectedState.OnEnter(); break; case NetState.DisConnected: disconnectState.OnEnter(); break; } } } } private ClientSocket mainSocket; // 保留兼容,但不再直接使用 public bool mainSocketConnected { get { return networkService?.IsConnected ?? false; } } public float timeSinceMainSocketLastProtocol { get { if (networkService == null) return Time.time; var lastTime = networkService.LastPackageTime; if (lastTime == DateTime.MinValue) return Time.time; // 从未收包 return (float)(DateTime.Now - lastTime).TotalSeconds; } } Queue mainProtocolQueue = new Queue(); public GameNetSystem() { var gameObject = new GameObject("NetUpdateBehaviour"); GameObject.DontDestroyOnLoad(gameObject); m_NetUpdateBehaviour = gameObject.AddComponent(); m_NetUpdateBehaviour.RegisterUpdateCallBack(OnUpdate); neverConnectState = gameObject.AddComponent(); accountLoginState = gameObject.AddComponent(); // createOrSelectRoleState = gameObject.AddComponent(); roleLoginState = gameObject.AddComponent(); connectedState = gameObject.AddComponent(); disconnectState = gameObject.AddComponent(); netState = NetState.NerverConnect; } public void BeginConnectGameServer(string ip, int port, Action onConnected) { try { if (networkService != null && networkService.IsConnected) { networkService.Disconnect(); } } catch (System.Exception ex) { Debug.Log(ex); } mainProtocolQueue.Clear(); // 根据 Main.CurrentNetworkType 选择网络类型 Debug.Log($"[GameNetSystem] 连接服务器 {ip}:{port},使用{(Main.CurrentNetworkType == NetworkType.WebSocket ? "WebSocket" : "TCP")}"); if (Main.CurrentNetworkType == NetworkType.WebSocket) { // 使用 WebSocket ConnectWithWebSocket(ip, port, onConnected); } else { // 使用 TCP Socket(通过适配器) ConnectWithTCP(ip, port, onConnected); } } private async void ConnectWithTCP(string ip, int port, Action onConnected) { try { // 创建 TCP Socket 适配器(不修改 ClientSocket) networkService = new ClientSocketAdapter(ServerType.Main); // 订阅状态事件 networkService.OnStateChanged += OnNetworkStateChanged; // 连接 string url = $"{ip}:{port}"; Debug.Log($"[GameNetSystem] TCP 开始连接: {url}"); bool success = await networkService.ConnectAsync(url); Debug.Log($"[GameNetSystem] TCP 连接{(success ? "成功" : "失败")}: {url}"); // 兼容:保留 mainSocket 引用(但通过 networkService 访问) mainSocket = (networkService as ClientSocketAdapter)?.GetClientSocket(); if (onConnected != null) { onConnected(success); } } catch (System.Exception ex) { Debug.LogError($"[GameNetSystem] TCP 连接异常: {ex.Message}"); if (onConnected != null) { onConnected(false); } } } private async void ConnectWithWebSocket(string ip, int port, Action onConnected) { try { // 创建 WebSocket 服务(传入 ServerType,与 ClientSocket 一致) networkService = new WebSocketNetworkService(ServerType.Main); // 订阅状态事件 networkService.OnStateChanged += OnNetworkStateChanged; string url = $"ws://{ip}:{port}"; Debug.Log($"[GameNetSystem] WebSocket 开始连接: {url}"); bool success = await networkService.ConnectAsync(url); Debug.Log($"[GameNetSystem] WebSocket 连接{(success ? "成功" : "失败")}: {url}"); if (onConnected != null) { onConnected(success); } } catch (System.Exception ex) { Debug.LogError($"[GameNetSystem] WebSocket 连接异常: {ex.Message}"); if (onConnected != null) { onConnected(false); } } } private void OnNetworkStateChanged(NetworkState state) { Debug.Log($"[GameNetSystem] 网络状态变化: {state}"); // 断开连接时触发断线处理 if (state == NetworkState.Disconnected || state == NetworkState.Closed) { netState = NetState.DisConnected; } } //限制客户端的下一个包是登录包C0101_tagCPlayerLogin,如果不是登录包不允许发送 public void SetIsWaitLogin(bool _wait) { waitLogin = _wait; } //等待服务端0403的包后才能发其他的功能包,只有C0123_tagCClientPackVersion 和 C0101_tagCPlayerLogin 可以发送 public void SetIsWaitLoginMap(bool _wait) { waitLoginMap = _wait; } public bool GetIsWaitLoginMap() { return waitLoginMap; } //0403登录之前的包缓存 Queue sendQueue = new Queue(); public void SendCachePackage() { int cnt = sendQueue.Count; while (sendQueue.Count > 0) { SendInfo(sendQueue.Dequeue()); } Debug.Log($"重点提醒:0403登录后 发送缓存包数量 {cnt} 个"); } public void SendInfo(GameNetPackBasic protocol) { Debug.LogError("protocol to send: " + protocol.ToString()); if (waitLogin) { if (protocol is not C0101_tagCPlayerLogin) { Debug.LogWarning("等待执行登录,不允许发送其他包 " + protocol.ToString()); return; } } // 0102是从地图发送的 说明已登录,但可能卡顿导致通知route状态慢于客户端,依然需要防范 if (waitLoginMap) { if (protocol is not C0123_tagCClientPackVersion && protocol is not C0101_tagCPlayerLogin) { Debug.LogError("重点提醒:登录完成前的封包先加入队列 等0403回包后再一起发送服务端 " + protocol.ToString()); sendQueue.Enqueue(protocol); return; } } if (networkService != null) { networkService.SendInfo(protocol); DebugPkgCache.Push(protocol); } } public void SendInfo(byte[] vBytes) { if (networkService != null) { networkService.SendInfo(vBytes); } } public void PushPackage(GameNetPackBasic protocol, ServerType type) { lock (this) { if (protocol == null) { return; } if (PackageRegedit.Contain(protocol.cmd)) { mainProtocolQueue.Enqueue(protocol); DebugPkgCache.Push(protocol); } else { Debug.LogErrorFormat("数据包(cmd:{0})未登记!", protocol.cmd); } } } public void Disconnect() { try { if (networkService != null) { networkService.Disconnect(); } mainProtocolQueue.Clear(); } catch (Exception ex) { Debug.Log(ex); } finally { netState = NetState.DisConnected; LoginManager.Instance.busy = false; } } public void Reconnect() { try { if (networkService != null) { networkService.Disconnect(); } mainProtocolQueue.Clear(); } catch (Exception ex) { Debug.Log(ex); } finally { netState = NetState.AccountLogin; LoginManager.Instance.busy = false; LoginManager.Instance.ReAccountLogin(); } } public void LoginOut() { try { SDKUtils.Instance.RoleLoginOut(); if (networkService != null) { networkService.Disconnect(); } mainProtocolQueue.Clear(); } catch (Exception ex) { Debug.Log(ex); } finally { netState = NetState.NerverConnect; LoginManager.Instance.busy = false; StageManager.Instance.ReturnToLoginScene(); NetLinkWin.Hide(); } } public void OnAccountLogin() { netState = NetState.AccountLogin; } public void OnEnterWorld() { netState = NetState.RoleLogin; } void OnUpdate() { if (networkService != null) { if (networkService is WebSocketNetworkService wsService) { wsService.Update(); } } lock (this) { while (mainProtocolQueue.Count > 0) { var package = mainProtocolQueue.Dequeue(); if (package != null) { PackageRegedit.Distribute(package); } } } } public enum NetState { NerverConnect = 1, AccountLogin = 2, // CreateOrSelectRole = 3, RoleLogin = 4, Connected = 5, DisConnected = 6, } } public enum ServerType { Main = 1, B430 = 2, MainFight = 3, }