/// <summary> /// 动画控制器比较特殊,不能通过序列化得到 /// </summary> /// <param name="info"></param> /// <param name="o"></param> private static void AnalyzeObjectReference2(AssetBundleFileInfo info, Object o) { AnimatorController ac = o as AnimatorController; if (ac) { #if UNITY_5 || UNITY_5_3_OR_NEWER foreach (var clip in ac.animationClips) { AnalyzeObjectReference(info, clip); } #else List <State> list = new List <State>(); for (int i = 0; i < ac.layerCount; i++) { AnimatorControllerLayer layer = ac.GetLayer(i); list.AddRange(AnimatorStateMachine_StatesRecursive(layer.stateMachine)); } foreach (State state in list) { var clip = state.GetMotion() as AnimationClip; if (clip) { AnalyzeObjectReference(info, clip); } } #endif } }
/// <summary> /// 分析对象的引用 /// </summary> /// <param name="assetBundleFileInfo"></param> /// <param name="obj"></param> public static void AnalyzeObjectReference(AssetBundleFileInfo assetBundleFileInfo, Object obj) { if (obj == null || assetBundleFileInfo.objDict.ContainsKey(obj)) { return; } var serializedObject = new SerializedObject(obj); assetBundleFileInfo.objDict.Add(obj, serializedObject); if (s_InspectorMode == null) { s_InspectorMode = typeof(SerializedObject).GetProperty("inspectorMode", BindingFlags.NonPublic | BindingFlags.Instance); } s_InspectorMode.SetValue(serializedObject, InspectorMode.Debug, null); var it = serializedObject.GetIterator(); while (it.NextVisible(true)) { if (it.propertyType == SerializedPropertyType.ObjectReference && it.objectReferenceValue != null) { AnalyzeObjectReference(assetBundleFileInfo, it.objectReferenceValue); } } // 只能用另一种方式获取的引用 AnalyzeObjectReference2(assetBundleFileInfo, obj); }
/// <summary> /// 直接递归所有文件 /// </summary> /// <param name="directoryPath"></param> /// <returns></returns> private static List <AssetBundleFileInfo> AnalyzAllFiles(string directoryPath) { List <AssetBundleFileInfo> infos = new List <AssetBundleFileInfo>(); string bom = "Unity"; char[] flag = new char[5]; string[] files = Directory.GetFiles(directoryPath, "*", SearchOption.AllDirectories); foreach (var file in files) { using (StreamReader streamReader = new StreamReader(file)) { if (streamReader.Read(flag, 0, flag.Length) == flag.Length && new string(flag) == bom) { AssetBundleFileInfo info = new AssetBundleFileInfo { name = file.Substring(directoryPath.Length + 1), path = file, rootPath = directoryPath, size = streamReader.BaseStream.Length, directDepends = new string[] { }, allDepends = new string[] { } }; infos.Add(info); } } } return(infos); }
public static void AnalyzeObjectsCompleted(AssetBundleFileInfo info) { foreach (var kv in info.objDict) { AssetBundleFilesAnalyzeObject.ObjectAddToFileInfo(kv.Key, kv.Value, info); kv.Value.Dispose(); } info.objDict.Clear(); }
public void AddBundleSceneInfo(AssetBundleFileInfo info, string[] scenePaths) { #if UNITY_5_4_OR_NEWER foreach (var scenePath in scenePaths) { m_BundleSceneInfos.Enqueue(new BundleSceneInfo() { fileInfo = info, sceneName = Path.GetFileNameWithoutExtension(scenePath), scenePath = scenePath }); } #endif }
/// <summary> /// 分析Unity5方式的依赖构成 /// </summary> /// <param name="directoryPath"></param> /// <returns></returns> private static List <AssetBundleFileInfo> AnalyzeManifestDepend(string directoryPath) { string manifestName = Path.GetFileName(directoryPath); string manifestPath = Path.Combine(directoryPath, manifestName); if (!File.Exists(manifestPath)) { Debug.LogWarningFormat("{0} is not exists! Use AnalyzAllFiles ...", manifestPath); return(null); } #if UNITY_5_3_OR_NEWER AssetBundle manifestAb = AssetBundle.LoadFromFile(manifestPath); #else AssetBundle manifestAb = AssetBundle.CreateFromMemoryImmediate(File.ReadAllBytes(manifestPath)); #endif if (manifestAb == null) { Debug.LogErrorFormat("{0} ab load faild!", manifestPath); return(null); } List <AssetBundleFileInfo> assetBundleFileInfos = new List <AssetBundleFileInfo>(); #if UNITY_5 || UNITY_5_3_OR_NEWER AssetBundleManifest assetBundleManifest = manifestAb.LoadAsset <AssetBundleManifest>("assetbundlemanifest"); var assetBundles = assetBundleManifest.GetAllAssetBundles(); foreach (var assetBundle in assetBundles) { string path = Path.Combine(directoryPath, assetBundle); AssetBundleFileInfo assetBundleFileInfo = new AssetBundleFileInfo { name = assetBundle, path = path, rootPath = directoryPath, size = new FileInfo(path).Length, directDepends = assetBundleManifest.GetDirectDependencies(assetBundle), allDepends = assetBundleManifest.GetAllDependencies(assetBundle) }; assetBundleFileInfos.Add(assetBundleFileInfo); } #endif manifestAb.Unload(true); return(assetBundleFileInfos); }
private static void FillAssetByType(AssetBundleFileInfo info, string type, ExcelWorksheet ws, ref int startRow) { int count = info.GetAssetCount(type); if (count == 0) { return; } startRow++; ws.Cells[startRow, 1].Value = type + " (" + count + ")"; SetRangeStyle(ws.Cells[startRow, 1, startRow, 4]); Color redColor = ColorTranslator.FromHtml("#FF0049"); int startCol = 1; foreach (var fileInfo in info.assets) { if (fileInfo.type == type) { if (startCol == 1) { startRow++; } ws.Cells[startRow, startCol].Value = fileInfo.name; ws.Cells[startRow, startCol].Hyperlink = fileInfo.detailHyperLink; // 冗余则红色显示 if (fileInfo.includedBundles.Count > 1 && fileInfo.type != AssetFileInfoType.monoScript) { ws.Cells[startRow, startCol].Style.Font.Color.SetColor(redColor); } startCol++; if (startCol > 4) { startCol = 1; } } } }
/// <summary> /// 分析脚本的引用(这只在脚本在工程里时才有效) /// </summary> /// <param name="info"></param> /// <param name="o"></param> public static void AnalyzeObjectComponent(AssetBundleFileInfo info, Object o) { var go = o as GameObject; if (!go) { return; } var components = go.GetComponentsInChildren <Component>(true); foreach (var component in components) { if (!component) { continue; } AnalyzeObjectReference(info, component); } }
public static void Pack(string path, string outPath, AssetBundleUpdateInfo updateInfo) { int id = 0; int totalSize = 0; var allFileInfoDic = new Dictionary <int, AssetBundleFileInfo>(); path = path.Replace("\\", "/"); foreach (var assetBundle in updateInfo.PendingList.Values) { var fileInfo = new FileInfo(Path.Combine(path, assetBundle.AssetBundleName)); if (!fileInfo.Exists) { continue; } string filename = fileInfo.FullName.Replace("\\", "/"); filename = filename.Replace(path + "/", ""); int filesize = (int)fileInfo.Length; Debug.Log(id + " : " + filename + " 文件大小: " + filesize); var info = new AssetBundleFileInfo(); info.Id = id; info.Size = filesize; info.Path = filename; info.PathLength = new UTF8Encoding().GetBytes(filename).Length; info.Hash = assetBundle.Hash; using (var fs = new FileStream(fileInfo.FullName, FileMode.Open)) { info.Data = new byte[fs.Length]; fs.Read(info.Data, 0, filesize); } allFileInfoDic.Add(id, info); id++; totalSize += filesize; } /** 遍历一个文件夹的所有文件 结束 **/ Debug.Log("文件数量 : " + id); Debug.Log("文件总大小 : " + totalSize); /** UPK中前面是写每个包的ID,StartPos,size,pathLength,path. * /** 更新文件在UPK中的起始点 **/ int firstfilestartpos = 0 + 4; for (int index = 0; index < allFileInfoDic.Count; index++) { firstfilestartpos += 4 + 4 + 4 + 4 + allFileInfoDic[index].PathLength + 24; } for (int index = 0; index < allFileInfoDic.Count; index++) { int startpos; if (index == 0) { startpos = firstfilestartpos; } else { startpos = allFileInfoDic[index - 1].StartPos + allFileInfoDic[index - 1].Size; //上一个文件的开始+文件大小; } allFileInfoDic[index].StartPos = startpos; } if (File.Exists(outPath)) { File.Delete(outPath); } using (var fileStream = new FileStream(outPath, FileMode.Create)) { /** 文件总数量 **/ var totaliddata = BitConverter.GetBytes(id); fileStream.Write(totaliddata, 0, totaliddata.Length); for (int index = 0; index < allFileInfoDic.Count; index++) { /** 写入ID **/ var iddata = BitConverter.GetBytes(allFileInfoDic[index].Id); fileStream.Write(iddata, 0, iddata.Length); /** 写入StartPos **/ var startposdata = BitConverter.GetBytes(allFileInfoDic[index].StartPos); fileStream.Write(startposdata, 0, startposdata.Length); /** 写入size **/ var sizedata = BitConverter.GetBytes(allFileInfoDic[index].Size); fileStream.Write(sizedata, 0, sizedata.Length); /** 写入pathLength **/ var pathLengthdata = BitConverter.GetBytes(allFileInfoDic[index].PathLength); fileStream.Write(pathLengthdata, 0, pathLengthdata.Length); /** 写入path **/ var mypathdata = new UTF8Encoding().GetBytes(allFileInfoDic[index].Path); fileStream.Write(mypathdata, 0, mypathdata.Length); /** 写入md5 **/ var md5Data = new UTF8Encoding().GetBytes(allFileInfoDic[index].Hash); fileStream.Write(md5Data, 0, md5Data.Length); Debug.Log(allFileInfoDic[index].ToString()); var abi = updateInfo.GetAssetBundleInfoHash(allFileInfoDic[index].Hash); if (abi != null) { abi.StartOffset = allFileInfoDic[index].StartPos; } } /** 写入文件数据 **/ foreach (var infopair in allFileInfoDic) { var info = infopair.Value; int size = info.Size; int processSize = 0; while (processSize < size) { var tmpdata = size - processSize < 1024 ? new byte[size - processSize] : new byte[1024]; fileStream.Write(info.Data, processSize, tmpdata.Length); processSize += tmpdata.Length; } } } Debug.Log("打包结束"); }
public static void ObjectAddToFileInfo(Object obj, SerializedObject serializedObject, AssetBundleFileInfo info) { if (obj == null) { return; } string name2 = obj.name; string type = obj.GetType().ToString(); if (type.StartsWith("UnityEngine.", System.StringComparison.Ordinal)) { type = type.Substring(12); // 如果是内置的组件,就不当作是资源 if (obj as Component) { return; } } else if (string.Equals(type, "UnityEditor.Animations.AnimatorController", System.StringComparison.Ordinal)) { type = "AnimatorController"; } else if (string.Equals(type, "UnityEditorInternal.AnimatorController", System.StringComparison.Ordinal)) { type = "AnimatorController"; } else if (string.Equals(type == "UnityEditor.MonoScript", System.StringComparison.Ordinal)) { MonoScript ms = obj as MonoScript; string type2 = ms.GetClass().ToString(); if (type2.StartsWith("UnityEngine.", System.StringComparison.Ordinal)) { // 内置的脚本对象也不显示出来 return; } // 外部的组件脚本,保留下来 type = "MonoScript"; } else { // 外部的组件脚本,走上面的MonoScript if (obj as Component) { return; } // 外部的序列化对象,已经被脚本给分析完毕了,不需要再添加进来 if (obj as ScriptableObject) { return; } Debug.LogError("What's this? " + type); return; } // 内建的资源排除掉 string assetPath = AssetDatabase.GetAssetPath(obj); if (!string.IsNullOrEmpty(assetPath)) { return; } long guid; if (info.isScene) { // 场景的话,没法根据PathID来确定唯一性,那么就认为每个场景用到的资源都不一样 guid = (info.name + name2 + type).GetHashCode(); } else { SerializedProperty pathIdProp = serializedObject.FindProperty("m_LocalIdentfierInFile"); #if UNITY_5 || UNITY_5_3_OR_NEWER guid = pathIdProp.longValue; #else guid = pathIdProp.intValue; #endif } if (info.IsAssetContain(guid)) { return; } AssetFileInfo info2 = AssetBundleFilesAnalyze.GetAssetFileInfo(guid); info2.name = name2; info2.type = type; info2.includedBundles.Add(info); if (info2.detailHyperLink == null) { // 初次创建对象时链接为空 info2.detailHyperLink = new OfficeOpenXml.ExcelHyperLink(System.String.Empty, info2.name); info2.propertys = AnalyzeObject(obj, serializedObject, info.rootPath, info.name); } info.assets.Add(info2); }
private static void FillAssetDepends(AssetBundleFileInfo info, ExcelWorksheet ws, ref int startRow) { if (info.allDepends == null && info.beDepends == null) { return; } if (info.allDepends != null && info.beDepends != null && info.allDepends.Length == 0 && info.beDepends.Length == 0) { return; } int rowAdd = 0; int titleRow = ++startRow; if (info.allDepends != null && info.allDepends.Length != 0) { ws.Cells[titleRow, 3].Value = "它依赖哪些AssetBundle文件? (" + info.allDepends.Length + ")"; SetRangeStyle(ws.Cells[titleRow, 3, titleRow, 4]); int dependRow = titleRow; foreach (var depend in info.allDepends) { if (string.IsNullOrEmpty(depend)) { continue; } dependRow++; var dependInfo = AssetBundleFilesAnalyze.GetAssetBundleFileInfo(depend); ws.Cells[dependRow, 3].Value = dependInfo.name; ws.Cells[dependRow, 3].Hyperlink = dependInfo.detailHyperLink; ws.Cells[dependRow, 3, dependRow, 4].Merge = true; } rowAdd = dependRow - titleRow; } if (info.beDepends != null && info.beDepends.Length != 0) { ws.Cells[titleRow, 1].Value = "哪些AssetBundle文件依赖它? (" + info.beDepends.Length + ")"; SetRangeStyle(ws.Cells[titleRow, 1, titleRow, 2]); int dependRow = titleRow; foreach (var depend in info.beDepends) { dependRow++; var dependInfo = AssetBundleFilesAnalyze.GetAssetBundleFileInfo(depend); ws.Cells[dependRow, 1].Value = dependInfo.name; ws.Cells[dependRow, 1].Hyperlink = dependInfo.detailHyperLink; ws.Cells[dependRow, 1, dependRow, 2].Merge = true; } int rowAdd2 = dependRow - titleRow; if (rowAdd2 > rowAdd) { rowAdd = rowAdd2; } } startRow += rowAdd; }