#UniTask Completion issue

1 messages ยท Page 1 of 1 (latest)

cinder blaze
slim shadow
#

I'm not sure what you trying to achieve. Why do you have two StartSpawn, when the second should by ignored?

cinder blaze
#

Two calls is for example.

In my project spawner creates objects until it fills up. When player triggers the trigger objects pops out from storage and spawner should fill up again

#

I'm trying to prevent double spawn task

#

At the moment thats how it works

    private void OnEnable()
    {
        _stash.OnRemove += (c) => StartSpawn();
        StartSpawn();
    }

    private void OnDisable()
    {
        _stash.OnRemove -= (c) => StartSpawn();
    }

    private async void StartSpawn()
    {
        if (_spawnFlag) return;

        _spawnFlag = true;

        while (!_stash.IsFull())
        {
            await UniTask.Delay(TimeSpan.FromSeconds(_spawnRate));

            Spawn();
        }

        _spawnFlag = false;
    }

    private void Spawn()
    {
        var point = _stash.GetPoint();
        var pickupable = _cubePool.Pull(point.position);

        pickupable.DisableCollider();
        
        _stash.Add(pickupable);
    }
slim shadow
#

Oh, i got it now. Let me think a minute

cinder blaze
#

Each time when Object got removed from stash spawner class should fill up again

#

Probably thats not how to work with async and you can get result only after completion but I wonder if its possible to cache already existing task and check if its completed or not

slim shadow
#

Yeah, It's possible and it's probably the best way. I'm trying to get some example for you, but I don't have a UniTask currently in any project, so it's a little pain

#
    
    private void StartSpawn()
    {
        if (_spawningTask?.Status == Pending)
        {
            return;
        }

        _spawningTask = ActualSpawn().Forget();
    }

    private async UniTask ActualSpawn()
    {
        await UniTask.Delay(TimeSpan.FromSeconds(_spawnRate));

        Spawn();
    }```
#

I'm not sure if Forget will return the UniTask

cinder blaze
#

"Also UniTask has the Forget method, it is similar to UniTaskVoid and has the same effects. However UniTaskVoid is more efficient if you completely don't use awaitใ€‚"

#

" If you don't require awaiting (fire and forget), using UniTaskVoid is better. Unfortunately to dismiss warning, you're required to call Forget()."

#

From docs

#

So Forget() means that you can execute and return void (i mean nothing)?

slim shadow
#

Yeah, when you don't wanna wait for result

cinder blaze
#

Ok, let my try to implement it and share results

slim shadow
#

Good luck ๐Ÿ™‚

cinder blaze
#

With a few changes it now works like i wanted.

  • Removed Forget() coz its gives me exception (Token version is not matched)
    private UniTask _spawningTask;

    private void StartSpawn()
    {
        if (_spawningTask.Status == UniTaskStatus.Pending)
        {
            Debug.Log("Already started");
            return;
        }

        _spawningTask = ActualSpawn();
    }

    private async UniTask ActualSpawn()
    {
        while (!_stash.IsFull())
        {
            await UniTask.Delay(TimeSpan.FromSeconds(_spawnRate));

            Spawn();
        }
        Debug.Log("Done");
    }
#

UniTask is the struct so thats why im not getting null exception when checking status?

slim shadow
#

oh right, I completly forget about it. Yeah, thats why

cinder blaze
#

But does this mean that UniTask variable is "empty" and can create problems?

slim shadow
#

Yeah, it has some default value it could be problematic, I'm not sure what defualt status it is

cinder blaze
#

default status is Succeeded

#

If you await empty variable it gives nothing. Interesting how it can be tracked (something like nullref)

slim shadow
#

It's probably not possible to be tracked

#

maybe the better way will be to use that Awaiter, and check for this status

cinder blaze
#

I just feel wrong when comparing status to variable that not associated with method yet

slim shadow
#

Yeah, feels kinda dangerous

cinder blaze
#

Yea

#

Gonna check this code right now

        var awaiter = _spawningTask.GetAwaiter();

        if (!awaiter.Equals(ActualSpawn()))
        {
            _spawningTask = ActualSpawn();
        }

        if (_spawningTask.Status == UniTaskStatus.Pending)
        {
            return;
        }

        _spawningTask.Forget();
slim shadow
#

I found some my old code with UniTask. We use UniTask.CompletedTask as initial value

#

so, it can be private UniTask _spawningTask = UniTask.CompletedTask and thats seems a lot better for me

cinder blaze
#

Hm, yeah looks like

#

Im made something, gonna test out, share results with you and make conclusion

#

Feels like i just gonna use your method

slim shadow
#

I'm not sure if there is some discord or something dedicated for UniTask, but maybe someone has a better way for this

#

but we use it UniTask.CompletedTask as initial value in production code, so it should be somehow valid ๐Ÿ˜„

cinder blaze
#

Maybe, but im not trying to make everything perfect at the moment because lack of knowledge

slim shadow
#

good enough it's always the best ๐Ÿ˜„

cinder blaze
#

Yea

wet fable
#

interesting thread people, im also using Unitask

#

adopted it like 1 month ago, before i was using mostly coroutines and normal Tasks

cinder blaze
#

When i was playing around with our result i found out that every time when you trying to spawn, it creates a new task that stores garbage. I saw it in UniTask Tracker.

#

The solution is to add Preserve().

    private void StartSpawn()
    {
        if (_spawningTask.Status == UniTaskStatus.Pending) return;

        _spawningTask = ActualSpawn().Preserve();
        _spawningTask.Forget();
    }
#

"Store to the class field, you can use UniTask.Lazy that supports calling multiple times. .Preserve() allows for multiple calls (internally cached results). This is useful when there are multiple calls in a function scope."

Now it clears out after success and gives no errors after new call

slim shadow
#

Cool, I didn't know that

slender beacon