123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- 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
- {
- /// <summary>
- /// 该类主要是给提供给编辑器快速查询Addressable/Assetbundle信息用
- /// 使用前必须保证AssetbundleMainfest已经存在
- /// 该类实例会产生大量的缓存数据,注意释放问题
- /// </summary>
- public class ProductAssetsContext: IDisposable
- {
- private Dictionary<string, AssetInfo> _addressableAssetMap;
- private Dictionary<string, string> _addressableToGuidMap;
- #region Assetbundle
- private Dictionary<string, AssetBundleBackupInfo> _abBackupInfoMap;
- private Dictionary<uint, string> _bundleIdToNameMap;
- private Dictionary<string, string> _assetNameToBundleNameMap;
- private Dictionary<string, string[]> _abDependenciesMap;
- private Dictionary<string, HashSet<string>> _bundleReferencesMap;
- #endregion
- /// <summary>
- /// 海报资源的标签
- /// </summary>
- public static readonly string PlacardTag = "/placard/";
- /// <summary>
- /// 内置资源的标签
- /// </summary>
- 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<string, string>();
- 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<string, AssetBundleBackupInfo>();
- _bundleIdToNameMap = new Dictionary<uint, string>();
- _assetNameToBundleNameMap = new Dictionary<string, string>();
- _abDependenciesMap = new Dictionary<string, string[]>();
- _bundleReferencesMap = new Dictionary<string, HashSet<string>>();
- 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<string> GetBundleReferences(string bundleName)
- {
- if (_bundleReferencesMap.TryGetValue(bundleName, out var references))
- {
- return references;
- }
- references = new HashSet<string>();
- 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;
- }
- /// <summary>
- /// 收集海报的bundle
- /// </summary>
- /// <returns></returns>
- public HashSet<string> CollectPlacardBundles()
- {
- return CollectInnerBundles(true);
- }
- /// <summary>
- /// 收集所有内置的AssetBundle信息
- /// </summary>
- /// <param name="customPackageBundles"></param>
- /// <returns></returns>
- public HashSet<string> CollectInnerBundles(HashSet<string> 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;
- }
- /// <summary>
- /// 收集所有内置的AssetBundle信息
- /// </summary>
- /// <param name="isPlacard">是否只收集海报资源</param>
- /// <param name="customPackageBundles">分包资源的bundleFullName列表</param>
- /// <returns></returns>
- private HashSet<string> CollectInnerBundles(bool isPlacard, HashSet<string> customPackageBundles = null)
- {
- //ResStatic下的依赖包至少会被两个AB包依赖
- //Regex rawBundleReg = new Regex(@"(^\d+)_(\d+)");
- var names = new HashSet<string>();
- //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<string>();
- for (int i = 0; i < paths.Length; i++)
- {
- result.Add(Path.Combine(bundleOutputPath, paths[i]).Replace("\\", "/"));
- }
- return result;
- }
- /// <summary>
- /// 判断一个资源是否是内置资源
- /// </summary>
- /// <param name="path"></param>
- /// <param name="isPlacard"></param>
- /// <returns></returns>
- 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();
- }
- }
- }
|