using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.Serialization.Formatters.Binary; using UnityEditor; using UnityEngine; namespace WeChatWASM.Analysis { public class ReferenceFinderData { //缓存路径 private const string CACHE_PATH = "Library/ReferenceFinderCache"; //资源引用信息字典 public Dictionary assetDict = new Dictionary(); //收集资源引用信息并更新缓存 public void CollectDependenciesInfo() { try { //ReadFromCache(); var allAssets = AssetDatabase.GetAllAssetPaths(); int totalCount = allAssets.Length; for (int i = 0; i < allAssets.Length; i++) { //每遍历100个Asset,更新一下进度条,同时对进度条的取消操作进行处理 if ((i % 100 == 0) && EditorUtility.DisplayCancelableProgressBar("Refresh", string.Format("Collecting {0} assets", i), (float)i / totalCount)) { EditorUtility.ClearProgressBar(); return; } if (File.Exists(allAssets[i])) ImportAsset(allAssets[i]); if (i % 2000 == 0) GC.Collect(); } ////将信息写入缓存 //EditorUtility.DisplayCancelableProgressBar("Refresh", "Write to cache", 1f); //WriteToChache(); ////生成引用数据 //EditorUtility.DisplayCancelableProgressBar("Refresh", "Generating asset reference info", 1f); UpdateReferenceInfo(); EditorUtility.ClearProgressBar(); } catch (Exception e) { Debug.LogError(e); EditorUtility.ClearProgressBar(); } } //通过依赖信息更新引用信息 private void UpdateReferenceInfo() { foreach (var asset in assetDict) { foreach (var assetGuid in asset.Value.dependencies) { assetDict[assetGuid].references.Add(asset.Key); } } } //生成并加入引用信息 private void ImportAsset(string path) { //通过path获取guid进行储存 string guid = AssetDatabase.AssetPathToGUID(path); //获取该资源的最后修改时间,用于之后的修改判断 Hash128 assetDependencyHash = AssetDatabase.GetAssetDependencyHash(path); //如果assetDict没包含该guid或包含了修改时间不一样则需要更新 if (!assetDict.ContainsKey(guid) || assetDict[guid].assetDependencyHash != assetDependencyHash) { //将每个资源的直接依赖资源转化为guid进行储存 var guids = AssetDatabase.GetDependencies(path, false). Select(p => AssetDatabase.AssetPathToGUID(p)). ToList(); //生成asset依赖信息,被引用需要在所有的asset依赖信息生成完后才能生成 AssetDescription ad = new AssetDescription(); ad.name = Path.GetFileNameWithoutExtension(path); ad.path = path; ad.assetDependencyHash = assetDependencyHash; ad.dependencies = guids; if (assetDict.ContainsKey(guid)) assetDict[guid] = ad; else assetDict.Add(guid, ad); } } //读取缓存信息 public bool ReadFromCache() { assetDict.Clear(); if (File.Exists(CACHE_PATH)) { var serializedGuid = new List(); var serializedDependencyHash = new List(); var serializedDenpendencies = new List(); //反序列化数据 using (FileStream fs = File.OpenRead(CACHE_PATH)) { BinaryFormatter bf = new BinaryFormatter(); //EditorUtility.DisplayCancelableProgressBar("Import Cache", "Reading Cache", 0); serializedGuid = (List)bf.Deserialize(fs); serializedDependencyHash = (List)bf.Deserialize(fs); serializedDenpendencies = (List)bf.Deserialize(fs); //EditorUtility.ClearProgressBar(); } for (int i = 0; i < serializedGuid.Count; ++i) { string path = AssetDatabase.GUIDToAssetPath(serializedGuid[i]); if (!string.IsNullOrEmpty(path)) { var ad = new AssetDescription(); ad.name = Path.GetFileNameWithoutExtension(path); ad.path = path; ad.assetDependencyHash = serializedDependencyHash[i]; assetDict.Add(serializedGuid[i], ad); } } for (int i = 0; i < serializedGuid.Count; ++i) { string guid = serializedGuid[i]; if (assetDict.ContainsKey(guid)) { var guids = serializedDenpendencies[i]. Select(index => serializedGuid[index]). Where(g => assetDict.ContainsKey(g)). ToList(); assetDict[guid].dependencies = guids; } } UpdateReferenceInfo(); return true; } return false; } //写入缓存 private void WriteToChache() { if (File.Exists(CACHE_PATH)) File.Delete(CACHE_PATH); var serializedGuid = new List(); var serializedDependencyHash = new List(); var serializedDenpendencies = new List(); //辅助映射字典 var guidIndex = new Dictionary(); //序列化 using (FileStream fs = File.OpenWrite(CACHE_PATH)) { foreach (var pair in assetDict) { guidIndex.Add(pair.Key, guidIndex.Count); serializedGuid.Add(pair.Key); serializedDependencyHash.Add(pair.Value.assetDependencyHash); } foreach (var guid in serializedGuid) { int[] indexes = assetDict[guid].dependencies.Select(s => guidIndex[s]).ToArray(); serializedDenpendencies.Add(indexes); } BinaryFormatter bf = new BinaryFormatter(); bf.Serialize(fs, serializedGuid); bf.Serialize(fs, serializedDependencyHash); bf.Serialize(fs, serializedDenpendencies); } } //更新引用信息状态 public void UpdateAssetState(string guid) { AssetDescription ad; if (assetDict.TryGetValue(guid, out ad) && ad.state != AssetState.NODATA) { if (File.Exists(ad.path)) { //修改时间与记录的不同为修改过的资源 if (ad.assetDependencyHash != AssetDatabase.GetAssetDependencyHash(ad.path)) { ad.state = AssetState.CHANGED; } else { //默认为普通资源 ad.state = AssetState.NORMAL; } } //不存在为丢失 else { ad.state = AssetState.MISSING; } } //字典中没有该数据 else if (!assetDict.TryGetValue(guid, out ad)) { string path = AssetDatabase.GUIDToAssetPath(guid); ad = new AssetDescription(); ad.name = Path.GetFileNameWithoutExtension(path); ad.path = path; ad.state = AssetState.NODATA; assetDict.Add(guid, ad); } } //根据引用信息状态获取状态描述 public static string GetInfoByState(AssetState state) { if (state == AssetState.CHANGED) { return "Changed"; } else if (state == AssetState.MISSING) { return "Missing"; } else if (state == AssetState.NODATA) { return "No Data"; } return "Normal"; } public class AssetDescription { public string name = ""; public string path = ""; public Hash128 assetDependencyHash; public List dependencies = new List(); public List references = new List(); public AssetState state = AssetState.NORMAL; } public enum AssetState { NORMAL, CHANGED, MISSING, NODATA, } } }