-
-
Save JBurkeKF/7d8d06ad0b4dafa15ec3fedc34df376e to your computer and use it in GitHub Desktop.
Utility method to refresh/reload Unity's Addressable content catalog after the initial load. (Written against Unity Addressables 1.19.19)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.AddressableAssets; | |
using UnityEngine.AddressableAssets.Initialization; | |
using UnityEngine.AddressableAssets.ResourceLocators; | |
using UnityEngine.ResourceManagement.AsyncOperations; | |
using UnityEngine.ResourceManagement.ResourceLocations; | |
using UnityEngine.ResourceManagement.ResourceProviders; | |
#if !UNITY_STANDALONE && !UNITY_ANDROID && !UNITY_IOS && !UNITY_TVOS | |
using System.Reflection; | |
#endif | |
// Written against Unity Addressables 1.19.19 | |
public class AddressableCatalogRefresh : MonoBehaviour | |
{ | |
public IEnumerator RefreshCatalog() | |
{ | |
// Always try initializing, just in case this is being called during initialization. It's okay to initialize multiple times, because the internal system can tolerate it | |
yield return Addressables.InitializeAsync(); | |
// Force the Addressables system to reload and refresh its catalog and pick up any newly registered DLC mount paths | |
AddressablesRuntimeProperties.ClearCachedPropertyValues(); | |
Addressables.ClearResourceLocators(); | |
#if UNITY_EDITOR | |
string settingsPath = PlayerPrefs.GetString( Addressables.kAddressablesRuntimeDataPath, Addressables.LibraryPath + "aa/" + PlatformMappingService.GetPlatformPathSubFolder() + "/settings.json" ); | |
#else | |
string settingsPath = Application.streamingAssetsPath + "/aa/settings.json"; | |
#endif | |
#if UNITY_EDITOR | |
if ( !settingsPath.StartsWith( "GUID:" ) ) // Skip reloading the catalog if we're in the editor and not using a packed mode simulation script | |
#endif | |
{ | |
AsyncOperationHandle<ResourceManagerRuntimeData> settingsDataOperation = Addressables.LoadAssetAsync<ResourceManagerRuntimeData>( | |
new ResourceLocationBase( | |
"RuntimeData", | |
Addressables.ResolveInternalId( settingsPath ), | |
typeof( JsonAssetProvider ).FullName, | |
typeof( ResourceManagerRuntimeData ) ) ); | |
yield return settingsDataOperation; | |
ResourceLocationMap catalogLocationMap = new ResourceLocationMap( "CatalogLocator", settingsDataOperation.Result.CatalogLocations ); | |
Addressables.AddResourceLocator( catalogLocationMap ); | |
AsyncOperationHandle<IList<IResourceLocation>> catalogPathsOperation = Addressables.LoadResourceLocationsAsync( | |
ResourceManagerRuntimeData.kCatalogAddress, | |
typeof( ContentCatalogData ) ); | |
yield return catalogPathsOperation; | |
IList<IResourceLocation> catalogPaths = catalogPathsOperation.Result; | |
if ( catalogPaths != null && catalogPaths.Count > 0 ) | |
{ | |
#if UNITY_STANDALONE || UNITY_ANDROID || UNITY_IOS || UNITY_TVOS | |
yield return Addressables.LoadContentCatalogAsync( catalogPaths[0].InternalId ); | |
#else | |
yield return LoadContentCatalogPlatformAsync( catalogPaths[0] ); | |
#endif | |
} | |
Addressables.RemoveResourceLocator( catalogLocationMap ); | |
} | |
} | |
#if !UNITY_STANDALONE && !UNITY_ANDROID && !UNITY_IOS && !UNITY_TVOS | |
/// <summary> | |
/// The Addressables system <see cref="Addressables.LoadContentCatalogAsync(string, string)" /> checks for cached versions | |
/// of the content catalog, which require access to <see cref="Application.persistentDataPath" />, something not allowed on | |
/// certain platforms. Unfortunately, we have to use reflection to dig into the underlying methods and bypass the check for | |
/// cached data. | |
/// </summary> | |
private AsyncOperationHandle<IResourceLocator> LoadContentCatalogPlatformAsync( IResourceLocation catalogLocation ) | |
{ | |
System.Type addressablesType = typeof( Addressables ); | |
System.Type addressablesImplType = System.Type.GetType( "UnityEngine.AddressableAssets.AddressablesImpl, Unity.Addressables, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" ); | |
if ( addressablesImplType == null ) | |
{ | |
Debug.LogError( "AddressableCatalogRefresh.LoadContentCatalogPlatformAsync: could not get AddressablesImpl type!" ); | |
return Addressables.ResourceManager.CreateCompletedOperation( default( IResourceLocator ), "Could not get AddressablesImpl type!" ); | |
} | |
System.Type addressablesInitializationOperationType = System.Type.GetType( "UnityEngine.AddressableAssets.Initialization.InitializationOperation, Unity.Addressables, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" ); | |
if ( addressablesInitializationOperationType == null ) | |
{ | |
Debug.LogError( "AddressableCatalogRefresh.LoadContentCatalogPlatformAsync: could not get InitializationOperation type!" ); | |
return Addressables.ResourceManager.CreateCompletedOperation( default( IResourceLocator ), "Could not get InitializationOperation type!" ); | |
} | |
// Get the Addressables instance | |
PropertyInfo addressablesImplInstancePropertyInfo = addressablesType.GetProperty( "Instance", BindingFlags.NonPublic | BindingFlags.Static ); | |
if ( addressablesImplInstancePropertyInfo == null ) | |
{ | |
Debug.LogError( "AddressableCatalogRefresh.LoadContentCatalogPlatformAsync: could not get AddressablesImpl Instance property type!" ); | |
return Addressables.ResourceManager.CreateCompletedOperation( default( IResourceLocator ), "Could not get AddressablesImpl Instance property type!" ); | |
} | |
object addressablesImplInstance = addressablesImplInstancePropertyInfo.GetValue( null ); | |
if ( addressablesImplInstance == null ) | |
{ | |
Debug.LogError( "AddressableCatalogRefresh.LoadContentCatalogPlatformAsync: could not get AddressablesImpl instance!" ); | |
return Addressables.ResourceManager.CreateCompletedOperation( default( IResourceLocator ), "Could not get AddressablesImpl instance!" ); | |
} | |
// ShouldChainRequest value | |
PropertyInfo addressablesImplShouldChainRequestPropertyInfo = addressablesImplType.GetProperty( "ShouldChainRequest", BindingFlags.NonPublic | BindingFlags.Instance ); | |
bool shouldChainRequest = false; | |
if ( addressablesImplShouldChainRequestPropertyInfo == null ) | |
{ | |
Debug.LogError( "AddressableCatalogRefresh.LoadContentCatalogPlatformAsync: could not get ShouldChainRequest property type!" ); | |
} | |
else | |
{ | |
shouldChainRequest = (bool) addressablesImplShouldChainRequestPropertyInfo.GetValue( addressablesImplInstance ); | |
} | |
if ( shouldChainRequest ) | |
{ | |
// ChainOperation value | |
PropertyInfo addressablesImplChainOperationPropertyInfo = addressablesImplType.GetProperty( "ChainOperation", BindingFlags.Public | BindingFlags.Instance ); | |
if ( addressablesImplChainOperationPropertyInfo == null ) | |
{ | |
Debug.LogError( "AddressableCatalogRefresh.LoadContentCatalogPlatformAsync: could not get ChainOperation property type!" ); | |
return Addressables.ResourceManager.CreateChainOperation( default( AsyncOperationHandle ), ( operation ) => | |
{ | |
return LoadContentCatalogPlatformAsync( catalogLocation ); | |
} ); | |
} | |
AsyncOperationHandle chainOperation = (AsyncOperationHandle) addressablesImplChainOperationPropertyInfo.GetValue( addressablesImplInstance ); | |
return Addressables.ResourceManager.CreateChainOperation( chainOperation, ( operation ) => | |
{ | |
return LoadContentCatalogPlatformAsync( catalogLocation ); | |
} ); | |
} | |
// LoadContentCatalog method | |
MethodInfo loadContentCatalogMethodInfo = addressablesInitializationOperationType.GetMethod( "LoadContentCatalog", | |
new System.Type[] { addressablesImplType, typeof( IResourceLocation ), typeof( string ), typeof( IResourceLocation ) } ); | |
if ( loadContentCatalogMethodInfo == null ) | |
{ | |
Debug.LogError( "AddressableCatalogRefresh.LoadContentCatalogPlatformAsync: could not get LoadContentCatalog method type!" ); | |
return Addressables.ResourceManager.CreateCompletedOperation( default( IResourceLocator ), "Could not get LoadContentCatalog method type!" ); | |
} | |
AsyncOperationHandle<IResourceLocator> handle = (AsyncOperationHandle<IResourceLocator>) loadContentCatalogMethodInfo.Invoke( null, new object[] { addressablesImplInstance, catalogLocation, null, null } ); | |
return handle; | |
} | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment