Home > OS >  Turn Coroutines into Async Await approach in Unity?
Turn Coroutines into Async Await approach in Unity?

Time:10-26

Let's say in Unity I'm using a web API to get a JSON response. I'm currently using a function similar to this

public IEnumerator GetCompletion(string prompt, System.Action<string> callback, float temperature = 0.8f)
{
    UnityWebRequest www = UnityWebRequest.Post("https://api.openai.com/v1/completions", "");
    // ... snip ....

    yield return www.SendWebRequest();
    if (www.result == UnityWebRequest.Result.ConnectionError)
    {
        Debug.Log(www.error);
        www.Dispose();
        yield return null;
    }
    else
    {
        www.Dispose();
        callback?.Invoke(GetResultFromJson(www.downloadHandler.text));
    }
}

which I can then call via

const string prompt = "Albert Einstein was";
StartCoroutine(
    textAI.GetCompletion(prompt, (string result) =>
    {
        Debug.Log(result);
    },
    temperature: 0.5f
));

How would I refactor this Coroutines approach to be using C#'s Await and Async approach?

I don't have any particular end goal, except perhaps to make things easier to read due to less nesting when calling (also when the coroutine would need another couroutine inside it, or when I need to await multiple simultaneously). Thanks!

CodePudding user response:

If you have time, unity is planning to use modern c# techniques. Await/async is on the roadmap.

IEnumerator Start() {
    yield return SceneManager.LoadSceneAsync("somescene");
    var task = SomeTaskBasedApi(CancellationToken.None);
    yield return null
}

is going to be something like:

async void Start() {
    var result = await PrepareSceneAndCallAPI();
    await AwaitableCoroutine.NextFrameAsync(CancellationToken);
}

source: Unity and .NET Whats next

CodePudding user response:

I don't know if there's an easier answer, but one can import the free UniRx from the Asset Store. Then, in some static class for extensions, add

using UnityEngine;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;

public static class Extensions
{
    public static TaskAwaiter GetAwaiter(this AsyncOperation asyncOp)
    {
        var tcs = new TaskCompletionSource<object>();
        asyncOp.completed  = obj => { tcs.SetResult(null); };
        return ((Task)tcs.Task).GetAwaiter();
    }
}

Now the following function code can be used:

using System.Threading.Tasks;
// ... snip ...

public async Task<string> GetCompletion(string prompt, float temperature = 0.8f)
{
    UnityWebRequest www = UnityWebRequest.Post("https://api.openai.com/v1/completions", "");
    // ... snip ...

    await www.SendWebRequest();
    if (www.result == UnityWebRequest.Result.ConnectionError)
    {
        Debug.Log(www.error);
        www.Dispose();
        return null;
    }
    else
    {
        www.Dispose();
        return GetResultFromJson(www.downloadHandler.text);
    }

    return null;
}

and it can be called like this

async void Test()
{
    string result = await textAI.GetCompletion_Async("Albert Einstein was");
    Debug.Log("Result:");
}
  • Related