using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using YooAsset.Editor; using static UnityEditor.Progress; namespace GFGEditor { public static class AssetBundleHelper { public const string RES_ROOT_DIR_PATH = "Assets/Res"; public const int LimitByteSize = 1024*1024*4; private static List excludeFileExtensions = new List() { ".meta", ".moc3" , ".can3" }; private static AssetBundleCollector assetBundleCollector; private static AssetBundleCollectRuler _ruler; private static AssetBundleCollectRuler ruler { get { if(_ruler == null) { _ruler = AssetBundleCollectRuler.GetData(); } return _ruler; } } private static Dictionary> itemsSizeDicDic; //记录文件的bundle名 private static Dictionary fileBundleDic; public static void OnPreExecuteBuild() { EditorUtility.DisplayProgressBar("进度", "正在收集资源", 1); itemsSizeDicDic = new Dictionary>(); assetBundleCollector = AssetBundleCollector.GetData(); foreach (var dir in ruler.PackBySeparately) { FileHelper.ForeachFileInDir(dir, null, (string filePath) => { var path = filePath.Replace("\\", "/"); var ext = Path.GetExtension(filePath); if(IsIgnoreFileExtension(ext)) { return; } var dirPath = dir + "/"; if (path.Contains(dirPath)) { var indexLastDot = path.LastIndexOf('.'); string key = path.Substring(0, indexLastDot); CollectDynamicFile(dir, key, path); } }); } foreach (var dir in ruler.PackByTopDir) { FileHelper.ForeachFileInDir(dir, null, (string filePath) => { var path = filePath.Replace("\\", "/"); var ext = Path.GetExtension(filePath); if (IsIgnoreFileExtension(ext)) { return; } var dirPath = dir + "/"; if (path.Contains(dirPath)) { var topPath = path.Replace(dir + "/", ""); var arr = topPath.Split('/'); string key = dir + "/" + arr[0]; CollectDynamicFile(dir, key, path); } }); } CollectNewItems(); RecordFileBundle(); EditorUtility.SetDirty(assetBundleCollector); AssetDatabase.SaveAssetIfDirty(assetBundleCollector); EditorUtility.ClearProgressBar(); } public static void OnPostExecuteBuild() { if(fileBundleDic != null) { fileBundleDic.Clear(); fileBundleDic = null; } if(itemsSizeDicDic != null) { itemsSizeDicDic.Clear(); itemsSizeDicDic = null; } assetBundleCollector = null; _ruler = null; } public static void CollectDynamicFile(string dirPath, string itemKey, string assetPath) { AssetBundleAssetList assetList; AssetBundleAssetListItem newItem; Dictionary itemsSizeDic; for (var i = 0; i < assetBundleCollector.assetBundleAssetLists.Count; i++) { assetList = assetBundleCollector.assetBundleAssetLists[i]; if (assetList.dir == dirPath) { foreach(var item in assetList.list) { if(item.key == itemKey) { //新增文件直接加进去 if (!item.list.Contains(assetPath)) { item.list.Add(assetPath); var fileSize = GetFileSize(assetPath); item.bytes += fileSize; assetList.bytes += fileSize; if (assetList.bytes >= LimitByteSize) { assetList.status = 1; } } return; } } } } //先计算每个item的大小缓存起来(item指必须打在一起的若干文件) itemsSizeDicDic.TryGetValue(dirPath, out itemsSizeDic); if (itemsSizeDic == null) { itemsSizeDic = new Dictionary(); itemsSizeDicDic[dirPath] = itemsSizeDic; } itemsSizeDic.TryGetValue(itemKey, out newItem); if (newItem == null) { newItem = new AssetBundleAssetListItem(); newItem.key = itemKey; newItem.list = new List(); itemsSizeDic[itemKey] = newItem; } newItem.list.Add(assetPath); newItem.bytes += GetFileSize(assetPath); } public static void CollectNewItems() { foreach(var t in itemsSizeDicDic) { CollectNewItems(t.Key, t.Value); } } public static void CollectNewItems(string dirPath, Dictionary itemsSizeDic) { foreach(var newItem in itemsSizeDic.Values) { bool toNew = true; AssetBundleAssetList assetList; //先找已存在的AB for (var i = 0; i < assetBundleCollector.assetBundleAssetLists.Count; i++) { assetList = assetBundleCollector.assetBundleAssetLists[i]; if (assetList.dir == dirPath) { if (assetList.status <= 0) { if (assetList.bytes < LimitByteSize && newItem.bytes < LimitByteSize) { assetList.list.Add(newItem); assetList.bytes += newItem.bytes; if (assetList.bytes >= LimitByteSize) { assetList.status = 1; } toNew = false; } } } } if(toNew) { //新建一个AB assetList = new AssetBundleAssetList(); assetList.dir = dirPath; assetList.list = new List(); assetList.list.Add(newItem); assetList.bytes += newItem.bytes; if (assetList.bytes >= LimitByteSize) { assetList.status = 1; } assetBundleCollector.assetBundleAssetLists.Add(assetList); } } } private static void RecordFileBundle() { fileBundleDic = new Dictionary(); AssetBundleAssetList assetList; for (var i = 0; i < assetBundleCollector.assetBundleAssetLists.Count; i++) { assetList = assetBundleCollector.assetBundleAssetLists[i]; foreach (var item in assetList.list) { foreach (var assetPath in item.list) { var bundleName = assetList.dir + "_" + i; fileBundleDic[assetPath] = bundleName; //UnityEngine.Debug.Log($"assetPath :{assetPath}"); //UnityEngine.Debug.Log($"bundleName :{bundleName}"); } } } } public static int GetFileSize(string filePath) { //var filePath = Path.Combine(Environment.CurrentDirectory, assetPath); //filePath = filePath.Replace("\\", "/"); var ext = Path.GetExtension(filePath); byte[] bytes = File.ReadAllBytes(filePath); var fileSize = bytes.Length; if (ext == ".jpg") { //unity处理jpg后会变的很大 fileSize *= 5; } return fileSize; } public static string GetBundleName(string assetPath) { var path = assetPath.Replace("\\", "/"); foreach (var dir in ruler.PackByCollecter) { var dirPath = dir + "/"; if (path.Contains(dirPath)) { return dir; } } string bundleName = null; if (fileBundleDic != null) { fileBundleDic.TryGetValue(assetPath, out bundleName); } return bundleName; } public static bool IsIgnoreFileExtension(string extension) { return excludeFileExtensions.Contains(extension); } } }