#if UNITY_EDITOR
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using Unity.EditorCoroutines.Editor;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using System.Security.Cryptography;

namespace Mi
{
    public class MiQGameConverter : EditorWindow
    {
        private const string CURRETN_VERSION = "1.5.9";
        private const string KEY_MI_QGAME_NAME = "key_mi_qgame_name";
        private const string KEY_MI_QGAME_PACKAGE = "key_mi_qgame_package";
        private const string KEY_MI_QGAME_VERSION = "key_mi_qgame_version";
        private const string KEY_MI_QGAME_VERSION_CODE = "key_mi_qgame_version_code";
        private const string KEY_MI_QGAME_BUILD_PATH = "key_mi_qgame_build_path";
        private const string KEY_MI_QGAME_BUILD_MODE = "key_mi_qgame_build_mode";
        private const string KEY_MI_QGAME_ORIENTATION = "key_mi_qgame_orientation";
        private const string KEY_MI_QGAME_SIGN_PATH = "key_mi_qgame_sign_path";
        private const string KEY_MI_QGAME_DATA_PATH = "key_mi_qgame_data_path";
        private const string KEY_MI_QGAME_WASM_PATH = "key_mi_qgame_wasm_path";
        private const string KEY_MI_QGAME_STREAM_PATH = "key_mi_qgame_stream_path";
        private const string KEY_MI_QGAME_STREAM_DATA = "key_mi_qgame_stream_data";
        private const string KEY_MI_QGAME_OPENSSL_PROVIDER = "key_mi_qgame_openssl_provider";
        private const string KEY_MI_QGAME_LOADING_BG = "key_mi_qgame_loading_bg";
        private const string KEY_MI_QGAME_BROTLI_WASM = "key_mi_qgame_brotli_wasm";
        private const string KEY_MI_QGAME_BROTLI_DATA  = "key_mi_qgame_brotli_data";
        private const string KEY_MI_QGAME_WEBGL2 = "key_mi_qgame_webgl2";

        private static string sGameName = "";
        private static string sPackageName = "";
        private static string sVersion = "";
        private static int sVersionCode = 0;
        private static string sLoadingBG = "";
        private static string sBuildPath = "";
        private static string sChooseBuildPath = "";
        private static bool sBuildPathBtn = false;
        private static bool sRelease = false;
        private static bool sPortrait = true;
        private static bool sNodeJS = false;
        private static string sSignPath = "";
        private static bool sSignBtn = false;
        private static string sBuildLog = "";
        private static bool sIsBuild = false;
        private static string sDataPath = "";
        private static string sWasmPath = "";
        private static bool sStreamRes = false;
        private static string sStreamAssetPath = "";
        private static bool sRemoveOpenSSLProvider = false;
        private Vector2 scrollRoot;
        private static bool sBrotliWasm = false;
        private static bool sBrotliData = false;
        private static bool sBuilding = false;
        private static int sBuildingCount = 0;
        private static bool isAutoHideLoading = true;
        private static bool sIsWebGL2 = false;

        private static void LoadData()
        {
            if (string.IsNullOrEmpty(sGameName))
            {
                sGameName = PlayerPrefs.GetString(KEY_MI_QGAME_NAME, "");
            }

            if (string.IsNullOrEmpty(sPackageName))
            {
                sPackageName = PlayerPrefs.GetString(KEY_MI_QGAME_PACKAGE, "");
            }

            if (string.IsNullOrEmpty(sVersion))
            {
                sVersion = PlayerPrefs.GetString(KEY_MI_QGAME_VERSION, "");
            }

            if (sVersionCode == 0)
            {
                sVersionCode = PlayerPrefs.GetInt(KEY_MI_QGAME_VERSION_CODE, 0);
            }

            if (string.IsNullOrEmpty(sChooseBuildPath))
            {
                sChooseBuildPath = PlayerPrefs.GetString(KEY_MI_QGAME_BUILD_PATH, "");
            }

            if (string.IsNullOrEmpty(sSignPath))
            {
                sSignPath = PlayerPrefs.GetString(KEY_MI_QGAME_SIGN_PATH, "");
            }

            if (string.IsNullOrEmpty(sDataPath))
            {
                sDataPath = PlayerPrefs.GetString(KEY_MI_QGAME_DATA_PATH, "");
            }

            if (string.IsNullOrEmpty(sWasmPath))
            {
                sWasmPath = PlayerPrefs.GetString(KEY_MI_QGAME_WASM_PATH, "");
            }

            if (string.IsNullOrEmpty(sStreamAssetPath))
            {
                sStreamAssetPath = PlayerPrefs.GetString(KEY_MI_QGAME_STREAM_PATH, "");
            }

            if (string.IsNullOrEmpty(sLoadingBG))
            {
                sLoadingBG = PlayerPrefs.GetString(KEY_MI_QGAME_LOADING_BG, "");
            }

            sStreamRes = PlayerPrefs.GetInt(KEY_MI_QGAME_STREAM_DATA, 0) == 1;
            sRelease = PlayerPrefs.GetInt(KEY_MI_QGAME_BUILD_MODE, 0) == 1; // 0 debug, 1 release
            sPortrait = PlayerPrefs.GetInt(KEY_MI_QGAME_ORIENTATION, 0) == 1; // 0 landscape, 1 portrait
            sRemoveOpenSSLProvider = PlayerPrefs.GetInt(KEY_MI_QGAME_OPENSSL_PROVIDER, 0) == 1; //0reserve 1remove
            sBrotliWasm = PlayerPrefs.GetInt(KEY_MI_QGAME_BROTLI_WASM, 0) == 1; //0 no 1 brotli
            sBrotliData = PlayerPrefs.GetInt(KEY_MI_QGAME_BROTLI_DATA, 0) == 1;
            sIsWebGL2 = PlayerPrefs.GetInt(KEY_MI_QGAME_WEBGL2, 0) == 1;
        }

        [MenuItem("小米快游戏/转换快游戏", false, 1)]
        public static void ShowWindow()
        {
            LoadData();
            Rect rect = new Rect(0, 0, 650, 800);
            MiQGameConverter window = (MiQGameConverter)GetWindowWithRect(typeof(MiQGameConverter), rect, true, "小米快游戏转换工具");
            window.Show();
            // GetVersionInfo();
        }

