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();
}
}
}