BuildEditor.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. using HybridCLR.Editor;
  2. using HybridCLR.Editor.Commands;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using UnityEditor;
  8. using UnityEditor.Compilation;
  9. using UnityEngine;
  10. using Debug = UnityEngine.Debug;
  11. namespace ET
  12. {
  13. public enum PlatformType
  14. {
  15. None,
  16. Android,
  17. IOS,
  18. Windows,
  19. MacOS,
  20. Linux
  21. }
  22. public enum BuildType
  23. {
  24. Development,
  25. Release,
  26. }
  27. public class BuildEditor : EditorWindow
  28. {
  29. private PlatformType activePlatform;
  30. private PlatformType platformType;
  31. private bool clearFolder = true;
  32. private bool isBuildExe = true;
  33. private bool isContainAB = false;
  34. private CodeOptimization codeOptimization = CodeOptimization.Release;
  35. private BuildOptions buildOptions;
  36. private BuildAssetBundleOptions buildAssetBundleOptions = BuildAssetBundleOptions.None;
  37. public static string YooAssetCodeDll;
  38. public static string BattlePluginDir = "./Assets/Plugins/BattlePlugin";
  39. private GlobalConfig globalConfig;
  40. [MenuItem("ET/Build Tool")]
  41. public static void ShowWindow()
  42. {
  43. GetWindow<BuildEditor>(DockDefine.Types);
  44. }
  45. private void OnEnable()
  46. {
  47. YooAssetCodeDll = Application.dataPath + "/Res/CodeDll/";
  48. globalConfig = Resources.Load<GlobalConfig>("GlobalConfig");
  49. #if UNITY_ANDROID
  50. activePlatform = PlatformType.Android;
  51. #elif UNITY_IOS
  52. activePlatform = PlatformType.IOS;
  53. #elif UNITY_STANDALONE_WIN
  54. activePlatform = PlatformType.Windows;
  55. #elif UNITY_STANDALONE_OSX
  56. activePlatform = PlatformType.MacOS;
  57. #elif UNITY_STANDALONE_LINUX
  58. activePlatform = PlatformType.Linux;
  59. #else
  60. activePlatform = PlatformType.None;
  61. #endif
  62. platformType = activePlatform;
  63. }
  64. private void OnGUI()
  65. {
  66. this.platformType = (PlatformType)EditorGUILayout.EnumPopup(platformType);
  67. this.clearFolder = EditorGUILayout.Toggle("clean folder? ", clearFolder);
  68. this.isBuildExe = EditorGUILayout.Toggle("build exe?", this.isBuildExe);
  69. this.isContainAB = false;
  70. this.codeOptimization = (CodeOptimization)EditorGUILayout.EnumPopup("CodeOptimization ", this.codeOptimization);
  71. //EditorGUILayout.LabelField("BuildAssetBundleOptions ");
  72. //this.buildAssetBundleOptions = (BuildAssetBundleOptions)EditorGUILayout.EnumFlagsField(this.buildAssetBundleOptions);
  73. switch (this.codeOptimization)
  74. {
  75. case CodeOptimization.None:
  76. case CodeOptimization.Debug:
  77. this.buildOptions = BuildOptions.Development | BuildOptions.ConnectWithProfiler;
  78. break;
  79. case CodeOptimization.Release:
  80. this.buildOptions = BuildOptions.None;
  81. break;
  82. }
  83. GUILayout.Space(5);
  84. if (GUILayout.Button("BuildPackage"))
  85. {
  86. if (this.platformType == PlatformType.None)
  87. {
  88. ShowNotification(new GUIContent("please select platform!"));
  89. return;
  90. }
  91. var globalConfig = Resources.Load<GlobalConfig>("GlobalConfig");
  92. if (globalConfig.CodeMode == CodeMode.Server)
  93. {
  94. ShowNotification(new GUIContent("not supoort CodeMode: Server!"));
  95. return;
  96. }
  97. if (globalConfig.PlayMode == YooAsset.YooAssets.EPlayMode.EditorSimulateMode)
  98. {
  99. ShowNotification(new GUIContent("YooAsset.PlayMode not support EditorSimulateMode!"));
  100. return;
  101. }
  102. if (platformType != activePlatform)
  103. {
  104. switch (EditorUtility.DisplayDialogComplex("Warning!", $"current platform is {activePlatform}, if change to {platformType}, may be take a long time", "change", "cancel", "no change"))
  105. {
  106. case 0:
  107. activePlatform = platformType;
  108. break;
  109. case 1:
  110. return;
  111. case 2:
  112. platformType = activePlatform;
  113. break;
  114. }
  115. }
  116. RemoveBattlePluginDlls();
  117. BuildHelper.Build(this.platformType, this.buildAssetBundleOptions, this.buildOptions, this.isBuildExe, this.isContainAB, this.clearFolder);
  118. }
  119. GUILayout.Label("");
  120. GUILayout.Label("Build & copy AOTMetadlls");
  121. if (GUILayout.Button("Hybrid-GenerateAll & copy2CodeDll"))
  122. {
  123. //CompileDll时,HotUpdateDll目录的model.dll会被清理掉,生成link.xml会报错
  124. //所以在compileDll后,增加了BuildModel & copy动作
  125. //PrebuildCommand.GenerateAll();
  126. //删除battle相关dll
  127. RemoveBattlePluginDlls();
  128. BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
  129. CompileDllCommand.CompileDll(target);
  130. //生成最新的mode.dll & hotfix.dll,然后copy到hotupdate目录,供linkxml用
  131. BuildModelAndHotfix(this.codeOptimization);
  132. CopyHotfixdllToHybridDir();
  133. Il2CppDefGeneratorCommand.GenerateIl2CppDef();
  134. // 这几个生成依赖HotUpdateDlls
  135. LinkGeneratorCommand.GenerateLinkXml(target);
  136. // 生成裁剪后的aot dll
  137. StripAOTDllCommand.GenerateStripedAOTDlls(target, EditorUserBuildSettings.selectedBuildTargetGroup);
  138. // 桥接函数生成依赖于AOT dll,必须保证已经build过,生成AOT dll
  139. MethodBridgeGeneratorCommand.GenerateMethodBridge(target);
  140. ReversePInvokeWrapperGeneratorCommand.GenerateReversePInvokeWrapper(target);
  141. AOTReferenceGeneratorCommand.GenerateAOTGenericReference(target);
  142. string aotDllDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target);
  143. ConfigStringList manifest = AssetDatabase.LoadAssetAtPath("Assets/Res/Config/HotUpdateAOTDlls.asset", typeof(ConfigStringList)) as ConfigStringList;
  144. if (manifest == null)
  145. {
  146. throw new Exception($"Assets/Res/Config/HotUpdateAOTDlls 配置不存在");
  147. }
  148. List<string> AOTMetaAssemblies = (manifest.List ?? Array.Empty<string>()).ToList();
  149. foreach (var dll in AOTMetaAssemblies)
  150. {
  151. string dllPath = $"{aotDllDir}/{dll}";
  152. if (!File.Exists(dllPath))
  153. {
  154. Debug.LogError($"ab中添加AOT补充元数据dll:{dllPath} 时发生错误,文件不存在。裁剪后的AOT dll在BuildPlayer时才能生成,因此需要你先构建一次游戏App后再打包。");
  155. continue;
  156. }
  157. string dllBytesPath = $"{YooAssetCodeDll}/{dll}.bytes";
  158. File.Copy(dllPath, dllBytesPath, true);
  159. Debug.Log($"copy AOT dll {dllPath} -> {dllBytesPath}");
  160. }
  161. }
  162. GUILayout.Label("");
  163. GUILayout.Label("Build热更dll & ab:");
  164. this.globalConfig.CodeMode = CodeMode.Client;// (CodeMode)EditorGUILayout.EnumPopup("CodeMode: ", this.globalConfig.CodeMode);
  165. if (GUILayout.Button("BuildModelAndHotfix"))
  166. {
  167. BuildModelAndHotfix(this.codeOptimization);
  168. //用yooAsset打ab, 不用你了
  169. //AfterCompiling();
  170. ShowNotification("Build Model And Hotfix Success!");
  171. }
  172. if (GUILayout.Button("BuildAB by YooAsset"))
  173. {
  174. var target = EditorUserBuildSettings.activeBuildTarget;
  175. BuildHelper.BuildAB(target, null);
  176. }
  177. GUILayout.Label("");
  178. GUILayout.Label("Config Tools: =======================");
  179. if (GUILayout.Button("ExcelExporter"))
  180. {
  181. //Directory.Delete("Assets/Bundles/Config", true);
  182. ToolsEditor.ExcelExporter();
  183. }
  184. if (GUILayout.Button("Proto2CS"))
  185. {
  186. ToolsEditor.Proto2CS();
  187. }
  188. GUILayout.Space(5);
  189. }
  190. //在打包前删除战斗相关dll
  191. //因为战斗dll是需要支持热更的,放在plugin目录的话,所有程序集都会自动引用
  192. //为了排除战斗dll被主工程打进包带来的各种问题,删除之以防万一
  193. private static void RemoveBattlePluginDlls()
  194. {
  195. var list = AssetDatabase.LoadAssetAtPath("Assets/Res/Config/HotupdateBattleDlls.asset", typeof(ConfigStringList)) as ConfigStringList;
  196. if (list == null)
  197. {
  198. throw new Exception($"Assets/Res/Config/HotupdateBattleDlls 配置不存在");
  199. }
  200. foreach (var dll in list.List)
  201. {
  202. var file = Path.Combine(BattlePluginDir, dll);
  203. File.Delete(file);
  204. Debug.Log($"delete dll {file}");
  205. }
  206. AssetDatabase.Refresh();
  207. }
  208. private static void CopyHotfixdllToHybridDir()
  209. {
  210. var target = EditorUserBuildSettings.activeBuildTarget;
  211. ConfigKeyValueMap manifest = AssetDatabase.LoadAssetAtPath("Assets/Res/Config/HotupdateDlls.asset", typeof(ConfigKeyValueMap)) as ConfigKeyValueMap;
  212. if (manifest == null)
  213. {
  214. throw new Exception($"Assets/Res/Config/HotupdateDlls 配置不存在");
  215. }
  216. foreach (var kvs in manifest.keyValueMaps)
  217. {
  218. var bytes = Path.Combine(YooAssetCodeDll, $"{kvs.Key}.bytes");
  219. if (!File.Exists(bytes))
  220. {
  221. Debug.LogError($"not exists: {bytes}");
  222. }
  223. else
  224. {
  225. File.Copy(bytes, Path.Combine(SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target), kvs.Key), true);
  226. Debug.Log($"copy hot dll {bytes} -> to dir: HotUpdateDlls");
  227. }
  228. }
  229. var list = AssetDatabase.LoadAssetAtPath("Assets/Res/Config/HotupdateBattleDlls.asset", typeof(ConfigStringList)) as ConfigStringList;
  230. if (list == null)
  231. {
  232. throw new Exception($"Assets/Res/Config/HotupdateBattleDlls 配置不存在");
  233. }
  234. foreach (var dll in list.List)
  235. {
  236. var bytes = Path.Combine(YooAssetCodeDll, $"{dll}.bytes");
  237. if (!File.Exists(bytes))
  238. {
  239. Debug.LogError($"not exists: {bytes}");
  240. }
  241. else
  242. {
  243. File.Copy(bytes, Path.Combine(SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target), dll), true);
  244. Debug.Log($"copy hot dll {bytes} -> to dir: HotUpdateDlls");
  245. }
  246. }
  247. }
  248. public static void BuildModelAndHotfix(CodeOptimization codeOptimization = CodeOptimization.Release)
  249. {
  250. if (Define.EnableCodes)
  251. {
  252. throw new Exception("Remove macro 'ENABLE_CODES' first!");
  253. }
  254. var globalConfig = Resources.Load<GlobalConfig>("GlobalConfig");
  255. if (globalConfig.CodeMode == CodeMode.Server)
  256. {
  257. throw new Exception("Don't compile server here, open 'ET.sln' to compile!");
  258. }
  259. BuildAssembliesHelper.BuildModel(codeOptimization, globalConfig);
  260. BuildAssembliesHelper.BuildHotfix(codeOptimization, globalConfig);
  261. BuildAssembliesHelper.BuildMuteAssembly("Unity.Mono", new List<string>() { "Assets/Scripts/Codes/Mono/" }, Array.Empty<string>(), codeOptimization, globalConfig.CodeMode);
  262. File.Copy(Path.Combine(Define.BuildOutputDir, "Unity.Mono.dll"), Path.Combine(YooAssetCodeDll, $"Unity.Mono.dll.bytes"), true);
  263. File.Copy(Path.Combine(Define.BuildOutputDir, "Unity.Mono.pdb"), Path.Combine(YooAssetCodeDll, $"Unity.Mono.pdb.bytes"), true);
  264. Debug.Log("copy Unity.Mono.dll to Assets/Res/CodeDll success!");
  265. }
  266. //将model.dll打包成ab
  267. /*private static void AfterCompiling()
  268. {
  269. Directory.CreateDirectory(BuildAssembliesHelper.CodeDir);
  270. // 设置ab包
  271. AssetImporter assetImporter = AssetImporter.GetAtPath("Assets/Bundles/Code");
  272. assetImporter.assetBundleName = "Code.unity3d";
  273. AssetDatabase.SaveAssets();
  274. AssetDatabase.Refresh();
  275. Debug.Log("build success!");
  276. }*/
  277. public static void ShowNotification(string tips)
  278. {
  279. EditorWindow game = EditorWindow.GetWindow(typeof(EditorWindow).Assembly.GetType("UnityEditor.GameView"));
  280. game?.ShowNotification(new GUIContent($"{tips}"));
  281. }
  282. }
  283. }