Init TEngine4.0.0

Init TEngine4.0.0
This commit is contained in:
ALEXTANG
2023-10-08 15:21:33 +08:00
parent 4c8c37ffd8
commit 8c3d6308b9
3773 changed files with 49313 additions and 150734 deletions

View File

@@ -0,0 +1,451 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace YooAsset
{
internal class AssetSystemImpl
{
private readonly Dictionary<string, BundleLoaderBase> _loaderDic = new Dictionary<string, BundleLoaderBase>(5000);
private readonly List<BundleLoaderBase> _loaderList = new List<BundleLoaderBase>(5000);
private readonly Dictionary<string, ProviderBase> _providerDic = new Dictionary<string, ProviderBase>(5000);
private readonly List<ProviderBase> _providerList = new List<ProviderBase>(5000);
private readonly static Dictionary<string, SceneOperationHandle> _sceneHandles = new Dictionary<string, SceneOperationHandle>(100);
private static long _sceneCreateCount = 0;
private bool _isUnloadSafe = true;
private string _packageName;
private bool _simulationOnEditor;
private long _loadingMaxTimeSlice;
public int DownloadFailedTryAgain { private set; get; }
public IDecryptionServices DecryptionServices { private set; get; }
public IBundleServices BundleServices { private set; get; }
// 计时器相关
private Stopwatch _watch;
private long _frameTime;
private bool IsBusy
{
get
{
return _watch.ElapsedMilliseconds - _frameTime >= _loadingMaxTimeSlice;
}
}
/// <summary>
/// 初始化
/// 注意在使用AssetSystem之前需要初始化
/// </summary>
public void Initialize(string packageName, bool simulationOnEditor, long loadingMaxTimeSlice, int downloadFailedTryAgain,
IDecryptionServices decryptionServices, IBundleServices bundleServices)
{
_packageName = packageName;
_simulationOnEditor = simulationOnEditor;
_loadingMaxTimeSlice = loadingMaxTimeSlice;
DownloadFailedTryAgain = downloadFailedTryAgain;
DecryptionServices = decryptionServices;
BundleServices = bundleServices;
_watch = Stopwatch.StartNew();
}
/// <summary>
/// 更新
/// </summary>
public void Update()
{
_frameTime = _watch.ElapsedMilliseconds;
// 更新加载器
foreach (var loader in _loaderList)
{
loader.Update();
}
// 更新资源提供者
// 注意:循环更新的时候,可能会扩展列表
_isUnloadSafe = false;
for (int i = 0; i < _providerList.Count; i++)
{
if (IsBusy)
break;
_providerList[i].Update();
}
_isUnloadSafe = true;
}
/// <summary>
/// 资源回收(卸载引用计数为零的资源)
/// </summary>
public void UnloadUnusedAssets()
{
if (_isUnloadSafe == false)
{
YooLogger.Warning("Can not unload unused assets when processing resource loading !");
return;
}
// 注意:资源包之间可能存在多层深层嵌套,需要多次循环释放。
int loopCount = 10;
for (int i = 0; i < loopCount; i++)
{
UnloadUnusedAssetsInternal();
}
}
private void UnloadUnusedAssetsInternal()
{
for (int i = _loaderList.Count - 1; i >= 0; i--)
{
BundleLoaderBase loader = _loaderList[i];
loader.TryDestroyAllProviders();
}
for (int i = _loaderList.Count - 1; i >= 0; i--)
{
BundleLoaderBase loader = _loaderList[i];
if (loader.CanDestroy())
{
string bundleName = loader.MainBundleInfo.Bundle.BundleName;
loader.Destroy();
_loaderList.RemoveAt(i);
_loaderDic.Remove(bundleName);
}
}
}
/// <summary>
/// 强制回收所有资源
/// </summary>
public void ForceUnloadAllAssets()
{
#if UNITY_WEBGL
throw new Exception($"WebGL not support invoke {nameof(ForceUnloadAllAssets)}");
#else
foreach (var provider in _providerList)
{
provider.WaitForAsyncComplete();
provider.Destroy();
}
foreach (var loader in _loaderList)
{
loader.WaitForAsyncComplete();
loader.Destroy();
}
_providerList.Clear();
_providerDic.Clear();
_loaderList.Clear();
_loaderDic.Clear();
ClearSceneHandle();
// 注意:调用底层接口释放所有资源
Resources.UnloadUnusedAssets();
#endif
}
/// <summary>
/// 加载场景
/// </summary>
public SceneOperationHandle LoadSceneAsync(AssetInfo assetInfo, LoadSceneMode sceneMode, bool suspendLoad, int priority)
{
if (assetInfo.IsInvalid)
{
YooLogger.Error($"Failed to load scene ! {assetInfo.Error}");
CompletedProvider completedProvider = new CompletedProvider(assetInfo);
completedProvider.SetCompleted(assetInfo.Error);
return completedProvider.CreateHandle<SceneOperationHandle>();
}
// 如果加载的是主场景,则卸载所有缓存的场景
if (sceneMode == LoadSceneMode.Single)
{
UnloadAllScene();
}
// 注意同一个场景的ProviderGUID每次加载都会变化
string providerGUID = $"{assetInfo.GUID}-{++_sceneCreateCount}";
ProviderBase provider;
{
if (_simulationOnEditor)
provider = new DatabaseSceneProvider(this, providerGUID, assetInfo, sceneMode, suspendLoad, priority);
else
provider = new BundledSceneProvider(this, providerGUID, assetInfo, sceneMode, suspendLoad, priority);
provider.InitSpawnDebugInfo();
_providerList.Add(provider);
_providerDic.Add(providerGUID, provider);
}
var handle = provider.CreateHandle<SceneOperationHandle>();
handle.PackageName = _packageName;
_sceneHandles.Add(providerGUID, handle);
return handle;
}
/// <summary>
/// 加载资源对象
/// </summary>
public AssetOperationHandle LoadAssetAsync(AssetInfo assetInfo)
{
if (assetInfo.IsInvalid)
{
YooLogger.Error($"Failed to load asset ! {assetInfo.Error}");
CompletedProvider completedProvider = new CompletedProvider(assetInfo);
completedProvider.SetCompleted(assetInfo.Error);
return completedProvider.CreateHandle<AssetOperationHandle>();
}
string providerGUID = assetInfo.GUID;
ProviderBase provider = TryGetProvider(providerGUID);
if (provider == null)
{
if (_simulationOnEditor)
provider = new DatabaseAssetProvider(this, providerGUID, assetInfo);
else
provider = new BundledAssetProvider(this, providerGUID, assetInfo);
provider.InitSpawnDebugInfo();
_providerList.Add(provider);
_providerDic.Add(providerGUID, provider);
}
return provider.CreateHandle<AssetOperationHandle>();
}
/// <summary>
/// 加载子资源对象
/// </summary>
public SubAssetsOperationHandle LoadSubAssetsAsync(AssetInfo assetInfo)
{
if (assetInfo.IsInvalid)
{
YooLogger.Error($"Failed to load sub assets ! {assetInfo.Error}");
CompletedProvider completedProvider = new CompletedProvider(assetInfo);
completedProvider.SetCompleted(assetInfo.Error);
return completedProvider.CreateHandle<SubAssetsOperationHandle>();
}
string providerGUID = assetInfo.GUID;
ProviderBase provider = TryGetProvider(providerGUID);
if (provider == null)
{
if (_simulationOnEditor)
provider = new DatabaseSubAssetsProvider(this, providerGUID, assetInfo);
else
provider = new BundledSubAssetsProvider(this, providerGUID, assetInfo);
provider.InitSpawnDebugInfo();
_providerList.Add(provider);
_providerDic.Add(providerGUID, provider);
}
return provider.CreateHandle<SubAssetsOperationHandle>();
}
/// <summary>
/// 加载所有资源对象
/// </summary>
public AllAssetsOperationHandle LoadAllAssetsAsync(AssetInfo assetInfo)
{
if (assetInfo.IsInvalid)
{
YooLogger.Error($"Failed to load all assets ! {assetInfo.Error}");
CompletedProvider completedProvider = new CompletedProvider(assetInfo);
completedProvider.SetCompleted(assetInfo.Error);
return completedProvider.CreateHandle<AllAssetsOperationHandle>();
}
string providerGUID = assetInfo.GUID;
ProviderBase provider = TryGetProvider(providerGUID);
if (provider == null)
{
if (_simulationOnEditor)
provider = new DatabaseAllAssetsProvider(this, providerGUID, assetInfo);
else
provider = new BundledAllAssetsProvider(this, providerGUID, assetInfo);
provider.InitSpawnDebugInfo();
_providerList.Add(provider);
_providerDic.Add(providerGUID, provider);
}
return provider.CreateHandle<AllAssetsOperationHandle>();
}
/// <summary>
/// 加载原生文件
/// </summary>
public RawFileOperationHandle LoadRawFileAsync(AssetInfo assetInfo)
{
if (assetInfo.IsInvalid)
{
YooLogger.Error($"Failed to load raw file ! {assetInfo.Error}");
CompletedProvider completedProvider = new CompletedProvider(assetInfo);
completedProvider.SetCompleted(assetInfo.Error);
return completedProvider.CreateHandle<RawFileOperationHandle>();
}
string providerGUID = assetInfo.GUID;
ProviderBase provider = TryGetProvider(providerGUID);
if (provider == null)
{
if (_simulationOnEditor)
provider = new DatabaseRawFileProvider(this, providerGUID, assetInfo);
else
provider = new BundledRawFileProvider(this, providerGUID, assetInfo);
provider.InitSpawnDebugInfo();
_providerList.Add(provider);
_providerDic.Add(providerGUID, provider);
}
return provider.CreateHandle<RawFileOperationHandle>();
}
internal void UnloadSubScene(ProviderBase provider)
{
string providerGUID = provider.ProviderGUID;
if (_sceneHandles.ContainsKey(providerGUID) == false)
throw new Exception("Should never get here !");
// 释放子场景句柄
_sceneHandles[providerGUID].ReleaseInternal();
_sceneHandles.Remove(providerGUID);
}
internal void UnloadAllScene()
{
// 释放所有场景句柄
foreach (var valuePair in _sceneHandles)
{
valuePair.Value.ReleaseInternal();
}
_sceneHandles.Clear();
}
internal void ClearSceneHandle()
{
// 释放资源包下的所有场景
if (BundleServices.IsServicesValid())
{
string packageName = _packageName;
List<string> removeList = new List<string>();
foreach (var valuePair in _sceneHandles)
{
if (valuePair.Value.PackageName == packageName)
{
removeList.Add(valuePair.Key);
}
}
foreach (var key in removeList)
{
_sceneHandles.Remove(key);
}
}
}
internal BundleLoaderBase CreateOwnerAssetBundleLoader(AssetInfo assetInfo)
{
BundleInfo bundleInfo = BundleServices.GetBundleInfo(assetInfo);
return CreateAssetBundleLoaderInternal(bundleInfo);
}
internal List<BundleLoaderBase> CreateDependAssetBundleLoaders(AssetInfo assetInfo)
{
BundleInfo[] depends = BundleServices.GetAllDependBundleInfos(assetInfo);
List<BundleLoaderBase> result = new List<BundleLoaderBase>(depends.Length);
foreach (var bundleInfo in depends)
{
BundleLoaderBase dependLoader = CreateAssetBundleLoaderInternal(bundleInfo);
result.Add(dependLoader);
}
return result;
}
internal void RemoveBundleProviders(List<ProviderBase> providers)
{
foreach (var provider in providers)
{
_providerList.Remove(provider);
_providerDic.Remove(provider.ProviderGUID);
}
}
internal bool CheckBundleDestroyed(int bundleID)
{
string bundleName = BundleServices.GetBundleName(bundleID);
BundleLoaderBase loader = TryGetAssetBundleLoader(bundleName);
if (loader == null)
return true;
return loader.IsDestroyed;
}
private BundleLoaderBase CreateAssetBundleLoaderInternal(BundleInfo bundleInfo)
{
// 如果加载器已经存在
string bundleName = bundleInfo.Bundle.BundleName;
BundleLoaderBase loader = TryGetAssetBundleLoader(bundleName);
if (loader != null)
return loader;
// 新增下载需求
if (_simulationOnEditor)
{
loader = new VirtualBundleFileLoader(this, bundleInfo);
}
else
{
#if UNITY_WEBGL
if (bundleInfo.Bundle.IsRawFile)
loader = new RawBundleWebLoader(this, bundleInfo);
else
loader = new AssetBundleWebLoader(this, bundleInfo);
#else
if (bundleInfo.Bundle.IsRawFile)
loader = new RawBundleFileLoader(this, bundleInfo);
else
loader = new AssetBundleFileLoader(this, bundleInfo);
#endif
}
_loaderList.Add(loader);
_loaderDic.Add(bundleName, loader);
return loader;
}
private BundleLoaderBase TryGetAssetBundleLoader(string bundleName)
{
if (_loaderDic.TryGetValue(bundleName, out BundleLoaderBase value))
return value;
else
return null;
}
private ProviderBase TryGetProvider(string providerGUID)
{
if (_providerDic.TryGetValue(providerGUID, out ProviderBase value))
return value;
else
return null;
}
#region
internal List<DebugProviderInfo> GetDebugReportInfos()
{
List<DebugProviderInfo> result = new List<DebugProviderInfo>(_providerList.Count);
foreach (var provider in _providerList)
{
DebugProviderInfo providerInfo = new DebugProviderInfo();
providerInfo.AssetPath = provider.MainAssetInfo.AssetPath;
providerInfo.SpawnScene = provider.SpawnScene;
providerInfo.SpawnTime = provider.SpawnTime;
providerInfo.LoadingTime = provider.LoadingTime;
providerInfo.RefCount = provider.RefCount;
providerInfo.Status = provider.Status.ToString();
providerInfo.DependBundleInfos = new List<DebugBundleInfo>();
provider.GetBundleDebugInfos(providerInfo.DependBundleInfos);
result.Add(providerInfo);
}
return result;
}
internal List<BundleInfo> GetLoadedBundleInfos()
{
List<BundleInfo> result = new List<BundleInfo>(100);
foreach (var loader in _loaderList)
{
result.Add(loader.MainBundleInfo);
}
return result;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3ecc5913758e8234fbba5ef2fd192f86
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 937392854b37d5043808598f2d0e07ec
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
namespace YooAsset
{
public sealed class AllAssetsOperationHandle : OperationHandleBase, IDisposable
{
private System.Action<AllAssetsOperationHandle> _callback;
internal AllAssetsOperationHandle(ProviderBase provider) : base(provider)
{
}
internal override void InvokeCallback()
{
_callback?.Invoke(this);
}
/// <summary>
/// 完成委托
/// </summary>
public event System.Action<AllAssetsOperationHandle> Completed
{
add
{
if (IsValidWithWarning == false)
throw new System.Exception($"{nameof(AllAssetsOperationHandle)} is invalid");
if (Provider.IsDone)
value.Invoke(this);
else
_callback += value;
}
remove
{
if (IsValidWithWarning == false)
throw new System.Exception($"{nameof(AllAssetsOperationHandle)} is invalid");
_callback -= value;
}
}
/// <summary>
/// 等待异步执行完毕
/// </summary>
public void WaitForAsyncComplete()
{
if (IsValidWithWarning == false)
return;
Provider.WaitForAsyncComplete();
}
/// <summary>
/// 释放资源句柄
/// </summary>
public void Release()
{
this.ReleaseInternal();
}
/// <summary>
/// 释放资源句柄
/// </summary>
public void Dispose()
{
this.ReleaseInternal();
}
/// <summary>
/// 子资源对象集合
/// </summary>
public UnityEngine.Object[] AllAssetObjects
{
get
{
if (IsValidWithWarning == false)
return null;
return Provider.AllAssetObjects;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6de8dc2be5f52704abe6db03818edff2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,156 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
public sealed class AssetOperationHandle : OperationHandleBase, IDisposable
{
private System.Action<AssetOperationHandle> _callback;
internal AssetOperationHandle(ProviderBase provider) : base(provider)
{
}
internal override void InvokeCallback()
{
_callback?.Invoke(this);
}
/// <summary>
/// 完成委托
/// </summary>
public event System.Action<AssetOperationHandle> Completed
{
add
{
if (IsValidWithWarning == false)
throw new System.Exception($"{nameof(AssetOperationHandle)} is invalid");
if (Provider.IsDone)
value.Invoke(this);
else
_callback += value;
}
remove
{
if (IsValidWithWarning == false)
throw new System.Exception($"{nameof(AssetOperationHandle)} is invalid");
_callback -= value;
}
}
/// <summary>
/// 等待异步执行完毕
/// </summary>
public void WaitForAsyncComplete()
{
if (IsValidWithWarning == false)
return;
Provider.WaitForAsyncComplete();
}
/// <summary>
/// 释放资源句柄
/// </summary>
public void Release()
{
this.ReleaseInternal();
}
/// <summary>
/// 释放资源句柄
/// </summary>
public void Dispose()
{
this.ReleaseInternal();
}
/// <summary>
/// 资源对象
/// </summary>
public UnityEngine.Object AssetObject
{
get
{
if (IsValidWithWarning == false)
return null;
return Provider.AssetObject;
}
}
/// <summary>
/// 获取资源对象
/// </summary>
/// <typeparam name="TAsset">资源类型</typeparam>
public TAsset GetAssetObject<TAsset>() where TAsset : UnityEngine.Object
{
if (IsValidWithWarning == false)
return null;
return Provider.AssetObject as TAsset;
}
/// <summary>
/// 同步初始化游戏对象
/// </summary>
public GameObject InstantiateSync()
{
return InstantiateSyncInternal(false, Vector3.zero, Quaternion.identity, null, false);
}
public GameObject InstantiateSync(Transform parent)
{
return InstantiateSyncInternal(false, Vector3.zero, Quaternion.identity, parent, false);
}
public GameObject InstantiateSync(Transform parent, bool worldPositionStays)
{
return InstantiateSyncInternal(false, Vector3.zero, Quaternion.identity, parent, worldPositionStays);
}
public GameObject InstantiateSync(Vector3 position, Quaternion rotation)
{
return InstantiateSyncInternal(true, position, rotation, null, false);
}
public GameObject InstantiateSync(Vector3 position, Quaternion rotation, Transform parent)
{
return InstantiateSyncInternal(true, position, rotation, parent, false);
}
/// <summary>
/// 异步初始化游戏对象
/// </summary>
public InstantiateOperation InstantiateAsync()
{
return InstantiateAsyncInternal(false, Vector3.zero, Quaternion.identity, null, false);
}
public InstantiateOperation InstantiateAsync(Transform parent)
{
return InstantiateAsyncInternal(false, Vector3.zero, Quaternion.identity, parent, false);
}
public InstantiateOperation InstantiateAsync(Transform parent, bool worldPositionStays)
{
return InstantiateAsyncInternal(false, Vector3.zero, Quaternion.identity, parent, worldPositionStays);
}
public InstantiateOperation InstantiateAsync(Vector3 position, Quaternion rotation)
{
return InstantiateAsyncInternal(true, position, rotation, null, false);
}
public InstantiateOperation InstantiateAsync(Vector3 position, Quaternion rotation, Transform parent)
{
return InstantiateAsyncInternal(true, position, rotation, parent, false);
}
private GameObject InstantiateSyncInternal(bool setPositionAndRotation, Vector3 position, Quaternion rotation, Transform parent, bool worldPositionStays)
{
if (IsValidWithWarning == false)
return null;
if (Provider.AssetObject == null)
return null;
return InstantiateOperation.InstantiateInternal(Provider.AssetObject, setPositionAndRotation, position, rotation, parent, worldPositionStays);
}
private InstantiateOperation InstantiateAsyncInternal(bool setPositionAndRotation, Vector3 position, Quaternion rotation, Transform parent, bool worldPositionStays)
{
InstantiateOperation operation = new InstantiateOperation(this, setPositionAndRotation, position, rotation, parent, worldPositionStays);
OperationSystem.StartOperation(operation);
return operation;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6b766125ab790154ca132adb5c77333d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,169 @@
using System;
using System.Collections;
namespace YooAsset
{
public abstract class OperationHandleBase : IEnumerator
{
private readonly AssetInfo _assetInfo;
internal ProviderBase Provider { private set; get; }
internal OperationHandleBase(ProviderBase provider)
{
Provider = provider;
_assetInfo = provider.MainAssetInfo;
}
internal abstract void InvokeCallback();
/// <summary>
/// 获取资源信息
/// </summary>
public AssetInfo GetAssetInfo()
{
return _assetInfo;
}
/// <summary>
/// 获取下载报告
/// </summary>
public DownloadReport GetDownloadReport()
{
if (IsValidWithWarning == false)
{
return DownloadReport.CreateDefaultReport();
}
return Provider.GetDownloadReport();
}
/// <summary>
/// 当前状态
/// </summary>
public EOperationStatus Status
{
get
{
if (IsValidWithWarning == false)
return EOperationStatus.None;
var status = Provider.Status;
if (status == ProviderBase.EStatus.None)
return EOperationStatus.None;
else if (status == ProviderBase.EStatus.Succeed)
return EOperationStatus.Succeed;
else if (status == ProviderBase.EStatus.Failed)
return EOperationStatus.Failed;
else
return EOperationStatus.Processing;
}
}
/// <summary>
/// 最近的错误信息
/// </summary>
public string LastError
{
get
{
if (IsValidWithWarning == false)
return string.Empty;
return Provider.LastError;
}
}
/// <summary>
/// 加载进度
/// </summary>
public float Progress
{
get
{
if (IsValidWithWarning == false)
return 0;
return Provider.Progress;
}
}
/// <summary>
/// 是否加载完毕
/// </summary>
public bool IsDone
{
get
{
if (IsValidWithWarning == false)
return false;
return Provider.IsDone;
}
}
/// <summary>
/// 句柄是否有效
/// </summary>
public bool IsValid
{
get
{
if (Provider != null && Provider.IsDestroyed == false)
return true;
else
return false;
}
}
/// <summary>
/// 句柄是否有效
/// </summary>
internal bool IsValidWithWarning
{
get
{
if (Provider != null && Provider.IsDestroyed == false)
{
return true;
}
else
{
if (Provider == null)
YooLogger.Warning($"Operation handle is released : {_assetInfo.AssetPath}");
else if (Provider.IsDestroyed)
YooLogger.Warning($"Provider is destroyed : {_assetInfo.AssetPath}");
return false;
}
}
}
/// <summary>
/// 释放句柄
/// </summary>
internal void ReleaseInternal()
{
if (IsValidWithWarning == false)
return;
Provider.ReleaseHandle(this);
Provider = null;
}
#region
/// <summary>
/// 异步操作任务
/// </summary>
public System.Threading.Tasks.Task Task
{
get { return Provider.Task; }
}
// 协程相关
bool IEnumerator.MoveNext()
{
return !IsDone;
}
void IEnumerator.Reset()
{
}
object IEnumerator.Current
{
get { return Provider; }
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a9f5acda1a4584648af7b47e19a0d24f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,100 @@
using System;
using System.IO;
using System.Text;
namespace YooAsset
{
public class RawFileOperationHandle : OperationHandleBase, IDisposable
{
private System.Action<RawFileOperationHandle> _callback;
internal RawFileOperationHandle(ProviderBase provider) : base(provider)
{
}
internal override void InvokeCallback()
{
_callback?.Invoke(this);
}
/// <summary>
/// 完成委托
/// </summary>
public event System.Action<RawFileOperationHandle> Completed
{
add
{
if (IsValidWithWarning == false)
throw new System.Exception($"{nameof(RawFileOperationHandle)} is invalid");
if (Provider.IsDone)
value.Invoke(this);
else
_callback += value;
}
remove
{
if (IsValidWithWarning == false)
throw new System.Exception($"{nameof(RawFileOperationHandle)} is invalid");
_callback -= value;
}
}
/// <summary>
/// 等待异步执行完毕
/// </summary>
public void WaitForAsyncComplete()
{
if (IsValidWithWarning == false)
return;
Provider.WaitForAsyncComplete();
}
/// <summary>
/// 释放资源句柄
/// </summary>
public void Release()
{
this.ReleaseInternal();
}
/// <summary>
/// 释放资源句柄
/// </summary>
public void Dispose()
{
this.ReleaseInternal();
}
/// <summary>
/// 获取原生文件的二进制数据
/// </summary>
public byte[] GetRawFileData()
{
if (IsValidWithWarning == false)
return null;
string filePath = Provider.RawFilePath;
return FileUtility.ReadAllBytes(filePath);
}
/// <summary>
/// 获取原生文件的文本数据
/// </summary>
public string GetRawFileText()
{
if (IsValidWithWarning == false)
return null;
string filePath = Provider.RawFilePath;
return FileUtility.ReadAllText(filePath);
}
/// <summary>
/// 获取原生文件的路径
/// </summary>
public string GetRawFilePath()
{
if (IsValidWithWarning == false)
return string.Empty;
return Provider.RawFilePath;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e8420ba734d425a4ba9f19173d74503c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,162 @@
using UnityEngine.SceneManagement;
namespace YooAsset
{
public class SceneOperationHandle : OperationHandleBase
{
private System.Action<SceneOperationHandle> _callback;
internal string PackageName { set; get; }
internal SceneOperationHandle(ProviderBase provider) : base(provider)
{
}
internal override void InvokeCallback()
{
_callback?.Invoke(this);
}
/// <summary>
/// 完成委托
/// </summary>
public event System.Action<SceneOperationHandle> Completed
{
add
{
if (IsValidWithWarning == false)
throw new System.Exception($"{nameof(SceneOperationHandle)} is invalid");
if (Provider.IsDone)
value.Invoke(this);
else
_callback += value;
}
remove
{
if (IsValidWithWarning == false)
throw new System.Exception($"{nameof(SceneOperationHandle)} is invalid");
_callback -= value;
}
}
/// <summary>
/// 场景对象
/// </summary>
public Scene SceneObject
{
get
{
if (IsValidWithWarning == false)
return new Scene();
return Provider.SceneObject;
}
}
/// <summary>
/// 激活场景(当同时存在多个场景时用于切换激活场景)
/// </summary>
public bool ActivateScene()
{
if (IsValidWithWarning == false)
return false;
if (SceneObject.IsValid() && SceneObject.isLoaded)
{
return SceneManager.SetActiveScene(SceneObject);
}
else
{
YooLogger.Warning($"Scene is invalid or not loaded : {SceneObject.name}");
return false;
}
}
/// <summary>
/// 解除场景加载挂起操作
/// </summary>
public bool UnSuspend()
{
if (IsValidWithWarning == false)
return false;
if (SceneObject.IsValid())
{
if (Provider is DatabaseSceneProvider)
{
var temp = Provider as DatabaseSceneProvider;
return temp.UnSuspendLoad();
}
else if (Provider is BundledSceneProvider)
{
var temp = Provider as BundledSceneProvider;
return temp.UnSuspendLoad();
}
else
{
throw new System.NotImplementedException();
}
}
else
{
YooLogger.Warning($"Scene is invalid : {SceneObject.name}");
return false;
}
}
/// <summary>
/// 是否为主场景
/// </summary>
public bool IsMainScene()
{
if (IsValidWithWarning == false)
return false;
if (Provider is DatabaseSceneProvider)
{
var temp = Provider as DatabaseSceneProvider;
return temp.SceneMode == LoadSceneMode.Single;
}
else if (Provider is BundledSceneProvider)
{
var temp = Provider as BundledSceneProvider;
return temp.SceneMode == LoadSceneMode.Single;
}
else
{
throw new System.NotImplementedException();
}
}
/// <summary>
/// 异步卸载子场景
/// </summary>
public UnloadSceneOperation UnloadAsync()
{
// 如果句柄无效
if (IsValidWithWarning == false)
{
string error = $"{nameof(SceneOperationHandle)} is invalid.";
var operation = new UnloadSceneOperation(error);
OperationSystem.StartOperation(operation);
return operation;
}
// 如果是主场景
if (IsMainScene())
{
string error = $"Cannot unload main scene. Use {nameof(YooAssets.LoadSceneAsync)} method to change the main scene !";
YooLogger.Error(error);
var operation = new UnloadSceneOperation(error);
OperationSystem.StartOperation(operation);
return operation;
}
// 卸载子场景
Scene sceneObject = SceneObject;
Provider.Impl.UnloadSubScene(Provider);
{
var operation = new UnloadSceneOperation(sceneObject);
OperationSystem.StartOperation(operation);
return operation;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c5d788ba2dd3c5243ae2e0be8e780825
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,119 @@
using System;
using System.Collections.Generic;
namespace YooAsset
{
public sealed class SubAssetsOperationHandle : OperationHandleBase, IDisposable
{
private System.Action<SubAssetsOperationHandle> _callback;
internal SubAssetsOperationHandle(ProviderBase provider) : base(provider)
{
}
internal override void InvokeCallback()
{
_callback?.Invoke(this);
}
/// <summary>
/// 完成委托
/// </summary>
public event System.Action<SubAssetsOperationHandle> Completed
{
add
{
if (IsValidWithWarning == false)
throw new System.Exception($"{nameof(SubAssetsOperationHandle)} is invalid");
if (Provider.IsDone)
value.Invoke(this);
else
_callback += value;
}
remove
{
if (IsValidWithWarning == false)
throw new System.Exception($"{nameof(SubAssetsOperationHandle)} is invalid");
_callback -= value;
}
}
/// <summary>
/// 等待异步执行完毕
/// </summary>
public void WaitForAsyncComplete()
{
if (IsValidWithWarning == false)
return;
Provider.WaitForAsyncComplete();
}
/// <summary>
/// 释放资源句柄
/// </summary>
public void Release()
{
this.ReleaseInternal();
}
/// <summary>
/// 释放资源句柄
/// </summary>
public void Dispose()
{
this.ReleaseInternal();
}
/// <summary>
/// 子资源对象集合
/// </summary>
public UnityEngine.Object[] AllAssetObjects
{
get
{
if (IsValidWithWarning == false)
return null;
return Provider.AllAssetObjects;
}
}
/// <summary>
/// 获取子资源对象
/// </summary>
/// <typeparam name="TObject">子资源对象类型</typeparam>
/// <param name="assetName">子资源对象名称</param>
public TObject GetSubAssetObject<TObject>(string assetName) where TObject : UnityEngine.Object
{
if (IsValidWithWarning == false)
return null;
foreach (var assetObject in Provider.AllAssetObjects)
{
if (assetObject.name == assetName)
return assetObject as TObject;
}
YooLogger.Warning($"Not found sub asset object : {assetName}");
return null;
}
/// <summary>
/// 获取所有的子资源对象集合
/// </summary>
/// <typeparam name="TObject">子资源对象类型</typeparam>
public TObject[] GetSubAssetObjects<TObject>() where TObject : UnityEngine.Object
{
if (IsValidWithWarning == false)
return null;
List<TObject> ret = new List<TObject>(Provider.AllAssetObjects.Length);
foreach (var assetObject in Provider.AllAssetObjects)
{
var retObject = assetObject as TObject;
if (retObject != null)
ret.Add(retObject);
}
return ret.ToArray();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 76b148be04a698e45a54dd85e64969dd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 58462a7dcef164e43878a037395d4417
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,356 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal sealed class AssetBundleFileLoader : BundleLoaderBase
{
private enum ESteps
{
None = 0,
Download,
CheckDownload,
Unpack,
CheckUnpack,
LoadBundleFile,
LoadDeliveryFile,
CheckLoadFile,
Done,
}
private ESteps _steps = ESteps.None;
private bool _isWaitForAsyncComplete = false;
private bool _isShowWaitForAsyncError = false;
private DownloaderBase _unpacker;
private DownloaderBase _downloader;
private AssetBundleCreateRequest _createRequest;
private Stream _stream;
public AssetBundleFileLoader(AssetSystemImpl impl, BundleInfo bundleInfo) : base(impl, bundleInfo)
{
}
/// <summary>
/// 轮询更新
/// </summary>
public override void Update()
{
if (_steps == ESteps.Done)
return;
if (_steps == ESteps.None)
{
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
{
_steps = ESteps.Download;
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
#if UNITY_ANDROID
EBundleLoadMethod loadMethod = (EBundleLoadMethod)MainBundleInfo.Bundle.LoadMethod;
if (loadMethod == EBundleLoadMethod.LoadFromMemory || loadMethod == EBundleLoadMethod.LoadFromStream)
{
_steps = ESteps.Unpack;
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
}
else
{
_steps = ESteps.LoadBundleFile;
FileLoadPath = MainBundleInfo.Bundle.StreamingFilePath;
}
#else
_steps = ESteps.LoadBundleFile;
FileLoadPath = MainBundleInfo.Bundle.StreamingFilePath;
#endif
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
_steps = ESteps.LoadBundleFile;
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromDelivery)
{
_steps = ESteps.LoadDeliveryFile;
FileLoadPath = MainBundleInfo.DeliveryFilePath;
}
else
{
throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
}
}
// 1. 从服务器下载
if (_steps == ESteps.Download)
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
_downloader = DownloadSystem.CreateDownload(MainBundleInfo, failedTryAgain);
_downloader.SendRequest();
_steps = ESteps.CheckDownload;
}
// 2. 检测服务器下载结果
if (_steps == ESteps.CheckDownload)
{
DownloadProgress = _downloader.DownloadProgress;
DownloadedBytes = _downloader.DownloadedBytes;
if (_downloader.IsDone() == false)
return;
if (_downloader.HasError())
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = _downloader.GetLastError();
}
else
{
_steps = ESteps.LoadBundleFile;
return; //下载完毕等待一帧再去加载!
}
}
// 3. 内置文件解压
if (_steps == ESteps.Unpack)
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
var bundleInfo = ManifestTools.ConvertToUnpackInfo(MainBundleInfo.Bundle);
_unpacker = DownloadSystem.CreateDownload(bundleInfo, failedTryAgain);
_unpacker.SendRequest();
_steps = ESteps.CheckUnpack;
}
// 4.检测内置文件解压结果
if (_steps == ESteps.CheckUnpack)
{
DownloadProgress = _unpacker.DownloadProgress;
DownloadedBytes = _unpacker.DownloadedBytes;
if (_unpacker.IsDone() == false)
return;
if (_unpacker.HasError())
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = _unpacker.GetLastError();
}
else
{
_steps = ESteps.LoadBundleFile;
}
}
// 5. 加载AssetBundle
if (_steps == ESteps.LoadBundleFile)
{
#if UNITY_EDITOR
// 注意Unity2017.4编辑器模式下如果AssetBundle文件不存在会导致编辑器崩溃这里做了预判。
if (System.IO.File.Exists(FileLoadPath) == false)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Not found assetBundle file : {FileLoadPath}";
YooLogger.Error(LastError);
return;
}
#endif
// 设置下载进度
DownloadProgress = 1f;
DownloadedBytes = (ulong)MainBundleInfo.Bundle.FileSize;
// Load assetBundle file
var loadMethod = (EBundleLoadMethod)MainBundleInfo.Bundle.LoadMethod;
if (loadMethod == EBundleLoadMethod.Normal)
{
if (_isWaitForAsyncComplete)
CacheBundle = AssetBundle.LoadFromFile(FileLoadPath);
else
_createRequest = AssetBundle.LoadFromFileAsync(FileLoadPath);
}
else
{
if (Impl.DecryptionServices == null)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"{nameof(IDecryptionServices)} is null : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
return;
}
DecryptFileInfo fileInfo = new DecryptFileInfo();
fileInfo.BundleName = MainBundleInfo.Bundle.BundleName;
fileInfo.FilePath = FileLoadPath;
if (loadMethod == EBundleLoadMethod.LoadFromFileOffset)
{
ulong offset = Impl.DecryptionServices.LoadFromFileOffset(fileInfo);
if (_isWaitForAsyncComplete)
CacheBundle = AssetBundle.LoadFromFile(FileLoadPath, 0, offset);
else
_createRequest = AssetBundle.LoadFromFileAsync(FileLoadPath, 0, offset);
}
else if (loadMethod == EBundleLoadMethod.LoadFromMemory)
{
byte[] fileData = Impl.DecryptionServices.LoadFromMemory(fileInfo);
if (_isWaitForAsyncComplete)
CacheBundle = AssetBundle.LoadFromMemory(fileData);
else
_createRequest = AssetBundle.LoadFromMemoryAsync(fileData);
}
else if (loadMethod == EBundleLoadMethod.LoadFromStream)
{
_stream = Impl.DecryptionServices.LoadFromStream(fileInfo);
uint managedReadBufferSize = Impl.DecryptionServices.GetManagedReadBufferSize();
if (_isWaitForAsyncComplete)
CacheBundle = AssetBundle.LoadFromStream(_stream, 0, managedReadBufferSize);
else
_createRequest = AssetBundle.LoadFromStreamAsync(_stream, 0, managedReadBufferSize);
}
else
{
throw new System.NotImplementedException();
}
}
_steps = ESteps.CheckLoadFile;
}
// 6. 加载AssetBundle
if (_steps == ESteps.LoadDeliveryFile)
{
// 设置下载进度
DownloadProgress = 1f;
DownloadedBytes = (ulong)MainBundleInfo.Bundle.FileSize;
// Load assetBundle file
var loadMethod = (EBundleLoadMethod)MainBundleInfo.Bundle.LoadMethod;
if (loadMethod == EBundleLoadMethod.Normal)
{
ulong offset = MainBundleInfo.DeliveryFileOffset;
if (_isWaitForAsyncComplete)
CacheBundle = AssetBundle.LoadFromFile(FileLoadPath, 0, offset);
else
_createRequest = AssetBundle.LoadFromFileAsync(FileLoadPath, 0, offset);
}
else
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Delivery file not support encryption : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
return;
}
_steps = ESteps.CheckLoadFile;
}
// 7. 检测AssetBundle加载结果
if (_steps == ESteps.CheckLoadFile)
{
if (_createRequest != null)
{
if (_isWaitForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity bundle.");
CacheBundle = _createRequest.assetBundle;
}
else
{
if (_createRequest.isDone == false)
return;
CacheBundle = _createRequest.assetBundle;
}
}
// Check error
if (CacheBundle == null)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Failed to load assetBundle : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
// 注意当缓存文件的校验等级为Low的时候并不能保证缓存文件的完整性。
// 在AssetBundle文件加载失败的情况下我们需要重新验证文件的完整性
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
var result = CacheSystem.VerifyingRecordFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
if (result != EVerifyResult.Succeed)
{
YooLogger.Error($"Found possibly corrupt file ! {MainBundleInfo.Bundle.CacheGUID} Verify result : {result}");
CacheSystem.DiscardFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
}
}
}
else
{
_steps = ESteps.Done;
Status = EStatus.Succeed;
}
}
}
/// <summary>
/// 销毁
/// </summary>
public override void Destroy()
{
base.Destroy();
if (_stream != null)
{
_stream.Close();
_stream.Dispose();
_stream = null;
}
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public override void WaitForAsyncComplete()
{
_isWaitForAsyncComplete = true;
int frame = 1000;
while (true)
{
// 文件解压
if (_unpacker != null)
{
if (_unpacker.IsDone() == false)
{
_unpacker.WaitForAsyncComplete = true;
_unpacker.Update();
continue;
}
}
// 保险机制
// 注意如果需要从WEB端下载资源可能会触发保险机制
frame--;
if (frame == 0)
{
if (_isShowWaitForAsyncError == false)
{
_isShowWaitForAsyncError = true;
YooLogger.Error($"{nameof(WaitForAsyncComplete)} failed ! Try load bundle : {MainBundleInfo.Bundle.BundleName} from remote with sync load method !");
}
break;
}
// 驱动流程
Update();
// 完成后退出
if (IsDone())
break;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 64d0a51f59c2a964eaf97b87db47428f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,114 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset
{
/// <summary>
/// WebGL平台加载器
/// </summary>
internal sealed class AssetBundleWebLoader : BundleLoaderBase
{
private enum ESteps
{
None = 0,
LoadWebSiteFile,
LoadRemoteFile,
CheckLoadFile,
Done,
}
private ESteps _steps = ESteps.None;
private WebDownloader _downloader;
public AssetBundleWebLoader(AssetSystemImpl impl, BundleInfo bundleInfo) : base(impl, bundleInfo)
{
}
/// <summary>
/// 轮询更新
/// </summary>
public override void Update()
{
if (_steps == ESteps.Done)
return;
if (_steps == ESteps.None)
{
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
{
_steps = ESteps.LoadRemoteFile;
FileLoadPath = string.Empty;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
_steps = ESteps.LoadWebSiteFile;
FileLoadPath = string.Empty;
}
else
{
throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
}
}
// 1. 跨域获取资源包
if (_steps == ESteps.LoadRemoteFile)
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
_downloader = DownloadSystem.CreateDownload(MainBundleInfo, failedTryAgain) as WebDownloader;
_downloader.SendRequest(true);
_steps = ESteps.CheckLoadFile;
}
// 2. 从站点获取资源包
if (_steps == ESteps.LoadWebSiteFile)
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
var bundleInfo = ManifestTools.ConvertToUnpackInfo(MainBundleInfo.Bundle);
_downloader = DownloadSystem.CreateDownload(bundleInfo, failedTryAgain) as WebDownloader;
_downloader.SendRequest(true);
_steps = ESteps.CheckLoadFile;
}
// 3. 检测加载结果
if (_steps == ESteps.CheckLoadFile)
{
DownloadProgress = _downloader.DownloadProgress;
DownloadedBytes = _downloader.DownloadedBytes;
if (_downloader.IsDone() == false)
return;
CacheBundle = _downloader.GetAssetBundle();
if (CacheBundle == null)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"AssetBundle file is invalid : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
}
else
{
_steps = ESteps.Done;
Status = EStatus.Succeed;
}
}
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public override void WaitForAsyncComplete()
{
if (IsDone() == false)
{
Status = EStatus.Failed;
LastError = $"{nameof(WaitForAsyncComplete)} failed ! WebGL platform not support sync load method !";
YooLogger.Error(LastError);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bd1ad395c62c5804589ec9b267ea0484
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,178 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal abstract class BundleLoaderBase
{
public enum EStatus
{
None = 0,
Succeed,
Failed
}
/// <summary>
/// 所属资源系统
/// </summary>
public AssetSystemImpl Impl { private set; get; }
/// <summary>
/// 资源包文件信息
/// </summary>
public BundleInfo MainBundleInfo { private set; get; }
/// <summary>
/// 引用计数
/// </summary>
public int RefCount { private set; get; }
/// <summary>
/// 加载状态
/// </summary>
public EStatus Status { protected set; get; }
/// <summary>
/// 最近的错误信息
/// </summary>
public string LastError { protected set; get; }
/// <summary>
/// 是否已经销毁
/// </summary>
public bool IsDestroyed { private set; get; } = false;
private readonly List<ProviderBase> _providers = new List<ProviderBase>(100);
internal AssetBundle CacheBundle { set; get; }
internal string FileLoadPath { set; get; }
internal float DownloadProgress { set; get; }
internal ulong DownloadedBytes { set; get; }
public BundleLoaderBase(AssetSystemImpl impl, BundleInfo bundleInfo)
{
Impl = impl;
MainBundleInfo = bundleInfo;
RefCount = 0;
Status = EStatus.None;
}
/// <summary>
/// 添加附属的资源提供者
/// </summary>
public void AddProvider(ProviderBase provider)
{
if (_providers.Contains(provider) == false)
_providers.Add(provider);
}
/// <summary>
/// 引用(引用计数递加)
/// </summary>
public void Reference()
{
RefCount++;
}
/// <summary>
/// 释放(引用计数递减)
/// </summary>
public void Release()
{
RefCount--;
}
/// <summary>
/// 是否完毕(无论成功或失败)
/// </summary>
public bool IsDone()
{
return Status == EStatus.Succeed || Status == EStatus.Failed;
}
/// <summary>
/// 是否可以销毁
/// </summary>
public bool CanDestroy()
{
if (IsDone() == false)
return false;
if (RefCount > 0)
return false;
// 检查引用链上的资源包是否已经全部销毁
// 注意:互相引用的资源包无法卸载!
foreach (var bundleID in MainBundleInfo.Bundle.ReferenceIDs)
{
if (Impl.CheckBundleDestroyed(bundleID) == false)
return false;
}
return true;
}
/// <summary>
/// 在满足条件的前提下,销毁所有资源提供者
/// </summary>
public void TryDestroyAllProviders()
{
if (IsDone() == false)
return;
// 条件1必须等待所有Provider可以销毁
foreach (var provider in _providers)
{
if (provider.CanDestroy() == false)
return;
}
// 条件2除了自己没有其它引用
if (RefCount > _providers.Count)
return;
// 销毁所有Providers
{
foreach (var provider in _providers)
{
provider.Destroy();
}
Impl.RemoveBundleProviders(_providers);
_providers.Clear();
}
}
/// <summary>
/// 轮询更新
/// </summary>
public abstract void Update();
/// <summary>
/// 销毁
/// </summary>
public virtual void Destroy()
{
IsDestroyed = true;
// Check fatal
if (RefCount > 0)
throw new Exception($"Bundle file loader ref is not zero : {MainBundleInfo.Bundle.BundleName}");
if (IsDone() == false)
throw new Exception($"Bundle file loader is not done : {MainBundleInfo.Bundle.BundleName}");
if (CacheBundle != null)
{
CacheBundle.Unload(true);
CacheBundle = null;
}
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public abstract void WaitForAsyncComplete();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b8aaabc43e74af14d8eb3c7c85e19cda
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,112 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
{
internal class DependAssetBundles
{
/// <summary>
/// 依赖的资源包加载器列表
/// </summary>
internal readonly List<BundleLoaderBase> DependList;
public DependAssetBundles(List<BundleLoaderBase> dpendList)
{
DependList = dpendList;
}
/// <summary>
/// 是否已经完成(无论成功或失败)
/// </summary>
public bool IsDone()
{
foreach (var loader in DependList)
{
if (loader.IsDone() == false)
return false;
}
return true;
}
/// <summary>
/// 依赖资源包是否全部加载成功
/// </summary>
public bool IsSucceed()
{
foreach (var loader in DependList)
{
if (loader.Status != BundleLoaderBase.EStatus.Succeed)
{
return false;
}
}
return true;
}
/// <summary>
/// 获取某个加载失败的资源包错误信息
/// </summary>
public string GetLastError()
{
foreach (var loader in DependList)
{
if (loader.Status != BundleLoaderBase.EStatus.Succeed)
{
return loader.LastError;
}
}
return string.Empty;
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public void WaitForAsyncComplete()
{
foreach (var loader in DependList)
{
if (loader.IsDone() == false)
loader.WaitForAsyncComplete();
}
}
/// <summary>
/// 增加引用计数
/// </summary>
public void Reference()
{
foreach (var loader in DependList)
{
loader.Reference();
}
}
/// <summary>
/// 减少引用计数
/// </summary>
public void Release()
{
foreach (var loader in DependList)
{
loader.Release();
}
}
/// <summary>
/// 获取资源包的调试信息列表
/// </summary>
internal void GetBundleDebugInfos(List<DebugBundleInfo> output)
{
foreach (var loader in DependList)
{
var bundleInfo = new DebugBundleInfo();
bundleInfo.BundleName = loader.MainBundleInfo.Bundle.BundleName;
bundleInfo.RefCount = loader.RefCount;
bundleInfo.Status = loader.Status.ToString();
output.Add(bundleInfo);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b7eeccc96e4c31c45bd105b0dbc3fd6e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@

namespace YooAsset
{
/// <summary>
/// Bundle文件的加载方法
/// </summary>
public enum EBundleLoadMethod
{
/// <summary>
/// 正常加载(不需要解密)
/// </summary>
Normal = 0,
/// <summary>
/// 通过文件偏移来解密加载
/// </summary>
LoadFromFileOffset = 1,
/// <summary>
/// 通过文件内存来解密加载
/// </summary>
LoadFromMemory = 2,
/// <summary>
/// 通过文件流来解密加载
/// </summary>
LoadFromStream = 3,
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5e32c14ed62806b4189d20ad48ce7631
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,190 @@
using System.IO;
namespace YooAsset
{
internal class RawBundleFileLoader : BundleLoaderBase
{
private enum ESteps
{
None,
Download,
CheckDownload,
Unpack,
CheckUnpack,
CheckFile,
Done,
}
private ESteps _steps = ESteps.None;
private DownloaderBase _unpacker;
private DownloaderBase _downloader;
public RawBundleFileLoader(AssetSystemImpl impl, BundleInfo bundleInfo) : base(impl, bundleInfo)
{
}
/// <summary>
/// 轮询更新
/// </summary>
public override void Update()
{
if (_steps == ESteps.Done)
return;
if (_steps == ESteps.None)
{
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
{
_steps = ESteps.Download;
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
#if UNITY_ANDROID
_steps = ESteps.Unpack;
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
#else
_steps = ESteps.CheckFile;
FileLoadPath = MainBundleInfo.Bundle.StreamingFilePath;
#endif
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
_steps = ESteps.CheckFile;
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromDelivery)
{
_steps = ESteps.CheckFile;
FileLoadPath = MainBundleInfo.DeliveryFilePath;
}
else
{
throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
}
}
// 1. 下载远端文件
if (_steps == ESteps.Download)
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
_downloader = DownloadSystem.CreateDownload(MainBundleInfo, failedTryAgain);
_downloader.SendRequest();
_steps = ESteps.CheckDownload;
}
// 2. 检测下载结果
if (_steps == ESteps.CheckDownload)
{
DownloadProgress = _downloader.DownloadProgress;
DownloadedBytes = _downloader.DownloadedBytes;
if (_downloader.IsDone() == false)
return;
if (_downloader.HasError())
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = _downloader.GetLastError();
}
else
{
_steps = ESteps.CheckFile;
}
}
// 3. 解压内置文件
if (_steps == ESteps.Unpack)
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
var bundleInfo = ManifestTools.ConvertToUnpackInfo(MainBundleInfo.Bundle);
_unpacker = DownloadSystem.CreateDownload(bundleInfo, failedTryAgain);
_unpacker.SendRequest();
_steps = ESteps.CheckUnpack;
}
// 4. 检测解压结果
if (_steps == ESteps.CheckUnpack)
{
DownloadProgress = _unpacker.DownloadProgress;
DownloadedBytes = _unpacker.DownloadedBytes;
if (_unpacker.IsDone() == false)
return;
if (_unpacker.HasError())
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = _unpacker.GetLastError();
}
else
{
_steps = ESteps.CheckFile;
}
}
// 5. 检测结果
if (_steps == ESteps.CheckFile)
{
// 设置下载进度
DownloadProgress = 1f;
DownloadedBytes = (ulong)MainBundleInfo.Bundle.FileSize;
if (File.Exists(FileLoadPath))
{
_steps = ESteps.Done;
Status = EStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Raw file not found : {FileLoadPath}";
}
}
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public override void WaitForAsyncComplete()
{
int frame = 1000;
while (true)
{
// 文件解压
if (_unpacker != null)
{
if (_unpacker.IsDone() == false)
{
_unpacker.WaitForAsyncComplete = true;
_unpacker.Update();
continue;
}
}
// 保险机制
// 注意:如果需要从远端下载资源,可能会触发保险机制!
frame--;
if (frame == 0)
{
if (IsDone() == false)
{
Status = EStatus.Failed;
LastError = $"WaitForAsyncComplete failed ! Try load bundle : {MainBundleInfo.Bundle.BundleName} from remote with sync load method !";
YooLogger.Error(LastError);
}
break;
}
// 驱动流程
Update();
// 完成后退出
if (IsDone())
break;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fa39f24727abe514093f18787c0c7e27
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,148 @@
using System.IO;
namespace YooAsset
{
/// <summary>
/// WebGL平台加载器
/// </summary>
internal class RawBundleWebLoader : BundleLoaderBase
{
private enum ESteps
{
None,
Download,
CheckDownload,
Website,
CheckWebsite,
CheckFile,
Done,
}
private ESteps _steps = ESteps.None;
private DownloaderBase _website;
private DownloaderBase _downloader;
public RawBundleWebLoader(AssetSystemImpl impl, BundleInfo bundleInfo) : base(impl, bundleInfo)
{
}
/// <summary>
/// 轮询更新
/// </summary>
public override void Update()
{
if (_steps == ESteps.Done)
return;
if (_steps == ESteps.None)
{
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
{
_steps = ESteps.Download;
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
_steps = ESteps.Website;
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
}
else
{
throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
}
}
// 1. 下载远端文件
if (_steps == ESteps.Download)
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
_downloader = DownloadSystem.CreateDownload(MainBundleInfo, failedTryAgain);
_downloader.SendRequest();
_steps = ESteps.CheckDownload;
}
// 2. 检测下载结果
if (_steps == ESteps.CheckDownload)
{
DownloadProgress = _downloader.DownloadProgress;
DownloadedBytes = _downloader.DownloadedBytes;
if (_downloader.IsDone() == false)
return;
if (_downloader.HasError())
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = _downloader.GetLastError();
}
else
{
_steps = ESteps.CheckFile;
}
}
// 3. 从站点下载
if (_steps == ESteps.Website)
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
var bundleInfo = ManifestTools.ConvertToUnpackInfo(MainBundleInfo.Bundle);
_website = DownloadSystem.CreateDownload(bundleInfo, failedTryAgain);
_website.SendRequest();
_steps = ESteps.CheckWebsite;
}
// 4. 检测站点下载
if (_steps == ESteps.CheckWebsite)
{
DownloadProgress = _website.DownloadProgress;
DownloadedBytes = _website.DownloadedBytes;
if (_website.IsDone() == false)
return;
if (_website.HasError())
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = _website.GetLastError();
}
else
{
_steps = ESteps.CheckFile;
}
}
// 5. 检测结果
if (_steps == ESteps.CheckFile)
{
// 设置下载进度
DownloadProgress = 1f;
DownloadedBytes = (ulong)MainBundleInfo.Bundle.FileSize;
_steps = ESteps.Done;
if (File.Exists(FileLoadPath))
{
Status = EStatus.Succeed;
}
else
{
Status = EStatus.Failed;
LastError = $"Raw file not found : {FileLoadPath}";
}
}
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public override void WaitForAsyncComplete()
{
if (IsDone() == false)
{
Status = EStatus.Failed;
LastError = $"{nameof(WaitForAsyncComplete)} failed ! WebGL platform not support sync load method !";
YooLogger.Error(LastError);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1d16b689f73611e44bd01a4cc429a6ac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,82 @@

namespace YooAsset
{
internal class VirtualBundleFileLoader : BundleLoaderBase
{
private enum ESteps
{
None,
CheckFile,
Done,
}
private ESteps _steps = ESteps.None;
public VirtualBundleFileLoader(AssetSystemImpl impl, BundleInfo bundleInfo) : base(impl, bundleInfo)
{
}
/// <summary>
/// 轮询更新
/// </summary>
public override void Update()
{
if (_steps == ESteps.Done)
return;
if (_steps == ESteps.None)
{
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromEditor)
{
_steps = ESteps.CheckFile;
}
else
{
throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
}
}
// 1. 检测结果
if (_steps == ESteps.CheckFile)
{
// 设置下载进度
DownloadProgress = 1f;
DownloadedBytes = (ulong)MainBundleInfo.Bundle.FileSize;
_steps = ESteps.Done;
Status = EStatus.Succeed;
}
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public override void WaitForAsyncComplete()
{
int frame = 1000;
while (true)
{
// 保险机制
// 注意:如果需要从远端下载资源,可能会触发保险机制!
frame--;
if (frame == 0)
{
if (IsDone() == false)
{
Status = EStatus.Failed;
LastError = $"WaitForAsyncComplete failed ! Try load bundle : {MainBundleInfo.Bundle.BundleName} from remote with sync load method !";
YooLogger.Error(LastError);
}
break;
}
// 驱动流程
Update();
// 完成后退出
if (IsDone())
break;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7b9023a940b496549894d9d8872219fb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fcfac83df022948478c32bf11b8e0987
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,132 @@
using UnityEngine;
namespace YooAsset
{
public sealed class InstantiateOperation : AsyncOperationBase
{
private enum ESteps
{
None,
Clone,
Done,
}
private readonly AssetOperationHandle _handle;
private readonly bool _setPositionAndRotation;
private readonly Vector3 _position;
private readonly Quaternion _rotation;
private readonly Transform _parent;
private readonly bool _worldPositionStays;
private ESteps _steps = ESteps.None;
/// <summary>
/// 实例化的游戏对象
/// </summary>
public GameObject Result = null;
internal InstantiateOperation(AssetOperationHandle handle, bool setPositionAndRotation, Vector3 position, Quaternion rotation, Transform parent, bool worldPositionStays)
{
_handle = handle;
_setPositionAndRotation = setPositionAndRotation;
_position = position;
_rotation = rotation;
_parent = parent;
_worldPositionStays = worldPositionStays;
}
internal override void Start()
{
_steps = ESteps.Clone;
}
internal override void Update()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.Clone)
{
if (_handle.IsValidWithWarning == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(AssetOperationHandle)} is invalid.";
return;
}
if (_handle.IsDone == false)
return;
if (_handle.AssetObject == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(AssetOperationHandle.AssetObject)} is null.";
return;
}
// 实例化游戏对象
Result = InstantiateInternal(_handle.AssetObject, _setPositionAndRotation, _position, _rotation, _parent, _worldPositionStays);
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
/// <summary>
/// 取消实例化对象操作
/// </summary>
public void Cancel()
{
if (IsDone == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"User cancelled !";
}
}
/// <summary>
/// 等待异步实例化结束
/// </summary>
public void WaitForAsyncComplete()
{
if (_steps == ESteps.Done)
return;
_handle.WaitForAsyncComplete();
Update();
}
internal static GameObject InstantiateInternal(UnityEngine.Object assetObject, bool setPositionAndRotation, Vector3 position, Quaternion rotation, Transform parent, bool worldPositionStays)
{
if (assetObject == null)
return null;
if (setPositionAndRotation)
{
if (parent != null)
{
GameObject clone = UnityEngine.Object.Instantiate(assetObject as GameObject, position, rotation, parent);
return clone;
}
else
{
GameObject clone = UnityEngine.Object.Instantiate(assetObject as GameObject, position, rotation);
return clone;
}
}
else
{
if (parent != null)
{
GameObject clone = UnityEngine.Object.Instantiate(assetObject as GameObject, parent, worldPositionStays);
return clone;
}
else
{
GameObject clone = UnityEngine.Object.Instantiate(assetObject as GameObject);
return clone;
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8e7d3b16d9b01f548b4654e958d43a37
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,86 @@
using UnityEngine;
using UnityEngine.SceneManagement;
namespace YooAsset
{
/// <summary>
/// 场景卸载异步操作类
/// </summary>
public sealed class UnloadSceneOperation : AsyncOperationBase
{
private enum EFlag
{
Normal,
Error,
}
private enum ESteps
{
None,
UnLoad,
Checking,
Done,
}
private readonly EFlag _flag;
private ESteps _steps = ESteps.None;
private Scene _scene;
private AsyncOperation _asyncOp;
internal UnloadSceneOperation(string error)
{
_flag = EFlag.Error;
Error = error;
}
internal UnloadSceneOperation(Scene scene)
{
_flag = EFlag.Normal;
_scene = scene;
}
internal override void Start()
{
if (_flag == EFlag.Normal)
{
_steps = ESteps.UnLoad;
}
else if (_flag == EFlag.Error)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
}
else
{
throw new System.NotImplementedException(_flag.ToString());
}
}
internal override void Update()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.UnLoad)
{
if (_scene.IsValid() && _scene.isLoaded)
{
_asyncOp = SceneManager.UnloadSceneAsync(_scene);
_steps = ESteps.Checking;
}
else
{
Error = "Scene is invalid or is not loaded.";
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
}
}
if (_steps == ESteps.Checking)
{
Progress = _asyncOp.progress;
if (_asyncOp.isDone == false)
return;
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5299512de5ab5c141ae37dac6ee1721e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c64025c73372d9d4cab02c9cf9436e55
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,118 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal sealed class BundledAllAssetsProvider : ProviderBase
{
private AssetBundleRequest _cacheRequest;
public BundledAllAssetsProvider(AssetSystemImpl impl, string providerGUID, AssetInfo assetInfo) : base(impl, providerGUID, assetInfo)
{
}
public override void Update()
{
DebugBeginRecording();
if (IsDone)
return;
if (Status == EStatus.None)
{
Status = EStatus.CheckBundle;
}
// 1. 检测资源包
if (Status == EStatus.CheckBundle)
{
if (IsWaitForAsyncComplete)
{
DependBundles.WaitForAsyncComplete();
OwnerBundle.WaitForAsyncComplete();
}
if (DependBundles.IsDone() == false)
return;
if (OwnerBundle.IsDone() == false)
return;
if (DependBundles.IsSucceed() == false)
{
Status = EStatus.Failed;
LastError = DependBundles.GetLastError();
InvokeCompletion();
return;
}
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
{
Status = EStatus.Failed;
LastError = OwnerBundle.LastError;
InvokeCompletion();
return;
}
if (OwnerBundle.CacheBundle == null)
{
ProcessCacheBundleException();
return;
}
Status = EStatus.Loading;
}
// 2. 加载资源对象
if (Status == EStatus.Loading)
{
if (IsWaitForAsyncComplete)
{
if (MainAssetInfo.AssetType == null)
AllAssetObjects = OwnerBundle.CacheBundle.LoadAllAssets();
else
AllAssetObjects = OwnerBundle.CacheBundle.LoadAllAssets(MainAssetInfo.AssetType);
}
else
{
if (MainAssetInfo.AssetType == null)
_cacheRequest = OwnerBundle.CacheBundle.LoadAllAssetsAsync();
else
_cacheRequest = OwnerBundle.CacheBundle.LoadAllAssetsAsync(MainAssetInfo.AssetType);
}
Status = EStatus.Checking;
}
// 3. 检测加载结果
if (Status == EStatus.Checking)
{
if (_cacheRequest != null)
{
if (IsWaitForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity asset.");
AllAssetObjects = _cacheRequest.allAssets;
}
else
{
Progress = _cacheRequest.progress;
if (_cacheRequest.isDone == false)
return;
AllAssetObjects = _cacheRequest.allAssets;
}
}
Status = AllAssetObjects == null ? EStatus.Failed : EStatus.Succeed;
if (Status == EStatus.Failed)
{
if (MainAssetInfo.AssetType == null)
LastError = $"Failed to load all assets : {MainAssetInfo.AssetPath} AssetType : null AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
else
LastError = $"Failed to load all assets : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType} AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
}
InvokeCompletion();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9b0e966838827284a9266a9f2237a460
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,118 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal sealed class BundledAssetProvider : ProviderBase
{
private AssetBundleRequest _cacheRequest;
public BundledAssetProvider(AssetSystemImpl impl, string providerGUID, AssetInfo assetInfo) : base(impl, providerGUID, assetInfo)
{
}
public override void Update()
{
DebugBeginRecording();
if (IsDone)
return;
if (Status == EStatus.None)
{
Status = EStatus.CheckBundle;
}
// 1. 检测资源包
if (Status == EStatus.CheckBundle)
{
if (IsWaitForAsyncComplete)
{
DependBundles.WaitForAsyncComplete();
OwnerBundle.WaitForAsyncComplete();
}
if (DependBundles.IsDone() == false)
return;
if (OwnerBundle.IsDone() == false)
return;
if (DependBundles.IsSucceed() == false)
{
Status = EStatus.Failed;
LastError = DependBundles.GetLastError();
InvokeCompletion();
return;
}
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
{
Status = EStatus.Failed;
LastError = OwnerBundle.LastError;
InvokeCompletion();
return;
}
if (OwnerBundle.CacheBundle == null)
{
ProcessCacheBundleException();
return;
}
Status = EStatus.Loading;
}
// 2. 加载资源对象
if (Status == EStatus.Loading)
{
if (IsWaitForAsyncComplete)
{
if (MainAssetInfo.AssetType == null)
AssetObject = OwnerBundle.CacheBundle.LoadAsset(MainAssetInfo.AssetPath);
else
AssetObject = OwnerBundle.CacheBundle.LoadAsset(MainAssetInfo.AssetPath, MainAssetInfo.AssetType);
}
else
{
if (MainAssetInfo.AssetType == null)
_cacheRequest = OwnerBundle.CacheBundle.LoadAssetAsync(MainAssetInfo.AssetPath);
else
_cacheRequest = OwnerBundle.CacheBundle.LoadAssetAsync(MainAssetInfo.AssetPath, MainAssetInfo.AssetType);
}
Status = EStatus.Checking;
}
// 3. 检测加载结果
if (Status == EStatus.Checking)
{
if (_cacheRequest != null)
{
if (IsWaitForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity asset.");
AssetObject = _cacheRequest.asset;
}
else
{
Progress = _cacheRequest.progress;
if (_cacheRequest.isDone == false)
return;
AssetObject = _cacheRequest.asset;
}
}
Status = AssetObject == null ? EStatus.Failed : EStatus.Succeed;
if (Status == EStatus.Failed)
{
if (MainAssetInfo.AssetType == null)
LastError = $"Failed to load asset : {MainAssetInfo.AssetPath} AssetType : null AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
else
LastError = $"Failed to load asset : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType} AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
}
InvokeCompletion();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ca5e4bf0c3efe6742bb57b494487be52
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,52 @@

namespace YooAsset
{
internal class BundledRawFileProvider : ProviderBase
{
public BundledRawFileProvider(AssetSystemImpl impl, string providerGUID, AssetInfo assetInfo) : base(impl, providerGUID, assetInfo)
{
}
public override void Update()
{
DebugBeginRecording();
if (IsDone)
return;
if (Status == EStatus.None)
{
Status = EStatus.CheckBundle;
}
// 1. 检测资源包
if (Status == EStatus.CheckBundle)
{
if (IsWaitForAsyncComplete)
{
OwnerBundle.WaitForAsyncComplete();
}
if (OwnerBundle.IsDone() == false)
return;
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
{
Status = EStatus.Failed;
LastError = OwnerBundle.LastError;
InvokeCompletion();
return;
}
Status = EStatus.Checking;
}
// 2. 检测加载结果
if (Status == EStatus.Checking)
{
RawFilePath = OwnerBundle.FileLoadPath;
Status = EStatus.Succeed;
InvokeCompletion();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8a00889582fd95446b103af1074fa6ba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,113 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace YooAsset
{
internal sealed class BundledSceneProvider : ProviderBase
{
public readonly LoadSceneMode SceneMode;
private readonly string _sceneName;
private readonly bool _suspendLoad;
private readonly int _priority;
private AsyncOperation _asyncOperation;
public BundledSceneProvider(AssetSystemImpl impl, string providerGUID, AssetInfo assetInfo, LoadSceneMode sceneMode, bool suspendLoad, int priority) : base(impl, providerGUID, assetInfo)
{
SceneMode = sceneMode;
_sceneName = Path.GetFileNameWithoutExtension(assetInfo.AssetPath);
_suspendLoad = suspendLoad;
_priority = priority;
}
public override void Update()
{
DebugBeginRecording();
if (IsDone)
return;
if (Status == EStatus.None)
{
Status = EStatus.CheckBundle;
}
// 1. 检测资源包
if (Status == EStatus.CheckBundle)
{
if (DependBundles.IsDone() == false)
return;
if (OwnerBundle.IsDone() == false)
return;
if (DependBundles.IsSucceed() == false)
{
Status = EStatus.Failed;
LastError = DependBundles.GetLastError();
InvokeCompletion();
return;
}
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
{
Status = EStatus.Failed;
LastError = OwnerBundle.LastError;
InvokeCompletion();
return;
}
Status = EStatus.Loading;
}
// 2. 加载场景
if (Status == EStatus.Loading)
{
// 注意如果场景不存在则返回NULL
_asyncOperation = SceneManager.LoadSceneAsync(MainAssetInfo.AssetPath, SceneMode);
if (_asyncOperation != null)
{
_asyncOperation.allowSceneActivation = !_suspendLoad;
_asyncOperation.priority = _priority;
SceneObject = SceneManager.GetSceneAt(SceneManager.sceneCount - 1);
Status = EStatus.Checking;
}
else
{
Status = EStatus.Failed;
LastError = $"Failed to load scene : {_sceneName}";
YooLogger.Error(LastError);
InvokeCompletion();
}
}
// 3. 检测加载结果
if (Status == EStatus.Checking)
{
Progress = _asyncOperation.progress;
if (_asyncOperation.isDone)
{
Status = SceneObject.IsValid() ? EStatus.Succeed : EStatus.Failed;
if (Status == EStatus.Failed)
{
LastError = $"The load scene is invalid : {MainAssetInfo.AssetPath}";
YooLogger.Error(LastError);
}
InvokeCompletion();
}
}
}
/// <summary>
/// 解除场景加载挂起操作
/// </summary>
public bool UnSuspendLoad()
{
if (_asyncOperation == null)
return false;
_asyncOperation.allowSceneActivation = true;
return true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 38b1b77cff590ca4e808c5068c9bf88b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,118 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal sealed class BundledSubAssetsProvider : ProviderBase
{
private AssetBundleRequest _cacheRequest;
public BundledSubAssetsProvider(AssetSystemImpl impl, string providerGUID, AssetInfo assetInfo) : base(impl, providerGUID, assetInfo)
{
}
public override void Update()
{
DebugBeginRecording();
if (IsDone)
return;
if (Status == EStatus.None)
{
Status = EStatus.CheckBundle;
}
// 1. 检测资源包
if (Status == EStatus.CheckBundle)
{
if (IsWaitForAsyncComplete)
{
DependBundles.WaitForAsyncComplete();
OwnerBundle.WaitForAsyncComplete();
}
if (DependBundles.IsDone() == false)
return;
if (OwnerBundle.IsDone() == false)
return;
if (DependBundles.IsSucceed() == false)
{
Status = EStatus.Failed;
LastError = DependBundles.GetLastError();
InvokeCompletion();
return;
}
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
{
Status = EStatus.Failed;
LastError = OwnerBundle.LastError;
InvokeCompletion();
return;
}
if (OwnerBundle.CacheBundle == null)
{
ProcessCacheBundleException();
return;
}
Status = EStatus.Loading;
}
// 2. 加载资源对象
if (Status == EStatus.Loading)
{
if (IsWaitForAsyncComplete)
{
if (MainAssetInfo.AssetType == null)
AllAssetObjects = OwnerBundle.CacheBundle.LoadAssetWithSubAssets(MainAssetInfo.AssetPath);
else
AllAssetObjects = OwnerBundle.CacheBundle.LoadAssetWithSubAssets(MainAssetInfo.AssetPath, MainAssetInfo.AssetType);
}
else
{
if (MainAssetInfo.AssetType == null)
_cacheRequest = OwnerBundle.CacheBundle.LoadAssetWithSubAssetsAsync(MainAssetInfo.AssetPath);
else
_cacheRequest = OwnerBundle.CacheBundle.LoadAssetWithSubAssetsAsync(MainAssetInfo.AssetPath, MainAssetInfo.AssetType);
}
Status = EStatus.Checking;
}
// 3. 检测加载结果
if (Status == EStatus.Checking)
{
if (_cacheRequest != null)
{
if (IsWaitForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity asset.");
AllAssetObjects = _cacheRequest.allAssets;
}
else
{
Progress = _cacheRequest.progress;
if (_cacheRequest.isDone == false)
return;
AllAssetObjects = _cacheRequest.allAssets;
}
}
Status = AllAssetObjects == null ? EStatus.Failed : EStatus.Succeed;
if (Status == EStatus.Failed)
{
if (MainAssetInfo.AssetType == null)
LastError = $"Failed to load sub assets : {MainAssetInfo.AssetPath} AssetType : null AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
else
LastError = $"Failed to load sub assets : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType} AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
}
InvokeCompletion();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b3763bf52bde23b41a756f0d015cb30d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@

namespace YooAsset
{
internal sealed class CompletedProvider : ProviderBase
{
public CompletedProvider(AssetInfo assetInfo) : base(null, string.Empty, assetInfo)
{
}
public override void Update()
{
}
public void SetCompleted(string error)
{
if (Status == EStatus.None)
{
Status = EStatus.Failed;
LastError = error;
InvokeCompletion();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8e64fd2ee771f7d498838ebf375a9531
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,105 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal sealed class DatabaseAllAssetsProvider : ProviderBase
{
public DatabaseAllAssetsProvider(AssetSystemImpl impl, string providerGUID, AssetInfo assetInfo) : base(impl, providerGUID, assetInfo)
{
}
public override void Update()
{
#if UNITY_EDITOR
if (IsDone)
return;
if (Status == EStatus.None)
{
// 检测资源文件是否存在
string guid = UnityEditor.AssetDatabase.AssetPathToGUID(MainAssetInfo.AssetPath);
if (string.IsNullOrEmpty(guid))
{
Status = EStatus.Failed;
LastError = $"Not found asset : {MainAssetInfo.AssetPath}";
YooLogger.Error(LastError);
InvokeCompletion();
return;
}
Status = EStatus.CheckBundle;
// 注意:模拟异步加载效果提前返回
if (IsWaitForAsyncComplete == false)
return;
}
// 1. 检测资源包
if (Status == EStatus.CheckBundle)
{
if (IsWaitForAsyncComplete)
{
OwnerBundle.WaitForAsyncComplete();
}
if (OwnerBundle.IsDone() == false)
return;
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
{
Status = EStatus.Failed;
LastError = OwnerBundle.LastError;
InvokeCompletion();
return;
}
Status = EStatus.Loading;
}
// 2. 加载资源对象
if (Status == EStatus.Loading)
{
if (MainAssetInfo.AssetType == null)
{
List<UnityEngine.Object> result = new List<Object>();
foreach (var assetPath in OwnerBundle.MainBundleInfo.IncludeAssets)
{
UnityEngine.Object mainAsset = UnityEditor.AssetDatabase.LoadMainAssetAtPath(assetPath);
if (mainAsset != null)
result.Add(mainAsset);
}
AllAssetObjects = result.ToArray();
}
else
{
List<UnityEngine.Object> result = new List<Object>();
foreach (var assetPath in OwnerBundle.MainBundleInfo.IncludeAssets)
{
UnityEngine.Object mainAsset = UnityEditor.AssetDatabase.LoadAssetAtPath(assetPath, MainAssetInfo.AssetType);
if (mainAsset != null)
result.Add(mainAsset);
}
AllAssetObjects = result.ToArray();
}
Status = EStatus.Checking;
}
// 3. 检测加载结果
if (Status == EStatus.Checking)
{
Status = AllAssetObjects == null ? EStatus.Failed : EStatus.Succeed;
if (Status == EStatus.Failed)
{
if (MainAssetInfo.AssetType == null)
LastError = $"Failed to load all assets : {MainAssetInfo.AssetPath} AssetType : null";
else
LastError = $"Failed to load all assets : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType}";
YooLogger.Error(LastError);
}
InvokeCompletion();
}
#endif
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c72eb6001f903de46bc72dea0d8b39c5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,87 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal sealed class DatabaseAssetProvider : ProviderBase
{
public DatabaseAssetProvider(AssetSystemImpl impl, string providerGUID, AssetInfo assetInfo) : base(impl, providerGUID, assetInfo)
{
}
public override void Update()
{
#if UNITY_EDITOR
if (IsDone)
return;
if (Status == EStatus.None)
{
// 检测资源文件是否存在
string guid = UnityEditor.AssetDatabase.AssetPathToGUID(MainAssetInfo.AssetPath);
if (string.IsNullOrEmpty(guid))
{
Status = EStatus.Failed;
LastError = $"Not found asset : {MainAssetInfo.AssetPath}";
YooLogger.Error(LastError);
InvokeCompletion();
return;
}
Status = EStatus.CheckBundle;
// 注意:模拟异步加载效果提前返回
if (IsWaitForAsyncComplete == false)
return;
}
// 1. 检测资源包
if (Status == EStatus.CheckBundle)
{
if (IsWaitForAsyncComplete)
{
OwnerBundle.WaitForAsyncComplete();
}
if (OwnerBundle.IsDone() == false)
return;
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
{
Status = EStatus.Failed;
LastError = OwnerBundle.LastError;
InvokeCompletion();
return;
}
Status = EStatus.Loading;
}
// 2. 加载资源对象
if (Status == EStatus.Loading)
{
if (MainAssetInfo.AssetType == null)
AssetObject = UnityEditor.AssetDatabase.LoadMainAssetAtPath(MainAssetInfo.AssetPath);
else
AssetObject = UnityEditor.AssetDatabase.LoadAssetAtPath(MainAssetInfo.AssetPath, MainAssetInfo.AssetType);
Status = EStatus.Checking;
}
// 3. 检测加载结果
if (Status == EStatus.Checking)
{
Status = AssetObject == null ? EStatus.Failed : EStatus.Succeed;
if (Status == EStatus.Failed)
{
if (MainAssetInfo.AssetType == null)
LastError = $"Failed to load asset object : {MainAssetInfo.AssetPath} AssetType : null";
else
LastError = $"Failed to load asset object : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType}";
YooLogger.Error(LastError);
}
InvokeCompletion();
}
#endif
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d4022dd2ea39af5458fb1d61ec997347
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,67 @@

namespace YooAsset
{
internal class DatabaseRawFileProvider : ProviderBase
{
public DatabaseRawFileProvider(AssetSystemImpl impl, string providerGUID, AssetInfo assetInfo) : base(impl, providerGUID, assetInfo)
{
}
public override void Update()
{
#if UNITY_EDITOR
if (IsDone)
return;
if (Status == EStatus.None)
{
// 检测资源文件是否存在
string guid = UnityEditor.AssetDatabase.AssetPathToGUID(MainAssetInfo.AssetPath);
if (string.IsNullOrEmpty(guid))
{
Status = EStatus.Failed;
LastError = $"Not found asset : {MainAssetInfo.AssetPath}";
YooLogger.Error(LastError);
InvokeCompletion();
return;
}
Status = EStatus.CheckBundle;
// 注意:模拟异步加载效果提前返回
if (IsWaitForAsyncComplete == false)
return;
}
// 1. 检测资源包
if (Status == EStatus.CheckBundle)
{
if (IsWaitForAsyncComplete)
{
OwnerBundle.WaitForAsyncComplete();
}
if (OwnerBundle.IsDone() == false)
return;
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
{
Status = EStatus.Failed;
LastError = OwnerBundle.LastError;
InvokeCompletion();
return;
}
Status = EStatus.Checking;
}
// 2. 检测加载结果
if (Status == EStatus.Checking)
{
RawFilePath = MainAssetInfo.AssetPath;
Status = EStatus.Succeed;
InvokeCompletion();
}
#endif
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 41d0e9bbc5a3a5b4e8b05d60d40d495a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,104 @@
using UnityEngine;
using UnityEngine.SceneManagement;
namespace YooAsset
{
internal sealed class DatabaseSceneProvider : ProviderBase
{
public readonly LoadSceneMode SceneMode;
private readonly bool _suspendLoad;
private readonly int _priority;
private AsyncOperation _asyncOperation;
public DatabaseSceneProvider(AssetSystemImpl impl, string providerGUID, AssetInfo assetInfo, LoadSceneMode sceneMode, bool suspendLoad, int priority) : base(impl, providerGUID, assetInfo)
{
SceneMode = sceneMode;
_suspendLoad = suspendLoad;
_priority = priority;
}
public override void Update()
{
#if UNITY_EDITOR
if (IsDone)
return;
if (Status == EStatus.None)
{
Status = EStatus.CheckBundle;
}
// 1. 检测资源包
if (Status == EStatus.CheckBundle)
{
if (IsWaitForAsyncComplete)
{
OwnerBundle.WaitForAsyncComplete();
}
if (OwnerBundle.IsDone() == false)
return;
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
{
Status = EStatus.Failed;
LastError = OwnerBundle.LastError;
InvokeCompletion();
return;
}
Status = EStatus.Loading;
}
// 2. 加载资源对象
if (Status == EStatus.Loading)
{
LoadSceneParameters loadSceneParameters = new LoadSceneParameters();
loadSceneParameters.loadSceneMode = SceneMode;
_asyncOperation = UnityEditor.SceneManagement.EditorSceneManager.LoadSceneAsyncInPlayMode(MainAssetInfo.AssetPath, loadSceneParameters);
if (_asyncOperation != null)
{
_asyncOperation.allowSceneActivation = !_suspendLoad;
_asyncOperation.priority = _priority;
SceneObject = SceneManager.GetSceneAt(SceneManager.sceneCount - 1);
Status = EStatus.Checking;
}
else
{
Status = EStatus.Failed;
LastError = $"Failed to load scene : {MainAssetInfo.AssetPath}";
YooLogger.Error(LastError);
InvokeCompletion();
}
}
// 3. 检测加载结果
if (Status == EStatus.Checking)
{
Progress = _asyncOperation.progress;
if (_asyncOperation.isDone)
{
Status = SceneObject.IsValid() ? EStatus.Succeed : EStatus.Failed;
if (Status == EStatus.Failed)
{
LastError = $"The loaded scene is invalid : {MainAssetInfo.AssetPath}";
YooLogger.Error(LastError);
}
InvokeCompletion();
}
}
#endif
}
/// <summary>
/// 解除场景加载挂起操作
/// </summary>
public bool UnSuspendLoad()
{
if (_asyncOperation == null)
return false;
_asyncOperation.allowSceneActivation = true;
return true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8252a639423064f498ed22f14912adae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,98 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal sealed class DatabaseSubAssetsProvider : ProviderBase
{
public DatabaseSubAssetsProvider(AssetSystemImpl impl, string providerGUID, AssetInfo assetInfo) : base(impl, providerGUID, assetInfo)
{
}
public override void Update()
{
#if UNITY_EDITOR
if (IsDone)
return;
if (Status == EStatus.None)
{
// 检测资源文件是否存在
string guid = UnityEditor.AssetDatabase.AssetPathToGUID(MainAssetInfo.AssetPath);
if (string.IsNullOrEmpty(guid))
{
Status = EStatus.Failed;
LastError = $"Not found asset : {MainAssetInfo.AssetPath}";
YooLogger.Error(LastError);
InvokeCompletion();
return;
}
Status = EStatus.CheckBundle;
// 注意:模拟异步加载效果提前返回
if (IsWaitForAsyncComplete == false)
return;
}
// 1. 检测资源包
if (Status == EStatus.CheckBundle)
{
if (IsWaitForAsyncComplete)
{
OwnerBundle.WaitForAsyncComplete();
}
if (OwnerBundle.IsDone() == false)
return;
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
{
Status = EStatus.Failed;
LastError = OwnerBundle.LastError;
InvokeCompletion();
return;
}
Status = EStatus.Loading;
}
// 2. 加载资源对象
if (Status == EStatus.Loading)
{
if (MainAssetInfo.AssetType == null)
{
AllAssetObjects = UnityEditor.AssetDatabase.LoadAllAssetRepresentationsAtPath(MainAssetInfo.AssetPath);
}
else
{
UnityEngine.Object[] findAssets = UnityEditor.AssetDatabase.LoadAllAssetRepresentationsAtPath(MainAssetInfo.AssetPath);
List<UnityEngine.Object> result = new List<Object>(findAssets.Length);
foreach (var findAsset in findAssets)
{
if (MainAssetInfo.AssetType.IsAssignableFrom(findAsset.GetType()))
result.Add(findAsset);
}
AllAssetObjects = result.ToArray();
}
Status = EStatus.Checking;
}
// 3. 检测加载结果
if (Status == EStatus.Checking)
{
Status = AllAssetObjects == null ? EStatus.Failed : EStatus.Succeed;
if (Status == EStatus.Failed)
{
if (MainAssetInfo.AssetType == null)
LastError = $"Failed to load sub assets : {MainAssetInfo.AssetPath} AssetType : null";
else
LastError = $"Failed to load sub assets : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType}";
YooLogger.Error(LastError);
}
InvokeCompletion();
}
#endif
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3837962b901d7ba4abf02a9991ac4c4a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,373 @@
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
namespace YooAsset
{
internal abstract class ProviderBase
{
public enum EStatus
{
None = 0,
CheckBundle,
Loading,
Checking,
Succeed,
Failed,
}
/// <summary>
/// 资源提供者唯一标识符
/// </summary>
public string ProviderGUID { private set; get; }
/// <summary>
/// 所属资源系统
/// </summary>
public AssetSystemImpl Impl { private set; get; }
/// <summary>
/// 资源信息
/// </summary>
public AssetInfo MainAssetInfo { private set; get; }
/// <summary>
/// 获取的资源对象
/// </summary>
public UnityEngine.Object AssetObject { protected set; get; }
/// <summary>
/// 获取的资源对象集合
/// </summary>
public UnityEngine.Object[] AllAssetObjects { protected set; get; }
/// <summary>
/// 获取的场景对象
/// </summary>
public UnityEngine.SceneManagement.Scene SceneObject { protected set; get; }
/// <summary>
/// 原生文件路径
/// </summary>
public string RawFilePath { protected set; get; }
/// <summary>
/// 当前的加载状态
/// </summary>
public EStatus Status { protected set; get; } = EStatus.None;
/// <summary>
/// 最近的错误信息
/// </summary>
public string LastError { protected set; get; } = string.Empty;
/// <summary>
/// 加载进度
/// </summary>
public float Progress { protected set; get; } = 0f;
/// <summary>
/// 引用计数
/// </summary>
public int RefCount { private set; get; } = 0;
/// <summary>
/// 是否已经销毁
/// </summary>
public bool IsDestroyed { private set; get; } = false;
/// <summary>
/// 是否完毕(成功或失败)
/// </summary>
public bool IsDone
{
get
{
return Status == EStatus.Succeed || Status == EStatus.Failed;
}
}
protected BundleLoaderBase OwnerBundle { private set; get; }
protected DependAssetBundles DependBundles { private set; get; }
protected bool IsWaitForAsyncComplete { private set; get; } = false;
private readonly List<OperationHandleBase> _handles = new List<OperationHandleBase>();
public ProviderBase(AssetSystemImpl impl, string providerGUID, AssetInfo assetInfo)
{
Impl = impl;
ProviderGUID = providerGUID;
MainAssetInfo = assetInfo;
// 创建资源包加载器
if (impl != null)
{
OwnerBundle = impl.CreateOwnerAssetBundleLoader(assetInfo);
OwnerBundle.Reference();
OwnerBundle.AddProvider(this);
var dependList = impl.CreateDependAssetBundleLoaders(assetInfo);
DependBundles = new DependAssetBundles(dependList);
DependBundles.Reference();
}
}
/// <summary>
/// 轮询更新方法
/// </summary>
public abstract void Update();
/// <summary>
/// 销毁资源对象
/// </summary>
public void Destroy()
{
IsDestroyed = true;
// 释放资源包加载器
if (OwnerBundle != null)
{
OwnerBundle.Release();
OwnerBundle = null;
}
if (DependBundles != null)
{
DependBundles.Release();
DependBundles = null;
}
}
/// <summary>
/// 是否可以销毁
/// </summary>
public bool CanDestroy()
{
if (IsDone == false)
return false;
return RefCount <= 0;
}
/// <summary>
/// 是否为场景提供者
/// </summary>
public bool IsSceneProvider()
{
if (this is BundledSceneProvider || this is DatabaseSceneProvider)
return true;
else
return false;
}
/// <summary>
/// 创建操作句柄
/// </summary>
public T CreateHandle<T>() where T : OperationHandleBase
{
// 引用计数增加
RefCount++;
OperationHandleBase handle;
if (typeof(T) == typeof(AssetOperationHandle))
handle = new AssetOperationHandle(this);
else if (typeof(T) == typeof(SceneOperationHandle))
handle = new SceneOperationHandle(this);
else if (typeof(T) == typeof(SubAssetsOperationHandle))
handle = new SubAssetsOperationHandle(this);
else if (typeof(T) == typeof(AllAssetsOperationHandle))
handle = new AllAssetsOperationHandle(this);
else if (typeof(T) == typeof(RawFileOperationHandle))
handle = new RawFileOperationHandle(this);
else
throw new System.NotImplementedException();
_handles.Add(handle);
return handle as T;
}
/// <summary>
/// 释放操作句柄
/// </summary>
public void ReleaseHandle(OperationHandleBase handle)
{
if (RefCount <= 0)
YooLogger.Warning("Asset provider reference count is already zero. There may be resource leaks !");
if (_handles.Remove(handle) == false)
throw new System.Exception("Should never get here !");
// 引用计数减少
RefCount--;
}
/// <summary>
/// 等待异步执行完毕
/// </summary>
public void WaitForAsyncComplete()
{
IsWaitForAsyncComplete = true;
// 注意:主动轮询更新完成同步加载
Update();
// 验证结果
if (IsDone == false)
{
YooLogger.Warning($"WaitForAsyncComplete failed to loading : {MainAssetInfo.AssetPath}");
}
}
/// <summary>
/// 处理特殊异常
/// </summary>
protected void ProcessCacheBundleException()
{
if (OwnerBundle.IsDestroyed)
throw new System.Exception("Should never get here !");
if (OwnerBundle.MainBundleInfo.Bundle.IsRawFile)
{
Status = EStatus.Failed;
LastError = $"Cannot load asset bundle file using {nameof(ResourcePackage.LoadRawFileAsync)} method !";
YooLogger.Error(LastError);
InvokeCompletion();
}
else
{
Status = EStatus.Failed;
LastError = $"The bundle {OwnerBundle.MainBundleInfo.Bundle.BundleName} has been destroyed by unity bugs !";
YooLogger.Error(LastError);
InvokeCompletion();
}
}
/// <summary>
/// 异步操作任务
/// </summary>
public Task Task
{
get
{
if (_taskCompletionSource == null)
{
_taskCompletionSource = new TaskCompletionSource<object>();
if (IsDone)
_taskCompletionSource.SetResult(null);
}
return _taskCompletionSource.Task;
}
}
#region
private TaskCompletionSource<object> _taskCompletionSource;
protected void InvokeCompletion()
{
DebugEndRecording();
// 进度百分百完成
Progress = 1f;
// 注意:创建临时列表是为了防止外部逻辑在回调函数内创建或者释放资源句柄。
// 注意:回调方法如果发生异常,会阻断列表里的后续回调方法!
List<OperationHandleBase> tempers = new List<OperationHandleBase>(_handles);
foreach (var hande in tempers)
{
if (hande.IsValid)
{
hande.InvokeCallback();
}
}
if (_taskCompletionSource != null)
_taskCompletionSource.TrySetResult(null);
}
#endregion
#region
/// <summary>
/// 出生的场景
/// </summary>
public string SpawnScene = string.Empty;
/// <summary>
/// 出生的时间
/// </summary>
public string SpawnTime = string.Empty;
/// <summary>
/// 加载耗时(单位:毫秒)
/// </summary>
public long LoadingTime { protected set; get; }
// 加载耗时统计
private Stopwatch _watch = null;
[Conditional("DEBUG")]
public void InitSpawnDebugInfo()
{
SpawnScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name; ;
SpawnTime = SpawnTimeToString(UnityEngine.Time.realtimeSinceStartup);
}
private string SpawnTimeToString(float spawnTime)
{
float h = UnityEngine.Mathf.FloorToInt(spawnTime / 3600f);
float m = UnityEngine.Mathf.FloorToInt(spawnTime / 60f - h * 60f);
float s = UnityEngine.Mathf.FloorToInt(spawnTime - m * 60f - h * 3600f);
return h.ToString("00") + ":" + m.ToString("00") + ":" + s.ToString("00");
}
[Conditional("DEBUG")]
protected void DebugBeginRecording()
{
if (_watch == null)
{
_watch = Stopwatch.StartNew();
}
}
[Conditional("DEBUG")]
private void DebugEndRecording()
{
if (_watch != null)
{
LoadingTime = _watch.ElapsedMilliseconds;
_watch = null;
}
}
/// <summary>
/// 获取下载报告
/// </summary>
internal DownloadReport GetDownloadReport()
{
DownloadReport result = new DownloadReport();
result.TotalSize = (ulong)OwnerBundle.MainBundleInfo.Bundle.FileSize;
result.DownloadedBytes = OwnerBundle.DownloadedBytes;
foreach (var dependBundle in DependBundles.DependList)
{
result.TotalSize += (ulong)dependBundle.MainBundleInfo.Bundle.FileSize;
result.DownloadedBytes += dependBundle.DownloadedBytes;
}
result.Progress = (float)result.DownloadedBytes / result.TotalSize;
return result;
}
/// <summary>
/// 获取资源包的调试信息列表
/// </summary>
internal void GetBundleDebugInfos(List<DebugBundleInfo> output)
{
var bundleInfo = new DebugBundleInfo();
bundleInfo.BundleName = OwnerBundle.MainBundleInfo.Bundle.BundleName;
bundleInfo.RefCount = OwnerBundle.RefCount;
bundleInfo.Status = OwnerBundle.Status.ToString();
output.Add(bundleInfo);
DependBundles.GetBundleDebugInfos(output);
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 02cc2ce3da5a88b48942ad96e6061aad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: