JJBB/Assets/Editor/AssetUpdate/AssetVersionWindow.cs
2024-09-03 19:56:21 +08:00

894 lines
41 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<AssetVersionWindow>("游戏版本管理器");
}
// 已经过时在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<string, string>();
// 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<string, string>();
// var plans = LoadAssetMarkFile();
// foreach (var plan in plans)
// foreach (var assetPath in plan.assetPaths)
// target[assetPath] = plan.bundleName;
// // 对比获得移除部分
// var removeNames = new HashSet<string>();
// // 对比获得修改部分
// var addNames = new Dictionary<string, string>();
// 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<AssetBundlePlan> LoadAssetMarkFile()
{
var result = new List<AssetBundlePlan>();
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>("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<AssetDependencyItem>();
// 灌注全部物品信息
// 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<AssetDependencyInfo>();
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<string, string>();
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<AssetDependencyItem> InitDependencyByExcel(AssetBundleManifest manifest)
{
var allBundles = manifest.GetAllAssetBundles().Select(a => a.RemoveExtension()).ToArray();
List<AssetDependencyItem> 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<AssetDependencyItem>(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<TextReader> GetExcelText()
{
List<TextReader> 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<TextReader>();
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>("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<string> assetPaths = new List<string>();
public readonly string bundleName;
public AssetBundlePlan(string bundle)
{
bundleName = bundle;
}
public void AddAsset(string assetPath)
{
assetPaths.Add(assetPath);
}
}
}
}