Firstborn/Library/PackageCache/com.unity.addressables@1.19.19/Runtime/AddressablesImpl.cs

1405 lines
59 KiB
C#
Raw Normal View History

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEngine.AddressableAssets.Initialization;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.AddressableAssets.ResourceProviders;
using UnityEngine.Networking;
using UnityEngine.ResourceManagement;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceLocations;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.ResourceManagement.Util;
using UnityEngine.SceneManagement;
namespace UnityEngine.AddressableAssets
{
internal class AddressablesImpl : IEqualityComparer<IResourceLocation>
{
ResourceManager m_ResourceManager;
IInstanceProvider m_InstanceProvider;
int m_CatalogRequestsTimeout;
internal const string kCacheDataFolder = "{UnityEngine.Application.persistentDataPath}/com.unity.addressables/";
public IInstanceProvider InstanceProvider
{
get
{
return m_InstanceProvider;
}
set
{
m_InstanceProvider = value;
var rec = m_InstanceProvider as IUpdateReceiver;
if (rec != null)
m_ResourceManager.AddUpdateReceiver(rec);
}
}
public ISceneProvider SceneProvider;
public ResourceManager ResourceManager
{
get
{
if (m_ResourceManager == null)
m_ResourceManager = new ResourceManager(new DefaultAllocationStrategy());
return m_ResourceManager;
}
}
public int CatalogRequestsTimeout
{
get
{
return m_CatalogRequestsTimeout;
}
set
{
m_CatalogRequestsTimeout = value;
}
}
public class ResourceLocatorInfo
{
public IResourceLocator Locator { get; private set; }
public string LocalHash { get; private set; }
public IResourceLocation CatalogLocation { get; private set; }
public bool ContentUpdateAvailable { get; internal set; }
public ResourceLocatorInfo(IResourceLocator loc, string localHash, IResourceLocation remoteCatalogLocation)
{
Locator = loc;
LocalHash = localHash;
CatalogLocation = remoteCatalogLocation;
}
public IResourceLocation HashLocation
{
get
{
return CatalogLocation.Dependencies[0];
}
}
public bool CanUpdateContent
{
get
{
return !string.IsNullOrEmpty(LocalHash) && CatalogLocation != null && CatalogLocation.HasDependencies && CatalogLocation.Dependencies.Count == 2;
}
}
internal void UpdateContent(IResourceLocator locator, string hash, IResourceLocation loc)
{
LocalHash = hash;
CatalogLocation = loc;
Locator = locator;
}
}
internal List<ResourceLocatorInfo> m_ResourceLocators = new List<ResourceLocatorInfo>();
AsyncOperationHandle<IResourceLocator> m_InitializationOperation;
AsyncOperationHandle<List<string>> m_ActiveCheckUpdateOperation;
internal AsyncOperationHandle<List<IResourceLocator>> m_ActiveUpdateOperation;
Action<AsyncOperationHandle> m_OnHandleCompleteAction;
Action<AsyncOperationHandle> m_OnSceneHandleCompleteAction;
Action<AsyncOperationHandle> m_OnHandleDestroyedAction;
Dictionary<object, AsyncOperationHandle> m_resultToHandle = new Dictionary<object, AsyncOperationHandle>();
internal HashSet<AsyncOperationHandle> m_SceneInstances = new HashSet<AsyncOperationHandle>();
AsyncOperationHandle<bool> m_ActiveCleanBundleCacheOperation;
internal int SceneOperationCount { get { return m_SceneInstances.Count; } }
internal int TrackedHandleCount { get { return m_resultToHandle.Count; } }
internal bool hasStartedInitialization = false;
public AddressablesImpl(IAllocationStrategy alloc)
{
m_ResourceManager = new ResourceManager(alloc);
SceneManager.sceneUnloaded += OnSceneUnloaded;
}
internal void ReleaseSceneManagerOperation()
{
SceneManager.sceneUnloaded -= OnSceneUnloaded;
}
public Func<IResourceLocation, string> InternalIdTransformFunc
{
get { return ResourceManager.InternalIdTransformFunc; }
set { ResourceManager.InternalIdTransformFunc = value; }
}
public Action<UnityWebRequest> WebRequestOverride
{
get { return ResourceManager.WebRequestOverride; }
set { ResourceManager.WebRequestOverride = value; }
}
public AsyncOperationHandle ChainOperation
{
get
{
if (!hasStartedInitialization)
return InitializeAsync();
if (m_InitializationOperation.IsValid() && !m_InitializationOperation.IsDone)
return m_InitializationOperation;
if (m_ActiveUpdateOperation.IsValid() && !m_ActiveUpdateOperation.IsDone)
return m_ActiveUpdateOperation;
Debug.LogWarning($"{nameof(ChainOperation)} property should not be accessed unless {nameof(ShouldChainRequest)} is true.");
return default;
}
}
internal bool ShouldChainRequest
{
get
{
if (!hasStartedInitialization)
return true;
if (m_InitializationOperation.IsValid() && !m_InitializationOperation.IsDone)
return true;
return m_ActiveUpdateOperation.IsValid() && !m_ActiveUpdateOperation.IsDone;
}
}
internal void OnSceneUnloaded(Scene scene)
{
foreach (var s in m_SceneInstances)
{
if (!s.IsValid())
{
m_SceneInstances.Remove(s);
break;
}
var sceneHandle = s.Convert<SceneInstance>();
if (sceneHandle.Result.Scene == scene)
{
m_SceneInstances.Remove(s);
m_resultToHandle.Remove(s.Result);
var op = SceneProvider.ReleaseScene(m_ResourceManager, sceneHandle);
AutoReleaseHandleOnCompletion(op);
break;
}
}
m_ResourceManager.CleanupSceneInstances(scene);
}
public string StreamingAssetsSubFolder
{
get
{
return "aa";
}
}
public string BuildPath
{
get { return Addressables.LibraryPath + StreamingAssetsSubFolder + "/" + PlatformMappingService.GetPlatformPathSubFolder(); }
}
public string PlayerBuildDataPath
{
get
{
return Application.streamingAssetsPath + "/" + StreamingAssetsSubFolder;
}
}
public string RuntimePath
{
get
{
#if UNITY_EDITOR
return BuildPath;
#else
return PlayerBuildDataPath;
#endif
}
}
public void Log(string msg)
{
Debug.Log(msg);
}
public void LogFormat(string format, params object[] args)
{
Debug.LogFormat(format, args);
}
public void LogWarning(string msg)
{
Debug.LogWarning(msg);
}
public void LogWarningFormat(string format, params object[] args)
{
Debug.LogWarningFormat(format, args);
}
public void LogError(string msg)
{
Debug.LogError(msg);
}
public void LogException(AsyncOperationHandle op, Exception ex)
{
if (op.Status == AsyncOperationStatus.Failed)
{
Debug.LogError(ex.ToString());
Addressables.Log($"Failed op : {op.DebugName}");
}
else
Addressables.Log(ex.ToString());
}
public void LogException(Exception ex)
{
Addressables.Log(ex.ToString());
}
public void LogErrorFormat(string format, params object[] args)
{
Debug.LogErrorFormat(format, args);
}
public string ResolveInternalId(string id)
{
var path = AddressablesRuntimeProperties.EvaluateString(id);
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN || UNITY_XBOXONE
if (path.Length >= 260 && path.StartsWith(Application.dataPath))
path = path.Substring(Application.dataPath.Length + 1);
#endif
return path;
}
public IEnumerable<IResourceLocator> ResourceLocators
{
get
{
return m_ResourceLocators.Select(l => l.Locator);
}
}
public void AddResourceLocator(IResourceLocator loc, string localCatalogHash = null, IResourceLocation remoteCatalogLocation = null)
{
m_ResourceLocators.Add(new ResourceLocatorInfo(loc, localCatalogHash, remoteCatalogLocation));
}
public void RemoveResourceLocator(IResourceLocator loc)
{
m_ResourceLocators.RemoveAll(l => l.Locator == loc);
}
public void ClearResourceLocators()
{
m_ResourceLocators.Clear();
}
internal bool GetResourceLocations(object key, Type type, out IList<IResourceLocation> locations)
{
if (type == null && (key is AssetReference))
type = (key as AssetReference).SubOjbectType;
key = EvaluateKey(key);
locations = null;
HashSet<IResourceLocation> current = null;
foreach (var locatorInfo in m_ResourceLocators)
{
var locator = locatorInfo.Locator;
IList<IResourceLocation> locs;
if (locator.Locate(key, type, out locs))
{
if (locations == null)
{
//simple, common case, no allocations
locations = locs;
}
else
{
//less common, need to merge...
if (current == null)
{
current = new HashSet<IResourceLocation>();
foreach (var loc in locations)
current.Add(loc);
}
current.UnionWith(locs);
}
}
}
if (current == null)
return locations != null;
locations = new List<IResourceLocation>(current);
return true;
}
internal bool GetResourceLocations(IEnumerable keys, Type type, Addressables.MergeMode merge, out IList<IResourceLocation> locations)
{
locations = null;
HashSet<IResourceLocation> current = null;
foreach (var key in keys)
{
IList<IResourceLocation> locs;
if (GetResourceLocations(key, type, out locs))
{
if (locations == null)
{
locations = locs;
if (merge == Addressables.MergeMode.UseFirst)
return true;
}
else
{
if (current == null)
{
current = new HashSet<IResourceLocation>(locations, this);
}
if (merge == Addressables.MergeMode.Intersection)
current.IntersectWith(locs);
else if (merge == Addressables.MergeMode.Union)
current.UnionWith(locs);
}
}
else
{
//if entries for a key are not found, the intersection is empty
if (merge == Addressables.MergeMode.Intersection)
{
locations = null;
return false;
}
}
}
if (current == null)
return locations != null;
if (current.Count == 0)
{
locations = null;
return false;
}
locations = new List<IResourceLocation>(current);
return true;
}
public AsyncOperationHandle<IResourceLocator> InitializeAsync(string runtimeDataPath, string providerSuffix = null, bool autoReleaseHandle = true)
{
if (hasStartedInitialization)
{
if (m_InitializationOperation.IsValid())
return m_InitializationOperation;
var completedOperation = ResourceManager.CreateCompletedOperation(m_ResourceLocators[0].Locator, errorMsg: null);
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(completedOperation);
return completedOperation;
}
if (ResourceManager.ExceptionHandler == null)
{
ResourceManager.ExceptionHandler = LogException;
}
hasStartedInitialization = true;
if (m_InitializationOperation.IsValid())
return m_InitializationOperation;
//these need to be referenced in order to prevent stripping on IL2CPP platforms.
if (string.IsNullOrEmpty(Application.streamingAssetsPath))
Addressables.LogWarning("Application.streamingAssetsPath has been stripped!");
#if !UNITY_SWITCH
if (string.IsNullOrEmpty(Application.persistentDataPath))
Addressables.LogWarning("Application.persistentDataPath has been stripped!");
#endif
if (string.IsNullOrEmpty(runtimeDataPath))
return ResourceManager.CreateCompletedOperation<IResourceLocator>(null, string.Format("Invalid Key: {0}", runtimeDataPath));
m_OnHandleCompleteAction = OnHandleCompleted;
m_OnSceneHandleCompleteAction = OnSceneHandleCompleted;
m_OnHandleDestroyedAction = OnHandleDestroyed;
#if UNITY_EDITOR
Object settingsObject = null;
string settingsPath = null;
//this indicates that a specific addressables settings asset is being used for the runtime locations
if (runtimeDataPath.StartsWith("GUID:"))
settingsPath = UnityEditor.AssetDatabase.GUIDToAssetPath(runtimeDataPath.Substring(runtimeDataPath.IndexOf(':') + 1));
var assembly = Assembly.Load("Unity.Addressables.Editor");
if (string.IsNullOrEmpty(settingsPath) && !UnityEditor.EditorApplication.isPlaying)
{
var rtp = runtimeDataPath.StartsWith("file://") ? runtimeDataPath.Substring("file://".Length) : runtimeDataPath;
if(!File.Exists(rtp))
{
var defaultSettingsObjectType = assembly.GetType("UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject");
var prop = defaultSettingsObjectType.GetProperty("DefaultAssetPath", BindingFlags.Public | BindingFlags.Static);
settingsPath = prop.GetValue(null) as string;
UnityEditor.EditorApplication.QueuePlayerLoopUpdate();
}
}
if (!string.IsNullOrEmpty(settingsPath))
{
var settingsType = assembly.GetType("UnityEditor.AddressableAssets.Settings.AddressableAssetSettings");
settingsObject = UnityEditor.AssetDatabase.LoadAssetAtPath(settingsPath, settingsType);
if (settingsObject != null)
{
var settingsSetupMethod = settingsType.GetMethod("CreatePlayModeInitializationOperation", BindingFlags.Instance | BindingFlags.NonPublic);
m_InitializationOperation = (AsyncOperationHandle<IResourceLocator>)settingsSetupMethod.Invoke(settingsObject, new object[] { this });
}
}
#endif
if(!m_InitializationOperation.IsValid())
m_InitializationOperation = Initialization.InitializationOperation.CreateInitializationOperation(this, runtimeDataPath, providerSuffix);
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(m_InitializationOperation);
return m_InitializationOperation;
}
public AsyncOperationHandle<IResourceLocator> InitializeAsync()
{
var settingsPath =
#if UNITY_EDITOR
PlayerPrefs.GetString(Addressables.kAddressablesRuntimeDataPath, RuntimePath + "/settings.json");
#else
RuntimePath + "/settings.json";
#endif
return InitializeAsync(ResolveInternalId(settingsPath));
}
public AsyncOperationHandle<IResourceLocator> InitializeAsync(bool autoReleaseHandle)
{
var settingsPath =
#if UNITY_EDITOR
PlayerPrefs.GetString(Addressables.kAddressablesRuntimeDataPath, RuntimePath + "/settings.json");
#else
RuntimePath + "/settings.json";
#endif
return InitializeAsync(ResolveInternalId(settingsPath), null, autoReleaseHandle);
}
internal ResourceLocationBase CreateCatalogLocationWithHashDependencies(string catalogPath, string hashFilePath)
{
var catalogLoc = new ResourceLocationBase(catalogPath, catalogPath, typeof(ContentCatalogProvider).FullName, typeof(IResourceLocator));
catalogLoc.Data = new ProviderLoadRequestOptions()
{
IgnoreFailures = false,
WebRequestTimeout = CatalogRequestsTimeout
};
if (!string.IsNullOrEmpty(hashFilePath))
{
ProviderLoadRequestOptions hashOptions = new ProviderLoadRequestOptions()
{
IgnoreFailures = true,
WebRequestTimeout = CatalogRequestsTimeout
};
string tmpPath = hashFilePath;
if (ResourceManagerConfig.IsPathRemote(hashFilePath))
{
tmpPath = ResourceManagerConfig.StripQueryParameters(hashFilePath);
}
// The file name of the local cached catalog + hash file is the hash code of the remote hash path, without query parameters (if any).
string cacheHashFilePath = ResolveInternalId(kCacheDataFolder + tmpPath.GetHashCode() + ".hash");
var hashResourceLocation = new ResourceLocationBase(hashFilePath, hashFilePath, typeof(TextDataProvider).FullName, typeof(string));
hashResourceLocation.Data = hashOptions.Copy();
catalogLoc.Dependencies.Add(hashResourceLocation);
var cacheResourceLocation = new ResourceLocationBase(cacheHashFilePath, cacheHashFilePath, typeof(TextDataProvider).FullName, typeof(string));
cacheResourceLocation.Data = hashOptions.Copy();
catalogLoc.Dependencies.Add(cacheResourceLocation);
}
return catalogLoc;
}
[Conditional("UNITY_EDITOR")]
void QueueEditorUpdateIfNeeded()
{
#if UNITY_EDITOR
if (!UnityEditor.EditorApplication.isPlaying)
UnityEditor.EditorApplication.QueuePlayerLoopUpdate();
#endif
}
public AsyncOperationHandle<IResourceLocator> LoadContentCatalogAsync(string catalogPath, bool autoReleaseHandle = true, string providerSuffix = null)
{
string catalogHashPath = catalogPath.Replace(".json", ".hash");
var catalogLoc = CreateCatalogLocationWithHashDependencies(catalogPath, catalogHashPath);
if (ShouldChainRequest)
return ResourceManager.CreateChainOperation(ChainOperation, op => LoadContentCatalogAsync(catalogPath, autoReleaseHandle, providerSuffix));
var handle = Initialization.InitializationOperation.LoadContentCatalog(this, catalogLoc, providerSuffix);
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(handle);
QueueEditorUpdateIfNeeded();
return handle;
}
AsyncOperationHandle<SceneInstance> TrackHandle(AsyncOperationHandle<SceneInstance> handle)
{
handle.Completed += (sceneHandle) =>
{
m_OnSceneHandleCompleteAction(sceneHandle);
};
return handle;
}
AsyncOperationHandle<TObject> TrackHandle<TObject>(AsyncOperationHandle<TObject> handle)
{
handle.CompletedTypeless += m_OnHandleCompleteAction;
return handle;
}
AsyncOperationHandle TrackHandle(AsyncOperationHandle handle)
{
handle.Completed += m_OnHandleCompleteAction;
return handle;
}
internal void ClearTrackHandles()
{
m_resultToHandle.Clear();
}
public AsyncOperationHandle<TObject> LoadAssetAsync<TObject>(IResourceLocation location)
{
QueueEditorUpdateIfNeeded();
return TrackHandle(ResourceManager.ProvideResource<TObject>(location));
}
AsyncOperationHandle<TObject> LoadAssetWithChain<TObject>(AsyncOperationHandle dep, object key)
{
return ResourceManager.CreateChainOperation(dep, op => LoadAssetAsync<TObject>(key));
}
public AsyncOperationHandle<TObject> LoadAssetAsync<TObject>(object key)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
return TrackHandle(LoadAssetWithChain<TObject>(ChainOperation, key));
key = EvaluateKey(key);
IList<IResourceLocation> locs;
var t = typeof(TObject);
if (t.IsArray)
t = t.GetElementType();
else if (t.IsGenericType && typeof(IList<>) == t.GetGenericTypeDefinition())
t = t.GetGenericArguments()[0];
foreach (var locatorInfo in m_ResourceLocators)
{
var locator = locatorInfo.Locator;
if (locator.Locate(key, t, out locs))
{
foreach (var loc in locs)
{
var provider = ResourceManager.GetResourceProvider(typeof(TObject), loc);
if (provider != null)
return TrackHandle(ResourceManager.ProvideResource<TObject>(loc));
}
}
}
return ResourceManager.CreateCompletedOperationWithException<TObject>(default(TObject), new InvalidKeyException(key, t, this));
}
class LoadResourceLocationKeyOp : AsyncOperationBase<IList<IResourceLocation>>
{
object m_Keys;
IList<IResourceLocation> m_locations;
AddressablesImpl m_Addressables;
Type m_ResourceType;
protected override string DebugName { get { return m_Keys.ToString(); } }
public void Init(AddressablesImpl aa, Type t, object keys)
{
m_Keys = keys;
m_ResourceType = t;
m_Addressables = aa;
}
/// <inheritdoc />
protected override bool InvokeWaitForCompletion()
{
m_RM?.Update(Time.unscaledDeltaTime);
if (!HasExecuted)
InvokeExecute();
return true;
}
protected override void Execute()
{
m_Addressables.GetResourceLocations(m_Keys, m_ResourceType, out m_locations);
if (m_locations == null)
m_locations = new List<IResourceLocation>();
Complete(m_locations, true, string.Empty);
}
}
class LoadResourceLocationKeysOp : AsyncOperationBase<IList<IResourceLocation>>
{
IEnumerable m_Key;
Addressables.MergeMode m_MergeMode;
IList<IResourceLocation> m_locations;
AddressablesImpl m_Addressables;
Type m_ResourceType;
protected override string DebugName { get { return "LoadResourceLocationKeysOp"; } }
public void Init(AddressablesImpl aa, Type t, IEnumerable key, Addressables.MergeMode mergeMode)
{
m_Key = key;
m_ResourceType = t;
m_MergeMode = mergeMode;
m_Addressables = aa;
}
protected override void Execute()
{
m_Addressables.GetResourceLocations(m_Key, m_ResourceType, m_MergeMode, out m_locations);
if (m_locations == null)
m_locations = new List<IResourceLocation>();
Complete(m_locations, true, string.Empty);
}
/// <inheritdoc />
protected override bool InvokeWaitForCompletion()
{
m_RM?.Update(Time.unscaledDeltaTime);
if (!HasExecuted)
InvokeExecute();
return true;
}
}
public AsyncOperationHandle<IList<IResourceLocation>> LoadResourceLocationsWithChain(AsyncOperationHandle dep, IEnumerable keys, Addressables.MergeMode mode, Type type)
{
return ResourceManager.CreateChainOperation(dep, op => LoadResourceLocationsAsync(keys, mode, type));
}
public AsyncOperationHandle<IList<IResourceLocation>> LoadResourceLocationsAsync(IEnumerable keys, Addressables.MergeMode mode, Type type = null)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
return TrackHandle(LoadResourceLocationsWithChain(ChainOperation, keys, mode, type));
var op = new LoadResourceLocationKeysOp();
op.Init(this, type, keys, mode);
return TrackHandle(ResourceManager.StartOperation(op, default));
}
public AsyncOperationHandle<IList<IResourceLocation>> LoadResourceLocationsWithChain(AsyncOperationHandle dep, object key, Type type)
{
return ResourceManager.CreateChainOperation(dep, op => LoadResourceLocationsAsync(key, type));
}
public AsyncOperationHandle<IList<IResourceLocation>> LoadResourceLocationsAsync(object key, Type type = null)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
return TrackHandle(LoadResourceLocationsWithChain(ChainOperation, key, type));
var op = new LoadResourceLocationKeyOp();
op.Init(this, type, key);
return TrackHandle(ResourceManager.StartOperation(op, default));
}
public AsyncOperationHandle<IList<TObject>> LoadAssetsAsync<TObject>(IList<IResourceLocation> locations, Action<TObject> callback, bool releaseDependenciesOnFailure)
{
QueueEditorUpdateIfNeeded();
return TrackHandle(ResourceManager.ProvideResources(locations, releaseDependenciesOnFailure, callback));
}
AsyncOperationHandle<IList<TObject>> LoadAssetsWithChain<TObject>(AsyncOperationHandle dep, IEnumerable keys, Action<TObject> callback, Addressables.MergeMode mode, bool releaseDependenciesOnFailure)
{
return ResourceManager.CreateChainOperation(dep, op => LoadAssetsAsync(keys, callback, mode, releaseDependenciesOnFailure));
}
public AsyncOperationHandle<IList<TObject>> LoadAssetsAsync<TObject>(IEnumerable keys, Action<TObject> callback, Addressables.MergeMode mode, bool releaseDependenciesOnFailure)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
return TrackHandle(LoadAssetsWithChain(ChainOperation, keys, callback, mode, releaseDependenciesOnFailure));
IList<IResourceLocation> locations;
if (!GetResourceLocations(keys, typeof(TObject), mode, out locations))
return ResourceManager.CreateCompletedOperationWithException<IList<TObject>>(null, new InvalidKeyException(keys, typeof(TObject), mode, this));
return LoadAssetsAsync(locations, callback, releaseDependenciesOnFailure);
}
AsyncOperationHandle<IList<TObject>> LoadAssetsWithChain<TObject>(AsyncOperationHandle dep, object key, Action<TObject> callback, bool releaseDependenciesOnFailure)
{
return ResourceManager.CreateChainOperation(dep, op2 => LoadAssetsAsync(key, callback, releaseDependenciesOnFailure));
}
public AsyncOperationHandle<IList<TObject>> LoadAssetsAsync<TObject>(object key, Action<TObject> callback, bool releaseDependenciesOnFailure)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
return TrackHandle(LoadAssetsWithChain(ChainOperation, key, callback, releaseDependenciesOnFailure));
IList<IResourceLocation> locations;
if (!GetResourceLocations(key, typeof(TObject), out locations))
return ResourceManager.CreateCompletedOperationWithException<IList<TObject>>(null, new InvalidKeyException(key, typeof(TObject), this));
return LoadAssetsAsync(locations, callback, releaseDependenciesOnFailure);
}
void OnHandleDestroyed(AsyncOperationHandle handle)
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
m_resultToHandle.Remove(handle.Result);
}
}
void OnSceneHandleCompleted(AsyncOperationHandle handle)
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
m_SceneInstances.Add(handle);
if (!m_resultToHandle.ContainsKey(handle.Result))
{
handle.Destroyed += m_OnHandleDestroyedAction;
m_resultToHandle.Add(handle.Result, handle);
}
}
}
void OnHandleCompleted(AsyncOperationHandle handle)
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
if (!m_resultToHandle.ContainsKey(handle.Result))
{
handle.Destroyed += m_OnHandleDestroyedAction;
m_resultToHandle.Add(handle.Result, handle);
}
}
}
public void Release<TObject>(TObject obj)
{
if (obj == null)
{
LogWarning("Addressables.Release() - trying to release null object.");
return;
}
AsyncOperationHandle handle;
if (m_resultToHandle.TryGetValue(obj, out handle))
Release(handle);
else
{
LogError("Addressables.Release was called on an object that Addressables was not previously aware of. Thus nothing is being released");
}
}
public void Release<TObject>(AsyncOperationHandle<TObject> handle)
{
if (typeof(TObject) == typeof(SceneInstance))
{
SceneInstance sceneInstance = (SceneInstance)Convert.ChangeType(handle.Result, typeof(SceneInstance));
if (sceneInstance.Scene.isLoaded && handle.ReferenceCount == 1)
{
if (SceneOperationCount == 1 && m_SceneInstances.First().Equals(handle))
m_SceneInstances.Clear();
UnloadSceneAsync(handle, UnloadSceneOptions.None, true);
}
else if (!sceneInstance.Scene.isLoaded && handle.ReferenceCount == 2 && !handle.UnloadSceneOpExcludeReleaseCallback)
{
AutoReleaseHandleOnCompletion(handle);
}
}
m_ResourceManager.Release(handle);
}
public void Release(AsyncOperationHandle handle)
{
m_ResourceManager.Release(handle);
}
AsyncOperationHandle<long> GetDownloadSizeWithChain(AsyncOperationHandle dep, object key)
{
return ResourceManager.CreateChainOperation(dep, op => GetDownloadSizeAsync(key));
}
AsyncOperationHandle<long> GetDownloadSizeWithChain(AsyncOperationHandle dep, IEnumerable keys)
{
return ResourceManager.CreateChainOperation(dep, op => GetDownloadSizeAsync(keys));
}
public AsyncOperationHandle<long> GetDownloadSizeAsync(object key)
{
QueueEditorUpdateIfNeeded();
return GetDownloadSizeAsync(new object[] { key });
}
public AsyncOperationHandle<long> GetDownloadSizeAsync(IEnumerable keys)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
return TrackHandle(GetDownloadSizeWithChain(ChainOperation, keys));
List<IResourceLocation> allLocations = new List<IResourceLocation>();
foreach (object key in keys)
{
IList<IResourceLocation> locations;
if (key is IList<IResourceLocation>)
locations = key as IList<IResourceLocation>;
else if (key is IResourceLocation)
{
locations = new List<IResourceLocation>(1)
{
key as IResourceLocation
};
}
else if (!GetResourceLocations(key, typeof(object), out locations))
return ResourceManager.CreateCompletedOperationWithException<long>(0, new InvalidKeyException(key, typeof(object), this));
foreach (var loc in locations)
{
if (loc.HasDependencies)
allLocations.AddRange(loc.Dependencies);
}
}
long size = 0;
foreach (IResourceLocation location in allLocations.Distinct())
{
var sizeData = location.Data as ILocationSizeData;
if (sizeData != null)
size += sizeData.ComputeSize(location, ResourceManager);
}
return ResourceManager.CreateCompletedOperation<long>(size, string.Empty);
}
AsyncOperationHandle DownloadDependenciesAsyncWithChain(AsyncOperationHandle dep, object key, bool autoReleaseHandle)
{
var handle = ResourceManager.CreateChainOperation(dep, op => DownloadDependenciesAsync(key).Convert<IList<IAssetBundleResource>>());
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(handle);
return handle;
}
internal static void WrapAsDownloadLocations(List<IResourceLocation> locations)
{
for (int i = 0; i < locations.Count; i++)
locations[i] = new DownloadOnlyLocation(locations[i]);
}
static List<IResourceLocation> GatherDependenciesFromLocations(IList<IResourceLocation> locations)
{
var locHash = new HashSet<IResourceLocation>();
foreach (var loc in locations)
{
if (loc.ResourceType == typeof(IAssetBundleResource))
{
locHash.Add(loc);
}
if (loc.HasDependencies)
{
foreach (var dep in loc.Dependencies)
if (dep.ResourceType == typeof(IAssetBundleResource))
locHash.Add(dep);
}
}
return new List<IResourceLocation>(locHash);
}
public AsyncOperationHandle DownloadDependenciesAsync(object key, bool autoReleaseHandle = false)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
return DownloadDependenciesAsyncWithChain(ChainOperation, key, autoReleaseHandle);
IList<IResourceLocation> locations;
if (!GetResourceLocations(key, typeof(object), out locations))
{
var handle = ResourceManager.CreateCompletedOperationWithException<IList<IAssetBundleResource>>(null, new InvalidKeyException(key, typeof(object), this));
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(handle);
return handle;
}
else
{
List<IResourceLocation> dlLocations = GatherDependenciesFromLocations(locations);
WrapAsDownloadLocations(dlLocations);
var handle = LoadAssetsAsync<IAssetBundleResource>(dlLocations, null, true);
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(handle);
return handle;
}
}
AsyncOperationHandle DownloadDependenciesAsyncWithChain(AsyncOperationHandle dep, IList<IResourceLocation> locations, bool autoReleaseHandle)
{
var handle = ResourceManager.CreateChainOperation(dep, op => DownloadDependenciesAsync(locations).Convert<IList<IAssetBundleResource>>());
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(handle);
return handle;
}
public AsyncOperationHandle DownloadDependenciesAsync(IList<IResourceLocation> locations, bool autoReleaseHandle = false)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
return DownloadDependenciesAsyncWithChain(ChainOperation, locations, autoReleaseHandle);
List<IResourceLocation> dlLocations = GatherDependenciesFromLocations(locations);
WrapAsDownloadLocations(dlLocations);
var handle = LoadAssetsAsync<IAssetBundleResource>(dlLocations, null, true);
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(handle);
return handle;
}
AsyncOperationHandle DownloadDependenciesAsyncWithChain(AsyncOperationHandle dep, IEnumerable keys, Addressables.MergeMode mode, bool autoReleaseHandle)
{
var handle = ResourceManager.CreateChainOperation(dep, op => DownloadDependenciesAsync(keys, mode).Convert<IList<IAssetBundleResource>>());
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(handle);
return handle;
}
public AsyncOperationHandle DownloadDependenciesAsync(IEnumerable keys, Addressables.MergeMode mode, bool autoReleaseHandle = false)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
return DownloadDependenciesAsyncWithChain(ChainOperation, keys, mode, autoReleaseHandle);
IList<IResourceLocation> locations;
if (!GetResourceLocations(keys, typeof(object), mode, out locations))
{
var handle = ResourceManager.CreateCompletedOperationWithException<IList<IAssetBundleResource>>(null, new InvalidKeyException(keys, typeof(object), mode, this));
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(handle);
return handle;
}
else
{
List<IResourceLocation> dlLocations = GatherDependenciesFromLocations(locations);
WrapAsDownloadLocations(dlLocations);
var handle = LoadAssetsAsync<IAssetBundleResource>(dlLocations, null, true);
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(handle);
return handle;
}
}
internal bool ClearDependencyCacheForKey(object key)
{
bool result = true;
#if ENABLE_CACHING
IList<IResourceLocation> locations;
if (key is IResourceLocation && (key as IResourceLocation).HasDependencies)
{
foreach (var dep in GatherDependenciesFromLocations((key as IResourceLocation).Dependencies))
{
//This should never be false when we get here, if it is there's likely a deeper problem.
if (dep.Data is AssetBundleRequestOptions)
result = result && Caching.ClearAllCachedVersions((dep.Data as AssetBundleRequestOptions).BundleName);
}
}
else if (GetResourceLocations(key, typeof(object), out locations))
{
foreach (var dep in GatherDependenciesFromLocations(locations))
{
//This should never be false when we get here, if it is there's likely a deeper problem.
if (dep.Data is AssetBundleRequestOptions)
result = result && Caching.ClearAllCachedVersions((dep.Data as AssetBundleRequestOptions).BundleName);
}
}
#endif
return result;
}
internal void AutoReleaseHandleOnCompletion(AsyncOperationHandle handle)
{
handle.Completed += op => Release(op);
}
internal void AutoReleaseHandleOnCompletion<TObject>(AsyncOperationHandle<TObject> handle)
{
handle.Completed += op => Release(op);
}
internal void AutoReleaseHandleOnCompletion<TObject>(AsyncOperationHandle<TObject> handle, bool unloadSceneOpExcludeReleaseCallback)
{
handle.Completed += op =>
{
if (unloadSceneOpExcludeReleaseCallback)
op.UnloadSceneOpExcludeReleaseCallback = true;
Release(op);
};
}
internal void AutoReleaseHandleOnTypelessCompletion<TObject>(AsyncOperationHandle<TObject> handle)
{
handle.CompletedTypeless += op => Release(op);
}
public AsyncOperationHandle<bool> ClearDependencyCacheAsync(object key, bool autoReleaseHandle)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
{
var chainOp = ResourceManager.CreateChainOperation(ChainOperation,
op => ClearDependencyCacheAsync(key, autoReleaseHandle));
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(chainOp);
return chainOp;
}
bool result = ClearDependencyCacheForKey(key);
var completedOp = ResourceManager.CreateCompletedOperation(result, result ? String.Empty : "Unable to clear the cache. AssetBundle's may still be loaded for the given key.");
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(completedOp);
return completedOp;
}
public AsyncOperationHandle<bool> ClearDependencyCacheAsync(IList<IResourceLocation> locations, bool autoReleaseHandle)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
{
var chainOp = ResourceManager.CreateChainOperation(ChainOperation,
op => ClearDependencyCacheAsync(locations, autoReleaseHandle));
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(chainOp);
return chainOp;
}
bool result = true;
foreach (var location in locations)
result = result && ClearDependencyCacheForKey(location);
var completedOp = ResourceManager.CreateCompletedOperation(result, result ? String.Empty : "Unable to clear the cache. AssetBundle's may still be loaded for the given key(s).");
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(completedOp);
return completedOp;
}
public AsyncOperationHandle<bool> ClearDependencyCacheAsync(IEnumerable keys, bool autoReleaseHandle)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
{
var chainOp = ResourceManager.CreateChainOperation(ChainOperation,
op => ClearDependencyCacheAsync(keys, autoReleaseHandle));
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(chainOp);
return chainOp;
}
bool result = true;
foreach (var key in keys)
result = result && ClearDependencyCacheForKey(key);
var completedOp = ResourceManager.CreateCompletedOperation(result, result ? String.Empty : "Unable to clear the cache. AssetBundle's may still be loaded for the given key(s).");
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(completedOp);
return completedOp;
}
public AsyncOperationHandle<GameObject> InstantiateAsync(IResourceLocation location, Transform parent = null, bool instantiateInWorldSpace = false, bool trackHandle = true)
{
return InstantiateAsync(location, new InstantiationParameters(parent, instantiateInWorldSpace), trackHandle);
}
public AsyncOperationHandle<GameObject> InstantiateAsync(IResourceLocation location, Vector3 position, Quaternion rotation, Transform parent = null, bool trackHandle = true)
{
return InstantiateAsync(location, new InstantiationParameters(position, rotation, parent), trackHandle);
}
public AsyncOperationHandle<GameObject> InstantiateAsync(object key, Transform parent = null, bool instantiateInWorldSpace = false, bool trackHandle = true)
{
return InstantiateAsync(key, new InstantiationParameters(parent, instantiateInWorldSpace), trackHandle);
}
public AsyncOperationHandle<GameObject> InstantiateAsync(object key, Vector3 position, Quaternion rotation, Transform parent = null, bool trackHandle = true)
{
return InstantiateAsync(key, new InstantiationParameters(position, rotation, parent), trackHandle);
}
AsyncOperationHandle<GameObject> InstantiateWithChain(AsyncOperationHandle dep, object key, InstantiationParameters instantiateParameters, bool trackHandle = true)
{
var chainOp = ResourceManager.CreateChainOperation(dep, op => InstantiateAsync(key, instantiateParameters, false));
if (trackHandle)
chainOp.CompletedTypeless += m_OnHandleCompleteAction;
return chainOp;
}
public AsyncOperationHandle<GameObject> InstantiateAsync(object key, InstantiationParameters instantiateParameters, bool trackHandle = true)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
return InstantiateWithChain(ChainOperation, key, instantiateParameters, trackHandle);
key = EvaluateKey(key);
IList<IResourceLocation> locs;
foreach (var locatorInfo in m_ResourceLocators)
{
var locator = locatorInfo.Locator;
if (locator.Locate(key, typeof(GameObject), out locs))
return InstantiateAsync(locs[0], instantiateParameters, trackHandle);
}
return ResourceManager.CreateCompletedOperationWithException<GameObject>(null, new InvalidKeyException(key, typeof(GameObject), this));
}
AsyncOperationHandle<GameObject> InstantiateWithChain(AsyncOperationHandle dep, IResourceLocation location, InstantiationParameters instantiateParameters, bool trackHandle = true)
{
var chainOp = ResourceManager.CreateChainOperation(dep, op => InstantiateAsync(location, instantiateParameters, false));
if (trackHandle)
chainOp.CompletedTypeless += m_OnHandleCompleteAction;
return chainOp;
}
public AsyncOperationHandle<GameObject> InstantiateAsync(IResourceLocation location, InstantiationParameters instantiateParameters, bool trackHandle = true)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
return InstantiateWithChain(ChainOperation, location, instantiateParameters, trackHandle);
var opHandle = ResourceManager.ProvideInstance(InstanceProvider, location, instantiateParameters);
if (!trackHandle)
return opHandle;
opHandle.CompletedTypeless += m_OnHandleCompleteAction;
return opHandle;
}
public bool ReleaseInstance(GameObject instance)
{
if (instance == null)
{
LogWarning("Addressables.ReleaseInstance() - trying to release null object.");
return false;
}
AsyncOperationHandle handle;
if (m_resultToHandle.TryGetValue(instance, out handle))
Release(handle);
else
return false;
return true;
}
internal AsyncOperationHandle<SceneInstance> LoadSceneWithChain(AsyncOperationHandle dep, object key, LoadSceneMode loadMode = LoadSceneMode.Single, bool activateOnLoad = true, int priority = 100)
{
return TrackHandle(ResourceManager.CreateChainOperation(dep, op => LoadSceneAsync(key, loadMode, activateOnLoad, priority, false)));
}
public AsyncOperationHandle<SceneInstance> LoadSceneAsync(object key, LoadSceneMode loadMode = LoadSceneMode.Single, bool activateOnLoad = true, int priority = 100, bool trackHandle = true)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
return LoadSceneWithChain(ChainOperation, key, loadMode, activateOnLoad, priority);
IList<IResourceLocation> locations;
if (!GetResourceLocations(key, typeof(SceneInstance), out locations))
return ResourceManager.CreateCompletedOperationWithException<SceneInstance>(default(SceneInstance), new InvalidKeyException(key, typeof(SceneInstance), this));
return LoadSceneAsync(locations[0], loadMode, activateOnLoad, priority, trackHandle);
}
public AsyncOperationHandle<SceneInstance> LoadSceneAsync(IResourceLocation location, LoadSceneMode loadMode = LoadSceneMode.Single, bool activateOnLoad = true, int priority = 100, bool trackHandle = true)
{
var handle = ResourceManager.ProvideScene(SceneProvider, location, loadMode, activateOnLoad, priority);
if (trackHandle)
return TrackHandle(handle);
return handle;
}
public AsyncOperationHandle<SceneInstance> UnloadSceneAsync(SceneInstance scene, UnloadSceneOptions unloadOptions = UnloadSceneOptions.None, bool autoReleaseHandle = true)
{
AsyncOperationHandle handle;
if (!m_resultToHandle.TryGetValue(scene, out handle))
{
var msg = string.Format("Addressables.UnloadSceneAsync() - Cannot find handle for scene {0}", scene);
LogWarning(msg);
return ResourceManager.CreateCompletedOperation<SceneInstance>(scene, msg);
}
if (handle.m_InternalOp.IsRunning)
return CreateUnloadSceneWithChain(handle, unloadOptions, autoReleaseHandle);
return UnloadSceneAsync(handle, unloadOptions, autoReleaseHandle);
}
public AsyncOperationHandle<SceneInstance> UnloadSceneAsync(AsyncOperationHandle handle, UnloadSceneOptions unloadOptions = UnloadSceneOptions.None, bool autoReleaseHandle = true)
{
QueueEditorUpdateIfNeeded();
if (handle.m_InternalOp.IsRunning)
return CreateUnloadSceneWithChain(handle, unloadOptions, autoReleaseHandle);
return UnloadSceneAsync(handle.Convert<SceneInstance>(), unloadOptions, autoReleaseHandle);
}
public AsyncOperationHandle<SceneInstance> UnloadSceneAsync(AsyncOperationHandle<SceneInstance> handle, UnloadSceneOptions unloadOptions = UnloadSceneOptions.None, bool autoReleaseHandle = true)
{
if (handle.m_InternalOp.IsRunning)
return CreateUnloadSceneWithChain(handle, unloadOptions, autoReleaseHandle);
return InternalUnloadScene(handle, unloadOptions, autoReleaseHandle);
}
internal AsyncOperationHandle<SceneInstance> CreateUnloadSceneWithChain(AsyncOperationHandle handle, UnloadSceneOptions unloadOptions, bool autoReleaseHandle)
{
return m_ResourceManager.CreateChainOperation(handle, (completedHandle) => InternalUnloadScene(completedHandle.Convert<SceneInstance>(), unloadOptions, autoReleaseHandle));
}
internal AsyncOperationHandle<SceneInstance> CreateUnloadSceneWithChain(AsyncOperationHandle<SceneInstance> handle, UnloadSceneOptions unloadOptions, bool autoReleaseHandle)
{
return m_ResourceManager.CreateChainOperation(handle, (completedHandle) => InternalUnloadScene(completedHandle, unloadOptions, autoReleaseHandle));
}
internal AsyncOperationHandle<SceneInstance> InternalUnloadScene(AsyncOperationHandle<SceneInstance> handle, UnloadSceneOptions unloadOptions, bool autoReleaseHandle)
{
QueueEditorUpdateIfNeeded();
var relOp = SceneProvider.ReleaseScene(ResourceManager, handle, unloadOptions);
if (autoReleaseHandle)
AutoReleaseHandleOnCompletion(relOp, true);
return relOp;
}
private object EvaluateKey(object obj)
{
if (obj is IKeyEvaluator)
return (obj as IKeyEvaluator).RuntimeKey;
return obj;
}
internal AsyncOperationHandle<List<string>> CheckForCatalogUpdates(bool autoReleaseHandle = true)
{
if (ShouldChainRequest)
return CheckForCatalogUpdatesWithChain(autoReleaseHandle);
if (m_ActiveCheckUpdateOperation.IsValid())
Release(m_ActiveCheckUpdateOperation);
m_ActiveCheckUpdateOperation = new CheckCatalogsOperation(this).Start(m_ResourceLocators);
if (autoReleaseHandle)
AutoReleaseHandleOnTypelessCompletion(m_ActiveCheckUpdateOperation);
return m_ActiveCheckUpdateOperation;
}
internal AsyncOperationHandle<List<string>> CheckForCatalogUpdatesWithChain(bool autoReleaseHandle)
{
return ResourceManager.CreateChainOperation(ChainOperation, op => CheckForCatalogUpdates(autoReleaseHandle));
}
internal ResourceLocatorInfo GetLocatorInfo(string c)
{
foreach (var l in m_ResourceLocators)
if (l.Locator.LocatorId == c)
return l;
return null;
}
internal IEnumerable<string> CatalogsWithAvailableUpdates => m_ResourceLocators.Where(s => s.ContentUpdateAvailable).Select(s => s.Locator.LocatorId);
internal AsyncOperationHandle<List<IResourceLocator>> UpdateCatalogs(IEnumerable<string> catalogIds = null, bool autoReleaseHandle = true, bool autoCleanBundleCache = false)
{
if (m_ActiveUpdateOperation.IsValid())
return m_ActiveUpdateOperation;
if (catalogIds == null && !CatalogsWithAvailableUpdates.Any())
return m_ResourceManager.CreateChainOperation(CheckForCatalogUpdates(), depOp => UpdateCatalogs(CatalogsWithAvailableUpdates, autoReleaseHandle, autoCleanBundleCache));
var op = new UpdateCatalogsOperation(this).Start(catalogIds == null ? CatalogsWithAvailableUpdates : catalogIds, autoCleanBundleCache);
if (autoReleaseHandle)
AutoReleaseHandleOnTypelessCompletion(op);
return op;
}
//needed for IEqualityComparer<IResourceLocation> interface
public bool Equals(IResourceLocation x, IResourceLocation y)
{
return x.PrimaryKey.Equals(y.PrimaryKey) && x.ResourceType.Equals(y.ResourceType) && x.InternalId.Equals(y.InternalId);
}
//needed for IEqualityComparer<IResourceLocation> interface
public int GetHashCode(IResourceLocation loc)
{
return loc.PrimaryKey.GetHashCode() * 31 + loc.ResourceType.GetHashCode();
}
internal AsyncOperationHandle<bool> CleanBundleCache(IEnumerable<string> catalogIds, bool forceSingleThreading)
{
if (ShouldChainRequest)
return CleanBundleCacheWithChain(catalogIds, forceSingleThreading);
#if !ENABLE_CACHING
return ResourceManager.CreateCompletedOperation(false, "Caching not enabled. There is no bundle cache to modify.");
#else
if (catalogIds == null)
catalogIds = m_ResourceLocators.Select(s => s.Locator.LocatorId);
var locations = new List<IResourceLocation>();
foreach (var c in catalogIds)
{
if (c == null)
continue;
var loc = GetLocatorInfo(c);
if (loc == null || loc.CatalogLocation == null)
continue;
locations.Add(loc.CatalogLocation);
}
if (locations.Count == 0)
return ResourceManager.CreateCompletedOperation(false, "Provided catalogs do not load data from a catalog file. This can occur when using the \"Use Asset Database (fastest)\" playmode script. Bundle cache was not modified.");
return CleanBundleCache(ResourceManager.CreateGroupOperation<object>(locations), forceSingleThreading);
#endif
}
internal AsyncOperationHandle<bool> CleanBundleCache(AsyncOperationHandle<IList<AsyncOperationHandle>> depOp, bool forceSingleThreading)
{
if (ShouldChainRequest)
return CleanBundleCacheWithChain(depOp, forceSingleThreading);
#if !ENABLE_CACHING
return ResourceManager.CreateCompletedOperation(false, "Caching not enabled. There is no bundle cache to modify.");
#else
if (m_ActiveCleanBundleCacheOperation.IsValid() && !m_ActiveCleanBundleCacheOperation.IsDone)
return ResourceManager.CreateCompletedOperation(false, "Bundle cache is already being cleaned.");
m_ActiveCleanBundleCacheOperation = new CleanBundleCacheOperation(this, forceSingleThreading).Start(depOp);
return m_ActiveCleanBundleCacheOperation;
#endif
}
internal AsyncOperationHandle<bool> CleanBundleCacheWithChain(AsyncOperationHandle<IList<AsyncOperationHandle>> depOp, bool forceSingleThreading)
{
return ResourceManager.CreateChainOperation(ChainOperation, op => CleanBundleCache(depOp, forceSingleThreading));
}
internal AsyncOperationHandle<bool> CleanBundleCacheWithChain(IEnumerable<string> catalogIds, bool forceSingleThreading)
{
return ResourceManager.CreateChainOperation(ChainOperation, op => CleanBundleCache(catalogIds, forceSingleThreading));
}
}
}