AssetBundleCollector.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEditor;
  5. using UnityEngine;
  6. namespace YooAsset.Editor
  7. {
  8. [Serializable]
  9. public class AssetBundleCollector
  10. {
  11. /// <summary>
  12. /// 收集路径
  13. /// 注意:支持文件夹或单个资源文件
  14. /// </summary>
  15. public string CollectPath = string.Empty;
  16. /// <summary>
  17. /// 收集器的GUID
  18. /// </summary>
  19. public string CollectorGUID = string.Empty;
  20. /// <summary>
  21. /// 收集器类型
  22. /// </summary>
  23. public ECollectorType CollectorType = ECollectorType.MainAssetCollector;
  24. /// <summary>
  25. /// 寻址规则类名
  26. /// </summary>
  27. public string AddressRuleName = nameof(AddressByFileName);
  28. /// <summary>
  29. /// 打包规则类名
  30. /// </summary>
  31. public string PackRuleName = nameof(PackDirectory);
  32. /// <summary>
  33. /// 过滤规则类名
  34. /// </summary>
  35. public string FilterRuleName = nameof(CollectAll);
  36. /// <summary>
  37. /// 资源分类标签
  38. /// </summary>
  39. public string AssetTags = string.Empty;
  40. /// <summary>
  41. /// 收集器是否有效
  42. /// </summary>
  43. public bool IsValid()
  44. {
  45. if (AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(CollectPath) == null)
  46. return false;
  47. if (CollectorType == ECollectorType.None)
  48. return false;
  49. if (AssetBundleCollectorSettingData.HasAddressRuleName(AddressRuleName) == false)
  50. return false;
  51. if (AssetBundleCollectorSettingData.HasPackRuleName(PackRuleName) == false)
  52. return false;
  53. if (AssetBundleCollectorSettingData.HasFilterRuleName(FilterRuleName) == false)
  54. return false;
  55. return true;
  56. }
  57. /// <summary>
  58. /// 检测配置错误
  59. /// </summary>
  60. public void CheckConfigError()
  61. {
  62. string assetGUID = AssetDatabase.AssetPathToGUID(CollectPath);
  63. if (string.IsNullOrEmpty(assetGUID))
  64. throw new Exception($"Invalid collect path : {CollectPath}");
  65. if (CollectorType == ECollectorType.None)
  66. throw new Exception($"{nameof(ECollectorType)}.{ECollectorType.None} is invalid in collector : {CollectPath}");
  67. if (AssetBundleCollectorSettingData.HasPackRuleName(PackRuleName) == false)
  68. throw new Exception($"Invalid {nameof(IPackRule)} class type : {PackRuleName} in collector : {CollectPath}");
  69. if (AssetBundleCollectorSettingData.HasFilterRuleName(FilterRuleName) == false)
  70. throw new Exception($"Invalid {nameof(IFilterRule)} class type : {FilterRuleName} in collector : {CollectPath}");
  71. if (AssetBundleCollectorSettingData.HasAddressRuleName(AddressRuleName) == false)
  72. throw new Exception($"Invalid {nameof(IAddressRule)} class type : {AddressRuleName} in collector : {CollectPath}");
  73. }
  74. /// <summary>
  75. /// 修复配置错误
  76. /// </summary>
  77. public bool FixConfigError()
  78. {
  79. bool isFixed = false;
  80. if (string.IsNullOrEmpty(CollectorGUID) == false)
  81. {
  82. string convertAssetPath = AssetDatabase.GUIDToAssetPath(CollectorGUID);
  83. if (string.IsNullOrEmpty(convertAssetPath))
  84. {
  85. Debug.LogWarning($"Collector GUID {CollectorGUID} is invalid and has been auto removed !");
  86. CollectorGUID = string.Empty;
  87. isFixed = true;
  88. }
  89. else
  90. {
  91. if (CollectPath != convertAssetPath)
  92. {
  93. CollectPath = convertAssetPath;
  94. isFixed = true;
  95. Debug.LogWarning($"Fix collect path : {CollectPath} -> {convertAssetPath}");
  96. }
  97. }
  98. }
  99. /*
  100. string convertGUID = AssetDatabase.AssetPathToGUID(CollectPath);
  101. if(string.IsNullOrEmpty(convertGUID) == false)
  102. {
  103. CollectorGUID = convertGUID;
  104. }
  105. */
  106. return isFixed;
  107. }
  108. /// <summary>
  109. /// 获取打包收集的资源文件
  110. /// </summary>
  111. public List<CollectAssetInfo> GetAllCollectAssets(EBuildMode buildMode, AssetBundleCollectorGroup group)
  112. {
  113. // 注意:模拟构建模式下只收集主资源
  114. if (buildMode == EBuildMode.SimulateBuild)
  115. {
  116. if (CollectorType != ECollectorType.MainAssetCollector)
  117. return new List<CollectAssetInfo>();
  118. }
  119. Dictionary<string, CollectAssetInfo> result = new Dictionary<string, CollectAssetInfo>(1000);
  120. bool isRawAsset = PackRuleName == nameof(PackRawFile);
  121. // 检测原生资源包的收集器类型
  122. if (isRawAsset && CollectorType != ECollectorType.MainAssetCollector)
  123. throw new Exception($"The raw file must be set to {nameof(ECollectorType)}.{ECollectorType.MainAssetCollector} : {CollectPath}");
  124. if (string.IsNullOrEmpty(CollectPath))
  125. throw new Exception($"The collect path is null or empty in group : {group.GroupName}");
  126. // 收集打包资源
  127. if (AssetDatabase.IsValidFolder(CollectPath))
  128. {
  129. string collectDirectory = CollectPath;
  130. string[] findAssets = EditorTools.FindAssets(EAssetSearchType.All, collectDirectory);
  131. foreach (string assetPath in findAssets)
  132. {
  133. if (IsValidateAsset(assetPath) && IsCollectAsset(assetPath))
  134. {
  135. if (result.ContainsKey(assetPath) == false)
  136. {
  137. var collectAssetInfo = CreateCollectAssetInfo(buildMode, group, assetPath, isRawAsset);
  138. result.Add(assetPath, collectAssetInfo);
  139. }
  140. else
  141. {
  142. throw new Exception($"The collecting asset file is existed : {assetPath} in collector : {CollectPath}");
  143. }
  144. }
  145. }
  146. }
  147. else
  148. {
  149. string assetPath = CollectPath;
  150. if (IsValidateAsset(assetPath) && IsCollectAsset(assetPath))
  151. {
  152. var collectAssetInfo = CreateCollectAssetInfo(buildMode, group, assetPath, isRawAsset);
  153. result.Add(assetPath, collectAssetInfo);
  154. }
  155. else
  156. {
  157. throw new Exception($"The collecting single asset file is invalid : {assetPath} in collector : {CollectPath}");
  158. }
  159. }
  160. // 检测可寻址地址是否重复
  161. if (AssetBundleCollectorSettingData.Setting.EnableAddressable)
  162. {
  163. HashSet<string> adressTemper = new HashSet<string>();
  164. foreach (var collectInfoPair in result)
  165. {
  166. if (collectInfoPair.Value.CollectorType == ECollectorType.MainAssetCollector)
  167. {
  168. string address = collectInfoPair.Value.Address;
  169. if (adressTemper.Contains(address) == false)
  170. adressTemper.Add(address);
  171. else
  172. throw new Exception($"The address is existed : {address} in collector : {CollectPath}");
  173. }
  174. }
  175. }
  176. // 返回列表
  177. return result.Values.ToList();
  178. }
  179. private CollectAssetInfo CreateCollectAssetInfo(EBuildMode buildMode, AssetBundleCollectorGroup group, string assetPath, bool isRawAsset)
  180. {
  181. string address = GetAddress(group, assetPath);
  182. string bundleName = GetBundleName(group, assetPath);
  183. List<string> assetTags = GetAssetTags(group);
  184. CollectAssetInfo collectAssetInfo = new CollectAssetInfo(CollectorType, bundleName, address, assetPath, assetTags, isRawAsset);
  185. // 注意:模拟构建模式下不需要收集依赖资源
  186. if (buildMode == EBuildMode.SimulateBuild)
  187. collectAssetInfo.DependAssets = new List<string>();
  188. else
  189. collectAssetInfo.DependAssets = GetAllDependencies(assetPath);
  190. return collectAssetInfo;
  191. }
  192. private bool IsValidateAsset(string assetPath)
  193. {
  194. if (assetPath.StartsWith("Assets/") == false && assetPath.StartsWith("Packages/") == false)
  195. {
  196. UnityEngine.Debug.LogError($"Invalid asset path : {assetPath}");
  197. return false;
  198. }
  199. // 忽略文件夹
  200. if (AssetDatabase.IsValidFolder(assetPath))
  201. return false;
  202. // 忽略编辑器下的类型资源
  203. Type type = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
  204. if (type == typeof(LightingDataAsset))
  205. return false;
  206. // 忽略Unity无法识别的无效文件
  207. /*
  208. if (type == typeof(UnityEditor.DefaultAsset))
  209. {
  210. UnityEngine.Debug.LogWarning($"Cannot pack default asset : {assetPath}");
  211. return false;
  212. }
  213. */
  214. string fileExtension = System.IO.Path.GetExtension(assetPath);
  215. if (IsIgnoreFile(fileExtension))
  216. return false;
  217. return true;
  218. }
  219. private bool IsIgnoreFile(string fileExtension)
  220. {
  221. foreach (var extension in YooAssetSettings.IgnoreFileExtensions)
  222. {
  223. if (extension == fileExtension)
  224. return true;
  225. }
  226. return false;
  227. }
  228. private bool IsCollectAsset(string assetPath)
  229. {
  230. Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
  231. if (assetType == typeof(UnityEngine.Shader))
  232. return true;
  233. // 根据规则设置过滤资源文件
  234. IFilterRule filterRuleInstance = AssetBundleCollectorSettingData.GetFilterRuleInstance(FilterRuleName);
  235. return filterRuleInstance.IsCollectAsset(new FilterRuleData(assetPath));
  236. }
  237. private string GetAddress(AssetBundleCollectorGroup group, string assetPath)
  238. {
  239. if (CollectorType != ECollectorType.MainAssetCollector)
  240. return string.Empty;
  241. IAddressRule addressRuleInstance = AssetBundleCollectorSettingData.GetAddressRuleInstance(AddressRuleName);
  242. string adressValue = addressRuleInstance.GetAssetAddress(new AddressRuleData(assetPath, CollectPath, group.GroupName));
  243. return adressValue;
  244. }
  245. private string GetBundleName(AssetBundleCollectorGroup group, string assetPath)
  246. {
  247. System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
  248. if (assetType == typeof(UnityEngine.Shader))
  249. {
  250. return EditorTools.GetRegularPath(YooAssetSettings.UnityShadersBundleName).ToLower();
  251. }
  252. // 根据规则设置获取资源包名称
  253. IPackRule packRuleInstance = AssetBundleCollectorSettingData.GetPackRuleInstance(PackRuleName);
  254. string bundleName = packRuleInstance.GetBundleName(new PackRuleData(assetPath, CollectPath, group.GroupName));
  255. return EditorTools.GetRegularPath(bundleName).ToLower();
  256. }
  257. private List<string> GetAssetTags(AssetBundleCollectorGroup group)
  258. {
  259. List<string> tags = StringUtility.StringToStringList(group.AssetTags, ';');
  260. List<string> temper = StringUtility.StringToStringList(AssetTags, ';');
  261. tags.AddRange(temper);
  262. return tags;
  263. }
  264. private List<string> GetAllDependencies(string mainAssetPath)
  265. {
  266. List<string> result = new List<string>();
  267. string[] depends = AssetDatabase.GetDependencies(mainAssetPath, true);
  268. foreach (string assetPath in depends)
  269. {
  270. if (IsValidateAsset(assetPath))
  271. {
  272. // 注意:排除主资源对象
  273. if (assetPath != mainAssetPath)
  274. result.Add(assetPath);
  275. }
  276. }
  277. return result;
  278. }
  279. }
  280. }