        // 打包面板UI
        private void OnGUI()
        {
            scrollRoot = EditorGUILayout.BeginScrollView(scrollRoot);
            var labelStyle = new GUIStyle(EditorStyles.boldLabel);
            labelStyle.alignment = TextAnchor.MiddleLeft;
            GUILayout.Label("工具信息", labelStyle);
            EditorGUILayout.BeginVertical("frameBox");
            GUILayout.Label("版本号：" + CURRETN_VERSION);
            GUILayout.BeginHorizontal();
            GUILayout.Label("检查升级：", GUILayout.Width(60));
            versionLog = "请查看工具使用说明";
            GUILayout.Label(versionLog);
            GUILayout.EndHorizontal();
            GUILayout.Label("转换工具适配Unity版本: 2022.3.50f1c1，2021.3.20f1，2021.3.14f1，2020.3.47f1，2019.4.35f1c1");
            GUILayout.Label("工具适配团结引擎版本: Tuanjie 1.x");
            GUILayout.BeginHorizontal();
            GUILayout.Label("小米快游戏介绍");
            var info = GUILayout.Button("链接", GUILayout.Width(100));
            if (info)
            {
                // Application.OpenURL("https://dev.mi.com/distribute/doc/details?pId=1450");
                Application.OpenURL("https://dev.mi.com/xiaomihyperos/quickgame-develop");
            }
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            GUILayout.Label("工具使用说明");
            var userInfo = GUILayout.Button("链接", GUILayout.Width(100));
            if (userInfo)
            {
                // Application.OpenURL("http://www.tennews.cn/unity/use.pdf");
                Application.OpenURL("https://dev.mi.com/xiaomihyperos/documentation/detail?pId=1991");
            }
            GUILayout.EndHorizontal();
            EditorGUILayout.EndVertical();

            GUILayout.Space(10);
            GUILayout.Label("参数设置", labelStyle);
            EditorGUILayout.BeginVertical("frameBox");
            sGameName = EditorGUILayout.TextField("游戏名称", sGameName);
            sPackageName = EditorGUILayout.TextField("包名", sPackageName);
            EditorGUILayout.LabelField("                                                   小米快游测试包名：com.demo.ch.mini");
            sVersion = EditorGUILayout.TextField("版本号", sVersion);
            sVersionCode = EditorGUILayout.IntField("版本Code", sVersionCode);
            sLoadingBG = EditorGUILayout.TextField("自定义Loading图片链接", sLoadingBG);
            EditorGUILayout.LabelField("                                                   用于屏蔽空白页面，需要快游戏框架11110002及以上版本");
            GUILayout.Space(3);
            GUILayout.BeginHorizontal();
            // 路径框
            sChooseBuildPath = EditorGUILayout.TextField("输出目录", sChooseBuildPath);
            sBuildPathBtn = GUILayout.Button("选择", GUILayout.Width(100));
            if (sBuildPathBtn)
            {
                string path = EditorUtility.SaveFolderPanel("选择输出目录", sChooseBuildPath, "");
                if (!string.IsNullOrEmpty(path))
                {
                    sChooseBuildPath = path;
                }
            }
            GUILayout.EndHorizontal();

            GUILayout.Space(3);
            GUILayout.Label("游戏屏幕方向", labelStyle);
            GUILayout.BeginHorizontal();
            sPortrait = EditorGUILayout.BeginToggleGroup("横屏", sPortrait);
            EditorGUILayout.EndToggleGroup();
            sPortrait = EditorGUILayout.BeginToggleGroup("竖屏", !sPortrait);
            EditorGUILayout.EndToggleGroup();
            GUILayout.EndHorizontal();

            GUILayout.Space(5);
            GUILayout.Label("WebGL版本", labelStyle);
            GUILayout.BeginHorizontal();
            sIsWebGL2 = EditorGUILayout.BeginToggleGroup("WebGL 1.0", sIsWebGL2);
            EditorGUILayout.EndToggleGroup();
            sIsWebGL2 = EditorGUILayout.BeginToggleGroup("WebGL 2.0", !sIsWebGL2);
            EditorGUILayout.EndToggleGroup();
            GUILayout.EndHorizontal();

            GUILayout.Space(5);
            GUILayout.Label("NodeJS版本（如果您的NodeJS版本高于17.9.1，请选择高版本）", labelStyle);
            GUILayout.BeginHorizontal();
            sRemoveOpenSSLProvider = EditorGUILayout.BeginToggleGroup("高版本(NodeJS 17.9.1+)", sRemoveOpenSSLProvider);
            EditorGUILayout.EndToggleGroup();
            sRemoveOpenSSLProvider = EditorGUILayout.BeginToggleGroup("低版本", !sRemoveOpenSSLProvider);
            EditorGUILayout.EndToggleGroup();
            GUILayout.EndHorizontal();

            GUILayout.Space(10);
            GUILayout.Label("包类型", labelStyle);

            GUILayout.BeginHorizontal();
            sRelease = EditorGUILayout.BeginToggleGroup("Debug", sRelease);
            EditorGUILayout.EndToggleGroup();
            sRelease = EditorGUILayout.BeginToggleGroup("Release", !sRelease);
            EditorGUILayout.EndToggleGroup();
            GUILayout.EndHorizontal();

            GUILayout.Space(10);
            GUILayout.BeginHorizontal();
            sSignPath = EditorGUILayout.TextField("签名文件根目录", sSignPath);
            sSignBtn = GUILayout.Button("选择", GUILayout.Width(100));
            if (sSignBtn)
            {
                string path = EditorUtility.OpenFolderPanel("选择签名文件目录", sSignPath, "");
                if (!string.IsNullOrEmpty(path))
                {
                    sSignPath = path;
                }
            }
            GUILayout.EndHorizontal();

            EditorGUILayout.LabelField("注意：签名文件生成方式，请查看小米快游戏介绍文档！");
            EditorGUILayout.EndVertical();

            GUILayout.Space(10);
            GUILayout.Label("资源说明", labelStyle);
            EditorGUILayout.BeginVertical("frameBox");
            GUILayout.Label("如果包体过大，请把打包后的Build/build.data或者Build/build.wasm放在网络上加载", labelStyle);

            sBrotliData = EditorGUILayout.BeginToggleGroup(new GUIContent("data brotli压缩(?)", "使用brotli压缩data文件，网络加载会强制开启"), sBrotliData);
            EditorGUILayout.EndToggleGroup();

            GUILayout.BeginHorizontal();
            sDataPath = EditorGUILayout.TextField("build.data地址(http)", sDataPath);
            GUILayout.EndHorizontal();

            GUILayout.Space(10);

            sBrotliWasm = EditorGUILayout.BeginToggleGroup(new GUIContent("wasm brotli压缩(?)", "使用brotli压缩wasm文件，网络加载会强制开启"), sBrotliWasm);
            EditorGUILayout.EndToggleGroup();

            GUILayout.BeginHorizontal();
            sWasmPath = EditorGUILayout.TextField("build.wasm地址(http)", sWasmPath);
            GUILayout.EndHorizontal();

            GUILayout.Space(10);
            sStreamRes = EditorGUILayout.BeginToggleGroup("StreamingAssets", sStreamRes);
            GUILayout.BeginHorizontal();
            sStreamAssetPath = EditorGUILayout.TextField("资源地址(http)", sStreamAssetPath);
            GUILayout.EndHorizontal();
            EditorGUILayout.EndToggleGroup();

            EditorGUILayout.EndVertical();
            //EditorGUILayout.EndToggleGroup();

            GUILayout.Space(10);
            GUILayout.Label("转换说明", labelStyle);
            EditorGUILayout.BeginVertical("frameBox");
            GUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("(1) 生成快游戏rpk，需要版本nodejs，请确定已安装! ");
            sNodeJS = GUILayout.Button("安装NodeJs", GUILayout.Width(100));
            if (sNodeJS)
            {
                Application.OpenURL("https://nodejs.org/en/download");
            }
            GUILayout.EndHorizontal();

            EditorGUILayout.LabelField("(2) 包名请确定是从小米快游戏中心申请的包名，否则游戏加载不出来！");
            EditorGUILayout.LabelField("(3) 请把Assets/XIAOMI-minigame/MiQGame/image/icon.png，图片替换成自己的游戏图标！");
            GUILayout.EndHorizontal();
            GUILayout.Space(20);

            if (GUILayout.Button("生成快游戏", GUILayout.Height(30)))
            {
                if (sBuilding)
                {
                    sBuildingCount += 1;
                    if (sBuildingCount >= 1)
                    {
                        sBuilding = false;
                        sBuildingCount = 0;
                    }
                    PrintBuildLog("正在生成中，请稍后重试");
                }
                else
                {
                    Camera mainCamera = Camera.main;
                    if (mainCamera != null)
                    {
                        var migame = mainCamera.gameObject.GetComponent<MiGameHelper>();
                        if (migame != null)
                        {
                            isAutoHideLoading = false;
                        }
                    }
                    else
                    {
                        isAutoHideLoading = true;
                    }
                    sBuilding = true;
                    Build();
                    //BuildWebGL();
                    //FrameworkConverter();
                    //CopyUnityData();
                    //PackageRpk();
                    //SetPackageParm
                    sBuilding = false;
                }
            }

            GUILayout.Space(20);
            EditorGUILayout.EndScrollView();
            GUIUtility.ExitGUI();
        }

        private void ResetBuilding()
        {
            sBuilding = false;
        }

        public static void QGameLog(string log)
        {
            UnityEngine.Debug.Log($"[qgame]{log}");
        }

        private static void PrintBuildLog(string log)
        {
            sBuildLog += $"{log}\n";
            UnityEngine.Debug.Log($"[unity]{log}");
        }

        private static void Build()
        {
            if (sIsBuild)
            {
                PrintBuildLog("正在打包中，请等待打包完成...");
                return;
            }

            if (string.IsNullOrEmpty(sGameName))
            {
                PrintBuildLog("游戏名称不能为空，请设置游戏名");
                return;
            }
            PlayerPrefs.SetString(KEY_MI_QGAME_NAME, sGameName);

            if (string.IsNullOrEmpty(sPackageName))
            {
                PrintBuildLog("包名不能为空，请设置包名");
                return;
            }
            PlayerPrefs.SetString(KEY_MI_QGAME_PACKAGE, sPackageName);
            PlayerPrefs.SetString(KEY_MI_QGAME_PACKAGE, sPackageName);

            if (string.IsNullOrEmpty(sVersion))
            {
                PrintBuildLog("版本号不能为空，请设置版本号");
                return;
            }
            PlayerPrefs.SetString(KEY_MI_QGAME_VERSION, sVersion);

            if (sVersionCode == 0)
            {
                PrintBuildLog("版本code为0，请设置版本code");
                return;
            }
            PlayerPrefs.SetInt(KEY_MI_QGAME_VERSION_CODE, sVersionCode);
            PlayerPrefs.SetString(KEY_MI_QGAME_LOADING_BG, sLoadingBG);

            if (string.IsNullOrEmpty(sChooseBuildPath))
            {
                PrintBuildLog("输出目录不能为空，请选择正确的输出目录");
                return;
            }

            PlayerPrefs.SetString(KEY_MI_QGAME_BUILD_PATH, sChooseBuildPath);
            PlayerPrefs.SetInt(KEY_MI_QGAME_BUILD_MODE, sRelease ? 1 : 0);
            PlayerPrefs.SetInt(KEY_MI_QGAME_ORIENTATION, sPortrait ? 1 : 0);
            PlayerPrefs.SetInt(KEY_MI_QGAME_OPENSSL_PROVIDER, sRemoveOpenSSLProvider ? 1 : 0);
            PlayerPrefs.SetInt(KEY_MI_QGAME_WEBGL2, sIsWebGL2 ? 1 : 0);

            if (string.IsNullOrEmpty(sSignPath))
            {
                PrintBuildLog("签名路径为空，请选择签名目录");
                return;
            }
            PlayerPrefs.SetString(KEY_MI_QGAME_SIGN_PATH, sSignPath);

            PlayerPrefs.SetString(KEY_MI_QGAME_DATA_PATH, sDataPath);
            PlayerPrefs.SetString(KEY_MI_QGAME_WASM_PATH, sWasmPath);
            PlayerPrefs.SetInt(KEY_MI_QGAME_BROTLI_WASM, sBrotliWasm ? 1 : 0);
            PlayerPrefs.SetInt(KEY_MI_QGAME_BROTLI_DATA, sBrotliData ? 1 : 0);
            PlayerPrefs.SetInt(KEY_MI_QGAME_STREAM_DATA, sStreamRes ? 1 : 0);
            PlayerPrefs.SetString(KEY_MI_QGAME_STREAM_PATH, sStreamAssetPath);

            // 判断是否是webgl平台
            if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.WebGL)
            {
                if (!EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.WebGL, BuildTarget.WebGL))
                {
                    PrintBuildLog("请检查打包平台，非WebGL打包方式，不能打包");
                    return;
                }
            }

