I have to check this because we are using multiple skins and have a fallback skin. If the requested asset doesnât exist we want to load the fallback skin for this element, which is always guaranteed to be there.
In a ideal world I would be calling: Addressables.DoesAssetExist<Sprite>(new List<object> { "Background" , "Skin2" });
Where âBackgroundâ would be the address and âSkin2â the label
What about using Addressables.LoadAssetAsync, wait until itâs done using AsyncOperationHandle<T>.isDone and then check whether it was possible to load the Asset using AsyncOperationHandle<T>.status? If it failed, you can try to load the fallback skin and if you suceeded youâre already done.
That is kind of the approach Iâm going for right now. Thank you for the suggestion, makes me more confident in doing so ^^ Iâll try out the status approach, I just checked if the handle.Result was null.
But Iâm getting spammed with ugly exceptions like ```
Exception encountered in operation UnityEngine.ResourceManagement.ResourceManager+CompletedOperation1[System.Collections.Generic.IList1[UnityEngine.Sprite]], result=ââ, status=âFailedâ: Exception of type âUnityEngine.AddressableAssets.InvalidKeyExceptionâ was thrown., Key=System.Collections.Generic.List1[System.Object], Type=UnityEngine.Sprite UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase1:<.ctor>b__33_0(AsyncOperationHandle)
Those will still appear when I try to load an address that doesn't exist right? Any ideas to work around that?
My post in that thread you linked shows how I cache the keys from initialization to check if an address exists. Since then, I have implemented a build script that rolls through all asset entries and builds a dictionary of keys to labels so I can lookup the label from the key. I save that dictionary to json in a remote location (next to the catalog), then while Iâm initializing addressables, I also download and deserialize that json to dictionary so I can do a synchronous lookup. That json can be updated at the same time as the content catalog if necessary.
Of course, Addressables already has that information internally, so Iâm doing a lot of workaround for something they could easily just expose. IReadOnlyCollection<string> Addressables.GetLabels(object key) would be nice. Or even IResourceLocation Addressables.GetResourceLocation(object key) then add IReadOnlyCollection<string> IResourceLocation.Labels. Iâm not even sure how weâre supposed to access or use IResourceLocations with the API as it isâŚ
As for your issue about getting spammed errors, you can disable that in the top level addressable settings then go about your business.
Yes they still appear because the exceptions are not thrown but just logged instead. Luckily there is indeed a very simple workaround: Turn off âLog runtime exceptionsâ in AddressablesAssetSettings:
If you really want to load the asset, LoadAssetAssync is not a bad choice. But if you only want to check for the existence of the key, a better approach would be to use the method in AddressablesImpl.cs.
internal bool GetResourceLocations(IEnumerable<object> 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>();
foreach (var loc in locations)
current.Add(loc);
}
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;
}
Of course this assumes that the system is already initialized.
I still, to that day, havenât found a way to overcome this, oh my god!
We went for âLoad, see if something comes back, if not, load something elseâ way.
First of all, the âLog Runtime Exceptionsâ flag in the Addressables settings activates itself randomly (of course we had to uncheck it to donât get spammed in the console).
But the team now decided to keep that checked, because it mutes potential problems elsewhere (which I understand).
I tried the whole bank.
I tried to create my own helper class that wraps these functions, but as you try you see that it depends on all kinds of other stuff that is only internal or private. And I canât change the Addressables classes because we would never be able to update the package.
Unity, there MUST be a way to ask the system if a combination of keys exist. Make it async, I donât care anymore, but we canât work with it how it is.
I triedâŚ
var validateAddress = Addressables.LoadResourceLocationsAsync(new List<object> {address, skin.skinLabel.labelString});
await validateAddress.Task;
if (validateAddress.Status == UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationStatus.Succeeded)
{
if (validateAddress.Result.Count > 0)
{
foreach (var loc in validateAddress.Result)
Log.Print(loc.PrimaryKey, "nob");
}
else
{
Log.Print("No: " + address + " " + skin.skinLabel.labelString, "nob");
}
}
else
{
Log.Print("Nope", "nob");
}
This always gives me âNoâ this canât be, Iâm raging!