AssetBundleHelper.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using UnityEditor;
  5. using UnityEngine;
  6. using YooAsset.Editor;
  7. namespace GFGEditor
  8. {
  9. public static class AssetBundleHelper
  10. {
  11. public static Action BuildHotUpdateDll;
  12. public const string RES_ROOT_DIR_PATH = "Assets/Res";
  13. public const int LimitByteSize = 1024*1024*4;
  14. private static List<string> excludeFileExtensions = new List<string>() { ".meta", ".moc3" , ".can3" };
  15. private static AssetBundleCollector assetBundleCollector;
  16. private static AssetBundleCollectRuler _ruler;
  17. private static AssetBundleCollectRuler ruler
  18. {
  19. get
  20. {
  21. if(_ruler == null)
  22. {
  23. _ruler = AssetBundleCollectRuler.GetData();
  24. }
  25. return _ruler;
  26. }
  27. }
  28. private static Dictionary<string, Dictionary<string, AssetBundleAssetListItem>> itemsSizeDicDic;
  29. //记录文件的bundle名
  30. private static Dictionary<string, string> fileBundleDic;
  31. public static void OnPreExecuteBuild()
  32. {
  33. EditorUtility.DisplayProgressBar("进度", "正在收集资源", 1);
  34. BuildHotUpdateDll();
  35. AssetDatabase.Refresh();
  36. itemsSizeDicDic = new Dictionary<string, Dictionary<string, AssetBundleAssetListItem>>();
  37. assetBundleCollector = AssetBundleCollector.GetData();
  38. foreach (var dir in ruler.PackBySeparately)
  39. {
  40. FileHelper.ForeachFileInDir(dir, null, (string filePath) =>
  41. {
  42. var path = filePath.Replace("\\", "/");
  43. var ext = Path.GetExtension(filePath);
  44. if(IsIgnoreFileExtension(ext))
  45. {
  46. return;
  47. }
  48. var dirPath = dir + "/";
  49. if (path.Contains(dirPath))
  50. {
  51. var indexLastDot = path.LastIndexOf('.');
  52. string key = path.Substring(0, indexLastDot);
  53. CollectDynamicFile(dir, key, path, true);
  54. }
  55. });
  56. }
  57. foreach (var dir in ruler.PackByTopDir)
  58. {
  59. FileHelper.ForeachFileInDir(dir, null, (string filePath) =>
  60. {
  61. var path = filePath.Replace("\\", "/");
  62. var ext = Path.GetExtension(filePath);
  63. if (IsIgnoreFileExtension(ext))
  64. {
  65. return;
  66. }
  67. var dirPath = dir + "/";
  68. if (path.Contains(dirPath))
  69. {
  70. var topPath = path.Replace(dir + "/", "");
  71. var arr = topPath.Split('/');
  72. string key = dir + "/" + arr[0];
  73. CollectDynamicFile(dir, key, path, true);
  74. }
  75. });
  76. }
  77. foreach (var dir in ruler.PackByFileName)
  78. {
  79. FileHelper.ForeachFileInDir(dir, null, (string filePath) =>
  80. {
  81. var path = filePath.Replace("\\", "/");
  82. var ext = Path.GetExtension(filePath);
  83. if (IsIgnoreFileExtension(ext))
  84. {
  85. return;
  86. }
  87. var dirPath = dir + "/";
  88. if (path.Contains(dirPath))
  89. {
  90. var indexLastDot = path.LastIndexOf('.');
  91. string key = path.Substring(0, indexLastDot);
  92. CollectDynamicFile(dir, key, path, false);
  93. }
  94. });
  95. }
  96. CollectNewItems();
  97. RecordFileBundle();
  98. EditorUtility.SetDirty(assetBundleCollector);
  99. AssetDatabase.SaveAssetIfDirty(assetBundleCollector);
  100. EditorUtility.ClearProgressBar();
  101. }
  102. public static void OnPostExecuteBuild(BuildResult buildResult)
  103. {
  104. if(fileBundleDic != null)
  105. {
  106. fileBundleDic.Clear();
  107. fileBundleDic = null;
  108. }
  109. if(itemsSizeDicDic != null)
  110. {
  111. itemsSizeDicDic.Clear();
  112. itemsSizeDicDic = null;
  113. }
  114. assetBundleCollector = null;
  115. _ruler = null;
  116. int index = buildResult.OutputPackageDirectory.LastIndexOf("/");
  117. string targetPath = buildResult.OutputPackageDirectory.Substring(0, index);
  118. Debug.Log($"sourcePath {buildResult.OutputPackageDirectory}");
  119. Debug.Log($"targetPath {targetPath}");
  120. CopyFilesTo(buildResult.OutputPackageDirectory, targetPath);
  121. Directory.Delete(buildResult.OutputPackageDirectory, true);
  122. }
  123. public static void CollectDynamicFile(string dirPath, string itemKey, string assetPath, bool autoMerge)
  124. {
  125. AssetBundleAssetList assetList;
  126. AssetBundleAssetListItem newItem;
  127. Dictionary<string, AssetBundleAssetListItem> itemsSizeDic;
  128. for (var i = 0; i < assetBundleCollector.assetBundleAssetLists.Count; i++)
  129. {
  130. assetList = assetBundleCollector.assetBundleAssetLists[i];
  131. if (assetList.dir == dirPath)
  132. {
  133. foreach(var item in assetList.list)
  134. {
  135. if(item.key == itemKey)
  136. {
  137. //新增文件直接加进去
  138. if (!item.list.Contains(assetPath))
  139. {
  140. item.list.Add(assetPath);
  141. var fileSize = GetFileSize(assetPath);
  142. item.bytes += fileSize;
  143. assetList.bytes += fileSize;
  144. if (assetList.bytes >= LimitByteSize)
  145. {
  146. assetList.status = 1;
  147. }
  148. }
  149. return;
  150. }
  151. }
  152. }
  153. }
  154. //先计算每个item的大小缓存起来(item指必须打在一起的若干文件)
  155. itemsSizeDicDic.TryGetValue(dirPath, out itemsSizeDic);
  156. if (itemsSizeDic == null)
  157. {
  158. itemsSizeDic = new Dictionary<string, AssetBundleAssetListItem>();
  159. itemsSizeDicDic[dirPath] = itemsSizeDic;
  160. }
  161. itemsSizeDic.TryGetValue(itemKey, out newItem);
  162. if (newItem == null)
  163. {
  164. newItem = new AssetBundleAssetListItem();
  165. newItem.key = itemKey;
  166. newItem.list = new List<string>();
  167. itemsSizeDic[itemKey] = newItem;
  168. }
  169. newItem.list.Add(assetPath);
  170. if(autoMerge)
  171. {
  172. newItem.bytes += GetFileSize(assetPath);
  173. }
  174. else
  175. {
  176. newItem.bytes = LimitByteSize;
  177. }
  178. }
  179. public static void CollectNewItems()
  180. {
  181. foreach(var t in itemsSizeDicDic)
  182. {
  183. CollectNewItems(t.Key, t.Value);
  184. }
  185. }
  186. public static void CollectNewItems(string dirPath, Dictionary<string, AssetBundleAssetListItem> itemsSizeDic)
  187. {
  188. foreach(var newItem in itemsSizeDic.Values)
  189. {
  190. bool toNew = true;
  191. AssetBundleAssetList assetList;
  192. //先找已存在的AB
  193. for (var i = 0; i < assetBundleCollector.assetBundleAssetLists.Count; i++)
  194. {
  195. assetList = assetBundleCollector.assetBundleAssetLists[i];
  196. if (assetList.dir == dirPath)
  197. {
  198. if (assetList.status <= 0)
  199. {
  200. if (assetList.bytes < LimitByteSize && newItem.bytes < LimitByteSize)
  201. {
  202. assetList.list.Add(newItem);
  203. assetList.bytes += newItem.bytes;
  204. if (assetList.bytes >= LimitByteSize)
  205. {
  206. assetList.status = 1;
  207. }
  208. toNew = false;
  209. }
  210. }
  211. }
  212. }
  213. if(toNew)
  214. {
  215. //新建一个AB
  216. assetList = new AssetBundleAssetList();
  217. assetList.dir = dirPath;
  218. assetList.list = new List<AssetBundleAssetListItem>();
  219. assetList.list.Add(newItem);
  220. assetList.bytes += newItem.bytes;
  221. if (assetList.bytes >= LimitByteSize)
  222. {
  223. assetList.status = 1;
  224. }
  225. assetBundleCollector.assetBundleAssetLists.Add(assetList);
  226. }
  227. }
  228. }
  229. private static void RecordFileBundle()
  230. {
  231. fileBundleDic = new Dictionary<string, string>();
  232. AssetBundleAssetList assetList;
  233. for (var i = 0; i < assetBundleCollector.assetBundleAssetLists.Count; i++)
  234. {
  235. assetList = assetBundleCollector.assetBundleAssetLists[i];
  236. foreach (var item in assetList.list)
  237. {
  238. foreach (var assetPath in item.list)
  239. {
  240. var bundleName = assetList.dir + "_" + i;
  241. fileBundleDic[assetPath] = bundleName;
  242. //UnityEngine.Debug.Log($"assetPath :{assetPath}");
  243. //UnityEngine.Debug.Log($"bundleName :{bundleName}");
  244. }
  245. }
  246. }
  247. }
  248. public static int GetFileSize(string filePath)
  249. {
  250. //var filePath = Path.Combine(Environment.CurrentDirectory, assetPath);
  251. //filePath = filePath.Replace("\\", "/");
  252. var ext = Path.GetExtension(filePath);
  253. byte[] bytes = File.ReadAllBytes(filePath);
  254. var fileSize = bytes.Length;
  255. if (ext == ".jpg")
  256. {
  257. //unity处理jpg后会变的很大
  258. fileSize *= 5;
  259. }
  260. return fileSize;
  261. }
  262. public static string GetBundleName(string assetPath)
  263. {
  264. string bundleName = null;
  265. if (fileBundleDic != null)
  266. {
  267. fileBundleDic.TryGetValue(assetPath, out bundleName);
  268. }
  269. return bundleName;
  270. }
  271. public static bool IsIgnoreFileExtension(string extension)
  272. {
  273. return excludeFileExtensions.Contains(extension);
  274. }
  275. public static List<string> CopyFilesTo(string sourcePath, string targetPath, string[] includeExtensionNames = null)
  276. {
  277. if(!sourcePath.EndsWith("/"))
  278. {
  279. sourcePath += "/";
  280. }
  281. if (!targetPath.EndsWith("/"))
  282. {
  283. targetPath += "/";
  284. }
  285. List<string> result = new List<string>();
  286. if (Directory.Exists(sourcePath))
  287. {
  288. var files = Directory.GetFiles(sourcePath);
  289. var dirs = Directory.GetDirectories(sourcePath);
  290. foreach (var dir in dirs)
  291. {
  292. List<string> tempResult = CopyFilesTo(dir, targetPath, includeExtensionNames);
  293. result.AddRange(tempResult);
  294. }
  295. foreach (var file in files)
  296. {
  297. var fileName = Path.GetFileName(file);
  298. string extensionName = Path.GetExtension(file);
  299. if (includeExtensionNames == null || Array.IndexOf(includeExtensionNames, extensionName) >= 0)
  300. {
  301. string targetFilePath = targetPath + fileName;
  302. if (!File.Exists(targetFilePath) || !Equals(file, targetFilePath))
  303. {
  304. File.Copy(file, targetFilePath, true);
  305. result.Add(file);
  306. }
  307. }
  308. }
  309. }
  310. return result;
  311. }
  312. }
  313. }