using System; using System.IO; using System.Diagnostics; using System.Collections; using System.Collections.Generic; namespace YooAsset { /// /// 清单文件 /// [Serializable] internal class PackageManifest { /// /// 文件版本 /// public string FileVersion; /// /// 启用可寻址资源定位 /// public bool EnableAddressable; /// /// 资源定位地址大小写不敏感 /// public bool LocationToLower; /// /// 包含资源GUID数据 /// public bool IncludeAssetGUID; /// /// 文件名称样式 /// public int OutputNameStyle; /// /// 构建管线名称 /// public string BuildPipeline; /// /// 资源包裹名称 /// public string PackageName; /// /// 资源包裹的版本信息 /// public string PackageVersion; /// /// 资源列表(主动收集的资源列表) /// public List AssetList = new List(); /// /// 资源包列表 /// public List BundleList = new List(); /// /// 资源包集合(提供BundleName获取PackageBundle) /// [NonSerialized] public Dictionary BundleDic1; /// /// 资源包集合(提供FileName获取PackageBundle) /// [NonSerialized] public Dictionary BundleDic2; /// /// 资源包集合(提供BundleGUID获取PackageBundle) /// [NonSerialized] public Dictionary BundleDic3; /// /// 资源映射集合(提供AssetPath获取PackageAsset) /// [NonSerialized] public Dictionary AssetDic; /// /// 资源路径映射集合(提供Location获取AssetPath) /// [NonSerialized] public Dictionary AssetPathMapping1; /// /// 资源路径映射集合(提供AssetGUID获取AssetPath) /// [NonSerialized] public Dictionary AssetPathMapping2; /// /// 尝试映射为资源路径 /// public string TryMappingToAssetPath(string location) { if (string.IsNullOrEmpty(location)) return string.Empty; if (LocationToLower) location = location.ToLower(); if (AssetPathMapping1.TryGetValue(location, out string assetPath)) return assetPath; else return string.Empty; } /// /// 获取主资源包 /// 注意:传入的资源路径一定合法有效! /// public PackageBundle GetMainPackageBundle(string assetPath) { if (AssetDic.TryGetValue(assetPath, out PackageAsset packageAsset)) { int bundleID = packageAsset.BundleID; if (bundleID >= 0 && bundleID < BundleList.Count) { var packageBundle = BundleList[bundleID]; return packageBundle; } else { throw new Exception($"Invalid bundle id : {bundleID} Asset path : {assetPath}"); } } else { throw new Exception("Should never get here !"); } } /// /// 获取资源依赖列表 /// 注意:传入的资源路径一定合法有效! /// public PackageBundle[] GetAllDependencies(string assetPath) { var packageBundle = GetMainPackageBundle(assetPath); List result = new List(packageBundle.DependIDs.Length); foreach (var dependID in packageBundle.DependIDs) { if (dependID >= 0 && dependID < BundleList.Count) { var dependBundle = BundleList[dependID]; result.Add(dependBundle); } else { throw new Exception($"Invalid bundle id : {dependID} Asset path : {assetPath}"); } } return result.ToArray(); } /// /// 尝试获取包裹的资源 /// public bool TryGetPackageAsset(string assetPath, out PackageAsset result) { return AssetDic.TryGetValue(assetPath, out result); } /// /// 尝试获取包裹的资源包 /// public bool TryGetPackageBundleByBundleName(string bundleName, out PackageBundle result) { return BundleDic1.TryGetValue(bundleName, out result); } /// /// 尝试获取包裹的资源包 /// public bool TryGetPackageBundleByFileName(string fileName, out PackageBundle result) { return BundleDic2.TryGetValue(fileName, out result); } /// /// 尝试获取包裹的资源包 /// public bool TryGetPackageBundleByBundleGUID(string bundleGUID, out PackageBundle result) { return BundleDic3.TryGetValue(bundleGUID, out result); } /// /// 是否包含资源文件 /// public bool IsIncludeBundleFile(string bundleGUID) { return BundleDic3.ContainsKey(bundleGUID); } /// /// 获取资源信息列表 /// public AssetInfo[] GetAssetsInfoByTags(string[] tags) { List result = new List(100); foreach (var packageAsset in AssetList) { if (packageAsset.HasTag(tags)) { AssetInfo assetInfo = new AssetInfo(PackageName, packageAsset, null); result.Add(assetInfo); } } return result.ToArray(); } /// /// 资源定位地址转换为资源信息。 /// /// 如果转换失败会返回一个无效的资源信息类 public AssetInfo ConvertLocationToAssetInfo(string location, System.Type assetType) { DebugCheckLocation(location); string assetPath = ConvertLocationToAssetInfoMapping(location); if (TryGetPackageAsset(assetPath, out PackageAsset packageAsset)) { AssetInfo assetInfo = new AssetInfo(PackageName, packageAsset, assetType); return assetInfo; } else { string error; if (string.IsNullOrEmpty(location)) error = $"The location is null or empty !"; else error = $"The location is invalid : {location}"; AssetInfo assetInfo = new AssetInfo(PackageName, error); return assetInfo; } } private string ConvertLocationToAssetInfoMapping(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 (AssetPathMapping1.TryGetValue(location, out string assetPath)) { return assetPath; } else { YooLogger.Warning($"Failed to mapping location to asset path : {location}"); return string.Empty; } } /// /// 资源GUID转换为资源信息。 /// /// 如果转换失败会返回一个无效的资源信息类 public AssetInfo ConvertAssetGUIDToAssetInfo(string assetGUID, System.Type assetType) { if (IncludeAssetGUID == false) { YooLogger.Warning("Package manifest not include asset guid ! Please check asset bundle collector settings."); AssetInfo assetInfo = new AssetInfo(PackageName, "AssetGUID data is empty !"); return assetInfo; } string assetPath = ConvertAssetGUIDToAssetInfoMapping(assetGUID); if (TryGetPackageAsset(assetPath, out PackageAsset packageAsset)) { AssetInfo assetInfo = new AssetInfo(PackageName, packageAsset, assetType); return assetInfo; } else { string error; if (string.IsNullOrEmpty(assetGUID)) error = $"The assetGUID is null or empty !"; else error = $"The assetGUID is invalid : {assetGUID}"; AssetInfo assetInfo = new AssetInfo(PackageName, error); return assetInfo; } } private string ConvertAssetGUIDToAssetInfoMapping(string assetGUID) { if (string.IsNullOrEmpty(assetGUID)) { YooLogger.Error("Failed to mapping assetGUID to asset path, The assetGUID is null or empty."); return string.Empty; } if (AssetPathMapping2.TryGetValue(assetGUID, out string assetPath)) { return assetPath; } else { YooLogger.Warning($"Failed to mapping assetGUID to asset path : {assetGUID}"); return string.Empty; } } /// /// 获取资源包内的主资源列表 /// public string[] GetBundleIncludeAssets(string assetPath) { List assetList = new List(); if (TryGetPackageAsset(assetPath, out PackageAsset result)) { foreach (var packageAsset in AssetList) { if (packageAsset.BundleID == result.BundleID) { assetList.Add(packageAsset.AssetPath); } } } return assetList.ToArray(); } #region 调试方法 [Conditional("DEBUG")] private void DebugCheckLocation(string location) { if (string.IsNullOrEmpty(location) == false) { // 检查路径末尾是否有空格 int index = location.LastIndexOf(' '); if (index != -1) { if (location.Length == index + 1) YooLogger.Warning($"Found blank character in location : \"{location}\""); } if (location.IndexOfAny(System.IO.Path.GetInvalidPathChars()) >= 0) YooLogger.Warning($"Found illegal character in location : \"{location}\""); } } #endregion } }