| | |
| | | Debug.Log(ex); |
| | | } |
| | | |
| | | Debug.unityLogger.logEnabled = true; |
| | | |
| | | mainSocket = new ClientSocket(ServerType.Main); |
| | | // websocket的断开链接需要处理一下 |
| | | mainSocket.OnDisconnected = () => |
| | |
| | | |
| | | public void Connect(string _ip, int _port, Action<bool> _onConnected) |
| | | { |
| | | Debug.unityLogger.logEnabled = true; |
| | | try |
| | | { |
| | | ip = _ip; |
| | | port = _port; |
| | | onConnected = _onConnected; |
| | | Debug.Log($"[ClientSocket][Connect] 尝试连接: ip={_ip}, port={_port}"); |
| | | //目前测试到异步两个问题 |
| | | // 1. BeginGetHostAddresses 不明情况下会很久才回调,导致触发超时 |
| | | // 2. 超时的情况下多次尝试登录后,会触发多次OnGetHostAddresses,导致登录异常 |
| | |
| | | ipAddress = ipAddresses[0]; |
| | | #endif |
| | | |
| | | |
| | | Debug.Log($"[ClientSocket][Connect] 解析到ipAddress={ipAddress}, family={ipAddress.AddressFamily}"); |
| | | if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6) |
| | | { |
| | | Debug.Log("当前使用的网络: IPV6"); |
| | | Debug.Log("[ClientSocket][Connect] 当前使用的网络: IPV6"); |
| | | m_Socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); |
| | | } |
| | | else |
| | | { |
| | | Debug.Log("当前使用的网络: IPV4"); |
| | | Debug.Log("[ClientSocket][Connect] 当前使用的网络: IPV4"); |
| | | m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); |
| | | } |
| | | |
| | | var ipEndPoint = new IPEndPoint(ipAddress, port); |
| | | if (ipEndPoint == null) |
| | | { |
| | | Debug.Log("IpEndPoint is null"); |
| | | Debug.LogError("[ClientSocket][Connect] IpEndPoint is null"); |
| | | } |
| | | |
| | | m_Socket.BeginConnect(ipEndPoint, new AsyncCallback(ConnectCallBack), null); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | Debug.LogError(e.Message); |
| | | Debug.LogError($"[ClientSocket][Connect] 异常: {e.Message}"); |
| | | } |
| | | |
| | | |
| | |
| | | /// <param name="_result"></param> |
| | | private void ConnectCallBack(IAsyncResult _result) |
| | | { |
| | | Debug.unityLogger.logEnabled = true; |
| | | if (!_result.IsCompleted) |
| | | { |
| | | Debug.Log("链接超时!"); |
| | | Debug.LogError("[ClientSocket][ConnectCallBack] 链接超时!"); |
| | | CloseConnect(); |
| | | if (onConnected != null) |
| | | { |
| | | Debug.LogError("[ClientSocket][ConnectCallBack] onConnected(false) 超时"); |
| | | onConnected(false); |
| | | onConnected = null; |
| | | } |
| | |
| | | { |
| | | if (m_Socket != null && m_Socket.Connected) |
| | | { |
| | | Debug.Log("确认的链接实现"); |
| | | Debug.Log("[ClientSocket][ConnectCallBack] 确认的链接实现"); |
| | | OnConnectSuccess(); |
| | | } |
| | | else |
| | | { |
| | | Debug.LogError("[ClientSocket][ConnectCallBack] m_Socket为null或未连接"); |
| | | if (m_Socket != null) |
| | | { |
| | | m_Socket.Disconnect(true); |
| | |
| | | } |
| | | catch (System.Exception ex) |
| | | { |
| | | Debug.Log(ex); |
| | | Debug.LogError($"[ClientSocket][ConnectCallBack] 异常: {ex}"); |
| | | } |
| | | finally |
| | | { |
| | | if (onConnected != null) |
| | | { |
| | | Debug.Log($"[ClientSocket][ConnectCallBack] onConnected({{0}})", m_Socket != null && m_Socket.Connected); |
| | | onConnected(m_Socket != null && m_Socket.Connected); |
| | | onConnected = null; |
| | | } |
| | |
| | | public void CloseConnect() |
| | | { |
| | | Debug.Log("==== CloseConnect"); |
| | | Debug.unityLogger.logEnabled = true; |
| | | Debug.Log("[ClientSocket][CloseConnect] ==== CloseConnect"); |
| | | try |
| | | { |
| | | isStopTreading = true; |
| | |
| | | { |
| | | if (m_packageThread != null) |
| | | { |
| | | m_packageThread.Abort(); |
| | | m_packageThread = null; |
| | | } |
| | | |
| | | m_LastPackageTime = DateTime.Now; |
| | | m_packageThread = new Thread(new ThreadStart(ReceiveInfo)); // 启动线程接收信息 |
| | | m_packageThread.IsBackground = true; |
| | | m_packageThread.Start(); |
| | | isStopTreading = false; |
| | | Debug.unityLogger.logEnabled = true; |
| | | Debug.Log("[ClientSocket][OnConnectSuccess] 连接成功,启动接收线程"); |
| | | if (m_packageThread != null) |
| | | { |
| | | Debug.LogWarning("[ClientSocket][OnConnectSuccess] m_packageThread已存在,先Abort"); |
| | | m_packageThread.Abort(); |
| | | m_packageThread = null; |
| | | } |
| | |
| | | Debug.Log(e); |
| | | } |
| | | } |
| | | Debug.unityLogger.logEnabled = true; |
| | | Debug.Log("[ClientSocket][ReceiveInfo] 接收线程启动"); |
| | | while (!isStopTreading) |
| | | { |
| | | try |
| | | { |
| | | var shutdown = false; |
| | | if (!m_Socket.Connected) |
| | | { |
| | | Debug.LogWarning("[ClientSocket][ReceiveInfo] m_Socket 已断开"); |
| | | shutdown = true; |
| | | } |
| | | |
| | | if (!shutdown) |
| | | { |
| | | var dataLength = m_Socket.Receive(bufferBytes); |
| | | Debug.Log($"[ClientSocket][ReceiveInfo] 收到数据长度: {dataLength}"); |
| | | if (dataLength <= 0) |
| | | { |
| | | Debug.LogWarning("[ClientSocket][ReceiveInfo] dataLength <= 0,准备断开"); |
| | | shutdown = true; |
| | | } |
| | | else |
| | | { |
| | | getBytesTotal += dataLength; |
| | | var bytes = new byte[dataLength]; |
| | | Array.Copy(bufferBytes, 0, bytes, 0, dataLength); |
| | | ReadInfo(bytes); |
| | | } |
| | | } |
| | | |
| | | if (shutdown) |
| | | { |
| | | Debug.LogWarning("[ClientSocket][ReceiveInfo] shutdown=true,关闭Socket"); |
| | | isStopTreading = true; |
| | | m_Socket.Shutdown(SocketShutdown.Both); |
| | | m_Socket.Close(); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | Debug.LogError($"[ClientSocket][ReceiveInfo] 异常: {e}"); |
| | | } |
| | | } |
| | | Debug.Log("[ClientSocket][ReceiveInfo] 接收线程退出"); |
| | | |
| | | } |
| | | |
| | |
| | | if (fragmentBytes != null && fragmentBytes.Length > 0) |
| | | { |
| | | Array.Resize(ref fixBytes, vBytes.Length + fragmentBytes.Length); |
| | | Debug.Log($"[ClientSocket][ReadInfo] 存在fragmentBytes, 长度: {fragmentBytes.Length}"); |
| | | Array.Copy(fragmentBytes, 0, fixBytes, 0, fragmentBytes.Length); |
| | | Array.Copy(vBytes, 0, fixBytes, fragmentBytes.Length, vBytes.Length); |
| | | } |
| | |
| | | |
| | | public async void Connect(string _ip, int _port, Action<bool> _onConnected) |
| | | { |
| | | Debug.unityLogger.logEnabled = true; |
| | | ip = _ip; |
| | | port = _port; |
| | | onConnected = _onConnected; |
| | |
| | | |
| | | public async void CloseConnect() |
| | | { |
| | | Debug.Log("[ClientSocket-WebSocket] ==== CloseConnect"); |
| | | Debug.Log("[ClientSocket-WebSocket] ==== CloseConnect\n" + System.Environment.StackTrace); |
| | | fragmentBytes = null; |
| | | |
| | | if (webSocket != null) |
| New file |
| | |
| | | #if UNITY_ANDROID |
| | | using UnityEngine; |
| | | using LitJson; |
| | | using System; |
| | | |
| | | /// <summary> |
| | | /// Android平台SDK实现,继承SDKBaseImpl。 |
| | | /// 通过AndroidJavaClass与原生SDK交互。 |
| | | /// </summary> |
| | | public class SDKAndroidImpl : SDKBaseImpl |
| | | { |
| | | public SDKAndroidImpl(SDKUtils utils) : base(utils) { } |
| | | |
| | | // ------------------------------------------------------- |
| | | // 底层消息发送 —— 通过AndroidJavaClass调用原生SDK |
| | | // ------------------------------------------------------- |
| | | public override void SendToNative(string jsonStr) |
| | | { |
| | | if (VersionConfig.Get().appId == "sghy") |
| | | { |
| | | using (var sdk = new AndroidJavaClass("com.xssg.sdk.UnityMsgHandler")) |
| | | sdk.CallStatic("onUnityMessage", jsonStr); |
| | | } |
| | | else |
| | | { |
| | | using (var sdk = new AndroidJavaClass("com.wgyx.sdk.UnityMsgHandler")) |
| | | sdk.CallStatic("onUnityMessage", jsonStr); |
| | | } |
| | | } |
| | | |
| | | // ------------------------------------------------------- |
| | | // 初始化 —— 检查内置资源拷贝状态 + 同步包ID |
| | | // ------------------------------------------------------- |
| | | public override void InitPlatform() |
| | | { |
| | | var savedVer = LocalSave.GetString("BuiltInAssetCopyCompleted_Android"); |
| | | SDKUtils.builtinAssetCopyFinished = !string.IsNullOrEmpty(savedVer) |
| | | && VersionConfig.Get().version == savedVer; |
| | | SyncClientPackageID(); |
| | | } |
| | | |
| | | // ------------------------------------------------------- |
| | | // SDK登录 —— 走正常原生SDK流程 |
| | | // ------------------------------------------------------- |
| | | public override void FreePlatformLogin() |
| | | { |
| | | utils.SendSdkMessage(SDKUtils.CodeU2A.FreePlatformLogin); |
| | | } |
| | | |
| | | // ------------------------------------------------------- |
| | | // 设备信息 —— Android特有:mac/imei/totalMemory |
| | | // ------------------------------------------------------- |
| | | public override void FillDeviceInfo(JsonData json) |
| | | { |
| | | utils.Device.macAddress = json["mac"].ToString(); |
| | | utils.Device.imei = json["imei"] != null ? json["imei"].ToString() : utils.Device.uniqueID; |
| | | utils.Device.totalMemory = (int)json["memoryTotal"]; |
| | | } |
| | | |
| | | // ------------------------------------------------------- |
| | | // 退出游戏 |
| | | // ------------------------------------------------------- |
| | | public override void ExitGame() |
| | | { |
| | | Application.Quit(); |
| | | } |
| | | |
| | | // ------------------------------------------------------- |
| | | // Android专属:权限 & 包ID |
| | | // ------------------------------------------------------- |
| | | |
| | | public override void SyncClientPackageID() |
| | | { |
| | | utils.SendSdkMessage(SDKUtils.CodeU2A.ClientPackage, |
| | | json => json["clientPkgID"] = VersionConfig.Get().clientPackageFlag); |
| | | } |
| | | |
| | | public override void RequestPermission(string permission, Action<string, int> callBack) |
| | | { |
| | | utils.RegisterPermissionCallback(callBack); |
| | | utils.SendSdkMessage(SDKUtils.CodeU2A.RequestPermission, |
| | | json => json["permission"] = permission); |
| | | } |
| | | |
| | | public override void RequestPermissionStart() |
| | | { |
| | | utils.SendSdkMessage(SDKUtils.CodeU2A.RequestPermissionStart); |
| | | } |
| | | |
| | | // ------------------------------------------------------- |
| | | // 静态工具 —— 获取Android应用上下文 |
| | | // ------------------------------------------------------- |
| | | public static AndroidJavaObject GetApplicationContext() |
| | | { |
| | | using (var jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) |
| | | using (var jo = jc.GetStatic<AndroidJavaObject>("currentActivity")) |
| | | return jo.Call<AndroidJavaObject>("getApplicationContext"); |
| | | } |
| | | } |
| | | #endif |
| New file |
| | |
| | | fileFormatVersion: 2 |
| | | guid: fad8ebe1b08b656489826bafdefb356f |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
| | | defaultReferences: [] |
| | | executionOrder: 0 |
| | | icon: {instanceID: 0} |
| | | userData: |
| | | assetBundleName: |
| | | assetBundleVariant: |
| New file |
| | |
| | | using UnityEngine; |
| | | using LitJson; |
| | | using System; |
| | | |
| | | /// <summary> |
| | | /// SDK平台实现的抽象基类。 |
| | | /// 每个目标平台(Android、WebGL等)继承此类并实现各自的逻辑。 |
| | | /// SDKUtils持有一个SDKBaseImpl实例,所有平台差异均通过此基类委托。 |
| | | /// </summary> |
| | | public abstract class SDKBaseImpl |
| | | { |
| | | protected readonly SDKUtils utils; |
| | | |
| | | protected SDKBaseImpl(SDKUtils utils) |
| | | { |
| | | this.utils = utils; |
| | | } |
| | | |
| | | // ------------------------------------------------------- |
| | | // 必须由子类实现的平台核心方法 |
| | | // ------------------------------------------------------- |
| | | |
| | | /// <summary>向平台原生SDK发送JSON消息</summary> |
| | | public abstract void SendToNative(string jsonStr); |
| | | |
| | | /// <summary>平台初始化(检查内置资源拷贝状态、平台特有设置等)</summary> |
| | | public abstract void InitPlatform(); |
| | | |
| | | /// <summary>触发SDK账号登录流程</summary> |
| | | public abstract void FreePlatformLogin(); |
| | | |
| | | /// <summary>填充平台特有的设备信息字段(如Android的mac/imei等)</summary> |
| | | public abstract void FillDeviceInfo(JsonData json); |
| | | |
| | | /// <summary>退出游戏(各平台行为不同)</summary> |
| | | public abstract void ExitGame(); |
| | | |
| | | // ------------------------------------------------------- |
| | | // 可选重写(默认空实现,仅Android等平台需要) |
| | | // ------------------------------------------------------- |
| | | |
| | | /// <summary>同步客户端包ID到原生SDK</summary> |
| | | public virtual void SyncClientPackageID() { } |
| | | |
| | | /// <summary>动态申请单个权限</summary> |
| | | public virtual void RequestPermission(string permission, Action<string, int> callBack) { } |
| | | |
| | | /// <summary>启动时批量申请权限(由SDK决定策略)</summary> |
| | | public virtual void RequestPermissionStart() { } |
| | | } |
| New file |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 75293dc3923823b408a427acffc9d6a8 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
| | | defaultReferences: [] |
| | | executionOrder: 0 |
| | | icon: {instanceID: 0} |
| | | userData: |
| | | assetBundleName: |
| | | assetBundleVariant: |
| | |
| | | /// sdk初始化是否完成标识 |
| | | /// 客户端一般需要等待这个值为true才继续逻辑 |
| | | /// </summary> |
| | | public bool InitFinished { get; private set; } |
| | | public bool InitFinished { get; set; } |
| | | |
| | | #region 基础定义与回调 |
| | | |
| | |
| | | /// </summary> |
| | | public UnityAction<NetworkReachability> OnNetworkStatusChanged; |
| | | |
| | | public static bool builtinAssetCopyFinished { get; private set; } |
| | | public static bool builtinAssetCopyFinished { get; internal set; } |
| | | |
| | | /// <summary> |
| | | /// 是否已经将StreamingAsset拷贝至目标路径 |
| | |
| | | #endregion |
| | | |
| | | #region 自由sdk |
| | | public FP_LoginOk FreePlatformInfo { get; private set; } |
| | | public FP_LoginOk FreePlatformInfo { get; set; } |
| | | #endregion |
| | | |
| | | private JsonData m_Json = new JsonData(); |
| | | |
| | | // 当前平台SDK实现 |
| | | private SDKBaseImpl m_impl; |
| | | |
| | | private SDKBaseImpl CreateImpl() |
| | | { |
| | | #if UNITY_ANDROID |
| | | return new SDKAndroidImpl(this); |
| | | #elif UNITY_WEBGL |
| | | return new SDKWebGLImpl(this); |
| | | #else |
| | | return null; // Editor/Standalone: SendMessageToSDK在Editor下直接跳过 |
| | | #endif |
| | | } |
| | | |
| | | public void Init() |
| | | { |
| | |
| | | NetworkType = NetworkReachability.NotReachable; |
| | | BatteryLevel = 100; |
| | | |
| | | m_impl = CreateImpl(); |
| | | |
| | | #if !UNITY_EDITOR |
| | | if (InitFinished) |
| | | { |
| | | return; |
| | | } |
| | | #if UNITY_ANDROID |
| | | var builtinAssetsCopyFinishVersion = LocalSave.GetString("BuiltInAssetCopyCompleted_Android"); |
| | | if (string.IsNullOrEmpty(builtinAssetsCopyFinishVersion)) |
| | | { |
| | | builtinAssetCopyFinished = false; |
| | | } |
| | | else |
| | | { |
| | | builtinAssetCopyFinished = VersionConfig.Get().version == builtinAssetsCopyFinishVersion; |
| | | } |
| | | #endif |
| | | m_impl?.InitPlatform(); |
| | | #if UNITY_IOS || UNITY_STANDALONE |
| | | var builtinAssetsCopyFinishVersion = LocalSave.GetString("BuiltInAssetCopyCompleted_IOSorStandalone"); |
| | | if (string.IsNullOrEmpty(builtinAssetsCopyFinishVersion)) |
| | |
| | | AssetCopyFinished = VersionConfig.Get().version == assetsCopyFinishVersion; |
| | | } |
| | | |
| | | #elif UNITY_ANDROID |
| | | SyncClientPackageID(); |
| | | #endif |
| | | |
| | | InitFinished = false; |
| | |
| | | SendMessageToSDK(m_Json); |
| | | } |
| | | |
| | | public void SyncClientPackageID() |
| | | { |
| | | #if UNITY_ANDROID |
| | | m_Json.Clear(); |
| | | m_Json["code"] = CodeU2A.ClientPackage; |
| | | m_Json["clientPkgID"] = VersionConfig.Get().clientPackageFlag; |
| | | SendMessageToSDK(m_Json); |
| | | #endif |
| | | } |
| | | |
| | | //申请Android 权限 |
| | | public void RequestAndroidPermission(string permission, Action<string, int> callBack) |
| | | { |
| | | onPermissionCallBack += callBack; |
| | | m_Json.Clear(); |
| | | m_Json["code"] = CodeU2A.RequestPermission; |
| | | m_Json["permission"] = permission; |
| | | SendMessageToSDK(m_Json); |
| | | } |
| | | |
| | | //申请Android 权限 启动时 |
| | | public void RequestAndroidPermissionStart() |
| | | { |
| | | m_Json.Clear(); |
| | | m_Json["code"] = CodeU2A.RequestPermissionStart; |
| | | SendMessageToSDK(m_Json); |
| | | } |
| | | |
| | | |
| | | public void RequestSecretRule() |
| | | { |
| | | m_Json.Clear(); |
| | | m_Json["code"] = CodeU2A.RequestSecretRule; |
| | | SendMessageToSDK(m_Json); |
| | | } |
| | | |
| | | /// <summary>同步客户端包ID(委托给平台实现)</summary> |
| | | public void SyncClientPackageID() => m_impl?.SyncClientPackageID(); |
| | | |
| | | /// <summary>动态申请Android权限(非Android平台为空操作)</summary> |
| | | public void RequestAndroidPermission(string permission, Action<string, int> callBack) |
| | | => m_impl?.RequestPermission(permission, callBack); |
| | | |
| | | /// <summary>启动时批量申请权限(非Android平台为空操作)</summary> |
| | | public void RequestAndroidPermissionStart() => m_impl?.RequestPermissionStart(); |
| | | |
| | | |
| | | |
| | |
| | | |
| | | #region 处理与SDK交互的底层方法 |
| | | |
| | | public static AndroidJavaObject GetApplicationContext() |
| | | { |
| | | using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) |
| | | { |
| | | using (AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity")) |
| | | { |
| | | return jo.Call<AndroidJavaObject>("getApplicationContext"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public string GetSplicePackageID() |
| | | { |
| | | var _result = "default"; |
| | |
| | | private void SendMessageToSDK(JsonData json) |
| | | { |
| | | #if !UNITY_EDITOR |
| | | #if UNITY_ANDROID |
| | | if (VersionConfig.Get().appId == "sghy") |
| | | { |
| | | using (AndroidJavaClass H2engineSDK = new AndroidJavaClass("com.xssg.sdk.UnityMsgHandler")) |
| | | { |
| | | H2engineSDK.CallStatic("onUnityMessage", json.ToJson()); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | using (AndroidJavaClass H2engineSDK = new AndroidJavaClass("com.wgyx.sdk.UnityMsgHandler")) |
| | | { |
| | | H2engineSDK.CallStatic("onUnityMessage", json.ToJson()); |
| | | } |
| | | } |
| | | #elif UNITY_IOS |
| | | AotSdkUtility.IOSUniyMessageHandle(json.ToJson()); |
| | | #elif UNITY_STANDALONE || UNITY_WEBGL |
| | | InitFinished=true; |
| | | var _jsonStr = json.ToJson(); |
| | | #if UNITY_IOS |
| | | AotSdkUtility.IOSUniyMessageHandle(_jsonStr); |
| | | #else |
| | | m_impl?.SendToNative(_jsonStr); |
| | | #endif |
| | | |
| | | #endif |
| | | } |
| | | |
| | | /// <summary>供平台实现类调用的便捷发包方法(带可选JSON填充)</summary> |
| | | internal void SendSdkMessage(int code, Action<JsonData> fillJson = null) |
| | | { |
| | | m_Json.Clear(); |
| | | m_Json["code"] = code; |
| | | fillJson?.Invoke(m_Json); |
| | | SendMessageToSDK(m_Json); |
| | | } |
| | | |
| | | /// <summary>供平台实现类注册权限回调</summary> |
| | | internal void RegisterPermissionCallback(Action<string, int> callBack) |
| | | { |
| | | onPermissionCallBack += callBack; |
| | | } |
| | | |
| | | public void HandleMsgWithSDK(string jsonString) |
| | |
| | | //Device.uniqueID = _json["unique_id"].ToString(); |
| | | Device.androidID = _json["android_id"].ToString();// ios平台下为idfa |
| | | Device.userAgent = _json["userAgent"].ToString(); |
| | | #if UNITY_ANDROID |
| | | Device.macAddress = _json["mac"].ToString(); |
| | | if (_json["imei"] != null) |
| | | { |
| | | Device.imei = _json["imei"].ToString(); |
| | | } |
| | | else |
| | | { |
| | | Device.imei = Device.uniqueID; |
| | | } |
| | | Device.totalMemory = (int)_json["memoryTotal"]; |
| | | #endif |
| | | m_impl?.FillDeviceInfo(_json); |
| | | if (OnDeviceInfoChanged != null) |
| | | { |
| | | OnDeviceInfoChanged(Device); |
| | |
| | | // else |
| | | { |
| | | //默认都是退出游戏 |
| | | #if UNITY_WEBGL |
| | | Application.OpenURL("about:blank"); |
| | | #else |
| | | Application.Quit(); |
| | | #endif |
| | | m_impl?.ExitGame(); |
| | | } |
| | | break; |
| | | case CodeA2U.GetAdAward: |
| | |
| | | #endregion |
| | | } |
| | | |
| | | private static class CodeU2A |
| | | public static class CodeU2A |
| | | { |
| | | /** |
| | | * 执行资源拷贝 |
| | |
| | | /// </summary> |
| | | public void FreePlatformLogin() |
| | | { |
| | | m_Json.Clear(); |
| | | m_Json["code"] = CodeU2A.FreePlatformLogin; |
| | | SendMessageToSDK(m_Json); |
| | | m_impl?.FreePlatformLogin(); |
| | | } |
| | | |
| | | |
| New file |
| | |
| | | #if UNITY_WEBGL |
| | | using UnityEngine; |
| | | using LitJson; |
| | | using System; |
| | | |
| | | /// <summary> |
| | | /// WebGL平台SDK实现,继承SDKBaseImpl。 |
| | | /// WebGL无原生SDK层,登录直接模拟回调,退出跳转空白页。 |
| | | /// </summary> |
| | | public class SDKWebGLImpl : SDKBaseImpl |
| | | { |
| | | public SDKWebGLImpl(SDKUtils utils) : base(utils) { } |
| | | |
| | | // ------------------------------------------------------- |
| | | // 消息发送 —— WebGL无原生SDK,标记初始化完成即可 |
| | | // ------------------------------------------------------- |
| | | public override void SendToNative(string jsonStr) |
| | | { |
| | | // WebGL无原生SDK Bridge,收到第一次SendToNative(Init消息)后标记完成 |
| | | utils.InitFinished = true; |
| | | } |
| | | |
| | | // ------------------------------------------------------- |
| | | // 初始化 —— WebGL无内置资源拷贝流程 |
| | | // ------------------------------------------------------- |
| | | public override void InitPlatform() |
| | | { |
| | | // WebGL不需要内置资源拷贝状态检查 |
| | | } |
| | | |
| | | // ------------------------------------------------------- |
| | | // SDK登录 —— WebGL直接模拟登录成功回调 |
| | | // ------------------------------------------------------- |
| | | public override void FreePlatformLogin() |
| | | { |
| | | Debug.Log("[SDKWebGLImpl] FreePlatformLogin: WebGL模拟登录"); |
| | | |
| | | var info = new SDKUtils.FP_LoginOk |
| | | { |
| | | account = "webgl_user", |
| | | token = "111", // 内测服免密约定,与 InterTest Password 一致 |
| | | qkUserName = "webgl_user", |
| | | tokenExpire = "9999999999", |
| | | accountID = 0, |
| | | phone = 0, |
| | | }; |
| | | |
| | | utils.FreePlatformInfo = info; |
| | | utils.onFreePlatformLoginOk?.Invoke(info); |
| | | } |
| | | |
| | | // ------------------------------------------------------- |
| | | // 设备信息 —— WebGL无特有设备字段 |
| | | // ------------------------------------------------------- |
| | | public override void FillDeviceInfo(JsonData json) |
| | | { |
| | | // WebGL下无mac/imei等字段,不做额外填充 |
| | | } |
| | | |
| | | // ------------------------------------------------------- |
| | | // 退出游戏 —— WebGL跳转空白页 |
| | | // ------------------------------------------------------- |
| | | public override void ExitGame() |
| | | { |
| | | Application.OpenURL("about:blank"); |
| | | } |
| | | } |
| | | #endif |
| New file |
| | |
| | | fileFormatVersion: 2 |
| | | guid: e46364c334945194eae43e4524adeb08 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
| | | defaultReferences: [] |
| | | executionOrder: 0 |
| | | icon: {instanceID: 0} |
| | | userData: |
| | | assetBundleName: |
| | | assetBundleVariant: |
| | |
| | | } |
| | | #endif |
| | | |
| | | path = AssetVersionUtility.GetAssetFilePath($"Config/{name}.txt"); |
| | | |
| | | using var req = UnityEngine.Networking.UnityWebRequest.Get(path); |
| | | await req.SendWebRequest(); |
| | | |
| | | if (req.result != UnityEngine.Networking.UnityWebRequest.Result.Success) |
| | | throw new Exception($"LoadConfigIni failed: {req.error}"); |
| | | |
| | | return req.downloadHandler.text |
| | | .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); |
| | | return await ResManager.Instance.LoadConfigAsync(name + ".ini", false); |
| | | } |
| | | |
| | | public int GetCanBuyPackGirdCount(PackType type) |
| | | { |
| | | if (!PackMaxCountDict.ContainsKey((int)type)) |
| | |
| | | |
| | | public void AccountLogin(string _account, string _ip, int _port, int _gamePort) |
| | | { |
| | | Debug.LogFormat("账号登录, account:{0} ; ip:{1} ; port:{2} ; gamePort:{3}", _account, _ip, _port, _gamePort); |
| | | Debug.unityLogger.logEnabled = true; |
| | | Debug.LogFormat("[LoginManager][AccountLogin] 账号登录, account:{0} ; ip:{1} ; port:{2} ; gamePort:{3}", _account, _ip, _port, _gamePort); |
| | | isLogined = true; |
| | | if (Application.internetReachability == NetworkReachability.NotReachable) |
| | | { |
| | | Debug.LogError("[LoginManager][AccountLogin] 网络不可达,弹出提示并return"); |
| | | ConfirmCancel.ShowPopConfirm( |
| | | Language.Get("Mail101"), |
| | | Language.Get("L1116"), |
| | |
| | | |
| | | if (busy) |
| | | { |
| | | Debug.LogWarning("[LoginManager][AccountLogin] busy为true,直接return"); |
| | | return; |
| | | } |
| | | |
| | |
| | | portBuf = _port; |
| | | gamePortBuf = _gamePort; |
| | | |
| | | Debug.Log("[LoginManager][AccountLogin] 调用ConnectGameServer"); |
| | | ConnectGameServer(ipBuf, gamePortBuf); |
| | | |
| | | GameNetSystem.Instance.OnAccountLogin(); |
| | |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | Debug.Log(ex); |
| | | Debug.LogError($"[LoginManager][AccountLogin] 异常: {ex}"); |
| | | busy = false; |
| | | } |
| | | |
| | |
| | | |
| | | public void AccountLogin(string _ip, int _port, int _gamePort) |
| | | { |
| | | Debug.unityLogger.logEnabled = true; |
| | | Debug.LogError("[YLTEST] Account Login " + sdkLogined); |
| | | if (sdkLogined) |
| | | { |
| | | AccountLogin(sdkLoginResult.account, _ip, _port, _gamePort); |
| | |
| | | |
| | | private void OnAccountLogin(bool _ok, string _result) |
| | | { |
| | | Debug.unityLogger.logEnabled = true; |
| | | if (!_ok) |
| | | { |
| | | busy = false; |
| | | Debug.LogError(_result); |
| | | Debug.LogError($"[LoginManager][OnAccountLogin] 登录回调失败: {_result}"); |
| | | NetLinkWin.Hide(); |
| | | return; |
| | | } |
| | |
| | | if (string.IsNullOrEmpty(_result)) |
| | | { |
| | | busy = false; |
| | | Debug.LogError("[LoginManager][OnAccountLogin] 登录回调_result为空,弹出提示"); |
| | | ServerTipDetails.DisplayNormalTip(Language.Get("L1117")); |
| | | NetLinkWin.Hide(); |
| | | return; |
| | |
| | | { |
| | | if (stringSet.Length > 1) |
| | | { |
| | | Debug.LogError($"[LoginManager][OnAccountLogin] 登录回调_result非OK,提示: {stringSet[1]}"); |
| | | ServerTipDetails.DisplayNormalTip(stringSet[1]); |
| | | } |
| | | |
| | |
| | | localSaveAccountName = accountBuf; |
| | | try |
| | | { |
| | | Debug.Log("[LoginManager][OnAccountLogin] 登录回调OK,准备ConnectGameServer"); |
| | | ConnectGameServer(ipBuf, gamePortBuf); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | busy = false; |
| | | Debug.LogError($"[LoginManager][OnAccountLogin] ConnectGameServer异常: {ex}"); |
| | | Debug.Log(ex); |
| | | } |
| | | } |
| | |
| | | |
| | | void ConnectGameServer(string _ip, int _port) |
| | | { |
| | | Debug.unityLogger.logEnabled = true; |
| | | Debug.LogError("[YLTEST] Connect Server " + _ip + ":" + _port); |
| | | GameNetSystem.Instance.BeginConnectGameServer(_ip, _port, OnGameServerConnected); |
| | | } |
| | | |
| | | private void OnGameServerConnected(bool ok) |
| | | { |
| | | Debug.unityLogger.logEnabled = true; |
| | | Debug.LogError("[YLTEST] Connect Server result " + ok); |
| | | if (ok) |
| | | { |
| | | GameNetSystem.Instance.SetIsWaitLogin(false); |
| | |
| | | { |
| | | GameNetSystem.Instance.SetIsWaitLogin(false); |
| | | var send = new C0101_tagCPlayerLogin(); |
| | | switch (VersionConfig.config.versionAuthority) |
| | | var authority = VersionConfig.config.versionAuthority; |
| | | #if UNITY_WEBGL && !UNITY_EDITOR |
| | | // WebGL 平台没有真实 SDK,强制走 InterTest 分支(账号+密码)登录 |
| | | authority = VersionAuthority.InterTest; |
| | | #endif |
| | | switch (authority) |
| | | { |
| | | case VersionAuthority.InterTest: |
| | | send.IDType = 1; |
| | |
| | | var appId = VersionConfig.config.appId; |
| | | var branch = VersionConfig.config.branch; |
| | | m_ContainerAccount.SetActive(isGetServerList |
| | | && (VersionConfig.config.versionAuthority == VersionAuthority.InterTest || VersionConfig.config.isBanShu)); |
| | | && (VersionConfig.config.versionAuthority == VersionAuthority.InterTest || VersionConfig.config.isBanShu || Application.platform == RuntimePlatform.WebGLPlayer)); |
| | | }).Forget(); |
| | | |
| | | // m_UserHelp.SetActive(ContactConfig.GetConfig(appId, branch) != null); |
| | |
| | | m_WaitServerList.SetActive(!ServerListCenter.Instance.serverListGot); |
| | | m_ContainerEnterGame.SetActive(ServerListCenter.Instance.serverListGot); |
| | | m_ContainerAccount.SetActive(ServerListCenter.Instance.serverListGot |
| | | && (VersionConfig.config.versionAuthority == VersionAuthority.InterTest || VersionConfig.config.isBanShu)); |
| | | && (VersionConfig.config.versionAuthority == VersionAuthority.InterTest || VersionConfig.config.isBanShu || Application.platform == RuntimePlatform.WebGLPlayer)); |
| | | } |
| | | |
| | | protected virtual void EnterGame() |
| | | { |
| | | Debug.unityLogger.logEnabled = true; |
| | | Debug.Log("[LoginWin][EnterGame] 方法进入"); |
| | | if (!checkRead.isOn) |
| | | { |
| | | Debug.LogWarning("[LoginWin][EnterGame] 用户未勾选协议,弹出确认框"); |
| | | ConfirmCancel.ShowPopConfirm(Language.Get("agreementTitle"), Language.Get("agreementInfo")); |
| | | Debug.LogWarning("[LoginWin][EnterGame] return: 未勾选协议"); |
| | | return; |
| | | } |
| | | |
| | | |
| | | Debug.Log("[LoginWin][EnterGame] 用户已勾选协议,准备隐藏浮窗并调用Login()"); |
| | | SDKUtils.Instance.SendHideFloatWin(); |
| | | |
| | | Login(); |
| | |
| | | |
| | | protected void Login() |
| | | { |
| | | Debug.unityLogger.logEnabled = true; |
| | | Debug.Log("[LoginWin][Login] 方法进入"); |
| | | var allow = false; |
| | | if (DebugUtility.Instance.isWhiteListAccount) |
| | | { |
| | | allow = true; |
| | | Debug.Log("[LoginWin][Login] 白名单账号,允许登录"); |
| | | } |
| | | else |
| | | { |
| | |
| | | || ServerListCenter.Instance.currentServer.running_status == (int)ServerState.Predicted) |
| | | { |
| | | allow = false; |
| | | Debug.LogWarning($"[LoginWin][Login] 当前服务器状态为 {ServerListCenter.Instance.currentServer.running_status},不允许登录"); |
| | | } |
| | | else |
| | | { |
| | | allow = true; |
| | | Debug.Log("[LoginWin][Login] 服务器状态允许登录"); |
| | | } |
| | | } |
| | | |
| | |
| | | switch ((ServerState)ServerListCenter.Instance.currentServer.running_status) |
| | | { |
| | | case ServerState.Maintain: |
| | | Debug.LogWarning("[LoginWin][Login] 服务器维护中,弹出维护提示"); |
| | | SysNotifyMgr.Instance.ShowTip("ServerDown"); |
| | | break; |
| | | case ServerState.Predicted: |
| | | Debug.LogWarning($"[LoginWin][Login] 服务器未开服,开服时间: {ServerListCenter.Instance.currentServer.start_date:yyyy-MM-dd HH:mm}"); |
| | | SysNotifyMgr.Instance.ShowTip("ServerOpen", ServerListCenter.Instance.currentServer.start_date.ToString("yyyy-MM-dd HH:mm")); |
| | | break; |
| | | } |
| | | |
| | | Debug.LogWarning("[LoginWin][Login] return: 服务器状态不允许登录"); |
| | | return; |
| | | } |
| | | |
| | |
| | | case VersionAuthority.InterTest: |
| | | if (string.IsNullOrEmpty(m_Account.text)) |
| | | { |
| | | Debug.LogWarning("[LoginWin][Login] 测试服账号为空,弹出提示"); |
| | | ServerTipDetails.DisplayNormalTip(Language.Get("L1095")); |
| | | Debug.LogWarning("[LoginWin][Login] return: 测试服账号为空"); |
| | | return; |
| | | } |
| | | |
| | | Debug.Log($"[LoginWin][Login] 测试服账号登录: {m_Account.text}, IP: {m_ServerIP}, Port: {m_Port}, GamePort: {m_GamePort}"); |
| | | LoginManager.Instance.AccountLogin(m_Account.text, m_ServerIP, m_Port, m_GamePort); |
| | | break; |
| | | case VersionAuthority.Release: |
| | | #if UNITY_WEBGL |
| | | if (string.IsNullOrEmpty(m_Account.text)) |
| | | { |
| | | Debug.LogWarning("[LoginWin][Login] WebGL账号为空,弹出提示"); |
| | | ServerTipDetails.DisplayNormalTip(Language.Get("L1095")); |
| | | return; |
| | | } |
| | | Debug.Log($"[LoginWin][Login] WebGL账号登录: {m_Account.text}, IP: {m_ServerIP}, Port: {m_Port}, GamePort: {m_GamePort}"); |
| | | LoginManager.Instance.AccountLogin(m_Account.text, m_ServerIP, m_Port, m_GamePort); |
| | | #else |
| | | Debug.Log($"[LoginWin][Login] 正式服账号登录: IP: {m_ServerIP}, Port: {m_Port}, GamePort: {m_GamePort}"); |
| | | LoginManager.Instance.AccountLogin(m_ServerIP, m_Port, m_GamePort); |
| | | #endif |
| | | break; |
| | | } |
| | | |
| | |
| | | using UnityEngine; |
| | | using UnityEngine.UI; |
| | | using DG.Tweening; |
| | | using Cysharp.Threading.Tasks; |
| | | |
| | | using System.Text.RegularExpressions; |
| | | |
| | |
| | | OnGMOpen(); |
| | | ServerTipDetails.requireOpenGM = false; |
| | | } |
| | | } |
| | | |
| | | private void OnDisable() |
| | | { |
| | | m_ContainerNormalHint.SetActive(false); |
| | | m_ContainerChatHint.SetActive(false); |
| | | DisableServerTip(); |
| | | StopAllCoroutines(); |
| | | } |
| | | |
| | | void CheckNormalHint() |
| | |
| | | |
| | | public static void ShowTip(string tip, ArrayList infoList = null, int _order = 0) |
| | | { |
| | | if (string.IsNullOrWhiteSpace(tip)) |
| | | return; |
| | | |
| | | int range = Math.Min(m_Hints.Count, 10); |
| | | int findCnt = 0; |
| | | for (int i = 1; i <= range; i++) |
| | |
| | | private float m_TipShowTime; |
| | | private float m_TipHideTime; |
| | | private float m_TipDistance; |
| | | private Sequence _sequence; |
| | | |
| | | private void Awake() |
| | | { |
| | |
| | | pos = transform.localPosition; |
| | | presentState = state; |
| | | //LateUpdate 改成dotwweing |
| | | Sequence tween = DOTween.Sequence();; |
| | | tween.Append(transform.DOLocalMove(pos.SetY(pos.y + m_TipDistance), ScrollTip.tipMoveTime)).SetEase(Ease.Linear); |
| | | tween.AppendInterval(m_TipShowTime); |
| | | tween.Append(canvasGroup.DOFade(0, m_TipHideTime)).SetEase(Ease.Linear); |
| | | tween.Play(); |
| | | tween.OnComplete(() => |
| | | _sequence = DOTween.Sequence(); |
| | | _sequence.Append(transform.DOLocalMove(pos.SetY(pos.y + m_TipDistance), ScrollTip.tipMoveTime).SetEase(Ease.Linear)); |
| | | _sequence.AppendInterval(m_TipShowTime); |
| | | _sequence.Append(canvasGroup.DOFade(0, m_TipHideTime).SetEase(Ease.Linear)); |
| | | _sequence.Play(); |
| | | _sequence.OnComplete(() => |
| | | { |
| | | presentState = ScrollTip.ScrollTipState.None; |
| | | ScrollTip.Release(this, false); |
| | |
| | | ScrollTipDetail tipDetail = await ScrollTip.Request(); |
| | | if (tipDetail != null) |
| | | { |
| | | // 首次登录时 pool 为 null,Request() 异步加载预制体耗时 >100ms。 |
| | | // LoopTipReceiveEvent 每 100ms 重入,可能已有另一次调用先消耗了 m_Hints[0]。 |
| | | // 若 await 返回时 m_Hints 已空,必须将 tipDetail 归还池,否则它会被插入 Canvas 但 |
| | | // 永远不会播放动画,导致提示条卡在屏幕上(第一次登录复现的根因)。 |
| | | if (ScrollTip.m_Hints.Count == 0) |
| | | { |
| | | ScrollTip.Release(tipDetail, false); |
| | | return; |
| | | } |
| | | tipDetail.SetTipConfig(m_TipShowTime, m_TipHideTime, m_TipDistance); |
| | | ScrollTip.m_ActiveTips.Add(tipDetail); |
| | | var rt = tipDetail.transform; |