using System; using System.IO; using System.Collections; using System.Collections.Generic; using UnityEngine; namespace YooAsset { /// /// 补丁清单文件 /// [Serializable] internal class PatchManifest { /// /// 文件版本 /// public string FileVersion; /// /// 启用可寻址资源定位 /// public bool EnableAddressable; /// /// 文件名称样式 /// public int OutputNameStyle; /// /// 资源包裹名称 /// public string PackageName; /// /// 资源列表(主动收集的资源列表) /// public List AssetList = new List(); /// /// 资源包列表 /// public List BundleList = new List(); /// /// 资源包集合(提供BundleName获取PatchBundle) /// [NonSerialized] public readonly Dictionary BundleDic = new Dictionary(); /// /// 资源映射集合(提供AssetPath获取PatchAsset) /// [NonSerialized] public readonly Dictionary AssetDic = new Dictionary(); /// /// 资源路径映射集合 /// [NonSerialized] public readonly Dictionary AssetPathMapping = new Dictionary(); // 资源路径映射相关 private bool _isInitAssetPathMapping = false; private bool _locationToLower = false; /// /// 初始化资源路径映射 /// public void InitAssetPathMapping(bool locationToLower) { if (_isInitAssetPathMapping) return; _isInitAssetPathMapping = true; if (EnableAddressable) { if (locationToLower) YooLogger.Error("Addressable not support location to lower !"); foreach (var patchAsset in AssetList) { string location = patchAsset.Address; if (AssetPathMapping.ContainsKey(location)) throw new Exception($"Address have existed : {location}"); else AssetPathMapping.Add(location, patchAsset.AssetPath); } } else { _locationToLower = locationToLower; foreach (var patchAsset in AssetList) { string location = patchAsset.AssetPath; if (locationToLower) location = location.ToLower(); // 添加原生路径的映射 if (AssetPathMapping.ContainsKey(location)) throw new Exception($"AssetPath have existed : {location}"); else AssetPathMapping.Add(location, patchAsset.AssetPath); // 添加无后缀名路径的映射 if (Path.HasExtension(location)) { string locationWithoutExtension = StringUtility.RemoveExtension(location); if (AssetPathMapping.ContainsKey(locationWithoutExtension)) YooLogger.Warning($"AssetPath have existed : {locationWithoutExtension}"); else AssetPathMapping.Add(locationWithoutExtension, patchAsset.AssetPath); } } } } /// /// 映射为资源路径 /// public string MappingToAssetPath(string location) { if (string.IsNullOrEmpty(location)) { YooLogger.Error("Failed to mapping location to asset path, The location is null or empty."); return string.Empty; } if (_locationToLower) location = location.ToLower(); if (AssetPathMapping.TryGetValue(location, out string assetPath)) { return assetPath; } else { YooLogger.Warning($"Failed to mapping location to asset path : {location}"); return string.Empty; } } /// /// 获取主资源包 /// 注意:传入的资源路径一定合法有效! /// public PatchBundle GetMainPatchBundle(string assetPath) { if (AssetDic.TryGetValue(assetPath, out PatchAsset patchAsset)) { int bundleID = patchAsset.BundleID; if (bundleID >= 0 && bundleID < BundleList.Count) { var patchBundle = BundleList[bundleID]; return patchBundle; } else { throw new Exception($"Invalid bundle id : {bundleID} Asset path : {assetPath}"); } } else { throw new Exception("Should never get here !"); } } /// /// 获取资源依赖列表 /// 注意:传入的资源路径一定合法有效! /// public PatchBundle[] GetAllDependencies(string assetPath) { if (AssetDic.TryGetValue(assetPath, out PatchAsset patchAsset)) { List result = new List(patchAsset.DependIDs.Length); foreach (var dependID in patchAsset.DependIDs) { if (dependID >= 0 && dependID < BundleList.Count) { var dependPatchBundle = BundleList[dependID]; result.Add(dependPatchBundle); } else { throw new Exception($"Invalid bundle id : {dependID} Asset path : {assetPath}"); } } return result.ToArray(); } else { throw new Exception("Should never get here !"); } } /// /// 尝试获取补丁资源 /// public bool TryGetPatchAsset(string assetPath, out PatchAsset result) { return AssetDic.TryGetValue(assetPath, out result); } /// /// 尝试获取补丁资源包 /// public bool TryGetPatchBundle(string bundleName, out PatchBundle result) { return BundleDic.TryGetValue(bundleName, out result); } /// /// 序列化 /// public static void Serialize(string savePath, PatchManifest patchManifest) { string json = JsonUtility.ToJson(patchManifest); FileUtility.CreateFile(savePath, json); } /// /// 反序列化 /// public static PatchManifest Deserialize(string jsonData) { PatchManifest patchManifest = JsonUtility.FromJson(jsonData); // 检测文件版本 if (patchManifest.FileVersion != YooAssetSettings.PatchManifestFileVersion) throw new Exception($"The manifest file version are not compatible : {patchManifest.FileVersion} != {YooAssetSettings.PatchManifestFileVersion}"); // BundleList foreach (var patchBundle in patchManifest.BundleList) { patchBundle.ParseFlagsValue(); patchBundle.ParseFileName(patchManifest.OutputNameStyle); patchManifest.BundleDic.Add(patchBundle.BundleName, patchBundle); } // AssetList foreach (var patchAsset in patchManifest.AssetList) { // 注意:我们不允许原始路径存在重名 string assetPath = patchAsset.AssetPath; if (patchManifest.AssetDic.ContainsKey(assetPath)) throw new Exception($"AssetPath have existed : {assetPath}"); else patchManifest.AssetDic.Add(assetPath, patchAsset); } return patchManifest; } } }