using HybridCLR.Editor; using HybridCLR.Editor.Commands; using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEditor.Compilation; using UnityEngine; using Debug = UnityEngine.Debug; namespace ET { public enum PlatformType { None, Android, IOS, Windows, MacOS, Linux } public enum BuildType { Development, Release, } public class BuildEditor : EditorWindow { private PlatformType activePlatform; private PlatformType platformType; private bool clearFolder = true; private bool isBuildExe = true; private bool isContainAB = false; private CodeOptimization codeOptimization = CodeOptimization.Debug; private BuildOptions buildOptions; private BuildAssetBundleOptions buildAssetBundleOptions = BuildAssetBundleOptions.None; public static string YooAssetCodeDll; private GlobalConfig globalConfig; [MenuItem("ET/Build Tool")] public static void ShowWindow() { GetWindow(DockDefine.Types); } private void OnEnable() { YooAssetCodeDll = Application.dataPath + "/Res/CodeDll/"; globalConfig = Resources.Load("GlobalConfig"); #if UNITY_ANDROID activePlatform = PlatformType.Android; #elif UNITY_IOS activePlatform = PlatformType.IOS; #elif UNITY_STANDALONE_WIN activePlatform = PlatformType.Windows; #elif UNITY_STANDALONE_OSX activePlatform = PlatformType.MacOS; #elif UNITY_STANDALONE_LINUX activePlatform = PlatformType.Linux; #else activePlatform = PlatformType.None; #endif platformType = activePlatform; } private void OnGUI() { this.platformType = (PlatformType)EditorGUILayout.EnumPopup(platformType); this.clearFolder = EditorGUILayout.Toggle("clean folder? ", clearFolder); this.isBuildExe = EditorGUILayout.Toggle("build exe?", this.isBuildExe); this.isContainAB = false; this.codeOptimization = (CodeOptimization)EditorGUILayout.EnumPopup("CodeOptimization ", this.codeOptimization); //EditorGUILayout.LabelField("BuildAssetBundleOptions "); //this.buildAssetBundleOptions = (BuildAssetBundleOptions)EditorGUILayout.EnumFlagsField(this.buildAssetBundleOptions); switch (this.codeOptimization) { case CodeOptimization.None: case CodeOptimization.Debug: this.buildOptions = BuildOptions.Development | BuildOptions.ConnectWithProfiler; break; case CodeOptimization.Release: this.buildOptions = BuildOptions.None; break; } GUILayout.Space(5); if (GUILayout.Button("BuildPackage")) { if (this.platformType == PlatformType.None) { ShowNotification(new GUIContent("please select platform!")); return; } if (platformType != activePlatform) { switch (EditorUtility.DisplayDialogComplex("Warning!", $"current platform is {activePlatform}, if change to {platformType}, may be take a long time", "change", "cancel", "no change")) { case 0: activePlatform = platformType; break; case 1: return; case 2: platformType = activePlatform; break; } } //生成exe之前,先生成最新的link.xml BuildModelAndHotfix(this.codeOptimization); CopyHotfixdllToHybridDir(); LinkGeneratorCommand.GenerateLinkXml(EditorUserBuildSettings.activeBuildTarget); BuildHelper.Build(this.platformType, this.buildAssetBundleOptions, this.buildOptions, this.isBuildExe, this.isContainAB, this.clearFolder); } GUILayout.Label(""); GUILayout.Label("Build & copy AOTMetadlls"); if (GUILayout.Button("BuildAOTDlls & copy ")) { BuildTarget target = EditorUserBuildSettings.activeBuildTarget; CompileDllCommand.CompileDll(target); CopyHotfixdllToHybridDir(); Il2CppDefGeneratorCommand.GenerateIl2CppDef(); // 这几个生成依赖HotUpdateDlls //LinkGeneratorCommand.GenerateLinkXml(target); // 生成裁剪后的aot dll StripAOTDllCommand.GenerateStripedAOTDlls(target, EditorUserBuildSettings.selectedBuildTargetGroup); // 桥接函数生成依赖于AOT dll,必须保证已经build过,生成AOT dll MethodBridgeGeneratorCommand.GenerateMethodBridge(target); ReversePInvokeWrapperGeneratorCommand.GenerateReversePInvokeWrapper(target); AOTReferenceGeneratorCommand.GenerateAOTGenericReference(target); string aotDllDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target); HotUpdateAssemblyManifest manifest = AssetDatabase.LoadAssetAtPath("Assets/Res/Config/HotUpdateAssemblyManifest.asset", typeof(HotUpdateAssemblyManifest)) as HotUpdateAssemblyManifest; if (manifest == null) { throw new Exception($"resource asset:{nameof(HotUpdateAssemblyManifest)} 配置不存在,请在Resources目录下创建"); } List AOTMetaAssemblies = (manifest.AOTMetadataDlls ?? Array.Empty()).ToList(); foreach (var dll in AOTMetaAssemblies) { string dllPath = $"{aotDllDir}/{dll}"; if (!File.Exists(dllPath)) { Debug.LogError($"ab中添加AOT补充元数据dll:{dllPath} 时发生错误,文件不存在。裁剪后的AOT dll在BuildPlayer时才能生成,因此需要你先构建一次游戏App后再打包。"); continue; } string dllBytesPath = $"{YooAssetCodeDll}/{dll}.bytes"; File.Copy(dllPath, dllBytesPath, true); Debug.Log($"copy AOT dll {dllPath} -> {dllBytesPath}"); } } GUILayout.Label(""); GUILayout.Label("Build热更dll & ab:"); this.globalConfig.CodeMode = CodeMode.Client;// (CodeMode)EditorGUILayout.EnumPopup("CodeMode: ", this.globalConfig.CodeMode); if (GUILayout.Button("BuildModelAndHotfix")) { BuildModelAndHotfix(this.codeOptimization); //用yooAsset打ab, 不用你了 //AfterCompiling(); ShowNotification("Build Model And Hotfix Success!"); } if (GUILayout.Button("BuildAB by YooAsset")) { var target = EditorUserBuildSettings.activeBuildTarget; BuildHelper.BuildAB(target, null); } GUILayout.Label(""); GUILayout.Label("Config Tools: ======================="); if (GUILayout.Button("ExcelExporter")) { //Directory.Delete("Assets/Bundles/Config", true); ToolsEditor.ExcelExporter(); // 设置ab包 AssetImporter assetImporter = AssetImporter.GetAtPath($"Assets/Bundles/Config"); assetImporter.assetBundleName = "Config.unity3d"; AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } if (GUILayout.Button("Proto2CS")) { ToolsEditor.Proto2CS(); } GUILayout.Space(5); } private static void CopyHotfixdllToHybridDir() { var target = EditorUserBuildSettings.activeBuildTarget; ; var dll = Path.Combine(YooAssetCodeDll, "Model.dll.bytes"); if (!File.Exists(dll)) { Debug.LogError($"not exists: {dll}"); } else { File.Copy(dll, Path.Combine(SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target), "Model.dll"), true); } dll = Path.Combine(YooAssetCodeDll, "Hotfix.dll.bytes"); if (!File.Exists(dll)) { Debug.LogError($"not exists: {dll}"); } else { File.Copy(dll, Path.Combine(SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target), "Hotfix.dll"), true); } } public static void BuildModelAndHotfix(CodeOptimization codeOptimization = CodeOptimization.Release) { if (Define.EnableCodes) { throw new Exception("Remove macro 'ENABLE_CODES' first!"); } var globalConfig = Resources.Load("GlobalConfig"); if (globalConfig.CodeMode == CodeMode.Server) { throw new Exception("Don't compile server here, open 'ET.sln' to compile!"); } BuildAssembliesHelper.BuildModel(codeOptimization, globalConfig); BuildAssembliesHelper.BuildHotfix(codeOptimization, globalConfig); } //将model.dll打包成ab /*private static void AfterCompiling() { Directory.CreateDirectory(BuildAssembliesHelper.CodeDir); // 设置ab包 AssetImporter assetImporter = AssetImporter.GetAtPath("Assets/Bundles/Code"); assetImporter.assetBundleName = "Code.unity3d"; AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Debug.Log("build success!"); }*/ public static void ShowNotification(string tips) { EditorWindow game = EditorWindow.GetWindow(typeof(EditorWindow).Assembly.GetType("UnityEditor.GameView")); game?.ShowNotification(new GUIContent($"{tips}")); } } }