AssetBundleHelper.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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. }
  117. public static void CollectDynamicFile(string dirPath, string itemKey, string assetPath, bool autoMerge)
  118. {
  119. AssetBundleAssetList assetList;
  120. AssetBundleAssetListItem newItem;
  121. Dictionary<string, AssetBundleAssetListItem> itemsSizeDic;
  122. for (var i = 0; i < assetBundleCollector.assetBundleAssetLists.Count; i++)
  123. {
  124. assetList = assetBundleCollector.assetBundleAssetLists[i];
  125. if (assetList.dir == dirPath)
  126. {
  127. foreach(var item in assetList.list)
  128. {
  129. if(item.key == itemKey)
  130. {
  131. //新增文件直接加进去
  132. if (!item.list.Contains(assetPath))
  133. {
  134. item.list.Add(assetPath);
  135. var fileSize = GetFileSize(assetPath);
  136. item.bytes += fileSize;
  137. assetList.bytes += fileSize;
  138. if (assetList.bytes >= LimitByteSize)
  139. {
  140. assetList.status = 1;
  141. }
  142. }
  143. return;
  144. }
  145. }
  146. }
  147. }
  148. //先计算每个item的大小缓存起来(item指必须打在一起的若干文件)
  149. itemsSizeDicDic.TryGetValue(dirPath, out itemsSizeDic);
  150. if (itemsSizeDic == null)
  151. {
  152. itemsSizeDic = new Dictionary<string, AssetBundleAssetListItem>();
  153. itemsSizeDicDic[dirPath] = itemsSizeDic;
  154. }
  155. itemsSizeDic.TryGetValue(itemKey, out newItem);
  156. if (newItem == null)
  157. {
  158. newItem = new AssetBundleAssetListItem();
  159. newItem.key = itemKey;
  160. newItem.list = new List<string>();
  161. itemsSizeDic[itemKey] = newItem;
  162. }
  163. newItem.list.Add(assetPath);
  164. if(autoMerge)
  165. {
  166. newItem.bytes += GetFileSize(assetPath);
  167. }
  168. else
  169. {
  170. newItem.bytes = LimitByteSize;
  171. }
  172. }
  173. public static void CollectNewItems()
  174. {
  175. foreach(var t in itemsSizeDicDic)
  176. {
  177. CollectNewItems(t.Key, t.Value);
  178. }
  179. }
  180. public static void CollectNewItems(string dirPath, Dictionary<string, AssetBundleAssetListItem> itemsSizeDic)
  181. {
  182. foreach(var newItem in itemsSizeDic.Values)
  183. {
  184. bool toNew = true;
  185. AssetBundleAssetList assetList;
  186. //先找已存在的AB
  187. for (var i = 0; i < assetBundleCollector.assetBundleAssetLists.Count; i++)
  188. {
  189. assetList = assetBundleCollector.assetBundleAssetLists[i];
  190. if (assetList.dir == dirPath)
  191. {
  192. if (assetList.status <= 0)
  193. {
  194. if (assetList.bytes < LimitByteSize && newItem.bytes < LimitByteSize)
  195. {
  196. assetList.list.Add(newItem);
  197. assetList.bytes += newItem.bytes;
  198. if (assetList.bytes >= LimitByteSize)
  199. {
  200. assetList.status = 1;
  201. }
  202. toNew = false;
  203. }
  204. }
  205. }
  206. }
  207. if(toNew)
  208. {
  209. //新建一个AB
  210. assetList = new AssetBundleAssetList();
  211. assetList.dir = dirPath;
  212. assetList.list = new List<AssetBundleAssetListItem>();
  213. assetList.list.Add(newItem);
  214. assetList.bytes += newItem.bytes;
  215. if (assetList.bytes >= LimitByteSize)
  216. {
  217. assetList.status = 1;
  218. }
  219. assetBundleCollector.assetBundleAssetLists.Add(assetList);
  220. }
  221. }
  222. }
  223. private static void RecordFileBundle()
  224. {
  225. fileBundleDic = new Dictionary<string, string>();
  226. AssetBundleAssetList assetList;
  227. for (var i = 0; i < assetBundleCollector.assetBundleAssetLists.Count; i++)
  228. {
  229. assetList = assetBundleCollector.assetBundleAssetLists[i];
  230. foreach (var item in assetList.list)
  231. {
  232. foreach (var assetPath in item.list)
  233. {
  234. var bundleName = assetList.dir + "_" + i;
  235. fileBundleDic[assetPath] = bundleName;
  236. //UnityEngine.Debug.Log($"assetPath :{assetPath}");
  237. //UnityEngine.Debug.Log($"bundleName :{bundleName}");
  238. }
  239. }
  240. }
  241. }
  242. public static int GetFileSize(string filePath)
  243. {
  244. //var filePath = Path.Combine(Environment.CurrentDirectory, assetPath);
  245. //filePath = filePath.Replace("\\", "/");
  246. var ext = Path.GetExtension(filePath);
  247. byte[] bytes = File.ReadAllBytes(filePath);
  248. var fileSize = bytes.Length;
  249. if (ext == ".jpg")
  250. {
  251. //unity处理jpg后会变的很大
  252. fileSize *= 5;
  253. }
  254. return fileSize;
  255. }
  256. public static string GetBundleName(string assetPath)
  257. {
  258. string bundleName = null;
  259. if (fileBundleDic != null)
  260. {
  261. fileBundleDic.TryGetValue(assetPath, out bundleName);
  262. }
  263. return bundleName;
  264. }
  265. public static bool IsIgnoreFileExtension(string extension)
  266. {
  267. return excludeFileExtensions.Contains(extension);
  268. }
  269. public static List<string> CopyFilesTo(string sourcePath, string targetPath, 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. }