Firstborn/Library/PackageCache/com.unity.addressables@1.19.19/Runtime/ResourceManager/ResourceProviders/BundledAssetProvider.cs

229 lines
9.7 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.ComponentModel;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.Util;
namespace UnityEngine.ResourceManagement.ResourceProviders
{
/// <summary>
/// Provides assets stored in an asset bundle.
/// </summary>
[DisplayName("Assets from Bundles Provider")]
public class BundledAssetProvider : ResourceProviderBase
{
internal class InternalOp
{
AssetBundle m_AssetBundle;
AssetBundleRequest m_PreloadRequest;
AssetBundleRequest m_RequestOperation;
object m_Result;
ProvideHandle m_ProvideHandle;
string subObjectName = null;
internal static T LoadBundleFromDependecies<T>(IList<object> results) where T : class, IAssetBundleResource
{
if (results == null || results.Count == 0)
return default(T);
IAssetBundleResource bundle = null;
bool firstBundleWrapper = true;
for (int i = 0; i < results.Count; i++)
{
var abWrapper = results[i] as IAssetBundleResource;
if (abWrapper != null)
{
//only use the first asset bundle, even if it is invalid
abWrapper.GetAssetBundle();
if (firstBundleWrapper)
bundle = abWrapper;
firstBundleWrapper = false;
}
}
return bundle as T;
}
public void Start(ProvideHandle provideHandle)
{
provideHandle.SetProgressCallback(ProgressCallback);
provideHandle.SetWaitForCompletionCallback(WaitForCompletionHandler);
subObjectName = null;
m_ProvideHandle = provideHandle;
m_RequestOperation = null;
List<object> deps = new List<object>(); // TODO: garbage. need to pass actual count and reuse the list
m_ProvideHandle.GetDependencies(deps);
var bundleResource = LoadBundleFromDependecies<IAssetBundleResource>(deps);
if (bundleResource == null)
{
m_ProvideHandle.Complete<AssetBundle>(null, false, new Exception("Unable to load dependent bundle from location " + m_ProvideHandle.Location));
}
else
{
m_AssetBundle = bundleResource.GetAssetBundle();
if (m_AssetBundle == null)
{
m_ProvideHandle.Complete<AssetBundle>(null, false, new Exception("Unable to load dependent bundle from location " + m_ProvideHandle.Location));
return;
}
var assetBundleResource = bundleResource as AssetBundleResource;
if(assetBundleResource != null)
m_PreloadRequest = assetBundleResource.GetAssetPreloadRequest();
if (m_PreloadRequest == null || m_PreloadRequest.isDone)
BeginAssetLoad();
else
m_PreloadRequest.completed += operation => BeginAssetLoad();
}
}
private void BeginAssetLoad()
{
if (m_AssetBundle == null)
{
m_ProvideHandle.Complete<AssetBundle>(null, false, new Exception("Unable to load dependent bundle from location " + m_ProvideHandle.Location));
}
else
{
var assetPath = m_ProvideHandle.ResourceManager.TransformInternalId(m_ProvideHandle.Location);
if (m_ProvideHandle.Type.IsArray)
{
#if !UNITY_2021_1_OR_NEWER
if (AsyncOperationHandle.IsWaitingForCompletion)
{
GetArrayResult(m_AssetBundle.LoadAssetWithSubAssets(assetPath, m_ProvideHandle.Type.GetElementType()));
CompleteOperation();
}
else
#endif
m_RequestOperation = m_AssetBundle.LoadAssetWithSubAssetsAsync(assetPath, m_ProvideHandle.Type.GetElementType());
}
else if (m_ProvideHandle.Type.IsGenericType && typeof(IList<>) == m_ProvideHandle.Type.GetGenericTypeDefinition())
{
#if !UNITY_2021_1_OR_NEWER
if (AsyncOperationHandle.IsWaitingForCompletion)
{
GetListResult(m_AssetBundle.LoadAssetWithSubAssets(assetPath, m_ProvideHandle.Type.GetGenericArguments()[0]));
CompleteOperation();
}
else
#endif
m_RequestOperation = m_AssetBundle.LoadAssetWithSubAssetsAsync(assetPath, m_ProvideHandle.Type.GetGenericArguments()[0]);
}
else
{
if (ResourceManagerConfig.ExtractKeyAndSubKey(assetPath, out string mainPath, out string subKey))
{
subObjectName = subKey;
#if !UNITY_2021_1_OR_NEWER
if (AsyncOperationHandle.IsWaitingForCompletion)
{
GetAssetSubObjectResult(m_AssetBundle.LoadAssetWithSubAssets(mainPath, m_ProvideHandle.Type));
CompleteOperation();
}
else
#endif
m_RequestOperation = m_AssetBundle.LoadAssetWithSubAssetsAsync(mainPath, m_ProvideHandle.Type);
}
else
{
#if !UNITY_2021_1_OR_NEWER
if (AsyncOperationHandle.IsWaitingForCompletion)
{
GetAssetResult(m_AssetBundle.LoadAsset(assetPath, m_ProvideHandle.Type));
CompleteOperation();
}
else
#endif
m_RequestOperation = m_AssetBundle.LoadAssetAsync(assetPath, m_ProvideHandle.Type);
}
}
if (m_RequestOperation != null)
{
if (m_RequestOperation.isDone)
ActionComplete(m_RequestOperation);
else
m_RequestOperation.completed += ActionComplete;
}
}
}
private bool WaitForCompletionHandler()
{
if (m_PreloadRequest != null && !m_PreloadRequest.isDone)
return m_PreloadRequest.asset == null;
if (m_Result != null)
return true;
if (m_RequestOperation == null)
return false;
if (m_RequestOperation.isDone)
return true;
return m_RequestOperation.asset != null;
}
private void ActionComplete(AsyncOperation obj)
{
if (m_RequestOperation != null)
{
if (m_ProvideHandle.Type.IsArray)
GetArrayResult(m_RequestOperation.allAssets);
else if (m_ProvideHandle.Type.IsGenericType && typeof(IList<>) == m_ProvideHandle.Type.GetGenericTypeDefinition())
GetListResult(m_RequestOperation.allAssets);
else if (string.IsNullOrEmpty(subObjectName))
GetAssetResult(m_RequestOperation.asset);
else
GetAssetSubObjectResult(m_RequestOperation.allAssets);
}
CompleteOperation();
}
private void GetArrayResult(Object[] allAssets)
{
m_Result = ResourceManagerConfig.CreateArrayResult(m_ProvideHandle.Type, allAssets);
}
private void GetListResult(Object[] allAssets)
{
m_Result = ResourceManagerConfig.CreateListResult(m_ProvideHandle.Type, allAssets);
}
private void GetAssetResult(Object asset)
{
m_Result = (asset != null && m_ProvideHandle.Type.IsAssignableFrom(asset.GetType())) ? asset : null;
}
private void GetAssetSubObjectResult(Object[] allAssets)
{
foreach (var o in allAssets)
{
if (o.name == subObjectName)
{
if (m_ProvideHandle.Type.IsAssignableFrom(o.GetType()))
{
m_Result = o;
break;
}
}
}
}
void CompleteOperation()
{
Exception e = m_Result == null
? new Exception($"Unable to load asset of type {m_ProvideHandle.Type} from location {m_ProvideHandle.Location}.")
: null;
m_ProvideHandle.Complete(m_Result, m_Result != null, e);
}
public float ProgressCallback() { return m_RequestOperation != null ? m_RequestOperation.progress : 0.0f; }
}
/// <inheritdoc/>
public override void Provide(ProvideHandle provideHandle)
{
new InternalOp().Start(provideHandle);
}
}
}