using System; using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine; using YooAsset.Editor; namespace GFGEditor { public static class AssetBundleHelper { public static Action BuildHotUpdateDll; 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); BuildHotUpdateDll(); AssetDatabase.Refresh(); 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, true); } }); } 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, true); } }); } foreach (var dir in ruler.PackByFileName) { 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, false); } }); } CollectNewItems(); RecordFileBundle(); EditorUtility.SetDirty(assetBundleCollector); AssetDatabase.SaveAssetIfDirty(assetBundleCollector); EditorUtility.ClearProgressBar(); } public static void OnPostExecuteBuild(BuildResult buildResult) { if(fileBundleDic != null) { fileBundleDic.Clear(); fileBundleDic = null; } if(itemsSizeDicDic != null) { itemsSizeDicDic.Clear(); itemsSizeDicDic = null; } assetBundleCollector = null; _ruler = null; int index = buildResult.OutputPackageDirectory.LastIndexOf("/"); string targetPath = buildResult.OutputPackageDirectory.Substring(0, index); Debug.Log($"sourcePath {buildResult.OutputPackageDirectory}"); Debug.Log($"targetPath {targetPath}"); CopyFilesTo(buildResult.OutputPackageDirectory, targetPath); Directory.Delete(buildResult.OutputPackageDirectory, true); } public static void CollectDynamicFile(string dirPath, string itemKey, string assetPath, bool autoMerge) { 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); if(autoMerge) { newItem.bytes += GetFileSize(assetPath); } else { newItem.bytes = LimitByteSize; } } 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) { string bundleName = null; if (fileBundleDic != null) { fileBundleDic.TryGetValue(assetPath, out bundleName); } return bundleName; } public static bool IsIgnoreFileExtension(string extension) { return excludeFileExtensions.Contains(extension); } public static List CopyFilesTo(string sourcePath, string targetPath, string[] includeExtensionNames = null) { if(!sourcePath.EndsWith("/")) { sourcePath += "/"; } if (!targetPath.EndsWith("/")) { targetPath += "/"; } List result = new List(); if (Directory.Exists(sourcePath)) { var files = Directory.GetFiles(sourcePath); var dirs = Directory.GetDirectories(sourcePath); foreach (var dir in dirs) { List tempResult = CopyFilesTo(dir, targetPath, includeExtensionNames); result.AddRange(tempResult); } foreach (var file in files) { var fileName = Path.GetFileName(file); string extensionName = Path.GetExtension(file); if (includeExtensionNames == null || Array.IndexOf(includeExtensionNames, extensionName) >= 0) { string targetFilePath = targetPath + fileName; if (!File.Exists(targetFilePath) || !Equals(file, targetFilePath)) { File.Copy(file, targetFilePath, true); result.Add(file); } } } } return result; } } }