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