Just felt like making this extension to support awaiting handles directly. I figured some people could use this, especially with the Task property not working well in WebGL right now.
Feel free to add this to the library, Addressables devs!
P.S. handle.CompletedTypeless is misleading, I expected it to just let me add an Action without arguments, which would’ve made this extension more efficient.
using System;
using UnityEngine.ResourceManagement.AsyncOperations;
using System.Runtime.CompilerServices;
public static class AsyncOperationHandleExtensions
{
public struct AsyncOperationHandleAwaiter<T> : INotifyCompletion
{
private AsyncOperationHandle<T> _handle;
public AsyncOperationHandleAwaiter(AsyncOperationHandle<T> handle)
{
_handle = handle;
}
public bool IsCompleted
{
get
{
return _handle.IsDone;
}
}
public T GetResult()
{
if (_handle.Status == AsyncOperationStatus.Succeeded)
{
return _handle.Result;
}
throw _handle.OperationException;
}
public void OnCompleted(Action continuation)
{
_handle.Completed += _ => continuation();
}
}
public struct AsyncOperationHandleAwaiter : INotifyCompletion
{
private AsyncOperationHandle _handle;
public AsyncOperationHandleAwaiter(AsyncOperationHandle handle)
{
_handle = handle;
}
public bool IsCompleted
{
get
{
return _handle.IsDone;
}
}
public object GetResult()
{
if (_handle.Status == AsyncOperationStatus.Succeeded)
{
return _handle.Result;
}
throw _handle.OperationException;
}
public void OnCompleted(Action continuation)
{
_handle.Completed += _ => continuation();
}
}
/// <summary>
/// Used to support the await keyword for AsyncOperationHandle.
/// </summary>
public static AsyncOperationHandleAwaiter<T> GetAwaiter<T>(this AsyncOperationHandle<T> handle)
{
return new AsyncOperationHandleAwaiter<T>(handle);
}
/// <summary>
/// Used to support the await keyword for AsyncOperationHandle.
/// </summary>
public static AsyncOperationHandleAwaiter GetAwaiter(this AsyncOperationHandle handle)
{
return new AsyncOperationHandleAwaiter(handle);
}
}
These are extensions that let you use the await keyword directly on an asynoperationhandle. Without this, you cannot await the handle without accessing the Task property. But the Task property doesn’t work in WebGL, so the ToTask extensions here let you create a Task that does work in WebGL (so you can use it in Task.WhenAll(), for example).
Assets\AsyncOperationHandleExtensions.cs(87,33): error CS1983: The return type of an async method must be void, Task or Task
Assets\AsyncOperationHandleExtensions.cs(87,25): error CS0308: The non-generic type ‘Task’ cannot be used with type arguments
for each of the functions
both functions are places in the AsyncOperationHandleExtensions folder, Task is still not recognized.
which libraries are in the “using” to solve it?
i gave an error " : ‘AsyncOperationHandle’ does not contain a definition for ‘GetAwaiter’ and no accessible extension method ‘GetAwaiter’ accepting a first argument of type ‘AsyncOperationHandle’ could be found (are you missing a using directive or an assembly reference?) " how can i fix ?
also what are the difference between reference.InstantiateAsync() and Instantiate ?
can I load an object before instantiating? without instantiateAsync?
You need to include the script from my original post in your project. ^^^
InstantiateAsync is an addressables function that keeps track of the internal reference counter so that the memory can be released when the object is destroyed (only works with Addressables.ReleaseInstance). My example there loads the asset without instantiating it, then instantiates it with the synchronous Object.Instantiate, which addressables does not track.
It doesn’t matter, you can place it anywhere under Assets. I usually place all my scripts under Asset/Scripts. You might even place it in something like Assets/Scripts/Extensions.
Hey, so I placed his first script in my assets in another folder and I named it this AsyncOperationHandleExtensions.
And now I have my original script which was giving me a problem
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
public class LoadRemote : MonoBehaviour
{
[SerializeField] private string _label;
void Start()
{
Get(_label);
}
private async Task Get(string label)
{
var locations = await Addressables.LoadResourceLocationsAsync(label).Task;
foreach (var location in locations)
await Addressables.InstantiateAsync(location).Task;
}
}
And for the second part of the extention OP posted, where do i put that, or do I use one of the methods inplace of my ‘private async’ method?
Hey, thanks for the quick reply. However, I am still pretty new to C# and I am unable to understand how exactly to use your solution.
I placed the below lines into the main extension class and had to added ‘using System.Threading.Tasks;’ to the top of the script.
public static class AsyncOperationHandleExtensions
{
public static async Task<T> ToTask<T>(this AsyncOperationHandle<T> handle)
{
return await handle;
}
public static async Task<object> ToTask(this AsyncOperationHandle handle)
{
return await handle;
//rest of the scrip
}
Now how do I use this extension into my script below?
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
public class LoadRemote : MonoBehaviour
{
[SerializeField] private string _label;
void Start()
{
Get(_label);
}
private async Task Get(string label)
{
var locations = await Addressables.LoadResourceLocationsAsync(label).Task;
foreach (var location in locations)
await Addressables.InstantiateAsync(location).Task;
}
}
I am really not able to find a suitable tutorial on how to implement extension and the one’s I found are using a different example to show which isn’t helping.