291 lines
9.7 KiB
C#
291 lines
9.7 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Runtime.Serialization.Formatters.Binary;
|
||
using UnityEditor;
|
||
using UnityEngine;
|
||
|
||
public class ReferenceFinderData
|
||
{
|
||
//缓存路径
|
||
private const string CACHE_PATH = "Library/ReferenceFinderCache";
|
||
private const string CACHE_VERSION = "V1";
|
||
//资源引用信息字典
|
||
public Dictionary<string, AssetDescription> assetDict = new Dictionary<string, AssetDescription>();
|
||
|
||
//收集资源引用信息并更新缓存
|
||
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)
|
||
{
|
||
AssetDescription assetDescription = null;
|
||
if (assetDict.TryGetValue(assetGuid, out assetDescription))
|
||
{
|
||
if (!assetDescription.references.Contains(asset.Key))
|
||
{
|
||
assetDescription.references.Add(asset.Key);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//生成并加入引用信息
|
||
private void ImportAsset(string path)
|
||
{
|
||
if (!path.StartsWith("Assets/"))
|
||
return;
|
||
|
||
//通过path获取guid进行储存
|
||
string guid = AssetDatabase.AssetPathToGUID(path);
|
||
//获取该资源的最后修改时间,用于之后的修改判断
|
||
FileInfo fi = new FileInfo(path);
|
||
Hash128 assetDependencyHash = AssetDatabase.GetAssetDependencyHash(path);
|
||
string assetDependencyString = assetDependencyHash.ToString() + fi.LastWriteTime.ToString();
|
||
|
||
//如果assetDict没包含该guid或包含了修改时间不一样则需要更新
|
||
if (!assetDict.ContainsKey(guid) || assetDict[guid].assetDependencyHash != assetDependencyString)
|
||
{
|
||
//将每个资源的直接依赖资源转化为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 = assetDependencyString;
|
||
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))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
var serializedGuid = new List<string>();
|
||
var serializedDependencyHash = new List<string>();
|
||
var serializedDenpendencies = new List<int[]>();
|
||
//反序列化数据
|
||
FileStream fs = File.OpenRead(CACHE_PATH);
|
||
try
|
||
{
|
||
BinaryFormatter bf = new BinaryFormatter();
|
||
string cacheVersion = (string) bf.Deserialize(fs);
|
||
if (cacheVersion != CACHE_VERSION)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
EditorUtility.DisplayCancelableProgressBar("Import Cache", "Reading Cache", 0);
|
||
serializedGuid = (List<string>) bf.Deserialize(fs);
|
||
serializedDependencyHash = (List<string>) bf.Deserialize(fs);
|
||
serializedDenpendencies = (List<int[]>) bf.Deserialize(fs);
|
||
EditorUtility.ClearProgressBar();
|
||
}
|
||
catch
|
||
{
|
||
//兼容旧版本序列化格式
|
||
return false;
|
||
}
|
||
finally
|
||
{
|
||
fs.Close();
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
//写入缓存
|
||
private void WriteToChache()
|
||
{
|
||
if (File.Exists(CACHE_PATH))
|
||
File.Delete(CACHE_PATH);
|
||
|
||
var serializedGuid = new List<string>();
|
||
var serializedDependencyHash = new List<string>();
|
||
var serializedDenpendencies = new List<int[]>();
|
||
//辅助映射字典
|
||
var guidIndex = new Dictionary<string, int>();
|
||
//序列化
|
||
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)
|
||
{
|
||
//使用 Where 子句过滤目录
|
||
int[] indexes = assetDict[guid].dependencies.
|
||
Where(s => guidIndex.ContainsKey(s)).
|
||
Select(s => guidIndex[s]).ToArray();
|
||
serializedDenpendencies.Add(indexes);
|
||
}
|
||
|
||
BinaryFormatter bf = new BinaryFormatter();
|
||
bf.Serialize(fs, CACHE_VERSION);
|
||
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))
|
||
{
|
||
//修改时间与记录的不同为修改过的资源
|
||
|
||
FileInfo fi = new FileInfo(ad.path);
|
||
Hash128 assetDependencyHash = AssetDatabase.GetAssetDependencyHash(ad.path);
|
||
string assetDependencyString = assetDependencyHash.ToString() + fi.LastWriteTime.ToString();
|
||
if (ad.assetDependencyHash != assetDependencyString)
|
||
{
|
||
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 "<color=#F0672AFF>Changed</color>";
|
||
}
|
||
else if (state == AssetState.MISSING)
|
||
{
|
||
return "<color=#FF0000FF>Missing</color>";
|
||
}
|
||
else if(state == AssetState.NODATA)
|
||
{
|
||
return "<color=#FFE300FF>No Data</color>";
|
||
}
|
||
return "Normal";
|
||
}
|
||
|
||
public class AssetDescription
|
||
{
|
||
public string name = "";
|
||
public string path = "";
|
||
public string assetDependencyHash;
|
||
public List<string> dependencies = new List<string>();
|
||
public List<string> references = new List<string>();
|
||
public AssetState state = AssetState.NORMAL;
|
||
}
|
||
|
||
public enum AssetState
|
||
{
|
||
NORMAL,
|
||
CHANGED,
|
||
MISSING,
|
||
NODATA,
|
||
}
|
||
}
|