Error when resuming yield

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By jacktype

Hello,

I’m trying to resume a yielded function. The function consists of a 5 second timer that when completes sucessfuly prints a message “Waited 5 seconds”, otherwise if a button is pressed in the middle of the timer execution the function exits and prints “yield cancelled”.
This code works correctly but the debugger shows an error resume: Condition "!function" is true. Returned: Variant()
I can’t figure out the reason for this error.

code:

extends Node2D

const CANCEL = true

var pending_yield

func _ready():

	pending_yield = do_stuff()

func _on_Button_pressed():

	if(pending_yield.is_valid()):
		pending_yield.resume(CANCEL)

func do_stuff():

	var result = yield(get_tree().create_timer(5), "timeout")
	
	if result == CANCEL:
		print("The yield was cancelled. Stopping the function.")
		return
	
	print("Waited 5 seconds")
:bust_in_silhouette: Reply From: omggomb

Once you call resume, the function state is invalidated. Since your SceneTreeTimer is still executing and trying to resume the function state once more on its timout, you get this error (it tries to resume an invalidated state, so I guess there is some check missing in Godot’s internals). I suggest you use a regular Timer node, which can be canceled.

extends Node2D

var timer = null

func _ready():
	# Wait 5 secs for something
	_do_stuff()
	# Simulate your _on_Button_pressed method by waiting 1 sec
	# This has nothing to do with your problem, I'm just too lazy
	# To create a button ;)
	yield(get_tree().create_timer(1), "timeout")
	_cancel_timer()
	
func _do_stuff():
	timer = Timer.new()
	timer.wait_time = 5
	timer.connect("timeout", self, "_timer_timeout")
	timer.autostart = true
	add_child(timer)

func _timer_timeout():
	print("Waitet 5 seconds")
	if timer:
		timer.queue_free()
		timer = null
		
func _cancel_timer():
	if timer:
		timer.stop()
		timer.queue_free()
		timer = null
		print("The yield was cancelled. Stopping the function")

You’re quite right, I thought that since the yield was resumed the SceneTree timer signal would be discarded somehow, but is indeed not the case.

I made a test with another SceneTree timer in other node emitting a custom signal on timeout, If I block that signal from firing once I resume the yield, there’s no errors. I also though about using a proper timer node like you suggested, but I wanted to understand why this wasn’t working.

I checked the documentation to see if there is a way to cancel a SceneTree timer, but as far as I can tell there’s no way to do it. So your method is the best option. Thanks for answering, helped me alot!

jacktype | 2020-04-06 22:41