using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.Serialization.Formatters.Binary; using System.Text; using BundleV2; using Games.GlobeDefine; using UnityEditor; using UnityEngine; using Debug = UnityEngine.Debug; namespace AssetUpdate { public class AssetVersionWindow : EditorWindow { public const int startVersion = 1; public const string excelName = "AssetList"; public const string excelNameKey = "name"; public const string excelLevelKey = "level"; public const string excelImportanceKey = "importance"; public const BuildAssetBundleOptions buildOptions = BuildAssetBundleOptions.DeterministicAssetBundle | BuildAssetBundleOptions.ChunkBasedCompression; private static IntSetting _currentVersion; private static IntSetting _previousVersion; private static string gameVersionKey { get { return AssetUtils.GetTextMd5(Application.dataPath.Open("GameVersion")); } } private static string lastVersionKey { get { return AssetUtils.GetTextMd5(Application.dataPath.Open("LastVersion")); } } public static string bundlePath { get { return Application.dataPath.MoveUp().Open("AssetBundle").Open(PlatformName.GetEditorPlatformName()); } } public static string excelToolPath { get; private set; } public static string excelTextPath { get; private set; } private void OnEnable() { if (_currentVersion == null) _currentVersion = new IntSetting(gameVersionKey, startVersion); if (_previousVersion == null) _previousVersion = new IntSetting(lastVersionKey, startVersion); if (string.IsNullOrEmpty(excelToolPath)) excelToolPath = Application.dataPath.MoveUp().Open("ExcelExport").Open("ExcelToText.exe"); if (string.IsNullOrEmpty(excelTextPath)) excelTextPath = Application.dataPath.MoveUp().Open("ExcelTexts"); } private void OnGUI() { EditorGUILayout.LabelField("测试工具"); if (GUILayout.Button("仅仅编译版本记录")) CreateAssetVersionBundle(); // var isLocalAsset = EngineManager.isLocalRes.current; // var setLocalAsset = EditorGUILayout.Toggle("使用序列化导表", isLocalAsset); // if (isLocalAsset != setLocalAsset) // EngineManager.isLocalRes.Set(setLocalAsset); // GUILayout.Space(10f); // if (GUILayout.Button("仅仅复制Lua文件")) // AssetBundleMarker.RedirectLua(); // GUILayout.Space(10f); // if (GUILayout.Button("仅仅编译动态库")) // { // var assetPath = AssetBundleMarker.dllPath; // var bundleName = AssetUtils.GetTextMd5(AssetConst.dllBundle); // var bundleVariant = AssetConst.bundleVariant.Substring(1); // var build = new AssetBundleBuild // { // assetNames = new[] {assetPath}, // addressableNames = new[] {Path.GetFileNameWithoutExtension(assetPath)}, // assetBundleName = bundleName, // assetBundleVariant = bundleVariant // }; // var manifest = BuildPipeline.BuildAssetBundles(bundlePath, // new[] {build}, // buildOptions, // EditorUserBuildSettings.activeBuildTarget); // if (!manifest) // ShowError("动态库资源编译失败!"); // else // Debug.LogWarning(string.Format("动态库资源编译完成,包名{0}!", bundleName)); // } GUILayout.Space(15f); EditorGUILayout.LabelField("资源包编辑工具"); // if (GUILayout.Button("创建Message Pack生成代码")) // GenerateMessagePackCode(); // GUILayout.Space(10f); // if (GUILayout.Button("编译GameConfig")) // BuildGameConfig(); // GUILayout.Space(10f); // if (GUILayout.Button("复制代码到Dll项目")) // DllUtilities.CopyAllCodes(); GUILayout.Space(10f); if (GUILayout.Button("标记资源包")) ClassifyBundles.ClassifyAllChange_Additive(); // Debug.LogWarning("Start Mark " + DateTime.Now); // ShaderVariantBuilder.BuildVariants(); // AssetDatabase.Refresh(); // var marker = new AssetBundleMarker(); // marker.MarkAllResources(); GUILayout.Space(10f); GUILayout.Label("当前编译平台:" + EditorUserBuildSettings.activeBuildTarget); if (GUILayout.Button("编辑资源包")) BuildAssetBundles(); GUILayout.Space(15f); EditorGUILayout.LabelField("游戏版本号"); GUILayout.Label("Apk版本号:" + Application.version); GUILayout.Label("上次打包资源版本号:" + _previousVersion.current); GUILayout.Label("当前编译平台:" + EditorUserBuildSettings.activeBuildTarget); GUILayout.Space(10f); int version = _currentVersion; var newVersion = EditorGUILayout.IntField("打包资源版本号", version); if (newVersion != version) _currentVersion.Set(newVersion); GUILayout.Space(15f); EditorGUILayout.LabelField("游戏资源路径工具"); CopyBundleType? copyType = null; if (GUILayout.Button("按版本复制资源")) copyType = CopyBundleType.UpdateOnly; GUILayout.Space(10f); if (GUILayout.Button("按版本复制资源 和 Apk资源")) copyType = CopyBundleType.UpdateAndApk; GUILayout.Space(10f); if (GUILayout.Button("按版本复制资源 和 全部资源")) copyType = CopyBundleType.UpdateAndFull; GUILayout.Space(10f); if (copyType != null) { var lastVersion = _previousVersion.current; bool confirm; if (version <= _previousVersion.current) confirm = EditorUtility.DisplayDialog("警告", string.Format("当前选择版本{0},等于或者低于上次处理版本{1}!\n该操作可能导致版本资源混乱 或者 需要抛弃全部更高版本的资源!", version, lastVersion), "确定", "取消"); else if (version > _previousVersion.current + 1) confirm = EditorUtility.DisplayDialog("警告", string.Format("当前选择版本{0},高于上次处理版本{1} + 1!\n该操作会跳过一个版本!", version, lastVersion), "确定", "取消"); else confirm = true; if (confirm) if (CopyAssetBundles(copyType.Value)) _previousVersion.Set(version); } // // 2020.04.08 iOS版本直接使用资源BundleName,单一项目打包,不排除动态库 // // 使用Unity内置方法排除重复资源 // GUILayout.Space(15f); // EditorGUILayout.LabelField("iOS特殊操作流程"); // GUILayout.Space(10f); // if (GUILayout.Button("创建iOS Link.xml文件")) // iOSDllUtilities.CreateLinkXml(); // GUILayout.Space(10f); // var iOSPath = iOSDllUtilities.GetiOSPath(); // if (GUILayout.Button("复制iOS代码")) // iOSDllUtilities.SyncCodeToiOS(iOSPath); // if (GUILayout.Button("设置资源BundleName")) // MarkFileOnImporters(); // GUILayout.Space(10f); // if (GUILayout.Button("按BundleName编辑资源包")) // BuildAssetBundlesByTag(); // GUILayout.Space(10f); // if (GUILayout.Button("复制全部到Streaming")) // if (EditorUtility.DisplayDialog("警告", "复制到Streaming的操作仅仅用于测试!需要至少做一次按版本复制资源才能正常运作!", "确定", "取消")) // CopyAllAssetToPath(false); // GUILayout.Space(10f); // if (GUILayout.Button("复制全部到Persist")) // if (EditorUtility.DisplayDialog("警告", "复制到Persist的操作仅仅用于测试!需要至少做一次按版本复制资源才能正常运作!", "确定", "取消")) // CopyAllAssetToPath(true); } private static AssetBundleManifest CreateAssetVersionBundle() { var versionFile = GlobeVar.testConfigPath.Open(AssetConst.versionFile + AssetConst.bytesExtension); AssetDatabase.Refresh(); var bundleName = AssetUtils.GetTextMd5(AssetConst.versionFile); var build = new AssetBundleBuild { assetNames = new[] {EditorCommonUtility.FileToAssetPath(versionFile)}, addressableNames = new[] {AssetConst.versionFile}, assetBundleName = bundleName, assetBundleVariant = AssetConst.bundleVariant.Substring(1) }; var path = GetTempPath(); if (!Directory.Exists(path)) Directory.CreateDirectory(path); var versionManifest = BuildPipeline.BuildAssetBundles(path, new[] {build}, buildOptions, EditorUserBuildSettings.activeBuildTarget); return versionManifest; } [MenuItem("Bundle V2/Asset Version Window")] public static void OpenWindow() { GetWindow("游戏版本管理器"); } // 已经过时,在AssetImporter标记太费时间 // private static void BuildAssetBundlesByTag() // { // var startTime = DateTime.Now; // if (!Directory.Exists(bundlePath)) // Directory.CreateDirectory(bundlePath); // var manifest = BuildPipeline.BuildAssetBundles(bundlePath, // buildOptions, // EditorUserBuildSettings.activeBuildTarget); // var endTime = DateTime.Now; // if (!manifest) // ShowError("Asset Bundle 编译失败!"); // else // Debug.LogWarning("Asset Bundle 编译成功于:" + endTime + ",共耗时:" + (endTime - startTime)); // } // 已经过时,在AssetImporter标记太费时间 // private static void MarkFileOnImporters() // { // var startTime = DateTime.Now; // // 监视当前已经配置部分 // var current = new Dictionary(); // var bundleNames = AssetDatabase.GetAllAssetBundleNames(); // foreach (var bundleName in bundleNames) // { // var noExtension = bundleName.RemoveExtension(); // var assetPaths = AssetDatabase.GetAssetPathsFromAssetBundle(bundleName); // foreach (var assetPath in assetPaths) // current[assetPath] = noExtension; // } // // // 监视当前目标配置部分 // var target = new Dictionary(); // var plans = LoadAssetMarkFile(); // foreach (var plan in plans) // foreach (var assetPath in plan.assetPaths) // target[assetPath] = plan.bundleName; // // 对比获得移除部分 // var removeNames = new HashSet(); // // 对比获得修改部分 // var addNames = new Dictionary(); // foreach (var key in current.Keys) // if (!target.ContainsKey(key)) // removeNames.Add(key); // foreach (var keyValue in target) // { // string bundleName; // if (!current.TryGetValue(keyValue.Key, out bundleName) || // bundleName != keyValue.Value) // addNames[keyValue.Key] = keyValue.Value; // } // // if (EditorUtility.DisplayDialog("Bundle Plan", string.Format( // "Total current {0}, total target {1}.\nRemove Bundle {2}.\nReset Bundle {3}.", // current.Count, // target.Count, // removeNames.Count, // addNames.Count), "Ok", "Cancel")) // { // var finished = 0; // var total = removeNames.Count; // foreach (var assetPath in removeNames) // { // EditorUtility.DisplayProgressBar("Remove Bundle Names", // string.Format("{0} / {1}", finished + 1, total), (float) finished / total); // finished++; // var importer = AssetImporter.GetAtPath(assetPath); // if (importer) // { // importer.assetBundleName = string.Empty; // importer.assetBundleVariant = string.Empty; // importer.SaveAndReimport(); // } // else // { // Debug.LogError(string.Format("Failed to get assetImporter at path {0}!", assetPath)); // } // } // // finished = 0; // total = target.Count; // // 移除前面的点 // var variant = AssetConst.bundleVariant.Substring(1); // foreach (var keyValue in target) // { // EditorUtility.DisplayProgressBar("Remove Bundle Names", // string.Format("{0} / {1}", finished + 1, total), (float) finished / total); // finished++; // var importer = AssetImporter.GetAtPath(keyValue.Key); // if (importer) // { // importer.assetBundleName = keyValue.Value; // importer.assetBundleVariant = variant; // importer.SaveAndReimport(); // } // else // { // Debug.LogError(string.Format("Failed to get assetImporter at path {0}!", keyValue.Key)); // } // } // // EditorUtility.ClearProgressBar(); // AssetDatabase.RemoveUnusedAssetBundleNames(); // var endTime = DateTime.Now; // Debug.LogWarning("Mark Asset 标记到Importers:" + endTime + ",共耗时:" + (endTime - startTime)); // } // } private static void BuildAssetBundles() { // 首先独立打包导出场景资源 // 然后打包其他类型带依赖资源 // 最后将两份资源信息合并到统一的清单之上 var startTime = DateTime.Now; Debug.LogWarning("Asset Bundle 编译开始于:" + startTime); // 注:bundleVariant 会自己加个点,因此跳过一个点。 if (!Directory.Exists(bundlePath)) Directory.CreateDirectory(bundlePath); var manifest = BuildPipeline.BuildAssetBundles(bundlePath, buildOptions, EditorUserBuildSettings.activeBuildTarget); var endTime = DateTime.Now; if (!manifest) ShowError("Asset Bundle 编译失败!"); else Debug.LogWarning("Asset Bundle 编译成功于:" + endTime + ",共耗时:" + (endTime - startTime)); } private static List LoadAssetMarkFile() { var result = new List(); var bundleNames = AssetDatabase.GetAllAssetBundleNames(); foreach (var bundleName in bundleNames) { var assets = AssetDatabase.GetAssetPathsFromAssetBundle(bundleName); if (assets.Length > 0) { var bundlePlan = new AssetBundlePlan(bundleName.RemoveExtension()); result.Add(bundlePlan); foreach (var asset in assets) bundlePlan.AddAsset(asset); } } return result; } private static bool CopyAssetBundles(CopyBundleType type) { var result = false; var versionPath = GetCurrentVersionPath(); var currentPath = versionPath.Open(_currentVersion.current.ToString()); var manifestPath = bundlePath.Open(PlatformName.GetEditorPlatformName()); AssetBundleManifest manifest = null; if (File.Exists(manifestPath)) { var assetBundle = AssetBundle.LoadFromFile(manifestPath); if (assetBundle) { manifest = assetBundle.LoadAsset("AssetBundleManifest"); assetBundle.Unload(false); } } if (!manifest) { ShowError("无法加载上次编译的AssetBundleManifest!请检查编译是否正常完成!路径:" + manifestPath); return result; } var itemList = InitDependencyByExcel(manifest); if (itemList == null) { ShowError("由Excel初始化资源等级失败!"); } // 按照当前版本初始化全部资源信息 else { var error = false; var finalItemList = new List(); // 灌注全部物品信息 // ReSharper disable once PossibleNullReferenceException var allAssets = manifest.GetAllAssetBundles() .Where(a => a != EditorAssetConst.dummyBundle + AssetConst.bundleVariant) .Select(a => a.RemoveExtension()).ToArray(); for (var i = 0; i < allAssets.Length; i++) { var asset = allAssets[i]; EditorUtility.DisplayProgressBar("构造资源信息", string.Format("{0} / {1}", i + 1, allAssets.Length), (float) i / allAssets.Length); var item = itemList.Find(a => a.name == asset) ?? new AssetDependencyItem { name = asset }; finalItemList.Add(item); item.dependencies = manifest.GetAllDependencies(item.name + AssetConst.bundleVariant) .Select(a => a.RemoveExtension()).ToArray(); } // 提升具有特殊权限的物品 // ReSharper disable once ForCanBeConvertedToForeach for (var i = 0; i < finalItemList.Count; i++) { EditorUtility.DisplayProgressBar("修改资源权限信息", string.Format("{0} / {1}", i + 1, finalItemList.Count), (float) i / finalItemList.Count); var item = finalItemList[i]; foreach (var dependency in item.dependencies) { var dependItem = finalItemList.Find(a => a.name == dependency); if (dependItem == null) { error = true; Debug.LogError(string.Format( "Cannot find item {0}! Some problem in AssetBundle Manifest!", dependency)); } else { dependItem.level = Mathf.Max(dependItem.level, item.level); dependItem.importance = Mathf.Min(dependItem.importance, item.importance); } } } // 灌注资源文件信息 for (var i = 0; i < finalItemList.Count; i++) { EditorUtility.DisplayProgressBar("增加资源文件信息", string.Format("{0} / {1}", i + 1, finalItemList.Count), (float) i / finalItemList.Count); var item = finalItemList[i]; var path = bundlePath.Open(item.name + AssetConst.bundleVariant); var fileInfo = new FileInfo(path); if (!fileInfo.Exists) { error = true; Debug.LogError(string.Format("无法获得文件{0}!检查是否打包中途出现故障!", path)); } else { // 单包不可能超过2G,不需要用int64做长度 item.fileSize = (int) fileInfo.Length; item.md5 = AssetUtils.GetFileMd5(path); item.version = _currentVersion; } } // 获得之前版本的信息 var oldFiles = new List(); if (error) { ShowError("文件信息构造流程出现问题,详见之前的报错!"); } else { if (!Directory.Exists(versionPath)) Directory.CreateDirectory(versionPath); // 仅仅对比最近10个版本的资源,减少对比负担 // 注:这个流程仅仅会不重用10个版本内都不使用的部分,实际未变动资源仍然可以逐版本继承上来 var versionDirs = (from path in Directory.GetDirectories(versionPath, "*", SearchOption.TopDirectoryOnly) // ReSharper disable once AssignNullToNotNullAttribute let version = int.Parse(Path.GetFileNameWithoutExtension(path)) where _currentVersion - version < 10 select path).ToArray(); for (var i = 0; i < versionDirs.Length; i++) { EditorUtility.DisplayProgressBar("加载旧版本清单", string.Format("{0} / {1}", i + 1, versionDirs.Length), (float) i / versionDirs.Length); var dir = versionDirs[i]; int oldVersion; if (!int.TryParse(Path.GetFileNameWithoutExtension(dir), out oldVersion)) { Debug.LogError(string.Format("路径并非版本号结尾,于{0}!", dir)); } else if (oldVersion < _currentVersion) { var filePath = dir.Open(AssetUtils.GetTextMd5(AssetConst.versionFile) + AssetConst.bundleVariant); if (!File.Exists(filePath)) { ShowError(string.Format("无法获得旧版本文件{0}!", filePath)); error = true; } else { var info = AssetDependencyInfo.Create(filePath); if (info == null) { ShowError(string.Format("无法解析旧版本文件{0}!", filePath)); error = true; } else { oldFiles.Add(info); } } } } } // 试图降级当前打包出来的文件 if (!error && oldFiles.Count > 0) { // 从大到小排列,策略是认为版本间有改动的资源数量不多 oldFiles.Sort((a, b) => -a.version.CompareTo(b.version)); // 对全部资源进行最小版本对比 for (var i = 0; i < finalItemList.Count; i++) { var item = finalItemList[i]; EditorUtility.DisplayProgressBar("检查文件是否重用老版本", string.Format("{0} / {1}", i + 1, finalItemList.Count), (float) i / finalItemList.Count); foreach (var oldFile in oldFiles) { var oldItem = oldFile.assetList.FirstOrDefault(a => a.name == item.name); if (oldItem != null && oldItem.md5 == item.md5) { item.version = Mathf.Min(item.version, oldItem.version); break; } } } } if (!error) { // 当前版本的资源清单 var dependencyInfo = new AssetDependencyInfo { version = _currentVersion, assetList = finalItemList.ToArray() }; // 输出资源包文件 var currentFiles = dependencyInfo.assetList.Where(a => a.version == _currentVersion).ToArray(); // if (currentFiles.Length == 0) // { // EditorUtility.DisplayDialog("当前版本无新资源", "所有资源同之前版本匹配,不需要更新资源!", "确定"); // } // else { EditorUtility.DisplayProgressBar("输出资源清单", string.Format("{0} / {1}", 0, 1), 0f); // 输出资源清单文件 var builder = new StringBuilder(); dependencyInfo.Write(builder); var bytes = Encoding.UTF8.GetBytes(builder.ToString()); var versionFile = GlobeVar.testConfigPath.Open(AssetConst.versionFile + AssetConst.bytesExtension); File.WriteAllBytes(versionFile, bytes); var versionManifest = CreateAssetVersionBundle(); if (!versionManifest) { Debug.LogError(string.Format("无法建立{0}的AssetBundle!", AssetConst.versionFile)); error = true; return !error; } if (Directory.Exists(currentPath)) Directory.Delete(currentPath, true); Directory.CreateDirectory(currentPath); var bundleName = AssetUtils.GetTextMd5(AssetConst.versionFile); File.Copy(GetTempPath().Open(bundleName + AssetConst.bundleVariant), currentPath.Open(bundleName + AssetConst.bundleVariant), true); for (var i = 0; i < currentFiles.Length; i++) { EditorUtility.DisplayProgressBar("复制资源服务器文件", string.Format("{0} / {1}", i + 1, currentFiles.Length), (float) i / currentFiles.Length); var file = currentFiles[i]; var filePath = bundlePath.Open(file.name + AssetConst.bundleVariant); var targetPath = currentPath.Open(file.name + AssetConst.bundleVariant); EnsureDirectory(targetPath); File.Copy(filePath, targetPath); } var apkFiles = type == CopyBundleType.UpdateAndFull ? dependencyInfo.assetList : dependencyInfo.assetList.Where(a => a.level == AssetLevel.inApk).ToArray(); if (type > CopyBundleType.UpdateOnly) { var apkPath = GetCurrentApkPath(); if (Directory.Exists(apkPath)) EditorCommonUtility.DeleteAllFiles(apkPath); else Directory.CreateDirectory(apkPath); for (var i = 0; i < apkFiles.Length; i++) { var file = apkFiles[i]; EditorUtility.DisplayProgressBar("复制首包文件", string.Format("{0} / {1}", i + 1, apkFiles.Length), (float) i / apkFiles.Length); var fileName = file.name + AssetConst.bundleVariant; var filePath = bundlePath.Open(fileName); var targetPath = apkPath.Open(fileName); EnsureDirectory(targetPath); File.Copy(filePath, targetPath); } // 构造当前版本数字文件 var currentVersionPath = AssetConst.csAssetHeader.Open("Resources").Open(AssetConst.currentVersionFile) + AssetConst.textExtension; File.WriteAllText(EditorCommonUtility.AssetToFilePath(currentVersionPath), _currentVersion.ToString()); } // 输出全部资源清单 var streamingPathDict = new Dictionary(); foreach (var file in apkFiles) streamingPathDict.Add(file.name, file.md5); var dataPath = Application.dataPath.MoveUp().Open(AssetConst.csAssetHeader) .Open("Resources") .Open(AssetConst.assetPathDataPath) .Open(AssetConst.pathFile + AssetConst.bytesExtension); var formatter = new BinaryFormatter(); using (var fs = File.Create(dataPath)) { formatter.Serialize(fs, streamingPathDict); } } result = !error; } } EditorUtility.ClearProgressBar(); return result; } private static void EnsureDirectory(string filePath) { var dir = Path.GetDirectoryName(filePath); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); } private static string GetTempPath() { var rootPath = Application.dataPath.MoveUp(); var tempPath = rootPath.Open("AssetBundleVersioned").Open("Temp"); return tempPath; } private static string GetCurrentApkPath() { var rootPath = Application.dataPath.MoveUp(); var buildTarget = GetBuildTargetDescription(); var apkFilePath = rootPath.Open("AssetBundleVersioned").Open("ApkFile").Open(buildTarget); return apkFilePath; } private static string GetCurrentVersionPath() { var rootPath = Application.dataPath.MoveUp(); var buildTarget = GetBuildTargetDescription(); var versionPath = rootPath.Open("AssetBundleVersioned").Open(buildTarget); return versionPath; } private static string GetBuildTargetDescription() { var buildTarget = EditorUserBuildSettings.activeBuildTarget.ToString(); var dotIndex = buildTarget.LastIndexOf('.'); if (dotIndex >= 0) buildTarget = buildTarget.Substring(dotIndex); return buildTarget; } private static List InitDependencyByExcel(AssetBundleManifest manifest) { var allBundles = manifest.GetAllAssetBundles().Select(a => a.RemoveExtension()).ToArray(); List itemList = null; var readers = GetExcelText(); if (readers == null || readers.Count < 1) { ShowError("读取Excel文件失败!"); } else { // 读取Excel文件,确定资源等级 var reader = readers.Find(a => a.name == excelName); if (reader == null) { ShowError(string.Format("无法获得Excel表单{0}!", excelName)); } else { var nameId = -1; var levelId = -1; var importanceId = -1; for (var i = 0; i < reader.titles.Length; i++) { var title = reader.titles[i]; // ReSharper disable once SwitchStatementMissingSomeCases switch (title) { case excelNameKey: nameId = i; break; case excelLevelKey: levelId = i; break; case excelImportanceKey: importanceId = i; break; } } if (nameId < 0 || levelId < 0 || importanceId < 0) { ShowError(string.Format("Excel表单{0}表头不包含全部标题{1},{2}和{3}!", excelName, excelNameKey, excelLevelKey, excelImportanceKey)); } else { var error = false; // 需要执行不完整对比,因此不能直接使用字典 // 先写入Excel中的特例 var activeList = allBundles.Where(a => !a.StartsWith(ClassifyBundles.dependBundleHeader)) .ToArray(); itemList = new List(activeList.Length); // 默认等级配置到于后台下载级 foreach (var active in activeList) itemList.Add(new AssetDependencyItem { name = active, level = AssetLevel.onRunning, importance = 0 }); for (var i = 0; i < reader.contentLines.Count; i++) { var line = reader.contentLines[i]; // 初始化每行Excel的状态 var bundleFeature = line[nameId].ToUrl(); var level = 0; var importance = 0; if (!string.IsNullOrEmpty(line[levelId]) && !int.TryParse(line[levelId], out level)) { Debug.LogError(string.Format("Asset {0} in Excel has no proper level!", bundleFeature)); error = true; } else if (!string.IsNullOrEmpty(line[importanceId]) && !int.TryParse(line[importanceId], out importance)) { Debug.LogError(string.Format("Asset {0} in Excel has no proper importance!", bundleFeature)); error = true; } if (!error) { EditorUtility.DisplayProgressBar("更新资源等级", string.Format("{0} / {1}: {2}", i, reader.contentLines.Count, bundleFeature), (float) i / reader.contentLines.Count); var group = itemList.Where(a => a.name.StartsWith(bundleFeature)); foreach (var item in group) { item.level = level; item.importance = importance; } } if (error) break; } if (error) itemList = null; } } } return itemList; } // private static bool CheckInPlan(string feature, AssetBundlePlan buildPlan) // { // return buildPlan.bundleName.StartsWith(feature); // } private static List GetExcelText() { List readers = null; var error = true; var process = Process.Start(excelToolPath); if (process == null) { Debug.LogError(string.Format("Path Error: Failed to start process at path {0}!", excelToolPath)); } else { while (!process.HasExited) { } var code = process.ExitCode; if (code != 0) Debug.LogError(string.Format("Process Error: Process didn't exit properly with exit code {0}!", code)); else error = false; } if (!error) { readers = new List(); var files = Directory.GetFiles(excelTextPath, "*.txt", SearchOption.TopDirectoryOnly); foreach (var file in files) try { var reader = new TextReader(file); if (reader.error) error = true; else readers.Add(reader); } catch (Exception e) { Debug.LogError(e); } } return error ? null : readers; } private static void ShowError(string content) { EditorUtility.DisplayDialog("错误", content, "确定"); } // private string[] GetLastAssetBundles() // { // string[] result = null; // AssetBundleManifest manifest = null; // var manifestPath = bundlePath.Open("AssetBundle"); // if (File.Exists(manifestPath)) // { // var assetBundle = AssetBundle.LoadFromFile(manifestPath); // if (assetBundle) // { // manifest = assetBundle.LoadAsset("AssetBundleManifest"); // assetBundle.Unload(false); // } // } // // if (!manifest) // ShowError(string.Format("无法获得AssetBundle Manifest,于路径{0}!", manifestPath)); // else // // ReSharper disable once PossibleNullReferenceException // result = manifest.GetAllAssetBundles().Where(a => a != EditorAssetConst.dummyBundle).ToArray(); // return result; // } private enum CopyBundleType { UpdateOnly, // 仅仅复制资源服务器文件 UpdateAndApk, // 服务器文件 和 最小Apk UpdateAndFull // 服务器文件 和 全部文件到Apk } public class AssetBundlePlan { public readonly List assetPaths = new List(); public readonly string bundleName; public AssetBundlePlan(string bundle) { bundleName = bundle; } public void AddAsset(string assetPath) { assetPaths.Add(assetPath); } } } }