TaskGetBuildMap.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using UnityEditor;
  7. namespace YooAsset.Editor
  8. {
  9. [TaskAttribute("获取资源构建内容")]
  10. public class TaskGetBuildMap : IBuildTask
  11. {
  12. void IBuildTask.Run(BuildContext context)
  13. {
  14. var buildParametersContext = context.GetContextObject<BuildParametersContext>();
  15. var buildMapContext = CreateBuildMap(buildParametersContext.Parameters);
  16. context.SetContextObject(buildMapContext);
  17. BuildLogger.Log("构建内容准备完毕!");
  18. // 检测构建结果
  19. CheckBuildMapContent(buildMapContext);
  20. }
  21. /// <summary>
  22. /// 资源构建上下文
  23. /// </summary>
  24. public BuildMapContext CreateBuildMap(BuildParameters buildParameters)
  25. {
  26. var buildMode = buildParameters.BuildMode;
  27. var packageName = buildParameters.PackageName;
  28. var sharedPackRule = buildParameters.SharedPackRule;
  29. Dictionary<string, BuildAssetInfo> allBuildAssetInfoDic = new Dictionary<string, BuildAssetInfo>(1000);
  30. // 1. 检测配置合法性
  31. AssetBundleCollectorSettingData.Setting.CheckPackageConfigError(packageName);
  32. // 2. 获取所有收集器收集的资源
  33. var collectResult = AssetBundleCollectorSettingData.Setting.GetPackageAssets(buildMode, packageName);
  34. List<CollectAssetInfo> allCollectAssetInfos = collectResult.CollectAssets;
  35. // 3. 剔除未被引用的依赖项资源
  36. RemoveZeroReferenceAssets(allCollectAssetInfos);
  37. // 4. 录入所有收集器收集的资源
  38. foreach (var collectAssetInfo in allCollectAssetInfos)
  39. {
  40. if (allBuildAssetInfoDic.ContainsKey(collectAssetInfo.AssetPath) == false)
  41. {
  42. var buildAssetInfo = new BuildAssetInfo(collectAssetInfo.CollectorType, collectAssetInfo.BundleName,
  43. collectAssetInfo.Address, collectAssetInfo.AssetPath, collectAssetInfo.IsRawAsset);
  44. buildAssetInfo.AddAssetTags(collectAssetInfo.AssetTags);
  45. buildAssetInfo.AddBundleTags(collectAssetInfo.AssetTags);
  46. allBuildAssetInfoDic.Add(collectAssetInfo.AssetPath, buildAssetInfo);
  47. }
  48. else
  49. {
  50. throw new Exception($"Should never get here !");
  51. }
  52. }
  53. // 5. 录入所有收集资源的依赖资源
  54. foreach (var collectAssetInfo in allCollectAssetInfos)
  55. {
  56. string collectAssetBundleName = collectAssetInfo.BundleName;
  57. foreach (var dependAssetPath in collectAssetInfo.DependAssets)
  58. {
  59. if (allBuildAssetInfoDic.ContainsKey(dependAssetPath))
  60. {
  61. allBuildAssetInfoDic[dependAssetPath].AddBundleTags(collectAssetInfo.AssetTags);
  62. allBuildAssetInfoDic[dependAssetPath].AddReferenceBundleName(collectAssetBundleName);
  63. }
  64. else
  65. {
  66. var buildAssetInfo = new BuildAssetInfo(dependAssetPath);
  67. buildAssetInfo.AddBundleTags(collectAssetInfo.AssetTags);
  68. buildAssetInfo.AddReferenceBundleName(collectAssetBundleName);
  69. allBuildAssetInfoDic.Add(dependAssetPath, buildAssetInfo);
  70. }
  71. }
  72. }
  73. // 6. 填充所有收集资源的依赖列表
  74. foreach (var collectAssetInfo in allCollectAssetInfos)
  75. {
  76. var dependAssetInfos = new List<BuildAssetInfo>(collectAssetInfo.DependAssets.Count);
  77. foreach (var dependAssetPath in collectAssetInfo.DependAssets)
  78. {
  79. if (allBuildAssetInfoDic.TryGetValue(dependAssetPath, out BuildAssetInfo value))
  80. dependAssetInfos.Add(value);
  81. else
  82. throw new Exception("Should never get here !");
  83. }
  84. allBuildAssetInfoDic[collectAssetInfo.AssetPath].SetAllDependAssetInfos(dependAssetInfos);
  85. }
  86. // 7. 记录关键信息
  87. BuildMapContext context = new BuildMapContext();
  88. context.AssetFileCount = allBuildAssetInfoDic.Count;
  89. context.Command = collectResult.Command;
  90. // 8. 计算共享资源的包名
  91. var command = collectResult.Command;
  92. foreach (var buildAssetInfo in allBuildAssetInfoDic.Values)
  93. {
  94. buildAssetInfo.CalculateShareBundleName(sharedPackRule, command.UniqueBundleName, command.PackageName, command.ShadersBundleName);
  95. }
  96. // 9. 记录冗余资源
  97. foreach (var buildAssetInfo in allBuildAssetInfoDic.Values)
  98. {
  99. if (buildAssetInfo.IsRedundancyAsset())
  100. {
  101. var redundancyInfo = new ReportRedundancyInfo();
  102. redundancyInfo.AssetPath = buildAssetInfo.AssetPath;
  103. redundancyInfo.AssetType = AssetDatabase.GetMainAssetTypeAtPath(buildAssetInfo.AssetPath).Name;
  104. redundancyInfo.AssetGUID = AssetDatabase.AssetPathToGUID(buildAssetInfo.AssetPath);
  105. redundancyInfo.FileSize = FileUtility.GetFileSize(buildAssetInfo.AssetPath);
  106. redundancyInfo.Number = buildAssetInfo.GetReferenceBundleCount();
  107. context.RedundancyInfos.Add(redundancyInfo);
  108. }
  109. }
  110. // 10. 移除不参与构建的资源
  111. List<BuildAssetInfo> removeBuildList = new List<BuildAssetInfo>();
  112. foreach (var buildAssetInfo in allBuildAssetInfoDic.Values)
  113. {
  114. if (buildAssetInfo.HasBundleName() == false)
  115. removeBuildList.Add(buildAssetInfo);
  116. }
  117. foreach (var removeValue in removeBuildList)
  118. {
  119. allBuildAssetInfoDic.Remove(removeValue.AssetPath);
  120. }
  121. // 11. 构建资源列表
  122. var allPackAssets = allBuildAssetInfoDic.Values.ToList();
  123. if (allPackAssets.Count == 0)
  124. throw new Exception("构建的资源列表不能为空");
  125. foreach (var assetInfo in allPackAssets)
  126. {
  127. context.PackAsset(assetInfo);
  128. }
  129. return context;
  130. }
  131. private void RemoveZeroReferenceAssets(List<CollectAssetInfo> allCollectAssetInfos)
  132. {
  133. // 1. 检测是否任何存在依赖资源
  134. bool hasAnyDependCollector = false;
  135. foreach (var collectAssetInfo in allCollectAssetInfos)
  136. {
  137. var collectorType = collectAssetInfo.CollectorType;
  138. if (collectorType == ECollectorType.DependAssetCollector)
  139. {
  140. hasAnyDependCollector = true;
  141. break;
  142. }
  143. }
  144. if (hasAnyDependCollector == false)
  145. return;
  146. // 2. 获取所有主资源的依赖资源集合
  147. HashSet<string> allDependAsset = new HashSet<string>();
  148. foreach (var collectAssetInfo in allCollectAssetInfos)
  149. {
  150. var collectorType = collectAssetInfo.CollectorType;
  151. if (collectorType == ECollectorType.MainAssetCollector || collectorType == ECollectorType.StaticAssetCollector)
  152. {
  153. foreach (var dependAsset in collectAssetInfo.DependAssets)
  154. {
  155. if (allDependAsset.Contains(dependAsset) == false)
  156. allDependAsset.Add(dependAsset);
  157. }
  158. }
  159. }
  160. // 3. 找出所有零引用的依赖资源集合
  161. List<CollectAssetInfo> removeList = new List<CollectAssetInfo>();
  162. foreach (var collectAssetInfo in allCollectAssetInfos)
  163. {
  164. var collectorType = collectAssetInfo.CollectorType;
  165. if (collectorType == ECollectorType.DependAssetCollector)
  166. {
  167. if (allDependAsset.Contains(collectAssetInfo.AssetPath) == false)
  168. removeList.Add(collectAssetInfo);
  169. }
  170. }
  171. // 4. 移除所有零引用的依赖资源
  172. foreach (var removeValue in removeList)
  173. {
  174. BuildLogger.Log($"发现未被依赖的资源并自动移除 : {removeValue.AssetPath}");
  175. allCollectAssetInfos.Remove(removeValue);
  176. }
  177. }
  178. /// <summary>
  179. /// 检测构建结果
  180. /// </summary>
  181. private void CheckBuildMapContent(BuildMapContext buildMapContext)
  182. {
  183. foreach (var bundleInfo in buildMapContext.Collection)
  184. {
  185. // 注意:原生文件资源包只能包含一个原生文件
  186. bool isRawFile = bundleInfo.IsRawFile;
  187. if (isRawFile)
  188. {
  189. if (bundleInfo.AllMainAssets.Count != 1)
  190. throw new Exception($"The bundle does not support multiple raw asset : {bundleInfo.BundleName}");
  191. continue;
  192. }
  193. // 注意:原生文件不能被其它资源文件依赖
  194. foreach (var assetInfo in bundleInfo.AllMainAssets)
  195. {
  196. if (assetInfo.AllDependAssetInfos != null)
  197. {
  198. foreach (var dependAssetInfo in assetInfo.AllDependAssetInfos)
  199. {
  200. if (dependAssetInfo.IsRawAsset)
  201. throw new Exception($"{assetInfo.AssetPath} can not depend raw asset : {dependAssetInfo.AssetPath}");
  202. }
  203. }
  204. }
  205. }
  206. }
  207. }
  208. }