using XGame.Framework.Asset; using System.Collections.Generic; using UnityEditor; using UnityEngine; using System.Linq; using System.Text.RegularExpressions; using System; using System.IO; using XGame.Framework.Asset.Addressable.Data; using XGame.Editor.Asset; using XGame.Editor.Build.AssetBundles; namespace XGame.Editor.Build { /// /// 该类主要是给提供给编辑器快速查询Addressable/Assetbundle信息用 /// 使用前必须保证AssetbundleMainfest已经存在 /// 该类实例会产生大量的缓存数据,注意释放问题 /// public class ProductAssetsContext: IDisposable { private Dictionary _addressableAssetMap; private Dictionary _addressableToGuidMap; #region Assetbundle private Dictionary _abBackupInfoMap; private Dictionary _bundleIdToNameMap; private Dictionary _assetNameToBundleNameMap; private Dictionary _abDependenciesMap; private Dictionary> _bundleReferencesMap; #endregion /// /// 海报资源的标签 /// public static readonly string PlacardTag = "/placard/"; /// /// 内置资源的标签 /// public string[] InnerAssetsTags = new string[] { "/XGame/", "/launch/", PlacardTag }; private IAssetsCustomHandler _customHandler; private bool IsOnlySplitCustomPackageBundles => _customHandler?.IsOnlySplitCustomPackageBundles ?? false; public bool Init() { var addressableManifest = AddressableHelper.LoadAssetManifest(); if (addressableManifest == null) { Debug.LogError($"找不到 AddressableAssetInfoManifest."); return false; } _addressableAssetMap = addressableManifest.GetAssetInfoMapWithGUID(); _addressableToGuidMap = new Dictionary(); foreach (var keyValue in _addressableAssetMap) { _addressableToGuidMap.Add(keyValue.Value.addressableName, keyValue.Key); } if (!InitAssetBundles()) { return false; } InitCustomHandler(); return true; } private bool InitAssetBundles() { var abManifest = AssetBundleBackupManifest.Load(); if (abManifest == null || abManifest.bundleInfos == null || abManifest.bundleInfos.Length == 0) return false; _abBackupInfoMap = new Dictionary(); _bundleIdToNameMap = new Dictionary(); _assetNameToBundleNameMap = new Dictionary(); _abDependenciesMap = new Dictionary(); _bundleReferencesMap = new Dictionary>(); foreach (var item in abManifest.bundleInfos) { var bundleName = item.FullName; var bundleId = item.bundleId; _abBackupInfoMap.Add(bundleName, item); _bundleIdToNameMap.Add(bundleId, bundleName); foreach(var asset in item.assets) { _assetNameToBundleNameMap.Add(asset, bundleName); } } return true; } private void InitCustomHandler() { var handlerType = typeof(IAssetsCustomHandler); var assembly = System.Reflection.Assembly.GetAssembly(handlerType); var handlerImplType = Array.Find(assembly.GetTypes(), type => type != handlerType && handlerType.IsAssignableFrom(type)); //var editorName = "XGame.Editor"; //var handlerImplType = AppDomain.CurrentDomain.GetAssemblies() // .First(assembly => assembly.GetName().Name.Equals(editorName)) // .GetTypes().First(type => type != handlerType && handlerType.IsAssignableFrom(type)); if (handlerImplType != null) { _customHandler = Activator.CreateInstance(handlerImplType) as IAssetsCustomHandler; Debug.Log($"AssetsControl: IAssetsCustomHandler {handlerImplType.FullName} if1"); } else { var assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var variable in assemblies) { // 仅扫描Editor关键字的程序集 if (!variable.FullName.Contains("Editor")) { continue; } handlerImplType = Array.Find(variable.GetTypes(), type => type != handlerType && handlerType.IsAssignableFrom(type)); if (handlerImplType != null) { _customHandler = Activator.CreateInstance(handlerImplType) as IAssetsCustomHandler; Debug.Log($"AssetsControl: IAssetsCustomHandler {handlerImplType.FullName} if2"); return; } } Debug.Log("没有找到 IAssetsCustomHandler 的实现类。"); } } public string GuidToAddressableName(string guid) { if (_addressableAssetMap.ContainsKey(guid)) { return _addressableAssetMap[guid].addressableName; } return string.Empty; } public string AddressableNameToGuid(string addressableName) { _addressableToGuidMap.TryGetValue(addressableName, out var guid); return guid; } public string AddressableToBundleName(string addressableName) { _assetNameToBundleNameMap.TryGetValue(addressableName, out var bundleName); return bundleName; } public HashSet GetBundleReferences(string bundleName) { if (_bundleReferencesMap.TryGetValue(bundleName, out var references)) { return references; } references = new HashSet(); if (!_abBackupInfoMap.TryGetValue(bundleName, out var bundle)) { return references; } var bundleId = bundle.bundleId; foreach(var item in _abBackupInfoMap) { var bundleInfo = item.Value; if (bundleInfo.bundleId == bundleId) { continue; } if (bundleInfo.DependenciesCount > 0) { foreach(var depId in bundleInfo.dependencies) { if (depId == bundleId) { references.Add(item.Key); break; } } } } _bundleReferencesMap.Add(bundleName, references); return references; } /// /// 收集海报的bundle /// /// public HashSet CollectPlacardBundles() { return CollectInnerBundles(true); } /// /// 收集所有内置的AssetBundle信息 /// /// /// public HashSet CollectInnerBundles(HashSet customPackageBundles = null) { return CollectInnerBundles(false, customPackageBundles); } public string[] GetDependenciesByBundleName(string assetBundleName) { if (string.IsNullOrEmpty(assetBundleName)) { return null; } if (_abDependenciesMap.TryGetValue(assetBundleName, out string[] dependencies)) { return dependencies; } if (_abBackupInfoMap.TryGetValue(assetBundleName, out var bundleInfo)) { int count = bundleInfo.DependenciesCount; if (count > 0) { dependencies = new string[count]; for (var index = 0; index < count; index++) { var depId = bundleInfo.dependencies[index]; dependencies[index] = _bundleIdToNameMap[depId]; } } _abDependenciesMap.Add(assetBundleName, dependencies); } return dependencies; } /// /// 收集所有内置的AssetBundle信息 /// /// 是否只收集海报资源 /// 分包资源的bundleFullName列表 /// private HashSet CollectInnerBundles(bool isPlacard, HashSet customPackageBundles = null) { //ResStatic下的依赖包至少会被两个AB包依赖 //Regex rawBundleReg = new Regex(@"(^\d+)_(\d+)"); var names = new HashSet(); //manifest names.Add(Define.MANIFEST_BUNDLE_FULLNAME); //识别所有bundle是否是内置资源 foreach (var item in _abBackupInfoMap) { var bundle = item.Value; var fullName = item.Key; if (!names.Contains(fullName)) { var isInner = false; if (bundle.bundleType == AssetBundleType.Dependency) { // 是ResStatic下的依赖包 foreach (var assetPath in bundle.assets) { if (IsInnerAsset(assetPath, isPlacard)) { isInner = true; break; } } } else { // 只分离分包资源且该ab不在分包的Assetbunle列表,则该ab保留在包内 isInner = isPlacard == false && IsOnlySplitCustomPackageBundles && customPackageBundles != null && customPackageBundles.Contains(fullName) == false; if (!isInner) { string assetPath; if (_addressableToGuidMap.TryGetValue(bundle.assets[0], out var assetGuid)) { assetPath = AssetDatabase.GUIDToAssetPath(assetGuid); } else { // ResStatic的图集资源 assetPath = bundle.assets[0]; } //其它内置资源,通过文件夹标签识别 if (IsInnerAsset(assetPath, isPlacard)) { isInner = true; } } } if (isInner) { names.Add(fullName); Debug.Log($"Inner Bundle:{bundle.nameOrGuid} Name:{fullName}"); if (bundle.DependenciesCount > 0) { names.UnionWith(GetDependenciesByBundleName(fullName)); } } } } var paths = names.ToArray(); var bundleOutputPath = PathDefine.AssetBundleOutputPath; var result = new HashSet(); for (int i = 0; i < paths.Length; i++) { result.Add(Path.Combine(bundleOutputPath, paths[i]).Replace("\\", "/")); } return result; } /// /// 判断一个资源是否是内置资源 /// /// /// /// private bool IsInnerAsset(string path, bool isPlacard) { var lowerPath = path.ToLower(); if (isPlacard) { return lowerPath.Contains(PlacardTag); } var innerAssetsTags = InnerAssetsTags; foreach (var tag in innerAssetsTags) { if (lowerPath.Contains(tag)) { return true; } } return _customHandler != null && _customHandler.IsInnerAsset(path); } void IDisposable.Dispose() { _addressableAssetMap?.Clear(); _addressableAssetMap = null; _abBackupInfoMap?.Clear(); _bundleIdToNameMap?.Clear(); _assetNameToBundleNameMap?.Clear(); _abDependenciesMap?.Clear(); } } }