Skip to content

Commit 2124133

Browse files
authored
Add an option to wait for a network request action to end before running other actions (#4023)
* In the future, there will be other actions where you can optionally wait for their tasks to be finished before running the rest of the actions. It makes logic easier and more straightforward to express in events. * This is similar to the Wait action, except that it's optional.
1 parent 905344f commit 2124133

File tree

24 files changed

+727
-254
lines changed

24 files changed

+727
-254
lines changed

Core/GDCore/Events/CodeGeneration/EventsCodeGenerator.cpp

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,14 @@ gd::String EventsCodeGenerator::GenerateActionCode(
468468
action, *this, context);
469469
}
470470

471+
// Get the correct function name depending on whether it should be async or
472+
// not.
473+
const gd::String& functionCallName =
474+
instrInfos.IsAsync() &&
475+
(!instrInfos.IsOptionallyAsync() || action.IsAwaited())
476+
? instrInfos.codeExtraInformation.asyncFunctionCallName
477+
: instrInfos.codeExtraInformation.functionCallName;
478+
471479
// Be sure there is no lack of parameter.
472480
while (action.GetParameters().size() < instrInfos.parameters.size()) {
473481
vector<gd::Expression> parameters = action.GetParameters();
@@ -522,6 +530,7 @@ gd::String EventsCodeGenerator::GenerateActionCode(
522530
action.GetParameters(), instrInfos.parameters, context);
523531
actionCode += GenerateObjectAction(realObjects[i],
524532
objInfo,
533+
functionCallName,
525534
arguments,
526535
instrInfos,
527536
context,
@@ -556,6 +565,7 @@ gd::String EventsCodeGenerator::GenerateActionCode(
556565
GenerateBehaviorAction(realObjects[i],
557566
action.GetParameter(1).GetPlainString(),
558567
autoInfo,
568+
functionCallName,
559569
arguments,
560570
instrInfos,
561571
context,
@@ -567,8 +577,11 @@ gd::String EventsCodeGenerator::GenerateActionCode(
567577
} else {
568578
vector<gd::String> arguments = GenerateParametersCodes(
569579
action.GetParameters(), instrInfos.parameters, context);
570-
actionCode +=
571-
GenerateFreeAction(arguments, instrInfos, context, optionalAsyncCallbackName);
580+
actionCode += GenerateFreeAction(functionCallName,
581+
arguments,
582+
instrInfos,
583+
context,
584+
optionalAsyncCallbackName);
572585
}
573586

574587
return actionCode;
@@ -678,7 +691,8 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
678691
} else if (ParameterMetadata::IsObject(metadata.type)) {
679692
// It would be possible to run a gd::ExpressionCodeGenerator if later
680693
// objects can have nested objects, or function returning objects.
681-
argOutput = GenerateObject(parameter.GetPlainString(), metadata.type, context);
694+
argOutput =
695+
GenerateObject(parameter.GetPlainString(), metadata.type, context);
682696
} else if (metadata.type == "relationalOperator") {
683697
auto parameterString = parameter.GetPlainString();
684698
argOutput += parameterString == "=" ? "==" : parameterString;
@@ -716,13 +730,15 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
716730
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
717731
} else if (metadata.type == "yesorno") {
718732
auto parameterString = parameter.GetPlainString();
719-
argOutput += (parameterString == "yes" || parameterString == "oui") ? GenerateTrue()
720-
: GenerateFalse();
733+
argOutput += (parameterString == "yes" || parameterString == "oui")
734+
? GenerateTrue()
735+
: GenerateFalse();
721736
} else if (metadata.type == "trueorfalse") {
722737
auto parameterString = parameter.GetPlainString();
723738
// This is duplicated in AdvancedExtension.cpp for GDJS
724-
argOutput += (parameterString == "True" || parameterString == "Vrai") ? GenerateTrue()
725-
: GenerateFalse();
739+
argOutput += (parameterString == "True" || parameterString == "Vrai")
740+
? GenerateTrue()
741+
: GenerateFalse();
726742
}
727743
// Code only parameter type
728744
else if (metadata.type == "inlineCode") {
@@ -1082,6 +1098,7 @@ gd::String EventsCodeGenerator::GenerateBehaviorCondition(
10821098
}
10831099

10841100
gd::String EventsCodeGenerator::GenerateFreeAction(
1101+
const gd::String& functionCallName,
10851102
const std::vector<gd::String>& arguments,
10861103
const gd::InstructionMetadata& instrInfos,
10871104
gd::EventsCodeGenerationContext& context,
@@ -1095,21 +1112,21 @@ gd::String EventsCodeGenerator::GenerateFreeAction(
10951112
call = GenerateOperatorCall(
10961113
instrInfos,
10971114
arguments,
1098-
instrInfos.codeExtraInformation.functionCallName,
1115+
functionCallName,
10991116
instrInfos.codeExtraInformation.optionalAssociatedInstruction);
11001117
else if (instrInfos.codeExtraInformation.accessType ==
11011118
gd::InstructionMetadata::ExtraInformation::Mutators)
11021119
call =
11031120
GenerateMutatorCall(instrInfos,
11041121
arguments,
1105-
instrInfos.codeExtraInformation.functionCallName);
1122+
functionCallName);
11061123
else
11071124
call = GenerateCompoundOperatorCall(
11081125
instrInfos,
11091126
arguments,
1110-
instrInfos.codeExtraInformation.functionCallName);
1127+
functionCallName);
11111128
} else {
1112-
call = instrInfos.codeExtraInformation.functionCallName + "(" +
1129+
call = functionCallName + "(" +
11131130
GenerateArgumentsList(arguments) + ")";
11141131
}
11151132

@@ -1123,6 +1140,7 @@ gd::String EventsCodeGenerator::GenerateFreeAction(
11231140
gd::String EventsCodeGenerator::GenerateObjectAction(
11241141
const gd::String& objectName,
11251142
const gd::ObjectMetadata& objInfo,
1143+
const gd::String& functionCallName,
11261144
const std::vector<gd::String>& arguments,
11271145
const gd::InstructionMetadata& instrInfos,
11281146
gd::EventsCodeGenerationContext& context,
@@ -1136,27 +1154,25 @@ gd::String EventsCodeGenerator::GenerateObjectAction(
11361154
call = GenerateOperatorCall(
11371155
instrInfos,
11381156
arguments,
1139-
instrInfos.codeExtraInformation.functionCallName,
1157+
functionCallName,
11401158
instrInfos.codeExtraInformation.optionalAssociatedInstruction,
11411159
2);
11421160
else
11431161
call = GenerateCompoundOperatorCall(
1144-
instrInfos,
1145-
arguments,
1146-
instrInfos.codeExtraInformation.functionCallName,
1147-
2);
1162+
instrInfos, arguments, functionCallName, 2);
11481163

11491164
return "For each picked object \"" + objectName + "\", call " + call +
11501165
".\n";
11511166
} else {
11521167
gd::String argumentsStr = GenerateArgumentsList(arguments, 1);
11531168

1154-
call = instrInfos.codeExtraInformation.functionCallName + "(" +
1155-
argumentsStr + ")";
1169+
call = functionCallName + "(" + argumentsStr + ")";
11561170

11571171
return "For each picked object \"" + objectName + "\", call " + call + "(" +
11581172
argumentsStr + ")" +
1159-
(optionalAsyncCallbackName.empty() ? "" : (", then call" + optionalAsyncCallbackName)) +
1173+
(optionalAsyncCallbackName.empty()
1174+
? ""
1175+
: (", then call" + optionalAsyncCallbackName)) +
11601176
".\n";
11611177
}
11621178
}
@@ -1165,6 +1181,7 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
11651181
const gd::String& objectName,
11661182
const gd::String& behaviorName,
11671183
const gd::BehaviorMetadata& autoInfo,
1184+
const gd::String& functionCallName,
11681185
const std::vector<gd::String>& arguments,
11691186
const gd::InstructionMetadata& instrInfos,
11701187
gd::EventsCodeGenerationContext& context,
@@ -1178,26 +1195,28 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
11781195
call = GenerateOperatorCall(
11791196
instrInfos,
11801197
arguments,
1181-
instrInfos.codeExtraInformation.functionCallName,
1198+
functionCallName,
11821199
instrInfos.codeExtraInformation.optionalAssociatedInstruction,
11831200
2);
11841201
else
11851202
call = GenerateCompoundOperatorCall(
11861203
instrInfos,
11871204
arguments,
1188-
instrInfos.codeExtraInformation.functionCallName,
1205+
functionCallName,
11891206
2);
11901207
return "For each picked object \"" + objectName + "\", call " + call +
11911208
" for behavior \"" + behaviorName + "\".\n";
11921209
} else {
11931210
gd::String argumentsStr = GenerateArgumentsList(arguments, 2);
11941211

1195-
call = instrInfos.codeExtraInformation.functionCallName + "(" +
1212+
call = functionCallName + "(" +
11961213
argumentsStr + ")";
11971214

11981215
return "For each picked object \"" + objectName + "\", call " + call + "(" +
11991216
argumentsStr + ")" + " for behavior \"" + behaviorName + "\"" +
1200-
(optionalAsyncCallbackName.empty() ? "" : (", then call" + optionalAsyncCallbackName)) +
1217+
(optionalAsyncCallbackName.empty()
1218+
? ""
1219+
: (", then call" + optionalAsyncCallbackName)) +
12011220
".\n";
12021221
}
12031222
}

Core/GDCore/Events/CodeGeneration/EventsCodeGenerator.h

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,10 @@ class GD_CORE_API EventsCodeGenerator {
154154
* \param context Context used for generation
155155
* \return Code
156156
*/
157-
gd::String GenerateActionCode(gd::Instruction& action,
158-
EventsCodeGenerationContext& context,
159-
const gd::String& optionalAsyncCallbackName = "");
157+
gd::String GenerateActionCode(
158+
gd::Instruction& action,
159+
EventsCodeGenerationContext& context,
160+
const gd::String& optionalAsyncCallbackName = "");
160161

161162
struct CallbackDescriptor {
162163
CallbackDescriptor(const gd::String functionName_,
@@ -174,7 +175,8 @@ class GD_CORE_API EventsCodeGenerator {
174175
*/
175176
const gd::String argumentsList;
176177
/**
177-
* A set of all objects that need to be backed up to be passed to the callback code.
178+
* A set of all objects that need to be backed up to be passed to the
179+
* callback code.
178180
*/
179181
const std::set<gd::String> requiredObjects;
180182
};
@@ -507,10 +509,10 @@ class GD_CORE_API EventsCodeGenerator {
507509
* - currentScene: Reference to the current runtime scene.
508510
* - objectList : a map containing lists of objects which are specified by the
509511
object name in another parameter.
510-
* - objectListOrEmptyIfJustDeclared : Same as `objectList` but do not pick object if
511-
they are not already picked.
512-
* - objectPtr: Return a reference to the object specified by the object name in
513-
another parameter. Example:
512+
* - objectListOrEmptyIfJustDeclared : Same as `objectList` but do not pick
513+
object if they are not already picked.
514+
* - objectPtr: Return a reference to the object specified by the object name
515+
in another parameter. Example:
514516
* \code
515517
.AddParameter("object", _("Object"))
516518
.AddParameter("objectPtr", _("Target object"))
@@ -700,6 +702,7 @@ class GD_CORE_API EventsCodeGenerator {
700702
gd::EventsCodeGenerationContext& context);
701703

702704
virtual gd::String GenerateFreeAction(
705+
const gd::String& functionCallName,
703706
const std::vector<gd::String>& arguments,
704707
const gd::InstructionMetadata& instrInfos,
705708
gd::EventsCodeGenerationContext& context,
@@ -708,6 +711,7 @@ class GD_CORE_API EventsCodeGenerator {
708711
virtual gd::String GenerateObjectAction(
709712
const gd::String& objectName,
710713
const gd::ObjectMetadata& objInfo,
714+
const gd::String& functionCallName,
711715
const std::vector<gd::String>& arguments,
712716
const gd::InstructionMetadata& instrInfos,
713717
gd::EventsCodeGenerationContext& context,
@@ -717,6 +721,7 @@ class GD_CORE_API EventsCodeGenerator {
717721
const gd::String& objectName,
718722
const gd::String& behaviorName,
719723
const gd::BehaviorMetadata& autoInfo,
724+
const gd::String& functionCallName,
720725
const std::vector<gd::String>& arguments,
721726
const gd::InstructionMetadata& instrInfos,
722727
gd::EventsCodeGenerationContext& context,
@@ -775,8 +780,8 @@ class GD_CORE_API EventsCodeGenerator {
775780

776781
bool hasProjectAndLayout; ///< true only if project and layout are valid
777782
///< references. If false, they should not be used.
778-
const gd::Project* project; ///< The project being used.
779-
const gd::Layout* scene; ///< The scene being generated.
783+
const gd::Project* project; ///< The project being used.
784+
const gd::Layout* scene; ///< The scene being generated.
780785

781786
bool errorOccurred; ///< Must be set to true if an error occured.
782787
bool compilationForRuntime; ///< Is set to true if the code generation is

Core/GDCore/Events/Event.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ void BaseEvent::PreprocessAsyncActions(const gd::Platform& platform) {
7575
const auto& action = actionsList->at(aId);
7676
const gd::InstructionMetadata& actionMetadata =
7777
gd::MetadataProvider::GetActionMetadata(platform, action.GetType());
78-
if (actionMetadata.IsAsync()) {
78+
if (actionMetadata.IsAsync() &&
79+
(!actionMetadata.IsOptionallyAsync() || action.IsAwaited())) {
7980
gd::InstructionsList remainingActions;
8081
remainingActions.InsertInstructions(
8182
*actionsList, aId + 1, actionsList->size() - 1);

Core/GDCore/Events/Instruction.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,22 @@ class GD_CORE_API Instruction {
7272
*/
7373
void SetInverted(bool inverted_) { inverted = inverted_; }
7474

75+
/**
76+
* \brief Return true if the async instruction should be awaited.
77+
* This is not relevant if the instruction is not optionally asynchronous.
78+
*
79+
* \return true if the instruction is to be awaited
80+
*/
81+
bool IsAwaited() const { return awaitAsync; }
82+
83+
/**
84+
* \brief Set if the async instruction is to be awaited or not.
85+
* This is not relevant if the instruction is not optionally asynchronous.
86+
*
87+
* \param inverted true if the instruction must be awaited
88+
*/
89+
void SetAwaited(bool awaited) { awaitAsync = awaited; }
90+
7591
/**
7692
* \brief Return the number of parameters of the instruction.
7793
*/
@@ -139,7 +155,9 @@ class GD_CORE_API Instruction {
139155
* Useful to get reference to the original instruction in memory during code
140156
* generation, to ensure stable unique identifiers.
141157
*/
142-
std::weak_ptr<Instruction> GetOriginalInstruction() { return originalInstruction; };
158+
std::weak_ptr<Instruction> GetOriginalInstruction() {
159+
return originalInstruction;
160+
};
143161

144162
friend std::shared_ptr<Instruction> CloneRememberingOriginalElement(
145163
std::shared_ptr<Instruction> instruction);
@@ -148,6 +166,9 @@ class GD_CORE_API Instruction {
148166
gd::String type; ///< Instruction type
149167
bool inverted; ///< True if the instruction if inverted. Only applicable for
150168
///< instruction used as conditions by events
169+
bool awaitAsync =
170+
false; ///< Tells the code generator whether the optionally asynchronous
171+
///< instruction should be generated as asynchronous (awaited) or not.
151172
mutable std::vector<gd::Expression>
152173
parameters; ///< Vector containing the parameters
153174
gd::InstructionsList subInstructions; ///< Sub instructions, if applicable.

Core/GDCore/Events/Serialization.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,9 @@ void gd::EventsListSerialization::UnserializeInstructionsFrom(
269269
instrElement.GetChild("type", 0, "Type")
270270
.GetBoolAttribute("inverted", false, "Contraire"));
271271

272+
instruction.SetAwaited(
273+
instrElement.GetChild("type", 0, "Type").GetBoolAttribute("await"));
274+
272275
// Read parameters
273276
vector<gd::Expression> parameters;
274277

@@ -346,6 +349,8 @@ void gd::EventsListSerialization::SerializeInstructionsTo(
346349

347350
if (list[k].IsInverted())
348351
instruction.GetChild("type").SetAttribute("inverted", true);
352+
if (list[k].IsAwaited())
353+
instruction.GetChild("type").SetAttribute("await", true);
349354

350355
// Parameters
351356
SerializerElement& parameters = instruction.AddChild("parameters");

Core/GDCore/Extensions/Builtin/TimeExtension.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
2121
"Florian Rival",
2222
"Open source (MIT License)")
2323
.SetExtensionHelpPath("/all-features/timers-and-time");
24-
extension.AddInstructionOrExpressionGroupMetadata(
25-
_("Timers and time")
26-
)
24+
extension.AddInstructionOrExpressionGroupMetadata(_("Timers and time"))
2725
.SetIcon("res/conditions/timer24.png");
2826

2927
// Deprecated and replaced by CompareTimer
@@ -158,8 +156,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
158156
"res/timer.svg",
159157
"res/timer.svg")
160158
.AddParameter("expression", "Time to wait in seconds")
161-
.SetHelpPath("/all-features/timers-and-time/wait-action")
162-
.SetAsync();
159+
.SetHelpPath("/all-features/timers-and-time/wait-action");
163160

164161
extension
165162
.AddExpression("TimeDelta",

Core/GDCore/Extensions/Metadata/InstructionMetadata.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ InstructionMetadata::InstructionMetadata()
2222
canHaveSubInstructions(false),
2323
hidden(true),
2424
usageComplexity(5),
25-
isAsync(false),
2625
isPrivate(false),
2726
isObjectInstruction(false),
2827
isBehaviorInstruction(false) {}
@@ -46,7 +45,6 @@ InstructionMetadata::InstructionMetadata(const gd::String& extensionNamespace_,
4645
extensionNamespace(extensionNamespace_),
4746
hidden(false),
4847
usageComplexity(5),
49-
isAsync(false),
5048
isPrivate(false),
5149
isObjectInstruction(false),
5250
isBehaviorInstruction(false) {}

0 commit comments

Comments
 (0)