            try
            {
                sIsBuild = true;
                var result = BuildWebGL();
                if (!result)
                {
                    UnityEngine.Debug.LogError("webgl打包失败");
                }
                else
                {
                    result = BuildMiQGame();
                    if (!result)
                    {
                        UnityEngine.Debug.LogError("rpk打包失败");
                    }
                    else
                    {
                        EditorUtility.OpenWithDefaultApp(Path.Combine(sBuildPath, "MiQGame"));
                        GUIUtility.ExitGUI();
                    }
                }
            }
            catch (SystemException e)
            {
                PrintBuildLog($"打包失败，请查看Console日志！");
                QGameLog($"打包失败: {e}");
            }
            finally
            {
                sIsBuild = false;
                sBuilding = false;
            }
        }

        private static bool BuildWebGL()
        {
            PrintBuildLog("WebGL打包...");
            sBuildPath = Path.Combine(sChooseBuildPath, "MiQGameBuild");
            FileInfo fi = new FileInfo(sBuildPath);
            var di = fi.Directory;
            if (!di.Exists)
            {
                di.Create();
            }

            sBuildPath = sBuildPath.Replace("\\", "/");

#if UNITY_2021
            PlayerSettings.colorSpace = ColorSpace.Gamma;
#endif
            PlayerSettings.runInBackground = false;
            PlayerSettings.WebGL.threadsSupport = false;
            PlayerSettings.SetUseDefaultGraphicsAPIs(BuildTarget.WebGL, false);
            if (!sIsWebGL2)
            {
                PrintBuildLog("webgl 1.0打包");
                GraphicsDeviceType[] targets = { GraphicsDeviceType.OpenGLES2 };
                PlayerSettings.SetGraphicsAPIs(BuildTarget.WebGL, targets);
            }
            else
            {
                PrintBuildLog("webgl 2.0打包");
            }
            PlayerSettings.WebGL.compressionFormat = WebGLCompressionFormat.Disabled;
            PlayerSettings.WebGL.template = "APPLICATION:Minimal";
            // EditorSettings.spritePackerMode = SpritePackerMode.AlwaysOnAtlas;
            PlayerSettings.WebGL.linkerTarget = WebGLLinkerTarget.Wasm;

            ClearBuildPath(sBuildPath);
            List<string> scenes = new List<string>();
            foreach (var scene in EditorBuildSettings.scenes)
            {
                if (scene.enabled)
                {
                    scenes.Add(scene.path);
                }
            }

            if (scenes.Count == 0)
            {
                PrintBuildLog("未选择需要打包的场景，请选择打包场景");
                return false;
            }

            // 禁用压缩格式，快应用转换需要
            PlayerSettings.WebGL.compressionFormat = WebGLCompressionFormat.Disabled;

            var result = BuildPipeline.BuildPlayer(scenes.ToArray(), sBuildPath, BuildTarget.WebGL, BuildOptions.None);
            var summary = result.summary;
            if (summary.result == UnityEditor.Build.Reporting.BuildResult.Succeeded)
            {
                PrintBuildLog("WebGL工程打包完成");
                return true;
            }
            else
            {
                PrintBuildLog("WebGL工程打包失败，请查看console日志！");
                return false;
            }
        }

        private static void ClearBuildPath(string path)
        {
            PrintBuildLog("清空输出目录...");
            DirectoryInfo buildDir = new DirectoryInfo(path);
            if (buildDir.Exists)
            {
                DirectoryInfo[] childs = buildDir.GetDirectories();
                foreach (DirectoryInfo child in childs)
                {
                    child.Delete(true);
                }
            }
            else
            {
                Directory.CreateDirectory(path);
            }
            PrintBuildLog("清空输出目录完成");
        }

        /// <summary>
        /// 转换成小米快游戏
        /// </summary>
        private static bool BuildMiQGame()
        {
            //资源文件的处理
            PrintBuildLog("小米快游戏转换...");
            UnityEngine.Debug.Log("小米快游戏转换...");
            var result = CopyQGameSdkToBuild();
            if (!result) {
                UnityEngine.Debug.LogError("快游戏转换失败");
                return false;
            }

            // 创建manifest.json
            PrintBuildLog("创建manifest.json");
            result = CreateManifest();
            if (!result)
            {
                UnityEngine.Debug.LogError("快游戏转换失败");
                return false;
            }
            PrintBuildLog("创建manifest.json完成");

            PrintBuildLog("修改package.json文件");
            result = SetPackageParm();
            if (!result)
            {
                UnityEngine.Debug.LogError("快游戏转换失败");
                return false;
            }
            PrintBuildLog("修改package.json文件完成");

            PrintBuildLog("修改config.json文件");
            result = SetConfigParm();
            if (!result)
            {
                UnityEngine.Debug.LogError("快游戏转换失败");
                return false;
            }
            PrintBuildLog("修改config.json文件完成");

            // 框架转换
            PrintBuildLog("framework转换");
            result = FrameworkConverter();
            if (!result)
            {
                UnityEngine.Debug.LogError("快游戏转换失败");
                return false;
            }
            PrintBuildLog("framework转换完成");

            // 复制unity数据
            PrintBuildLog("整理webgl数据");
            result = CopyUnityData();
            if (!result)
            {
                UnityEngine.Debug.LogError("快游戏转换失败");
                return false;
            }
            PrintBuildLog("整理webgl数据完成");

            // 整理工程结构
            PrintBuildLog("整理工程结构");
            result = ArrangeProject();
            if (!result)
            {
                UnityEngine.Debug.LogError("快游戏转换失败");
                return false;
            }
            PrintBuildLog("整理工程结构完成");

            // rpk打包
            PrintBuildLog("rpk打包");
            UnityEngine.Debug.Log("rpk打包...");
            result = PackageRpk();
            if (!result)
            {
                UnityEngine.Debug.LogError("快游戏转换失败");
                return false;
            }
            UnityEngine.Debug.Log("rpk打包完成");
            PrintBuildLog("rpk打包完成");

            return true;
        }

        private static bool CopyQGameSdkToBuild()
        {
            string sourcePath = "Assets/XIAOMI-minigame/MiQGame";
            if (!AssetDatabase.IsValidFolder(sourcePath))
            {
                PrintBuildLog($"文件目录不存在MiQGame，请检查资源文件");
                UnityEngine.Debug.Log("Folder not exists!");
                return false;
            }

            UnityEngine.Object folderObject = AssetDatabase.LoadAssetAtPath(sourcePath, typeof(UnityEngine.Object));
            sourcePath = AssetDatabase.GetAssetPath(folderObject);

            //复制快游戏框架
            CopyDirectory(sourcePath, sBuildPath);

            if (!string.IsNullOrEmpty(sSignPath))
            {
                //复制签名文件
                CopyDirectory(sSignPath, Path.Combine(sBuildPath, "MiQGame"));
            }

            return true;
        }

        /// <summary>
        /// 递归复制文件夹
        /// </summary>
        /// <param name="sourcePath">源文件夹</param>
        /// <param name="destPath">目标文件夹</param>
        private static void CopyDirectory(string sourcePath, string destPath)
        {
            string floderName = Path.GetFileName(sourcePath);
            DirectoryInfo di = Directory.CreateDirectory(Path.Combine(destPath, floderName));
            string[] files = Directory.GetFileSystemEntries(sourcePath);

            foreach (string file in files)
            {
                if (Directory.Exists(file))
                {
                    CopyDirectory(file, di.FullName);
                }
                else
                {
                    if (!file.EndsWith(".meta"))
                    {
                        File.Copy(file, Path.Combine(di.FullName, Path.GetFileName(file)), true);
                    }
                }
            }
        }

        private static bool CreateManifest()
        {
            var manifest = "{\n";
            manifest += $"  \"package\":\"{sPackageName}\",\n";
            manifest += $"  \"name\":\"{sGameName}\",\n";
            manifest += $"  \"versionName\":\"{sVersion}\",\n";
            manifest += $"  \"versionCode\":{sVersionCode},\n";
            manifest += $"  \"minPlatformVersion\":1080,\n";
            manifest += $"  \"icon\":\"/image/icon.png\",\n";
            var orientation = sPortrait ? "portrait" : "landscape";
            manifest += $"  \"orientation\":\"{orientation}\",\n";
            manifest += $"  \"type\":\"game\",\n";
            manifest += "   \"config\":{},\n";
            manifest += "   \"display\":{},\n";
            manifest += "  \"subpackages\": [\n";
            manifest += "  {\n";
            manifest += "       \"name\" : \"subpackage\",\n";
            manifest += "       \"root\" : \"subpackage/\"\n";
            manifest += "  }]\n";
            manifest += "}";
            File.WriteAllText(Path.Combine(sBuildPath, "MiQGame", "manifest.json"), manifest);
            return true;
        }

        /// <summary>
        /// 修改package.json文件
        /// </summary>
        /// <returns></returns>
        private static bool SetPackageParm()
        {
            bool needRemove = false;
            if (Application.platform == RuntimePlatform.WindowsEditor)
            {
                //判断是否需要移除 OpenSSL Provider
                if (sRemoveOpenSSLProvider)
                {
                    needRemove = true;
                }
            }
            else
            {
                needRemove = true;
            }

            //判断是否需要移除 OpenSSL Provider
            if (needRemove)
            {
                //获取package.json的完整路径
                string packageJsonPath = Path.Combine(sBuildPath, "MiQGame", "package.json");

                // 读取原始文件内容
                string originalContent = File.ReadAllText(packageJsonPath);
                string openSSLProvider = "SET NODE_OPTIONS=--openssl-legacy-provider && ";
                string replaceStr = string.Empty;
                // 移除 SET NODE_OPTIONS=--openssl-legacy-provider &&
                originalContent = Regex.Replace(originalContent, Regex.Escape(openSSLProvider), replaceStr);

                //保存修改后的内容
                File.WriteAllText(packageJsonPath, originalContent);
            }
            return true;
        }

        /// <summary>
        /// 修改config.json文件
        /// </summary>
        /// <returns></returns>
        private static bool SetConfigParm()
        {
            //获取config.json的完整路径
            string jsonPath = Path.Combine(sBuildPath, "MiQGame", "config.json");

            // 读取原始文件内容
            string originalContent = File.ReadAllText(jsonPath);
            if (sIsWebGL2)
            {
                string originStr = "\"hasWebGL\": 1,";
                string replaceStr = "\"hasWebGL\": 2,";
                originalContent = Regex.Replace(originalContent, originStr, replaceStr);
            }

            if (!sIsWebGL2)
            {
                PrintBuildLog("webgl 1.0打包");
            }
            else
            {
                PrintBuildLog("webgl 2.0打包");
            }

            //保存修改后的内容
            File.WriteAllText(jsonPath, originalContent);
            return true;
        }

        private static String GetLocalIP()
        {
            var curDir = System.IO.Directory.GetCurrentDirectory();
            UnityEngine.Debug.Log(curDir);
            var workDir = Common.FormatPath(Path.Combine(curDir, "Assets", "XIAOMI-minigame", "Editor", "Tools"));
            var ipExe = Common.FormatPath(Path.Combine(workDir, "localip.exe"));
            var outList = Common.RunCmd(ipExe, "", workDir, 60);
            var ipPath = Common.FormatPath(Path.Combine(workDir, "ip.txt"));
            var ipFile = File.ReadAllText(ipPath);
            UnityEngine.Debug.Log($"本机ip{ipFile}");
            return ipFile;
        }

        private static bool FrameworkConverter()
        {
            //sBuildPath = Path.Combine(sChooseBuildPath, "MiQGameBuild");
            //sBuildPath = sBuildPath.Replace("\\", "/");

            var pathList = sBuildPath.Split("/".ToCharArray());
            var lastPath = pathList[pathList.Length - 1];
#if TUANJIE_1_0_OR_NEWER || TUANJIE_2022
            var frameContent = File.ReadAllText(Path.Combine(sBuildPath, "Build", $"{lastPath}.framework.js"));
            int starIndex = frameContent.IndexOf("function(tuanjieFramework) {");
            int endIndex = frameContent.IndexOf("return tuanjieFramework.ready");
            frameContent = frameContent.Substring(starIndex, endIndex - starIndex);
            frameContent += "};";

            var srcStr = "function\\(tuanjieFramework\\) \\{";
            var replaceStr = "var UnityModule = function tuanjieFramework(tuanjieFramework) { var _scriptDir=undefined;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
#elif UNITY_2019
            var frameContent = File.ReadAllText(Path.Combine(sBuildPath, "Build", $"{lastPath}.wasm.framework.unityweb"));
            int starIndex = frameContent.IndexOf("function(UnityModule) {");
            int endIndex = frameContent.IndexOf("return UnityModule;");
            frameContent = frameContent.Substring(starIndex, endIndex - starIndex);
            frameContent += "};";

            var srcStr = "function\\(UnityModule\\) \\{";
            var replaceStr = "var UnityModule = function unityFramework(UnityModule) { var _scriptDir=undefined;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ";delete http;";
            replaceStr = ";";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "UnityLoader.";
            replaceStr = "Module.";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "Module.streamingAssetsUrl\\(\\)";
            replaceStr = "Module.streamingAssetsUrl";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
#elif UNITY_2020 || UNITY_2021
            var frameContent = File.ReadAllText(Path.Combine(sBuildPath, "Build", $"{lastPath}.framework.js"));
            var srcStr = "function unityFramework";
            var replaceStr = "var UnityModule = function unityFramework";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
#elif UNITY_2022
            var frameContent = File.ReadAllText(Path.Combine(sBuildPath, "Build", $"{lastPath}.framework.js"));
            int starIndex = frameContent.IndexOf("function(unityFramework) {");
            int endIndex = frameContent.IndexOf("return unityFramework.ready");
            frameContent = frameContent.Substring(starIndex, endIndex - starIndex);
            frameContent += "};";

            var srcStr = "function\\(unityFramework\\) \\{";
            var replaceStr = "var UnityModule = function unityFramework(unityFramework) { var _scriptDir=undefined;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
#endif
#if UNITY_2021
            srcStr = "var enumerateWatchdog=null;";
            replaceStr = "";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "var removeEnumerateMediaDevicesRunDependency;";
            replaceStr = "var removeEnumerateMediaDevicesRunDependency;var enumerateWatchdog=null;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = @"setTimeout\(function\(\)\{.*?\},0\);";
            replaceStr = "setTimeout(function(){try{addRunDependency(\"enumerateMediaDevices\");removeEnumerateMediaDevicesRunDependency=function(){if(enumerateWatchdog!==null)clearTimeout(enumerateWatchdog);removeRunDependency(\"enumerateMediaDevices\");if(navigator.mediaDevices)console.log(\"navigator.mediaDevices support available\");removeEnumerateMediaDevicesRunDependency=function(){}};enumerateMediaDeviceList();enumerateWatchdog=setTimeout(removeEnumerateMediaDevicesRunDependency,1e3);navigator.mediaDevices.addEventListener(\"devicechange\",enumerateMediaDeviceList)}catch(e){console.warn(\"Unable to enumerate media devices: \"+e);disableAccessToMediaDevices()}},0);";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
#endif
            srcStr = "function stringToUTF8Array\\(str,heap,outIdx,maxBytesToWrite\\)\\{";
            replaceStr = "function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { if(str==undefined){return 0} ";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "function lengthBytesUTF8\\(str\\)\\{";
            replaceStr = "function lengthBytesUTF8(str){if(str==undefined){return 0}";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "if\\(!navigator.mediaDevices\\)\\{";
            replaceStr = "if (navigator == undefined || navigator.mediaDevices == undefined) {";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "navigator.mediaDevices.addEventListener\\(\"devicechange\",enumerateMediaDeviceList\\)";
            replaceStr = "";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "function enumerateMediaDeviceList\\(\\)\\{";
            replaceStr = "function enumerateMediaDeviceList(){return;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "function disableAccessToMediaDevices\\(\\)\\{";
            replaceStr = "function disableAccessToMediaDevices(){videoInputDevices=null;return;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "var callback=callbacks.shift\\(\\);";
            replaceStr = "var callback=callbacks.shift();if (callback == undefined) { continue; }";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "var canvas=document.querySelector\\(canvasSelector\\);";
            replaceStr = "var canvas=Module[\"canvas\"];";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "location.protocol==\"https:\"?";
            replaceStr = "false";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "function JS_ScreenOrientation_eventHandler\\(\\)\\{";
            replaceStr = "function JS_ScreenOrientation_eventHandler(){ return;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "function _JS_ScreenOrientation_DeInit\\(\\)\\{";
            replaceStr = "function _JS_ScreenOrientation_DeInit(){ return;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "function _JS_ScreenOrientation_Init\\(callback\\)\\{";
            replaceStr = "function _JS_ScreenOrientation_Init(callback){ return;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "function _JS_ScreenOrientation_Lock\\(orientationLockType\\)\\{";
            replaceStr = "function _JS_ScreenOrientation_Lock(orientationLockType){ return;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "function _emscripten_sample_gamepad_data\\(\\)\\{";
            replaceStr = "function _emscripten_sample_gamepad_data(){ return -1;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "function _emscripten_set_gamepadconnected_callback_on_thread\\(userData,useCapture,callbackfunc,targetThread\\)\\{";
            replaceStr = "function _emscripten_set_gamepadconnected_callback_on_thread (userData, useCapture, callbackfunc, targetThread) { return -1;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "function _emscripten_set_gamepaddisconnected_callback_on_thread\\(userData,useCapture,callbackfunc,targetThread\\)\\{";
            replaceStr = "function _emscripten_set_gamepaddisconnected_callback_on_thread (userData, useCapture, callbackfunc, targetThread) { return -1;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ";var firstState=navigator.getGamepads";
            replaceStr = ";var firstState=null;return;firstState=navigator.getGamepads";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "\\(function\\(\\)\\{var enumerateMediaDevices=\\(function\\(\\)\\{";
            replaceStr = "(function(){var enumerateMediaDevices=(function(){return;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "function getChromeVersion\\(\\)\\{";
            replaceStr = "function getChromeVersion(){return false;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "isInternetExplorer:\\(function\\(\\)\\{";
            replaceStr = "isInternetExplorer:(function(){return false;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "alert\\(";
            replaceStr = "console.log(";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "_weblg_console.log\\(";
            replaceStr = "_weblg_alert(";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "delete http";
            replaceStr = "";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

#if TUANJIE_1_0_OR_NEWER || TUANJIE_2022 || UNITY_2021 || UNITY_2022
            srcStr = @"var domElement=specialHTMLTargets[\s\S]*?:undefined\);";
            replaceStr = "var domElement=Module[\"canvas\"];";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = @"function *getRandomDevice *\( *\) *\{";
            replaceStr = "function getRandomDevice(){ if(window[\"qg\"])return function () {return Math.random() * 256 | 0};";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "var abortController=new AbortController;";
            replaceStr = "var abortController=new XMLHttpRequest;abortController.open(_method,_url,true);";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "function HandleSuccess\\(response,body\\)\\{";
            replaceStr = "function HandleSuccess(response,body){HandleProgress(response);var body=new Uint8Array(body);";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = @"var fetchImpl=Module.fetchWithProgress;[\s\S]*?kWebErrorUnknown\)\}\}\)";
            replaceStr = "requestOptions.timeout&&requestOptions.timeout>=0&&(abortController.timeout=requestOptions.timeout);Object.keys(requestOptions.init.headers).map(r=>{abortController.setRequestHeader(r,requestOptions.init.headers[r])}),abortController.responseType=\"arraybuffer\",abortController.onload=function(){abortController.status<400?HandleSuccess(abortController,abortController.response):(HandleError(abortController.statusText,abortController.status),console.log(\" xml request error msg = \"+abortController.statusText+\" code = \"+abortController.status))},abortController.onerror=function(){HandleError(abortController.statusText?abortController.statusText:\"\",abortController.status)},postData?abortController.send(postData):abortController.send();";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "\\|\\|abortController.signal.aborted";
            replaceStr = "";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            if (Application.unityVersion.Contains("2021.3.14"))
            {
                srcStr = @"function HandleProgress[\s\S]*?e.loaded,e.total]\)\}";
                replaceStr = "function HandleProgress(s){onprogress&&((wr.responses[requestId] = s),dynCall(\"viii\",onprogress,[arg, 6, 6]));}";
                frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
            }
            else
            {
                srcStr = @"function HandleProgress[\s\S]*?e.loaded,e.total,0,0]\)\}\}";
                replaceStr = "function HandleProgress(s){onprogress&&(wr.responses[requestId]=s,dynCall(\"viiiiii\",onprogress,[arg,s.status,6,6,0,0]))}";
                frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
            }

            srcStr = @"function jsWebRequestGetResponseHeaderString[\s\S]*?return headers";
            replaceStr = "function jsWebRequestGetResponseHeaderString(e){var r=wr.responses[e];return r?r.headerString?r.headerString:r.getAllResponseHeaders()?r.getAllResponseHeaders():\"\":\"\"";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "var kWebRequestOK=0;if\\(requestOptions.init.enableStreamingDownload\\)";
            replaceStr = "var kWebRequestOK=0;if(false)";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "_WebGLWindowInit\\(\\)\\{if\\(typeof Runtime===\"undefined\"\\)Runtime=\\{dynCall:dynCall\\}\\}";
            replaceStr = "_WebGLWindowInit(){}";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
#endif
            srcStr = @"var WEBAudio=\{[\s\S]*?\};";
            replaceStr = "function QG_JS_Sound_GetAudioBufferSampleRate(soundInstance){return WEBAudio.FAKEMOD_SAMPLERATE;};function QG_JS_Sound_GetAudioContextSampleRate(soundInstance){return WEBAudio.FAKEMOD_SAMPLERATE;};function QG_JS_Sound_Create_Channel(o,i){if(0!=WEBAudio.audioWebEnabled&&window.qg){var e=function(){o&&dynCall(\"vi\",o,[i])},u={audio:null,loop:!1,volume:1,isBind:!1,isStop:!1,stopTime:0,isPlay:!1,playTime:0,isStopped:!1,playAudio:function(o,i){this.setup(),o>0?(this.audio.volume=0,this.isPlay=!0,this.playTime=o):(this.audio.volume=this.volume,this.audio.loop=this.loop),this.audio.play(),0!=i&&this.audio.seek(i)},setup:function(){if(this.audio&&0==this.isBind){this.audio.offEnded(e),this.audio.onEnded(e);var o=this;this.isStoped=!1,this.audio.offTimeUpdate(null),this.audio.onTimeUpdate(function(){1==o.isStop&&parseFloat(o.audio.currentTime)>=o.stopTime&&(o.stopTime=0,o.isStop=!1,o.audio.stop(),o.audio.destroy(),o.audio.src=\"\",o.isBind=!1,o.isStoped=!0),!o.isStoped&&1==o.isPlay&&parseFloat(o.audio.currentTime)>=o.playTime&&(o.isPlay=!1,o.playTime=0,o.audio.volume=o.volume,o.audio.loop=o.loop)}),this.isBind=!0}},stopAudio:function(o){0==o?(this.audio.offTimeUpdate(null),this.audio.offEnded(e),this.stopTime=0,this.isStop=!1,this.audio.pause(),this.isBind=!1):(this.stopTime=o,this.isStop=!0)}};return WEBAudio.audioInstances.push(u)-1}}function QG_JS_Sound_GetLength(o){if(0==WEBAudio.audioWebEnabled)return 0;var i=WEBAudio.audioInstances[o];return i?window.qg?i.bufferLength:void 0:0}function QG_JS_Sound_GetLoadState(o){if(0==WEBAudio.audioWebEnabled)return 2;if(window.qg){var i=WEBAudio.audioInstances[o],e=i.loadState;return 1==e?2:2==e?0:1}}function QG_JS_Sound_Load(o,i){if(0==WEBAudio.audioWebEnabled)return 0;if(window.qg){var e={buffer:null,error:!1,file:\"\",audio:window.qg.createInnerAudioContext(),bufferLength:0,ptr:o,loadState:0},u=window.qg.getFileSystemManager(),t=WEBAudio.audioInstances.push(e)-1;return e.file=window.qg.env.USER_DATA_PATH+\"/audio\"+o+i+\".mp3\",console.log(\"_JS_Sound_Load \"+e.file),e.buffer=HEAPU8.buffer.slice(o,o+i),u.writeFileSync(e.file,e.buffer,\"binary\"),e.audio.onCanplay(function(){e.bufferLength=44100*e.audio.duration|0,e.loadState=2}),e.audio.onError(function(o){console.log(o),e.loadState=1}),e.audio.src=e.file,t}}function QG_JS_Sound_Init(){window.qg&&(WEBAudio.audioWebEnabled=1)}function QG_JS_Sound_Load_PCM(o,i,e,u){if(0==WEBAudio.audioWebEnabled)return 0;for(var t={buffer:WEBAudio.audioContext.createBuffer(o,i,e),error:!1},n=0;n<o;n++){var d=(u>>2)+i*n,a=t.buffer,s=a.copyToChannel||function(o,i,e){var u=o.subarray(0,Math.min(o.length,this.length-(0|e)));this.getChannelData(0|i).set(u,0|e)};s.apply(a,[HEAPF32.subarray(d,d+i),n,0])}var r=WEBAudio.audioInstances.push(t)-1;return r}function QG_JS_Sound_Play(o,i,e,u){if(window.qg){if(QG_JS_Sound_Stop(i,0),console.log(\"sound play\",o,i,e,u),0==WEBAudio.audioWebEnabled)return;var t=WEBAudio.audioInstances[o],n=WEBAudio.audioInstances[i];if(t.buffer)try{if(console.log(\"play\",t.file),\"\"!==t.audio.src)n.audio=t.audio,n.audio.volume=n.volume,n.audio.loop=n.loop,n.playAudio(parseFloat(t.audio.currentTime)+u,e);else{t.loadState=0,t.audio=window.qg.createInnerAudioContext(),t.audio.onCanplay(function(){t.bufferLength=44100*t.audio.duration|0,t.loadState=2}),t.audio.onError(function(o){console.log(o),t.loadState=1}),t.audio.src=t.file,n.audio=t.audio,n.audio.volume=n.volume,n.audio.loop=n.loop;var d=t.loadState;if(0==d)var a=setInterval(function(){0!==t.loadState&&(2==t.loadState&&n.playAudio(parseFloat(t.audio.currentTime)+u,e),clearInterval(a))},100);else 2==d&&n.playAudio(parseFloat(t.audio.currentTime)+u,e)}}catch(o){console.error(\"playBuffer error. Exception: \"+o)}else console.log(\"Trying to play sound which is not loaded.\")}}function QG_JS_Sound_ReleaseInstance(o){WEBAudio.audioInstances[o]=null}function QG_JS_Sound_ResumeIfNeeded(){0!=WEBAudio.audioWebEnabled&&(window.qg||\"suspended\"===WEBAudio.audioContext.state&&WEBAudio.audioContext.resume())}function QG_JS_Sound_Set3D(o,i){if(!window.qg){var e=WEBAudio.audioInstances[o];e.threeD!=i&&(e.threeD=i,e.setupPanning())}}function QG_JS_Sound_SetListenerOrientation(o,i,e,u,t,n){0!=WEBAudio.audioWebEnabled&&(window.qg||(WEBAudio.audioContext.listener.forwardX?(WEBAudio.audioContext.listener.forwardX.setValueAtTime(-o,WEBAudio.audioContext.currentTime),WEBAudio.audioContext.listener.forwardY.setValueAtTime(-i,WEBAudio.audioContext.currentTime),WEBAudio.audioContext.listener.forwardZ.setValueAtTime(-e,WEBAudio.audioContext.currentTime),WEBAudio.audioContext.listener.upX.setValueAtTime(u,WEBAudio.audioContext.currentTime),WEBAudio.audioContext.listener.upY.setValueAtTime(t,WEBAudio.audioContext.currentTime),WEBAudio.audioContext.listener.upZ.setValueAtTime(n,WEBAudio.audioContext.currentTime)):WEBAudio.audioContext.listener.setOrientation(-o,-i,-e,u,t,n)))}function QG_JS_Sound_SetListenerPosition(o,i,e){0!=WEBAudio.audioWebEnabled&&(window.qg||(WEBAudio.audioContext.listener.positionX?(WEBAudio.audioContext.listener.positionX.setValueAtTime(o,WEBAudio.audioContext.currentTime),WEBAudio.audioContext.listener.positionY.setValueAtTime(i,WEBAudio.audioContext.currentTime),WEBAudio.audioContext.listener.positionZ.setValueAtTime(e,WEBAudio.audioContext.currentTime)):WEBAudio.audioContext.listener.setPosition(o,i,e)))}function QG_JS_Sound_SetLoop(o,i){if(0!=WEBAudio.audioWebEnabled&&window.qg){var e=WEBAudio.audioInstances[o],u=1==i;e.loop=u,null!==e.audio&&(e.audio.loop=u)}}function QG_JS_Sound_SetLoopPoints(o,i,e){if(!window.qg){if(0==WEBAudio.audioWebEnabled)return;var u=WEBAudio.audioInstances[o];u.source.loopStart=i,u.source.loopEnd=e}}function QG_JS_Sound_SetPitch(o,i){0!=WEBAudio.audioWebEnabled&&(window.qg||WEBAudio.audioInstances[o].source.playbackRate.setValueAtTime(i,WEBAudio.audioContext.currentTime))}function QG_JS_Sound_SetPosition(o,i,e,u){0!=WEBAudio.audioWebEnabled&&(window.qg||WEBAudio.audioInstances[o].panner.setPosition(i,e,u))}function QG_JS_Sound_SetVolume(o,i){if(window.qg){if(0==WEBAudio.audioWebEnabled)return;if(i>1){i=1;};var e=WEBAudio.audioInstances[o];e.volume=i,null!==e.audio&&(e.audio.volume=i)}}function QG_JS_Sound_Stop(o,i){if(window.qg){if(0==WEBAudio.audioWebEnabled)return;console.log(\"stop\",o,i);var e=WEBAudio.audioInstances[o];e.audio&&(console.log(o),0==i?(e.stopAudio(i),e.audio.offEnded(null)):e.stopAudio(parseFloat(e.audio.currentTime)+i),e.audio=null)}}function QG_JS_Sound_SetPaused(a,d){if(0!=WEBAudio.audioWebEnabled&&window.qg){var u=WEBAudio.audioInstances[a],i=!u.audio||u.audio.paused;d!=i&&(d?u.audio.pause():u.audio.play())}}var WEBAudio={audioInstanceIdCounter:0,audioInstances:[],audioContext:null,audioWebEnabled:0};";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_GetAudioBufferSampleRate";
            replaceStr = ":QG_JS_Sound_GetAudioBufferSampleRate";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_GetAudioContextSampleRate";
            replaceStr = ":QG_JS_Sound_GetAudioContextSampleRate";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_GetLength";
            replaceStr = ":QG_JS_Sound_GetLength";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_Create_Channel";
            replaceStr = ":QG_JS_Sound_Create_Channel";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_GetLoadState";
            replaceStr = ":QG_JS_Sound_GetLoadState";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_Init";
            replaceStr = ":QG_JS_Sound_Init";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_Load";
            replaceStr = ":QG_JS_Sound_Load";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_Load_PCM";
            replaceStr = ":QG_JS_Sound_Load_PCM";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_Play";
            replaceStr = ":QG_JS_Sound_Play";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_ReleaseInstance";
            replaceStr = ":QG_JS_Sound_ReleaseInstance";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_ResumeIfNeeded";
            replaceStr = ":QG_JS_Sound_ResumeIfNeeded";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_Set3D";
            replaceStr = ":QG_JS_Sound_Set3D";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_SetListenerOrientation";
            replaceStr = ":QG_JS_Sound_SetListenerOrientation";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_SetListenerPosition";
            replaceStr = ":QG_JS_Sound_SetListenerPosition";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_SetLoop";
            replaceStr = ":QG_JS_Sound_SetLoop";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_SetLoopPoints";
            replaceStr = ":QG_JS_Sound_SetLoopPoints";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_SetPitch";
            replaceStr = ":QG_JS_Sound_SetPitch";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_SetPosition";
            replaceStr = ":QG_JS_Sound_SetPosition";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_SetVolume";
            replaceStr = ":QG_JS_Sound_SetVolume";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_Stop";
            replaceStr = ":QG_JS_Sound_Stop";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = ": *_JS_Sound_SetPaused";
            replaceStr = ":QG_JS_Sound_SetPaused";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "function _WebGLInputBeginEditing";
            replaceStr = "var _curInputID = 0; function _WebGLInputBeginEditing";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "WebAssembly.instantiate\\(binary, info\\)";
            replaceStr = "Module[\"result\"]";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = @"function _system\(command\)\{.*?setErrNo\(6\);return-1\}";
            replaceStr = "function _system(command){return -1;}";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = "self\\[\"performance\"\\]";
            replaceStr = "window[\"performance\"]";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = @"e.preventDefault\(\)";
            replaceStr = "if(e.cancelable) e.preventDefault()";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

#if UNITY_2020 || UNITY_2021
            srcStr = @"function createWasm\(\)\{.*?\}";
            replaceStr = "var splitModuleProxyHandler={get(target, prop, receiver){return (...args)=>{return wasmTable.get(prop)(...args);};}};function createWasm(){console.log(\"wasm load\", new Date().toLocaleDateString());var info = { a : asmLibraryArg,'placeholder' : new Proxy({},splitModuleProxyHandler)};";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
#elif TUANJIE_1_0_OR_NEWER || TUANJIE_2022 || UNITY_2022
            srcStr = @"function createWasm\(\)\{.*?\}";
            replaceStr = "var splitModuleProxyHandler={get(target, prop, receiver){return (...args)=>{return wasmTable.get(prop)(...args);};}};function createWasm(){console.log(\"wasm load\", new Date().toLocaleDateString());var info = { 'env':asmLibraryArg, 'wasi_snapshot_preview1':asmLibraryArg, 'a': asmLibraryArg, 'placeholder' : new Proxy({},splitModuleProxyHandler)};";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
#endif

#if UNITY_2019
            srcStr = @"function doNativeWasm\(global,env,providedBuffer\)\{.*?\}";
            replaceStr = "var splitModuleProxyHandler={get(target, prop, receiver){return (...args)=>{return wasmTable.get(prop)(...args);};}};function doNativeWasm(global,env,providedBuffer){console.log(\"wasm load\", new Date().toLocaleDateString());info[\"placeholder\"]=new Proxy({},splitModuleProxyHandler);";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
#endif
            srcStr = @"function receiveInstance\(instance,module\)\{.*?\}";
            var matches = Regex.Match(frameContent, srcStr);
            replaceStr = matches.Value.Split('}')[0] + ";console.log(\"wasm load end\", new Date().toLocaleDateString())}";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            if (Application.platform == RuntimePlatform.WindowsEditor)
            {
                var ip = GetLocalIP();
                srcStr = @"function _QGPrintInt\(num\)\{.*?\}";
                replaceStr = "var collectDic={};var qgWebsocket=null;var qgWebsocketOpened=false;function _QGWebsocket(){qgWebsocket=new WebSocket('ws://" + ip + ":32371');qgWebsocket.onopen=function(event){console.log('WebSocket is open now.');qgWebsocketOpened = true;};qgWebsocket.onmessage = function(event) {console.log('WebSocket message received:', event.data);try {var msg = JSON.parse(event.data);if (msg.hasOwnProperty('cmd')) {switch(msg.cmd) {case 'qg.start':console.log('collect funcs start...');break;case 'qg.end':console.log('send cmd qg.collect',collectDic);var sendMsg = {};sendMsg['cmd'] = 'qg.collect';sendMsg['data'] = Object.values(collectDic);if (qgWebsocketOpened) {qgWebsocket.send(JSON.stringify(sendMsg));}console.log('collect funcs end');break;}}} catch(e) {console.error(e);}};qgWebsocket.onclose = function(event) {qgWebsocketOpened = false;console.log('WebSocket is closed now.');};qgWebsocket.onclose = function(event) {qgWebsocketOpened = false;console.log('WebSocket is closed now.');};qgWebsocket.onerror = function(event) {console.error('WebSocket error observed:', event);};}var openSocket=true;function _QGPrintInt(num){if(openSocket){let length=Object.keys(collectDic).length;if(length===10){_QGWebsocket();}if (length<10){console.log('collect-funcs', num);}else{openSocket=false;}}if(collectDic[num] === undefined){collectDic[num]=num;}}";
                frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
            }

            if (isAutoHideLoading)
            {
                srcStr = @"requestAnimationFrame:function\(func\)\{";
                replaceStr = "requestAnimationFrame:function(func){window[\"hideloading\"]();";
                frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

                srcStr = @"requestAnimationFrame:function requestAnimationFrame\(func\)\{";
                replaceStr = "requestAnimationFrame:function requestAnimationFrame(func){window[\"hideloading\"]();";
                frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
            }

            srcStr = @"assert\(ret,""IDBFS used, but indexedDB not supported""\);";
            replaceStr = "/*assert(ret,\"IDBFS used, but indexedDB not supported\");*/";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

#if TUANJIE_1_0_OR_NEWER || TUANJIE_2022 || UNITY_2022
            srcStr = @"input.select\(\);input.focus\(\)";
            replaceStr = "input.focus()";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
#endif

            #region websocket适配

            srcStr = @"function _WebSocketConnect\(instanceId\)\{";
            replaceStr = "function _WebSocketConnect(instanceId){var hasFileReaderAdapterLogged = false;";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            srcStr = @"if\(typeof Blob!==""undefined""&&ev\.data instanceof Blob\)\{.*?reader\.readAsArrayBuffer\(ev\.data\)\}";
            replaceStr = "if(typeof Blob!==\"undefined\"&&ev.data instanceof Blob){var reader = new FileReader();if(typeof reader.readAsArrayBuffer === \"function\"){reader.onload=function(){var array=new Uint8Array(reader.result);var buffer=_malloc(array.length);writeArrayToMemory(array,buffer);try{if(webSocketManager.support6000){(function(a1,a2,a3){dynCall_viii.apply(null,[webSocketManager.onMessage,a1,a2,a3])})(instanceId,buffer,array.length)}else{Module.dynCall_viii(webSocketManager.onMessage,instanceId,buffer,array.length)}}finally{reader=null;_free(buffer)}};reader.readAsArrayBuffer(ev.data)}else{if(!hasFileReaderAdapterLogged){console.warn(\"FileReader.readAsArrayBuffer 不是一个函数, 采用兼容性方案\");hasFileReaderAdapterLogged = true;}ev.data.arrayBuffer().then(function(arrayBuffer){var array=new Uint8Array(arrayBuffer);var buffer=_malloc(array.length);writeArrayToMemory(array,buffer);try{Module.dynCall_viii(webSocketManager.onMessage,instanceId,buffer,array.length)}finally{_free(buffer)}}).catch(function(error){console.log(\"[JSLIB WebSocket] arrayBuffer error: \",error)})}}";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            #endregion

            #region 接口适配

            //主动检查更新快游戏 [onUpdateReady]
            srcStr = @"updateManager\.onUpdateReady\(function\(\)\{[^}]*\}\}\}\)\}\)";
            replaceStr = "updateManager.onUpdateReady(function () { console.log(\"[unity]\", \"onUpdateReady\");qg.showModal({ title: \"更新提示\",content: \"新版本已经准备好，是否重启应用?\", success: function (res) { if (res.confirm) { updateManager.applyUpdate() }}})})";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            #endregion

            frameContent += "\n";
            frameContent += "export { UnityModule };";
            File.WriteAllText(Path.Combine(sBuildPath, "MiQGame", $"build.framework.js"), frameContent);

            #region main.js 规则替换

            frameContent = File.ReadAllText(Path.Combine(sBuildPath, "MiQGame", "main.js"));

            //替换版本号
            srcStr = @"window\[""toolVersion""\] =";
            replaceStr = $"window[\"toolVersion\"] = \"{CURRETN_VERSION}\" //";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            //替换游戏名称
            srcStr = "var gameName =";
            replaceStr = $"var gameName = \"{sGameName}\" //";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            //替换游戏版本号
            srcStr = "var gameVersion =";
            replaceStr = $"var gameVersion = \"{sVersion}\" //";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

            //替换md5
            using (var md5 = MD5.Create())
            {
                long timestamp = ((DateTimeOffset)DateTime.UtcNow).ToUnixTimeSeconds();
#if UNITY_2020_3_OR_NEWER
                using (var stream = File.OpenRead(Path.Combine(sBuildPath, "Build", $"{lastPath}.data")))
#elif UNITY_2019
                using (var stream = File.OpenRead(Path.Combine(sBuildPath, "Build", $"{lastPath}.data.unityweb")))
#endif
                {
                    byte[] hash = md5.ComputeHash(stream);
                    var md5Str = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant() + $"_{timestamp}";
                    srcStr = "var dataFileMd5 =";
                    replaceStr = $"var dataFileMd5 = \"{md5Str}\" //";
                    frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
                }

#if UNITY_2020_3_OR_NEWER
                using (var stream = File.OpenRead(Path.Combine(sBuildPath, "Build", $"{lastPath}.wasm")))
#elif UNITY_2019
                using (var stream = File.OpenRead(Path.Combine(sBuildPath, "Build", $"{lastPath}.wasm.code.unityweb")))
#endif
                {
                    byte[] hash = md5.ComputeHash(stream);
                    var md5Str = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant() + $"_{timestamp}";
                    srcStr = "var wasmFileMd5 =";
                    replaceStr = $"var wasmFileMd5 = \"{md5Str}\" //";
                    frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
                }
            }

            if (!string.IsNullOrEmpty(sDataPath))
            {
                sBrotliData = true;

                srcStr = "var localData =";
                replaceStr = "var localData = false //";
                frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
                srcStr = "var dataUrl =";
                replaceStr = $"var dataUrl = \"{sDataPath}\" //";
                frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
            }

            if (!string.IsNullOrEmpty(sWasmPath))
            {
                sBrotliWasm = true;

                srcStr = "var localWasm =";
                replaceStr = "var localWasm = false //";
                frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
                srcStr = "var wasmUrl =";
                replaceStr = $"var wasmUrl = \"{sWasmPath}\" //";
                frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
            }

            if (sBrotliData)
            {
                srcStr = "var dataBrotli =";
                replaceStr = "var dataBrotli = true //";
                frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
            }

            if (sBrotliWasm)
            {
                srcStr = "var wasmBrotli =";
                replaceStr = "var wasmBrotli = true //";
                frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
            }

            if (sStreamRes && !string.IsNullOrEmpty(sStreamAssetPath))
            {
                srcStr = "c.streamingAssetsUrl =";
                replaceStr = $"c.streamingAssetsUrl = \"{sStreamAssetPath}\" //";
                frameContent = Regex.Replace(frameContent, srcStr, replaceStr);
            }

            //替换loading图片
            srcStr = "var loadingUrl = ";
            replaceStr = $"var loadingUrl = \"{sLoadingBG}\" //";
            frameContent = Regex.Replace(frameContent, srcStr, replaceStr);

#if TUANJIE_1_0_OR_NEWER || TUANJIE_2022
            srcStr = "var n = \"UnityWebData1.0\\0\";";
            replaceStr = "var n = \"TuanjieWebData1.0\\0\";";
            frameContent = Regex.Replace(frameContent, Regex.Escape(srcStr), replaceStr);
#endif
            File.WriteAllText(Path.Combine(sBuildPath, "MiQGame", "main.js"), frameContent);
            return true;

            #endregion
        }

        private static bool CopyUnityData()
        {
            var pathList = sBuildPath.Split("/".ToCharArray());
            var lastPath = pathList[pathList.Length - 1];

#if UNITY_2019
            var wasmFF = new FileInfo(Path.Combine(sBuildPath, "Build", $"{lastPath}.wasm.code.unityweb"));
            wasmFF.CopyTo(Path.Combine(sBuildPath, "Build", "build.wasm"), true);
#else
            var wasmFF = new FileInfo(Path.Combine(sBuildPath, "Build", $"{lastPath}.wasm"));
#endif
            if (sBrotliWasm)
            {
                //brotli压缩wasm资源   "Build/build.wasm.br"
#if UNITY_2019 || UNITY_2020
                string sourcePath = "Assets/XIAOMI-minigame/Editor/Tools";
                var workDir = Path.Combine(System.Environment.CurrentDirectory, sourcePath);
                string brotliExePath;
                if (Application.platform == RuntimePlatform.WindowsEditor)
                {
                    brotliExePath = Path.Combine(System.Environment.CurrentDirectory, sourcePath, "brotli.exe");
                }
                else if (Application.platform == RuntimePlatform.OSXEditor)
                {
                    brotliExePath = Path.Combine(System.Environment.CurrentDirectory, sourcePath, "brotli.sh");
                }
                else
                {
                    Debug.LogError("Unsupported platform for brotli compression.");
                    return false;
                }

                string args = Path.Combine(sBuildPath, "Build") + " -wasm";
                var outList = Common.RunCmd(brotliExePath, args, workDir, 1000);
#else
                string sourcePath = wasmFF.FullName;
                string outputPath = Path.Combine(sBuildPath, "Build", "build.wasm.br");
                MiFileCompressor.CompressFileWithBrotli(sourcePath, outputPath);
#endif
            }
            else
            {
                string wasmPath = Path.Combine(sBuildPath, "Build", "build.wasm");
                if (!File.Exists(wasmPath))
                {
                    wasmFF.CopyTo(wasmPath, true);
                }
            }

            if (string.IsNullOrEmpty(sWasmPath))
            {
                if (!sBrotliWasm)
                {
                    wasmFF = new FileInfo(Path.Combine(sBuildPath, "Build", "build.wasm"));
                    wasmFF.CopyTo(Path.Combine(sBuildPath, "MiQGame", "unity", "build.wasm"), true);
                }
                else
                {
                    //复制wasm资源     "unity/build.wasm.br"
                    var wasmBr = new FileInfo(Path.Combine(sBuildPath, "Build", "build.wasm.br"));
                    wasmBr.CopyTo(Path.Combine(sBuildPath, "MiQGame", "unity", "build.wasm.br"), true);
                }
            }

#if UNITY_2019
            var dataFF = new FileInfo(Path.Combine(sBuildPath, "Build", $"{lastPath}.data.unityweb"));
            dataFF.CopyTo(Path.Combine(sBuildPath, "Build", "build.data"), true);
#else
            var dataFF = new FileInfo(Path.Combine(sBuildPath, "Build", $"{lastPath}.data"));
#endif

            if (sBrotliData)
            {
                //brotli压缩data资源   "Build/build.data.br"
#if UNITY_2019 || UNITY_2020
                string sourcePath = "Assets/XIAOMI-minigame/Editor/Tools";
                var workDir = Path.Combine(System.Environment.CurrentDirectory, sourcePath);
                string brotliExePath;
                if (Application.platform == RuntimePlatform.WindowsEditor)
                {
                    brotliExePath = Path.Combine(System.Environment.CurrentDirectory, sourcePath, "brotli.exe");
                }
                else if (Application.platform == RuntimePlatform.OSXEditor)
                {
                    brotliExePath = Path.Combine(System.Environment.CurrentDirectory, sourcePath, "brotli.sh");
                }
                else
                {
                    Debug.LogError("Unsupported platform for brotli compression.");
                    return false;
                }

                string args = Path.Combine(sBuildPath, "Build") + " -data";
                var outList = Common.RunCmd(brotliExePath, args, workDir, 1000);
#else
                string sourcePath = dataFF.FullName;
                string outputPath = Path.Combine(sBuildPath, "Build", "build.data.br");
                MiFileCompressor.CompressFileWithBrotli(sourcePath, outputPath);
#endif
            }
            else
            {
                string dataPath = Path.Combine(sBuildPath, "Build", "build.data");
                if (!File.Exists(dataPath))
                {
                    dataFF.CopyTo(dataPath, true);
                }
            }

            if (string.IsNullOrEmpty(sDataPath))
            {
                if (!sBrotliData)
                {
                    dataFF = new FileInfo(Path.Combine(sBuildPath, "Build", "build.data"));
                    dataFF.CopyTo(Path.Combine(sBuildPath, "MiQGame", "unity", "build.data"), true);
                }
                else
                {
                    //复制data资源     "unity/build.data.br"
                    var dataBr = new FileInfo(Path.Combine(sBuildPath, "Build", "build.data.br"));
                    dataBr.CopyTo(Path.Combine(sBuildPath, "MiQGame", "unity", "build.data.br"), true);
                }
            }

            return true;
        }

        private static bool ArrangeProject()
        {
            Directory.Move(Path.Combine(sBuildPath, "MiQGame", "unity"), Path.Combine(sBuildPath, "MiQGame", "subpackage", "unity"));

            File.Move(Path.Combine(sBuildPath, "MiQGame", "main.js"),
                Path.Combine(sBuildPath, "MiQGame", "subpackage", "main.js"));

            File.Move(Path.Combine(sBuildPath, "MiQGame", "build.framework.js"),
                Path.Combine(sBuildPath, "MiQGame", "subpackage", "build.framework.js"));

            File.Move(Path.Combine(sBuildPath, "MiQGame", "qgame-adapter.js"),
                Path.Combine(sBuildPath, "MiQGame", "subpackage", "qgame-adapter.js"));

            File.Move(Path.Combine(sBuildPath, "MiQGame", "game.js"),
                Path.Combine(sBuildPath, "MiQGame", "main.js"));

            File.Move(Path.Combine(sBuildPath, "MiQGame", "config.json"),
                Path.Combine(sBuildPath, "MiQGame", "subpackage", "config.json"));

            return true;
        }

        private static bool PackageRpk()
        {
            if (Application.platform == RuntimePlatform.WindowsEditor)
            {
                string sourcePath = "Assets/XIAOMI-minigame/Editor/Tools";

                var cmdInstall = Path.Combine(System.Environment.CurrentDirectory, sourcePath, "npm_install.bat");
                cmdInstall = Common.FormatPath(cmdInstall);

                var cmdRelease = Path.Combine(System.Environment.CurrentDirectory, sourcePath, "npm_release.bat");
                cmdRelease = Common.FormatPath(cmdRelease);

                var cmdBuild = Path.Combine(System.Environment.CurrentDirectory, sourcePath, "npm_build.bat");
                cmdBuild = Common.FormatPath(cmdBuild);

                var workDir = Path.Combine(sBuildPath, "MiQGame");
                workDir = Common.FormatPath(workDir);

                var cmdRpk = sRelease ? cmdRelease : cmdBuild;

                var outList = Common.RunCmd(cmdInstall, "", workDir, 60);
                foreach (var log in outList)
                {
                    if (!String.IsNullOrEmpty(log))
                    {
                        UnityEngine.Debug.Log(log);
                    }
                }

                outList = Common.RunCmd(cmdRpk, "", workDir, 30);
                foreach (var log in outList)
                {
                    if (!string.IsNullOrEmpty(log))
                    {
                        if (!log.Contains("Warning:"))
                        {
                            UnityEngine.Debug.Log(log);
                        }
                    }
                }
            }
            else if (Application.platform == RuntimePlatform.OSXEditor)
            {
                UnityEngine.Debug.Log("OSX暂不支持自动打包RPK，请进入转换完成目录手动执行npm打包命令 " +
                    "\n 1. npm install \n 2. Debug RPK： npm run build \n 3. Release RPK： npm run release");
            }

            return true;
        }

#region ===============检查工具版本=================
        private static string pkgPath  = "";
        private static string url      = "http://tennews.cn/unity/";
        private static string infoName = "version.txt";
        private static string versionLog = "";
        private static void GetVersionInfo()
        {
            //本地package包文件夹
            pkgPath = Path.Combine(Application.dataPath, "../") + "/Mi_Tools/";
            if (!Directory.Exists(pkgPath))
            {
                Directory.CreateDirectory(pkgPath);
            }
            EditorCoroutineUtility.StartCoroutineOwnerless(GetRequest(url + infoName));
        }

        static IEnumerator GetRequest(string uri)
        {
            versionLog = "开始获取版本信息...";
            UnityEngine.Debug.Log(uri);
            UnityWebRequest webRequest = UnityWebRequest.Get(uri);
            webRequest.timeout = 10;
            yield return webRequest.SendWebRequest();
#if UNITY_2019
            if (webRequest.isNetworkError ||webRequest.isHttpError)
#else
            if (webRequest.result != UnityWebRequest.Result.Success)
#endif
            {
                versionLog = "获取版本信息失败，请确保服务器配置了版本信息";
                yield break;
            }

            var lastVersion = webRequest.downloadHandler.text;
            versionLog = $"最新版本，{lastVersion}";

            // 解析版本号
            Version latestVersionParsed = ParseVersion(lastVersion);
            Version currentVersionParsed = ParseVersion(CURRETN_VERSION);
            if (currentVersionParsed.CompareTo(latestVersionParsed) >= 0)
            {
                versionLog = "当前已是最新版本";
                yield break;
            }

            string newPkg = $"MiQGameConverter_{webRequest.downloadHandler.text}.unitypackage";
            versionLog = "发现新版本,开始下载..." + url + newPkg;

            UnityWebRequest pkgReq = UnityWebRequest.Get(url + newPkg);
            yield return pkgReq.SendWebRequest();

#if UNITY_2019
            if (pkgReq.isNetworkError ||pkgReq.isHttpError)
#else
            if (pkgReq.result != UnityWebRequest.Result.Success)
#endif
            {
                versionLog = $"下载失败，{pkgReq.error}";
                yield break;
            }

            string savePath = pkgPath + newPkg;
            byte[] resultData = pkgReq.downloadHandler.data;
            FileInfo fileInfo = new FileInfo(savePath);
            FileStream fileStream = fileInfo.Create();
            fileStream.Write(resultData, 0, resultData.Length);
            fileStream.Flush();
            fileStream.Close();
            fileStream.Dispose();

            versionLog = "最新版本下载完成，请手动导入！";
            EditorUtility.OpenWithDefaultApp(pkgPath);
        }

        private static Version ParseVersion(string versionString)
        {
            // 版本号格式为 "主版本.次版本.修订号" 或 "主版本.次版本.修订号后缀"
            var match = Regex.Match(versionString, @"(\d+\.\d+\.\d+)");
            if (match.Success)
            {
                // 提取数字部分（如 "1.4.0"）
                string numericPart = match.Groups[1].Value;
                return new Version(numericPart);
            }
            else
            {
                throw new FormatException("版本号格式不正确");
            }
        }
#endregion
    }
}
#endif