| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Text;
- using UnityEditor;
- using UnityEngine;
- namespace YooAsset.Editor
- {
- /// <summary>
- /// 资源依赖数据库
- /// </summary>
- public class AssetDependencyDatabase
- {
- private const string FILE_VERSION = "1.0";
- private class DependencyInfo
- {
- /// <summary>
- /// 此哈希函数会聚合了以下内容:源资源路径、源资源、元文件、目标平台以及导入器版本。
- /// 如果此哈希值发送变化,则说明导入资源可能已更改,因此应重新搜集依赖关系。
- /// </summary>
- public string DependHash;
- /// <summary>
- /// 直接依赖资源的GUID列表
- /// </summary>
- public List<string> DependGUIDs = new List<string>();
- }
- private string _databaseFilePath;
- private readonly Dictionary<string, DependencyInfo> _database = new Dictionary<string, DependencyInfo>(100000);
- /// <summary>
- /// 创建缓存数据库
- /// </summary>
- public void CreateDatabase(bool readCacheDatabaseFile, string databaseFilePath)
- {
- _databaseFilePath = databaseFilePath;
- _database.Clear();
- FileStream stream = null;
- BinaryReader reader = null;
- try
- {
- if (readCacheDatabaseFile && File.Exists(databaseFilePath))
- {
- // 解析缓存文件
- stream = File.OpenRead(databaseFilePath);
- reader = new BinaryReader(stream);
- string fileVersion = reader.ReadString();
- if (fileVersion != FILE_VERSION)
- throw new Exception("The database file version not match !");
- var count = reader.ReadInt32();
- for (int i = 0; i < count; i++)
- {
- var assetPath = reader.ReadString();
- var cacheInfo = new DependencyInfo
- {
- DependHash = reader.ReadString(),
- DependGUIDs = ReadStringList(reader),
- };
- _database.Add(assetPath, cacheInfo);
- }
- // 移除无效资源
- List<string> removeList = new List<string>(10000);
- foreach (var cacheInfoPair in _database)
- {
- var assetPath = cacheInfoPair.Key;
- var assetGUID = AssetDatabase.AssetPathToGUID(assetPath);
- if (string.IsNullOrEmpty(assetGUID))
- {
- removeList.Add(assetPath);
- }
- }
- foreach (var assetPath in removeList)
- {
- _database.Remove(assetPath);
- }
- }
- }
- catch (Exception ex)
- {
- ClearDatabase(true);
- Debug.LogError($"Failed to load cache database : {ex.Message}");
- }
- finally
- {
- if (reader != null)
- reader.Close();
- if (stream != null)
- stream.Close();
- }
- // 查找新增或变动资源
- var allAssetPaths = AssetDatabase.GetAllAssetPaths();
- foreach (var assetPath in allAssetPaths)
- {
- if (_database.TryGetValue(assetPath, out DependencyInfo cacheInfo))
- {
- var dependHash = AssetDatabase.GetAssetDependencyHash(assetPath);
- if (dependHash.ToString() != cacheInfo.DependHash)
- {
- _database[assetPath] = CreateDependencyInfo(assetPath);
- }
- }
- else
- {
- var newCacheInfo = CreateDependencyInfo(assetPath);
- _database.Add(assetPath, newCacheInfo);
- }
- }
- }
- /// <summary>
- /// 保存缓存数据库
- /// </summary>
- public void SaveDatabase()
- {
- if (File.Exists(_databaseFilePath))
- File.Delete(_databaseFilePath);
- FileStream stream = null;
- BinaryWriter writer = null;
- try
- {
- stream = File.Create(_databaseFilePath);
- writer = new BinaryWriter(stream);
- writer.Write(FILE_VERSION);
- writer.Write(_database.Count);
- foreach (var assetPair in _database)
- {
- string assetPath = assetPair.Key;
- var assetInfo = assetPair.Value;
- writer.Write(assetPath);
- writer.Write(assetInfo.DependHash);
- WriteStringList(writer, assetInfo.DependGUIDs);
- }
- writer.Flush();
- }
- catch (Exception ex)
- {
- Debug.LogError($"Failed to save cache database : {ex.Message}");
- }
- finally
- {
- if (writer != null)
- writer.Close();
- if (stream != null)
- stream.Close();
- }
- }
- /// <summary>
- /// 清理缓存数据库
- /// </summary>
- public void ClearDatabase(bool deleteDatabaseFile)
- {
- if (deleteDatabaseFile)
- {
- if (File.Exists(_databaseFilePath))
- File.Delete(_databaseFilePath);
- }
- _database.Clear();
- }
- /// <summary>
- /// 获取资源的依赖列表
- /// </summary>
- public string[] GetDependencies(string assetPath, bool recursive)
- {
- // 注意:AssetDatabase.GetDependencies()方法返回结果里会踢出丢失文件!
- // 注意:AssetDatabase.GetDependencies()方法返回结果里会包含主资源路径!
- // 注意:机制上不允许存在未收录的资源
- if (_database.ContainsKey(assetPath) == false)
- {
- throw new Exception($"Fatal : can not found cache info : {assetPath}");
- }
- var result = new HashSet<string> { assetPath };
- CollectDependencies(assetPath, result, recursive);
- // 注意:AssetDatabase.GetDependencies保持一致,将主资源添加到依赖列表最前面
- return result.ToArray();
- }
- private void CollectDependencies(string assetPath, HashSet<string> result, bool recursive)
- {
- if (_database.TryGetValue(assetPath, out var cacheInfo) == false)
- {
- throw new Exception($"Fatal : can not found cache info : {assetPath}");
- }
- foreach (var dependGUID in cacheInfo.DependGUIDs)
- {
- string dependAssetPath = AssetDatabase.GUIDToAssetPath(dependGUID);
- if (string.IsNullOrEmpty(dependAssetPath))
- continue;
- // 如果是文件夹资源
- if (AssetDatabase.IsValidFolder(dependAssetPath))
- continue;
- // 如果已经收集过
- if (result.Contains(dependAssetPath))
- continue;
- result.Add(dependAssetPath);
- // 递归收集依赖
- if (recursive)
- CollectDependencies(dependAssetPath, result, recursive);
- }
- }
- private List<string> ReadStringList(BinaryReader reader)
- {
- var count = reader.ReadInt32();
- var values = new List<string>(count);
- for (int i = 0; i < count; i++)
- {
- values.Add(reader.ReadString());
- }
- return values;
- }
- private void WriteStringList(BinaryWriter writer, List<string> values)
- {
- writer.Write(values.Count);
- foreach (var value in values)
- {
- writer.Write(value);
- }
- }
- private DependencyInfo CreateDependencyInfo(string assetPath)
- {
- var dependHash = AssetDatabase.GetAssetDependencyHash(assetPath);
- var dependAssetPaths = AssetDatabase.GetDependencies(assetPath, false);
- var dependGUIDs = new List<string>();
- foreach (var dependAssetPath in dependAssetPaths)
- {
- string guid = AssetDatabase.AssetPathToGUID(dependAssetPath);
- if (string.IsNullOrEmpty(guid) == false)
- {
- dependGUIDs.Add(guid);
- }
- }
- var cacheInfo = new DependencyInfo();
- cacheInfo.DependHash = dependHash.ToString();
- cacheInfo.DependGUIDs = dependGUIDs;
- return cacheInfo;
- }
- }
- }
|