AssetBundleBuilderWindow.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #if UNITY_2019_4_OR_NEWER
  2. using System;
  3. using System.Linq;
  4. using System.Collections.Generic;
  5. using UnityEditor;
  6. using UnityEngine;
  7. using UnityEditor.UIElements;
  8. using UnityEngine.UIElements;
  9. namespace YooAsset.Editor
  10. {
  11. public class AssetBundleBuilderWindow : EditorWindow
  12. {
  13. [MenuItem("YooAsset/AssetBundle Builder", false, 102)]
  14. public static void ShowExample()
  15. {
  16. AssetBundleBuilderWindow window = GetWindow<AssetBundleBuilderWindow>("资源包构建工具", true, EditorDefine.DockedWindowTypes);
  17. window.minSize = new Vector2(800, 600);
  18. }
  19. private BuildTarget _buildTarget;
  20. private List<Type> _encryptionServicesClassTypes;
  21. private List<string> _encryptionServicesClassNames;
  22. private Button _saveButton;
  23. private TextField _buildOutputField;
  24. private IntegerField _buildVersionField;
  25. private EnumField _buildPipelineField;
  26. private EnumField _buildModeField;
  27. private TextField _buildinTagsField;
  28. private PopupField<string> _encryptionField;
  29. private EnumField _compressionField;
  30. private EnumField _outputNameStyleField;
  31. public void CreateGUI()
  32. {
  33. try
  34. {
  35. VisualElement root = this.rootVisualElement;
  36. // 加载布局文件
  37. var visualAsset = EditorHelper.LoadWindowUXML<AssetBundleBuilderWindow>();
  38. if (visualAsset == null)
  39. return;
  40. visualAsset.CloneTree(root);
  41. // 配置保存按钮
  42. _saveButton = root.Q<Button>("SaveButton");
  43. _saveButton.clicked += SaveBtn_clicked;
  44. // 构建平台
  45. _buildTarget = EditorUserBuildSettings.activeBuildTarget;
  46. // 加密服务类
  47. _encryptionServicesClassTypes = GetEncryptionServicesClassTypes();
  48. _encryptionServicesClassNames = _encryptionServicesClassTypes.Select(t => t.FullName).ToList();
  49. // 输出目录
  50. string defaultOutputRoot = AssetBundleBuilderHelper.GetDefaultOutputRoot();
  51. string pipelineOutputDirectory = AssetBundleBuilderHelper.MakePipelineOutputDirectory(defaultOutputRoot, _buildTarget);
  52. _buildOutputField = root.Q<TextField>("BuildOutput");
  53. _buildOutputField.SetValueWithoutNotify(pipelineOutputDirectory);
  54. _buildOutputField.SetEnabled(false);
  55. // 构建版本
  56. _buildVersionField = root.Q<IntegerField>("BuildVersion");
  57. _buildVersionField.SetValueWithoutNotify(AssetBundleBuilderSettingData.Setting.BuildVersion);
  58. _buildVersionField.RegisterValueChangedCallback(evt =>
  59. {
  60. AssetBundleBuilderSettingData.IsDirty = true;
  61. AssetBundleBuilderSettingData.Setting.BuildVersion = _buildVersionField.value;
  62. });
  63. // 构建管线
  64. _buildPipelineField = root.Q<EnumField>("BuildPipeline");
  65. _buildPipelineField.Init(AssetBundleBuilderSettingData.Setting.BuildPipeline);
  66. _buildPipelineField.SetValueWithoutNotify(AssetBundleBuilderSettingData.Setting.BuildPipeline);
  67. _buildPipelineField.style.width = 350;
  68. _buildPipelineField.RegisterValueChangedCallback(evt =>
  69. {
  70. AssetBundleBuilderSettingData.IsDirty = true;
  71. AssetBundleBuilderSettingData.Setting.BuildPipeline = (EBuildPipeline)_buildPipelineField.value;
  72. RefreshWindow();
  73. });
  74. // 构建模式
  75. _buildModeField = root.Q<EnumField>("BuildMode");
  76. _buildModeField.Init(AssetBundleBuilderSettingData.Setting.BuildMode);
  77. _buildModeField.SetValueWithoutNotify(AssetBundleBuilderSettingData.Setting.BuildMode);
  78. _buildModeField.style.width = 350;
  79. _buildModeField.RegisterValueChangedCallback(evt =>
  80. {
  81. AssetBundleBuilderSettingData.IsDirty = true;
  82. AssetBundleBuilderSettingData.Setting.BuildMode = (EBuildMode)_buildModeField.value;
  83. RefreshWindow();
  84. });
  85. // 内置资源标签
  86. _buildinTagsField = root.Q<TextField>("BuildinTags");
  87. _buildinTagsField.SetValueWithoutNotify(AssetBundleBuilderSettingData.Setting.BuildTags);
  88. _buildinTagsField.RegisterValueChangedCallback(evt =>
  89. {
  90. AssetBundleBuilderSettingData.IsDirty = true;
  91. AssetBundleBuilderSettingData.Setting.BuildTags = _buildinTagsField.value;
  92. });
  93. // 加密方法
  94. var encryptionContainer = root.Q("EncryptionContainer");
  95. if (_encryptionServicesClassNames.Count > 0)
  96. {
  97. int defaultIndex = GetEncryptionDefaultIndex(AssetBundleBuilderSettingData.Setting.EncyptionClassName);
  98. _encryptionField = new PopupField<string>(_encryptionServicesClassNames, defaultIndex);
  99. _encryptionField.label = "Encryption";
  100. _encryptionField.style.width = 350;
  101. _encryptionField.RegisterValueChangedCallback(evt =>
  102. {
  103. AssetBundleBuilderSettingData.IsDirty = true;
  104. AssetBundleBuilderSettingData.Setting.EncyptionClassName = _encryptionField.value;
  105. });
  106. encryptionContainer.Add(_encryptionField);
  107. }
  108. else
  109. {
  110. _encryptionField = new PopupField<string>();
  111. _encryptionField.label = "Encryption";
  112. _encryptionField.style.width = 350;
  113. encryptionContainer.Add(_encryptionField);
  114. }
  115. // 压缩方式
  116. _compressionField = root.Q<EnumField>("Compression");
  117. _compressionField.Init(AssetBundleBuilderSettingData.Setting.CompressOption);
  118. _compressionField.SetValueWithoutNotify(AssetBundleBuilderSettingData.Setting.CompressOption);
  119. _compressionField.style.width = 350;
  120. _compressionField.RegisterValueChangedCallback(evt =>
  121. {
  122. AssetBundleBuilderSettingData.IsDirty = true;
  123. AssetBundleBuilderSettingData.Setting.CompressOption = (ECompressOption)_compressionField.value;
  124. });
  125. // 输出文件名称样式
  126. _outputNameStyleField = root.Q<EnumField>("OutputNameStyle");
  127. _outputNameStyleField.Init(AssetBundleBuilderSettingData.Setting.OutputNameStyle);
  128. _outputNameStyleField.SetValueWithoutNotify(AssetBundleBuilderSettingData.Setting.OutputNameStyle);
  129. _outputNameStyleField.style.width = 350;
  130. _outputNameStyleField.RegisterValueChangedCallback(evt =>
  131. {
  132. AssetBundleBuilderSettingData.IsDirty = true;
  133. AssetBundleBuilderSettingData.Setting.OutputNameStyle = (EOutputNameStyle)_outputNameStyleField.value;
  134. });
  135. // 构建按钮
  136. var buildButton = root.Q<Button>("Build");
  137. buildButton.clicked += BuildButton_clicked; ;
  138. RefreshWindow();
  139. }
  140. catch (Exception e)
  141. {
  142. Debug.LogError(e.ToString());
  143. }
  144. }
  145. public void OnDestroy()
  146. {
  147. if(AssetBundleBuilderSettingData.IsDirty)
  148. AssetBundleBuilderSettingData.SaveFile();
  149. }
  150. public void Update()
  151. {
  152. if(_saveButton != null)
  153. {
  154. if(AssetBundleBuilderSettingData.IsDirty)
  155. {
  156. if (_saveButton.enabledSelf == false)
  157. _saveButton.SetEnabled(true);
  158. }
  159. else
  160. {
  161. if(_saveButton.enabledSelf)
  162. _saveButton.SetEnabled(false);
  163. }
  164. }
  165. }
  166. private void RefreshWindow()
  167. {
  168. var buildMode = AssetBundleBuilderSettingData.Setting.BuildMode;
  169. bool enableElement = buildMode == EBuildMode.ForceRebuild;
  170. _buildinTagsField.SetEnabled(enableElement);
  171. _encryptionField.SetEnabled(enableElement);
  172. _compressionField.SetEnabled(enableElement);
  173. _outputNameStyleField.SetEnabled(enableElement);
  174. }
  175. private void SaveBtn_clicked()
  176. {
  177. AssetBundleBuilderSettingData.SaveFile();
  178. }
  179. private void BuildButton_clicked()
  180. {
  181. var buildMode = AssetBundleBuilderSettingData.Setting.BuildMode;
  182. if (EditorUtility.DisplayDialog("提示", $"通过构建模式【{buildMode}】来构建!", "Yes", "No"))
  183. {
  184. EditorTools.ClearUnityConsole();
  185. EditorApplication.delayCall += ExecuteBuild;
  186. }
  187. else
  188. {
  189. Debug.LogWarning("[Build] 打包已经取消");
  190. }
  191. }
  192. /// <summary>
  193. /// 执行构建
  194. /// </summary>
  195. private void ExecuteBuild()
  196. {
  197. string defaultOutputRoot = AssetBundleBuilderHelper.GetDefaultOutputRoot();
  198. BuildParameters buildParameters = new BuildParameters();
  199. buildParameters.OutputRoot = defaultOutputRoot;
  200. buildParameters.BuildTarget = _buildTarget;
  201. buildParameters.BuildPipeline = AssetBundleBuilderSettingData.Setting.BuildPipeline;
  202. buildParameters.BuildMode = AssetBundleBuilderSettingData.Setting.BuildMode;
  203. buildParameters.BuildVersion = AssetBundleBuilderSettingData.Setting.BuildVersion;
  204. buildParameters.BuildinTags = AssetBundleBuilderSettingData.Setting.BuildTags;
  205. buildParameters.VerifyBuildingResult = true;
  206. buildParameters.EnableAddressable = AssetBundleCollectorSettingData.Setting.EnableAddressable;
  207. buildParameters.CopyBuildinTagFiles = AssetBundleBuilderSettingData.Setting.BuildMode == EBuildMode.ForceRebuild;
  208. buildParameters.EncryptionServices = CreateEncryptionServicesInstance();
  209. buildParameters.CompressOption = AssetBundleBuilderSettingData.Setting.CompressOption;
  210. buildParameters.OutputNameStyle = AssetBundleBuilderSettingData.Setting.OutputNameStyle;
  211. if (AssetBundleBuilderSettingData.Setting.BuildPipeline == EBuildPipeline.ScriptableBuildPipeline)
  212. {
  213. buildParameters.SBPParameters = new BuildParameters.SBPBuildParameters();
  214. buildParameters.SBPParameters.WriteLinkXML = true;
  215. }
  216. var builder = new AssetBundleBuilder();
  217. var buildResult = builder.Run(buildParameters);
  218. if (buildResult.Success)
  219. {
  220. EditorUtility.RevealInFinder($"{buildParameters.OutputRoot}/{buildParameters.BuildTarget}/{buildParameters.BuildVersion}");
  221. }
  222. }
  223. // 加密类相关
  224. private int GetEncryptionDefaultIndex(string className)
  225. {
  226. for (int index = 0; index < _encryptionServicesClassNames.Count; index++)
  227. {
  228. if (_encryptionServicesClassNames[index] == className)
  229. {
  230. return index;
  231. }
  232. }
  233. return 0;
  234. }
  235. private List<Type> GetEncryptionServicesClassTypes()
  236. {
  237. return EditorTools.GetAssignableTypes(typeof(IEncryptionServices));
  238. }
  239. private IEncryptionServices CreateEncryptionServicesInstance()
  240. {
  241. if (_encryptionField.index < 0)
  242. return null;
  243. var classType = _encryptionServicesClassTypes[_encryptionField.index];
  244. return (IEncryptionServices)Activator.CreateInstance(classType);
  245. }
  246. }
  247. }
  248. #endif