using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine.Networking;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.Diagnostics;
using UnityEngine.ResourceManagement.Exceptions;
using UnityEngine.ResourceManagement.ResourceLocations;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.ResourceManagement.Util;
using UnityEngine.SceneManagement;
[assembly: InternalsVisibleTo("Unity.ResourceManager.Tests")]
[assembly: InternalsVisibleTo("Unity.Addressables.Tests")]
namespace UnityEngine.ResourceManagement
{
///
/// Entry point for ResourceManager API
///
public class ResourceManager : IDisposable
{
///
/// Event types that will be sent by the ResourceManager
///
public enum DiagnosticEventType
{
EventCount,
FrameRate,
HeapSize,
AsyncOperationFail,
AsyncOperationCreate,
AsyncOperationPercentComplete,
AsyncOperationComplete,
AsyncOperationReferenceCount,
AsyncOperationDestroy,
}
///
/// Global exception handler. This will be called whenever an IAsyncOperation.OperationException is set to a non-null value.
///
public static Action ExceptionHandler { get; set; }
internal bool CallbackHooksEnabled = true; // tests might need to disable the callback hooks to manually pump updating
private MonoBehaviourCallbackHooks m_CallbackHooks;
ListWithEvents m_ResourceProviders = new ListWithEvents();
IAllocationStrategy m_allocator;
// list of all the providers in s_ResourceProviders that implement IUpdateReceiver
ListWithEvents m_UpdateReceivers = new ListWithEvents();
List m_UpdateReceiversToRemove = null;
bool m_UpdatingReceivers = false;
internal int OperationCacheCount { get { return m_AssetOperationCache.Count; } }
internal int InstanceOperationCount { get { return m_TrackedInstanceOperations.Count; } }
//cache of type + providerId to IResourceProviders for faster lookup
Dictionary m_providerMap = new Dictionary();
Dictionary m_AssetOperationCache = new Dictionary();
HashSet m_TrackedInstanceOperations = new HashSet();
DelegateList m_UpdateCallbacks = DelegateList.CreateWithGlobalCache();
List m_DeferredCompleteCallbacks = new List();
Action m_diagnosticsHandler;
Action m_ReleaseOpNonCached;
Action m_ReleaseOpCached;
Action m_ReleaseInstanceOp;
static int s_GroupOperationTypeHash = typeof(GroupOperation).GetHashCode();
static int s_InstanceOperationTypeHash = typeof(InstanceOperation).GetHashCode();
///
/// Add an update reveiver.
///
/// The object to add. The Update method will be called until the object is removed.
public void AddUpdateReceiver(IUpdateReceiver receiver)
{
if (receiver == null)
return;
m_UpdateReceivers.Add(receiver);
}
///
/// Remove update receiver.
///
/// The object to remove.
public void RemoveUpdateReciever(IUpdateReceiver receiver)
{
if (receiver == null)
return;
if (m_UpdatingReceivers)
{
if (m_UpdateReceiversToRemove == null)
m_UpdateReceiversToRemove = new List();
m_UpdateReceiversToRemove.Add(receiver);
}
else
{
m_UpdateReceivers.Remove(receiver);
}
}
///
/// The allocation strategy object.
///
public IAllocationStrategy Allocator { get { return m_allocator; } set { m_allocator = value; } }
///
/// Gets the list of configured objects. Resource Providers handle load and release operations for objects.
///
/// The resource providers list.
public IList ResourceProviders { get { return m_ResourceProviders; } }
///
/// The CertificateHandler instance object.
///
public CertificateHandler CertificateHandlerInstance { get; set; }
///
/// Constructor for the resource manager.
///
/// The allocation strategy to use.
public ResourceManager(IAllocationStrategy alloc = null)
{
m_ReleaseOpNonCached = OnOperationDestroyNonCached;
m_ReleaseOpCached = OnOperationDestroyCached;
m_ReleaseInstanceOp = OnInstanceOperationDestroy;
m_allocator = alloc == null ? new LRUCacheAllocationStrategy(1000, 1000, 100, 10) : alloc;
m_ResourceProviders.OnElementAdded += OnObjectAdded;
m_ResourceProviders.OnElementRemoved += OnObjectRemoved;
m_UpdateReceivers.OnElementAdded += x => RegisterForCallbacks();
}
private void OnObjectAdded(object obj)
{
IUpdateReceiver updateReceiver = obj as IUpdateReceiver;
if (updateReceiver != null)
AddUpdateReceiver(updateReceiver);
}
private void OnObjectRemoved(object obj)
{
IUpdateReceiver updateReceiver = obj as IUpdateReceiver;
if (updateReceiver != null)
RemoveUpdateReciever(updateReceiver);
}
private void RegisterForCallbacks()
{
if (CallbackHooksEnabled && m_CallbackHooks == null)
{
m_CallbackHooks = new GameObject("ResourceManagerCallbacks", typeof(MonoBehaviourCallbackHooks)).GetComponent();
m_CallbackHooks.OnUpdateDelegate += Update;
}
}
///
/// Clears out the diagnostics callback handler.
///
public void ClearDiagnosticsCallback()
{
m_diagnosticsHandler = null;
}
///
/// Register a handler for diagnostic events.
///
/// The event handler function.
public void RegisterDiagnosticCallback(Action func)
{
m_diagnosticsHandler = func;
}
internal void PostDiagnosticEvent(AsyncOperationHandle op, ResourceManager.DiagnosticEventType type, int eventValue = 0, object context = null)
{
if (m_diagnosticsHandler == null)
return;
m_diagnosticsHandler(op, type, eventValue, context);
}
///
/// Gets the appropriate for the given and .
///
/// The resource provider. Or null if an appropriate provider cannot be found
/// The resource location.
/// The desired object type to be loaded from the provider.
public IResourceProvider GetResourceProvider(Type t, IResourceLocation location)
{
if (location != null)
{
IResourceProvider prov = null;
var hash = location.ProviderId.GetHashCode() * 31 + (t == null ? 0: t.GetHashCode());
if (!m_providerMap.TryGetValue(hash, out prov))
{
for (int i = 0; i < ResourceProviders.Count; i++)
{
var p = ResourceProviders[i];
if (p.ProviderId.Equals(location.ProviderId, StringComparison.Ordinal) && (t == null || p.CanProvide(t, location)))
{
m_providerMap.Add(hash, prov = p);
break;
}
}
}
return prov;
}
return null;
}
Type GetDefaultTypeForLocation(IResourceLocation loc)
{
var provider = GetResourceProvider(null, loc);
if (provider == null)
return typeof(object);
Type t = provider.GetDefaultType(loc);
return t != null ? t : typeof(object);
}
private int CalculateLocationsHash(IList locations, Type t=null)
{
if (locations == null || locations.Count == 0)
return 0;
int hash = 17;
foreach (var loc in locations)
{
Type t2 = t != null ? t : GetDefaultTypeForLocation(loc);
hash = hash * 31 + loc.Hash(t2);
}
return hash;
}
///
/// Load the at the specified .
///
/// An async operation.
/// Location to load.
/// Object type to load.
private AsyncOperationHandle ProvideResource(IResourceLocation location, Type desiredType = null)
{
if (location == null)
throw new ArgumentNullException("location");
IResourceProvider provider = null;
if (desiredType == null)
{
provider = GetResourceProvider(desiredType, location);
if (provider == null)
return CreateCompletedOperation