So we have two stuff going on:
- Choosing what it would look like
- How to implement this
How it would look like
Look you have done a indentation, it’s intinctive 
No, I think you misunderstood how my example work.
I only have indention here because I have a special actions waiting on two others at the same time. This is a special case (I should not have mentioned it ^^) and will probably be almost never used.
The action itself “Wait for these actions to finish” would not be indented compared to others.
But this is not what I wrote
Here in what you write, it would:
- Wait 5 seconds
- THEN it would send a GET Request.
While my example was:
- You start to wait 5 seconds AND you send a GET request (hence the indentation)
- You continue when BOTH are finished.
See the difference? It’s like in JavaScript:
// ...
await delay(5); // Wait 5 seconds
await axios.get(...); // Launch a request
// next stuff (no indentation)
vs:
// ...
await Promise.all([
delay(5),
axios.get(...)
]); // Launch a request and wait 5 seconds, then continue when both things are done
// next stuff (no indentation)
I do agree that waiting for an action to finish is something that needs emphasise. But indentation proved to be something that in JavaScript and other languages was found to be cumbersome. And so await
keyword was introduced.
Let me explain with another example. I’ll take the “wait X seconds” as the most simple “asynchronous action”. It would be useful to put some pause between two actions, great for timing stuff like animations or cut scenes.
If I write down as I speak, I would come up with something like:
- Set animation of player to “something”
- Wait 2 seconds
- Show some text
- Make a cool effect on screen
- Wait 2 seconds
- Play a sound
- Play an animation
- Wait 2 seconds
- Go to the next scene.
See how my list of things (“actions”) has no indentation? 
If you didn’t like the idea, i would see a more verbose chips…
“Wait for result (sub-actions are in pending)”
“Continue only if the result come”
“Pause the actions and wait for result”
Something like that.
Yep I agree with that. Something like:
Maybe the “chip” is not a great idea, we can also alternate some background color to distinguish the actions that are “after” the wait:
Anyway, maybe we’re bikeshedding, but I think that it’s good if we can keep the indentation for events/conditions.
Asynchronous actions introduce a time delay, but not a flow change.
On the implementation
- What are all the
{ }
for?
They are just there to delimitate every event, condition, action generated code. They should not be doing any harm, as any that is opened is then closed and actions are executed sequentially, not in the scope of the previous.
- Am I wrong about the way async/await work?
The main issue is that we can’t just use async/await. It won’t work like this, notably because we have scenes in GDevelop. Anything that is waiting must be scoped to a scene. For example, if I do:
Set the animation of player to "Run"
Wait for 2 seconds
Set the animation of player to "Jump"
Wait for 2 seconds
Change scene to "Main menu"
and in the meantime I go to a scene (i.e: in another event, I used the action to change the scene to go to “Final Level”, because the player won).
What should happen after 2 seconds? Nothing!
The “player” should not have its animation changed to jump… because I’m not even in the scene anymore 
What should happen after yet another 2 seconds? Nothing! I don’t want to go back to the main menu, because I’m not even in the scene where I ran these actions.
Even more interesting: If I pause a scene, play another scene and then comes back to the first scene, the actions “Wait X seconds” must have “stopped”. This means these actions timer must be updated using the game engine (not using a setTimeout).
In other words => because we’re a game engine, our “tasks in suspend” must be periodically checked to be launched at the beginning of each frame.
We can still code our extensions using async/await, in the sense that we can make an action that is a Javascript async
function (or a function that returns a Promise - this is equivalent).
But the generated code should do something like this:
function myActions() {
myUsualAction1();
myUsualAction2();
runtimeScene.addAsynchronousTask(myAsyncAction(...), mapOfObjectsList, theRestOfMyActions);
}
function theRestOfMyActions(mapOfObjectsList) {
// Restore object lists from mapOfObjectsList
myUsualAction4();
myUsualAction5();
// ...
}
At the beginning of each frame, the runtimeScene would iterate on the “tasks”. If one has a promise that is completed (or errored), it will call the function to continue.
When all tasks are executed, events are triggered as usual.
- If there are synchronous actions before the asynchronous one, should they still be executed “asynchronously”?
No, they should be executed as usual.
If I change the player animation, it’s not asynchronous, so the action is executed, and that’s it.
Only the asynchronous actions are doing something special:
- they launch their code
- and the promise that they return is saved in a “asynchronous task in the scene”, along with the context. The context is : 1) the selected objects and 2) the function to call when it’s finished.
- the “function to call when it’s finished” is the generated code of other actions. Note that if one of these actions is asynchronous… well same thing!
(promise must be saved with the context, then another function is generated for actions after it).