using UnityEngine; using UnityEditor; using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; using System.Collections; using BF; namespace BFEditor.Build { struct ABNameInfo { public string name; public string path; } public class AssetBundleUtils { const string ASSETS_STR = "Assets/"; const string FIRST_LUA = "lua/app/first/first.lua.bytes"; const string PROTOC_LUA = "lua/app/first/protoc.lua.bytes"; const string FIRST_TEXT_LUA = "lua/app/first/first_text.lua.bytes"; static string assetDirectory = Application.dataPath + "/"; public static List languagePathList = new List { "arts/language/", "lua/app/config/strings/" }; //需要忽略的文件后缀 static Dictionary ignoreResSuffix = new Dictionary() { { ".meta", true }, { ".ds_store", true }, { ".cs", true }, { ".fnt", true }, { ".unity", true }, { ".ttf", true }, { ".otf", true }, }; public static void ClearStreamingAssets() { Debug.Log("[bfinfo]清理streamingAssets..."); EditorUtility.DisplayProgressBar("提示", "正在清理streamingAssets...", 1); var path = Path.Combine(Application.dataPath, "StreamingAssets"); if (Directory.Exists(path)) { var di = new DirectoryInfo(path); di.Delete(true); AssetDatabase.Refresh(); } EditorUtility.ClearProgressBar(); } /// /// 打对应平台下的AB /// public static bool BuildAssetBundles(BuildTarget target, string outputPath, bool release, BuildAssetBundleOptions options, BFLanguageInfo languageInfo, string version = "0.1.0") { Debug.Log("[bfinfo]正在build assetbundle..."); if (languageInfo == null) { Debug.LogError("[bferror]BuildAssetBundles: languageInfo = null"); return false; } var streamingPath = Application.streamingAssetsPath; if (Directory.Exists(streamingPath)) { Directory.Delete(streamingPath, true); } if (!Directory.Exists(outputPath)) { Directory.CreateDirectory(outputPath); } AssetBundleManifest manifest; if (release) { manifest = BuildPipeline.BuildAssetBundles(outputPath, options | BuildAssetBundleOptions.StrictMode | BuildAssetBundleOptions.DisableLoadAssetByFileName | BuildAssetBundleOptions.DisableLoadAssetByFileNameWithExtension | BuildAssetBundleOptions.DeterministicAssetBundle, target); } else { manifest = BuildPipeline.BuildAssetBundles(outputPath, options | BuildAssetBundleOptions.StrictMode | BuildAssetBundleOptions.DisableLoadAssetByFileName | BuildAssetBundleOptions.DisableLoadAssetByFileNameWithExtension | BuildAssetBundleOptions.DeterministicAssetBundle, target); } if (manifest == null) { return false; } if (!RebuildMp4AssetsBundle(outputPath, target)) { return false; } DeleteManifest(outputPath); RenameManifest(outputPath); GenerateAssetBundleConfig(outputPath, languageInfo, version); //生成 assetbundleconfig 配置文件 AssetDatabase.Refresh(); return true; } static void DeleteManifest(string abPath) { var dir = new DirectoryInfo(abPath); var files = dir.GetFiles("*.manifest", SearchOption.AllDirectories); for (var i = 0; i < files.Length; ++i) { var fileInfo = files[i]; FileUtil.DeleteFileOrDirectory(fileInfo.FullName); } AssetDatabase.Refresh(); } public static void RenameManifest(string abPath) { var manifestName = ""; int subIndex; if (abPath[abPath.Length - 1] == '/') { subIndex = abPath.LastIndexOf('/', abPath.Length - 2); if (subIndex >= 0) { manifestName = abPath.Substring(subIndex + 1, abPath.Length - subIndex - 2); } } else { subIndex = abPath.LastIndexOf('/'); if (subIndex >= 0) { manifestName = abPath.Substring(subIndex + 1); } } var manifestPath = Path.Combine(abPath, manifestName); var manifestNewPath = Path.Combine(abPath, "asset_bundle_manifest.ab"); Debug.Log(manifestPath); Debug.Log(manifestNewPath); File.Move(manifestPath, manifestNewPath); AssetDatabase.Refresh(); } public static void GenerateAssetBundleConfig(string abPath, BFLanguageInfo languageInfo, string version = "0.1.0") { var abcc = new AssetBundleConfigCollection(); abcc.version = version; var manifestPath = Path.Combine(abPath, "asset_bundle_manifest.ab"); var fileInfo = new FileInfo(manifestPath); var abc = new AssetBundleConfig(); abc.assetBundlePath = "asset_bundle_manifest.ab"; abc.md5 = GetFileMD5(manifestPath); abc.rawSize = fileInfo.Length; abcc.AddAssetBundleConfig(abc); var dirInfo = new DirectoryInfo(abPath); var floders = dirInfo.GetDirectories(); for (int i = 0; i < floders.Length; i++) { var f = floders[i]; WriteInfo(abPath, f.Name, abcc, languageInfo); } var bytes = AssetBundleConfigCollection.Compress(abcc.ToJson()); File.WriteAllBytes(Path.Combine(abPath, "ab_config.bytes"), bytes); } static void WriteInfo(string rootPath, string path, AssetBundleConfigCollection abcc, BFLanguageInfo languageInfo) { var searchPath = Path.Combine(rootPath, path); var dirInfo = new DirectoryInfo(searchPath); var files = dirInfo.GetFiles(); var subDirs = dirInfo.GetDirectories(); for (int i = 0; i < files.Length; i++) { var f = files[i]; var extension = f.Extension; if (extension == ".meta" || extension == ".DS_Store") { continue; } var abCfg = new AssetBundleConfig(); abCfg.assetBundlePath = Path.Combine(path, f.Name).Replace("\\", "/"); var bundle = AssetBundle.LoadFromFile(f.FullName); var assets = bundle.GetAllAssetNames(); abCfg.assetsPath = assets; bundle.Unload(true); abCfg.md5 = GetFileMD5(f.FullName); abCfg.rawSize = f.Length; if (abCfg == null) { Debug.LogError("f : " + f.FullName); } if (TryGetLanguageName(abCfg.assetBundlePath, languageInfo, out string languageName)) { abcc.AddLangAssetBundleConfig(languageName, abCfg); } else { abcc.AddAssetBundleConfig(abCfg); } } for (int i = 0; i < subDirs.Length; i++) { var subDir = Path.Combine(path, subDirs[i].Name); WriteInfo(rootPath, subDir, abcc, languageInfo); } } /// /// 是否是多语言包资源 /// static bool TryGetLanguageName(string abPath, BFLanguageInfo languageInfo, out string languageName) { if(true) { languageName = ""; return false; } foreach (var startStr in languagePathList) { if (abPath.Contains(startStr)) { var startIndex = abPath.IndexOf(startStr); var temp = abPath.Substring(startIndex + startStr.Length); var endIndex = temp.IndexOf("/"); var name = temp.Remove(endIndex); if (languageInfo.Contains(name)) { languageName = ""; return false; } if (!Resource.ResourceProcessConfig.languageNames.Contains(name)) { languageName = ""; return false; } languageName = name; return true; } } languageName = ""; return false; } public static void RegenerateABConfigMd5(string abPath, string version = "") { Debug.Log("[bfinfo]正在重新生成abConfig md5..."); var abConfigPath = Path.Combine(abPath, "ab_config.bytes"); var bytes = File.ReadAllBytes(abConfigPath); var json = AssetBundleConfigCollection.Decompress(bytes); var abcc = AssetBundleConfigCollection.Create(json); foreach (var abc in abcc.allConfigs) { abc.md5 = GetFileMD5(Path.Combine(abPath, abc.assetBundlePath)); } if (!string.IsNullOrEmpty(version)) { abcc.version = version; } var newJson = abcc.ToJson(); var newBytes = AssetBundleConfigCollection.Compress(newJson); File.WriteAllBytes(abConfigPath, newBytes); } static string GetFileMD5(string filePath) { return GameLaunchUtils.GetFileMD5(filePath); } /// /// 重新打包mp4AB 不使用压缩 /// public static bool RebuildMp4AssetsBundle(string outputPath, BuildTarget target) { var suc = true; var videoAbPath = Path.Combine(outputPath, "arts/video"); if (!Directory.Exists(videoAbPath)) { Directory.CreateDirectory(videoAbPath); } var fileInfos = new DirectoryInfo(videoAbPath).GetFiles(); foreach (var fInfo in fileInfos) { if (fInfo.Extension != ".ab") { continue; } var fileName = fInfo.Name; fInfo.Delete(); var tempPath = outputPath + "_temp"; if (Directory.Exists(tempPath)) { Directory.Delete(tempPath, true); } Directory.CreateDirectory(tempPath); var buildMap = new AssetBundleBuild[1]; var cgAbName = "arts/video/" + fileName; buildMap[0].assetBundleName = cgAbName; var mp4Assets = new string[1]; mp4Assets[0] = "Assets/arts/video/" + Path.GetFileNameWithoutExtension(fileName); buildMap[0].assetNames = mp4Assets; var manifest = BuildPipeline.BuildAssetBundles(tempPath, buildMap, BuildAssetBundleOptions.UncompressedAssetBundle, target); if (manifest) { File.Move(Path.Combine(tempPath, cgAbName), Path.Combine(outputPath, cgAbName)); } else { Debug.LogError("[bferror]重新打包mp4不压缩ab失败 " + fileName); suc = false; } Directory.Delete(tempPath, true); } AssetDatabase.Refresh(); return suc; } /// /// 设置所有资源的ABName /// public static void SetAllAssetsBundleName() { Debug.Log("[bfinfo]设置资源abName..."); float total = 14; float index = 1; ClearFolderABName(Path.Combine(Application.dataPath, "arts", "effects")); ClearFolderABName(Path.Combine(Application.dataPath, "first")); SetLuaAssetBundleName(index++ / total); SetSceneABName(index++ / total); SetAnimationsABName(Path.Combine(Application.dataPath, "arts", "animations"), index++ / total); SetAtlasABName(Path.Combine(Application.dataPath, "arts", "atlas"), index++ / total); // SetEffectsABName(Path.Combine(Application.dataPath, "arts", "effects"), index++ / total); SetBMFontsABName(Path.Combine(Application.dataPath, "arts", "fonts", "bmfonts"), index++ / total); SetTmpFontsABName(Path.Combine(Application.dataPath, "arts", "fonts", "tmpfonts"), index++ / total); SetMaterialABName(Path.Combine(Application.dataPath, "arts", "materials"), index++ / total); SetModelsABName(Path.Combine(Application.dataPath, "arts", "models"), index++ / total); SetShadersABName(Path.Combine(Application.dataPath, "arts", "shaders"), index++ / total); SetSoundsABName(Path.Combine(Application.dataPath, "arts", "sounds"), index++ / total); SetTexturesABName(Path.Combine(Application.dataPath, "arts", "textures"), index++ / total); SetPrefabsABName(Path.Combine(Application.dataPath, "prefabs"), index++ / total); SetProtoABName(Path.Combine(Application.dataPath, "proto"), index++ / total); SetSpineABName(Path.Combine(Application.dataPath, "arts", "spines"), index++ / total); SetFirstABName(Path.Combine(Application.dataPath, "first"), index++ / total); // SetTimelineABName(Path.Combine(Application.dataPath, "arts", "timeline"), 16f / total); // SetVideoABName(Path.Combine(Application.dataPath, "arts", "video"), 17f / total); // SetLanguageResABName(Resource.ResourceProcessConfig.LANGUAGE_PATH, 19f / total); // SetBakedatasABName(Path.Combine(Application.dataPath, "arts", "bakedatas"), 21f / total); // SetLightProbesABName(Path.Combine(Application.dataPath, "arts", "lightprobes"), 22f / total); // SetReflectionsABName(Path.Combine(Application.dataPath, "arts", "reflections"), 23f / total); EditorUtility.ClearProgressBar(); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } static void SetLuaAssetBundleName(float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置lua ABName", progress); var dirInfo = new DirectoryInfo(Path.Combine(Application.dataPath, "lua")); SetABNameByFile(dirInfo); } static void SetAnimationsABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置animation ABName", progress); string[] subDirList = { "ui", "frame" }; for (var i = 0; i < subDirList.Length; ++i) { var dirInfo = new DirectoryInfo(Path.Combine(dirPath, subDirList[i])); if (dirInfo.Exists) { SetABNameBySubDir(dirInfo); } } } // atlas和textures里的图片是一一对应的,所以ab name设置为一样的 static void SetAtlasABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置atlas ABName", progress); var abNameInfos = new List(); string[] subDirList = { "ui", "icon" }; for (var i = 0; i < subDirList.Length; ++i) { var dirInfo = new DirectoryInfo(Path.Combine(dirPath, subDirList[i])); var files = dirInfo.GetFiles("*.*", SearchOption.AllDirectories); for (var j = 0; j < files.Length; ++j) { var fileInfo = files[j]; if (CheckIgnoreOrHidden(fileInfo)) { continue; } ABNameInfo ab; ab.name = fileInfo.FullName.Substring(assetDirectory.Length).Replace(".asset", "").Replace(".spriteatlas", "").Replace("atlas", "textures"); var relativePath = fileInfo.FullName.Substring(assetDirectory.Length); ab.path = relativePath; abNameInfos.Add(ab); } } foreach (var relativePath in abNameInfos) { SetAssetBundleName(ASSETS_STR + relativePath.path, relativePath.name); } } static void SetEffectsABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置特效 ABName", progress); SetEffectsCommonABName(Path.Combine(dirPath, "texture")); SetEffectsCommonABName(Path.Combine(dirPath, "models")); // arts/effects/material 的子文件夹 string[] materialSubDirList = { "battle", "buff", "ui", "show" }; var materialSubDirPath = Path.Combine(dirPath, "material"); var dirInfo = new DirectoryInfo(materialSubDirPath); var subDirs = dirInfo.GetDirectories(); for (var i = 0; i < subDirs.Length; ++i) { if(((IList)materialSubDirList).Contains(subDirs[i].Name)) { var subDirInfo = new DirectoryInfo(Path.Combine(materialSubDirPath, subDirs[i].Name)); SetABNameBySubDir(subDirInfo); } else { SetABNameByDir(subDirs[i]); } } } static void SetEffectsCommonABName(string dirPath) { var dir = new DirectoryInfo(dirPath); var files = dir.GetFiles("*.*", SearchOption.AllDirectories); var assetFiles = new List(); for (var i = 0; i < files.Length; ++i) { var fileInfo = files[i]; if (CheckIgnoreOrHidden(fileInfo)) { continue; } var relativePath = fileInfo.FullName.Substring(assetDirectory.Length); assetFiles.Add(relativePath); } foreach (var relativePath in assetFiles) { //prefab设置为和同名特效一个ab包 if (relativePath.ToLower().Contains("prefab")) { var abName = relativePath.Replace("prefab", "fbx"); SetAssetBundleName(ASSETS_STR + relativePath, abName); } else { SetAssetBundleName(ASSETS_STR + relativePath, relativePath); } } } static void SetBMFontsABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置BMFonts ABName", progress); var dirInfo = new DirectoryInfo(dirPath); SetABNameBySubDir(dirInfo); } static void SetMaterialABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置材质 ABName", progress); var dirInfo = new DirectoryInfo(dirPath); SetABNameByDir(dirInfo); } static void SetShadersABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置shader ABName", progress); var dirInfo = new DirectoryInfo(dirPath); SetABNameByDir(dirInfo); } static void SetModelsABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置模型 ABName", progress); // 这几个文件夹按子文件夹来打ab,其他的文件夹就直接按每个文件夹打一个ab string[] subDirList = { "characters", "maps", "maincity", "battle", "weapon" }; var dirInfo = new DirectoryInfo(dirPath); var subDirs = dirInfo.GetDirectories(); for (var i = 0; i < subDirs.Length; ++i) { if(((IList)subDirList).Contains(subDirs[i].Name)) { var subDirInfo = new DirectoryInfo(Path.Combine(dirPath, subDirs[i].Name)); SetABNameBySubDir(subDirInfo); // // 角色材质因为改动比较频繁,和模型打包在一起的话热更的时候会导致热更量比较大,所以单独设置一下 // if(subDirs[i].Name == "characters") // { // var materialPath = BFEditorUtils.GetAssetPathsWithSuffix(subDirInfo.FullName, ".mat"); // foreach (var path in materialPath) // { // SetABNameByDirName(path); // } // } } else { SetABNameByDir(subDirs[i]); } } } static void SetSoundsABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置sounds ABName", progress); var dirInfo = new DirectoryInfo(dirPath); SetABNameByFile(dirInfo); } static void SetVideoABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置video ABName", progress); var dirInfo = new DirectoryInfo(dirPath); SetABNameByFile(dirInfo); } static void SetSpineABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置spine ABName", progress); var dirInfo = new DirectoryInfo(dirPath); var dirs = dirInfo.GetDirectories(); for (var i = 0; i < dirs.Length; i++) { SetABNameBySubDir(dirs[i]); } } static void SetTexturesABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置texture ABName", progress); SetSpriteABName(dirPath); SetBackgroundABName(dirPath); } static void SetSpriteABName(string dirPath) { string[] dirList = { "ui", "icon" }; for (var i = 0; i < dirList.Length; ++i) { var dirInfo = new DirectoryInfo(Path.Combine(dirPath, dirList[i])); SetABNameBySubDir(dirInfo); } } static void SetBackgroundABName(string dirPath) { var dirInfo = new DirectoryInfo(Path.Combine(dirPath, "background")); SetABNameByFile(dirInfo); } static void SetPrefabsABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置perfab ABName", progress); var dirInfo = new DirectoryInfo(dirPath); SetABNameByFile(dirInfo); } static void SetProtoABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置proto ABName", progress); var dirInfo = new DirectoryInfo(dirPath); var pathList = new List(); var files = dirInfo.GetFiles("*.*", SearchOption.AllDirectories); for (var i = 0; i < files.Length; ++i) { var fileInfo = files[i]; if (CheckIgnoreOrHidden(fileInfo)) { continue; } var relativePath = fileInfo.FullName.Substring(assetDirectory.Length); pathList.Add(relativePath); } foreach (var path in pathList) { SetAssetBundleName(ASSETS_STR + path, "proto/proto"); } } static void SetSceneABName(float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置scene ABName", progress); var scenes = GetBuildScenes(); foreach (var scene in scenes) { SetAssetBundleName(scene, scene.Replace("Assets/", "")); } } public static void SetTimelineABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置timeline ABName", progress); var dirInfo = new DirectoryInfo(dirPath); SetABNameByFile(dirInfo); } public static void SetFirstABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置首包ABName", progress); var dirInfo = new DirectoryInfo(dirPath); var pathList = new List(); var files = dirInfo.GetFiles("*.*", SearchOption.AllDirectories); for (var i = 0; i < files.Length; ++i) { var fileInfo = files[i]; if (CheckIgnoreOrHidden(fileInfo)) { continue; } var relativePath = fileInfo.FullName.Substring(assetDirectory.Length); pathList.Add(relativePath); } pathList.Add(FIRST_LUA); pathList.Add(PROTOC_LUA); pathList.Add(FIRST_TEXT_LUA); foreach (var path in pathList) { SetAssetBundleName(ASSETS_STR + path, "first/first"); } } public static void SetLanguageResABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置多语言资源 ABName", progress); var dirInfo = new DirectoryInfo(dirPath); var files = dirInfo.GetFiles("*.*", SearchOption.AllDirectories); foreach (var f in files) { if (CheckIgnoreOrHidden(f)) { continue; } var dirName = Path.GetDirectoryName(f.FullName); var abName = dirName.Substring(assetDirectory.Length); var relativePath = f.FullName.Substring(assetDirectory.Length); SetAssetBundleName(ASSETS_STR + relativePath, abName); } } public static void SetTmpFontsABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置tmp font ABName", progress); var dirInfo = new DirectoryInfo(dirPath); SetABNameBySubDir(dirInfo); } public static void SetBakedatasABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置bakedatas ABName", progress); var dirInfo = new DirectoryInfo(dirPath); SetABNameBySubDir(dirInfo); } public static void SetLightProbesABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置lightprobe ABName", progress); var dirInfo = new DirectoryInfo(dirPath); SetABNameBySubDir(dirInfo); } public static void SetReflectionsABName(string dirPath, float progress) { EditorUtility.DisplayProgressBar("提示", "正在设置reflection ABName", progress); var dirInfo = new DirectoryInfo(dirPath); SetABNameBySubDir(dirInfo); } /// /// 通过文件名设置abName, dirInfo下的每个资源的abName都设置为fileName /// static void SetABNameByFile(DirectoryInfo dirInfo) { var files = dirInfo.GetFiles("*.*", SearchOption.AllDirectories); var assetFiles = new List(); for (var i = 0; i < files.Length; ++i) { var fileInfo = files[i]; if (CheckIgnoreOrHidden(fileInfo)) { continue; } var relativePath = fileInfo.FullName.Substring(assetDirectory.Length); assetFiles.Add(relativePath); } foreach (var relativePath in assetFiles) { SetAssetBundleName(ASSETS_STR + relativePath, relativePath); } } /// /// 根据dirInfo下的二级文件夹名设置资源abName /// static void SetABNameBySubDir(DirectoryInfo dirInfo) { var dirs = dirInfo.GetDirectories(); for (var i = 0; i < dirs.Length; i++) { SetABNameByDir(dirs[i]); } } /// /// 根据文件夹路径设置资源的abName /// static void SetABNameByDirName(string relativeFilePath) { if (!File.Exists(relativeFilePath)) { return; } var dirPath = Path.GetDirectoryName(relativeFilePath); var name = dirPath.Replace("\\", "/").Replace(ASSETS_STR, ""); SetAssetBundleName(relativeFilePath, name); } /// /// 根据文件夹路径设置资源的abName, dirInfo下的资源abName都设置为dirPath相对路径 /// static void SetABNameByDir(DirectoryInfo dirInfo) { var abInfos = new List(); var files = dirInfo.GetFiles("*.*", SearchOption.AllDirectories); for (var i = 0; i < files.Length; ++i) { var fileInfo = files[i]; if (CheckIgnoreOrHidden(fileInfo)) { continue; } ABNameInfo into; into.name = dirInfo.FullName.Substring(assetDirectory.Length); var relativePath = fileInfo.FullName.Substring(assetDirectory.Length); into.path = relativePath; abInfos.Add(into); } foreach (var abInfo in abInfos) { SetAssetBundleName(ASSETS_STR + abInfo.path, abInfo.name); } } static void ClearFolderABName(string dirPath) { var dirInfo = new DirectoryInfo(dirPath); var files = dirInfo.GetFiles("*.*", SearchOption.AllDirectories); var assetFiles = new List(); for (var i = 0; i < files.Length; ++i) { var fileInfo = files[i]; if (CheckIgnoreOrHidden(fileInfo)) { continue; } var relativePath = fileInfo.FullName.Substring(assetDirectory.Length); assetFiles.Add(relativePath); } foreach (var relativePath in assetFiles) { ClearAssetBundleName(ASSETS_STR + relativePath); } } static void ClearAssetBundleName(string assetPath) { if (string.IsNullOrEmpty(assetPath)) { return; } if (!assetPath.Contains("Editor/")) { var importer = AssetImporter.GetAtPath(assetPath); if (importer == null) { AssetDatabase.ImportAsset(assetPath); importer = AssetImporter.GetAtPath(assetPath); } if (!string.IsNullOrEmpty(importer.assetBundleName)) { importer.assetBundleName = string.Empty; EditorUtility.SetDirty(importer); AssetDatabase.WriteImportSettingsIfDirty(assetPath); } } } static void SetAssetBundleName(string assetPath, string bundleName) { if (string.IsNullOrEmpty(assetPath) || string.IsNullOrWhiteSpace(bundleName)) { return; } if (Regex.IsMatch(assetPath, @"[\u4e00-\u9fbb]")) { Debug.LogError("AssetBundleUtils SetAssetBundleName: " + assetPath + " 存在中文"); return; } if (!assetPath.Contains("Editor/")) { bundleName = bundleName.ToLower() + ".ab"; //所有AB名设定为相对于assets目录 var special = "assets/"; if (bundleName.Contains(special)) { bundleName = bundleName.Substring(special.Length); } var changed = false; var importer = AssetImporter.GetAtPath(assetPath); if (importer == null) { AssetDatabase.ImportAsset(assetPath); importer = AssetImporter.GetAtPath(assetPath); } if (string.IsNullOrEmpty(importer.assetBundleName) || !string.Equals(importer.assetBundleName, bundleName)) { importer.assetBundleName = bundleName; EditorUtility.SetDirty(importer); changed = true; } if (changed) { AssetDatabase.WriteImportSettingsIfDirty(assetPath); } } } static bool CheckIgnoreOrHidden(FileInfo fi) { if (((fi.Attributes & FileAttributes.Hidden) > 0) || ((fi.Attributes & FileAttributes.System) > 0)) { return true; } if (ignoreResSuffix.ContainsKey(fi.Extension.ToLower())) { return true; } return false; } public static string[] GetBuildScenes() { var result = new List(); foreach (var scene in EditorBuildSettings.scenes) { if (scene == null) { continue; } if (scene.enabled) { result.Add(scene.path); } } return result.ToArray(); } } }