Question about function stack resolution queue

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

I am trying to program turn-based system, and was thinking on some kind of chain of functions with yield, to ensure that everything is resolved one after another.
But then I realised I don’t understand some very fundamental rule about code :

if I do :

func foo():
      for x in soldiers:

than every soldier executes its resolve function independently, fastest code is resolved first.

But what would happen if I do :

func foo():
      var whatever
      for x in soldiers:
             whatever = x.resolve()

Does this mean that loop is now waiting for each soldier to return its resolve function ??
If so, I would need no yields in my design

:bust_in_silhouette: Reply From: timothybrentwood

So whenever you yield() inside of a function you drop out of that function call and return to the caller in the stack with a return type of GDFunctionState or something along those lines. Any yield() calls in x.resolve() would explain the behavior your are experiencing.

You could still have yields in your design. A quick solution that I came up with would be to register a stack of units to act with a turn manager and have a lock on the turn manager that each unit grabs when they start to act. Inside of _process() for the turn manager you check to see if the lock is locked - if it is do nothing otherwise make the next unit in the stack act.

Let me know if that makes sense or if you need further explanations on anything.

Thank You, these ideas are definetely interesting to consider :slight_smile:
However I wanted to know if I assign a function result to a variable, like in my example, wouldn’t it have the same result as yielding ?
Take a look :

func foo():
      var whatever
      for x in soldiers:
             whatever = x.resolve()

Imagine that every x node has very different code in resolve() function, so each x require various time to be finished.
var whatever is introduced in higher scope then for loop. Its value is made dependant on each iterated element of the loop. So this should force each resolvecoroutine to be resolved one after another, independently of their individual resolution speed, am I not right ?

Inces | 2022-12-27 18:35

whatever will just be assigned the GDScriptFunctionState that yield() passes back in x.resolve() then on the next loop it will be overwritten with the new GDScriptFunctionState from the next x.resolve(). @GDScript — Godot Engine (stable) documentation in English

I think to achieve the turn queue system you desire you’ll need to have a manager that waits until each unit’s turn is completely over then lets the next unit start their turn.

I remember being just as confused as you were because my function was returning a boolean that I tested with if(variable) and I was confused why it was returning true when there as no way for it to possibly return true then I realized that variable was being assigned a GDScriptFunctionState instead of a boolean.

I should note that Yield is going away with godot 4.

timothybrentwood | 2022-12-27 18:59

But there is no yield in my example, no yield inside corroutines also ! :slight_smile:
so whatever won’t be assigned frozen function state. It should be assigned returning result of each of these coroutines instead. One after the other.
As opposed to if I would just do

for x in soldiers:

wchi would resolve all soldiers in order depending on their code complication

Am I getting this part wrong ?

Inces | 2022-12-28 06:59