In 3.X functions containing a yield would return a GDScriptFunctionState instead of crashing.
But in 4.X, if I were not sure if my function I want to get an output value from is async or not, and I also don't want to wait for the function if it is async, what can I do?

E.g.

func maybe_async_function():
	#I know this function doesn't return a value because it awaits on something
	# and i don't want _ready() to await for this
	await get_tree().create_timer(2).timeout

func maybe_async_function2():
	return true

func _ready():
	#i don't know if i'm calling an async function or not
	var caller = Callable(self,["maybe_async_function","maybe_async_function2"].pick_random())
	#call without await:
	var val = caller.call()

I could solve this by adding another function which makes the await call but that adds more clutter.

  • xyz replied to this.
  • KnightNine You can use lambda signal handlers within vfx functions to elegantly do cleanups inside function's scope.

    func do_animation():
    	var effectiveness = .5
    	var cleanup = func():
    		print("cleaning up")
    	get_tree().create_timer(1).connect("timeout", cleanup)
    	return effectiveness
    
    func _ready():
    	print("effectiveness ", do_animation())

    Btw, names in your code are too long and complicated.

    xyz
    It could be complicated to explain but: I have a list of functions each one represents a specific event in my game "deal damage", "teleport to position", "emit explosion VFX", etc... and I want these functions to be self contained and not spread across several other functions.
    Some of these functions return an effectiveness_score for my AI to determine whether it aligns with the AI's biases.
    My "emit explosion VFX" function is one of them that doesn't return an effectiveness score because it doesn't actually change anything besides create an explosion effect animation. But then it awaits till that explosion animation completes so it can delete the nodes that were made specifically for the animation after the fact.

    And I call these functions via a callable without knowing anything about the function.

    I could label and store data about all my functions on whether they do or don't return an effectiveness_score but it would be more convenient if the function would just return null to indicate that it does not return a score.

    it would be cool if i could do something like this:

    func maybe_async_function():
    	#return the effectiveness_score
    	return
    	#then allow this function to persist after the return.
    	await get_tree().create_timer(2).timeout
    	remove_child(get_node("ColorRect"))
    • xyz replied to this.

      KnightNine You should rethink the architecture of your system so it doesn't use coroutines at all. Use signal handlers for cleanup.

      this is what a VFX function ends in, in my actual code:

      	System.Loose_Animation_Function_Instances.append(anim_funct_instance)
      	await anim_funct_instance.play_animation(vfx_model_instance,"Slash Evaporate",transition_time)
      	
      	#then erase the anim_funct_instance and the vfx_model_instance
      	Global_Variables_3D.world.remove_child(anim_funct_instance)
      	Global_Variables_3D.world.remove_child(vfx_model_instance)
      	System.Loose_Animation_Function_Instances.erase(anim_funct_instance)

      I could add additional functionality within anim_funct_instance.play_animation() to handle the addition and removal of the vfx_model_instance and itself from the world and from the Loose_Animation_Function_Instances, so that I can call it without await.
      This code is likely being used enough to have this functionality embedded within play_animation() though I don't like that it's not exposed within the function itself.

      I'm not sure of what other context I'd be using await within these types of functions so I guess this is the solution.
      🤷

      • xyz replied to this.

        KnightNine You can use lambda signal handlers within vfx functions to elegantly do cleanups inside function's scope.

        func do_animation():
        	var effectiveness = .5
        	var cleanup = func():
        		print("cleaning up")
        	get_tree().create_timer(1).connect("timeout", cleanup)
        	return effectiveness
        
        func _ready():
        	print("effectiveness ", do_animation())

        Btw, names in your code are too long and complicated.

          xyz
          Oh that's how I can have nested functions! I didn't think it was possible in gdscript.
          Was this is 3.X or is this a new addition to 4.X?

          Btw, names in your code are too long and complicated.

          I'll try to clean it up when it's worth polishing and I'm working with more ppl than just myself.

          • xyz replied to this.

            KnightNine Was this is 3.X or is this a new addition to 4.X?

            Lambdas were added in v 4, alongside vanilla callables.