ProcessPurchase with yield

I’m a web developer that currently works on a new unity project… I used c# long years ago and dont really remember anything.

I implemented this Coroutine and I’m trying to fetch data from a server and make game objects with the retrieved data. I managed to make it work with a very wired syntax for me as a web developer

I can’t understand why I need to write so many yields and how can I avoid that as I don’t want to change my start function to IEnumerator.

This is part of a store screen script and I need to implement the ProcessPurchase function. In the function, I need to make an API call and based on the response return if the purchase is complete… but if I use the same solution as I did at the Start function I will be forced to change the ProcessPurchase function to IEnumerator and I can’t do that as it expects specific result.

here is the code:

private IEnumerator Start()
    {
        var fetchStoreItems = new CoroutineWithData(this, managers.server.FetchStoreItems());
        yield return fetchStoreItems.coroutine;

        if (fetchStoreItems.result is StoreItemsResponse response)
        {
            foreach (var t in response.packages)
            {
                var a = packageBox.gameObject.GetComponent<StoreBox>();
                GameObject newPanel = Instantiate(a.gameObject, generalPackages.transform);
                newPanel.GetComponent<UnityEngine.UI.Button>().onClick
                .AddListener(() => BuyItem(a.id));
            }
        }
    }

And here is the fetch:

    public IEnumerator FetchStoreItems()
    {
        var request = CreateGetRequest(BaseUrl + "/store/items", true);
        CoroutineWithData cd = new CoroutineWithData(this, LoadSomeStuff(request));

        yield return cd.coroutine;
        yield return JsonUtility.FromJson<StoreItemsResponse>(cd.result.ToString());
    }

ProcessPurchase:

    public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent)
    {
        //Retrieve the purchased product
        var product = purchaseEvent.purchasedProduct;

        string os = RuntimePlatform.Android == Application.platform ? "android" : "ios";

        var a = managers.server.PurchaseItem(os, product.definition.id,
          purchaseEvent.purchasedProduct.receipt);

        return PurchaseProcessingResult.Complete;
    }

Coroutine is more like a lazy crutch that lets you avoid having to build a proper time scheduler or a state machine. There are cases when it’s very convenient and there are genuine uses for it, but people use and abuse it all over the place.

So don’t blame coroutines when the language itself supports asynchronous functions and that’s the preferred way to access web.

Anyway, whoever wrote that code, intended it to be just a simple sequential state machine with some event callbacks.

You should not modify Start, you need to move all that aside, and then call the first IEnumerator method from your Start method

void Start() {
  StartCoroutine(MyCouroutineMethod());
}

You might consider the Sample IAP Project here to get started with Unity IAP, it shows a typical example of ProcessPurchase https://discussions.unity.com/t/700293/6

Thank you guys for your comment, but my main problem is inside ProcessPurchase, I want to inform my server that user purchased an item and get the response and return the PurchaseProcessingResult based on it.
If I change the function to use Coroutine I will be forced to change the return type to IEnumerator but that will make this error:

example of the not working code:

public IEnumerable ProcessPurchase(PurchaseEventArgs purchaseEvent)
{
    //Retrieve the purchased product
    var product = purchaseEvent.purchasedProduct;

    string os = RuntimePlatform.Android == Application.platform ? "android" : "ios";
    var purchaseItemRequest = new CoroutineWithData(this, managers.server.PurchaseItem(os, product.definition.id, purchaseEvent.purchasedProduct.receipt));
    yield return purchaseItemRequest.coroutine;

    if (purchaseItemRequest.result.ToString() == "success")
    {
        return PurchaseProcessingResult.Complete;
    }

    return PurchaseProcessingResult.Pending;
}

How can I wait for my server to process the request and based on the server respond return the correct PurchaseProcessingResult?

Usually such APIs implement async/await. Doesn’t this one?

return PurchaseProcessingResult.Pending;

This isn’t returning an IEnumerable, looks more like an enum.
You may have to do a while loop like so:

do
{
    yield return purchaseItemRequest.coroutine;
} while (purchaseItemRequest.result.ToString() != "success");

Note 1: you may want to handle the “failed” case (and any other potential result) or this loop will get stuck forever. :wink:

Note 2: I have a hunch that comparing result to a “success” string is bonkers. You probably want something like “result == PurchaseProcessingResult.Success”.

What type is result? Pretty certain it’s an enum.

I don’t know where people find these coroutine bushes, it’s like there is some conspiracy against rookies.
If you’re rusty on C# and admit you have a hard time reading this, why go neck deep into someone’s hacky algorithms only to ask for help? JeffD told you already about the more instructional and much more gentle/natural way of using such APIs. It’s literally like the Unity desktop icon itself came in here to recommend you the best practice, but no.

ProcessPurchase is already an async callback from the respective store APIs (Google and Apple). Fire off your call to your server from ProcessPurchase, and return Pending from ProcessPurchase. Once you receive your server callback, call ConfirmPendingPurchase.

This is the correct answer to my question… and by the way, there is an example in the sample iap project but I missed it.
Thank you guys for your help!