AssetBundleHelper.cs 12 KB

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