BundleManifestsController.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. using XGame.Editor.Asset;
  2. using XGame.Framework.Asset;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using UnityEditor;
  8. using UnityEngine;
  9. namespace XGame.Editor.Build.AssetBundles
  10. {
  11. internal partial class BundleManifestsController
  12. {
  13. /// <summary>
  14. /// ab加密的偏移值上限
  15. /// </summary>
  16. internal readonly uint EncryptOffsetLimit = 256;
  17. private BundleContext _context;
  18. private AssetBundleCollector _bundleCollector;
  19. private BundleDepsController _depsController;
  20. private SceneManifestController _sceneController;
  21. public BundleManifestsController(BundleContext context, AssetBundleCollector bundleCollector, BundleDepsController depsController, SceneManifestController sceneController)
  22. {
  23. _context = context;
  24. _bundleCollector = bundleCollector;
  25. _depsController = depsController;
  26. _sceneController = sceneController;
  27. }
  28. public bool GenerateManifests()
  29. {
  30. _bundleCollector.CollectBundleBuilds(true);
  31. //检查重名资源
  32. if (!CheckAssetsNameRepeat())
  33. {
  34. //有同名资源就中断打包
  35. return false;
  36. }
  37. if (!_bundleCollector.CollectSceneBundles())
  38. {
  39. //可能有同名Scene
  40. return false;
  41. }
  42. //if (!_bundleCollector.MergeSceneBundles())
  43. //{
  44. // return false;
  45. //}
  46. //处理AssetBundle分组
  47. //_groupController.ModifyBundleNameByGroup();
  48. BuildLog.Log("BuildBundles count:" + _context.bundleDataMap.Count);
  49. if (!Directory.Exists(PathDefine.ConfigsRelative))
  50. {
  51. Directory.CreateDirectory(PathDefine.ConfigsRelative);
  52. }
  53. if (!GenerateBundleManifest() || !_sceneController.GenerateManifest() || !GenReferencesManifest())
  54. {
  55. return false;
  56. }
  57. BuildLog.Log($"AssetBundle GenerateManifests completed.");
  58. return true;
  59. }
  60. /// <summary>
  61. /// 收集bundle信息,后期可能需要改成异步操作
  62. /// </summary>
  63. /// <param name="bundleBuilds"></param>
  64. /// <returns></returns>
  65. private bool GenerateBundleManifest()
  66. {
  67. if (_context.bundleDataMap.Count == 0)
  68. {
  69. return false;
  70. }
  71. if (!_depsController.CollectBundleDependencies())
  72. {
  73. return false;
  74. }
  75. //BundleManifest
  76. string bundleManifestPath = PathDefine.BundleManifestPath;//"Assets/KCAssetBundlesData/KCAssetBundleManifest.asset";
  77. var kcBundleManifest = AssetDatabase.LoadAssetAtPath<AssetBundleInfosSo>(bundleManifestPath);
  78. if (kcBundleManifest == null)
  79. {
  80. kcBundleManifest = ScriptableObject.CreateInstance<AssetBundleInfosSo>();
  81. AssetDatabase.CreateAsset(kcBundleManifest, bundleManifestPath);
  82. }
  83. //bundle信息
  84. var bundleDataLst = _context.SortAssetBundleDatas();
  85. var count = bundleDataLst.Count;
  86. var bundleInfos = new AssetBundleInfo[count];
  87. var backupInfos = new AssetBundleBackupInfo[count];
  88. for (var index = 0; index < count; index++)
  89. {
  90. var bundleData = bundleDataLst[index];
  91. EditorUtility.DisplayProgressBar("Collect AssetBundleInfo", bundleData.assetBundleName, index / (float)count);
  92. var dependencies = _context.dependenciesMap[bundleData.bundleId];
  93. //var bundleId = CreateBundleId(build.assetBundleName, build.assetBundleVariant, build.addressableNames);
  94. //var bytes = System.Text.Encoding.UTF8.GetBytes(bundleData.originBundleName);
  95. //originBundleName大部分为guid,固定32字节,用bundleId取余数增加点offset的差异
  96. var originName = bundleData.originBundleName;
  97. var offset = (uint)Math.Clamp(bundleData.bundleId % originName.Length, 4, EncryptOffsetLimit);
  98. var bundleInfo = new AssetBundleInfo()
  99. {
  100. bundleName = bundleData.assetBundleName,
  101. variantName = bundleData.assetBundleVariant,
  102. bundleId = bundleData.bundleId,
  103. assets = bundleData.addressableNames,
  104. dependencies = dependencies,
  105. //originBundleName = originName,
  106. offset = offset,
  107. };
  108. bundleInfos[index] = bundleInfo;
  109. // 备份数据
  110. var backupInfo = new AssetBundleBackupInfo()
  111. {
  112. bundleName = bundleData.assetBundleName,
  113. variantName = bundleData.assetBundleVariant,
  114. bundleId = bundleData.bundleId,
  115. assets = bundleData.addressableNames,
  116. dependencies = dependencies,
  117. offset = offset,
  118. bundleType = bundleData.bundleType,
  119. nameOrGuid = originName,
  120. originAssetPath = _context.bundleNameMode == AssetBundleNameMode.Guid ? AssetDatabase.GUIDToAssetPath(originName) : string.Empty,
  121. };
  122. backupInfos[index] = backupInfo;
  123. }
  124. EditorUtility.ClearProgressBar();
  125. //保存
  126. kcBundleManifest.bundleInfos = bundleInfos;
  127. EditorUtility.SetDirty(kcBundleManifest);
  128. AssetBundleBackupManifest.Save(backupInfos, false);
  129. AssetDatabase.SaveAssets();
  130. BuildLog.Log("Save BundleManifest.");
  131. AssetDatabase.Refresh();
  132. return true;
  133. }
  134. bool GenReferencesManifest()
  135. {
  136. string refManifestPath = PathDefine.ReferenceManifestPath;
  137. var referenceManifest = AssetDatabase.LoadAssetAtPath<AssetReferenceInfosSo>(refManifestPath);
  138. if (referenceManifest == null)
  139. {
  140. referenceManifest = ScriptableObject.CreateInstance<AssetReferenceInfosSo>();
  141. AssetDatabase.CreateAsset(referenceManifest, refManifestPath);
  142. }
  143. //asset被引用信息
  144. var assetReferencesMap = new Dictionary<string, HashSet<string>>();
  145. //addressable信息
  146. //ResStatic的bundle不允许动态加载,因此不需要记录引用信息
  147. var addressableMap = _context.GetAddressableInfoMap();
  148. var sw = new System.Diagnostics.Stopwatch();
  149. foreach (var item in addressableMap)
  150. {
  151. if (_context.allTexturePaths.Contains(item.Key))
  152. {
  153. //忽略贴图资源
  154. continue;
  155. }
  156. var assetPath = item.Key;
  157. var assetAddressable = item.Value;
  158. sw.Start();
  159. var dependencies = AssetDatabase.GetDependencies(assetPath, true);
  160. sw.Stop();
  161. foreach (var dep in dependencies)
  162. {
  163. if (dep != assetPath && addressableMap.TryGetValue(dep, out var depAddressableName))
  164. { // 同bundle内的asset引用也需要记录
  165. if (assetReferencesMap.TryGetValue(depAddressableName, out var referenceLst) == false)
  166. {
  167. referenceLst = new HashSet<string>();
  168. assetReferencesMap.Add(depAddressableName, referenceLst);
  169. }
  170. referenceLst.Add(assetAddressable);
  171. }
  172. }
  173. }
  174. BuildLog.Log($"GenReferencesManifest GetDependencies Time:{sw.ElapsedMilliseconds}");
  175. AssetReferenceInfo[] referenceInfos = new AssetReferenceInfo[assetReferencesMap.Count];
  176. int index = 0;
  177. foreach (var item in assetReferencesMap)
  178. {
  179. referenceInfos[index++] = new AssetReferenceInfo()
  180. {
  181. assetName = item.Key,
  182. references = item.Value.ToArray()
  183. };
  184. }
  185. referenceManifest.references = referenceInfos;
  186. EditorUtility.SetDirty(referenceManifest);
  187. AssetDatabase.SaveAssets();
  188. BuildLog.Log("Save ReferenceManifest.");
  189. AssetDatabase.Refresh();
  190. return true;
  191. }
  192. /// <summary>
  193. /// 检查Assetbundle内是否存在同名资源
  194. /// </summary>
  195. /// <param name="assetBundleBuilds"></param>
  196. /// <returns></returns>
  197. private bool CheckAssetsNameRepeat()
  198. {
  199. bool result = true;
  200. Dictionary<string, string> assetPathMap = new Dictionary<string, string>();
  201. var allAssetPaths = new HashSet<string>();
  202. foreach (var item in _context.bundleDataMap)
  203. {
  204. assetPathMap.Clear();
  205. foreach (var assetPath in item.Value.assetNames)
  206. {
  207. var fileName = Path.GetFileName(assetPath);
  208. if (assetPathMap.ContainsKey(fileName))
  209. {
  210. result = false;
  211. BuildLog.Error($"[XBuild] AssetBundle存在重名资源。Bundle:{item.Value.originBundleName} 重名资源1:{assetPathMap[fileName]} 重名资源2:{assetPath}");
  212. }
  213. else
  214. {
  215. assetPathMap.Add(fileName, assetPath);
  216. }
  217. if (allAssetPaths.Contains(assetPath))
  218. {
  219. BuildLog.Error($"[XBuild] AssetBundle存在重复资源。Path:{assetPath}");
  220. result = false;
  221. continue;
  222. }
  223. allAssetPaths.Add(assetPath);
  224. }
  225. }
  226. return result;
  227. }
  228. }
  229. }