using System; using System.IO; using System.Collections; using System.Collections.Generic; using System.Diagnostics; namespace YooAsset { internal static class CacheSystem { private readonly static Dictionary _cachedDic = new Dictionary(1000); /// /// 禁用Unity缓存系统在WebGL平台 /// public static bool DisableUnityCacheOnWebGL = false; /// /// 初始化时的验证级别 /// public static EVerifyLevel InitVerifyLevel { set; get; } = EVerifyLevel.Middle; /// /// 清空所有数据 /// public static void ClearAll() { _cachedDic.Clear(); } /// /// 清空指定包裹的所有缓存数据 /// public static void ClearPackage(string packageName) { var cache = GetOrCreateCache(packageName); cache.ClearAll(); } /// /// 获取缓存文件总数 /// public static int GetCachedFilesCount(string packageName) { var cache = GetOrCreateCache(packageName); return cache.GetCachedFilesCount(); } /// /// 查询是否为验证文件 /// public static bool IsCached(string packageName, string cacheGUID) { var cache = GetOrCreateCache(packageName); return cache.IsCached(cacheGUID); } /// /// 录入验证的文件 /// public static void RecordFile(string packageName, string cacheGUID, PackageCache.RecordWrapper wrapper) { //YooLogger.Log($"Record file : {packageName} = {cacheGUID}"); var cache = GetOrCreateCache(packageName); cache.Record(cacheGUID, wrapper); } /// /// 丢弃验证的文件(同时删除文件) /// public static void DiscardFile(string packageName, string cacheGUID) { var cache = GetOrCreateCache(packageName); var wrapper = cache.TryGetWrapper(cacheGUID); if (wrapper == null) return; cache.Discard(cacheGUID); try { string dataFilePath = wrapper.DataFilePath; FileInfo fileInfo = new FileInfo(dataFilePath); if (fileInfo.Exists) fileInfo.Directory.Delete(true); } catch (Exception e) { YooLogger.Error($"Failed to delete cache file ! {e.Message}"); } } /// /// 验证缓存文件(子线程内操作) /// public static EVerifyResult VerifyingCacheFile(VerifyCacheFileElement element) { try { if (InitVerifyLevel == EVerifyLevel.Low) { if (File.Exists(element.InfoFilePath) == false) return EVerifyResult.InfoFileNotExisted; if (File.Exists(element.DataFilePath) == false) return EVerifyResult.DataFileNotExisted; return EVerifyResult.Succeed; } else { if (File.Exists(element.InfoFilePath) == false) return EVerifyResult.InfoFileNotExisted; // 解析信息文件获取验证数据 CacheFileInfo.ReadInfoFromFile(element.InfoFilePath, out element.DataFileCRC, out element.DataFileSize); } } catch (Exception) { return EVerifyResult.Exception; } return VerifyingInternal(element.DataFilePath, element.DataFileSize, element.DataFileCRC, InitVerifyLevel); } /// /// 验证下载文件(子线程内操作) /// public static EVerifyResult VerifyingTempFile(VerifyTempFileElement element) { return VerifyingInternal(element.TempDataFilePath, element.FileSize, element.FileCRC, EVerifyLevel.High); } /// /// 验证记录文件(主线程内操作) /// public static EVerifyResult VerifyingRecordFile(string packageName, string cacheGUID) { var cache = GetOrCreateCache(packageName); var wrapper = cache.TryGetWrapper(cacheGUID); if (wrapper == null) return EVerifyResult.CacheNotFound; EVerifyResult result = VerifyingInternal(wrapper.DataFilePath, wrapper.DataFileSize, wrapper.DataFileCRC, EVerifyLevel.High); return result; } /// /// 获取未被使用的缓存文件 /// public static List GetUnusedCacheGUIDs(ResourcePackage package) { var cache = GetOrCreateCache(package.PackageName); var keys = cache.GetAllKeys(); List result = new List(keys.Count); foreach (var cacheGUID in keys) { if (package.IsIncludeBundleFile(cacheGUID) == false) { result.Add(cacheGUID); } } return result; } /// /// 获取所有的缓存文件 /// public static List GetAllCacheGUIDs(ResourcePackage package) { var cache = GetOrCreateCache(package.PackageName); return cache.GetAllKeys(); } private static EVerifyResult VerifyingInternal(string filePath, long fileSize, string fileCRC, EVerifyLevel verifyLevel) { try { if (File.Exists(filePath) == false) return EVerifyResult.DataFileNotExisted; // 先验证文件大小 long size = FileUtility.GetFileSize(filePath); if (size < fileSize) return EVerifyResult.FileNotComplete; else if (size > fileSize) return EVerifyResult.FileOverflow; // 再验证文件CRC if (verifyLevel == EVerifyLevel.High) { string crc = HashUtility.FileCRC32(filePath); if (crc == fileCRC) return EVerifyResult.Succeed; else return EVerifyResult.FileCrcError; } else { return EVerifyResult.Succeed; } } catch (Exception) { return EVerifyResult.Exception; } } private static PackageCache GetOrCreateCache(string packageName) { if (_cachedDic.TryGetValue(packageName, out PackageCache cache) == false) { cache = new PackageCache(packageName); _cachedDic.Add(packageName, cache); } return cache; } } }