123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- using XGame.Framework.Asyncs;
- using XGame.Framework.Utils;
- using System.Collections.Generic;
- using UnityEngine;
- namespace XGame.Framework.Asset
- {
- /// <summary>
- /// AssetBundle的加载方式,需要先实现Bundle的Manifest管理
- /// </summary>
- internal partial class AssetBundleLoader : BaseLoader, IAssetLoader
- {
- private IAssetBundleManifest _bundleManifest;
- private IAssetReferencesManifest _referenceManifest;
- private ISceneInfosManifest _sceneInfosManifest;
- /// <summary>
- /// 已加载的Bundle仓库
- /// </summary>
- 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<TResult>(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<IAssetAsync> asyncs = new List<IAssetAsync>();
- 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<TResult>(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<IAssetAsync> asyncs = new List<IAssetAsync>();
- 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);
- }
- /// <summary>
- /// AssetBundle.LoadFromFile的包装
- /// </summary>
- /// <param name="path"></param>
- /// <param name="offset"></param>
- /// <returns></returns>
- 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);
- }
- /// <summary>
- /// 检查某个资源是否被引用着
- /// </summary>
- /// <param name="addressableName"></param>
- /// <returns></returns>
- 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);
- }
- }
- }
- /// <summary>
- /// 卸载资源
- /// 该方法只会将Asset回收进Repository缓存
- /// </summary>
- /// <param name="addressableName"></param>
- /// <param name="source"></param>
- 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);
- }
- }
- /// <summary>
- /// 卸载卸载所有没有使用的资源
- /// </summary>
- 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;
- }
- }
- }
|