using XGame.Framework.Asyncs;
using XGame.Framework.Utils;
using System.Collections.Generic;
using UnityEngine;
namespace XGame.Framework.Asset
{
///
/// AssetBundle的加载方式,需要先实现Bundle的Manifest管理
///
internal partial class AssetBundleLoader : BaseLoader, IAssetLoader
{
private IAssetBundleManifest _bundleManifest;
private IAssetReferencesManifest _referenceManifest;
private ISceneInfosManifest _sceneInfosManifest;
///
/// 已加载的Bundle仓库
///
private BundleRepository Repository { set; get; }
public bool IsBundleEncrypt { set; get; }
public AssetBundleLoader(IAssetBundleManifest bundleManifest, IAssetReferencesManifest referenceManifest, ISceneInfosManifest sceneInfosManifest)
{
Repository = new BundleRepository();
_bundleManifest = bundleManifest;
_referenceManifest = referenceManifest;
_sceneInfosManifest = sceneInfosManifest;
}
public IAssetAsync LoadAsync(string addressableName)
{
if (!TryGetBundleInfo(addressableName, out string bundleName, out string[] dependencies))
{ //找不到bundle信息
AssetsLog.Error($"Can't find bundleInfo. Name:{addressableName}");
return null;
}
var assetFromCacheAsync = CreateAssetFromCacheAsync(addressableName);
if (assetFromCacheAsync != null)
{ //从Repository拿出来的asset,可以直接结束该异步
assetFromCacheAsync.Start();
return assetFromCacheAsync;
}
if (AsyncPool.GetAssetAsync(addressableName) is AssetLoadFromBundleAsync assetLoadAsync)
{
//Asset 正在加载
return assetLoadAsync;
}
assetLoadAsync = new AssetLoadFromBundleAsync
{
AddressableName = addressableName,
BundleName = bundleName,
IsSprite = typeof(TResult) == typeof(Sprite),
GetBundleFromCache = GetAssetBundleByName,
};
List asyncs = new List();
if (dependencies != null)
{//收集依赖的bundle Async
foreach (var dep in dependencies)
{
var async = CreateBundleAsync(dep);
if (async != null)
{
asyncs.Add(async);
}
}
}
var bundleAsync = CreateBundleAsync(bundleName);
if (bundleAsync != null)
{ //自己的bundle Async
asyncs.Add(bundleAsync);
}
if (asyncs.Count > 0)
{
AsyncGroup group = new AsyncGroup();
foreach (var async in asyncs)
{
group.AddAsync(async);
}
//先赋值
assetLoadAsync.BundleAsyncGroup = group;
//再将Async加进Pool
foreach (var async in asyncs)
{
AsyncPool.AddAsync(async);
}
group.End();
asyncs.Clear();
}
assetLoadAsync.On(OnAssetCompleted);
AsyncPool.AddAsync(assetLoadAsync);
return assetLoadAsync;
}
public object LoadSync(string addressableName)
{
if (!TryGetBundleInfo(addressableName, out string bundleName, out string[] dependencies))
{ //找不到bundle信息
AssetsLog.Error($"Can't find bundleInfo. Name:{addressableName}");
return null;
}
//先从Repository查找缓存的Asset
if (Repository.ContainsUnusedAsset(addressableName))
{
return Repository.PopUnusedAsset(addressableName);
}
if (AsyncPool.ContainsAssetAsync(addressableName))
{//该Asset正在加载使用异步加载
AssetsLog.Info($"{addressableName} is loading asynchronously, but load synchronously again.");
}
//先加载依赖的bundle
if (dependencies != null)
{
foreach (var dep in dependencies)
{
LoadBundleSync(dep);
}
}
//加载bundle
var assetType = typeof(TResult);
var isSprite = assetType == typeof(Sprite);
var bundle = LoadBundleSync(bundleName);
var asset = isSprite ? bundle?.LoadAsset(addressableName, assetType) : bundle?.LoadAsset(addressableName);
if (asset != null)
Repository.RegistAssetHash(asset.GetInstanceID(), addressableName);
return asset;
}
public IAssetAsync LoadSceneBundleAsync(string sceneName)
{
//获取bundle信息
if (!TryGetSceneBundleInfo(sceneName, out string bundleName, out string[] dependencies))
{ //找不到bundle信息
AssetsLog.Error($"Can't find bundleInfo. Name:{sceneName}");
return null;
}
if (AsyncPool.GetAssetAsync(sceneName) is SceneLoadAsync sceneLoadAsync)
{
//AssetBundle 正在加载
return sceneLoadAsync;
}
sceneLoadAsync = new SceneLoadAsync
{
AddressableName = sceneName,
};
List asyncs = new List();
if (dependencies != null)
{//收集依赖的bundle Async
foreach (var dep in dependencies)
{
var async = CreateBundleAsync(dep);
if (async != null)
{
asyncs.Add(async);
}
}
}
var bundleAsync = CreateBundleAsync(bundleName);
if (bundleAsync != null)
{ //自己的bundle Async
asyncs.Add(bundleAsync);
}
if (asyncs.Count > 0)
{
AsyncGroup group = new AsyncGroup();
foreach (var async in asyncs)
{
group.AddAsync(async);
}
//先赋值
sceneLoadAsync.BundleAsyncGroup = group;
//再将Async加进Pool
foreach (var async in asyncs)
{
AsyncPool.AddAsync(async);
}
group.End();
asyncs.Clear();
}
sceneLoadAsync.On(OnSceneComplete);
AsyncPool.AddAsync(sceneLoadAsync);
return sceneLoadAsync;
}
public void UnLoadSceneBundle(string sceneName)
{
if (TryGetSceneBundleInfo(sceneName, out string bundleName, out string[] dependencies))
{
//更新引用计数
Repository.ReleaseBundle(bundleName);
if (dependencies != null)
{
foreach (var dep in dependencies)
{
Repository.ReleaseBundle(dep);
}
}
}
}
AssetBundle LoadBundleSync(string bundleName)
{
AssetBundle bundle;
var bundleAsset = Repository.GetBundle(bundleName);
if (bundleAsset != null)
{
bundle = bundleAsset.Clone() as AssetBundle;
}
else
{
if (AsyncPool.ContainsAssetAsync(bundleName))
{//Bundle正在加载使用异步加载
AssetsLog.Info($"{bundleName} is loading asynchronously, but load synchronously again.");
}
var path = FileUtils.GetAssetBundlePath(bundleName);
var offset = GetBundleOffest(bundleName);
bundle = LoadFromFile(path, offset);
bundleAsset = AssetCreator.Create(bundleName, bundle) as BundleAsset;
if (bundleAsset != null)
{
bundleAsset.Retain();
Repository.AddBundle(bundleAsset);
}
else
{
AssetsLog.Warn("Asset Error: Load Bundle Failed. bundle:{0}", bundleName);
}
}
return bundle;
}
private uint GetBundleOffest(string bundleName)
{
#if UNITY_EDITOR
if (!IsBundleEncrypt)
{
return 0;
}
#endif
return _bundleManifest.GetBundleOffest(bundleName);
}
///
/// AssetBundle.LoadFromFile的包装
///
///
///
///
private AssetBundle LoadFromFile(string path, ulong offset)
{
var bundle = offset > 0 ? AssetBundle.LoadFromFile(path, 0, offset) : AssetBundle.LoadFromFile(path);
return bundle;
}
bool TryGetBundleInfo(string addressableName, out string bundleName, out string[] dependencies)
{
if (_bundleManifest == null || string.IsNullOrEmpty(addressableName))
{
bundleName = string.Empty;
dependencies = null;
return false;
}
bundleName = _bundleManifest.GetBundleNameByAssetName(addressableName);
dependencies = _bundleManifest.GetDependenciesByBundleName(bundleName);
return !string.IsNullOrEmpty(bundleName);
}
bool TryGetSceneBundleInfo(string sceneName, out string bundleName, out string[] dependencies)
{
var assetName = _sceneInfosManifest?.GetSceneAssetName(sceneName) ?? string.Empty;
return TryGetBundleInfo(assetName, out bundleName, out dependencies);
}
///
/// 检查某个资源是否被引用着
///
///
///
bool IsReferencing(string addressableName)
{
if (AsyncPool.ContainsAssetAsync(addressableName))
{//该资源正在加载中
return true;
}
var references = _referenceManifest.GetReferencesByAssetName(addressableName);
if (references == null)
return false;
foreach (var reference in references)
{
if (AsyncPool.ContainsAssetAsync(reference))
{ //加载中
return true;
}
if (Repository.ContainsAsset(reference) && Repository.ContainsUnusedAsset(reference) == false)
{ //已加载,并且不在回收缓存里
return true;
}
}
return false;
}
void OnUnloadAsset(string addressableName)
{
if (!TryGetBundleInfo(addressableName, out string bundleName, out string[] dependencies))
{ //找不到bundle信息
return;
}
Repository.ReleaseBundle(bundleName);
if (dependencies != null)
{
foreach (var dependency in dependencies)
{
Repository.ReleaseBundle(dependency);
}
}
}
///
/// 卸载资源
/// 该方法只会将Asset回收进Repository缓存
///
///
///
public void Unload(string addressableName, object source)
{
if (source is Object obj)
{
var instanceId = obj.GetInstanceID();
if (string.IsNullOrEmpty(Repository.GetAssetNameByHash(instanceId)))
{
AssetsLog.Warn($"{instanceId} is unregistered. Name:{addressableName}");
}
Repository.PushUnusedAsset(obj);
}
}
///
/// 卸载卸载所有没有使用的资源
///
public void UnloadUnusedAssets()
{
Repository.UnloadUnusedAssets(IsReferencing, OnUnloadAsset);
}
protected override void OnDispose()
{
Repository.Dispose();
(_bundleManifest as System.IDisposable)?.Dispose();
(_referenceManifest as System.IDisposable)?.Dispose();
(_sceneInfosManifest as System.IDisposable)?.Dispose();
_bundleManifest = null;
_referenceManifest = null;
_sceneInfosManifest = null;
}
}
}