mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
132 Commits
40c576bc2d
...
experiment
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5ebe8ab072 | ||
![]() |
066e474031 | ||
![]() |
54bc2b1c5a | ||
![]() |
f7ea137f32 | ||
![]() |
73374200b7 | ||
![]() |
0506fba90c | ||
![]() |
e9b873b8d2 | ||
![]() |
ff6862b9dd | ||
![]() |
def3bfef5b | ||
![]() |
fc782c44e9 | ||
![]() |
e26a2e297f | ||
![]() |
3e7b91fc0c | ||
![]() |
9b0b031b2d | ||
![]() |
0b081bb4d3 | ||
![]() |
623ddcf0dc | ||
![]() |
7fe65e7bd7 | ||
![]() |
ef58895b90 | ||
![]() |
7b1378701b | ||
![]() |
bcd225fe31 | ||
![]() |
1ad86b878a | ||
![]() |
4232ea911f | ||
![]() |
b7d92249dd | ||
![]() |
9891ba29bb | ||
![]() |
3090bdcc00 | ||
![]() |
9e53bea7f8 | ||
![]() |
ec9a1dda96 | ||
![]() |
212eb1d802 | ||
![]() |
bc42367841 | ||
![]() |
15976105df | ||
![]() |
c2aa314395 | ||
![]() |
5448576511 | ||
![]() |
2ef3e93a42 | ||
![]() |
552a818cd1 | ||
![]() |
43e56ef014 | ||
![]() |
5d51554518 | ||
![]() |
83f34527ba | ||
![]() |
2cfdcc7d5d | ||
![]() |
2f14a3e4dd | ||
![]() |
4072999480 | ||
![]() |
97d4cb2bf6 | ||
![]() |
56264ce3cf | ||
![]() |
73eb5b3d5d | ||
![]() |
50b89cd4e4 | ||
![]() |
a734f1c935 | ||
![]() |
6b39c26dd0 | ||
![]() |
3726bc7b9e | ||
![]() |
72733afb23 | ||
![]() |
2fc3355246 | ||
![]() |
62baa43e9f | ||
![]() |
3ed0782ca8 | ||
![]() |
02358ae735 | ||
![]() |
cb16eb37a4 | ||
![]() |
9f1a8ad29d | ||
![]() |
b07bcf678c | ||
![]() |
f0e65b9aa0 | ||
![]() |
2facabc351 | ||
![]() |
7642a4b3bb | ||
![]() |
74283a8f8e | ||
![]() |
f7a0e566e0 | ||
![]() |
bcf26fabd1 | ||
![]() |
e72173979e | ||
![]() |
68d0ec4c71 | ||
![]() |
23e63e623a | ||
![]() |
48b42b2ad5 | ||
![]() |
33209cb4e6 | ||
![]() |
be7b2a27ae | ||
![]() |
519413f155 | ||
![]() |
a621cef6ea | ||
![]() |
83cbace83b | ||
![]() |
778c7fc979 | ||
![]() |
ab9340eb4d | ||
![]() |
aa89468337 | ||
![]() |
f529ba09a4 | ||
![]() |
56107ab6e6 | ||
![]() |
f8c99d2582 | ||
![]() |
fe68e449bc | ||
![]() |
d7f66d92dc | ||
![]() |
5c1626c420 | ||
![]() |
29f296a479 | ||
![]() |
222c6ef111 | ||
![]() |
0abb21de3d | ||
![]() |
c6928ae319 | ||
![]() |
a865dee46a | ||
![]() |
215169c08e | ||
![]() |
8fa1141494 | ||
![]() |
5a371905c5 | ||
![]() |
2c5d683d57 | ||
![]() |
d512d90224 | ||
![]() |
1cd8999589 | ||
![]() |
7f46a76ed5 | ||
![]() |
ee7f6ef896 | ||
![]() |
330189fa4e | ||
![]() |
08fd7f0475 | ||
![]() |
75ed38bcba | ||
![]() |
1901c0d52c | ||
![]() |
69e3fde654 | ||
![]() |
57ce230fce | ||
![]() |
2f253d8c9e | ||
![]() |
47bdf734cb | ||
![]() |
8ec16c9cc6 | ||
![]() |
605b392e3c | ||
![]() |
1c66b8b8c4 | ||
![]() |
15f405b385 | ||
![]() |
3637551cd7 | ||
![]() |
4b6d5d069e | ||
![]() |
1b9a17e243 | ||
![]() |
d4d35ee8e9 | ||
![]() |
d956433d6b | ||
![]() |
d9e5e269a0 | ||
![]() |
4a69e59d98 | ||
![]() |
276ac4137c | ||
![]() |
4352e3d7ef | ||
![]() |
faaaac446a | ||
![]() |
283d8a36df | ||
![]() |
913373e56d | ||
![]() |
bc8535bbca | ||
![]() |
eb9bef00ca | ||
![]() |
2dc6b5d91d | ||
![]() |
17777f68b7 | ||
![]() |
dac08538b0 | ||
![]() |
a5946ec7db | ||
![]() |
c9d73a2ad4 | ||
![]() |
9d464fe8a8 | ||
![]() |
0c2158c3dc | ||
![]() |
fa22e1b272 | ||
![]() |
e6ec5997ee | ||
![]() |
c45eef1114 | ||
![]() |
c92eb17486 | ||
![]() |
ca227ef077 | ||
![]() |
460770e9d8 | ||
![]() |
c4915fabd9 | ||
![]() |
737c497e66 |
@@ -15,7 +15,8 @@ using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
StandardEvent::StandardEvent() : BaseEvent() {}
|
||||
StandardEvent::StandardEvent()
|
||||
: BaseEvent(), variables(gd::VariablesContainer::SourceType::Local) {}
|
||||
|
||||
StandardEvent::~StandardEvent(){};
|
||||
|
||||
@@ -57,6 +58,9 @@ void StandardEvent::SerializeTo(SerializerElement& element) const {
|
||||
if (!events.IsEmpty())
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
if (HasVariables()) {
|
||||
variables.SerializeTo(element.AddChild("variables"));
|
||||
}
|
||||
}
|
||||
|
||||
void StandardEvent::UnserializeFrom(gd::Project& project,
|
||||
@@ -71,6 +75,11 @@ void StandardEvent::UnserializeFrom(gd::Project& project,
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
}
|
||||
|
||||
variables.Clear();
|
||||
if (element.HasChild("variables")) {
|
||||
variables.UnserializeFrom(element.GetChild("variables"));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -4,13 +4,13 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef GDCORE_STANDARDEVENT_H
|
||||
#define GDCORE_STANDARDEVENT_H
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Events/InstructionsList.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
namespace gd {
|
||||
class Instruction;
|
||||
class Project;
|
||||
@@ -33,6 +33,10 @@ class GD_CORE_API StandardEvent : public gd::BaseEvent {
|
||||
virtual const gd::EventsList& GetSubEvents() const { return events; };
|
||||
virtual gd::EventsList& GetSubEvents() { return events; };
|
||||
|
||||
virtual bool CanHaveVariables() const { return true; }
|
||||
virtual const gd::VariablesContainer& GetVariables() const { return variables; };
|
||||
virtual gd::VariablesContainer& GetVariables() { return variables; };
|
||||
|
||||
const gd::InstructionsList& GetConditions() const { return conditions; };
|
||||
gd::InstructionsList& GetConditions() { return conditions; };
|
||||
|
||||
@@ -53,9 +57,7 @@ class GD_CORE_API StandardEvent : public gd::BaseEvent {
|
||||
gd::InstructionsList conditions;
|
||||
gd::InstructionsList actions;
|
||||
EventsList events;
|
||||
VariablesContainer variables;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_STANDARDEVENT_H
|
||||
#endif
|
||||
|
@@ -3,8 +3,8 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef EVENTSCODEGENERATIONCONTEXT_H
|
||||
#define EVENTSCODEGENERATIONCONTEXT_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
@@ -325,4 +325,3 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
#endif // EVENTSCODEGENERATIONCONTEXT_H
|
||||
|
@@ -254,12 +254,12 @@ gd::String EventsCodeGenerator::GenerateMutatorCall(
|
||||
}
|
||||
|
||||
gd::String operatorStr = arguments[operatorIndex];
|
||||
if (operatorStr.size() > 2)
|
||||
if (operatorStr.size() > 2 && operatorStr[0] == '\"') {
|
||||
operatorStr = operatorStr.substr(
|
||||
1,
|
||||
operatorStr.length() - 1 -
|
||||
1); // Operator contains quote which must be removed.
|
||||
|
||||
}
|
||||
auto mutators = instrInfos.codeExtraInformation.optionalMutators;
|
||||
auto mutator = mutators.find(operatorStr);
|
||||
if (mutator == mutators.end()) {
|
||||
@@ -279,6 +279,9 @@ gd::String EventsCodeGenerator::GenerateMutatorCall(
|
||||
argumentsStr += arguments[i];
|
||||
}
|
||||
}
|
||||
if (instrInfos.GetManipulatedType() == "boolean") {
|
||||
return callStartString + "(" + argumentsStr + ")." + mutator->second;
|
||||
}
|
||||
|
||||
return callStartString + "(" + argumentsStr + ")." + mutator->second + "(" +
|
||||
rhs + ")";
|
||||
@@ -583,6 +586,12 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
return actionCode;
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateLocalVariablesStackAccessor() {
|
||||
return (HasProjectAndLayout() ? GetCodeNamespace()
|
||||
: "eventsFunctionContext") +
|
||||
".localVariables";
|
||||
}
|
||||
|
||||
const EventsCodeGenerator::CallbackDescriptor
|
||||
EventsCodeGenerator::GenerateCallback(
|
||||
const gd::String& callbackID,
|
||||
@@ -607,14 +616,20 @@ EventsCodeGenerator::GenerateCallback(
|
||||
actionsCode += "} //End of subevents\n";
|
||||
}
|
||||
|
||||
gd::String restoreLocalVariablesCode;
|
||||
restoreLocalVariablesCode +=
|
||||
"asyncObjectsList.restoreLocalVariablesContainers(" +
|
||||
GenerateLocalVariablesStackAccessor() + ");\n";
|
||||
|
||||
// Compose the callback function and add outside main
|
||||
const gd::String actionsDeclarationsCode =
|
||||
GenerateObjectsDeclarationCode(callbackContext);
|
||||
|
||||
const gd::String callbackCode = callbackFunctionName + " = function (" +
|
||||
GenerateEventsParameters(callbackContext) +
|
||||
") {\n" + actionsDeclarationsCode +
|
||||
actionsCode + "}\n";
|
||||
const gd::String callbackCode =
|
||||
callbackFunctionName + " = function (" +
|
||||
GenerateEventsParameters(callbackContext) + ") {\n" +
|
||||
restoreLocalVariablesCode +
|
||||
actionsDeclarationsCode + actionsCode + "}\n";
|
||||
|
||||
AddCustomCodeOutsideMain(callbackCode);
|
||||
|
||||
@@ -677,13 +692,13 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
|
||||
if (ParameterMetadata::IsExpression("number", metadata.GetType())) {
|
||||
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, "number", parameter, lastObjectName);
|
||||
*this, context, "number", parameter, lastObjectName, metadata.GetExtraInfo());
|
||||
} else if (ParameterMetadata::IsExpression("string", metadata.GetType())) {
|
||||
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, "string", parameter, lastObjectName);
|
||||
*this, context, "string", parameter, lastObjectName, metadata.GetExtraInfo());
|
||||
} else if (ParameterMetadata::IsExpression("variable", metadata.GetType())) {
|
||||
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, metadata.GetType(), parameter, lastObjectName);
|
||||
*this, context, metadata.GetType(), parameter, lastObjectName, metadata.GetExtraInfo());
|
||||
} else if (ParameterMetadata::IsObject(metadata.GetType())) {
|
||||
// It would be possible to run a gd::ExpressionCodeGenerator if later
|
||||
// objects can have nested objects, or function returning objects.
|
||||
@@ -695,7 +710,8 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
} else if (metadata.GetType() == "operator") {
|
||||
argOutput += parameter.GetPlainString();
|
||||
if (argOutput != "=" && argOutput != "+" && argOutput != "-" &&
|
||||
argOutput != "/" && argOutput != "*") {
|
||||
argOutput != "/" && argOutput != "*" && argOutput != "True" &&
|
||||
argOutput != "False" && argOutput != "Toggle") {
|
||||
cout << "Warning: Bad operator: Set to = by default." << endl;
|
||||
argOutput = "=";
|
||||
}
|
||||
@@ -865,6 +881,11 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(
|
||||
gd::EventsList& events, EventsCodeGenerationContext& parentContext) {
|
||||
gd::String output;
|
||||
for (std::size_t eId = 0; eId < events.size(); ++eId) {
|
||||
auto& event = events[eId];
|
||||
if (event.HasVariables()) {
|
||||
GetProjectScopedContainers().GetVariablesContainersList().Push(event.GetVariables());
|
||||
}
|
||||
|
||||
// Each event has its own context : Objects picked in an event are totally
|
||||
// different than the one picked in another.
|
||||
gd::EventsCodeGenerationContext newContext;
|
||||
@@ -885,13 +906,17 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(
|
||||
|
||||
auto& context = reuseParentContext ? reusedContext : newContext;
|
||||
|
||||
gd::String eventCoreCode = events[eId].GenerateEventCode(*this, context);
|
||||
gd::String eventCoreCode = event.GenerateEventCode(*this, context);
|
||||
gd::String scopeBegin = GenerateScopeBegin(context);
|
||||
gd::String scopeEnd = GenerateScopeEnd(context);
|
||||
gd::String declarationsCode = GenerateObjectsDeclarationCode(context);
|
||||
|
||||
output += "\n" + scopeBegin + "\n" + declarationsCode + "\n" +
|
||||
eventCoreCode + "\n" + scopeEnd + "\n";
|
||||
|
||||
if (event.HasVariables()) {
|
||||
GetProjectScopedContainers().GetVariablesContainersList().Pop();
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
@@ -1067,7 +1092,8 @@ gd::String EventsCodeGenerator::GenerateFreeAction(
|
||||
// Generate call
|
||||
gd::String call;
|
||||
if (instrInfos.codeExtraInformation.type == "number" ||
|
||||
instrInfos.codeExtraInformation.type == "string") {
|
||||
instrInfos.codeExtraInformation.type == "string" ||
|
||||
instrInfos.codeExtraInformation.type == "boolean") {
|
||||
if (instrInfos.codeExtraInformation.accessType ==
|
||||
gd::InstructionMetadata::ExtraInformation::MutatorAndOrAccessor)
|
||||
call = GenerateOperatorCall(
|
||||
|
@@ -336,6 +336,16 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Give access to the project scoped containers as code generation might
|
||||
* push and pop variable containers (for local variables).
|
||||
* This could be passed as a parameter recursively in code generation, but this requires
|
||||
* heavy refactoring. Instead, we use this single instance.
|
||||
*/
|
||||
gd::ProjectScopedContainers& GetProjectScopedContainers() {
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the code generation is done for a given project and
|
||||
* layout. If not, this means that the code is generated for a function.
|
||||
@@ -448,7 +458,7 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
*/
|
||||
virtual gd::String GetCodeNamespace() { return ""; };
|
||||
|
||||
enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE };
|
||||
enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE, ANY_VARIABLE };
|
||||
|
||||
/**
|
||||
* Generate a single unique number for the specified instruction.
|
||||
@@ -478,6 +488,11 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
const gd::String& lhs,
|
||||
const gd::String& rhs);
|
||||
|
||||
/**
|
||||
* \brief Generate the code to access the local variables stack.
|
||||
*/
|
||||
virtual gd::String GenerateLocalVariablesStackAccessor();
|
||||
|
||||
protected:
|
||||
virtual const gd::String GenerateRelationalOperatorCodes(
|
||||
const gd::String& operatorString);
|
||||
@@ -534,11 +549,15 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
const VariableScope& scope,
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
const gd::String& objectName) {
|
||||
// This code is only used as a mock.
|
||||
// See the real implementation in GDJS.
|
||||
if (scope == LAYOUT_VARIABLE) {
|
||||
return "getLayoutVariable(" + variableName + ")";
|
||||
|
||||
} else if (scope == PROJECT_VARIABLE) {
|
||||
return "getProjectVariable(" + variableName + ")";
|
||||
} else if (scope == ANY_VARIABLE) {
|
||||
return "getAnyVariable(" + variableName + ")";
|
||||
}
|
||||
|
||||
return "getVariableForObject(" + objectName + ", " + variableName + ")";
|
||||
|
@@ -39,7 +39,8 @@ gd::String ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
EventsCodeGenerationContext& context,
|
||||
const gd::String& rootType,
|
||||
const gd::Expression& expression,
|
||||
const gd::String& rootObjectName) {
|
||||
const gd::String& rootObjectName,
|
||||
const gd::String& extraInfo) {
|
||||
ExpressionCodeGenerator generator(rootType, rootObjectName, codeGenerator, context);
|
||||
|
||||
auto node = expression.GetRootNode();
|
||||
@@ -52,7 +53,8 @@ gd::String ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
|
||||
gd::ExpressionValidator validator(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetProjectScopedContainers(),
|
||||
rootType);
|
||||
rootType,
|
||||
extraInfo);
|
||||
node->Visit(validator);
|
||||
if (!validator.GetFatalErrors().empty()) {
|
||||
std::cout << "Error: \"" << validator.GetFatalErrors()[0]->GetMessage()
|
||||
@@ -110,11 +112,13 @@ void ExpressionCodeGenerator::OnVisitVariableNode(VariableNode& node) {
|
||||
if (gd::ParameterMetadata::IsExpression("variable", type)) {
|
||||
// The node is a variable inside an expression waiting for a *variable* to be returned, not its value.
|
||||
EventsCodeGenerator::VariableScope scope =
|
||||
type == "globalvar"
|
||||
type == "variable"
|
||||
? gd::EventsCodeGenerator::ANY_VARIABLE
|
||||
: type == "globalvar"
|
||||
? gd::EventsCodeGenerator::PROJECT_VARIABLE
|
||||
: ((type == "scenevar")
|
||||
: type == "scenevar"
|
||||
? gd::EventsCodeGenerator::LAYOUT_VARIABLE
|
||||
: gd::EventsCodeGenerator::OBJECT_VARIABLE);
|
||||
: gd::EventsCodeGenerator::OBJECT_VARIABLE;
|
||||
|
||||
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetObjectsContainersList(),
|
||||
@@ -137,19 +141,8 @@ void ExpressionCodeGenerator::OnVisitVariableNode(VariableNode& node) {
|
||||
|
||||
output += codeGenerator.GenerateVariableValueAs(type);
|
||||
}, [&]() {
|
||||
if (!codeGenerator.HasProjectAndLayout()) {
|
||||
gd::LogWarning("Tried to generate access to a variable without a project/scene - the code generator only works for global and scene variables for now.");
|
||||
output += GenerateDefaultValue(type);
|
||||
return;
|
||||
}
|
||||
|
||||
// This could be adapted in the future if more scopes are supported.
|
||||
EventsCodeGenerator::VariableScope scope = gd::EventsCodeGenerator::PROJECT_VARIABLE;
|
||||
if (codeGenerator.GetProjectScopedContainers().GetVariablesContainersList().GetBottomMostVariablesContainer()->Has(node.name)) {
|
||||
scope = gd::EventsCodeGenerator::LAYOUT_VARIABLE;
|
||||
}
|
||||
|
||||
output += codeGenerator.GenerateGetVariable(node.name, scope, context, "");
|
||||
output += codeGenerator.GenerateGetVariable(
|
||||
node.name, gd::EventsCodeGenerator::ANY_VARIABLE, context, "");
|
||||
if (node.child) node.child->Visit(*this);
|
||||
output += codeGenerator.GenerateVariableValueAs(type);
|
||||
}, [&]() {
|
||||
@@ -209,11 +202,13 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
|
||||
codeGenerator.GenerateObject(node.identifierName, type, context);
|
||||
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
|
||||
EventsCodeGenerator::VariableScope scope =
|
||||
type == "globalvar"
|
||||
type == "variable"
|
||||
? gd::EventsCodeGenerator::ANY_VARIABLE
|
||||
: type == "globalvar"
|
||||
? gd::EventsCodeGenerator::PROJECT_VARIABLE
|
||||
: ((type == "scenevar")
|
||||
: type == "scenevar"
|
||||
? gd::EventsCodeGenerator::LAYOUT_VARIABLE
|
||||
: gd::EventsCodeGenerator::OBJECT_VARIABLE);
|
||||
: gd::EventsCodeGenerator::OBJECT_VARIABLE;
|
||||
|
||||
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetObjectsContainersList(),
|
||||
@@ -236,19 +231,9 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
|
||||
node.childIdentifierName, gd::EventsCodeGenerator::OBJECT_VARIABLE, context, node.identifierName);
|
||||
output += codeGenerator.GenerateVariableValueAs(type);
|
||||
}, [&]() {
|
||||
if (!codeGenerator.HasProjectAndLayout()) {
|
||||
gd::LogWarning("Tried to generate access to a variable without a project/scene - the code generator only works for global and scene variables for now.");
|
||||
output += GenerateDefaultValue(type);
|
||||
return;
|
||||
}
|
||||
|
||||
// This could be adapted in the future if more scopes are supported at runtime.
|
||||
EventsCodeGenerator::VariableScope scope = gd::EventsCodeGenerator::PROJECT_VARIABLE;
|
||||
if (variablesContainersList.GetBottomMostVariablesContainer()->Has(node.identifierName)) {
|
||||
scope = gd::EventsCodeGenerator::LAYOUT_VARIABLE;
|
||||
}
|
||||
|
||||
output += codeGenerator.GenerateGetVariable(node.identifierName, scope, context, "");
|
||||
output += codeGenerator.GenerateGetVariable(
|
||||
node.identifierName, gd::EventsCodeGenerator::ANY_VARIABLE, context,
|
||||
"");
|
||||
if (!node.childIdentifierName.empty()) {
|
||||
output += codeGenerator.GenerateVariableAccessor(node.childIdentifierName);
|
||||
}
|
||||
|
@@ -59,7 +59,8 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
|
||||
EventsCodeGenerationContext& context,
|
||||
const gd::String& type,
|
||||
const gd::Expression& expression,
|
||||
const gd::String& objectName = "");
|
||||
const gd::String& objectName = "",
|
||||
const gd::String& extraInfo = "");
|
||||
|
||||
const gd::String& GetOutput() { return output; };
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
namespace gd {
|
||||
|
||||
EventsList BaseEvent::badSubEvents;
|
||||
VariablesContainer BaseEvent::badLocalVariables;
|
||||
std::vector<gd::String> BaseEvent::emptyDependencies;
|
||||
gd::String BaseEvent::emptySourceFile;
|
||||
|
||||
@@ -28,6 +29,8 @@ BaseEvent::BaseEvent()
|
||||
|
||||
bool BaseEvent::HasSubEvents() const { return !GetSubEvents().IsEmpty(); }
|
||||
|
||||
bool BaseEvent::HasVariables() const { return GetVariables().Count() > 0; }
|
||||
|
||||
gd::String BaseEvent::GenerateEventCode(
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
|
@@ -3,9 +3,7 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef GDCORE_EVENT_H
|
||||
#define GDCORE_EVENT_H
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
@@ -26,6 +24,7 @@ class SerializerElement;
|
||||
class Instruction;
|
||||
class EventVisitor;
|
||||
class ReadOnlyEventVisitor;
|
||||
class VariablesContainer;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -92,6 +91,32 @@ class GD_CORE_API BaseEvent {
|
||||
*/
|
||||
bool HasSubEvents() const;
|
||||
|
||||
/**
|
||||
* Derived class have to redefine this function, so as to return true, if they
|
||||
* can have local variables.
|
||||
*/
|
||||
virtual bool CanHaveVariables() const { return false; }
|
||||
|
||||
/**
|
||||
* Return the local variables, if applicable.
|
||||
*/
|
||||
virtual const gd::VariablesContainer& GetVariables() const {
|
||||
return badLocalVariables;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the local variables, if applicable.
|
||||
*/
|
||||
virtual gd::VariablesContainer& GetVariables() {
|
||||
return badLocalVariables;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Return true if the events has local variables.
|
||||
* \warning This is only applicable when CanHaveVariables() return true.
|
||||
*/
|
||||
bool HasVariables() const;
|
||||
|
||||
/**
|
||||
* \brief Return a list of all conditions of the event.
|
||||
* \note Used to preprocess or search in the conditions.
|
||||
@@ -301,6 +326,7 @@ class GD_CORE_API BaseEvent {
|
||||
///< Used for saving the event for instance.
|
||||
|
||||
static gd::EventsList badSubEvents;
|
||||
static gd::VariablesContainer badLocalVariables;
|
||||
static std::vector<gd::String> emptyDependencies;
|
||||
static gd::String emptySourceFile;
|
||||
};
|
||||
@@ -325,6 +351,3 @@ class EmptyEvent : public BaseEvent {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EVENT_H
|
||||
#endif
|
||||
|
@@ -417,6 +417,93 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.SetDefaultValue("\"\"")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("SetNumberObjectVariable",
|
||||
_("Change variable value"),
|
||||
_("Modify the number value of an object variable."),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("number",
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction("SetStringObjectVariable",
|
||||
_("Change text variable"),
|
||||
_("Modify the text of an object variable."),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("string",
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction("SetBooleanObjectVariable",
|
||||
_("Change boolean variable"),
|
||||
_("Modify the boolean value of an object variable."),
|
||||
_("Change the variable _PARAM1_ of _PARAM0_: _PARAM2_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("operator", _("Value"), "boolean")
|
||||
// This parameter allows to keep the operand expression
|
||||
// when the editor switch between variable instructions.
|
||||
.AddCodeOnlyParameter("yesorno", _("Value"))
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddCondition("NumberObjectVariable",
|
||||
_("Variable value"),
|
||||
_("Compare the number value of an object variable."),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddCondition("StringObjectVariable",
|
||||
_("Text variable"),
|
||||
_("Compare the text of an object variable."),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddCondition("BooleanObjectVariable",
|
||||
_("Boolean variable"),
|
||||
_("Compare the boolean value of an object variable."),
|
||||
_("The variable _PARAM1_ of _PARAM0_ is _PARAM2_"),
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("Check if the value is"))
|
||||
.SetDefaultValue("true")
|
||||
// This parameter allows to keep the operand expression
|
||||
// when the editor switch between variable instructions.
|
||||
.AddCodeOnlyParameter("yesorno", _("Value"))
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction("ModVarObjet",
|
||||
_("Change number variable"),
|
||||
_("Modify the number value of an object variable."),
|
||||
@@ -428,7 +515,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("number",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction("ModVarObjetTxt",
|
||||
_("Change text variable"),
|
||||
@@ -441,7 +529,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("string",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction("SetObjectVariableAsBoolean",
|
||||
_("Change boolean variable"),
|
||||
@@ -454,7 +543,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("New Value:"));
|
||||
.AddParameter("trueorfalse", _("New Value:"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction(
|
||||
"ToggleObjectVariableAsBoolean",
|
||||
@@ -469,7 +559,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/actions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"));
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddCondition("ObjectVariableChildExists",
|
||||
_("Child existence"),
|
||||
@@ -657,7 +748,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions());
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddCondition("VarObjetTxt",
|
||||
_("Text variable"),
|
||||
@@ -670,7 +762,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", ParameterOptions::MakeNewOptions());
|
||||
"string", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddCondition("ObjectVariableAsBoolean",
|
||||
_("Boolean variable"),
|
||||
@@ -683,7 +776,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("Check if the value is"))
|
||||
.SetDefaultValue("true");
|
||||
.SetDefaultValue("true")
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddCondition("VarObjetDef",
|
||||
"Variable defined",
|
||||
@@ -697,6 +791,47 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("string", _("Variable"))
|
||||
.SetHidden(); // Deprecated.
|
||||
|
||||
obj.AddAction(
|
||||
"PushStringToObjectVariable",
|
||||
_("Add text variable"),
|
||||
_("Adds a text (string) to the end of an object array variable."),
|
||||
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction("PushNumberToObjectVariable",
|
||||
_("Add variable array value"),
|
||||
_("Adds a number to the end of an object array variable."),
|
||||
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction(
|
||||
"PushBooleanToObjectVariable",
|
||||
_("Add boolean variable"),
|
||||
_("Adds a boolean to the end of an object array variable."),
|
||||
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction(
|
||||
"ObjectVariablePush",
|
||||
_("Add existing variable"),
|
||||
@@ -724,7 +859,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction("ObjectVariablePushNumber",
|
||||
_("Add number variable"),
|
||||
@@ -736,7 +872,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction(
|
||||
"ObjectVariablePushBool",
|
||||
@@ -749,7 +886,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction(
|
||||
"ObjectVariableRemoveAt",
|
||||
@@ -1203,7 +1341,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"));
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddExpression(
|
||||
"VariableChildCount",
|
||||
|
@@ -25,29 +25,275 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Variables"))
|
||||
.SetIcon("res/conditions/var24.png");
|
||||
|
||||
extension
|
||||
.AddCondition("NumberVariable",
|
||||
_("Variable value"),
|
||||
_("Compare the number value of a variable."),
|
||||
_("The variable _PARAM0_"),
|
||||
"",
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions());
|
||||
|
||||
extension
|
||||
.AddCondition("StringVariable",
|
||||
_("Variable value"),
|
||||
_("Compare the text (string) of a variable."),
|
||||
_("The variable _PARAM0_"),
|
||||
"",
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", ParameterOptions::MakeNewOptions());
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"BooleanVariable",
|
||||
_("Variable value"),
|
||||
_("Compare the boolean value of a variable."),
|
||||
_("The variable _PARAM0_ is _PARAM1_"),
|
||||
"",
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("Check if the value is"))
|
||||
.SetDefaultValue("true")
|
||||
// This parameter allows to keep the operand expression
|
||||
// when the editor switch between variable instructions.
|
||||
.AddCodeOnlyParameter("trueorfalse", "");
|
||||
|
||||
extension
|
||||
.AddAction("SetNumberVariable",
|
||||
_("Change variable value"),
|
||||
_("Modify the number value of a variable."),
|
||||
_("the variable _PARAM0_"),
|
||||
"",
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.UseStandardOperatorParameters("number",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
|
||||
extension
|
||||
.AddAction("SetStringVariable",
|
||||
_("Change text variable"),
|
||||
_("Modify the text (string) of a variable."),
|
||||
_("the variable _PARAM0_"),
|
||||
"",
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.UseStandardOperatorParameters("string",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"SetBooleanVariable",
|
||||
_("Change boolean variable"),
|
||||
_("Modify the boolean value of a variable."),
|
||||
_("Change the variable _PARAM0_: _PARAM1_"),
|
||||
"",
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.AddParameter("operator", _("Value"), "boolean")
|
||||
// This parameter allows to keep the operand expression
|
||||
// when the editor switch between variable instructions.
|
||||
.AddCodeOnlyParameter("trueorfalse", "");
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"VariableChildCount",
|
||||
_("Number of children"),
|
||||
_("Compare the number of children in an array variable."),
|
||||
_("The number of children in the array variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("VariableChildExists2",
|
||||
_("Child existence"),
|
||||
_("Check if the specified child of the structure "
|
||||
"variable exists."),
|
||||
_("Child _PARAM1_ of variable _PARAM0_ exists"),
|
||||
_("Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.AddParameter("string", _("Name of the child"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"RemoveVariableChild",
|
||||
_("Remove a child"),
|
||||
_("Remove a child from a structure variable."),
|
||||
_("Remove child _PARAM1_ from structure variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Structure variable"))
|
||||
.AddParameter("string", _("Child's name"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("ClearVariableChildren",
|
||||
_("Clear children"),
|
||||
_("Remove all the children from the structure or array "
|
||||
"variable."),
|
||||
_("Clear children from variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Structure or array variable"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("PushVariable",
|
||||
_("Add existing variable"),
|
||||
_("Adds an existing variable at the end of an array "
|
||||
"variable."),
|
||||
_("Add variable _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.AddParameter("variable", _("Variable with the content to add"))
|
||||
.SetParameterLongDescription(
|
||||
_("The content of the variable will *be copied* and added at the "
|
||||
"end of the array."))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"PushString",
|
||||
_("Add text variable"),
|
||||
_("Adds a text (string) at the end of a array variable."),
|
||||
_("Add the value _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("PushNumber",
|
||||
_("Add variable array value"),
|
||||
_("Adds a number at the end of an array variable."),
|
||||
_("Add the value _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("PushBoolean",
|
||||
_("Add boolean variable"),
|
||||
_("Adds a boolean at the end of an array variable."),
|
||||
_("Add the value _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("RemoveVariableAt",
|
||||
_("Remove variable by index"),
|
||||
_("Removes a variable at the specified index of an array "
|
||||
"variable."),
|
||||
_("Remove variable at index _PARAM1_ from array "
|
||||
"variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.AddParameter("expression", _("Index to remove"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddStrExpression(
|
||||
"VariableFirstString",
|
||||
_("First text child"),
|
||||
_("Get the value of the first element of an array variable, if "
|
||||
"it is a text (string)."),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
"VariableFirstNumber",
|
||||
_("First number child"),
|
||||
_("Get the value of the first element of an array variable, if "
|
||||
"it is a number."),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
extension
|
||||
.AddStrExpression(
|
||||
"VariableLastString",
|
||||
_("Last text child"),
|
||||
_("Get the value of the last element of an array variable, if "
|
||||
"it is a text (string)."),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
"VariableLastNumber",
|
||||
_("Last number child"),
|
||||
_("Get the value of the last element of an array variable, if "
|
||||
"it is a number."),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
// Legacy instructions
|
||||
|
||||
extension
|
||||
.AddCondition("VarScene",
|
||||
_("Number variable"),
|
||||
_("Compare the number value of a scene variable."),
|
||||
_("The number of scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions());
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddCondition("VarSceneTxt",
|
||||
_("Text variable"),
|
||||
_("Compare the text (string) of a scene variable."),
|
||||
_("The text of scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", ParameterOptions::MakeNewOptions());
|
||||
"string", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
@@ -55,12 +301,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Boolean variable"),
|
||||
_("Compare the boolean value of a scene variable."),
|
||||
_("The boolean value of scene variable _PARAM0_ is _PARAM1_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("Check if the value is"))
|
||||
.SetDefaultValue("true");
|
||||
.SetDefaultValue("true")
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddCondition("VariableChildExists",
|
||||
@@ -68,11 +315,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Check if the specified child of the scene structure "
|
||||
"variable exists."),
|
||||
_("Child _PARAM1_ of scene variable _PARAM0_ exists"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddParameter("string", _("Name of the child"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -81,11 +329,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Check if the specified child of the global structure "
|
||||
"variable exists."),
|
||||
_("Child _PARAM1_ of global variable _PARAM0_ exists"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddParameter("string", _("Name of the child"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -93,7 +342,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
"Variable defined",
|
||||
"Test if the scene variable exists.",
|
||||
"Scene variable _PARAM0_ is defined",
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
@@ -105,12 +354,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Number variable"),
|
||||
_("Compare the number value of a global variable."),
|
||||
_("the global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -118,12 +368,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Text variable"),
|
||||
_("Compare the text (string) of a global variable."),
|
||||
_("the text of the global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -132,19 +383,20 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Boolean variable"),
|
||||
_("Compare the boolean value of a global variable."),
|
||||
_("The boolean value of global variable _PARAM0_ is _PARAM1_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("Check if the value is"))
|
||||
.SetDefaultValue("true");
|
||||
.SetDefaultValue("true")
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddCondition("VarGlobalDef",
|
||||
"Variable defined",
|
||||
"Test if a global variable exists.",
|
||||
"Global variable _PARAM0_ is defined",
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
@@ -157,24 +409,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Change number variable"),
|
||||
_("Modify the number value of a scene variable."),
|
||||
_("the scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.UseStandardOperatorParameters("number",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction("ModVarSceneTxt",
|
||||
_("Change text variable"),
|
||||
_("Modify the text (string) of a scene variable."),
|
||||
_("the text of scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.UseStandardOperatorParameters("string",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
@@ -182,11 +436,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Change boolean variable"),
|
||||
_("Modify the boolean value of a scene variable."),
|
||||
_("Set the boolean value of scene variable _PARAM0_ to _PARAM1_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("New Value:"));
|
||||
.AddParameter("trueorfalse", _("New Value:"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction("ToggleSceneVariableAsBoolean",
|
||||
@@ -195,22 +450,24 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("If it was true, it will become false, and if it was "
|
||||
"false it will become true."),
|
||||
_("Toggle the boolean value of scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"));
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction("ModVarGlobal",
|
||||
_("Change number variable"),
|
||||
_("Modify the number value of a global variable."),
|
||||
_("the global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("number",
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -218,12 +475,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Change text variable"),
|
||||
_("Modify the text (string) of a global variable."),
|
||||
_("the text of global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("string",
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -232,11 +490,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Change boolean variable"),
|
||||
_("Modify the boolean value of a global variable."),
|
||||
_("Set the boolean value of global variable _PARAM0_ to _PARAM1_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("New Value:"));
|
||||
.AddParameter("trueorfalse", _("New Value:"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction("ToggleGlobalVariableAsBoolean",
|
||||
@@ -245,10 +504,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("If it was true, it will become false, and if it was "
|
||||
"false it will become true."),
|
||||
_("Toggle the boolean value of global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"));
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
@@ -256,12 +516,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Remove a child"),
|
||||
_("Remove a child from a scene structure variable."),
|
||||
_("Remove child _PARAM1_ from scene structure variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Structure variable"))
|
||||
.AddParameter("string", _("Child's name"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
@@ -269,12 +530,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Remove a child"),
|
||||
_("Remove a child from a global structure variable."),
|
||||
_("Remove child _PARAM1_ from global structure variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Structure variable"))
|
||||
.AddParameter("string", _("Child's name"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction("VariableClearChildren",
|
||||
@@ -282,10 +544,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Remove all the children from the scene structure or array "
|
||||
"variable."),
|
||||
_("Clear children from scene variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Structure or array variable"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -294,10 +557,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Remove all the children from the global structure or array "
|
||||
"variable."),
|
||||
_("Clear children from global variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Structure or array variable"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -306,7 +570,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Adds an existing variable at the end of a scene array "
|
||||
"variable."),
|
||||
_("Add variable _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
@@ -314,6 +578,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
.SetParameterLongDescription(
|
||||
_("The content of the variable will *be copied* and added at the "
|
||||
"end of the array."))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -322,11 +587,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add text variable"),
|
||||
_("Adds a text (string) at the end of a scene array variable."),
|
||||
_("Add text _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -334,11 +600,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add number variable"),
|
||||
_("Adds a number at the end of a scene array variable."),
|
||||
_("Add number _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -346,11 +613,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add boolean variable"),
|
||||
_("Adds a boolean at the end of a scene array variable."),
|
||||
_("Add boolean _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -360,11 +628,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
"variable."),
|
||||
_("Remove variable at index _PARAM1_ from scene array "
|
||||
"variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("expression", _("Index to remove"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -373,12 +642,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Number of children"),
|
||||
_("Compare the number of children in a scene array variable."),
|
||||
_("The number of children in the array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -387,9 +657,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("First text child"),
|
||||
_("Get the value of the first element of a scene array variable, if "
|
||||
"it is a text (string)."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
@@ -397,9 +668,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("First number child"),
|
||||
_("Get the value of the first element of a scene array variable, if "
|
||||
"it is a number."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddStrExpression(
|
||||
@@ -407,9 +679,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Last text child"),
|
||||
_("Get the value of the last element of a scene array variable, if "
|
||||
"it is a text (string)."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
@@ -417,9 +690,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Last number child"),
|
||||
_("Get the value of the last element of a scene array variable, if "
|
||||
"it is a number."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
@@ -427,7 +701,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add existing variable"),
|
||||
_("Adds an existing variable at the end of a global array variable."),
|
||||
_("Add variable _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
@@ -435,6 +709,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
.SetParameterLongDescription(
|
||||
_("The content of the variable will *be copied* and added at the "
|
||||
"end of the array."))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -444,11 +719,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
"array variable."),
|
||||
_("Remove variable at index _PARAM1_ from global array "
|
||||
"variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Index to remove"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -457,11 +733,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add text variable"),
|
||||
_("Adds a text (string) at the end of a global array variable."),
|
||||
_("Add text _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -469,11 +746,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add number variable"),
|
||||
_("Adds a number at the end of a global array variable."),
|
||||
_("Add number _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -481,11 +759,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add boolean variable"),
|
||||
_("Adds a boolean at the end of a global array variable."),
|
||||
_("Add boolean _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -494,12 +773,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Number of children"),
|
||||
_("Compare the number of children in a global array variable."),
|
||||
_("The number of children of the array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -507,18 +787,20 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("First text child"),
|
||||
_("Value of the first element of a global array "
|
||||
"variable, if it is a text (string) variable."),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression("GlobalVariableFirstNumber",
|
||||
_("First number child"),
|
||||
_("Value of the first element of a global array "
|
||||
"variable, if it is a number variable"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddStrExpression(
|
||||
@@ -526,9 +808,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Last text child"),
|
||||
_("Value of the last element of a global array variable, if "
|
||||
"it is a text (string) variable."),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
@@ -536,59 +819,65 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Last number child"),
|
||||
_("Value of the last element of a global array variable, if "
|
||||
"it is a number variable"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression("GlobalVariableChildCount",
|
||||
_("Number of children"),
|
||||
_("Number of children in a global array or "
|
||||
"structure variable"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array or structure variable"));
|
||||
.AddParameter("globalvar", _("Array or structure variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression("VariableChildCount",
|
||||
_("Number of children"),
|
||||
_("Number of children in a scene array or "
|
||||
"structure variable"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array or structure variable"));
|
||||
.AddParameter("variable", _("Array or structure variable"), "AllowUndeclaredVariable");
|
||||
|
||||
extension
|
||||
.AddExpression("Variable",
|
||||
_("Number variable"),
|
||||
_("Number value of a scene variable"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"));
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddStrExpression("VariableString",
|
||||
_("Text variable"),
|
||||
_("Text of a scene variable"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"));
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression("GlobalVariable",
|
||||
_("Number variable"),
|
||||
_("Number value of a global variable"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Name of the global variable"));
|
||||
.AddParameter("globalvar", _("Name of the global variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddStrExpression("GlobalVariableString",
|
||||
_("Text variable"),
|
||||
_("Text of a global variable"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"));
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -456,6 +456,15 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the type manipulated in a standard way by the instruction.
|
||||
*
|
||||
* \param type "number" or "string"
|
||||
*/
|
||||
const gd::String &GetManipulatedType() const {
|
||||
return codeExtraInformation.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* If InstructionMetadata::ExtraInformation::SetManipulatedType was called
|
||||
* with "number" or "string", this function will tell the code generator the
|
||||
|
@@ -26,7 +26,7 @@ void EventBasedBehaviorBrowser::ExposeEvents(
|
||||
void EventBasedBehaviorBrowser::ExposeEvents(
|
||||
gd::Project &project, gd::ArbitraryEventsWorkerWithContext &worker) const {
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
project, eventsBasedBehavior, worker);
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior, worker);
|
||||
}
|
||||
|
||||
void EventBasedBehaviorBrowser::ExposeObjects(
|
||||
|
@@ -29,8 +29,11 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API EventBasedBehaviorBrowser : public ProjectBrowser {
|
||||
public:
|
||||
EventBasedBehaviorBrowser(gd::EventsBasedBehavior &eventsBasedBehavior_)
|
||||
: eventsBasedBehavior(eventsBasedBehavior_) {}
|
||||
EventBasedBehaviorBrowser(
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension_,
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior_)
|
||||
: eventsFunctionsExtension(eventsFunctionsExtension_),
|
||||
eventsBasedBehavior(eventsBasedBehavior_) {}
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all events of the event-based
|
||||
@@ -48,7 +51,7 @@ public:
|
||||
* This should be the preferred way to traverse all the events of an event-based behavior.
|
||||
*/
|
||||
void
|
||||
ExposeEvents(gd::Project &project,
|
||||
ExposeEvents(gd::Project &project,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) const override;
|
||||
|
||||
/**
|
||||
@@ -80,6 +83,7 @@ public:
|
||||
gd::ArbitraryBehaviorSharedDataWorker &worker) const override;
|
||||
|
||||
private:
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension;
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior;
|
||||
};
|
||||
|
||||
|
@@ -19,9 +19,9 @@ using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
ArbitraryEventsWorker::~ArbitraryEventsWorker() {}
|
||||
AbstractArbitraryEventsWorker::~AbstractArbitraryEventsWorker() {}
|
||||
|
||||
void ArbitraryEventsWorker::VisitEventList(gd::EventsList& events) {
|
||||
void AbstractArbitraryEventsWorker::VisitEventList(gd::EventsList& events) {
|
||||
DoVisitEventList(events);
|
||||
|
||||
for (std::size_t i = 0; i < events.size();) {
|
||||
@@ -36,7 +36,7 @@ void ArbitraryEventsWorker::VisitEventList(gd::EventsList& events) {
|
||||
}
|
||||
}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
|
||||
bool AbstractArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
|
||||
bool shouldDelete = DoVisitEvent(event);
|
||||
if (shouldDelete) return true;
|
||||
|
||||
@@ -55,15 +55,14 @@ bool ArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
|
||||
*expressionAndMetadata.first, expressionAndMetadata.second);
|
||||
}
|
||||
|
||||
|
||||
return shouldDelete;
|
||||
}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitLinkEvent(gd::LinkEvent& linkEvent) {
|
||||
bool AbstractArbitraryEventsWorker::VisitLinkEvent(gd::LinkEvent& linkEvent) {
|
||||
return DoVisitLinkEvent(linkEvent);
|
||||
}
|
||||
|
||||
void ArbitraryEventsWorker::VisitInstructionList(
|
||||
void AbstractArbitraryEventsWorker::VisitInstructionList(
|
||||
gd::InstructionsList& instructions, bool areConditions) {
|
||||
DoVisitInstructionList(instructions, areConditions);
|
||||
|
||||
@@ -79,22 +78,19 @@ void ArbitraryEventsWorker::VisitInstructionList(
|
||||
}
|
||||
}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitInstruction(gd::Instruction& instruction,
|
||||
bool AbstractArbitraryEventsWorker::VisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
return DoVisitInstruction(instruction, isCondition);
|
||||
}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitEventExpression(gd::Expression& expression,
|
||||
bool AbstractArbitraryEventsWorker::VisitEventExpression(gd::Expression& expression,
|
||||
const gd::ParameterMetadata& metadata) {
|
||||
return DoVisitEventExpression(expression, metadata);
|
||||
}
|
||||
|
||||
ArbitraryEventsWorkerWithContext::~ArbitraryEventsWorkerWithContext() {}
|
||||
AbstractReadOnlyArbitraryEventsWorker::~AbstractReadOnlyArbitraryEventsWorker() {}
|
||||
|
||||
|
||||
ReadOnlyArbitraryEventsWorker::~ReadOnlyArbitraryEventsWorker() {}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events) {
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events) {
|
||||
DoVisitEventList(events);
|
||||
|
||||
for (std::size_t i = 0; i < events.size(); ++i) {
|
||||
@@ -109,7 +105,7 @@ void ReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events)
|
||||
}
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
|
||||
DoVisitEvent(event);
|
||||
|
||||
const vector<const gd::InstructionsList*> conditionsVectors =
|
||||
@@ -130,11 +126,11 @@ void ReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
|
||||
}
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitLinkEvent(const gd::LinkEvent& linkEvent) {
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitLinkEvent(const gd::LinkEvent& linkEvent) {
|
||||
DoVisitLinkEvent(linkEvent);
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitInstructionList(
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitInstructionList(
|
||||
const gd::InstructionsList& instructions, bool areConditions) {
|
||||
DoVisitInstructionList(instructions, areConditions);
|
||||
|
||||
@@ -150,21 +146,73 @@ void ReadOnlyArbitraryEventsWorker::VisitInstructionList(
|
||||
}
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitInstruction(const gd::Instruction& instruction,
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitInstruction(const gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
DoVisitInstruction(instruction, isCondition);
|
||||
}
|
||||
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitEventExpression(const gd::Expression& expression,
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitEventExpression(const gd::Expression& expression,
|
||||
const gd::ParameterMetadata& metadata) {
|
||||
DoVisitEventExpression(expression, metadata);
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::StopAnyEventIteration() {
|
||||
void AbstractReadOnlyArbitraryEventsWorker::StopAnyEventIteration() {
|
||||
shouldStopIteration = true;
|
||||
}
|
||||
|
||||
ArbitraryEventsWorker::~ArbitraryEventsWorker() {}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitEvent(gd::BaseEvent &event) {
|
||||
return AbstractArbitraryEventsWorker::VisitEvent(event);
|
||||
}
|
||||
|
||||
ArbitraryEventsWorkerWithContext::~ArbitraryEventsWorkerWithContext() {}
|
||||
|
||||
bool ArbitraryEventsWorkerWithContext::VisitEvent(gd::BaseEvent &event) {
|
||||
if (!event.HasVariables()) {
|
||||
return AbstractArbitraryEventsWorker::VisitEvent(event);
|
||||
}
|
||||
// Push local variables
|
||||
auto newProjectScopedContainers =
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersWithLocalVariables(
|
||||
*currentProjectScopedContainers, event);
|
||||
auto *parentProjectScopedContainers = currentProjectScopedContainers;
|
||||
currentProjectScopedContainers = &newProjectScopedContainers;
|
||||
|
||||
bool shouldDelete = AbstractArbitraryEventsWorker::VisitEvent(event);
|
||||
|
||||
// Pop local variables
|
||||
currentProjectScopedContainers = parentProjectScopedContainers;
|
||||
return shouldDelete;
|
||||
}
|
||||
|
||||
ReadOnlyArbitraryEventsWorker::~ReadOnlyArbitraryEventsWorker() {}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitEvent(
|
||||
const gd::BaseEvent &event) {
|
||||
AbstractReadOnlyArbitraryEventsWorker::VisitEvent(event);
|
||||
}
|
||||
|
||||
ReadOnlyArbitraryEventsWorkerWithContext::~ReadOnlyArbitraryEventsWorkerWithContext() {}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorkerWithContext::VisitEvent(
|
||||
const gd::BaseEvent &event) {
|
||||
if (!event.HasVariables()) {
|
||||
AbstractReadOnlyArbitraryEventsWorker::VisitEvent(event);
|
||||
return;
|
||||
}
|
||||
// Push local variables
|
||||
auto newProjectScopedContainers =
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersWithLocalVariables(
|
||||
*currentProjectScopedContainers, event);
|
||||
auto *parentProjectScopedContainers = currentProjectScopedContainers;
|
||||
currentProjectScopedContainers = &newProjectScopedContainers;
|
||||
|
||||
AbstractReadOnlyArbitraryEventsWorker::VisitEvent(event);
|
||||
|
||||
// Pop local variables
|
||||
currentProjectScopedContainers = parentProjectScopedContainers;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -3,8 +3,8 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_ARBITRARYEVENTSWORKER_H
|
||||
#define GDCORE_ARBITRARYEVENTSWORKER_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "GDCore/Events/EventVisitor.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Instruction;
|
||||
class BaseEvent;
|
||||
@@ -25,27 +26,24 @@ class ParameterMetadata;
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief ArbitraryEventsWorker is an abstract class used to browse events (and
|
||||
* instructions) and do some work on them. Can be used to implement refactoring
|
||||
* for example.
|
||||
* \brief AbstractArbitraryEventsWorker is a base abstract class used to browse events (and
|
||||
* instructions) and do some work on them. It must not be inherited directly.
|
||||
*
|
||||
* \see gd::ArbitraryEventsWorker
|
||||
* \see gd::ArbitraryEventsWorkerWithContext
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
|
||||
class GD_CORE_API AbstractArbitraryEventsWorker : private EventVisitor {
|
||||
public:
|
||||
ArbitraryEventsWorker(){};
|
||||
virtual ~ArbitraryEventsWorker();
|
||||
AbstractArbitraryEventsWorker(){};
|
||||
virtual ~AbstractArbitraryEventsWorker();
|
||||
|
||||
/**
|
||||
* \brief Launch the worker on the specified events list.
|
||||
*/
|
||||
void Launch(gd::EventsList& events) { VisitEventList(events); };
|
||||
protected:
|
||||
virtual bool VisitEvent(gd::BaseEvent& event) override;
|
||||
void VisitEventList(gd::EventsList& events);
|
||||
|
||||
private:
|
||||
void VisitEventList(gd::EventsList& events);
|
||||
bool VisitEvent(gd::BaseEvent& event) override;
|
||||
bool VisitLinkEvent(gd::LinkEvent& linkEvent) override;
|
||||
void VisitInstructionList(gd::InstructionsList& instructions,
|
||||
bool areConditions);
|
||||
@@ -101,6 +99,31 @@ class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ArbitraryEventsWorker is an abstract class used to browse events (and
|
||||
* instructions) and do some work on them. Can be used to implement refactoring
|
||||
* for example.
|
||||
*
|
||||
* \see gd::ArbitraryEventsWorkerWithContext
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ArbitraryEventsWorker : public AbstractArbitraryEventsWorker {
|
||||
public:
|
||||
ArbitraryEventsWorker(){};
|
||||
virtual ~ArbitraryEventsWorker();
|
||||
|
||||
/**
|
||||
* \brief Launch the worker on the specified events list.
|
||||
*/
|
||||
void Launch(gd::EventsList &events) {
|
||||
AbstractArbitraryEventsWorker::VisitEventList(events);
|
||||
};
|
||||
|
||||
private:
|
||||
bool VisitEvent(gd::BaseEvent &event) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief An events worker that will know about the context (the objects
|
||||
* container). Useful for workers working on expressions notably.
|
||||
@@ -110,10 +133,10 @@ class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ArbitraryEventsWorkerWithContext
|
||||
: public ArbitraryEventsWorker {
|
||||
: public AbstractArbitraryEventsWorker {
|
||||
public:
|
||||
ArbitraryEventsWorkerWithContext()
|
||||
: projectScopedContainers(nullptr){};
|
||||
: currentProjectScopedContainers(nullptr){};
|
||||
virtual ~ArbitraryEventsWorkerWithContext();
|
||||
|
||||
/**
|
||||
@@ -121,53 +144,50 @@ class GD_CORE_API ArbitraryEventsWorkerWithContext
|
||||
* giving the objects container on which the events are applying to.
|
||||
*/
|
||||
void Launch(gd::EventsList& events,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_) {
|
||||
projectScopedContainers = &projectScopedContainers_;
|
||||
ArbitraryEventsWorker::Launch(events);
|
||||
const gd::ProjectScopedContainers& projectScopedContainers) {
|
||||
currentProjectScopedContainers = &projectScopedContainers;
|
||||
AbstractArbitraryEventsWorker::VisitEventList(events);
|
||||
};
|
||||
|
||||
void Launch(gd::EventsList& events) = delete;
|
||||
|
||||
protected:
|
||||
protected:
|
||||
const gd::ProjectScopedContainers& GetProjectScopedContainers() {
|
||||
// Pointers are guaranteed to be not nullptr after
|
||||
// Launch was called.
|
||||
return *projectScopedContainers;
|
||||
return *currentProjectScopedContainers;
|
||||
};
|
||||
const gd::ObjectsContainersList& GetObjectsContainersList() {
|
||||
// Pointers are guaranteed to be not nullptr after
|
||||
// Launch was called.
|
||||
return projectScopedContainers->GetObjectsContainersList();
|
||||
return currentProjectScopedContainers->GetObjectsContainersList();
|
||||
};
|
||||
|
||||
private:
|
||||
const gd::ProjectScopedContainers* projectScopedContainers;
|
||||
bool VisitEvent(gd::BaseEvent& event) override;
|
||||
|
||||
const gd::ProjectScopedContainers* currentProjectScopedContainers;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ReadOnlyArbitraryEventsWorker is an abstract class used to browse events (and
|
||||
* instructions). It can be used to implement autocompletion for example.
|
||||
* instructions). It must not be inherited directly.
|
||||
*
|
||||
* \see gd::ReadOnlyArbitraryEventsWorker
|
||||
* \see gd::ReadOnlyArbitraryEventsWorkerWithContext
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ReadOnlyArbitraryEventsWorker : private ReadOnlyEventVisitor {
|
||||
class GD_CORE_API AbstractReadOnlyArbitraryEventsWorker : private ReadOnlyEventVisitor {
|
||||
public:
|
||||
ReadOnlyArbitraryEventsWorker() : shouldStopIteration(false) {};
|
||||
virtual ~ReadOnlyArbitraryEventsWorker();
|
||||
|
||||
/**
|
||||
* \brief Launch the worker on the specified events list.
|
||||
*/
|
||||
void Launch(const gd::EventsList& events) { VisitEventList(events); };
|
||||
AbstractReadOnlyArbitraryEventsWorker() : shouldStopIteration(false) {};
|
||||
virtual ~AbstractReadOnlyArbitraryEventsWorker();
|
||||
|
||||
protected:
|
||||
void StopAnyEventIteration() override;
|
||||
virtual void VisitEvent(const gd::BaseEvent& event) override;
|
||||
|
||||
void VisitEventList(const gd::EventsList& events);
|
||||
|
||||
private:
|
||||
void VisitEventList(const gd::EventsList& events);
|
||||
void VisitEvent(const gd::BaseEvent& event) override;
|
||||
void VisitLinkEvent(const gd::LinkEvent& linkEvent) override;
|
||||
void VisitInstructionList(const gd::InstructionsList& instructions,
|
||||
bool areConditions);
|
||||
@@ -213,6 +233,31 @@ protected:
|
||||
bool shouldStopIteration;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ReadOnlyArbitraryEventsWorker is an abstract class used to browse events (and
|
||||
* instructions). It can be used to implement autocompletion for example.
|
||||
*
|
||||
* \see gd::ReadOnlyArbitraryEventsWorkerWithContext
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ReadOnlyArbitraryEventsWorker
|
||||
: public AbstractReadOnlyArbitraryEventsWorker {
|
||||
public:
|
||||
ReadOnlyArbitraryEventsWorker(){};
|
||||
virtual ~ReadOnlyArbitraryEventsWorker();
|
||||
|
||||
/**
|
||||
* \brief Launch the worker on the specified events list.
|
||||
*/
|
||||
void Launch(const gd::EventsList &events) {
|
||||
AbstractReadOnlyArbitraryEventsWorker::VisitEventList(events);
|
||||
};
|
||||
|
||||
private:
|
||||
void VisitEvent(const gd::BaseEvent &event) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief An events worker that will know about the context (the objects
|
||||
* container). Useful for workers working on expressions notably.
|
||||
@@ -222,10 +267,10 @@ protected:
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ReadOnlyArbitraryEventsWorkerWithContext
|
||||
: public ReadOnlyArbitraryEventsWorker {
|
||||
: public AbstractReadOnlyArbitraryEventsWorker {
|
||||
public:
|
||||
ReadOnlyArbitraryEventsWorkerWithContext()
|
||||
: projectScopedContainers(nullptr){};
|
||||
: currentProjectScopedContainers(nullptr){};
|
||||
virtual ~ReadOnlyArbitraryEventsWorkerWithContext();
|
||||
|
||||
/**
|
||||
@@ -233,24 +278,22 @@ class GD_CORE_API ReadOnlyArbitraryEventsWorkerWithContext
|
||||
* giving the objects container on which the events are applying to.
|
||||
*/
|
||||
void Launch(const gd::EventsList& events,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_) {
|
||||
projectScopedContainers = &projectScopedContainers_;
|
||||
ReadOnlyArbitraryEventsWorker::Launch(events);
|
||||
const gd::ProjectScopedContainers& projectScopedContainers) {
|
||||
currentProjectScopedContainers = &projectScopedContainers;
|
||||
AbstractReadOnlyArbitraryEventsWorker::VisitEventList(events);
|
||||
};
|
||||
|
||||
void Launch(gd::EventsList& events) = delete;
|
||||
|
||||
protected:
|
||||
protected:
|
||||
const gd::ProjectScopedContainers& GetProjectScopedContainers() {
|
||||
// Pointers are guaranteed to be not nullptr after
|
||||
// Launch was called.
|
||||
return *projectScopedContainers;
|
||||
return *currentProjectScopedContainers;
|
||||
};
|
||||
|
||||
private:
|
||||
const gd::ProjectScopedContainers* projectScopedContainers;
|
||||
void VisitEvent(const gd::BaseEvent& event) override;
|
||||
|
||||
const gd::ProjectScopedContainers* currentProjectScopedContainers;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_ARBITRARYEVENTSWORKER_H
|
||||
|
@@ -20,6 +20,8 @@
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableNameFinder.h"
|
||||
#include "GDCore/IDE/VariableInstructionSwitcher.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
@@ -104,7 +106,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList()
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
// The node represents a variable, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
|
||||
@@ -123,7 +125,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
[&]() {
|
||||
// This is something else - potentially a deleted variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList()
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
// The node represents a variable, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
|
||||
@@ -188,7 +190,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList()
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
// The node represents a variable, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(
|
||||
@@ -204,7 +206,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
[&]() {
|
||||
// This is something else - potentially a deleted variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList()
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
// The node represents a variable, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(
|
||||
@@ -364,6 +366,50 @@ bool EventsVariableReplacer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
parameterIndex, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
|
||||
if (gd::ParameterMetadata::IsExpression("variable", type) &&
|
||||
gd::VariableInstructionSwitcher::IsSwitchableVariableInstruction(
|
||||
instruction.GetType())) {
|
||||
const auto &newParameterValue =
|
||||
instruction.GetParameter(parameterIndex);
|
||||
const auto variableName =
|
||||
gd::ExpressionVariableNameFinder::GetVariableName(
|
||||
*newParameterValue.GetRootNode());
|
||||
|
||||
const gd::VariablesContainer *variablesContainer = nullptr;
|
||||
if (type == "objectvar") {
|
||||
const auto &objectsContainersList =
|
||||
GetProjectScopedContainers().GetObjectsContainersList();
|
||||
if (objectsContainersList.HasObjectOrGroupWithVariableNamed(
|
||||
lastObjectName, variableName) !=
|
||||
gd::ObjectsContainersList::VariableExistence::DoesNotExist) {
|
||||
variablesContainer =
|
||||
GetProjectScopedContainers()
|
||||
.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(lastObjectName);
|
||||
}
|
||||
} else {
|
||||
if (GetProjectScopedContainers().GetVariablesContainersList().Has(
|
||||
variableName)) {
|
||||
variablesContainer =
|
||||
&GetProjectScopedContainers()
|
||||
.GetVariablesContainersList()
|
||||
.GetVariablesContainerFromVariableName(variableName);
|
||||
}
|
||||
}
|
||||
|
||||
// Every occurrence of the variable or its children are checked.
|
||||
// Ensuring that a child is actually the one with a type change would
|
||||
// take more time.
|
||||
if (variablesContainer == &targetVariablesContainer) {
|
||||
if (typeChangedVariableNames.find(variableName) !=
|
||||
typeChangedVariableNames.end()) {
|
||||
gd::VariableInstructionSwitcher::
|
||||
SwitchBetweenUnifiedInstructionIfNeeded(
|
||||
platform, GetProjectScopedContainers(), instruction);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return shouldDeleteInstruction;
|
||||
|
@@ -34,11 +34,13 @@ class GD_CORE_API EventsVariableReplacer
|
||||
const gd::Platform &platform_,
|
||||
const gd::VariablesContainer &targetVariablesContainer_,
|
||||
const std::unordered_map<gd::String, gd::String> &oldToNewVariableNames_,
|
||||
const std::unordered_set<gd::String> &removedVariableNames_)
|
||||
const std::unordered_set<gd::String> &removedVariableNames_,
|
||||
const std::unordered_set<gd::String> &typeChangedVariableNames_)
|
||||
: platform(platform_),
|
||||
targetVariablesContainer(targetVariablesContainer_),
|
||||
oldToNewVariableNames(oldToNewVariableNames_),
|
||||
removedVariableNames(removedVariableNames_){};
|
||||
removedVariableNames(removedVariableNames_),
|
||||
typeChangedVariableNames(typeChangedVariableNames_){};
|
||||
virtual ~EventsVariableReplacer();
|
||||
|
||||
private:
|
||||
@@ -55,6 +57,7 @@ class GD_CORE_API EventsVariableReplacer
|
||||
gd::String objectName;
|
||||
const std::unordered_map<gd::String, gd::String> &oldToNewVariableNames;
|
||||
const std::unordered_set<gd::String> &removedVariableNames;
|
||||
const std::unordered_set<gd::String> &typeChangedVariableNames;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -229,7 +229,7 @@ std::set<gd::String> EventsVariablesFinder::FindAllObjectVariables(
|
||||
const gd::Platform& platform,
|
||||
const gd::Project& project,
|
||||
const gd::Layout& layout,
|
||||
const gd::Object& object) {
|
||||
const gd::String& objectName) {
|
||||
std::set<gd::String> results;
|
||||
|
||||
FindArgumentsInEventsAndDependencies(
|
||||
@@ -238,7 +238,7 @@ std::set<gd::String> EventsVariablesFinder::FindAllObjectVariables(
|
||||
project,
|
||||
layout,
|
||||
"objectvar",
|
||||
object.GetName());
|
||||
objectName);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
@@ -63,14 +63,14 @@ class EventsVariablesFinder {
|
||||
*
|
||||
* \param project The project
|
||||
* \param layout The layout to use.
|
||||
* \param object The object to be scanned
|
||||
* \param objectName The name of the object to be scanned
|
||||
* \return A std::set containing the names of all object variables used.
|
||||
*/
|
||||
static std::set<gd::String> FindAllObjectVariables(
|
||||
const gd::Platform& platform,
|
||||
const gd::Project& project,
|
||||
const gd::Layout& layout,
|
||||
const gd::Object& object);
|
||||
const gd::String& objectName);
|
||||
|
||||
private:
|
||||
|
||||
|
@@ -3,8 +3,7 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
|
||||
#define GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -20,7 +19,7 @@
|
||||
#include "GDCore/IDE/Events/ExpressionNodeLocationFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableParentFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariablePathFinder.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
|
||||
@@ -525,7 +524,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
VariableAndItsParent variableAndItsParent =
|
||||
gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, node);
|
||||
|
||||
// If no child, we're at the end of a variable (like `GrandChild` in
|
||||
@@ -666,7 +665,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
VariableAndItsParent variableAndItsParent =
|
||||
gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, node);
|
||||
|
||||
AddCompletionsForChildrenVariablesOf(
|
||||
@@ -1113,5 +1112,3 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
|
||||
|
@@ -166,8 +166,7 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
return true; // We found a property, even if the child is not allowed.
|
||||
}
|
||||
|
||||
const gd::NamedPropertyDescriptor& property = projectScopedContainers
|
||||
.GetPropertiesContainersList().Get(identifier.identifierName).second;
|
||||
const gd::NamedPropertyDescriptor& property = propertiesContainersList.Get(identifier.identifierName).second;
|
||||
|
||||
if (property.GetType() == "Number") {
|
||||
childType = Type::Number;
|
||||
@@ -376,7 +375,10 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
|
||||
dynamic_cast<EmptyNode*>(parameter.get()) == nullptr) {
|
||||
auto currentParentType = parentType;
|
||||
parentType = StringToType(parameterMetadata.GetType());
|
||||
auto parentParameterExtraInfo = currentParameterExtraInfo;
|
||||
currentParameterExtraInfo = ¶meterMetadata.GetExtraInfo();
|
||||
parameter->Visit(*this);
|
||||
currentParameterExtraInfo = parentParameterExtraInfo;
|
||||
parentType = currentParentType;
|
||||
|
||||
const gd::String& expectedParameterType = parameterMetadata.GetType();
|
||||
@@ -440,6 +442,10 @@ const gd::String& ExpressionValidator::TypeToString(Type type) {
|
||||
return numberOrStringTypeString;
|
||||
case Type::Variable:
|
||||
return variableTypeString;
|
||||
case Type::LegacyVariable:
|
||||
// This function is only used to display error.
|
||||
// Users don't care if it's legacy or not.
|
||||
return variableTypeString;
|
||||
case Type::Object:
|
||||
return objectTypeString;
|
||||
case Type::Empty:
|
||||
@@ -466,7 +472,12 @@ ExpressionValidator::Type ExpressionValidator::StringToType(
|
||||
if (type == ExpressionValidator::variableTypeString ||
|
||||
gd::ParameterMetadata::IsExpression(
|
||||
ExpressionValidator::variableTypeString, type)) {
|
||||
return Type::Variable;
|
||||
if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
|
||||
return Type::LegacyVariable;
|
||||
}
|
||||
else {
|
||||
return Type::Variable;
|
||||
}
|
||||
}
|
||||
if (type == ExpressionValidator::objectTypeString ||
|
||||
gd::ParameterMetadata::IsObject(type)) {
|
||||
|
@@ -3,8 +3,7 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EXPRESSIONVALIDATOR_H
|
||||
#define GDCORE_EXPRESSIONVALIDATOR_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -39,12 +38,14 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionValidator(const gd::Platform &platform_,
|
||||
const gd::ProjectScopedContainers & projectScopedContainers_,
|
||||
const gd::String &rootType_)
|
||||
const gd::String &rootType_,
|
||||
const gd::String &extraInfo_ = "")
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
parentType(StringToType(gd::ParameterMetadata::GetExpressionValueType(rootType_))),
|
||||
childType(Type::Unknown),
|
||||
forbidsUsageOfBracketsBecauseParentIsObject(false) {};
|
||||
forbidsUsageOfBracketsBecauseParentIsObject(false),
|
||||
currentParameterExtraInfo(&extraInfo_) {};
|
||||
virtual ~ExpressionValidator(){};
|
||||
|
||||
/**
|
||||
@@ -115,7 +116,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
_("Operators (+, -, /, *) can't be used with an object name. Remove "
|
||||
"the operator."),
|
||||
node.rightHandSide->location);
|
||||
} else if (leftType == Type::Variable) {
|
||||
} else if (leftType == Type::Variable || leftType == Type::LegacyVariable) {
|
||||
RaiseOperatorError(
|
||||
_("Operators (+, -, /, *) can't be used in variable names. Remove "
|
||||
"the operator from the variable name."),
|
||||
@@ -162,7 +163,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
_("Operators (+, -) can't be used with an object name. Remove the "
|
||||
"operator."),
|
||||
node.location);
|
||||
} else if (rightType == Type::Variable) {
|
||||
} else if (rightType == Type::Variable || rightType == Type::LegacyVariable) {
|
||||
RaiseTypeError(
|
||||
_("Operators (+, -) can't be used in variable names. Remove "
|
||||
"the operator from the variable name."),
|
||||
@@ -200,7 +201,20 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
ReportAnyError(node);
|
||||
|
||||
if (parentType == Type::Variable) {
|
||||
childType = Type::Variable;
|
||||
childType = parentType;
|
||||
|
||||
if (!currentParameterExtraInfo || *currentParameterExtraInfo != "AllowUndeclaredVariable") {
|
||||
const auto& variablesContainersList = projectScopedContainers.GetVariablesContainersList();
|
||||
if (!variablesContainersList.Has(node.name)) {
|
||||
RaiseTypeError(_("No variable with this name found."), node.location);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.child) {
|
||||
node.child->Visit(*this);
|
||||
}
|
||||
} else if (parentType == Type::LegacyVariable) {
|
||||
childType = parentType;
|
||||
|
||||
if (node.child) {
|
||||
node.child->Visit(*this);
|
||||
@@ -280,7 +294,10 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
|
||||
Type currentParentType = parentType;
|
||||
parentType = Type::NumberOrString;
|
||||
auto parentParameterExtraInfo = currentParameterExtraInfo;
|
||||
currentParameterExtraInfo = nullptr;
|
||||
node.expression->Visit(*this);
|
||||
currentParameterExtraInfo = parentParameterExtraInfo;
|
||||
parentType = currentParentType;
|
||||
|
||||
if (node.child) {
|
||||
@@ -314,7 +331,15 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
node.location);
|
||||
}
|
||||
}
|
||||
else if (parentType != Type::Object && parentType != Type::Variable) {
|
||||
else if (parentType == Type::Variable) {
|
||||
if (!currentParameterExtraInfo || *currentParameterExtraInfo != "AllowUndeclaredVariable") {
|
||||
const auto& variablesContainersList = projectScopedContainers.GetVariablesContainersList();
|
||||
if (!variablesContainersList.Has(node.identifierName)) {
|
||||
RaiseTypeError(_("No variable with this name found."), node.location);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (parentType != Type::Object && parentType != Type::LegacyVariable) {
|
||||
// It can't happen.
|
||||
RaiseTypeError(
|
||||
_("You've entered a name, but this type was expected:") + " " + TypeToString(parentType),
|
||||
@@ -338,7 +363,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
} else if (parentType == Type::String) {
|
||||
message = _(
|
||||
"You must enter a text (between quotes) or a valid expression call.");
|
||||
} else if (parentType == Type::Variable) {
|
||||
} else if (parentType == Type::Variable || parentType == Type::LegacyVariable) {
|
||||
message = _("You must enter a variable name.");
|
||||
} else if (parentType == Type::Object) {
|
||||
message = _("You must enter a valid object name.");
|
||||
@@ -351,7 +376,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
}
|
||||
|
||||
private:
|
||||
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, Object, Empty};
|
||||
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, LegacyVariable, Object, Empty};
|
||||
Type ValidateFunction(const gd::FunctionCallNode& function);
|
||||
bool ValidateObjectVariableOrVariableOrProperty(const gd::IdentifierNode& identifier);
|
||||
|
||||
@@ -412,6 +437,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
static const gd::String stringTypeString;
|
||||
static const gd::String numberOrStringTypeString;
|
||||
static const gd::String variableTypeString;
|
||||
static const gd::String legacyVariableTypeString;
|
||||
static const gd::String objectTypeString;
|
||||
static const gd::String identifierTypeString;
|
||||
static const gd::String emptyTypeString;
|
||||
@@ -422,10 +448,10 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
Type childType; ///< The type "discovered" down the tree and passed up.
|
||||
Type parentType; ///< The type "required" by the top of the tree.
|
||||
bool forbidsUsageOfBracketsBecauseParentIsObject;
|
||||
const gd::String *currentParameterExtraInfo;
|
||||
const gd::Platform &platform;
|
||||
const gd::ProjectScopedContainers &projectScopedContainers;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXPRESSIONVALIDATOR_H
|
||||
|
55
Core/GDCore/IDE/Events/ExpressionVariableNameFinder.h
Normal file
55
Core/GDCore/IDE/Events/ExpressionVariableNameFinder.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Find the variable name from a variable expression.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionVariableNameFinder : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
|
||||
static const gd::String GetVariableName(gd::ExpressionNode& node) {
|
||||
gd::ExpressionVariableNameFinder typeFinder;
|
||||
node.Visit(typeFinder);
|
||||
return typeFinder.variableName;
|
||||
}
|
||||
|
||||
virtual ~ExpressionVariableNameFinder(){};
|
||||
|
||||
protected:
|
||||
ExpressionVariableNameFinder()
|
||||
: variableName("") {};
|
||||
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
variableName = node.name;
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
variableName = node.identifierName;
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {}
|
||||
|
||||
private:
|
||||
gd::String variableName;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -1,374 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
namespace gd {
|
||||
class Expression;
|
||||
class ObjectsContainer;
|
||||
class Platform;
|
||||
class ParameterMetadata;
|
||||
class ExpressionMetadata;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Contains a variables container or a variable. Useful
|
||||
* to refer to the parent of a variable (which can be a VariablesContainer
|
||||
* or another Variable).
|
||||
*/
|
||||
struct VariableAndItsParent {
|
||||
const gd::VariablesContainer* parentVariablesContainer;
|
||||
const gd::Variable* parentVariable;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Find the last parent (i.e: the variables container) of a node
|
||||
* representing a variable.
|
||||
*
|
||||
* Useful for completions, to know which variables can be entered in a node.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionVariableParentFinder
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
static VariableAndItsParent GetLastParentOfNode(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::ExpressionNode& node) {
|
||||
gd::ExpressionVariableParentFinder typeFinder(platform,
|
||||
projectScopedContainers);
|
||||
node.Visit(typeFinder);
|
||||
return typeFinder.variableAndItsParent;
|
||||
}
|
||||
|
||||
virtual ~ExpressionVariableParentFinder(){};
|
||||
|
||||
protected:
|
||||
ExpressionVariableParentFinder(
|
||||
const gd::Platform& platform_,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_)
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
variableNode(nullptr),
|
||||
thisIsALegacyPrescopedVariable(false),
|
||||
bailOutBecauseEmptyVariableName(false),
|
||||
legacyPrescopedVariablesContainer(nullptr),
|
||||
variableAndItsParent{} {};
|
||||
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
if (variableNode != nullptr) {
|
||||
// This is not possible
|
||||
return;
|
||||
}
|
||||
variableNode = &node;
|
||||
|
||||
// Check if the parent is a function call, in which we might be dealing
|
||||
// with a legacy pre-scoped variable parameter:
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
|
||||
if (thisIsALegacyPrescopedVariable) {
|
||||
// The node represents a variable name, and the variables container
|
||||
// containing it was identified in the FunctionCallNode.
|
||||
childVariableNames.insert(childVariableNames.begin(), node.name);
|
||||
if (legacyPrescopedVariablesContainer)
|
||||
variableAndItsParent = WalkUntilLastParent(
|
||||
*legacyPrescopedVariablesContainer, childVariableNames);
|
||||
} else {
|
||||
// Otherwise, the identifier is to be interpreted as usual:
|
||||
// it can be an object (on which a variable is accessed),
|
||||
// or a variable.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
node.name,
|
||||
[&]() {
|
||||
// This is an object.
|
||||
const auto* variablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(node.name);
|
||||
if (variablesContainer)
|
||||
variableAndItsParent =
|
||||
WalkUntilLastParent(*variablesContainer, childVariableNames);
|
||||
},
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList().Has(
|
||||
node.name)) {
|
||||
variableAndItsParent = WalkUntilLastParent(
|
||||
projectScopedContainers.GetVariablesContainersList().Get(
|
||||
node.name),
|
||||
childVariableNames);
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
// Ignore properties here.
|
||||
// There is no support for "children" of properties.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore parameters here.
|
||||
// There is no support for "children" of parameters.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore unrecognised identifiers here.
|
||||
});
|
||||
}
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
if (node.name.empty() && node.child) {
|
||||
// A variable accessor should always have a name if it has a child (i.e:
|
||||
// another accessor). While the parser may have generated an empty name,
|
||||
// flag this so we avoid finding a wrong parent (and so, run the risk of
|
||||
// giving wrong autocompletions).
|
||||
bailOutBecauseEmptyVariableName = true;
|
||||
}
|
||||
childVariableNames.insert(childVariableNames.begin(), node.name);
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
if (variableNode != nullptr) {
|
||||
// This is not possible
|
||||
return;
|
||||
}
|
||||
// This node is not necessarily a variable node.
|
||||
// It will be checked when visiting the FunctionCallNode, just after.
|
||||
variableNode = &node;
|
||||
|
||||
// Check if the parent is a function call, in which we might be dealing
|
||||
// with a legacy pre-scoped variable parameter:
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
|
||||
if (thisIsALegacyPrescopedVariable) {
|
||||
// The identifier represents a variable name, and the variables container
|
||||
// containing it was identified in the FunctionCallNode.
|
||||
if (!node.childIdentifierName.empty())
|
||||
childVariableNames.insert(childVariableNames.begin(),
|
||||
node.childIdentifierName);
|
||||
childVariableNames.insert(childVariableNames.begin(),
|
||||
node.identifierName);
|
||||
|
||||
if (legacyPrescopedVariablesContainer)
|
||||
variableAndItsParent = WalkUntilLastParent(
|
||||
*legacyPrescopedVariablesContainer, childVariableNames);
|
||||
|
||||
} else {
|
||||
// Otherwise, the identifier is to be interpreted as usual:
|
||||
// it can be an object (on which a variable is accessed),
|
||||
// or a variable.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
node.identifierName,
|
||||
[&]() {
|
||||
// This is an object.
|
||||
if (!node.childIdentifierName.empty())
|
||||
childVariableNames.insert(childVariableNames.begin(),
|
||||
node.childIdentifierName);
|
||||
|
||||
const auto* variablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(node.identifierName);
|
||||
if (variablesContainer)
|
||||
variableAndItsParent =
|
||||
WalkUntilLastParent(*variablesContainer, childVariableNames);
|
||||
},
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
if (!node.childIdentifierName.empty())
|
||||
childVariableNames.insert(childVariableNames.begin(),
|
||||
node.childIdentifierName);
|
||||
|
||||
if (projectScopedContainers.GetVariablesContainersList().Has(
|
||||
node.identifierName)) {
|
||||
variableAndItsParent = WalkUntilLastParent(
|
||||
projectScopedContainers.GetVariablesContainersList().Get(
|
||||
node.identifierName),
|
||||
childVariableNames);
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
// Ignore properties here.
|
||||
// There is no support for "children" of properties.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore parameters here.
|
||||
// There is no support for "children" of properties.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore unrecognised identifiers here.
|
||||
});
|
||||
}
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
// Add a child with an empty name, which will be interpreted as
|
||||
// "take the first child/item of the structure/array".
|
||||
childVariableNames.insert(childVariableNames.begin(), "");
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {
|
||||
if (variableNode == nullptr) {
|
||||
return;
|
||||
}
|
||||
int parameterIndex = -1;
|
||||
for (int i = 0; i < functionCall.parameters.size(); i++) {
|
||||
if (functionCall.parameters.at(i).get() == variableNode) {
|
||||
parameterIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parameterIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& objectsContainersList =
|
||||
projectScopedContainers.GetObjectsContainersList();
|
||||
|
||||
const gd::ParameterMetadata* parameterMetadata =
|
||||
MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, objectsContainersList, functionCall, parameterIndex);
|
||||
if (parameterMetadata == nullptr) return; // Unexpected
|
||||
|
||||
// Support for legacy pre-scoped variables:
|
||||
if (parameterMetadata->GetValueTypeMetadata().IsLegacyPreScopedVariable()) {
|
||||
if (parameterMetadata->GetType() == "objectvar") {
|
||||
// Legacy convention where a "objectvar"
|
||||
// parameter represents a variable of the object represented by the
|
||||
// previous "object" parameter. The object on which the function is
|
||||
// called is returned if no previous parameters are objects.
|
||||
gd::String objectName = functionCall.objectName;
|
||||
for (int previousIndex = parameterIndex - 1; previousIndex >= 0;
|
||||
previousIndex--) {
|
||||
const gd::ParameterMetadata* previousParameterMetadata =
|
||||
MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, objectsContainersList, functionCall, previousIndex);
|
||||
if (previousParameterMetadata != nullptr &&
|
||||
gd::ParameterMetadata::IsObject(
|
||||
previousParameterMetadata->GetType())) {
|
||||
auto previousParameterNode =
|
||||
functionCall.parameters[previousIndex].get();
|
||||
IdentifierNode* objectNode =
|
||||
dynamic_cast<IdentifierNode*>(previousParameterNode);
|
||||
objectName = objectNode->identifierName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
legacyPrescopedVariablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(objectName);
|
||||
thisIsALegacyPrescopedVariable = true;
|
||||
} else if (parameterMetadata->GetType() == "scenevar") {
|
||||
legacyPrescopedVariablesContainer =
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetBottomMostVariablesContainer();
|
||||
thisIsALegacyPrescopedVariable = true;
|
||||
} else if (parameterMetadata->GetType() == "globalvar") {
|
||||
legacyPrescopedVariablesContainer =
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetTopMostVariablesContainer();
|
||||
thisIsALegacyPrescopedVariable = true;
|
||||
}
|
||||
} else {
|
||||
thisIsALegacyPrescopedVariable = false;
|
||||
legacyPrescopedVariablesContainer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
VariableAndItsParent WalkUntilLastParent(
|
||||
const gd::Variable& variable,
|
||||
const std::vector<gd::String>& childVariableNames,
|
||||
size_t startIndex = 0) {
|
||||
if (bailOutBecauseEmptyVariableName)
|
||||
return {}; // Do not even attempt to find the parent if we had an issue
|
||||
// when visiting nodes.
|
||||
|
||||
const gd::Variable* currentVariable = &variable;
|
||||
|
||||
// Walk until size - 1 as we want the last parent.
|
||||
for (size_t index = startIndex; index + 1 < childVariableNames.size();
|
||||
++index) {
|
||||
const gd::String& childName = childVariableNames[index];
|
||||
|
||||
if (childName.empty()) {
|
||||
if (currentVariable->GetChildrenCount() == 0) {
|
||||
// The array or structure is empty, we can't walk through it - there
|
||||
// is no "parent".
|
||||
return {};
|
||||
}
|
||||
|
||||
if (currentVariable->GetType() == gd::Variable::Array) {
|
||||
currentVariable = ¤tVariable->GetAtIndex(0);
|
||||
} else {
|
||||
currentVariable =
|
||||
currentVariable->GetAllChildren().begin()->second.get();
|
||||
}
|
||||
} else {
|
||||
if (!currentVariable->HasChild(childName)) {
|
||||
// Non existing child - there is no "parent".
|
||||
return {};
|
||||
}
|
||||
|
||||
currentVariable = ¤tVariable->GetChild(childName);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the last parent of the chain of variables (so not the last
|
||||
// variable but the one before it).
|
||||
return {.parentVariable = currentVariable};
|
||||
}
|
||||
|
||||
VariableAndItsParent WalkUntilLastParent(
|
||||
const gd::VariablesContainer& variablesContainer,
|
||||
const std::vector<gd::String>& childVariableNames) {
|
||||
if (bailOutBecauseEmptyVariableName)
|
||||
return {}; // Do not even attempt to find the parent if we had an issue
|
||||
// when visiting nodes.
|
||||
if (childVariableNames.empty())
|
||||
return {}; // There is no "parent" to the variables container itself.
|
||||
|
||||
const gd::String& firstChildName = *childVariableNames.begin();
|
||||
|
||||
const gd::Variable* variable = variablesContainer.Has(firstChildName)
|
||||
? &variablesContainer.Get(firstChildName)
|
||||
: nullptr;
|
||||
if (childVariableNames.size() == 1 || !variable)
|
||||
return {// Only one child: the parent is the variables container itself.
|
||||
.parentVariablesContainer = &variablesContainer};
|
||||
|
||||
return WalkUntilLastParent(*variable, childVariableNames, 1);
|
||||
}
|
||||
|
||||
gd::ExpressionNode* variableNode;
|
||||
std::vector<gd::String> childVariableNames;
|
||||
bool thisIsALegacyPrescopedVariable;
|
||||
bool bailOutBecauseEmptyVariableName;
|
||||
const gd::VariablesContainer* legacyPrescopedVariablesContainer;
|
||||
VariableAndItsParent variableAndItsParent;
|
||||
|
||||
const gd::Platform& platform;
|
||||
const gd::ProjectScopedContainers& projectScopedContainers;
|
||||
};
|
||||
|
||||
} // namespace gd
|
195
Core/GDCore/IDE/Events/ExpressionVariablePathFinder.cpp
Normal file
195
Core/GDCore/IDE/Events/ExpressionVariablePathFinder.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "ExpressionVariablePathFinder.h"
|
||||
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Find the pre-scoped container of legacy variables or the object name
|
||||
* from the function call node.
|
||||
*/
|
||||
class GD_CORE_API ExpressionLiteralFinder : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
virtual ~ExpressionLiteralFinder(){};
|
||||
|
||||
gd::String literalValue;
|
||||
|
||||
ExpressionLiteralFinder() : literalValue(""){};
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode &node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode &node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode &node) override {}
|
||||
void OnVisitNumberNode(NumberNode &node) override {
|
||||
literalValue = node.number;
|
||||
}
|
||||
void OnVisitTextNode(TextNode &node) override { literalValue = node.text; }
|
||||
void OnVisitVariableNode(VariableNode &node) override {}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode &node) override {}
|
||||
void OnVisitIdentifierNode(IdentifierNode &node) override {}
|
||||
void OnVisitEmptyNode(EmptyNode &node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode &node) override {}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode &node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode &functionCall) override {}
|
||||
};
|
||||
|
||||
void ExpressionVariablePathFinder::OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode &node) {
|
||||
// Try to find a literal accessor or add a child with an empty name, which
|
||||
// will be interpreted as "take the first child/item of the structure/array".
|
||||
gd::ExpressionLiteralFinder expressionLiteralFinder;
|
||||
if (node.expression) {
|
||||
node.expression->Visit(expressionLiteralFinder);
|
||||
}
|
||||
childVariableNames.push_back(expressionLiteralFinder.literalValue);
|
||||
|
||||
if (node.child && &node != lastNodeToCheck) {
|
||||
node.child->Visit(*this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Find the pre-scoped container of legacy variables or the object name
|
||||
* from the function call node.
|
||||
*/
|
||||
class GD_CORE_API ExpressionVariableContextFinder
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
|
||||
virtual ~ExpressionVariableContextFinder(){};
|
||||
|
||||
gd::String objectName;
|
||||
gd::String parameterType;
|
||||
gd::ExpressionNode* variableNode;
|
||||
|
||||
ExpressionVariableContextFinder(
|
||||
const gd::Platform& platform_,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_)
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
variableNode(nullptr),
|
||||
objectName(""),
|
||||
parameterType("") {};
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
if (variableNode) {
|
||||
// This is not possible
|
||||
return;
|
||||
}
|
||||
variableNode = &node;
|
||||
|
||||
// Check if the parent is a function call, in which we might be dealing
|
||||
// with a legacy pre-scoped variable parameter:
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
if (variableNode) {
|
||||
// This is not possible
|
||||
return;
|
||||
}
|
||||
// This node is not necessarily a variable node.
|
||||
// It will be checked when visiting the FunctionCallNode, just after.
|
||||
variableNode = &node;
|
||||
|
||||
// Check if the parent is a function call, in which we might be dealing
|
||||
// with a legacy pre-scoped variable parameter:
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {
|
||||
int parameterIndex = -1;
|
||||
for (int i = 0; i < functionCall.parameters.size(); i++) {
|
||||
if (functionCall.parameters.at(i).get() == variableNode) {
|
||||
parameterIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parameterIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& objectsContainersList =
|
||||
projectScopedContainers.GetObjectsContainersList();
|
||||
|
||||
const gd::ParameterMetadata* parameterMetadata =
|
||||
MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, objectsContainersList, functionCall, parameterIndex);
|
||||
if (parameterMetadata == nullptr) return; // Unexpected
|
||||
|
||||
if (parameterMetadata->GetType() == "objectvar") {
|
||||
// Legacy convention where a "objectvar"
|
||||
// parameter represents a variable of the object represented by the
|
||||
// previous "object" parameter. The object on which the function is
|
||||
// called is returned if no previous parameters are objects.
|
||||
objectName = functionCall.objectName;
|
||||
for (int previousIndex = parameterIndex - 1; previousIndex >= 0;
|
||||
previousIndex--) {
|
||||
const gd::ParameterMetadata* previousParameterMetadata =
|
||||
MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, objectsContainersList, functionCall, previousIndex);
|
||||
if (previousParameterMetadata != nullptr &&
|
||||
gd::ParameterMetadata::IsObject(
|
||||
previousParameterMetadata->GetType())) {
|
||||
auto previousParameterNode =
|
||||
functionCall.parameters[previousIndex].get();
|
||||
IdentifierNode* objectNode =
|
||||
dynamic_cast<IdentifierNode*>(previousParameterNode);
|
||||
objectName = objectNode->identifierName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
parameterType = parameterMetadata->GetType();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const gd::Platform& platform;
|
||||
const gd::ProjectScopedContainers& projectScopedContainers;
|
||||
|
||||
};
|
||||
|
||||
VariableAndItsParent ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
const gd::Platform &platform,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::ExpressionNode &node) {
|
||||
|
||||
gd::ExpressionVariableContextFinder contextFinder(platform,
|
||||
projectScopedContainers);
|
||||
node.Visit(contextFinder);
|
||||
if (!contextFinder.variableNode) {
|
||||
return {};
|
||||
}
|
||||
|
||||
gd::ExpressionVariablePathFinder typeFinder(platform, projectScopedContainers,
|
||||
contextFinder.parameterType,
|
||||
contextFinder.objectName, &node);
|
||||
contextFinder.variableNode->Visit(typeFinder);
|
||||
|
||||
if (typeFinder.variableName.empty() || !typeFinder.variablesContainer) {
|
||||
return {};
|
||||
}
|
||||
return typeFinder.WalkUntilLastParent(*typeFinder.variablesContainer,
|
||||
typeFinder.childVariableNames);
|
||||
}
|
||||
|
||||
} // namespace gd
|
354
Core/GDCore/IDE/Events/ExpressionVariablePathFinder.h
Normal file
354
Core/GDCore/IDE/Events/ExpressionVariablePathFinder.h
Normal file
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
|
||||
namespace gd {
|
||||
class Platform;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Contains a variables container or a variable. Useful
|
||||
* to refer to the parent of a variable (which can be a VariablesContainer
|
||||
* or another Variable).
|
||||
*/
|
||||
struct VariableAndItsParent {
|
||||
const gd::VariablesContainer* parentVariablesContainer;
|
||||
const gd::Variable* parentVariable;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Find a variable path from an expression node.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionVariablePathFinder
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
|
||||
static VariableAndItsParent GetLastParentOfNode(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::ExpressionNode& node);
|
||||
|
||||
static const gd::Variable::Type GetVariableType(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::ExpressionNode& node, const gd::String& objectName) {
|
||||
// The context is not checked because this is called on variable parameters.
|
||||
gd::String parameterType = objectName.empty() ? "variable" : "objectvar";
|
||||
gd::String objName = objectName;
|
||||
gd::ExpressionVariablePathFinder typeFinder(
|
||||
platform, projectScopedContainers, parameterType, objName);
|
||||
node.Visit(typeFinder);
|
||||
|
||||
if (typeFinder.variableName.empty() || !typeFinder.variablesContainer) {
|
||||
return gd::Variable::Unknown;
|
||||
}
|
||||
auto *variable = typeFinder.WalkUntilLastChild(
|
||||
typeFinder.variablesContainer->Get(typeFinder.variableName),
|
||||
typeFinder.childVariableNames);
|
||||
return variable ? variable->GetType() : gd::Variable::Unknown;
|
||||
}
|
||||
|
||||
static const gd::Variable::Type GetArrayVariableType(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::ExpressionNode& node, const gd::String& objectName) {
|
||||
// The context is not checked because this is called on variable parameters.
|
||||
gd::String parameterType = objectName.empty() ? "variable" : "objectvar";
|
||||
gd::String objName = objectName;
|
||||
gd::ExpressionVariablePathFinder typeFinder(
|
||||
platform, projectScopedContainers, parameterType, objName);
|
||||
node.Visit(typeFinder);
|
||||
|
||||
if (typeFinder.variableName.empty() || !typeFinder.variablesContainer) {
|
||||
return gd::Variable::Unknown;
|
||||
}
|
||||
auto *variable = typeFinder.WalkUntilLastChild(
|
||||
typeFinder.variablesContainer->Get(typeFinder.variableName),
|
||||
typeFinder.childVariableNames);
|
||||
return variable && variable->GetChildrenCount() > 0
|
||||
? variable->GetAtIndex(0).GetType()
|
||||
: gd::Variable::Unknown;
|
||||
}
|
||||
|
||||
virtual ~ExpressionVariablePathFinder(){};
|
||||
|
||||
protected:
|
||||
ExpressionVariablePathFinder(
|
||||
const gd::Platform& platform_,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_,
|
||||
const gd::String& parameterType_,
|
||||
gd::String& objectName_,
|
||||
const gd::ExpressionNode* lastNodeToCheck_ = nullptr)
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
parameterType(parameterType_),
|
||||
objectName(objectName_),
|
||||
lastNodeToCheck(lastNodeToCheck_),
|
||||
variablesContainer(nullptr),
|
||||
variableName(""),
|
||||
bailOutBecauseEmptyVariableName(false) {};
|
||||
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override;
|
||||
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
FindVariableFor(node.name);
|
||||
if (node.child && &node != lastNodeToCheck) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
if (node.name.empty() && node.child) {
|
||||
// A variable accessor should always have a name if it has a child (i.e:
|
||||
// another accessor). While the parser may have generated an empty name,
|
||||
// flag this so we avoid finding a wrong parent (and so, run the risk of
|
||||
// giving wrong autocompletions).
|
||||
bailOutBecauseEmptyVariableName = true;
|
||||
}
|
||||
if (variableName.empty()) {
|
||||
const auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
|
||||
if (objectsContainersList.HasObjectOrGroupWithVariableNamed(objectName,
|
||||
node.name) !=
|
||||
gd::ObjectsContainersList::VariableExistence::DoesNotExist) {
|
||||
variableName = node.name;
|
||||
variablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(objectName);
|
||||
}
|
||||
} else {
|
||||
childVariableNames.push_back(node.name);
|
||||
}
|
||||
if (node.child && &node != lastNodeToCheck) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
FindVariableFor(node.identifierName, node.identifierNameDotLocation.IsValid() ? &node.childIdentifierName : nullptr);
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {}
|
||||
|
||||
void FindVariableFor(const gd::String& identifier, gd::String* childIdentifier = nullptr) {
|
||||
if (!objectName.empty()) {
|
||||
const auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
|
||||
if (objectsContainersList.HasObjectOrGroupWithVariableNamed(objectName,
|
||||
identifier) !=
|
||||
gd::ObjectsContainersList::VariableExistence::DoesNotExist) {
|
||||
variableName = identifier;
|
||||
variablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(objectName);
|
||||
if (childIdentifier) {
|
||||
childVariableNames.push_back(*childIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (parameterType == "scenevar") {
|
||||
// The node represents a variable name, and the variables container
|
||||
// containing it was identified in the FunctionCallNode.
|
||||
variablesContainer = projectScopedContainers.GetVariablesContainersList()
|
||||
.GetBottomMostVariablesContainer();
|
||||
variableName = identifier;
|
||||
if (childIdentifier) {
|
||||
childVariableNames.push_back(*childIdentifier);
|
||||
}
|
||||
}
|
||||
else if (parameterType == "globalvar") {
|
||||
// The node represents a variable name, and the variables container
|
||||
// containing it was identified in the FunctionCallNode.
|
||||
variablesContainer = projectScopedContainers.GetVariablesContainersList()
|
||||
.GetTopMostVariablesContainer();
|
||||
variableName = identifier;
|
||||
if (childIdentifier) {
|
||||
childVariableNames.push_back(*childIdentifier);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, the identifier is to be interpreted as usual:
|
||||
// it can be an object (on which a variable is accessed),
|
||||
// or a variable.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
identifier,
|
||||
[&]() {
|
||||
objectName = identifier;
|
||||
if (childIdentifier) {
|
||||
if (parameterType == "variable") {
|
||||
// An object is overlapping the variable.
|
||||
// Even in "variable" parameters, this is not allowed to be
|
||||
// consistent with expressions.
|
||||
} else {
|
||||
// It's an object variable expression.
|
||||
const auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
|
||||
if (objectsContainersList.HasObjectOrGroupWithVariableNamed(objectName,
|
||||
*childIdentifier) !=
|
||||
gd::ObjectsContainersList::VariableExistence::DoesNotExist) {
|
||||
variableName = *childIdentifier;
|
||||
variablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(objectName);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList().Has(identifier)) {
|
||||
variablesContainer =
|
||||
&(projectScopedContainers.GetVariablesContainersList()
|
||||
.GetVariablesContainerFromVariableName(identifier));
|
||||
variableName = identifier;
|
||||
if (childIdentifier) {
|
||||
childVariableNames.push_back(*childIdentifier);
|
||||
}
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
// Ignore properties here.
|
||||
// There is no support for "children" of properties.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore parameters here.
|
||||
// There is no support for "children" of parameters.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore unrecognised identifiers here.
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const gd::Variable* WalkUntilLastChild(
|
||||
const gd::Variable& variable,
|
||||
const std::vector<gd::String>& childVariableNames,
|
||||
size_t startIndex = 0) {
|
||||
if (bailOutBecauseEmptyVariableName)
|
||||
return nullptr; // Do not even attempt to find the parent if we had an issue
|
||||
// when visiting nodes.
|
||||
|
||||
const gd::Variable* currentVariable = &variable;
|
||||
|
||||
for (size_t index = startIndex; index < childVariableNames.size();
|
||||
++index) {
|
||||
const gd::String& childName = childVariableNames[index];
|
||||
|
||||
if (childName.empty()) {
|
||||
if (currentVariable->GetChildrenCount() == 0) {
|
||||
// The array or structure is empty, we can't walk through it - there
|
||||
// is no "parent".
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (currentVariable->GetType() == gd::Variable::Array) {
|
||||
currentVariable = ¤tVariable->GetAtIndex(0);
|
||||
} else {
|
||||
currentVariable =
|
||||
currentVariable->GetAllChildren().begin()->second.get();
|
||||
}
|
||||
} else {
|
||||
if (!currentVariable->HasChild(childName)) {
|
||||
// Non existing child - there is no "parent".
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
currentVariable = ¤tVariable->GetChild(childName);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the last parent of the chain of variables (so not the last
|
||||
// variable but the one before it).
|
||||
return currentVariable;
|
||||
}
|
||||
|
||||
VariableAndItsParent WalkUntilLastParent(
|
||||
const gd::Variable& variable,
|
||||
const std::vector<gd::String>& childVariableNames,
|
||||
size_t startIndex = 0) {
|
||||
if (bailOutBecauseEmptyVariableName)
|
||||
return {}; // Do not even attempt to find the parent if we had an issue
|
||||
// when visiting nodes.
|
||||
|
||||
const gd::Variable* currentVariable = &variable;
|
||||
|
||||
// Walk until size - 1 as we want the last parent.
|
||||
for (size_t index = startIndex; index + 1 < childVariableNames.size();
|
||||
++index) {
|
||||
const gd::String& childName = childVariableNames[index];
|
||||
|
||||
if (childName.empty()) {
|
||||
if (currentVariable->GetChildrenCount() == 0) {
|
||||
// The array or structure is empty, we can't walk through it - there
|
||||
// is no "parent".
|
||||
return {};
|
||||
}
|
||||
|
||||
if (currentVariable->GetType() == gd::Variable::Array) {
|
||||
currentVariable = ¤tVariable->GetAtIndex(0);
|
||||
} else {
|
||||
currentVariable =
|
||||
currentVariable->GetAllChildren().begin()->second.get();
|
||||
}
|
||||
} else {
|
||||
if (!currentVariable->HasChild(childName)) {
|
||||
// Non existing child - there is no "parent".
|
||||
return {};
|
||||
}
|
||||
|
||||
currentVariable = ¤tVariable->GetChild(childName);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the last parent of the chain of variables (so not the last
|
||||
// variable but the one before it).
|
||||
return {.parentVariable = currentVariable};
|
||||
}
|
||||
|
||||
VariableAndItsParent WalkUntilLastParent(
|
||||
const gd::VariablesContainer& variablesContainer,
|
||||
const std::vector<gd::String>& childVariableNames) {
|
||||
if (bailOutBecauseEmptyVariableName)
|
||||
return {}; // Do not even attempt to find the parent if we had an issue
|
||||
// when visiting nodes.
|
||||
|
||||
if (variableName.empty())
|
||||
return {}; // There is no "parent" to the variables container itself.
|
||||
|
||||
const gd::Variable* variable = variablesContainer.Has(variableName)
|
||||
? &variablesContainer.Get(variableName)
|
||||
: nullptr;
|
||||
if (childVariableNames.empty() || !variable)
|
||||
return {// No child: the parent is the variables container itself.
|
||||
.parentVariablesContainer = &variablesContainer};
|
||||
|
||||
return WalkUntilLastParent(*variable, childVariableNames, 0);
|
||||
}
|
||||
|
||||
const gd::Platform& platform;
|
||||
const gd::ProjectScopedContainers& projectScopedContainers;
|
||||
const gd::String& parameterType;
|
||||
gd::String& objectName;
|
||||
const gd::ExpressionNode* lastNodeToCheck;
|
||||
|
||||
const gd::VariablesContainer* variablesContainer;
|
||||
gd::String variableName;
|
||||
std::vector<gd::String> childVariableNames;
|
||||
bool bailOutBecauseEmptyVariableName;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -22,12 +22,7 @@ void EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
const gd::EventsFunctionsContainer functionContainer,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
// Functions don't have access to objects from the "outer" scope.
|
||||
outputGlobalObjectsContainer.GetObjects().clear();
|
||||
outputGlobalObjectsContainer.GetObjectGroups().Clear();
|
||||
|
||||
// Functions scope for objects is defined according
|
||||
// to parameters
|
||||
outputObjectsContainer.GetObjects().clear();
|
||||
@@ -45,13 +40,11 @@ void EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
// The context is build the same way as free function...
|
||||
FreeEventsFunctionToObjectsContainer(project,
|
||||
eventsBasedBehavior.GetEventsFunctions(),
|
||||
eventsFunction,
|
||||
outputGlobalObjectsContainer,
|
||||
outputObjectsContainer);
|
||||
|
||||
// ...and has an "Object" by convention...
|
||||
@@ -83,13 +76,11 @@ void EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
// The context is build the same way as free function...
|
||||
FreeEventsFunctionToObjectsContainer(project,
|
||||
eventsBasedObject.GetEventsFunctions(),
|
||||
eventsFunction,
|
||||
outputGlobalObjectsContainer,
|
||||
outputObjectsContainer);
|
||||
|
||||
// TODO EBO Use a constant instead a hard coded value "Object".
|
||||
|
@@ -3,11 +3,11 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef EventsFunctionTools_H
|
||||
#define EventsFunctionTools_H
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Project;
|
||||
class EventsFunctionsContainer;
|
||||
@@ -37,8 +37,8 @@ class GD_CORE_API EventsFunctionTools {
|
||||
const gd::Project& project,
|
||||
const gd::EventsFunctionsContainer functionContainer,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
|
||||
/**
|
||||
* \brief Given a behavior events function, initialize the given objects container
|
||||
* with objects described in the events function parameters, in
|
||||
@@ -52,8 +52,8 @@ class GD_CORE_API EventsFunctionTools {
|
||||
const gd::Project& project,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
|
||||
/**
|
||||
* \brief Given a parent-object events function, initialize the given objects container
|
||||
* with objects described in the events function parameters, in
|
||||
@@ -67,10 +67,6 @@ class GD_CORE_API EventsFunctionTools {
|
||||
const gd::Project& project,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
};
|
||||
} // namespace gd
|
||||
|
||||
#endif // EventsFunctionTools_H
|
||||
#endif
|
||||
|
@@ -148,12 +148,6 @@ void ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
|
||||
gd::ArbitraryEventsWorker &worker) {
|
||||
// Add (free) events functions
|
||||
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
project, eventsFunctionsExtension, *eventsFunction,
|
||||
globalObjectsAndGroups, objectsAndGroups);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents());
|
||||
}
|
||||
|
||||
@@ -176,14 +170,11 @@ void ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
// Add (free) events functions
|
||||
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
project, eventsFunctionsExtension, *eventsFunction,
|
||||
globalObjectsAndGroups, objectsAndGroups);
|
||||
auto projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsAndGroups, objectsAndGroups);
|
||||
projectScopedContainers.AddParameters(eventsFunction->GetParametersForEvents(eventsFunctionsExtension));
|
||||
gd::ObjectsContainer parameterObjectsContainer;
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project, eventsFunctionsExtension, *eventsFunction,
|
||||
parameterObjectsContainer);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
|
||||
}
|
||||
@@ -192,13 +183,13 @@ void ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
|
||||
for (auto &&eventsBasedBehavior :
|
||||
eventsFunctionsExtension.GetEventsBasedBehaviors()
|
||||
.GetInternalVector()) {
|
||||
ExposeEventsBasedBehaviorEvents(project, *eventsBasedBehavior, worker);
|
||||
ExposeEventsBasedBehaviorEvents(project, eventsFunctionsExtension, *eventsBasedBehavior, worker);
|
||||
}
|
||||
|
||||
// Add (object) events functions
|
||||
for (auto &&eventsBasedObject :
|
||||
eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) {
|
||||
ExposeEventsBasedObjectEvents(project, *eventsBasedObject, worker);
|
||||
ExposeEventsBasedObjectEvents(project, eventsFunctionsExtension, *eventsBasedObject, worker);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,20 +203,17 @@ void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
gd::Project &project, const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
auto &behaviorEventsFunctions = eventsBasedBehavior.GetEventsFunctions();
|
||||
for (auto &&eventsFunction : behaviorEventsFunctions.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
|
||||
project, eventsBasedBehavior, *eventsFunction, globalObjectsAndGroups,
|
||||
objectsAndGroups);
|
||||
auto projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsAndGroups, objectsAndGroups);
|
||||
projectScopedContainers.AddPropertiesContainer(eventsBasedBehavior.GetSharedPropertyDescriptors());
|
||||
projectScopedContainers.AddPropertiesContainer(eventsBasedBehavior.GetPropertyDescriptors());
|
||||
projectScopedContainers.AddParameters(eventsFunction->GetParametersForEvents(eventsBasedBehavior.GetEventsFunctions()));
|
||||
|
||||
gd::ObjectsContainer parameterObjectsContainers;
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForBehaviorEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior,
|
||||
*eventsFunction, parameterObjectsContainers);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
|
||||
}
|
||||
@@ -236,30 +224,23 @@ void ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
|
||||
gd::ArbitraryEventsWorker &worker) {
|
||||
auto &objectEventsFunctions = eventsBasedObject.GetEventsFunctions();
|
||||
for (auto &&eventsFunction : objectEventsFunctions.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
project, eventsBasedObject, *eventsFunction, globalObjectsAndGroups,
|
||||
objectsAndGroups);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents());
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
|
||||
gd::Project &project, const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
auto &objectEventsFunctions = eventsBasedObject.GetEventsFunctions();
|
||||
for (auto &&eventsFunction : objectEventsFunctions.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
project, eventsBasedObject, *eventsFunction, globalObjectsAndGroups,
|
||||
objectsAndGroups);
|
||||
auto projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsAndGroups, objectsAndGroups);
|
||||
projectScopedContainers.AddPropertiesContainer(eventsBasedObject.GetPropertyDescriptors());
|
||||
projectScopedContainers.AddParameters(eventsFunction->GetParametersForEvents(eventsBasedObject.GetEventsFunctions()));
|
||||
|
||||
gd::ObjectsContainer parameterObjectsContainers;
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForObjectEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsBasedObject,
|
||||
*eventsFunction, parameterObjectsContainers);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
|
||||
}
|
||||
|
@@ -122,7 +122,9 @@ public:
|
||||
* event-based behavior.
|
||||
*/
|
||||
static void ExposeEventsBasedBehaviorEvents(
|
||||
gd::Project &project, const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker);
|
||||
|
||||
/**
|
||||
@@ -144,10 +146,11 @@ public:
|
||||
* This should be the preferred way to traverse all the events of an
|
||||
* event-based object.
|
||||
*/
|
||||
static void
|
||||
ExposeEventsBasedObjectEvents(gd::Project &project,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker);
|
||||
static void ExposeEventsBasedObjectEvents(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker);
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all ObjectContainers of the project
|
||||
|
@@ -30,14 +30,18 @@ void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project &project) {
|
||||
project.GetLayout(i).GetEvents().Clear();
|
||||
}
|
||||
|
||||
// Keep the EventsBasedObject object list because it's useful for the Runtime
|
||||
// Keep:
|
||||
// - the EventsBasedObject object list because it's useful for the Runtime
|
||||
// to create the child-object.
|
||||
// - the globalVariables and sceneVariables
|
||||
for (unsigned int extensionIndex = 0;
|
||||
extensionIndex < project.GetEventsFunctionsExtensionsCount();
|
||||
++extensionIndex) {
|
||||
auto &extension = project.GetEventsFunctionsExtension(extensionIndex);
|
||||
auto &eventsBasedObjects = extension.GetEventsBasedObjects();
|
||||
if (eventsBasedObjects.size() == 0) {
|
||||
if (eventsBasedObjects.size() == 0 &&
|
||||
extension.GetGlobalVariables().Count() == 0 &&
|
||||
extension.GetSceneVariables().Count() == 0) {
|
||||
project.RemoveEventsFunctionsExtension(extension.GetName());
|
||||
extensionIndex--;
|
||||
continue;
|
||||
@@ -51,6 +55,7 @@ void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project &project) {
|
||||
eventsBasedObject.GetPropertyDescriptors().GetInternalVector().clear();
|
||||
}
|
||||
extension.GetEventsBasedBehaviors().Clear();
|
||||
extension.ClearEventsFunctions();
|
||||
}
|
||||
}
|
||||
|
||||
|
241
Core/GDCore/IDE/VariableInstructionSwitcher.cpp
Normal file
241
Core/GDCore/IDE/VariableInstructionSwitcher.cpp
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "VariableInstructionSwitcher.h"
|
||||
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariablePathFinder.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
const gd::String VariableInstructionSwitcher::variableGetterIdentifier =
|
||||
"NumberVariable";
|
||||
const gd::String VariableInstructionSwitcher::variableSetterIdentifier =
|
||||
"SetNumberVariable";
|
||||
const gd::String VariableInstructionSwitcher::variablePushIdentifier =
|
||||
"PushNumber";
|
||||
const gd::String VariableInstructionSwitcher::objectVariableGetterIdentifier =
|
||||
"NumberObjectVariable";
|
||||
const gd::String VariableInstructionSwitcher::objectVariableSetterIdentifier =
|
||||
"SetNumberObjectVariable";
|
||||
const gd::String VariableInstructionSwitcher::objectVariablePushIdentifier =
|
||||
"PushNumberToObjectVariable";
|
||||
const gd::String VariableInstructionSwitcher::unknownInstructionIdentifier = "";
|
||||
|
||||
bool VariableInstructionSwitcher::IsSwitchableVariableInstruction(
|
||||
const gd::String &instructionType) {
|
||||
return instructionType == "NumberVariable" ||
|
||||
instructionType == "StringVariable" ||
|
||||
instructionType == "BooleanVariable" ||
|
||||
|
||||
instructionType == "SetNumberVariable" ||
|
||||
instructionType == "SetStringVariable" ||
|
||||
instructionType == "SetBooleanVariable" ||
|
||||
|
||||
instructionType == "PushNumber" || instructionType == "PushString" ||
|
||||
instructionType == "PushBoolean" ||
|
||||
|
||||
IsSwitchableObjectVariableInstruction(instructionType);
|
||||
}
|
||||
|
||||
bool VariableInstructionSwitcher::IsSwitchableObjectVariableInstruction(
|
||||
const gd::String &instructionType) {
|
||||
return instructionType == "NumberObjectVariable" ||
|
||||
instructionType == "StringObjectVariable" ||
|
||||
instructionType == "BooleanObjectVariable" ||
|
||||
|
||||
instructionType == "SetNumberObjectVariable" ||
|
||||
instructionType == "SetStringObjectVariable" ||
|
||||
instructionType == "SetBooleanObjectVariable" ||
|
||||
|
||||
instructionType == "PushNumberToObjectVariable" ||
|
||||
instructionType == "PushStringToObjectVariable" ||
|
||||
instructionType == "PushBooleanToObjectVariable";
|
||||
}
|
||||
|
||||
const gd::String &
|
||||
VariableInstructionSwitcher::GetSwitchableVariableInstructionIdentifier(
|
||||
const gd::String &instructionType) {
|
||||
return instructionType == "NumberVariable" ||
|
||||
instructionType == "StringVariable" ||
|
||||
instructionType == "BooleanVariable"
|
||||
? VariableInstructionSwitcher::variableGetterIdentifier
|
||||
:
|
||||
|
||||
instructionType == "SetNumberVariable" ||
|
||||
instructionType == "SetStringVariable" ||
|
||||
instructionType == "SetBooleanVariable"
|
||||
? VariableInstructionSwitcher::variableSetterIdentifier
|
||||
:
|
||||
|
||||
instructionType == "PushNumber" || instructionType == "PushString" ||
|
||||
instructionType == "PushBoolean"
|
||||
? VariableInstructionSwitcher::variablePushIdentifier
|
||||
:
|
||||
|
||||
instructionType == "NumberObjectVariable" ||
|
||||
instructionType == "StringObjectVariable" ||
|
||||
instructionType == "BooleanObjectVariable"
|
||||
? VariableInstructionSwitcher::objectVariableGetterIdentifier
|
||||
:
|
||||
|
||||
instructionType == "SetNumberObjectVariable" ||
|
||||
instructionType == "SetStringObjectVariable" ||
|
||||
instructionType == "SetBooleanObjectVariable"
|
||||
? VariableInstructionSwitcher::objectVariableSetterIdentifier
|
||||
:
|
||||
|
||||
instructionType == "PushNumberToObjectVariable" ||
|
||||
instructionType == "PushStringToObjectVariable" ||
|
||||
instructionType == "PushBooleanToObjectVariable"
|
||||
? VariableInstructionSwitcher::objectVariablePushIdentifier
|
||||
:
|
||||
|
||||
VariableInstructionSwitcher::unknownInstructionIdentifier;
|
||||
}
|
||||
|
||||
const gd::Variable::Type
|
||||
VariableInstructionSwitcher::GetSwitchableInstructionVariableType(
|
||||
const gd::String &instructionType) {
|
||||
return instructionType == "NumberVariable" ||
|
||||
instructionType == "SetNumberVariable" ||
|
||||
instructionType == "PushNumber" ||
|
||||
instructionType == "NumberObjectVariable" ||
|
||||
instructionType == "SetNumberObjectVariable" ||
|
||||
instructionType == "PushNumberToObjectVariable"
|
||||
? gd::Variable::Number
|
||||
:
|
||||
|
||||
instructionType == "StringVariable" ||
|
||||
instructionType == "SetStringVariable" ||
|
||||
instructionType == "PushString" ||
|
||||
instructionType == "StringObjectVariable" ||
|
||||
instructionType == "SetStringObjectVariable" ||
|
||||
instructionType == "PushStringToObjectVariable"
|
||||
? gd::Variable::String
|
||||
:
|
||||
|
||||
instructionType == "BooleanVariable" ||
|
||||
instructionType == "SetBooleanVariable" ||
|
||||
instructionType == "PushBoolean" ||
|
||||
instructionType == "BooleanObjectVariable" ||
|
||||
instructionType == "SetBooleanObjectVariable" ||
|
||||
instructionType == "PushBooleanToObjectVariable"
|
||||
? gd::Variable::Boolean
|
||||
:
|
||||
|
||||
gd::Variable::Unknown;
|
||||
}
|
||||
|
||||
void VariableInstructionSwitcher::SwitchVariableInstructionType(
|
||||
gd::Instruction &instruction, const gd::Variable::Type variableType) {
|
||||
if (instruction.GetType() == "NumberVariable" ||
|
||||
instruction.GetType() == "StringVariable" ||
|
||||
instruction.GetType() == "BooleanVariable") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("NumberVariable");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("StringVariable");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("BooleanVariable");
|
||||
}
|
||||
} else if (instruction.GetType() == "SetNumberVariable" ||
|
||||
instruction.GetType() == "SetStringVariable" ||
|
||||
instruction.GetType() == "SetBooleanVariable") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("SetNumberVariable");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("SetStringVariable");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("SetBooleanVariable");
|
||||
}
|
||||
} else if (instruction.GetType() == "PushNumber" ||
|
||||
instruction.GetType() == "PushString" ||
|
||||
instruction.GetType() == "PushBoolean") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("PushNumber");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("PushString");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("PushBoolean");
|
||||
}
|
||||
} else if (instruction.GetType() == "NumberObjectVariable" ||
|
||||
instruction.GetType() == "StringObjectVariable" ||
|
||||
instruction.GetType() == "BooleanObjectVariable") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("NumberObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("StringObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("BooleanObjectVariable");
|
||||
}
|
||||
} else if (instruction.GetType() == "SetNumberObjectVariable" ||
|
||||
instruction.GetType() == "SetStringObjectVariable" ||
|
||||
instruction.GetType() == "SetBooleanObjectVariable") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("SetNumberObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("SetStringObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("SetBooleanObjectVariable");
|
||||
}
|
||||
} else if (instruction.GetType() == "PushNumberToObjectVariable" ||
|
||||
instruction.GetType() == "PushStringToObjectVariable" ||
|
||||
instruction.GetType() == "PushBooleanToObjectVariable") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("PushNumberToObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("PushStringToObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("PushBooleanToObjectVariable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const gd::Variable::Type
|
||||
VariableInstructionSwitcher::GetVariableTypeFromParameters(
|
||||
const gd::Platform &platform,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
const gd::Instruction &instruction) {
|
||||
if (instruction.GetParametersCount() < 2 ||
|
||||
!gd::VariableInstructionSwitcher::IsSwitchableVariableInstruction(
|
||||
instruction.GetType())) {
|
||||
return gd::Variable::Type::Unknown;
|
||||
}
|
||||
const bool isObjectVariable =
|
||||
gd::VariableInstructionSwitcher::IsSwitchableObjectVariableInstruction(
|
||||
instruction.GetType());
|
||||
const gd::String &objectName =
|
||||
isObjectVariable ? instruction.GetParameter(0).GetPlainString() : "";
|
||||
|
||||
const std::size_t variableParameterIndex = isObjectVariable ? 1 : 0;
|
||||
auto &variableExpressionNode =
|
||||
*instruction.GetParameter(variableParameterIndex).GetRootNode();
|
||||
|
||||
auto variableType = gd::ExpressionVariablePathFinder::GetVariableType(
|
||||
platform, projectScopedContainers, variableExpressionNode, objectName);
|
||||
return variableType == gd::Variable::Type::Array
|
||||
? // "Push" actions need the child type to be able to switch.
|
||||
gd::ExpressionVariablePathFinder::GetArrayVariableType(
|
||||
platform, projectScopedContainers, variableExpressionNode,
|
||||
objectName)
|
||||
: variableType;
|
||||
}
|
||||
|
||||
void VariableInstructionSwitcher::SwitchBetweenUnifiedInstructionIfNeeded(
|
||||
const gd::Platform &platform,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::Instruction &instruction) {
|
||||
const auto variableType =
|
||||
gd::VariableInstructionSwitcher::GetVariableTypeFromParameters(
|
||||
platform, projectScopedContainers, instruction);
|
||||
if (variableType != gd::Variable::Type::Unknown) {
|
||||
gd::VariableInstructionSwitcher::SwitchVariableInstructionType(
|
||||
instruction, variableType);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
91
Core/GDCore/IDE/VariableInstructionSwitcher.h
Normal file
91
Core/GDCore/IDE/VariableInstructionSwitcher.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "GDCore/Project/Variable.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Instruction;
|
||||
class Platform;
|
||||
class ProjectScopedContainers;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
/**
|
||||
* Events set and check variables with sets of 3 instructions for:
|
||||
* - number
|
||||
* - string
|
||||
* - boolean
|
||||
*
|
||||
* Users only see 1 instruction. The editor automatically switches between the 3
|
||||
* instructions according to the variable type.
|
||||
*/
|
||||
class GD_CORE_API VariableInstructionSwitcher {
|
||||
public:
|
||||
/**
|
||||
* \brief Return true if the instruction is a variable getter or setter
|
||||
* (including object variable instructions).
|
||||
*/
|
||||
static bool
|
||||
IsSwitchableVariableInstruction(const gd::String &instructionType);
|
||||
|
||||
/**
|
||||
* \brief Return true if the instruction is an object variable getter or
|
||||
* setter.
|
||||
*/
|
||||
static bool
|
||||
IsSwitchableObjectVariableInstruction(const gd::String &instructionType);
|
||||
|
||||
/**
|
||||
* \brief Return the common identifier for variable getter or setter or an
|
||||
* empty string otherwise.
|
||||
*
|
||||
* The instruction type of the "number" one is actually used as the common
|
||||
* identifier.
|
||||
*/
|
||||
static const gd::String &
|
||||
GetSwitchableVariableInstructionIdentifier(const gd::String &instructionType);
|
||||
|
||||
/**
|
||||
* \brief Return the variable type for variable getter or setter.
|
||||
*/
|
||||
static const gd::Variable::Type
|
||||
GetSwitchableInstructionVariableType(const gd::String &instructionType);
|
||||
|
||||
/**
|
||||
* \brief Modify the instruction type to match the given variable type.
|
||||
*/
|
||||
static void
|
||||
SwitchVariableInstructionType(gd::Instruction &instruction,
|
||||
const gd::Variable::Type variableType);
|
||||
|
||||
/**
|
||||
* \brief Return the variable type of the instruction parameter.
|
||||
*/
|
||||
static const gd::Variable::Type GetVariableTypeFromParameters(
|
||||
const gd::Platform &platform,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
const gd::Instruction &instruction);
|
||||
|
||||
/**
|
||||
* \brief Modify the instruction type to match the variable type of the
|
||||
* instruction parameter.
|
||||
*/
|
||||
static void SwitchBetweenUnifiedInstructionIfNeeded(
|
||||
const gd::Platform &platform,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::Instruction &instruction);
|
||||
|
||||
private:
|
||||
static const gd::String variableGetterIdentifier;
|
||||
static const gd::String variableSetterIdentifier;
|
||||
static const gd::String variablePushIdentifier;
|
||||
static const gd::String objectVariableGetterIdentifier;
|
||||
static const gd::String objectVariableSetterIdentifier;
|
||||
static const gd::String objectVariablePushIdentifier;
|
||||
static const gd::String unknownInstructionIdentifier;
|
||||
};
|
||||
} // namespace gd
|
@@ -140,7 +140,6 @@ void WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
|
||||
|
||||
VariablesChangeset
|
||||
WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
gd::Project &project,
|
||||
const gd::SerializerElement &oldSerializedVariablesContainer,
|
||||
const gd::VariablesContainer &newVariablesContainer) {
|
||||
gd::VariablesChangeset changeset;
|
||||
@@ -180,6 +179,11 @@ WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
changeset.oldToNewVariableNames[oldName] = variableName;
|
||||
}
|
||||
|
||||
const auto &oldVariable = oldVariablesContainer.Get(oldName);
|
||||
if (gd::WholeProjectRefactorer::HasAnyVariableTypeChanged(oldVariable, variable)) {
|
||||
changeset.typeChangedVariableNames.insert(variableName);
|
||||
}
|
||||
|
||||
// Renamed or not, this is not a removed variable.
|
||||
removedUuidAndNames.erase(variable.GetPersistentUuid());
|
||||
}
|
||||
@@ -192,12 +196,54 @@ WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
return changeset;
|
||||
}
|
||||
|
||||
bool WholeProjectRefactorer::HasAnyVariableTypeChanged(
|
||||
const gd::Variable &oldVariable, const gd::Variable &newVariable) {
|
||||
if (newVariable.GetType() != oldVariable.GetType()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (newVariable.GetChildrenCount() == 0 ||
|
||||
oldVariable.GetChildrenCount() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unordered_map<gd::String, gd::String> removedUuidAndNames;
|
||||
for (const auto &pair : oldVariable.GetAllChildren()) {
|
||||
const auto &oldName = pair.first;
|
||||
const auto oldChild = pair.second;
|
||||
|
||||
// All variables are candidate to be removed.
|
||||
removedUuidAndNames[oldChild->GetPersistentUuid()] = oldName;
|
||||
}
|
||||
|
||||
for (const auto &pair : newVariable.GetAllChildren()) {
|
||||
const auto &newName = pair.first;
|
||||
const auto newChild = pair.second;
|
||||
|
||||
auto existingOldVariableUuidAndName =
|
||||
removedUuidAndNames.find(newChild->GetPersistentUuid());
|
||||
if (existingOldVariableUuidAndName == removedUuidAndNames.end()) {
|
||||
// This is a new variable.
|
||||
continue;
|
||||
}
|
||||
const gd::String &oldName = existingOldVariableUuidAndName->second;
|
||||
const auto &oldChild = oldVariable.GetChild(oldName);
|
||||
|
||||
if (gd::WholeProjectRefactorer::HasAnyVariableTypeChanged(oldChild,
|
||||
*newChild)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
gd::Project &project, const gd::VariablesContainer &newVariablesContainer,
|
||||
const gd::VariablesChangeset &changeset) {
|
||||
gd::EventsVariableReplacer eventsVariableReplacer(
|
||||
project.GetCurrentPlatform(), newVariablesContainer,
|
||||
changeset.oldToNewVariableNames, changeset.removedVariableNames);
|
||||
changeset.oldToNewVariableNames, changeset.removedVariableNames,
|
||||
changeset.typeChangedVariableNames);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
|
||||
eventsVariableReplacer);
|
||||
}
|
||||
@@ -208,7 +254,7 @@ void WholeProjectRefactorer::UpdateExtensionNameInEventsBasedBehavior(
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::String &sourceExtensionName) {
|
||||
const EventBasedBehaviorBrowser eventBasedBehaviorExposer(
|
||||
eventsBasedBehavior);
|
||||
eventsFunctionsExtension, eventsBasedBehavior);
|
||||
WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
project, eventsFunctionsExtension, sourceExtensionName,
|
||||
eventsFunctionsExtension.GetName(), eventBasedBehaviorExposer);
|
||||
@@ -724,7 +770,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
oldPropertyName, newPropertyName);
|
||||
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
project, eventsBasedBehavior, behaviorRenamer);
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior, behaviorRenamer);
|
||||
} else {
|
||||
// Properties that represent primitive values will be used through
|
||||
// their related actions/conditions/expressions. Rename these.
|
||||
@@ -794,7 +840,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
|
||||
oldPropertyName, newPropertyName);
|
||||
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
project, eventsBasedBehavior, behaviorRenamer);
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior, behaviorRenamer);
|
||||
} else {
|
||||
// Properties that represent primitive values will be used through
|
||||
// their related actions/conditions/expressions. Rename these.
|
||||
|
@@ -10,6 +10,8 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
|
||||
namespace gd {
|
||||
class Platform;
|
||||
class Project;
|
||||
@@ -41,6 +43,12 @@ namespace gd {
|
||||
struct VariablesChangeset {
|
||||
std::unordered_set<gd::String> removedVariableNames;
|
||||
std::unordered_map<gd::String, gd::String> oldToNewVariableNames;
|
||||
/**
|
||||
* No distinction is done between a change of the variable itself or its
|
||||
* children. Ensuring that a child is actually the one with a type change
|
||||
* would take more time than checking the instruction type is rightly set.
|
||||
*/
|
||||
std::unordered_set<gd::String> typeChangedVariableNames;
|
||||
|
||||
bool HasRemovedVariables() { return !removedVariableNames.empty(); }
|
||||
|
||||
@@ -62,7 +70,6 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
* \brief Compute the changes made on the variables of a variable container.
|
||||
*/
|
||||
static VariablesChangeset ComputeChangesetForVariablesContainer(
|
||||
gd::Project &project,
|
||||
const gd::SerializerElement &oldSerializedVariablesContainer,
|
||||
const gd::VariablesContainer &newVariablesContainer);
|
||||
|
||||
@@ -555,6 +562,9 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& behaviorName,
|
||||
std::unordered_set<gd::String>& dependentBehaviorNames);
|
||||
|
||||
static bool HasAnyVariableTypeChanged(const gd::Variable &oldVariable,
|
||||
const gd::Variable &newVariable);
|
||||
|
||||
static const gd::String behaviorObjectParameterName;
|
||||
static const gd::String parentObjectParameterName;
|
||||
|
||||
|
@@ -107,6 +107,7 @@ public:
|
||||
return Insert(object, position);
|
||||
}
|
||||
void RemoveEventsFunction(const gd::String& name) { return Remove(name); }
|
||||
void ClearEventsFunctions() { return Clear(); }
|
||||
void MoveEventsFunction(std::size_t oldIndex, std::size_t newIndex) {
|
||||
return Move(oldIndex, newIndex);
|
||||
};
|
||||
|
@@ -15,7 +15,9 @@ namespace gd {
|
||||
|
||||
EventsFunctionsExtension::EventsFunctionsExtension() :
|
||||
gd::EventsFunctionsContainer(
|
||||
gd::EventsFunctionsContainer::FunctionOwner::Extension) {}
|
||||
gd::EventsFunctionsContainer::FunctionOwner::Extension),
|
||||
globalVariables(gd::VariablesContainer::SourceType::ExtensionGlobal),
|
||||
sceneVariables(gd::VariablesContainer::SourceType::ExtensionScene) {}
|
||||
|
||||
EventsFunctionsExtension::EventsFunctionsExtension(
|
||||
const EventsFunctionsExtension& other) :
|
||||
@@ -48,6 +50,8 @@ void EventsFunctionsExtension::Init(const gd::EventsFunctionsExtension& other) {
|
||||
EventsFunctionsContainer::Init(other);
|
||||
eventsBasedBehaviors = other.eventsBasedBehaviors;
|
||||
eventsBasedObjects = other.eventsBasedObjects;
|
||||
globalVariables = other.GetGlobalVariables();
|
||||
sceneVariables = other.GetSceneVariables();
|
||||
}
|
||||
|
||||
void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
|
||||
@@ -82,6 +86,9 @@ void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
|
||||
for (auto& dependency : dependencies)
|
||||
SerializeDependencyTo(dependency, dependenciesElement.AddChild(""));
|
||||
|
||||
GetGlobalVariables().SerializeTo(element.AddChild("globalVariables"));
|
||||
GetSceneVariables().SerializeTo(element.AddChild("sceneVariables"));
|
||||
|
||||
SerializeEventsFunctionsTo(element.AddChild("eventsFunctions"));
|
||||
eventsBasedBehaviors.SerializeElementsTo(
|
||||
"eventsBasedBehavior", element.AddChild("eventsBasedBehaviors"));
|
||||
@@ -147,6 +154,9 @@ void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
|
||||
for (size_t i = 0; i < dependenciesElement.GetChildrenCount(); ++i)
|
||||
dependencies.push_back(
|
||||
UnserializeDependencyFrom(dependenciesElement.GetChild(i)));
|
||||
|
||||
globalVariables.UnserializeFrom(element.GetChild("globalVariables"));
|
||||
sceneVariables.UnserializeFrom(element.GetChild("sceneVariables"));
|
||||
|
||||
// Only unserialize behaviors and objects names.
|
||||
// As event based objects can contains objects using CustomBehavior and/or
|
||||
|
@@ -3,8 +3,7 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EVENTSFUNCTIONEXTENSION_H
|
||||
#define GDCORE_EVENTSFUNCTIONEXTENSION_H
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -12,6 +11,7 @@
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/EventsFunctionsContainer.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/SerializableWithNameList.h"
|
||||
namespace gd {
|
||||
@@ -216,6 +216,41 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
|
||||
|
||||
///@}
|
||||
|
||||
/** \name Variable management
|
||||
* Members functions related to layout variables management.
|
||||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Return the global variables of the extension (variables scoped to the
|
||||
* entire game lifetime).
|
||||
*/
|
||||
inline const gd::VariablesContainer& GetGlobalVariables() const {
|
||||
return globalVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the global variables of the extension (variables scoped to the
|
||||
* entire game lifetime).
|
||||
*/
|
||||
inline gd::VariablesContainer& GetGlobalVariables() { return globalVariables; }
|
||||
|
||||
/**
|
||||
* Return the global variables of the extension (variables scoped to the
|
||||
* lifetime of a scene).
|
||||
*/
|
||||
inline const gd::VariablesContainer& GetSceneVariables() const {
|
||||
return sceneVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the global variables of the extension (variables scoped to the
|
||||
* lifetime of a scene).
|
||||
*/
|
||||
inline gd::VariablesContainer& GetSceneVariables() { return sceneVariables; }
|
||||
|
||||
///@}
|
||||
|
||||
/** \name Serialization
|
||||
*/
|
||||
///@{
|
||||
@@ -298,8 +333,9 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
|
||||
gd::SerializableWithNameList<EventsBasedBehavior> eventsBasedBehaviors;
|
||||
gd::SerializableWithNameList<EventsBasedObject> eventsBasedObjects;
|
||||
std::vector<gd::DependencyMetadata> dependencies;
|
||||
|
||||
gd::VariablesContainer globalVariables;
|
||||
gd::VariablesContainer sceneVariables;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EVENTSFUNCTIONEXTENSION_H
|
||||
|
@@ -53,7 +53,8 @@ Layout::Layout()
|
||||
stopSoundsOnStartup(true),
|
||||
standardSortMethod(true),
|
||||
disableInputWhenNotFocused(true),
|
||||
profiler(NULL)
|
||||
profiler(NULL),
|
||||
variables(gd::VariablesContainer::SourceType::Scene)
|
||||
{
|
||||
gd::Layer layer;
|
||||
layer.SetCameraCount(1);
|
||||
|
@@ -4,8 +4,8 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef GDCORE_LAYOUT_H
|
||||
#define GDCORE_LAYOUT_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -504,5 +504,3 @@ GetBehaviorsOfObject(const ObjectsContainer& game,
|
||||
} // namespace gd
|
||||
|
||||
typedef gd::Layout Scene;
|
||||
|
||||
#endif // GDCORE_LAYOUT_H
|
||||
|
@@ -24,14 +24,18 @@ Object::~Object() {}
|
||||
Object::Object(const gd::String& name_,
|
||||
const gd::String& type_,
|
||||
std::unique_ptr<gd::ObjectConfiguration> configuration_)
|
||||
: name(name_), configuration(std::move(configuration_)) {
|
||||
: name(name_),
|
||||
configuration(std::move(configuration_)),
|
||||
objectVariables(gd::VariablesContainer::SourceType::Object) {
|
||||
SetType(type_);
|
||||
}
|
||||
|
||||
Object::Object(const gd::String& name_,
|
||||
const gd::String& type_,
|
||||
gd::ObjectConfiguration* configuration_)
|
||||
: name(name_), configuration(configuration_) {
|
||||
: name(name_),
|
||||
configuration(configuration_),
|
||||
objectVariables(gd::VariablesContainer::SourceType::Object) {
|
||||
SetType(type_);
|
||||
}
|
||||
|
||||
|
@@ -3,8 +3,8 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_OBJECT_H
|
||||
#define GDCORE_OBJECT_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -287,5 +287,3 @@ struct ObjectHasName : public std::binary_function<std::unique_ptr<gd::Object>,
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_OBJECT_H
|
||||
|
@@ -31,6 +31,14 @@ ObjectsContainersList::MakeNewObjectsContainersListForContainers(
|
||||
return objectsContainersList;
|
||||
}
|
||||
|
||||
ObjectsContainersList
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
|
||||
const gd::ObjectsContainer& objectsContainer) {
|
||||
ObjectsContainersList objectsContainersList;
|
||||
objectsContainersList.Add(objectsContainer);
|
||||
return objectsContainersList;
|
||||
}
|
||||
|
||||
bool ObjectsContainersList::HasObjectOrGroupNamed(
|
||||
const gd::String& name) const {
|
||||
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
|
||||
@@ -370,7 +378,7 @@ void ObjectsContainersList::ForEachObject(
|
||||
|
||||
gd::String ObjectsContainersList::GetTypeOfObject(
|
||||
const gd::String& objectName) const {
|
||||
if (objectsContainers.size() != 2) {
|
||||
if (objectsContainers.size() > 2) {
|
||||
std::cout << this << std::endl;
|
||||
std::cout << objectsContainers.size() << std::endl;
|
||||
// TODO: rework forwarded methods so they can work with any number of
|
||||
@@ -379,19 +387,40 @@ gd::String ObjectsContainersList::GetTypeOfObject(
|
||||
"ObjectsContainersList::GetTypeOfObject called with objectsContainers "
|
||||
"not being exactly 2. This is a logical error and will crash.");
|
||||
}
|
||||
if (objectsContainers.size() == 0) {
|
||||
gd::LogWarning("ObjectsContainersList::GetTypeOfObject called without any "
|
||||
"objectsContainer");
|
||||
return "";
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
return gd::GetTypeOfObject(emptyObjectsContainer, *objectsContainers[0],
|
||||
objectName, true);
|
||||
}
|
||||
return gd::GetTypeOfObject(
|
||||
*objectsContainers[0], *objectsContainers[1], objectName, true);
|
||||
}
|
||||
|
||||
bool ObjectsContainersList::HasBehaviorInObjectOrGroup(
|
||||
const gd::String& objectOrGroupName, const gd::String& behaviorName) const {
|
||||
if (objectsContainers.size() != 2) {
|
||||
if (objectsContainers.size() > 2) {
|
||||
// TODO: rework forwarded methods so they can work with any number of
|
||||
// containers.
|
||||
gd::LogFatalError(
|
||||
"ObjectsContainersList::GetTypeOfObject called with objectsContainers "
|
||||
"ObjectsContainersList::HasBehaviorInObjectOrGroup called with objectsContainers "
|
||||
"not being exactly 2. This is a logical error and will crash.");
|
||||
}
|
||||
if (objectsContainers.size() == 0) {
|
||||
gd::LogWarning("ObjectsContainersList::HasBehaviorInObjectOrGroup called without any "
|
||||
"objectsContainer");
|
||||
return false;
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
return gd::HasBehaviorInObjectOrGroup(
|
||||
emptyObjectsContainer, *objectsContainers[0], objectOrGroupName,
|
||||
behaviorName, true);
|
||||
}
|
||||
return gd::HasBehaviorInObjectOrGroup(*objectsContainers[0],
|
||||
*objectsContainers[1],
|
||||
objectOrGroupName,
|
||||
@@ -403,13 +432,24 @@ gd::String ObjectsContainersList::GetTypeOfBehaviorInObjectOrGroup(
|
||||
const gd::String& objectOrGroupName,
|
||||
const gd::String& behaviorName,
|
||||
bool searchInGroups) const {
|
||||
if (objectsContainers.size() != 2) {
|
||||
if (objectsContainers.size() > 2) {
|
||||
// TODO: rework forwarded methods so they can work with any number of
|
||||
// containers.
|
||||
gd::LogFatalError(
|
||||
"ObjectsContainersList::GetTypeOfObject called with objectsContainers "
|
||||
"ObjectsContainersList::GetTypeOfBehaviorInObjectOrGroup called with objectsContainers "
|
||||
"not being exactly 2. This is a logical error and will crash.");
|
||||
}
|
||||
if (objectsContainers.size() == 0) {
|
||||
gd::LogWarning("ObjectsContainersList::GetTypeOfBehaviorInObjectOrGroup called without any "
|
||||
"objectsContainer");
|
||||
return "";
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
return gd::GetTypeOfBehaviorInObjectOrGroup(
|
||||
emptyObjectsContainer, *objectsContainers[0], objectOrGroupName,
|
||||
behaviorName, searchInGroups);
|
||||
}
|
||||
return gd::GetTypeOfBehaviorInObjectOrGroup(*objectsContainers[0],
|
||||
*objectsContainers[1],
|
||||
objectOrGroupName,
|
||||
@@ -419,13 +459,23 @@ gd::String ObjectsContainersList::GetTypeOfBehaviorInObjectOrGroup(
|
||||
|
||||
gd::String ObjectsContainersList::GetTypeOfBehavior(
|
||||
const gd::String& behaviorName, bool searchInGroups) const {
|
||||
if (objectsContainers.size() != 2) {
|
||||
if (objectsContainers.size() > 2) {
|
||||
// TODO: rework forwarded methods so they can work with any number of
|
||||
// containers.
|
||||
gd::LogFatalError(
|
||||
"ObjectsContainersList::GetTypeOfObject called with objectsContainers "
|
||||
"ObjectsContainersList::GetTypeOfBehavior called with objectsContainers "
|
||||
"not being exactly 2. This is a logical error and will crash.");
|
||||
}
|
||||
if (objectsContainers.size() == 0) {
|
||||
gd::LogWarning("ObjectsContainersList::GetTypeOfBehavior called without any "
|
||||
"objectsContainer");
|
||||
return "";
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
return gd::GetTypeOfBehavior(emptyObjectsContainer, *objectsContainers[0],
|
||||
behaviorName, searchInGroups);
|
||||
}
|
||||
return gd::GetTypeOfBehavior(*objectsContainers[0],
|
||||
*objectsContainers[1],
|
||||
behaviorName,
|
||||
@@ -434,14 +484,25 @@ gd::String ObjectsContainersList::GetTypeOfBehavior(
|
||||
|
||||
std::vector<gd::String> ObjectsContainersList::GetBehaviorsOfObject(
|
||||
const gd::String& objectName, bool searchInGroups) const {
|
||||
if (objectsContainers.size() != 2) {
|
||||
if (objectsContainers.size() > 2) {
|
||||
// TODO: rework forwarded methods so they can work with any number of
|
||||
// containers.
|
||||
gd::LogFatalError(
|
||||
"ObjectsContainersList::GetTypeOfObject called with objectsContainers "
|
||||
"ObjectsContainersList::GetBehaviorsOfObject called with objectsContainers "
|
||||
"not being exactly 2. This is a logical error and will crash.");
|
||||
}
|
||||
|
||||
if (objectsContainers.size() == 0) {
|
||||
gd::LogWarning("ObjectsContainersList::GetBehaviorsOfObject called without any "
|
||||
"objectsContainer");
|
||||
std::vector<gd::String> behaviors;
|
||||
return behaviors;
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
return gd::GetBehaviorsOfObject(emptyObjectsContainer,
|
||||
*objectsContainers[0], objectName,
|
||||
searchInGroups);
|
||||
}
|
||||
return gd::GetBehaviorsOfObject(
|
||||
*objectsContainers[0], *objectsContainers[1], objectName, searchInGroups);
|
||||
}
|
||||
|
@@ -37,6 +37,9 @@ class GD_CORE_API ObjectsContainersList {
|
||||
const gd::ObjectsContainer& globalObjectsContainer,
|
||||
const gd::ObjectsContainer& objectsContainer);
|
||||
|
||||
static ObjectsContainersList MakeNewObjectsContainersListForContainer(
|
||||
const gd::ObjectsContainer& objectsContainer);
|
||||
|
||||
/**
|
||||
* \brief Check if the specified object or group exists.
|
||||
*/
|
||||
|
@@ -75,7 +75,8 @@ Project::Project()
|
||||
currentPlatform(NULL),
|
||||
gdMajorVersion(gd::VersionWrapper::Major()),
|
||||
gdMinorVersion(gd::VersionWrapper::Minor()),
|
||||
gdBuildVersion(gd::VersionWrapper::Build()) {}
|
||||
gdBuildVersion(gd::VersionWrapper::Build()),
|
||||
variables(gd::VariablesContainer::SourceType::Global) {}
|
||||
|
||||
Project::~Project() {}
|
||||
|
||||
|
@@ -4,8 +4,8 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef GDCORE_PROJECT_H
|
||||
#define GDCORE_PROJECT_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@@ -1134,5 +1134,3 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_PROJECT_H
|
||||
|
103
Core/GDCore/Project/ProjectScopedContainers.cpp
Normal file
103
Core/GDCore/Project/ProjectScopedContainers.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#include "ProjectScopedContainers.h"
|
||||
|
||||
#include "GDCore/IDE/EventsFunctionTools.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
const gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsFunction &eventsFunction,
|
||||
gd::ObjectsContainer ¶meterObjectsContainer) {
|
||||
|
||||
gd::EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
project, eventsFunctionsExtension, eventsFunction, parameterObjectsContainer);
|
||||
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
|
||||
parameterObjectsContainer),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(eventsFunctionsExtension),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
projectScopedContainers.AddParameters(
|
||||
eventsFunction.GetParametersForEvents(eventsFunctionsExtension));
|
||||
|
||||
return projectScopedContainers;
|
||||
};
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersForBehaviorEventsFunction(
|
||||
const gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction &eventsFunction,
|
||||
gd::ObjectsContainer ¶meterObjectsContainer) {
|
||||
|
||||
gd::EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
|
||||
project,
|
||||
eventsBasedBehavior,
|
||||
eventsFunction,
|
||||
parameterObjectsContainer);
|
||||
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
|
||||
parameterObjectsContainer),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(eventsFunctionsExtension),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
eventsBasedBehavior.GetSharedPropertyDescriptors());
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
eventsBasedBehavior.GetPropertyDescriptors());
|
||||
projectScopedContainers.AddParameters(eventsFunction.GetParametersForEvents(
|
||||
eventsBasedBehavior.GetEventsFunctions()));
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersForObjectEventsFunction(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::EventsFunction &eventsFunction,
|
||||
gd::ObjectsContainer ¶meterObjectsContainer) {
|
||||
|
||||
gd::EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
project, eventsBasedObject, eventsFunction, parameterObjectsContainer);
|
||||
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
|
||||
parameterObjectsContainer),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(
|
||||
eventsFunctionsExtension),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
eventsBasedObject.GetPropertyDescriptors());
|
||||
projectScopedContainers.AddParameters(eventsFunction.GetParametersForEvents(
|
||||
eventsBasedObject.GetEventsFunctions()));
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersWithLocalVariables(
|
||||
const ProjectScopedContainers &projectScopedContainers,
|
||||
const gd::BaseEvent &event) {
|
||||
ProjectScopedContainers newProjectScopedContainers = projectScopedContainers;
|
||||
newProjectScopedContainers.variablesContainersList =
|
||||
VariablesContainersList::MakeNewVariablesContainersListPushing(
|
||||
projectScopedContainers.GetVariablesContainersList(),
|
||||
event.GetVariables());
|
||||
return newProjectScopedContainers;
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -13,6 +13,11 @@ class ObjectsContainersList;
|
||||
class VariablesContainersList;
|
||||
class PropertiesContainersList;
|
||||
class NamedPropertyDescriptor;
|
||||
class BaseEvent;
|
||||
class EventsFunctionsExtension;
|
||||
class EventsFunction;
|
||||
class EventsBasedBehavior;
|
||||
class EventsBasedObject;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -51,6 +56,9 @@ class ProjectScopedContainers {
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use another method for an explicit context instead.
|
||||
*/
|
||||
static ProjectScopedContainers MakeNewProjectScopedContainersFor(
|
||||
const gd::ObjectsContainer &globalObjectsContainers,
|
||||
const gd::ObjectsContainer &objectsContainers) {
|
||||
@@ -61,7 +69,35 @@ class ProjectScopedContainers {
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
};
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& parameterObjectsContainer);
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersForBehaviorEventsFunction(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::EventsFunction &eventsFunction,
|
||||
gd::ObjectsContainer ¶meterObjectsContainer);
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersForObjectEventsFunction(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::EventsFunction &eventsFunction,
|
||||
gd::ObjectsContainer ¶meterObjectsContainer);
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersWithLocalVariables(
|
||||
const ProjectScopedContainers &projectScopedContainers,
|
||||
const gd::BaseEvent &event);
|
||||
|
||||
ProjectScopedContainers &AddPropertiesContainer(
|
||||
const gd::PropertiesContainer &container) {
|
||||
@@ -152,6 +188,14 @@ class ProjectScopedContainers {
|
||||
return variablesContainersList;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Allow modification of the variables containers list. This is used
|
||||
* by code generation which does push and pop of local variable containers.
|
||||
*/
|
||||
gd::VariablesContainersList &GetVariablesContainersList() {
|
||||
return variablesContainersList;
|
||||
};
|
||||
|
||||
const gd::PropertiesContainersList &GetPropertiesContainersList() const {
|
||||
return propertiesContainersList;
|
||||
};
|
||||
|
@@ -198,7 +198,24 @@ void Variable::MoveChildInArray(const size_t oldIndex, const size_t newIndex) {
|
||||
childrenArray.insert(childrenArray.begin() + newIndex, std::move(object));
|
||||
}
|
||||
|
||||
Variable& Variable::PushNew() { return GetAtIndex(GetChildrenCount()); };
|
||||
Variable& Variable::PushNew() {
|
||||
const size_t count = GetChildrenCount();
|
||||
auto& variable = GetAtIndex(count);
|
||||
if (type == Type::Array && count > 0) {
|
||||
const auto childType = GetAtIndex(count - 1).type;
|
||||
variable.type = childType;
|
||||
if (childType == Type::Number) {
|
||||
variable.SetValue(0);
|
||||
}
|
||||
else if (childType == Type::String) {
|
||||
variable.SetString("");
|
||||
}
|
||||
else if (childType == Type::Boolean) {
|
||||
variable.SetBool(false);
|
||||
}
|
||||
}
|
||||
return variable;
|
||||
};
|
||||
|
||||
void Variable::RemoveAtIndex(const size_t index) {
|
||||
if (index >= childrenArray.size()) return;
|
||||
|
@@ -30,6 +30,8 @@ class GD_CORE_API Variable {
|
||||
public:
|
||||
static gd::Variable badVariable;
|
||||
enum Type {
|
||||
Unknown,
|
||||
|
||||
// Primitive types
|
||||
String,
|
||||
Number,
|
||||
|
@@ -35,7 +35,13 @@ class VariableHasName {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
VariablesContainer::VariablesContainer() {}
|
||||
VariablesContainer::VariablesContainer()
|
||||
: sourceType(VariablesContainer::SourceType::Unknown) {}
|
||||
|
||||
VariablesContainer::VariablesContainer(
|
||||
VariablesContainer::SourceType sourceType_) {
|
||||
sourceType = sourceType_;
|
||||
}
|
||||
|
||||
bool VariablesContainer::Has(const gd::String& name) const {
|
||||
auto i =
|
||||
@@ -229,6 +235,7 @@ VariablesContainer& VariablesContainer::operator=(
|
||||
}
|
||||
|
||||
void VariablesContainer::Init(const gd::VariablesContainer& other) {
|
||||
sourceType = other.sourceType;
|
||||
persistentUuid = other.persistentUuid;
|
||||
variables.clear();
|
||||
for (auto& it : other.variables) {
|
||||
|
@@ -4,8 +4,7 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef GDCORE_VARIABLESCONTAINER_H
|
||||
#define GDCORE_VARIABLESCONTAINER_H
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/Project/Variable.h"
|
||||
@@ -29,12 +28,25 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API VariablesContainer {
|
||||
public:
|
||||
enum SourceType {
|
||||
Unknown,
|
||||
Global,
|
||||
Scene,
|
||||
Object,
|
||||
Local,
|
||||
ExtensionGlobal,
|
||||
ExtensionScene
|
||||
};
|
||||
|
||||
VariablesContainer();
|
||||
VariablesContainer(const SourceType sourceType);
|
||||
VariablesContainer(const VariablesContainer&);
|
||||
virtual ~VariablesContainer(){};
|
||||
|
||||
VariablesContainer& operator=(const VariablesContainer& rhs);
|
||||
|
||||
SourceType GetSourceType() const { return sourceType; }
|
||||
|
||||
/** \name Variables management
|
||||
* Members functions related to variables management.
|
||||
*/
|
||||
@@ -89,7 +101,6 @@ class GD_CORE_API VariablesContainer {
|
||||
*/
|
||||
const gd::String& GetNameAt(std::size_t index) const;
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief return the position of the variable called "name" in the variable
|
||||
* list
|
||||
@@ -131,7 +142,6 @@ class GD_CORE_API VariablesContainer {
|
||||
* \brief Move the specified variable at a new position in the list.
|
||||
*/
|
||||
void Move(std::size_t oldIndex, std::size_t newIndex);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Clear all variables of the container.
|
||||
@@ -178,6 +188,7 @@ class GD_CORE_API VariablesContainer {
|
||||
///@}
|
||||
|
||||
private:
|
||||
SourceType sourceType;
|
||||
std::vector<std::pair<gd::String, std::shared_ptr<gd::Variable>>> variables;
|
||||
mutable gd::String persistentUuid; ///< A persistent random version 4 UUID,
|
||||
///< useful for computing changesets.
|
||||
@@ -192,5 +203,3 @@ class GD_CORE_API VariablesContainer {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_VARIABLESCONTAINER_H
|
||||
|
@@ -5,20 +5,41 @@
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
Variable VariablesContainersList::badVariable;
|
||||
VariablesContainer VariablesContainersList::badVariablesContainer;
|
||||
|
||||
VariablesContainersList
|
||||
VariablesContainersList::MakeNewVariablesContainersListForProjectAndLayout(
|
||||
const gd::Project& project, const gd::Layout& layout) {
|
||||
VariablesContainersList variablesContainersList;
|
||||
variablesContainersList.Add(project.GetVariables());
|
||||
variablesContainersList.Add(layout.GetVariables());
|
||||
variablesContainersList.Push(project.GetVariables());
|
||||
variablesContainersList.Push(layout.GetVariables());
|
||||
variablesContainersList.firstLocalVariableContainerIndex = 2;
|
||||
return variablesContainersList;
|
||||
}
|
||||
|
||||
VariablesContainersList
|
||||
VariablesContainersList::MakeNewVariablesContainersListForEventsFunctionsExtension(
|
||||
const gd::EventsFunctionsExtension &extension) {
|
||||
VariablesContainersList variablesContainersList;
|
||||
variablesContainersList.Push(extension.GetGlobalVariables());
|
||||
variablesContainersList.Push(extension.GetSceneVariables());
|
||||
variablesContainersList.firstLocalVariableContainerIndex = 2;
|
||||
return variablesContainersList;
|
||||
}
|
||||
|
||||
VariablesContainersList
|
||||
VariablesContainersList::MakeNewVariablesContainersListPushing(
|
||||
const VariablesContainersList& variablesContainersList, const gd::VariablesContainer& variablesContainer) {
|
||||
VariablesContainersList newVariablesContainersList(variablesContainersList);
|
||||
newVariablesContainersList.Push(variablesContainer);
|
||||
return newVariablesContainersList;
|
||||
}
|
||||
|
||||
VariablesContainersList
|
||||
VariablesContainersList::MakeNewEmptyVariablesContainersList() {
|
||||
VariablesContainersList variablesContainersList;
|
||||
@@ -43,6 +64,37 @@ const Variable& VariablesContainersList::Get(const gd::String& name) const {
|
||||
return badVariable;
|
||||
}
|
||||
|
||||
const VariablesContainer &
|
||||
VariablesContainersList::GetVariablesContainerFromVariableName(
|
||||
const gd::String &variableName) const {
|
||||
for (auto it = variablesContainers.rbegin(); it != variablesContainers.rend();
|
||||
++it) {
|
||||
if ((*it)->Has(variableName))
|
||||
return **it;
|
||||
}
|
||||
return badVariablesContainer;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
VariablesContainersList::GetVariablesContainerPositionFromVariableName(
|
||||
const gd::String &variableName) const {
|
||||
for (std::size_t i = variablesContainers.size() - 1; i >= 0 ; --i) {
|
||||
if (variablesContainers[i]->Has(variableName))
|
||||
return i;
|
||||
}
|
||||
return gd::String::npos;
|
||||
}
|
||||
|
||||
std::size_t VariablesContainersList::GetLocalVariablesContainerPosition(
|
||||
const gd::VariablesContainer &localVariableContainer) const {
|
||||
for (std::size_t i = firstLocalVariableContainerIndex;
|
||||
i < variablesContainers.size(); ++i) {
|
||||
if (variablesContainers[i] == &localVariableContainer)
|
||||
return i - firstLocalVariableContainerIndex;
|
||||
}
|
||||
return gd::String::npos;
|
||||
}
|
||||
|
||||
bool VariablesContainersList::HasVariablesContainer(const gd::VariablesContainer& variablesContainer) const {
|
||||
for (auto it = variablesContainers.rbegin(); it != variablesContainers.rend();
|
||||
++it) {
|
||||
|
@@ -8,6 +8,7 @@ class Project;
|
||||
class Layout;
|
||||
class VariablesContainer;
|
||||
class Variable;
|
||||
class EventsFunctionsExtension;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -30,6 +31,17 @@ class GD_CORE_API VariablesContainersList {
|
||||
MakeNewVariablesContainersListForProjectAndLayout(const gd::Project& project,
|
||||
const gd::Layout& layout);
|
||||
|
||||
static VariablesContainersList
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(
|
||||
const gd::EventsFunctionsExtension &extension);
|
||||
|
||||
static VariablesContainersList MakeNewVariablesContainersListPushing(
|
||||
const VariablesContainersList &variablesContainersList,
|
||||
const gd::VariablesContainer &variablesContainer);
|
||||
|
||||
/**
|
||||
* @deprecated Use another method for an explicit context instead.
|
||||
*/
|
||||
static VariablesContainersList MakeNewEmptyVariablesContainersList();
|
||||
|
||||
/**
|
||||
@@ -47,6 +59,10 @@ class GD_CORE_API VariablesContainersList {
|
||||
*/
|
||||
bool HasVariablesContainer(const gd::VariablesContainer& variablesContainer) const;
|
||||
|
||||
// TODO: Rename GetTopMostVariablesContainer and GetBottomMostVariablesContainer
|
||||
// to give a clearer access to segments of the container list.
|
||||
// For instance, a project tree segment and an event tree segment.
|
||||
|
||||
/**
|
||||
* Get the variables container at the top of the scope (so the most "global" one).
|
||||
* \brief Avoid using apart when a scope must be forced.
|
||||
@@ -57,29 +73,76 @@ class GD_CORE_API VariablesContainersList {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the variables container at the bottom of the scope (so the most "local" one).
|
||||
* Get the variables container at the bottom of the scope
|
||||
* (so the most "local" one) excluding local variables.
|
||||
* \brief Avoid using apart when a scope must be forced.
|
||||
*/
|
||||
const VariablesContainer* GetBottomMostVariablesContainer() const {
|
||||
if (variablesContainers.empty()) return nullptr;
|
||||
return variablesContainers.back();
|
||||
return variablesContainers.at(firstLocalVariableContainerIndex - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the variables container for a given variable.
|
||||
*/
|
||||
const VariablesContainer &
|
||||
GetVariablesContainerFromVariableName(const gd::String &variableName) const;
|
||||
|
||||
/**
|
||||
* Get the variables container index for a given variable.
|
||||
*/
|
||||
std::size_t GetVariablesContainerPositionFromVariableName(
|
||||
const gd::String &variableName) const;
|
||||
|
||||
/**
|
||||
* \brief Get the index of the given local variables container.
|
||||
*/
|
||||
std::size_t GetLocalVariablesContainerPosition(
|
||||
const gd::VariablesContainer &localVariableContainer) const;
|
||||
|
||||
/**
|
||||
* \brief Get the variable container at the specified index in the list.
|
||||
*
|
||||
* \warning Trying to access to a not existing variable container will result
|
||||
* in undefined behavior.
|
||||
*/
|
||||
const gd::VariablesContainer& GetVariablesContainer(std::size_t index) const {
|
||||
return *variablesContainers.at(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the number variable containers.
|
||||
*/
|
||||
std::size_t GetVariablesContainersCount() const { return variablesContainers.size(); }
|
||||
|
||||
/**
|
||||
* \brief Call the callback for each variable having a name matching the specified search.
|
||||
*/
|
||||
void ForEachVariableMatchingSearch(const gd::String& search, std::function<void(const gd::String& name, const gd::Variable& variable)> fn) const;
|
||||
|
||||
/** Do not use - should be private but accessible to let Emscripten create a temporary. */
|
||||
VariablesContainersList() {};
|
||||
private:
|
||||
|
||||
void Add(const gd::VariablesContainer& variablesContainer) {
|
||||
/**
|
||||
* \brief Push a new variables container to the context.
|
||||
*/
|
||||
void Push(const gd::VariablesContainer& variablesContainer) {
|
||||
variablesContainers.push_back(&variablesContainer);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Pop a variables container from the context.
|
||||
*/
|
||||
void Pop() {
|
||||
variablesContainers.pop_back();
|
||||
};
|
||||
|
||||
|
||||
/** Do not use - should be private but accessible to let Emscripten create a temporary. */
|
||||
VariablesContainersList(): firstLocalVariableContainerIndex(0) {};
|
||||
private:
|
||||
|
||||
std::vector<const gd::VariablesContainer*> variablesContainers;
|
||||
std::size_t firstLocalVariableContainerIndex;
|
||||
static Variable badVariable;
|
||||
static VariablesContainer badVariablesContainer;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -126,6 +126,46 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
.AddParameter("object", _("Object"), "")
|
||||
.SetFunctionName("getFromBaseExpression");
|
||||
|
||||
baseObject.AddAction("SetNumberObjectVariable",
|
||||
"Do something with number object variables",
|
||||
"This does something with variables",
|
||||
"Do something with variables",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("object", "Object")
|
||||
.AddParameter("objectvar", "Variable")
|
||||
.AddParameter("operator", "Operator", "number")
|
||||
.AddParameter("number", "Value");
|
||||
|
||||
baseObject.AddAction("SetStringObjectVariable",
|
||||
"Do something with string object variables",
|
||||
"This does something with variables",
|
||||
"Do something with variables",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("object", "Object")
|
||||
.AddParameter("objectvar", "Variable")
|
||||
.AddParameter("operator", "Operator", "string")
|
||||
.AddParameter("string", "Value")
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
baseObject.AddAction("SetBooleanObjectVariable",
|
||||
"Do something with boolean object variables",
|
||||
"This does something with object variables",
|
||||
"Do something with object variables",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("object", "Object")
|
||||
.AddParameter("objectvar", "Variable")
|
||||
.AddParameter("operator", "Value", "boolean")
|
||||
// This parameter allows to keep the operand expression
|
||||
// when the editor switch between variable instructions.
|
||||
.AddCodeOnlyParameter("yesorno", "Value")
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
// Declare default behaviors that are used by event-based objects to avoid
|
||||
// warnings.
|
||||
{
|
||||
@@ -204,6 +244,58 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
.SetHidden();
|
||||
platform.AddExtension(extension);
|
||||
}
|
||||
|
||||
{
|
||||
// Create an extension without namespace to match the switchable variable instructions.
|
||||
std::shared_ptr<gd::PlatformExtension> extension =
|
||||
std::shared_ptr<gd::PlatformExtension>(new gd::PlatformExtension);
|
||||
extension->SetExtensionInformation(
|
||||
"BuiltinVariables", "My testing extension for variables", "", "", "");
|
||||
|
||||
extension
|
||||
->AddAction("SetNumberVariable",
|
||||
"Do something with number variables",
|
||||
"This does something with variables",
|
||||
"Do something with variables",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("variable", "Variable")
|
||||
.AddParameter("operator", "Operator", "number")
|
||||
.AddParameter("number", "Value")
|
||||
.SetFunctionName("setNumberVariable");
|
||||
|
||||
extension
|
||||
->AddAction("SetStringVariable",
|
||||
"Do something with string variables",
|
||||
"This does something with variables",
|
||||
"Do something with variables",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("variable", "Variable")
|
||||
.AddParameter("operator", "Operator", "string")
|
||||
.AddParameter("string", "Value")
|
||||
.SetFunctionName("setStringVariable");
|
||||
|
||||
extension
|
||||
->AddAction("SetBooleanVariable",
|
||||
"Do something with boolean variables",
|
||||
"This does something with variables",
|
||||
"Do something with variables",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("variable", "Variable")
|
||||
.AddParameter("operator", "Operator", "boolean")
|
||||
// This parameter allows to keep the operand expression
|
||||
// when the editor switch between variable instructions.
|
||||
.AddCodeOnlyParameter("trueorfalse", "")
|
||||
.SetFunctionName("setBooleanVariable");
|
||||
|
||||
platform.AddExtension(extension);
|
||||
}
|
||||
|
||||
// Create an extension with various stuff inside.
|
||||
std::shared_ptr<gd::PlatformExtension> extension =
|
||||
std::shared_ptr<gd::PlatformExtension>(new gd::PlatformExtension);
|
||||
|
@@ -273,7 +273,7 @@ TEST_CASE("EventsVariablesFinder (FindAllObjectVariables)", "[common]") {
|
||||
UseObjectVariable("MyObject", "MyObjectVariable"));
|
||||
|
||||
auto variableNames = gd::EventsVariablesFinder::FindAllObjectVariables(
|
||||
platform, project, layout, object);
|
||||
platform, project, layout, "MyObject");
|
||||
|
||||
REQUIRE(variableNames.size() == 1);
|
||||
REQUIRE(*(variableNames.begin()) == "MyObjectVariable");
|
||||
@@ -290,7 +290,7 @@ TEST_CASE("EventsVariablesFinder (FindAllObjectVariables)", "[common]") {
|
||||
UseObjectVariableInExpression("MyObject", "MyObjectVariable"));
|
||||
|
||||
auto variableNames = gd::EventsVariablesFinder::FindAllObjectVariables(
|
||||
platform, project, layout, object);
|
||||
platform, project, layout, "MyObject");
|
||||
|
||||
REQUIRE(variableNames.size() == 1);
|
||||
REQUIRE(*(variableNames.begin()) == "MyObjectVariable");
|
||||
@@ -309,7 +309,7 @@ TEST_CASE("EventsVariablesFinder (FindAllObjectVariables)", "[common]") {
|
||||
UseExternalEvents(layout, externalEvents);
|
||||
|
||||
auto variableNames = gd::EventsVariablesFinder::FindAllObjectVariables(
|
||||
platform, project, layout, object);
|
||||
platform, project, layout, "MyObject");
|
||||
|
||||
REQUIRE(variableNames.size() == 1);
|
||||
REQUIRE(*(variableNames.begin()) == "MyObjectVariable");
|
||||
@@ -329,7 +329,7 @@ TEST_CASE("EventsVariablesFinder (FindAllObjectVariables)", "[common]") {
|
||||
UseObjectVariable("MyObject2", "MyObjectVariable2"));
|
||||
|
||||
auto variableNames = gd::EventsVariablesFinder::FindAllObjectVariables(
|
||||
platform, project, layout, object1);
|
||||
platform, project, layout, "MyObject1");
|
||||
|
||||
REQUIRE(variableNames.size() == 1);
|
||||
REQUIRE(*(variableNames.begin()) == "MyObjectVariable1");
|
||||
@@ -352,7 +352,7 @@ TEST_CASE("EventsVariablesFinder (FindAllObjectVariables)", "[common]") {
|
||||
UseExternalEvents(layout, externalEvents);
|
||||
|
||||
auto variableNames = gd::EventsVariablesFinder::FindAllObjectVariables(
|
||||
platform, project, layout, object1);
|
||||
platform, project, layout, "MyObject1");
|
||||
|
||||
REQUIRE(variableNames.size() == 1);
|
||||
REQUIRE(*(variableNames.begin()) == "MyObjectVariable1");
|
||||
|
@@ -627,7 +627,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneVariable).getAsNumber() + 1");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneVariable).getAsNumber() + 1");
|
||||
}
|
||||
{
|
||||
auto node =
|
||||
@@ -639,7 +639,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneVariable).getAsNumber() + getLayoutVariable(MySceneVariable2).getAsNumber()");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneVariable).getAsNumber() + getAnyVariable(MySceneVariable2).getAsNumber()");
|
||||
}
|
||||
}
|
||||
SECTION("Scene variables (conflict with a global variable)") {
|
||||
@@ -653,7 +653,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(SceneVariableWithNameReused).getAsNumber() + 1");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(SceneVariableWithNameReused).getAsNumber() + 1");
|
||||
}
|
||||
}
|
||||
SECTION("Scene variables (2 levels)") {
|
||||
@@ -667,7 +667,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(\"MyChild\").getAsNumber() + 1");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStructureVariable).getChild(\"MyChild\").getAsNumber() + 1");
|
||||
}
|
||||
{
|
||||
auto node =
|
||||
@@ -679,7 +679,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(\"MyChild\").getAsNumber() + getLayoutVariable(MySceneStructureVariable2).getChild(\"MyChild\").getAsNumber()");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStructureVariable).getChild(\"MyChild\").getAsNumber() + getAnyVariable(MySceneStructureVariable2).getChild(\"MyChild\").getAsNumber()");
|
||||
}
|
||||
}
|
||||
SECTION("Scene variables (2 levels with bracket accessor, string)") {
|
||||
@@ -693,7 +693,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(\"MyChild\").getAsNumber() + 1");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStructureVariable).getChild(\"MyChild\").getAsNumber() + 1");
|
||||
}
|
||||
{
|
||||
auto node =
|
||||
@@ -705,7 +705,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(\"MyChild\").getAsNumber() + getLayoutVariable(MySceneStructureVariable2).getChild(\"MyChild\").getAsNumber()");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStructureVariable).getChild(\"MyChild\").getAsNumber() + getAnyVariable(MySceneStructureVariable2).getChild(\"MyChild\").getAsNumber()");
|
||||
}
|
||||
}
|
||||
SECTION("Scene variables (2 levels with bracket accessor, number)") {
|
||||
@@ -719,7 +719,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(3).getAsNumber() + 1");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStructureVariable).getChild(3).getAsNumber() + 1");
|
||||
}
|
||||
{
|
||||
auto node =
|
||||
@@ -731,7 +731,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(3).getAsNumber() + getLayoutVariable(MySceneStructureVariable2).getChild(3).getAsNumber()");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStructureVariable).getChild(3).getAsNumber() + getAnyVariable(MySceneStructureVariable2).getChild(3).getAsNumber()");
|
||||
}
|
||||
}
|
||||
SECTION("Scene variables (2 levels with bracket accessor, using a number variable as index)") {
|
||||
@@ -745,7 +745,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(getLayoutVariable(MySceneVariable).getAsNumber()).getAsNumber() + 1");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStructureVariable).getChild(getAnyVariable(MySceneVariable).getAsNumber()).getAsNumber() + 1");
|
||||
}
|
||||
}
|
||||
SECTION("Scene variables (2 levels with bracket accessor, using a string variable as index)") {
|
||||
@@ -759,7 +759,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(getLayoutVariable(MySceneStringVariable).getAsString()).getAsNumber() + 1");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStructureVariable).getChild(getAnyVariable(MySceneStringVariable).getAsString()).getAsNumber() + 1");
|
||||
}
|
||||
}
|
||||
SECTION("Scene variables (2 levels with bracket accessor, using a non string/number variable as index)") {
|
||||
@@ -773,7 +773,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(getLayoutVariable(MySceneBooleanVariable).getAsNumberOrString()).getAsNumber() + 1");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStructureVariable).getChild(getAnyVariable(MySceneBooleanVariable).getAsNumberOrString()).getAsNumber() + 1");
|
||||
}
|
||||
}
|
||||
SECTION("Scene variables (2 levels with bracket accessor, using a unknown variable type as index)") {
|
||||
@@ -787,7 +787,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(getLayoutVariable(MySceneStructureVariable).getChild(\"MyChild\").getChild(\"CantKnownTheTypeSoStayGeneric\").getAsNumberOrString()).getAsNumber() + 1");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStructureVariable).getChild(getAnyVariable(MySceneStructureVariable).getChild(\"MyChild\").getChild(\"CantKnownTheTypeSoStayGeneric\").getAsNumberOrString()).getAsNumber() + 1");
|
||||
}
|
||||
}
|
||||
SECTION("Scene variables (2 levels with bracket accessor, using a unknown variable type and an operator with a number as index)") {
|
||||
@@ -801,7 +801,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(getLayoutVariable(MySceneStructureVariable).getChild(\"MyChild\").getChild(\"CantKnownTheTypeSoStayGeneric\").getAsNumber() + 2).getAsNumber() + 1");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStructureVariable).getChild(getAnyVariable(MySceneStructureVariable).getChild(\"MyChild\").getChild(\"CantKnownTheTypeSoStayGeneric\").getAsNumber() + 2).getAsNumber() + 1");
|
||||
}
|
||||
}
|
||||
SECTION("Scene variables (2 levels with bracket accessor, using a unknown variable type and an operator with a string as index)") {
|
||||
@@ -815,7 +815,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(getLayoutVariable(MySceneStructureVariable).getChild(\"MyChild\").getChild(\"CantKnownTheTypeSoStayGeneric\").getAsString() + \"Test\").getAsNumber() + 1");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStructureVariable).getChild(getAnyVariable(MySceneStructureVariable).getChild(\"MyChild\").getChild(\"CantKnownTheTypeSoStayGeneric\").getAsString() + \"Test\").getAsNumber() + 1");
|
||||
}
|
||||
}
|
||||
SECTION("Scene variables (2 levels with bracket accessor, using a unknown variable type as index) (expression type: number|string)") {
|
||||
@@ -829,7 +829,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(getLayoutVariable(MySceneStructureVariable).getChild(\"MyChild\").getChild(\"CantKnownTheTypeSoStayGeneric\").getAsNumberOrString()).getAsNumberOrString()");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStructureVariable).getChild(getAnyVariable(MySceneStructureVariable).getChild(\"MyChild\").getChild(\"CantKnownTheTypeSoStayGeneric\").getAsNumberOrString()).getAsNumberOrString()");
|
||||
}
|
||||
}
|
||||
SECTION("Scene variables (2 levels with bracket accessor, using a number variable casted to string as index)") {
|
||||
@@ -843,7 +843,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(\"\" + getLayoutVariable(MySceneVariable).getAsString()).getAsNumber() + 1");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStructureVariable).getChild(\"\" + getAnyVariable(MySceneVariable).getAsString()).getAsNumber() + 1");
|
||||
}
|
||||
}
|
||||
SECTION("Object variable with non existing object (invalid)") {
|
||||
@@ -1023,80 +1023,83 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
"fakeBadVariable");
|
||||
}
|
||||
}
|
||||
SECTION("Valid variables (upcoming, new 'variable' type working for any variable)") {
|
||||
// When implemented, copy the test cases from the next section, like this:
|
||||
// SECTION("simple variable") {
|
||||
// REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
// codeGenerator, context, "variable", "MySceneVariable", "")
|
||||
// == "getLayoutVariable(MySceneVariable)");
|
||||
// }
|
||||
// SECTION("simple (global) variable") {
|
||||
// REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
// codeGenerator, context, "variable", "MyGlobalNumberVariable", "")
|
||||
// == "getProjectVariable(MyGlobalNumberVariable)");
|
||||
// }
|
||||
}
|
||||
SECTION("Valid variables (legacy, pre-scoped variables)") {
|
||||
// Check that the scope is forwarded by the parser.
|
||||
SECTION("simple variable") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable", "")
|
||||
== "getLayoutVariable(myVariable)");
|
||||
codeGenerator, context, "scenevar", "MySceneVariable", "")
|
||||
== "getLayoutVariable(MySceneVariable)");
|
||||
}
|
||||
SECTION("simple (global) variable") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "globalvar", "MyGlobalNumberVariable", "")
|
||||
== "getProjectVariable(MyGlobalNumberVariable)");
|
||||
}
|
||||
}
|
||||
SECTION("Valid variables") {
|
||||
// getAnyVariable is a mocked value. The function doesn't actually exist.
|
||||
// The actual scope switching is done by GDJS and tested by GDevelop.js
|
||||
// integration tests.
|
||||
SECTION("simple variable") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "variable", "MySceneVariable", "")
|
||||
== "getAnyVariable(MySceneVariable)");
|
||||
}
|
||||
SECTION("child dot accessor") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable.myChild", "")
|
||||
== "getLayoutVariable(myVariable).getChild(\"myChild\")");
|
||||
codeGenerator, context, "variable", "MySceneVariable.myChild", "")
|
||||
== "getAnyVariable(MySceneVariable).getChild(\"myChild\")");
|
||||
}
|
||||
SECTION("2 children") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable.child1.child2", "")
|
||||
== "getLayoutVariable(myVariable).getChild(\"child1\").getChild(\"child2\")");
|
||||
codeGenerator, context, "variable", "MySceneVariable.child1.child2", "")
|
||||
== "getAnyVariable(MySceneVariable).getChild(\"child1\").getChild(\"child2\")");
|
||||
}
|
||||
SECTION("bracket access") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable[ \"hello\" + "
|
||||
codeGenerator, context, "variable", "MySceneVariable[ \"hello\" + "
|
||||
"\"world\" ]", "")
|
||||
== "getLayoutVariable(myVariable).getChild(\"hello\" + \"world\")");
|
||||
== "getAnyVariable(MySceneVariable).getChild(\"hello\" + \"world\")");
|
||||
}
|
||||
SECTION("bracket access (using a string object variable inside)") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable[MySpriteObject.MyStringVariable]", "")
|
||||
== "getLayoutVariable(myVariable).getChild(getVariableForObject(MySpriteObject, MyStringVariable).getAsString())");
|
||||
codeGenerator, context, "variable", "MySceneVariable[MySpriteObject.MyStringVariable]", "")
|
||||
== "getAnyVariable(MySceneVariable).getChild(getVariableForObject(MySpriteObject, MyStringVariable).getAsString())");
|
||||
}
|
||||
SECTION("bracket access (using a number object variable inside)") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable[MySpriteObject.MyNumberVariable]", "")
|
||||
== "getLayoutVariable(myVariable).getChild(getVariableForObject(MySpriteObject, MyNumberVariable).getAsNumber())");
|
||||
codeGenerator, context, "variable", "MySceneVariable[MySpriteObject.MyNumberVariable]", "")
|
||||
== "getAnyVariable(MySceneVariable).getChild(getVariableForObject(MySpriteObject, MyNumberVariable).getAsNumber())");
|
||||
}
|
||||
SECTION("bracket access (using a string variable inside)") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable[MySceneStringVariable]", "")
|
||||
== "getLayoutVariable(myVariable).getChild(getLayoutVariable(MySceneStringVariable).getAsString())");
|
||||
codeGenerator, context, "variable", "MySceneVariable[MySceneStringVariable]", "")
|
||||
== "getAnyVariable(MySceneVariable).getChild(getAnyVariable(MySceneStringVariable).getAsString())");
|
||||
}
|
||||
SECTION("bracket access (using a number variable inside)") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable[MySceneVariable]", "")
|
||||
== "getLayoutVariable(myVariable).getChild(getLayoutVariable(MySceneVariable).getAsNumber())");
|
||||
codeGenerator, context, "variable", "MySceneVariable[MySceneVariable]", "")
|
||||
== "getAnyVariable(MySceneVariable).getChild(getAnyVariable(MySceneVariable).getAsNumber())");
|
||||
}
|
||||
SECTION("bracket access (using a string global variable inside)") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable[MyGlobalStringVariable]", "")
|
||||
== "getLayoutVariable(myVariable).getChild(getProjectVariable(MyGlobalStringVariable).getAsString())");
|
||||
codeGenerator, context, "variable", "MySceneVariable[MyGlobalStringVariable]", "")
|
||||
== "getAnyVariable(MySceneVariable).getChild(getAnyVariable(MyGlobalStringVariable).getAsString())");
|
||||
}
|
||||
SECTION("bracket access (using a number global variable inside)") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable[MyGlobalNumberVariable]", "")
|
||||
== "getLayoutVariable(myVariable).getChild(getProjectVariable(MyGlobalNumberVariable).getAsNumber())");
|
||||
codeGenerator, context, "variable", "MySceneVariable[MyGlobalNumberVariable]", "")
|
||||
== "getAnyVariable(MySceneVariable).getChild(getAnyVariable(MyGlobalNumberVariable).getAsNumber())");
|
||||
}
|
||||
SECTION("bracket access (using a boolean variable inside)") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable[MySceneBooleanVariable]", "")
|
||||
== "getLayoutVariable(myVariable).getChild(getLayoutVariable(MySceneBooleanVariable).getAsNumberOrString())");
|
||||
codeGenerator, context, "variable", "MySceneVariable[MySceneBooleanVariable]", "")
|
||||
== "getAnyVariable(MySceneVariable).getChild(getAnyVariable(MySceneBooleanVariable).getAsNumberOrString())");
|
||||
}
|
||||
SECTION("bracket access (using a structure variable inside)") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable[MySceneStructureVariable.MyChild.SubChild]", "")
|
||||
== "getLayoutVariable(myVariable).getChild(getLayoutVariable(MySceneStructureVariable).getChild(\"MyChild\").getChild(\"SubChild\").getAsNumberOrString())");
|
||||
codeGenerator, context, "variable", "MySceneVariable[MySceneStructureVariable.MyChild.SubChild]", "")
|
||||
== "getAnyVariable(MySceneVariable).getChild(getAnyVariable(MySceneStructureVariable).getChild(\"MyChild\").getChild(\"SubChild\").getAsNumberOrString())");
|
||||
}
|
||||
SECTION("object variable") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
@@ -1106,7 +1109,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
SECTION("object variable with bracket access (using a structure variable inside)") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "objectvar", "myVariable[MySceneStringVariable]", "MySpriteObject")
|
||||
== "getVariableForObject(MySpriteObject, myVariable).getChild(getLayoutVariable(MySceneStringVariable).getAsString())");
|
||||
== "getVariableForObject(MySpriteObject, myVariable).getChild(getAnyVariable(MySceneStringVariable).getAsString())");
|
||||
}
|
||||
SECTION("object variable with bracket access (using an object variable inside)") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
@@ -1322,7 +1325,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "\"You have \" + getLayoutVariable(MySceneVariable).getAsString() + \" points\"");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "\"You have \" + getAnyVariable(MySceneVariable).getAsString() + \" points\"");
|
||||
}
|
||||
{
|
||||
auto node =
|
||||
@@ -1334,7 +1337,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneVariable).getAsString() + getLayoutVariable(MySceneStringVariable).getAsString()");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneVariable).getAsString() + getAnyVariable(MySceneStringVariable).getAsString()");
|
||||
}
|
||||
}
|
||||
SECTION("Expression/parent type is 'string' (with an unknown variable)") {
|
||||
@@ -1348,7 +1351,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "\"You have \" + getLayoutVariable(MySceneStructureVariable).getChild(\"MyChild\").getChild(\"CantKnownTheTypeSoStayGeneric\").getAsString() + \" points\"");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "\"You have \" + getAnyVariable(MySceneStructureVariable).getChild(\"MyChild\").getChild(\"CantKnownTheTypeSoStayGeneric\").getAsString() + \" points\"");
|
||||
}
|
||||
}
|
||||
SECTION("Expression/parent type is 'string' (2 number variables)") {
|
||||
@@ -1362,7 +1365,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneVariable).getAsString() + getLayoutVariable(MySceneVariable2).getAsString() + \"world\"");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneVariable).getAsString() + getAnyVariable(MySceneVariable2).getAsString() + \"world\"");
|
||||
}
|
||||
{
|
||||
auto node =
|
||||
@@ -1374,7 +1377,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneVariable).getAsString() + getLayoutVariable(MySceneVariable2).getAsString() + getLayoutVariable(MySceneStringVariable).getAsString()");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneVariable).getAsString() + getAnyVariable(MySceneVariable2).getAsString() + getAnyVariable(MySceneStringVariable).getAsString()");
|
||||
}
|
||||
}
|
||||
SECTION("Expression/parent type is 'string' (array variable)") {
|
||||
@@ -1388,7 +1391,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "\"hello\" + getLayoutVariable(MySceneNumberArrayVariable).getChild(2).getAsString() + \"world\"");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "\"hello\" + getAnyVariable(MySceneNumberArrayVariable).getChild(2).getAsString() + \"world\"");
|
||||
}
|
||||
{
|
||||
auto node =
|
||||
@@ -1400,7 +1403,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "\"hello\" + getLayoutVariable(MySceneEmptyArrayVariable).getChild(2).getAsString() + \"world\"");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "\"hello\" + getAnyVariable(MySceneEmptyArrayVariable).getChild(2).getAsString() + \"world\"");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1415,7 +1418,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "123 + getLayoutVariable(MySceneVariable).getAsNumber() + 456");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "123 + getAnyVariable(MySceneVariable).getAsNumber() + 456");
|
||||
}
|
||||
{
|
||||
auto node =
|
||||
@@ -1427,7 +1430,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStringVariable).getAsNumber() + getLayoutVariable(MySceneVariable).getAsNumber()");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStringVariable).getAsNumber() + getAnyVariable(MySceneVariable).getAsNumber()");
|
||||
}
|
||||
}
|
||||
SECTION("Expression/parent type is 'string' (with an unknown variable)") {
|
||||
@@ -1441,7 +1444,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "123 + getLayoutVariable(MySceneStructureVariable).getChild(\"MyChild\").getChild(\"CantKnownTheTypeSoStayGeneric\").getAsNumber() + 456");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "123 + getAnyVariable(MySceneStructureVariable).getChild(\"MyChild\").getChild(\"CantKnownTheTypeSoStayGeneric\").getAsNumber() + 456");
|
||||
}
|
||||
}
|
||||
SECTION("Expression/parent type is 'number' (2 string variables)") {
|
||||
@@ -1455,7 +1458,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStringVariable).getAsNumber() + getLayoutVariable(MySceneStringVariable).getAsNumber() + 456");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStringVariable).getAsNumber() + getAnyVariable(MySceneStringVariable).getAsNumber() + 456");
|
||||
}
|
||||
{
|
||||
auto node =
|
||||
@@ -1467,7 +1470,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStringVariable).getAsNumber() + getLayoutVariable(MySceneStringVariable).getAsNumber() + getLayoutVariable(MySceneVariable).getAsNumber()");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "getAnyVariable(MySceneStringVariable).getAsNumber() + getAnyVariable(MySceneStringVariable).getAsNumber() + getAnyVariable(MySceneVariable).getAsNumber()");
|
||||
}
|
||||
}
|
||||
SECTION("Expression/parent type is 'number' (array variable)") {
|
||||
@@ -1481,7 +1484,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "123 + getLayoutVariable(MySceneNumberArrayVariable).getChild(2).getAsNumber() + 456");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "123 + getAnyVariable(MySceneNumberArrayVariable).getChild(2).getAsNumber() + 456");
|
||||
}
|
||||
{
|
||||
auto node =
|
||||
@@ -1493,7 +1496,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "123 + getLayoutVariable(MySceneEmptyArrayVariable).getChild(2).getAsNumber() + 456");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "123 + getAnyVariable(MySceneEmptyArrayVariable).getChild(2).getAsNumber() + 456");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1509,7 +1512,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "\"hello\" + getLayoutVariable(MySceneNumberArrayVariable).getChild(2 + getLayoutVariable(MySceneStringVariable).getAsNumber()).getAsString() + \"world\" + getLayoutVariable(MySceneVariable).getAsString() + \"world 2\"");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "\"hello\" + getAnyVariable(MySceneNumberArrayVariable).getChild(2 + getAnyVariable(MySceneStringVariable).getAsNumber()).getAsString() + \"world\" + getAnyVariable(MySceneVariable).getAsString() + \"world 2\"");
|
||||
}
|
||||
{
|
||||
auto node =
|
||||
@@ -1521,7 +1524,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "\"hello\" + getLayoutVariable(MySceneNumberArrayVariable).getChild(\"foo\" + getLayoutVariable(MySceneVariable).getAsString() + \"bar\").getAsString() + \"world\" + getLayoutVariable(MySceneVariable).getAsString() + \"world 2\"");
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "\"hello\" + getAnyVariable(MySceneNumberArrayVariable).getChild(\"foo\" + getAnyVariable(MySceneVariable).getAsString() + \"bar\").getAsString() + \"world\" + getAnyVariable(MySceneVariable).getAsString() + \"world 2\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -55,8 +55,8 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Object or expression completions when type is string") {
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedCompletions{
|
||||
"{ 0, string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
"{ 3, no type, 1, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
"{ 0, string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
"{ 3, no type, 2, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("string", "My", 0, 2).ToString()
|
||||
};
|
||||
// clang-format on
|
||||
@@ -67,8 +67,8 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Object or expression completions when type is number") {
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedCompletions{
|
||||
"{ 0, number, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
"{ 3, no type, 1, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
"{ 0, number, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
"{ 3, no type, 2, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("number", "My", 0, 2).ToString()
|
||||
};
|
||||
// clang-format on
|
||||
@@ -79,8 +79,8 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Object or expression completions when type is number|string") {
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedCompletions{
|
||||
"{ 0, number|string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
"{ 3, no type, 1, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
"{ 0, number|string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
"{ 3, no type, 2, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("number|string", "My", 0, 2).ToString()
|
||||
};
|
||||
// clang-format on
|
||||
@@ -94,8 +94,8 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Object or expression completions in a variable name") {
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedCompletions{
|
||||
"{ 0, string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
"{ 3, no type, 1, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
"{ 0, string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
"{ 3, no type, 2, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("string", "My", 0, 2).ToString()
|
||||
};
|
||||
// clang-format on
|
||||
@@ -115,8 +115,8 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Object or expression completions in a variable index") {
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedCompletions{
|
||||
"{ 0, number, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
"{ 3, no type, 1, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
"{ 0, number, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
"{ 3, no type, 2, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("number", "My", 0, 2).ToString()
|
||||
};
|
||||
// clang-format on
|
||||
@@ -136,7 +136,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Object when type is an object") {
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedCompletions{
|
||||
"{ 0, object, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
"{ 0, object, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
};
|
||||
// clang-format on
|
||||
REQUIRE(getCompletionsFor("object", "My", 0) == expectedCompletions);
|
||||
@@ -149,7 +149,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
// result in different code generation):
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedCompletions{
|
||||
"{ 0, objectPtr, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
"{ 0, objectPtr, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
};
|
||||
// clang-format on
|
||||
REQUIRE(getCompletionsFor("objectPtr", "My", 0) == expectedCompletions);
|
||||
@@ -204,8 +204,8 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedCompletions{
|
||||
"{ 0, unknown, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
"{ 3, no type, 1, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
"{ 0, unknown, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
|
||||
"{ 3, no type, 2, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("unknown", "My", 9, 10).ToString()
|
||||
};
|
||||
// clang-format on
|
||||
@@ -215,7 +215,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Function with a Variable as argument") {
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedCompletions{
|
||||
"{ 3, no type, 1, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
"{ 3, no type, 2, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
};
|
||||
// clang-format on
|
||||
REQUIRE(getCompletionsFor("number",
|
||||
@@ -225,7 +225,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Object function with a Variable as argument") {
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedCompletions{
|
||||
"{ 3, no type, 1, no prefix, myObjectVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
"{ 3, no type, 2, no prefix, myObjectVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
|
||||
};
|
||||
// clang-format on
|
||||
REQUIRE(getCompletionsFor("number",
|
||||
@@ -254,7 +254,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Test with string type") {
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedObjectCompletions{
|
||||
"{ 0, string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
|
||||
"{ 0, string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
|
||||
};
|
||||
std::vector<gd::String> expectedBehaviorOrFunctionCompletions{
|
||||
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("Func", 9, 13, "MyObject").ToString(),
|
||||
@@ -277,7 +277,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Test with 'number|string' type") {
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedObjectCompletions{
|
||||
"{ 0, number|string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
|
||||
"{ 0, number|string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
|
||||
};
|
||||
std::vector<gd::String> expectedBehaviorOrFunctionCompletions{
|
||||
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("Func", 9, 13, "MyObject").ToString(),
|
||||
@@ -303,7 +303,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Test 1") {
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedObjectCompletions{
|
||||
"{ 0, string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
|
||||
"{ 0, string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
|
||||
};
|
||||
std::vector<gd::String> expectedBehaviorOrFunctionCompletions{
|
||||
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("Func", 9, 13, "MyObject").ToString(),
|
||||
@@ -336,7 +336,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Test 1") {
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedObjectCompletions{
|
||||
"{ 0, string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
|
||||
"{ 0, string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
|
||||
};
|
||||
std::vector<gd::String> expectedBehaviorCompletions{
|
||||
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("MyBehavior", 9, 19, "MyObject").ToString()};
|
||||
@@ -366,7 +366,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Test 2") {
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedObjectCompletions{
|
||||
"{ 0, string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
|
||||
"{ 0, string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
|
||||
};
|
||||
std::vector<gd::String> expectedBehaviorCompletions{
|
||||
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("MyBehavior", 9, 19, "MyObject").ToString()
|
||||
@@ -396,7 +396,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Test 1") {
|
||||
// clang-format off
|
||||
std::vector<gd::String> expectedObjectCompletions{
|
||||
"{ 0, string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
|
||||
"{ 0, string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
|
||||
};
|
||||
std::vector<gd::String> expectedBehaviorCompletions{
|
||||
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("MyBehavior", 9, 19, "MyObject").ToString()
|
||||
|
@@ -11,7 +11,7 @@
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableParentFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariablePathFinder.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
@@ -22,6 +22,8 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
project.GetVariables().InsertNew("MyProjectVariable");
|
||||
|
||||
auto &layout1 = project.InsertNewLayout("Layout1", 0);
|
||||
layout1.GetVariables().InsertNew("MySceneVariable");
|
||||
layout1.GetVariables().InsertNew("MySceneVariable2");
|
||||
@@ -204,7 +206,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
// Also check that if we try to find the last parent of node, it is not defined.
|
||||
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
auto lastParentOfNode = gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, *node);
|
||||
REQUIRE(lastParentOfNode.parentVariable == nullptr);
|
||||
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
|
||||
@@ -232,7 +234,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
// Also check that if we try to find the last parent of node, it is not defined.
|
||||
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
auto lastParentOfNode = gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, *node);
|
||||
REQUIRE(lastParentOfNode.parentVariable == nullptr);
|
||||
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
|
||||
@@ -786,7 +788,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
// Also check that if we try to find the last parent of node, it is not defined.
|
||||
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
auto lastParentOfNode = gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, *node);
|
||||
REQUIRE(lastParentOfNode.parentVariable == nullptr);
|
||||
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
|
||||
@@ -1525,7 +1527,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
parser.ParseExpression("MyNonExistingSceneVariable");
|
||||
|
||||
// Also check that if we try to find the last parent of node, it is not defined.
|
||||
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
auto lastParentOfNode = gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, *node);
|
||||
REQUIRE(lastParentOfNode.parentVariable == nullptr);
|
||||
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
|
||||
@@ -1557,7 +1559,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
parser.ParseExpression("MyNonExistingSceneVariable.MyNonExistingChild");
|
||||
|
||||
// Also check that if we try to find the last parent of node, it is not defined.
|
||||
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
auto lastParentOfNode = gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, *node);
|
||||
REQUIRE(lastParentOfNode.parentVariable == nullptr);
|
||||
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
|
||||
@@ -1641,7 +1643,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
parser.ParseExpression("MyNonExistingSpriteObject.MyVariable");
|
||||
|
||||
// Also check that if we try to find the last parent of node, it is not defined.
|
||||
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
auto lastParentOfNode = gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, *node);
|
||||
REQUIRE(lastParentOfNode.parentVariable == nullptr);
|
||||
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
|
||||
@@ -2711,6 +2713,103 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
"You entered a text, but this type was expected: variable");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Variable declaration") {
|
||||
SECTION("Undeclared variable") {
|
||||
auto node = parser.ParseExpression("MyUndeclaredVariable");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "variable");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
|
||||
"No variable with this name found.");
|
||||
}
|
||||
|
||||
SECTION("Undeclared variable with children") {
|
||||
auto node = parser.ParseExpression("MyUndeclaredVariable.MyChild.MyChild");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "variable");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 1);
|
||||
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
|
||||
"No variable with this name found.");
|
||||
}
|
||||
|
||||
SECTION("Declared scene variable") {
|
||||
auto node = parser.ParseExpression("MySceneVariable");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "variable");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 0);
|
||||
}
|
||||
|
||||
SECTION("Declared scene variable with children") {
|
||||
// Children themselves don't need to be declared.
|
||||
auto node = parser.ParseExpression("MySceneVariable.MyChild.MyChild");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "variable");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 0);
|
||||
}
|
||||
|
||||
SECTION("Declared project variable") {
|
||||
auto node = parser.ParseExpression("MyProjectVariable");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "variable");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 0);
|
||||
}
|
||||
|
||||
SECTION("Declared project variable with children") {
|
||||
auto node = parser.ParseExpression("MyProjectVariable.MyChild.MyChild");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "variable");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 0);
|
||||
}
|
||||
|
||||
SECTION("Undeclared legacy pre-scope scene variable") {
|
||||
auto node = parser.ParseExpression("MyUndeclaredVariable");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "scenevar");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 0);
|
||||
}
|
||||
|
||||
SECTION("Undeclared legacy pre-scope scene variable with children") {
|
||||
auto node = parser.ParseExpression("MyUndeclaredVariable.MyChild.MyChild");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "scenevar");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 0);
|
||||
}
|
||||
|
||||
SECTION("Undeclared legacy pre-scope project variable") {
|
||||
auto node = parser.ParseExpression("MyUndeclaredVariable");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "globalvar");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 0);
|
||||
}
|
||||
|
||||
SECTION("Undeclared legacy pre-scope project variable with children") {
|
||||
auto node = parser.ParseExpression("MyUndeclaredVariable.MyChild.MyChild");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
gd::ExpressionValidator validator(platform, projectScopedContainers, "globalvar");
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetFatalErrors().size() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Valid variables") {
|
||||
SECTION("simple variable") {
|
||||
@@ -3218,10 +3317,10 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
REQUIRE(variable2ObjectName == "MySpriteObject2");
|
||||
|
||||
// Also check the ability to find the last parent of the variables:
|
||||
auto lastParentOfVariable1Node = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
auto lastParentOfVariable1Node = gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, variable1Node);
|
||||
REQUIRE(lastParentOfVariable1Node.parentVariablesContainer == &mySpriteObject.GetVariables());
|
||||
auto lastParentOfVariable2Node = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
auto lastParentOfVariable2Node = gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, variable2Node);
|
||||
REQUIRE(lastParentOfVariable2Node.parentVariablesContainer == &mySpriteObject2.GetVariables());
|
||||
|
||||
@@ -3257,10 +3356,10 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
REQUIRE(variable2ObjectName == "MySpriteObject");
|
||||
|
||||
// Also check the ability to find the last parent of the variables:
|
||||
auto lastParentOfVariable1Node = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
auto lastParentOfVariable1Node = gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, variable1Node);
|
||||
REQUIRE(lastParentOfVariable1Node.parentVariablesContainer == &mySpriteObject.GetVariables());
|
||||
auto lastParentOfVariable2Node = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
auto lastParentOfVariable2Node = gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, variable2Node);
|
||||
REQUIRE(lastParentOfVariable2Node.parentVariablesContainer == &mySpriteObject.GetVariables());
|
||||
|
||||
@@ -3286,7 +3385,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
REQUIRE(variable1ObjectName == "MySpriteObject");
|
||||
|
||||
// Also check the ability to find the last parent of the variable:
|
||||
auto lastParentOfVariable1Node = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
auto lastParentOfVariable1Node = gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, variable1Node);
|
||||
REQUIRE(lastParentOfVariable1Node.parentVariablesContainer == &mySpriteObject.GetVariables());
|
||||
|
||||
@@ -3313,7 +3412,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
REQUIRE(variable1ObjectName == "MySpriteObject");
|
||||
|
||||
// Also check the ability to find the last parent of the variable:
|
||||
auto lastParentOfVariable1Node = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
auto lastParentOfVariable1Node = gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, variable1Node);
|
||||
REQUIRE(lastParentOfVariable1Node.parentVariable == &mySpriteObject.GetVariables().Get("MyVariable"));
|
||||
|
||||
|
@@ -203,7 +203,6 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
|
||||
"RenamedGlobalVariableFromASharedName");
|
||||
auto changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedProjectVariables,
|
||||
project.GetVariables());
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
@@ -214,7 +213,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
|
||||
"MyRenamedSceneStructureVariable");
|
||||
changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project, originalSerializedLayoutVariables, layout1.GetVariables());
|
||||
originalSerializedLayoutVariables, layout1.GetVariables());
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
project, layout1.GetVariables(), changeset);
|
||||
|
||||
@@ -224,7 +223,6 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
|
||||
"MyRenamedObjectStructureVariable");
|
||||
changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedObject1Variables,
|
||||
object1.GetVariables());
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
@@ -436,7 +434,6 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
|
||||
"MyRenamedObjectStructureVariable");
|
||||
auto changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedObject1Variables,
|
||||
object1.GetVariables());
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
@@ -668,7 +665,6 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
|
||||
project.GetVariables().Remove("SharedVariableName");
|
||||
auto changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedProjectVariables,
|
||||
project.GetVariables());
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
@@ -678,7 +674,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
|
||||
layout1.GetVariables().Remove("MySceneStructureVariable");
|
||||
changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project, originalSerializedLayoutVariables, layout1.GetVariables());
|
||||
originalSerializedLayoutVariables, layout1.GetVariables());
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
project, layout1.GetVariables(), changeset);
|
||||
|
||||
@@ -686,7 +682,6 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
|
||||
object1.GetVariables().Remove("MyObjectStructureVariable");
|
||||
changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
project,
|
||||
originalSerializedObject1Variables,
|
||||
object1.GetVariables());
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
@@ -732,4 +727,285 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
|
||||
gd::Serializer::ToJSON(originalSerializedLayout2));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Can change the instruction type of variable occurrences (scene)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto &scene = project.InsertNewLayout("Scene", 0);
|
||||
scene.GetVariables().InsertNew("MySceneVariable").SetValue(123);
|
||||
|
||||
gd::StandardEvent &event =
|
||||
dynamic_cast<gd::StandardEvent &>(scene.GetEvents().InsertNewEvent(
|
||||
project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
{
|
||||
gd::Instruction action;
|
||||
action.SetType("SetNumberVariable");
|
||||
action.SetParametersCount(3);
|
||||
action.SetParameter(0, gd::Expression("MySceneVariable"));
|
||||
action.SetParameter(1, gd::Expression("="));
|
||||
action.SetParameter(2, gd::Expression("123"));
|
||||
event.GetActions().Insert(action);
|
||||
}
|
||||
|
||||
// Do the changes and launch the refactoring.
|
||||
scene.GetVariables().ResetPersistentUuid();
|
||||
gd::SerializerElement originalSerializedVariables;
|
||||
scene.GetVariables().SerializeTo(originalSerializedVariables);
|
||||
|
||||
scene.GetVariables().Get("MySceneVariable").SetString("Hello");
|
||||
auto changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
originalSerializedVariables, scene.GetVariables());
|
||||
|
||||
REQUIRE(changeset.typeChangedVariableNames.find("MySceneVariable") !=
|
||||
changeset.typeChangedVariableNames.end());
|
||||
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
project, scene.GetVariables(), changeset);
|
||||
|
||||
// Check the the action has changed to follow the variable type.
|
||||
REQUIRE(event.GetActions()[0].GetType() == "SetStringVariable");
|
||||
}
|
||||
|
||||
SECTION("Can change the instruction type of variable occurrences (function)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto &extension = project.InsertNewEventsFunctionsExtension("Extension", 0);
|
||||
extension.GetSceneVariables().InsertNew("MySceneVariable").SetValue(123);
|
||||
|
||||
auto &function = extension.InsertNewEventsFunction("MyFunction", 0);
|
||||
gd::StandardEvent &event =
|
||||
dynamic_cast<gd::StandardEvent &>(function.GetEvents().InsertNewEvent(
|
||||
project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
{
|
||||
gd::Instruction action;
|
||||
action.SetType("SetNumberVariable");
|
||||
action.SetParametersCount(3);
|
||||
action.SetParameter(0, gd::Expression("MySceneVariable"));
|
||||
action.SetParameter(1, gd::Expression("="));
|
||||
action.SetParameter(2, gd::Expression("123"));
|
||||
event.GetActions().Insert(action);
|
||||
}
|
||||
|
||||
// Do the changes and launch the refactoring.
|
||||
extension.GetSceneVariables().ResetPersistentUuid();
|
||||
gd::SerializerElement originalSerializedVariables;
|
||||
extension.GetSceneVariables().SerializeTo(originalSerializedVariables);
|
||||
|
||||
extension.GetSceneVariables().Get("MySceneVariable").SetString("Hello");
|
||||
auto changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
originalSerializedVariables, extension.GetSceneVariables());
|
||||
|
||||
REQUIRE(changeset.typeChangedVariableNames.find("MySceneVariable") !=
|
||||
changeset.typeChangedVariableNames.end());
|
||||
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
project, extension.GetSceneVariables(), changeset);
|
||||
|
||||
// Check the the action has changed to follow the variable type.
|
||||
REQUIRE(event.GetActions()[0].GetType() == "SetStringVariable");
|
||||
}
|
||||
|
||||
SECTION("Can change the instruction type of child-variable occurrences (scene)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto &scene = project.InsertNewLayout("Scene", 0);
|
||||
scene.GetVariables()
|
||||
.InsertNew("MySceneVariable")
|
||||
.GetChild("MyChild")
|
||||
.SetValue(123);
|
||||
|
||||
gd::StandardEvent &event =
|
||||
dynamic_cast<gd::StandardEvent &>(scene.GetEvents().InsertNewEvent(
|
||||
project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
{
|
||||
gd::Instruction action;
|
||||
action.SetType("SetNumberVariable");
|
||||
action.SetParametersCount(3);
|
||||
action.SetParameter(0, gd::Expression("MySceneVariable.MyChild"));
|
||||
action.SetParameter(1, gd::Expression("="));
|
||||
action.SetParameter(2, gd::Expression("123"));
|
||||
event.GetActions().Insert(action);
|
||||
}
|
||||
|
||||
// Do the changes and launch the refactoring.
|
||||
scene.GetVariables().ResetPersistentUuid();
|
||||
gd::SerializerElement originalSerializedVariables;
|
||||
scene.GetVariables().SerializeTo(originalSerializedVariables);
|
||||
|
||||
scene.GetVariables().Get("MySceneVariable").GetChild("MyChild").SetString("Hello");
|
||||
auto changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
originalSerializedVariables, scene.GetVariables());
|
||||
|
||||
REQUIRE(changeset.typeChangedVariableNames.find("MySceneVariable") !=
|
||||
changeset.typeChangedVariableNames.end());
|
||||
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
project, scene.GetVariables(), changeset);
|
||||
|
||||
// Check the the action has changed to follow the variable type.
|
||||
REQUIRE(event.GetActions()[0].GetType() == "SetStringVariable");
|
||||
}
|
||||
|
||||
SECTION("Can change the instruction type of child-variable occurrences with a literal brackets accessor (scene)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto &scene = project.InsertNewLayout("Scene", 0);
|
||||
auto &variable = scene.GetVariables().InsertNew("MySceneVariable");
|
||||
auto &childVariable = variable.GetChild("MyChild");
|
||||
childVariable.GetChild("Key A").SetValue(123);
|
||||
childVariable.GetChild("Key B").SetValue(123);
|
||||
|
||||
gd::StandardEvent &event =
|
||||
dynamic_cast<gd::StandardEvent &>(scene.GetEvents().InsertNewEvent(
|
||||
project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
{
|
||||
gd::Instruction action;
|
||||
action.SetType("SetNumberVariable");
|
||||
action.SetParametersCount(3);
|
||||
action.SetParameter(0, gd::Expression("MySceneVariable.MyChild[\"Key A\"]"));
|
||||
action.SetParameter(1, gd::Expression("="));
|
||||
action.SetParameter(2, gd::Expression("123"));
|
||||
event.GetActions().Insert(action);
|
||||
}
|
||||
{
|
||||
gd::Instruction action;
|
||||
action.SetType("SetNumberVariable");
|
||||
action.SetParametersCount(3);
|
||||
action.SetParameter(0, gd::Expression("MySceneVariable.MyChild[\"Key B\"]"));
|
||||
action.SetParameter(1, gd::Expression("="));
|
||||
action.SetParameter(2, gd::Expression("123"));
|
||||
event.GetActions().Insert(action);
|
||||
}
|
||||
|
||||
// Do the changes and launch the refactoring.
|
||||
scene.GetVariables().ResetPersistentUuid();
|
||||
gd::SerializerElement originalSerializedVariables;
|
||||
scene.GetVariables().SerializeTo(originalSerializedVariables);
|
||||
|
||||
scene.GetVariables().Get("MySceneVariable").GetChild("MyChild").GetChild("Key A").SetString("Hello");
|
||||
auto changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
originalSerializedVariables, scene.GetVariables());
|
||||
|
||||
REQUIRE(changeset.typeChangedVariableNames.find("MySceneVariable") !=
|
||||
changeset.typeChangedVariableNames.end());
|
||||
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
project, scene.GetVariables(), changeset);
|
||||
|
||||
// Check the the action has changed to follow the variable type.
|
||||
REQUIRE(event.GetActions()[0].GetType() == "SetStringVariable");
|
||||
REQUIRE(event.GetActions()[1].GetType() == "SetNumberVariable");
|
||||
}
|
||||
|
||||
SECTION("Can change the instruction type of variable occurrences (object)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto &scene = project.InsertNewLayout("Scene", 0);
|
||||
auto &object =
|
||||
scene.InsertNewObject(project, "MyExtension::Sprite", "Object", 0);
|
||||
object.GetVariables().InsertNew("MyObjectVariable").SetValue(123);
|
||||
|
||||
gd::StandardEvent &event =
|
||||
dynamic_cast<gd::StandardEvent &>(scene.GetEvents().InsertNewEvent(
|
||||
project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
{
|
||||
gd::Instruction action;
|
||||
action.SetType("SetNumberObjectVariable");
|
||||
action.SetParametersCount(4);
|
||||
action.SetParameter(0, gd::Expression("Object"));
|
||||
action.SetParameter(1, gd::Expression("MyObjectVariable"));
|
||||
action.SetParameter(2, gd::Expression("="));
|
||||
action.SetParameter(3, gd::Expression("123"));
|
||||
event.GetActions().Insert(action);
|
||||
}
|
||||
|
||||
// Do the changes and launch the refactoring.
|
||||
object.GetVariables().ResetPersistentUuid();
|
||||
gd::SerializerElement originalSerializedVariables;
|
||||
object.GetVariables().SerializeTo(originalSerializedVariables);
|
||||
|
||||
object.GetVariables().Get("MyObjectVariable").SetString("Hello");
|
||||
auto changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
originalSerializedVariables, object.GetVariables());
|
||||
|
||||
REQUIRE(changeset.typeChangedVariableNames.find("MyObjectVariable") !=
|
||||
changeset.typeChangedVariableNames.end());
|
||||
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
project, object.GetVariables(), changeset);
|
||||
|
||||
// Check the the action has changed to follow the variable type.
|
||||
REQUIRE(event.GetActions()[0].GetType() == "SetStringObjectVariable");
|
||||
}
|
||||
|
||||
SECTION("Can change the instruction type of child-variable occurrences (object)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto &scene = project.InsertNewLayout("Scene", 0);
|
||||
auto &object =
|
||||
scene.InsertNewObject(project, "MyExtension::Sprite", "Object", 0);
|
||||
object.GetVariables()
|
||||
.InsertNew("MyObjectVariable")
|
||||
.GetChild("MyChild")
|
||||
.SetValue(123);
|
||||
|
||||
gd::StandardEvent &event =
|
||||
dynamic_cast<gd::StandardEvent &>(scene.GetEvents().InsertNewEvent(
|
||||
project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
{
|
||||
gd::Instruction action;
|
||||
action.SetType("SetNumberObjectVariable");
|
||||
action.SetParametersCount(4);
|
||||
action.SetParameter(0, gd::Expression("Object"));
|
||||
action.SetParameter(1, gd::Expression("MyObjectVariable.MyChild"));
|
||||
action.SetParameter(2, gd::Expression("="));
|
||||
action.SetParameter(3, gd::Expression("123"));
|
||||
event.GetActions().Insert(action);
|
||||
}
|
||||
|
||||
// Do the changes and launch the refactoring.
|
||||
object.GetVariables().ResetPersistentUuid();
|
||||
gd::SerializerElement originalSerializedVariables;
|
||||
object.GetVariables().SerializeTo(originalSerializedVariables);
|
||||
|
||||
object.GetVariables()
|
||||
.Get("MyObjectVariable")
|
||||
.GetChild("MyChild")
|
||||
.SetString("Hello");
|
||||
auto changeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
originalSerializedVariables, object.GetVariables());
|
||||
|
||||
REQUIRE(changeset.typeChangedVariableNames.find("MyObjectVariable") !=
|
||||
changeset.typeChangedVariableNames.end());
|
||||
|
||||
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
project, object.GetVariables(), changeset);
|
||||
|
||||
// Check the the action has changed to follow the variable type.
|
||||
REQUIRE(event.GetActions()[0].GetType() == "SetStringObjectVariable");
|
||||
}
|
||||
}
|
||||
|
@@ -6,31 +6,34 @@ describe('gdjs.AnchorRuntimeBehavior', function () {
|
||||
const anchorBehaviorName = 'Anchor';
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
cameras: [],
|
||||
effects: [],
|
||||
ambientLightColorR: 127,
|
||||
ambientLightColorB: 127,
|
||||
ambientLightColorG: 127,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: false,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
sceneData: {
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
cameras: [],
|
||||
effects: [],
|
||||
ambientLightColorR: 127,
|
||||
ambientLightColorB: 127,
|
||||
ambientLightColorG: 127,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: false,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
},
|
||||
usedExtensionsWithVariablesData: [],
|
||||
});
|
||||
|
||||
function createObject(behaviorProperties) {
|
||||
|
@@ -3,31 +3,34 @@ describe('gdjs.DraggableRuntimeBehavior', function () {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
var runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
cameras: [],
|
||||
effects: [],
|
||||
ambientLightColorR: 127,
|
||||
ambientLightColorB: 127,
|
||||
ambientLightColorG: 127,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: false,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
sceneData: {
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
cameras: [],
|
||||
effects: [],
|
||||
ambientLightColorR: 127,
|
||||
ambientLightColorB: 127,
|
||||
ambientLightColorG: 127,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: false,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
},
|
||||
usedExtensionsWithVariablesData: [],
|
||||
});
|
||||
|
||||
var object = new gdjs.TestRuntimeObject(runtimeScene, {
|
||||
|
@@ -59,11 +59,14 @@ describe('gdjs.LightRuntimeObject', function () {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [{ name: '', visibility: true, effects: [] }],
|
||||
variables: [],
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
sceneData: {
|
||||
layers: [{ name: '', visibility: true, effects: [] }],
|
||||
variables: [],
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
},
|
||||
usedExtensionsWithVariablesData: [],
|
||||
});
|
||||
const lightObj = addLightObject(runtimeScene, 100);
|
||||
lightObj.setPosition(200, 200);
|
||||
@@ -93,11 +96,14 @@ describe('Light with obstacles around it', function () {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [{ name: '', visibility: true, effects: [] }],
|
||||
variables: [],
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
sceneData: {
|
||||
layers: [{ name: '', visibility: true, effects: [] }],
|
||||
variables: [],
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
},
|
||||
usedExtensionsWithVariablesData: [],
|
||||
});
|
||||
runtimeScene._timeManager.getElapsedTime = function () {
|
||||
return (1 / 60) * 1000;
|
||||
|
@@ -9,31 +9,34 @@ describe('gdjs.LinksManager', function () {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
cameras: [],
|
||||
effects: [],
|
||||
ambientLightColorR: 127,
|
||||
ambientLightColorB: 127,
|
||||
ambientLightColorG: 127,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: false,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
usedResources: [],
|
||||
sceneData: {
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
cameras: [],
|
||||
effects: [],
|
||||
ambientLightColorR: 127,
|
||||
ambientLightColorB: 127,
|
||||
ambientLightColorG: 127,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: false,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
usedResources: [],
|
||||
},
|
||||
usedExtensionsWithVariablesData: [],
|
||||
});
|
||||
|
||||
const manager = gdjs.LinksManager.getManager(runtimeScene);
|
||||
|
@@ -9,32 +9,35 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
cameras: [],
|
||||
sceneData: {
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
cameras: [],
|
||||
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: true,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: true,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
},
|
||||
usedExtensionsWithVariablesData: [],
|
||||
});
|
||||
setFramePerSecond(runtimeScene, framePerSecond);
|
||||
return runtimeScene;
|
||||
|
@@ -12,32 +12,35 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
cameras: [],
|
||||
sceneData: {
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
cameras: [],
|
||||
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: true,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: true,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
},
|
||||
usedExtensionsWithVariablesData: [],
|
||||
});
|
||||
setFramePerSecond(runtimeScene, framePerSecond);
|
||||
return runtimeScene;
|
||||
|
@@ -14,32 +14,35 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
cameras: [],
|
||||
sceneData: {
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
cameras: [],
|
||||
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: true,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: true,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
},
|
||||
usedExtensionsWithVariablesData: [],
|
||||
});
|
||||
runtimeScene._timeManager.getElapsedTime = function () {
|
||||
return (1 / 60) * 1000;
|
||||
|
@@ -62,30 +62,33 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
const runtimeScene = new gdjs.TestRuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
cameras: [],
|
||||
effects: [],
|
||||
ambientLightColorR: 127,
|
||||
ambientLightColorB: 127,
|
||||
ambientLightColorG: 127,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: false,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
sceneData: {
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
cameras: [],
|
||||
effects: [],
|
||||
ambientLightColorR: 127,
|
||||
ambientLightColorB: 127,
|
||||
ambientLightColorG: 127,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: false,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
},
|
||||
usedExtensionsWithVariablesData: [],
|
||||
});
|
||||
|
||||
runtimeScene.setInitialSharedDataForBehavior('Physics2', {
|
||||
|
@@ -2,13 +2,13 @@
|
||||
const makePlatformerTestRuntimeScene = (timeDelta = 1000 / 60) => {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
const runtimeScene = new gdjs.TestRuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
runtimeScene.loadFromScene({sceneData: {
|
||||
layers: [{ name: '', visibility: true, effects: [] }],
|
||||
variables: [],
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
});
|
||||
}, usedExtensionsWithVariablesData: []});
|
||||
runtimeScene._timeManager.getElapsedTime = function () {
|
||||
return timeDelta;
|
||||
};
|
||||
|
@@ -3,11 +3,14 @@ describe(`gdjs.PlatformerObjectRuntimeBehavior.findHighestFloorAndMoveOnTop`, fu
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [{ name: '', visibility: true, effects: [] }],
|
||||
variables: [],
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
sceneData: {
|
||||
layers: [{ name: '', visibility: true, effects: [] }],
|
||||
variables: [],
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
},
|
||||
usedExtensionsWithVariablesData: [],
|
||||
});
|
||||
runtimeScene._timeManager.getElapsedTime = function () {
|
||||
return (1 / 60) * 1000;
|
||||
|
@@ -24,31 +24,34 @@ describe('gdjs.ShapePainterRuntimeObject (using a PixiJS RuntimeGame with assets
|
||||
/** @param {gdjs.RuntimeScene} runtimeScene */
|
||||
const loadScene = (runtimeScene) => {
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
cameras: [],
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: true,
|
||||
},
|
||||
],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
variables: [],
|
||||
usedResources: [],
|
||||
sceneData: {
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
cameras: [],
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: true,
|
||||
},
|
||||
],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
variables: [],
|
||||
usedResources: [],
|
||||
},
|
||||
usedExtensionsWithVariablesData: [],
|
||||
});
|
||||
};
|
||||
|
||||
|
@@ -31,31 +31,34 @@ describe('gdjs.TextInputRuntimeObject (using a PixiJS RuntimeGame with DOM eleme
|
||||
/** @param {gdjs.RuntimeScene} runtimeScene */
|
||||
const loadScene = (runtimeScene) => {
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
cameras: [],
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: true,
|
||||
},
|
||||
],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
variables: [],
|
||||
usedResources: [],
|
||||
sceneData: {
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
cameras: [],
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: true,
|
||||
},
|
||||
],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
variables: [],
|
||||
usedResources: [],
|
||||
},
|
||||
usedExtensionsWithVariablesData: [],
|
||||
});
|
||||
};
|
||||
|
||||
|
@@ -33,32 +33,35 @@ describe('gdjs.TileMapCollisionMaskRuntimeObject', function () {
|
||||
});
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
cameras: [],
|
||||
sceneData: {
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
cameras: [],
|
||||
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: true,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: true,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
},
|
||||
usedExtensionsWithVariablesData: [],
|
||||
});
|
||||
setFramesPerSecond(runtimeScene, framePerSecond);
|
||||
return runtimeScene;
|
||||
|
@@ -7,32 +7,35 @@ describe('gdjs.TopDownMovementRuntimeBehavior', function () {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
cameras: [],
|
||||
sceneData: {
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
cameras: [],
|
||||
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: true,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: true,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
},
|
||||
usedExtensionsWithVariablesData: [],
|
||||
});
|
||||
runtimeScene._timeManager.getElapsedTime = function () {
|
||||
return timeDelta;
|
||||
|
@@ -6,6 +6,8 @@
|
||||
#include "BehaviorCodeGenerator.h"
|
||||
|
||||
#include "EventsCodeGenerator.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
|
||||
namespace gdjs {
|
||||
|
||||
@@ -13,7 +15,7 @@ gd::String BehaviorCodeGenerator::doStepPreEventsFunctionName =
|
||||
"doStepPreEvents";
|
||||
|
||||
gd::String BehaviorCodeGenerator::GenerateRuntimeBehaviorCompleteCode(
|
||||
const gd::String& extensionName,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::String& codeNamespace,
|
||||
const std::map<gd::String, gd::String>& behaviorMethodMangledNames,
|
||||
@@ -92,6 +94,7 @@ gd::String BehaviorCodeGenerator::GenerateRuntimeBehaviorCompleteCode(
|
||||
runtimeBehaviorMethodsCode +=
|
||||
EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
project,
|
||||
eventsFunctionsExtension,
|
||||
eventsBasedBehavior,
|
||||
*eventsFunction,
|
||||
methodCodeNamespace,
|
||||
@@ -137,7 +140,7 @@ gd::String BehaviorCodeGenerator::GenerateRuntimeBehaviorCompleteCode(
|
||||
};
|
||||
|
||||
return GenerateRuntimeBehaviorTemplateCode(
|
||||
extensionName,
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior,
|
||||
codeNamespace,
|
||||
generateInitializePropertiesCode,
|
||||
|
@@ -3,16 +3,19 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDJS_BEHAVIORCODEGENERATOR_H
|
||||
#define GDJS_BEHAVIORCODEGENERATOR_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
|
||||
namespace gd {
|
||||
class NamedPropertyDescriptor;
|
||||
class EventsBasedBehavior;
|
||||
}
|
||||
|
||||
namespace gdjs {
|
||||
@@ -32,7 +35,7 @@ class BehaviorCodeGenerator {
|
||||
* behavior.
|
||||
*/
|
||||
gd::String GenerateRuntimeBehaviorCompleteCode(
|
||||
const gd::String& extensionName,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::String& codeNamespace,
|
||||
const std::map<gd::String, gd::String>& behaviorMethodMangledNames,
|
||||
@@ -166,4 +169,3 @@ class BehaviorCodeGenerator {
|
||||
};
|
||||
|
||||
} // namespace gdjs
|
||||
#endif // GDJS_BEHAVIORCODEGENERATOR_H
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertiesContainer.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDJS/Events/CodeGeneration/BehaviorCodeGenerator.h"
|
||||
#include "GDJS/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
#include "GDJS/Extensions/JsPlatform.h"
|
||||
@@ -67,9 +68,16 @@ gd::String EventsCodeGenerator::GenerateEventsListCompleteFunctionCode(
|
||||
gd::String globalObjectLists = allObjectsDeclarationsAndResets.first;
|
||||
gd::String globalObjectListsReset = allObjectsDeclarationsAndResets.second;
|
||||
|
||||
gd::String localVariablesInitializationCode;
|
||||
if (codeGenerator.HasProjectAndLayout()) {
|
||||
localVariablesInitializationCode +=
|
||||
codeGenerator.GetCodeNamespace() + ".localVariables = [];\n";
|
||||
}
|
||||
|
||||
gd::String output =
|
||||
// clang-format off
|
||||
codeGenerator.GetCodeNamespace() + " = {};\n" +
|
||||
localVariablesInitializationCode +
|
||||
globalDeclarations +
|
||||
globalObjectLists + "\n\n" +
|
||||
codeGenerator.GetCustomCodeOutsideMain() + "\n\n" +
|
||||
@@ -113,25 +121,15 @@ gd::String EventsCodeGenerator::GenerateLayoutCode(
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateEventsFunctionCode(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsContainer& functionsContainer,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& codeNamespace,
|
||||
std::set<gd::String>& includeFiles,
|
||||
bool compilationForRuntime) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
project,
|
||||
functionsContainer,
|
||||
eventsFunction,
|
||||
globalObjectsAndGroups,
|
||||
objectsAndGroups);
|
||||
|
||||
gd::ProjectScopedContainers projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(
|
||||
globalObjectsAndGroups, objectsAndGroups);
|
||||
projectScopedContainers.AddParameters(
|
||||
eventsFunction.GetParametersForEvents(functionsContainer));
|
||||
gd::ObjectsContainer parameterObjectsAndGroups;
|
||||
auto projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsFunction, parameterObjectsAndGroups);
|
||||
|
||||
EventsCodeGenerator codeGenerator(projectScopedContainers);
|
||||
codeGenerator.SetCodeNamespace(codeNamespace);
|
||||
@@ -141,11 +139,11 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionCode(
|
||||
codeGenerator,
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "func",
|
||||
codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
|
||||
eventsFunction.GetParametersForEvents(functionsContainer), 0, true),
|
||||
eventsFunction.GetParametersForEvents(eventsFunctionsExtension), 0, true),
|
||||
codeGenerator.GenerateFreeEventsFunctionContext(
|
||||
eventsFunction.GetParametersForEvents(functionsContainer),
|
||||
"runtimeScene.getOnceTriggers()",
|
||||
eventsFunction.IsAsync()),
|
||||
eventsFunctionsExtension,
|
||||
eventsFunction,
|
||||
"runtimeScene.getOnceTriggers()"),
|
||||
eventsFunction.GetEvents(),
|
||||
"",
|
||||
codeGenerator.GenerateEventsFunctionReturn(eventsFunction));
|
||||
@@ -157,6 +155,7 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionCode(
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& codeNamespace,
|
||||
@@ -165,24 +164,12 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
const gd::String& preludeCode,
|
||||
std::set<gd::String>& includeFiles,
|
||||
bool compilationForRuntime) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
|
||||
project,
|
||||
eventsBasedBehavior,
|
||||
eventsFunction,
|
||||
globalObjectsAndGroups,
|
||||
objectsAndGroups);
|
||||
|
||||
gd::ProjectScopedContainers projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(
|
||||
globalObjectsAndGroups, objectsAndGroups);
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
eventsBasedBehavior.GetSharedPropertyDescriptors());
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
eventsBasedBehavior.GetPropertyDescriptors());
|
||||
projectScopedContainers.AddParameters(eventsFunction.GetParametersForEvents(
|
||||
eventsBasedBehavior.GetEventsFunctions()));
|
||||
gd::ObjectsContainer parameterObjectsContainers;
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForBehaviorEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior,
|
||||
eventsFunction, parameterObjectsContainers);
|
||||
|
||||
EventsCodeGenerator codeGenerator(projectScopedContainers);
|
||||
codeGenerator.SetCodeNamespace(codeNamespace);
|
||||
@@ -204,11 +191,10 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
// as a parameter called "Behavior".
|
||||
"var Behavior = this.name;\n" +
|
||||
codeGenerator.GenerateBehaviorEventsFunctionContext(
|
||||
eventsFunctionsExtension,
|
||||
eventsBasedBehavior,
|
||||
eventsFunction.GetParametersForEvents(
|
||||
eventsBasedBehavior.GetEventsFunctions()),
|
||||
eventsFunction,
|
||||
onceTriggersVariable,
|
||||
eventsFunction.IsAsync(),
|
||||
// Pass the names of the parameters considered as the current
|
||||
// object and behavior parameters:
|
||||
"Object",
|
||||
@@ -234,6 +220,7 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateObjectEventsFunctionCode(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& codeNamespace,
|
||||
@@ -243,22 +230,12 @@ gd::String EventsCodeGenerator::GenerateObjectEventsFunctionCode(
|
||||
const gd::String& endingCode,
|
||||
std::set<gd::String>& includeFiles,
|
||||
bool compilationForRuntime) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
project,
|
||||
eventsBasedObject,
|
||||
eventsFunction,
|
||||
globalObjectsAndGroups,
|
||||
objectsAndGroups);
|
||||
|
||||
gd::ProjectScopedContainers projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(
|
||||
globalObjectsAndGroups, objectsAndGroups);
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
eventsBasedObject.GetPropertyDescriptors());
|
||||
projectScopedContainers.AddParameters(eventsFunction.GetParametersForEvents(
|
||||
eventsBasedObject.GetEventsFunctions()));
|
||||
gd::ObjectsContainer parameterObjectsContainers;
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForObjectEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsBasedObject,
|
||||
eventsFunction, parameterObjectsContainers);
|
||||
|
||||
EventsCodeGenerator codeGenerator(projectScopedContainers);
|
||||
codeGenerator.SetCodeNamespace(codeNamespace);
|
||||
@@ -290,11 +267,10 @@ gd::String EventsCodeGenerator::GenerateObjectEventsFunctionCode(
|
||||
}
|
||||
|
||||
fullPreludeCode += codeGenerator.GenerateObjectEventsFunctionContext(
|
||||
eventsFunctionsExtension,
|
||||
eventsBasedObject,
|
||||
eventsFunction.GetParametersForEvents(
|
||||
eventsBasedObject.GetEventsFunctions()),
|
||||
eventsFunction,
|
||||
onceTriggersVariable,
|
||||
eventsFunction.IsAsync(),
|
||||
// Pass the names of the parameters considered as the current
|
||||
// object and behavior parameters:
|
||||
"Object");
|
||||
@@ -345,25 +321,26 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionParameterDeclarationsList(
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateFreeEventsFunctionContext(
|
||||
const vector<gd::ParameterMetadata>& parameters,
|
||||
const gd::String& onceTriggersVariable,
|
||||
bool isAsync) {
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& onceTriggersVariable) {
|
||||
gd::String objectsGettersMap;
|
||||
gd::String objectArraysMap;
|
||||
gd::String behaviorNamesMap;
|
||||
return GenerateEventsFunctionContext(parameters,
|
||||
return GenerateEventsFunctionContext(eventsFunctionsExtension,
|
||||
eventsFunctionsExtension,
|
||||
eventsFunction,
|
||||
onceTriggersVariable,
|
||||
objectsGettersMap,
|
||||
objectArraysMap,
|
||||
behaviorNamesMap,
|
||||
isAsync);
|
||||
behaviorNamesMap);
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionContext(
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const vector<gd::ParameterMetadata>& parameters,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& onceTriggersVariable,
|
||||
bool isAsync,
|
||||
const gd::String& thisObjectName,
|
||||
const gd::String& thisBehaviorName) {
|
||||
// See the comment at the start of the GenerateEventsFunctionContext function
|
||||
@@ -409,21 +386,22 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionContext(
|
||||
}
|
||||
}
|
||||
|
||||
return GenerateEventsFunctionContext(parameters,
|
||||
return GenerateEventsFunctionContext(eventsFunctionsExtension,
|
||||
eventsBasedBehavior.GetEventsFunctions(),
|
||||
eventsFunction,
|
||||
onceTriggersVariable,
|
||||
objectsGettersMap,
|
||||
objectArraysMap,
|
||||
behaviorNamesMap,
|
||||
isAsync,
|
||||
thisObjectName,
|
||||
thisBehaviorName);
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateObjectEventsFunctionContext(
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const vector<gd::ParameterMetadata>& parameters,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& onceTriggersVariable,
|
||||
bool isAsync,
|
||||
const gd::String& thisObjectName) {
|
||||
// See the comment at the start of the GenerateEventsFunctionContext function
|
||||
|
||||
@@ -454,24 +432,30 @@ gd::String EventsCodeGenerator::GenerateObjectEventsFunctionContext(
|
||||
}
|
||||
}
|
||||
|
||||
return GenerateEventsFunctionContext(parameters,
|
||||
return GenerateEventsFunctionContext(eventsFunctionsExtension,
|
||||
eventsBasedObject.GetEventsFunctions(),
|
||||
eventsFunction,
|
||||
onceTriggersVariable,
|
||||
objectsGettersMap,
|
||||
objectArraysMap,
|
||||
behaviorNamesMap,
|
||||
isAsync,
|
||||
thisObjectName);
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
const vector<gd::ParameterMetadata>& parameters,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsFunctionsContainer& eventsFunctionsContainer,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& onceTriggersVariable,
|
||||
gd::String& objectsGettersMap,
|
||||
gd::String& objectArraysMap,
|
||||
gd::String& behaviorNamesMap,
|
||||
bool isAsync,
|
||||
const gd::String& thisObjectName,
|
||||
const gd::String& thisBehaviorName) {
|
||||
const auto& extensionName = eventsFunctionsExtension.GetName();
|
||||
const auto ¶meters = eventsFunction.GetParametersForEvents(
|
||||
eventsFunctionsContainer);
|
||||
|
||||
// When running in the context of a function generated from events, we
|
||||
// need some indirection to deal with objects, behaviors and parameters in
|
||||
// general:
|
||||
@@ -525,7 +509,7 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
}
|
||||
|
||||
const gd::String async =
|
||||
isAsync ? " task: new gdjs.ManuallyResolvableTask(),\n" : "";
|
||||
eventsFunction.IsAsync() ? " task: new gdjs.ManuallyResolvableTask(),\n" : "";
|
||||
|
||||
return gd::String("var eventsFunctionContext = {\n") +
|
||||
// The async task, if there is one
|
||||
@@ -541,6 +525,14 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
" _behaviorNamesMap: {\n" +
|
||||
behaviorNamesMap +
|
||||
"},\n"
|
||||
" globalVariablesForExtension: "
|
||||
"runtimeScene.getGame().getVariablesForExtension(" +
|
||||
ConvertToStringExplicit(extensionName) + "),\n" +
|
||||
" sceneVariablesForExtension: "
|
||||
"runtimeScene.getVariablesForExtension(" +
|
||||
ConvertToStringExplicit(extensionName) + "),\n" +
|
||||
// The local variables stack:
|
||||
" localVariables: [],\n"
|
||||
// Function that will be used to query objects, when a new object list
|
||||
// is needed by events. We assume it's used a lot by the events
|
||||
// generated code, so we cache the arrays in a map.
|
||||
@@ -875,7 +867,8 @@ gd::String EventsCodeGenerator::GenerateObjectAction(
|
||||
// Create call
|
||||
gd::String call;
|
||||
if (instrInfos.codeExtraInformation.type == "number" ||
|
||||
instrInfos.codeExtraInformation.type == "string") {
|
||||
instrInfos.codeExtraInformation.type == "string" ||
|
||||
instrInfos.codeExtraInformation.type == "boolean") {
|
||||
if (instrInfos.codeExtraInformation.accessType ==
|
||||
gd::InstructionMetadata::ExtraInformation::MutatorAndOrAccessor)
|
||||
call = GenerateOperatorCall(
|
||||
@@ -936,7 +929,8 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
|
||||
// Create call
|
||||
gd::String call;
|
||||
if ((instrInfos.codeExtraInformation.type == "number" ||
|
||||
instrInfos.codeExtraInformation.type == "string")) {
|
||||
instrInfos.codeExtraInformation.type == "string" ||
|
||||
instrInfos.codeExtraInformation.type == "boolean")) {
|
||||
if (instrInfos.codeExtraInformation.accessType ==
|
||||
gd::InstructionMetadata::ExtraInformation::MutatorAndOrAccessor)
|
||||
call = GenerateOperatorCall(
|
||||
@@ -1298,7 +1292,35 @@ gd::String EventsCodeGenerator::GenerateGetVariable(
|
||||
const gd::String& objectName) {
|
||||
gd::String output;
|
||||
const gd::VariablesContainer* variables = NULL;
|
||||
if (scope == LAYOUT_VARIABLE) {
|
||||
if (scope == ANY_VARIABLE) {
|
||||
const auto variablesContainersList =
|
||||
GetProjectScopedContainers().GetVariablesContainersList();
|
||||
const auto &variablesContainer =
|
||||
variablesContainersList.GetVariablesContainerFromVariableName(
|
||||
variableName);
|
||||
const auto sourceType = variablesContainer.GetSourceType();
|
||||
if (sourceType == gd::VariablesContainer::SourceType::Scene) {
|
||||
variables = &variablesContainer;
|
||||
output = "runtimeScene.getScene().getVariables()";
|
||||
} else if (sourceType == gd::VariablesContainer::SourceType::Global) {
|
||||
variables = &variablesContainer;
|
||||
output = "runtimeScene.getGame().getVariables()";
|
||||
} else if (sourceType == gd::VariablesContainer::SourceType::Local) {
|
||||
variables = &variablesContainer;
|
||||
std::size_t localVariablesIndex =
|
||||
variablesContainersList.GetLocalVariablesContainerPosition(
|
||||
variablesContainer);
|
||||
output = GenerateLocalVariablesStackAccessor() + "[" +
|
||||
gd::String::From(localVariablesIndex) + "]";
|
||||
} else if (sourceType ==
|
||||
gd::VariablesContainer::SourceType::ExtensionGlobal) {
|
||||
variables = &variablesContainer;
|
||||
output = "eventsFunctionContext.globalVariablesForExtension";
|
||||
} else if (sourceType == gd::VariablesContainer::SourceType::ExtensionScene) {
|
||||
variables = &variablesContainer;
|
||||
output = "eventsFunctionContext.sceneVariablesForExtension";
|
||||
}
|
||||
} else if (scope == LAYOUT_VARIABLE) {
|
||||
output = "runtimeScene.getScene().getVariables()";
|
||||
|
||||
if (HasProjectAndLayout()) {
|
||||
|
@@ -3,8 +3,8 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef EVENTSCODEGENERATOR_H
|
||||
#define EVENTSCODEGENERATOR_H
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -57,7 +57,7 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
* Generate JavaScript for executing events of an events based function.
|
||||
*
|
||||
* \param project Project used.
|
||||
* \param functionsContainer The container of the compiled event function.
|
||||
* \param eventsFunctionsExtension The container of the compiled event function.
|
||||
* \param eventsFunction The events function to be compiled.
|
||||
* \param codeNamespace Where to store the context used by the function.
|
||||
* \param includeFiles Will be filled with the necessary include files.
|
||||
@@ -68,7 +68,7 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
*/
|
||||
static gd::String GenerateEventsFunctionCode(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsContainer& functionsContainer,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& codeNamespace,
|
||||
std::set<gd::String>& includeFiles,
|
||||
@@ -94,6 +94,7 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
*/
|
||||
static gd::String GenerateBehaviorEventsFunctionCode(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& codeNamespace,
|
||||
@@ -126,6 +127,7 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
*/
|
||||
static gd::String GenerateObjectEventsFunctionCode(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& codeNamespace,
|
||||
@@ -398,9 +400,9 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
* arguments from the rest of the events.
|
||||
*/
|
||||
gd::String GenerateFreeEventsFunctionContext(
|
||||
const std::vector<gd::ParameterMetadata>& parameters,
|
||||
const gd::String& onceTriggersVariable,
|
||||
bool isAsync);
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsFunction &eventsFunction,
|
||||
const gd::String& onceTriggersVariable);
|
||||
|
||||
/**
|
||||
* \brief Generate the "eventsFunctionContext" object that allow a behavior
|
||||
@@ -408,10 +410,10 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
* arguments from the rest of the events.
|
||||
*/
|
||||
gd::String GenerateBehaviorEventsFunctionContext(
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const std::vector<gd::ParameterMetadata>& parameters,
|
||||
const gd::EventsFunction &eventsFunction,
|
||||
const gd::String& onceTriggersVariable,
|
||||
bool isAsync,
|
||||
const gd::String& thisObjectName,
|
||||
const gd::String& thisBehaviorName);
|
||||
|
||||
@@ -421,10 +423,10 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
* arguments from the rest of the events.
|
||||
*/
|
||||
gd::String GenerateObjectEventsFunctionContext(
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const std::vector<gd::ParameterMetadata>& parameters,
|
||||
const gd::EventsFunction &eventsFunction,
|
||||
const gd::String& onceTriggersVariable,
|
||||
bool isAsync,
|
||||
const gd::String& thisObjectName);
|
||||
|
||||
gd::String GenerateEventsFunctionReturn(
|
||||
@@ -443,22 +445,23 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
|
||||
gd::String codeNamespace; ///< Optional namespace for the generated code,
|
||||
///< used when generating events function.
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief Generate the "eventsFunctionContext" object that allow a function
|
||||
* to provides access objects, object creation and access to arguments from
|
||||
* the rest of the events.
|
||||
*/
|
||||
gd::String GenerateEventsFunctionContext(
|
||||
const std::vector<gd::ParameterMetadata>& parameters,
|
||||
const gd::String& onceTriggersVariable,
|
||||
gd::String& objectsGettersMap,
|
||||
gd::String& objectArraysMap,
|
||||
gd::String& behaviorNamesMap,
|
||||
bool isAsync,
|
||||
const gd::String& thisObjectName = "",
|
||||
const gd::String& thisBehaviorName = "");
|
||||
gd::String GenerateEventsFunctionContext(
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsFunctionsContainer &eventsFunctionsContainer,
|
||||
const gd::EventsFunction &eventsFunction,
|
||||
const gd::String &onceTriggersVariable,
|
||||
gd::String &objectsGettersMap,
|
||||
gd::String &objectArraysMap,
|
||||
gd::String &behaviorNamesMap,
|
||||
const gd::String &thisObjectName = "",
|
||||
const gd::String &thisBehaviorName = "");
|
||||
};
|
||||
|
||||
} // namespace gdjs
|
||||
#endif // EVENTSCODEGENERATOR_H
|
||||
|
@@ -6,6 +6,8 @@
|
||||
#include "ObjectCodeGenerator.h"
|
||||
|
||||
#include "EventsCodeGenerator.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
|
||||
namespace gdjs {
|
||||
|
||||
@@ -16,7 +18,7 @@ gd::String ObjectCodeGenerator::doStepPreEventsFunctionName =
|
||||
"doStepPreEvents";
|
||||
|
||||
gd::String ObjectCodeGenerator::GenerateRuntimeObjectCompleteCode(
|
||||
const gd::String& extensionName,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::String& codeNamespace,
|
||||
const std::map<gd::String, gd::String>& objectMethodMangledNames,
|
||||
@@ -26,7 +28,7 @@ gd::String ObjectCodeGenerator::GenerateRuntimeObjectCompleteCode(
|
||||
eventsBasedObject.GetEventsFunctions().GetInternalVector();
|
||||
|
||||
return GenerateRuntimeObjectTemplateCode(
|
||||
extensionName,
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedObject,
|
||||
codeNamespace,
|
||||
[&]() {
|
||||
@@ -72,6 +74,7 @@ gd::String ObjectCodeGenerator::GenerateRuntimeObjectCompleteCode(
|
||||
runtimeObjectMethodsCode +=
|
||||
EventsCodeGenerator::GenerateObjectEventsFunctionCode(
|
||||
project,
|
||||
eventsFunctionsExtension,
|
||||
eventsBasedObject,
|
||||
*eventsFunction,
|
||||
methodCodeNamespace,
|
||||
|
@@ -3,16 +3,18 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDJS_OBJECTCODEGENERATOR_H
|
||||
#define GDJS_OBJECTCODEGENERATOR_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
|
||||
namespace gd {
|
||||
class NamedPropertyDescriptor;
|
||||
class EventsBasedObject;
|
||||
}
|
||||
|
||||
namespace gdjs {
|
||||
@@ -32,7 +34,7 @@ class ObjectCodeGenerator {
|
||||
* object.
|
||||
*/
|
||||
gd::String GenerateRuntimeObjectCompleteCode(
|
||||
const gd::String& extensionName,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::String& codeNamespace,
|
||||
const std::map<gd::String, gd::String>& objectMethodMangledNames,
|
||||
@@ -117,4 +119,3 @@ class ObjectCodeGenerator {
|
||||
};
|
||||
|
||||
} // namespace gdjs
|
||||
#endif // GDJS_OBJECTCODEGENERATOR_H
|
||||
|
@@ -44,19 +44,24 @@ AsyncExtension::AsyncExtension() {
|
||||
parentContext.IsInsideAsync()
|
||||
? "const parentAsyncObjectsList = asyncObjectsList;\n"
|
||||
: "";
|
||||
gd::String asyncObjectsListBuilder =
|
||||
gd::String asyncContextBuilder =
|
||||
parentContext.IsInsideAsync()
|
||||
? "const asyncObjectsList = "
|
||||
"gdjs.LongLivedObjectsList.from(parentAsyncObjectsList);\n"
|
||||
: "const asyncObjectsList = new gdjs.LongLivedObjectsList();\n";
|
||||
|
||||
asyncContextBuilder +=
|
||||
"asyncObjectsList.backupLocalVariablesContainers(" +
|
||||
codeGenerator.GenerateLocalVariablesStackAccessor() + ");\n";
|
||||
|
||||
for (const gd::String &objectNameToBackup :
|
||||
callbackDescriptor.requiredObjects) {
|
||||
if (parentContext.ShouldUseAsyncObjectsList(objectNameToBackup))
|
||||
asyncObjectsListBuilder +=
|
||||
asyncContextBuilder +=
|
||||
"/* Don't save " + objectNameToBackup +
|
||||
" as it will be provided by the parent asyncObjectsList. */\n";
|
||||
else
|
||||
asyncObjectsListBuilder +=
|
||||
asyncContextBuilder +=
|
||||
"for (const obj of " +
|
||||
codeGenerator.GetObjectListName(objectNameToBackup,
|
||||
parentContext) +
|
||||
@@ -66,7 +71,7 @@ AsyncExtension::AsyncExtension() {
|
||||
}
|
||||
|
||||
return "{\n" + parentAsyncObjectsListGetter + "{\n" +
|
||||
asyncObjectsListBuilder + asyncActionCode + "}\n" + "}\n";
|
||||
asyncContextBuilder + asyncActionCode + "}\n" + "}\n";
|
||||
});
|
||||
|
||||
GetAllActions()["BuiltinAsync::ResolveAsyncEventsFunction"].SetFunctionName(
|
||||
|
@@ -230,6 +230,35 @@ BaseObjectExtension::BaseObjectExtension() {
|
||||
GetAllConditions()["PickNearest"].SetFunctionName(
|
||||
"gdjs.evtTools.object.pickNearestObject");
|
||||
|
||||
objectActions["SetNumberObjectVariable"]
|
||||
.SetFunctionName("returnVariable")
|
||||
.SetManipulatedType("number")
|
||||
.SetMutators({
|
||||
{"=", "setNumber"},
|
||||
{"+", "add"},
|
||||
{"-", "sub"},
|
||||
{"*", "mul"},
|
||||
{"/", "div"},
|
||||
});
|
||||
objectActions["SetStringObjectVariable"]
|
||||
.SetFunctionName("returnVariable")
|
||||
.SetManipulatedType("string")
|
||||
.SetMutators({
|
||||
{"=", "setString"},
|
||||
{"+", "concatenate"},
|
||||
});
|
||||
objectActions["SetBooleanObjectVariable"]
|
||||
.SetFunctionName("returnVariable")
|
||||
.SetManipulatedType("boolean")
|
||||
.SetMutators({
|
||||
{"True", "setBoolean(true)"},
|
||||
{"False", "setBoolean(false)"},
|
||||
{"Toggle", "toggle()"},
|
||||
});
|
||||
objectConditions["NumberObjectVariable"].SetFunctionName("getVariableNumber");
|
||||
objectConditions["StringObjectVariable"].SetFunctionName("getVariableString");
|
||||
objectConditions["BooleanObjectVariable"].SetFunctionName("getVariableBoolean");
|
||||
|
||||
objectActions["ModVarObjet"]
|
||||
.SetFunctionName("returnVariable")
|
||||
.SetManipulatedType("number")
|
||||
@@ -257,6 +286,9 @@ BaseObjectExtension::BaseObjectExtension() {
|
||||
objectActions["ObjectVariablePushString"].SetFunctionName("valuePush");
|
||||
objectActions["ObjectVariablePushNumber"].SetFunctionName("valuePush");
|
||||
objectActions["ObjectVariablePushBool"].SetFunctionName("valuePush");
|
||||
objectActions["PushStringToObjectVariable"].SetFunctionName("valuePush");
|
||||
objectActions["PushNumberToObjectVariable"].SetFunctionName("valuePush");
|
||||
objectActions["PushBooleanToObjectVariable"].SetFunctionName("valuePush");
|
||||
objectActions["ObjectVariableRemoveAt"].SetFunctionName("variableRemoveAt");
|
||||
objectConditions["ObjectVariableChildCount"].SetFunctionName(
|
||||
"getVariableChildCount");
|
||||
|
@@ -51,22 +51,20 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
gd::String value1Code =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"number",
|
||||
codeGenerator, context, "number",
|
||||
instruction.GetParameter(0).GetPlainString());
|
||||
|
||||
gd::String operatorString = instruction.GetParameter(1).GetPlainString();
|
||||
gd::String operatorString =
|
||||
instruction.GetParameter(1).GetPlainString();
|
||||
|
||||
gd::String value2Code =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"number",
|
||||
codeGenerator, context, "number",
|
||||
instruction.GetParameter(2).GetPlainString());
|
||||
|
||||
gd::String resultingBoolean =
|
||||
codeGenerator.GenerateUpperScopeBooleanFullName("isConditionTrue", context);
|
||||
codeGenerator.GenerateUpperScopeBooleanFullName("isConditionTrue",
|
||||
context);
|
||||
|
||||
return resultingBoolean + " = " +
|
||||
gd::String(instruction.IsInverted() ? "!" : "") + "(" +
|
||||
@@ -78,27 +76,24 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
.codeExtraInformation = GetAllConditions()["Egal"].codeExtraInformation;
|
||||
|
||||
GetAllConditions()["StrEqual"].SetCustomCodeGenerator(
|
||||
[](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
[](gd::Instruction &instruction, gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
gd::String value1Code =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"string",
|
||||
codeGenerator, context, "string",
|
||||
instruction.GetParameter(0).GetPlainString());
|
||||
|
||||
gd::String operatorString = instruction.GetParameter(1).GetPlainString();
|
||||
gd::String operatorString =
|
||||
instruction.GetParameter(1).GetPlainString();
|
||||
|
||||
gd::String value2Code =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"string",
|
||||
codeGenerator, context, "string",
|
||||
instruction.GetParameter(2).GetPlainString());
|
||||
|
||||
gd::String resultingBoolean =
|
||||
codeGenerator.GenerateUpperScopeBooleanFullName("isConditionTrue", context);
|
||||
codeGenerator.GenerateUpperScopeBooleanFullName("isConditionTrue",
|
||||
context);
|
||||
|
||||
return resultingBoolean + " = " +
|
||||
gd::String(instruction.IsInverted() ? "!" : "") + "(" +
|
||||
@@ -111,43 +106,48 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
GetAllConditions()["StrEqual"].codeExtraInformation;
|
||||
|
||||
GetAllEvents()["BuiltinCommonInstructions::Link"]
|
||||
.SetCodeGenerator([](gd::BaseEvent& event_,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
.SetCodeGenerator([](gd::BaseEvent &event_,
|
||||
gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
return "/*Link should not have any generated code. You probably "
|
||||
"wrongly used a link in events without a layout.*/";
|
||||
})
|
||||
.SetPreprocessing([](gd::BaseEvent& event_,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsList& eventList,
|
||||
.SetPreprocessing([](gd::BaseEvent &event_,
|
||||
gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsList &eventList,
|
||||
unsigned int indexOfTheEventInThisList) {
|
||||
if (!codeGenerator.HasProjectAndLayout()) return;
|
||||
if (!codeGenerator.HasProjectAndLayout())
|
||||
return;
|
||||
|
||||
gd::LinkEvent& event = dynamic_cast<gd::LinkEvent&>(event_);
|
||||
event.ReplaceLinkByLinkedEvents(
|
||||
codeGenerator.GetProject(), eventList, indexOfTheEventInThisList);
|
||||
gd::LinkEvent &event = dynamic_cast<gd::LinkEvent &>(event_);
|
||||
event.ReplaceLinkByLinkedEvents(codeGenerator.GetProject(), eventList,
|
||||
indexOfTheEventInThisList);
|
||||
});
|
||||
|
||||
GetAllEvents()["BuiltinCommonInstructions::Standard"].SetCodeGenerator(
|
||||
[](gd::BaseEvent& event_,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
gd::StandardEvent& event = dynamic_cast<gd::StandardEvent&>(event_);
|
||||
[](gd::BaseEvent &event_, gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
gd::StandardEvent &event = dynamic_cast<gd::StandardEvent &>(event_);
|
||||
|
||||
gd::String localVariablesInitializationCode = "";
|
||||
if (event_.HasVariables()) {
|
||||
GenerateLocalVariablesInitializationCode(
|
||||
event_.GetVariables(), codeGenerator,
|
||||
localVariablesInitializationCode);
|
||||
}
|
||||
|
||||
gd::String conditionsCode = codeGenerator.GenerateConditionsListCode(
|
||||
event.GetConditions(), context);
|
||||
gd::String ifPredicate =
|
||||
event.GetConditions().empty()
|
||||
? ""
|
||||
: codeGenerator.GenerateBooleanFullName(
|
||||
"isConditionTrue",
|
||||
context);
|
||||
gd::String ifPredicate = event.GetConditions().empty()
|
||||
? ""
|
||||
: codeGenerator.GenerateBooleanFullName(
|
||||
"isConditionTrue", context);
|
||||
|
||||
gd::EventsCodeGenerationContext actionsContext;
|
||||
actionsContext.Reuse(context);
|
||||
gd::String actionsCode = codeGenerator.GenerateActionsListCode(
|
||||
event.GetActions(), actionsContext);
|
||||
if (event.HasSubEvents()) // Sub events
|
||||
if (event.HasSubEvents()) // Sub events
|
||||
{
|
||||
actionsCode += "\n{ //Subevents\n";
|
||||
actionsCode += codeGenerator.GenerateEventsListCode(
|
||||
@@ -158,222 +158,209 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
codeGenerator.GenerateObjectsDeclarationCode(actionsContext);
|
||||
|
||||
gd::String outputCode;
|
||||
outputCode += localVariablesInitializationCode;
|
||||
outputCode += conditionsCode;
|
||||
if (!ifPredicate.empty()) outputCode += "if (" + ifPredicate + ") ";
|
||||
if (!ifPredicate.empty())
|
||||
outputCode += "if (" + ifPredicate + ") ";
|
||||
outputCode += "{\n";
|
||||
outputCode += actionsDeclarationsCode;
|
||||
outputCode += actionsCode;
|
||||
outputCode += "}\n";
|
||||
|
||||
if (event_.HasVariables()) {
|
||||
outputCode += codeGenerator.GenerateLocalVariablesStackAccessor() +
|
||||
".pop();\n";
|
||||
}
|
||||
|
||||
return outputCode;
|
||||
});
|
||||
|
||||
GetAllEvents()["BuiltinCommonInstructions::Comment"].SetCodeGenerator(
|
||||
[](gd::BaseEvent& event_,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
[](gd::BaseEvent &event_, gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
// If we do not add a code generator to the comments,
|
||||
// they will be stripped as considered as not implemented by the
|
||||
// platform.
|
||||
return "";
|
||||
});
|
||||
|
||||
GetAllConditions()["BuiltinCommonInstructions::Or"]
|
||||
.SetCustomCodeGenerator(
|
||||
[](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& parentContext) {
|
||||
// Conditions code
|
||||
gd::String conditionsCode;
|
||||
gd::InstructionsList& conditions = instruction.GetSubInstructions();
|
||||
GetAllConditions()["BuiltinCommonInstructions::Or"].SetCustomCodeGenerator(
|
||||
[](gd::Instruction &instruction, gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &parentContext) {
|
||||
// Conditions code
|
||||
gd::String conditionsCode;
|
||||
gd::InstructionsList &conditions = instruction.GetSubInstructions();
|
||||
|
||||
// The Or "return" true by setting the upper boolean to true.
|
||||
// So, it needs to be initialized to false.
|
||||
conditionsCode += codeGenerator.GenerateUpperScopeBooleanFullName(
|
||||
"isConditionTrue", parentContext) +
|
||||
" = false;\n";
|
||||
//"OR" condition must declare objects list, but without picking the
|
||||
// objects from the scene. Lists are either empty or come from a
|
||||
// parent event.
|
||||
set<gd::String> emptyListsNeeded;
|
||||
for (unsigned int cId = 0; cId < conditions.size(); ++cId) {
|
||||
// Each condition inherits the context from the "Or" condition:
|
||||
// For example, two sub conditions using an object called
|
||||
// "MyObject" will both have to declare a "MyObject" object list.
|
||||
gd::EventsCodeGenerationContext context;
|
||||
context.InheritsFrom(parentContext);
|
||||
context.ForbidReuse(); // TODO: This may not be necessary (to be investigated/heavily tested).
|
||||
// The Or "return" true by setting the upper boolean to true.
|
||||
// So, it needs to be initialized to false.
|
||||
conditionsCode += codeGenerator.GenerateUpperScopeBooleanFullName(
|
||||
"isConditionTrue", parentContext) +
|
||||
" = false;\n";
|
||||
//"OR" condition must declare objects list, but without picking the
|
||||
// objects from the scene. Lists are either empty or come from a
|
||||
// parent event.
|
||||
set<gd::String> emptyListsNeeded;
|
||||
for (unsigned int cId = 0; cId < conditions.size(); ++cId) {
|
||||
// Each condition inherits the context from the "Or" condition:
|
||||
// For example, two sub conditions using an object called
|
||||
// "MyObject" will both have to declare a "MyObject" object list.
|
||||
gd::EventsCodeGenerationContext context;
|
||||
context.InheritsFrom(parentContext);
|
||||
context.ForbidReuse(); // TODO: This may not be necessary (to be
|
||||
// investigated/heavily tested).
|
||||
|
||||
gd::String conditionCode = codeGenerator.GenerateConditionCode(
|
||||
conditions[cId],
|
||||
"isConditionTrue",
|
||||
context);
|
||||
gd::String conditionCode = codeGenerator.GenerateConditionCode(
|
||||
conditions[cId], "isConditionTrue", context);
|
||||
|
||||
conditionsCode += "{\n";
|
||||
conditionsCode += "{\n";
|
||||
|
||||
// Create new objects lists and generate condition
|
||||
conditionsCode +=
|
||||
codeGenerator.GenerateObjectsDeclarationCode(context);
|
||||
if (!conditions[cId].GetType().empty())
|
||||
conditionsCode += conditionCode;
|
||||
// Create new objects lists and generate condition
|
||||
conditionsCode +=
|
||||
codeGenerator.GenerateObjectsDeclarationCode(context);
|
||||
if (!conditions[cId].GetType().empty())
|
||||
conditionsCode += conditionCode;
|
||||
|
||||
// If the condition is true : merge all objects picked in the
|
||||
// final object lists.
|
||||
conditionsCode +=
|
||||
"if(" +
|
||||
codeGenerator.GenerateBooleanFullName(
|
||||
"isConditionTrue", context) +
|
||||
") {\n";
|
||||
conditionsCode += " " +
|
||||
codeGenerator.GenerateUpperScopeBooleanFullName(
|
||||
// If the condition is true : merge all objects picked in the
|
||||
// final object lists.
|
||||
conditionsCode += "if(" +
|
||||
codeGenerator.GenerateBooleanFullName(
|
||||
"isConditionTrue", context) +
|
||||
") {\n";
|
||||
conditionsCode += " " +
|
||||
codeGenerator.GenerateUpperScopeBooleanFullName(
|
||||
"isConditionTrue", context) +
|
||||
" = true;\n";
|
||||
std::set<gd::String> objectsListsToBeDeclared =
|
||||
context.GetAllObjectsToBeDeclared();
|
||||
for (set<gd::String>::iterator it = objectsListsToBeDeclared.begin();
|
||||
it != objectsListsToBeDeclared.end(); ++it) {
|
||||
emptyListsNeeded.insert(*it);
|
||||
gd::String objList = codeGenerator.GetObjectListName(*it, context);
|
||||
gd::String finalObjList =
|
||||
codeGenerator.GetCodeNamespaceAccessor() + ManObjListName(*it) +
|
||||
gd::String::From(parentContext.GetContextDepth()) + "_" +
|
||||
gd::String::From(parentContext.GetCurrentConditionDepth()) +
|
||||
"final";
|
||||
conditionsCode += " for (let j = 0, jLen = " + objList +
|
||||
".length; j < jLen ; ++j) {\n";
|
||||
conditionsCode += " if ( " + finalObjList + ".indexOf(" +
|
||||
objList + "[j]) === -1 )\n";
|
||||
conditionsCode +=
|
||||
" " + finalObjList + ".push(" + objList + "[j]);\n";
|
||||
conditionsCode += " }\n";
|
||||
}
|
||||
conditionsCode += "}\n";
|
||||
|
||||
conditionsCode += "}\n";
|
||||
}
|
||||
|
||||
gd::String declarationsCode;
|
||||
|
||||
// Declarations code
|
||||
gd::String codeNamespace = codeGenerator.GetCodeNamespaceAccessor();
|
||||
for (set<gd::String>::iterator it = emptyListsNeeded.begin();
|
||||
it != emptyListsNeeded.end(); ++it) {
|
||||
//"OR" condition must declare objects list, but without getting
|
||||
// the objects from the scene. Lists are either empty or come from
|
||||
// a parent event.
|
||||
parentContext.ObjectsListNeededOrEmptyIfJustDeclared(*it);
|
||||
// We need to duplicate the object lists : The "final" ones will
|
||||
// be filled with objects by conditions, but they will have no
|
||||
// incidence on further conditions, as conditions use "normal"
|
||||
// ones.
|
||||
gd::String finalObjList =
|
||||
codeNamespace + ManObjListName(*it) +
|
||||
gd::String::From(parentContext.GetContextDepth()) + "_" +
|
||||
gd::String::From(parentContext.GetCurrentConditionDepth()) +
|
||||
"final";
|
||||
codeGenerator.AddGlobalDeclaration(finalObjList + " = [];\n");
|
||||
declarationsCode += finalObjList + ".length = 0;\n";
|
||||
}
|
||||
declarationsCode += "let " +
|
||||
codeGenerator.GenerateBooleanFullName(
|
||||
"isConditionTrue", parentContext) +
|
||||
" = false;\n";
|
||||
|
||||
// Generate code
|
||||
gd::String code;
|
||||
code += declarationsCode;
|
||||
code += conditionsCode;
|
||||
|
||||
// When condition is finished, "final" objects lists become the
|
||||
// "normal" ones.
|
||||
code += "{\n";
|
||||
for (set<gd::String>::iterator it = emptyListsNeeded.begin();
|
||||
it != emptyListsNeeded.end(); ++it) {
|
||||
gd::String finalObjList =
|
||||
codeNamespace + ManObjListName(*it) +
|
||||
gd::String::From(parentContext.GetContextDepth()) + "_" +
|
||||
gd::String::From(parentContext.GetCurrentConditionDepth()) +
|
||||
"final";
|
||||
code += "gdjs.copyArray(" + finalObjList + ", " +
|
||||
codeGenerator.GetObjectListName(*it, parentContext) + ");\n";
|
||||
}
|
||||
code += "}\n";
|
||||
|
||||
return code;
|
||||
});
|
||||
|
||||
GetAllConditions()["BuiltinCommonInstructions::And"].SetCustomCodeGenerator(
|
||||
[](gd::Instruction &instruction, gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &parentContext) {
|
||||
gd::String outputCode;
|
||||
|
||||
outputCode += codeGenerator.GenerateConditionsListCode(
|
||||
instruction.GetSubInstructions(), parentContext);
|
||||
|
||||
outputCode += codeGenerator.GenerateUpperScopeBooleanFullName(
|
||||
"isConditionTrue", parentContext) +
|
||||
" = " +
|
||||
codeGenerator.GenerateBooleanFullName("isConditionTrue",
|
||||
parentContext) +
|
||||
";\n";
|
||||
|
||||
return outputCode;
|
||||
});
|
||||
|
||||
GetAllConditions()["BuiltinCommonInstructions::Not"].SetCustomCodeGenerator(
|
||||
[](gd::Instruction &instruction, gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &parentContext) {
|
||||
gd::String outputCode;
|
||||
|
||||
outputCode += codeGenerator.GenerateConditionsListCode(
|
||||
instruction.GetSubInstructions(), parentContext);
|
||||
|
||||
outputCode += codeGenerator.GenerateUpperScopeBooleanFullName(
|
||||
"isConditionTrue", parentContext) +
|
||||
" = !" +
|
||||
codeGenerator.GenerateBooleanFullName("isConditionTrue",
|
||||
parentContext) +
|
||||
";\n";
|
||||
;
|
||||
|
||||
return outputCode;
|
||||
});
|
||||
|
||||
GetAllConditions()["BuiltinCommonInstructions::Once"].SetCustomCodeGenerator(
|
||||
[](gd::Instruction &instruction, gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
size_t uniqueId = codeGenerator.GenerateSingleUsageUniqueIdFor(
|
||||
instruction.GetOriginalInstruction().lock().get());
|
||||
gd::String outputCode = codeGenerator.GenerateUpperScopeBooleanFullName(
|
||||
"isConditionTrue", context) +
|
||||
" = true;\n";
|
||||
std::set<gd::String> objectsListsToBeDeclared =
|
||||
context.GetAllObjectsToBeDeclared();
|
||||
for (set<gd::String>::iterator it =
|
||||
objectsListsToBeDeclared.begin();
|
||||
it != objectsListsToBeDeclared.end();
|
||||
++it) {
|
||||
emptyListsNeeded.insert(*it);
|
||||
gd::String objList =
|
||||
codeGenerator.GetObjectListName(*it, context);
|
||||
gd::String finalObjList =
|
||||
codeGenerator.GetCodeNamespaceAccessor() +
|
||||
ManObjListName(*it) +
|
||||
gd::String::From(parentContext.GetContextDepth()) + "_" +
|
||||
gd::String::From(parentContext.GetCurrentConditionDepth()) +
|
||||
"final";
|
||||
conditionsCode += " for (let j = 0, jLen = " + objList +
|
||||
".length; j < jLen ; ++j) {\n";
|
||||
conditionsCode += " if ( " + finalObjList + ".indexOf(" +
|
||||
objList + "[j]) === -1 )\n";
|
||||
conditionsCode += " " + finalObjList + ".push(" +
|
||||
objList + "[j]);\n";
|
||||
conditionsCode += " }\n";
|
||||
}
|
||||
conditionsCode += "}\n";
|
||||
|
||||
conditionsCode += "}\n";
|
||||
}
|
||||
|
||||
gd::String declarationsCode;
|
||||
|
||||
// Declarations code
|
||||
gd::String codeNamespace = codeGenerator.GetCodeNamespaceAccessor();
|
||||
for (set<gd::String>::iterator it = emptyListsNeeded.begin();
|
||||
it != emptyListsNeeded.end();
|
||||
++it) {
|
||||
//"OR" condition must declare objects list, but without getting
|
||||
// the objects from the scene. Lists are either empty or come from
|
||||
// a parent event.
|
||||
parentContext.ObjectsListNeededOrEmptyIfJustDeclared(*it);
|
||||
// We need to duplicate the object lists : The "final" ones will
|
||||
// be filled with objects by conditions, but they will have no
|
||||
// incidence on further conditions, as conditions use "normal"
|
||||
// ones.
|
||||
gd::String finalObjList =
|
||||
codeNamespace + ManObjListName(*it) +
|
||||
gd::String::From(parentContext.GetContextDepth()) + "_" +
|
||||
gd::String::From(parentContext.GetCurrentConditionDepth()) +
|
||||
"final";
|
||||
codeGenerator.AddGlobalDeclaration(finalObjList + " = [];\n");
|
||||
declarationsCode += finalObjList + ".length = 0;\n";
|
||||
}
|
||||
declarationsCode += "let " +
|
||||
codeGenerator.GenerateBooleanFullName(
|
||||
"isConditionTrue", parentContext) +
|
||||
" = false;\n";
|
||||
|
||||
// Generate code
|
||||
gd::String code;
|
||||
code += declarationsCode;
|
||||
code += conditionsCode;
|
||||
|
||||
// When condition is finished, "final" objects lists become the
|
||||
// "normal" ones.
|
||||
code += "{\n";
|
||||
for (set<gd::String>::iterator it = emptyListsNeeded.begin();
|
||||
it != emptyListsNeeded.end();
|
||||
++it) {
|
||||
gd::String finalObjList =
|
||||
codeNamespace + ManObjListName(*it) +
|
||||
gd::String::From(parentContext.GetContextDepth()) + "_" +
|
||||
gd::String::From(parentContext.GetCurrentConditionDepth()) +
|
||||
"final";
|
||||
code += "gdjs.copyArray(" + finalObjList + ", " +
|
||||
codeGenerator.GetObjectListName(*it, parentContext) +
|
||||
");\n";
|
||||
}
|
||||
code += "}\n";
|
||||
|
||||
return code;
|
||||
});
|
||||
|
||||
GetAllConditions()["BuiltinCommonInstructions::And"]
|
||||
.SetCustomCodeGenerator(
|
||||
[](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& parentContext) {
|
||||
gd::String outputCode;
|
||||
|
||||
outputCode += codeGenerator.GenerateConditionsListCode(
|
||||
instruction.GetSubInstructions(), parentContext);
|
||||
|
||||
outputCode += codeGenerator.GenerateUpperScopeBooleanFullName(
|
||||
"isConditionTrue", parentContext) +
|
||||
" = " +
|
||||
codeGenerator.GenerateBooleanFullName(
|
||||
"isConditionTrue", parentContext) +
|
||||
";\n";
|
||||
|
||||
return outputCode;
|
||||
});
|
||||
|
||||
GetAllConditions()["BuiltinCommonInstructions::Not"]
|
||||
.SetCustomCodeGenerator(
|
||||
[](gd::Instruction &instruction,
|
||||
gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &parentContext) {
|
||||
gd::String outputCode;
|
||||
|
||||
outputCode += codeGenerator.GenerateConditionsListCode(
|
||||
instruction.GetSubInstructions(), parentContext);
|
||||
|
||||
outputCode += codeGenerator.GenerateUpperScopeBooleanFullName(
|
||||
"isConditionTrue", parentContext) +
|
||||
" = !" +
|
||||
codeGenerator.GenerateBooleanFullName(
|
||||
"isConditionTrue", parentContext) +
|
||||
";\n";
|
||||
;
|
||||
|
||||
return outputCode;
|
||||
});
|
||||
|
||||
GetAllConditions()["BuiltinCommonInstructions::Once"]
|
||||
.SetCustomCodeGenerator(
|
||||
[](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
size_t uniqueId = codeGenerator.GenerateSingleUsageUniqueIdFor(
|
||||
instruction.GetOriginalInstruction().lock().get());
|
||||
gd::String outputCode = codeGenerator.GenerateUpperScopeBooleanFullName(
|
||||
"isConditionTrue", context) +
|
||||
" = ";
|
||||
gd::String contextObjectName = codeGenerator.HasProjectAndLayout()
|
||||
? "runtimeScene"
|
||||
: "eventsFunctionContext";
|
||||
outputCode += contextObjectName +
|
||||
".getOnceTriggers().triggerOnce(" +
|
||||
gd::String::From(uniqueId) + ");\n";
|
||||
return outputCode;
|
||||
});
|
||||
" = ";
|
||||
gd::String contextObjectName = codeGenerator.HasProjectAndLayout()
|
||||
? "runtimeScene"
|
||||
: "eventsFunctionContext";
|
||||
outputCode += contextObjectName + ".getOnceTriggers().triggerOnce(" +
|
||||
gd::String::From(uniqueId) + ");\n";
|
||||
return outputCode;
|
||||
});
|
||||
|
||||
GetAllEvents()["BuiltinCommonInstructions::While"].SetCodeGenerator(
|
||||
[](gd::BaseEvent& event_,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& parentContext) {
|
||||
gd::WhileEvent& event = dynamic_cast<gd::WhileEvent&>(event_);
|
||||
[](gd::BaseEvent &event_, gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &parentContext) {
|
||||
gd::WhileEvent &event = dynamic_cast<gd::WhileEvent &>(event_);
|
||||
|
||||
// Prevent code generation if the event is empty, as this would
|
||||
// get the game stuck in a never ending loop.
|
||||
@@ -420,8 +407,8 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
outputCode += "if (" + ifPredicate + ") {\n";
|
||||
outputCode += actionsCode;
|
||||
outputCode += "\n{ //Subevents: \n";
|
||||
// TODO: check (and heavily test) if sub events should be generated before
|
||||
// the call to GenerateObjectsDeclarationCode.
|
||||
// TODO: check (and heavily test) if sub events should be generated
|
||||
// before the call to GenerateObjectsDeclarationCode.
|
||||
outputCode +=
|
||||
codeGenerator.GenerateEventsListCode(event.GetSubEvents(), context);
|
||||
outputCode += "} //Subevents end.\n";
|
||||
@@ -434,12 +421,12 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
});
|
||||
|
||||
GetAllEvents()["BuiltinCommonInstructions::ForEachChildVariable"]
|
||||
.SetCodeGenerator([](gd::BaseEvent& event_,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& parentContext) {
|
||||
.SetCodeGenerator([](gd::BaseEvent &event_,
|
||||
gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &parentContext) {
|
||||
gd::String outputCode;
|
||||
gd::ForEachChildVariableEvent& event =
|
||||
dynamic_cast<gd::ForEachChildVariableEvent&>(event_);
|
||||
gd::ForEachChildVariableEvent &event =
|
||||
dynamic_cast<gd::ForEachChildVariableEvent &>(event_);
|
||||
|
||||
// Context is "reset" each time the event is repeated (i.e. objects are
|
||||
// picked again)
|
||||
@@ -452,9 +439,9 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
gd::String actionsCode =
|
||||
codeGenerator.GenerateActionsListCode(event.GetActions(), context);
|
||||
gd::String ifPredicate = event.GetConditions().empty()
|
||||
? "true"
|
||||
: codeGenerator.GenerateBooleanFullName(
|
||||
"isConditionTrue", context);
|
||||
? "true"
|
||||
: codeGenerator.GenerateBooleanFullName(
|
||||
"isConditionTrue", context);
|
||||
|
||||
// Prepare object declaration and sub events
|
||||
gd::String subevents =
|
||||
@@ -553,9 +540,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
.FindAndReplace(
|
||||
"$VALUE_ITERATOR_VARIABLE_ACCESSOR",
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"scenevar",
|
||||
codeGenerator, context, "scenevar",
|
||||
event.GetValueIteratorVariableName()))
|
||||
.FindAndReplace("$VALUE_ITERATOR_REFERENCE",
|
||||
iteratorReferenceVariableName);
|
||||
@@ -570,9 +555,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
.FindAndReplace(
|
||||
"$KEY_ITERATOR_VARIABLE_ACCESSOR",
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"scenevar",
|
||||
codeGenerator, context, "scenevar",
|
||||
event.GetKeyIteratorVariableName()))
|
||||
.FindAndReplace("$KEY_ITERATOR_REFERENCE",
|
||||
iteratorReferenceVariableName);
|
||||
@@ -585,18 +568,15 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
iterableReferenceVariableName)
|
||||
.FindAndReplace("$ITERABLE_VARIABLE_ACCESSOR",
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"scenevar",
|
||||
codeGenerator, context, "scenevar",
|
||||
event.GetIterableVariableName()));
|
||||
});
|
||||
|
||||
GetAllEvents()["BuiltinCommonInstructions::Repeat"].SetCodeGenerator(
|
||||
[](gd::BaseEvent& event_,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& parentContext) {
|
||||
[](gd::BaseEvent &event_, gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &parentContext) {
|
||||
gd::String outputCode;
|
||||
gd::RepeatEvent& event = dynamic_cast<gd::RepeatEvent&>(event_);
|
||||
gd::RepeatEvent &event = dynamic_cast<gd::RepeatEvent &>(event_);
|
||||
|
||||
gd::String repeatNumberExpression = event.GetRepeatExpression();
|
||||
|
||||
@@ -632,7 +612,8 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
"repeatCount" + gd::String::From(context.GetContextDepth());
|
||||
gd::String repeatIndexVar =
|
||||
"repeatIndex" + gd::String::From(context.GetContextDepth());
|
||||
outputCode += "const " + repeatCountVar + " = " + repeatCountCode + ";\n";
|
||||
outputCode +=
|
||||
"const " + repeatCountVar + " = " + repeatCountCode + ";\n";
|
||||
outputCode += "for (let " + repeatIndexVar + " = 0;" + repeatIndexVar +
|
||||
" < " + repeatCountVar + ";++" + repeatIndexVar + ") {\n";
|
||||
outputCode += objectDeclaration;
|
||||
@@ -653,16 +634,17 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
});
|
||||
|
||||
GetAllEvents()["BuiltinCommonInstructions::ForEach"].SetCodeGenerator(
|
||||
[](gd::BaseEvent& event_,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& parentContext) {
|
||||
[](gd::BaseEvent &event_, gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &parentContext) {
|
||||
gd::String outputCode;
|
||||
gd::ForEachEvent& event = dynamic_cast<gd::ForEachEvent&>(event_);
|
||||
gd::ForEachEvent &event = dynamic_cast<gd::ForEachEvent &>(event_);
|
||||
|
||||
std::vector<gd::String> realObjects = codeGenerator.GetObjectsContainersList().ExpandObjectName(
|
||||
event.GetObjectToPick(), parentContext.GetCurrentObject());
|
||||
std::vector<gd::String> realObjects =
|
||||
codeGenerator.GetObjectsContainersList().ExpandObjectName(
|
||||
event.GetObjectToPick(), parentContext.GetCurrentObject());
|
||||
|
||||
if (realObjects.empty()) return gd::String("");
|
||||
if (realObjects.empty())
|
||||
return gd::String("");
|
||||
for (unsigned int i = 0; i < realObjects.size(); ++i)
|
||||
parentContext.ObjectsListNeeded(realObjects[i]);
|
||||
|
||||
@@ -670,7 +652,8 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
// picked again)
|
||||
gd::EventsCodeGenerationContext context;
|
||||
context.InheritsFrom(parentContext);
|
||||
context.ForbidReuse(); // TODO: This may not be necessary (to be investigated/heavily tested).
|
||||
context.ForbidReuse(); // TODO: This may not be necessary (to be
|
||||
// investigated/heavily tested).
|
||||
|
||||
for (unsigned int i = 0; i < realObjects.size(); ++i)
|
||||
context.EmptyObjectsListNeeded(realObjects[i]);
|
||||
@@ -706,8 +689,8 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
codeGenerator.AddGlobalDeclaration(forEachObjectsList + " = [];\n");
|
||||
|
||||
if (realObjects.size() !=
|
||||
1) //(We write a slightly more simple ( and optimized ) output code
|
||||
// when only one object list is used.)
|
||||
1) //(We write a slightly more simple ( and optimized ) output code
|
||||
// when only one object list is used.)
|
||||
{
|
||||
outputCode += forEachTotalCountVar + " = 0;\n";
|
||||
outputCode += forEachObjectsList + ".length = 0;\n";
|
||||
@@ -735,8 +718,8 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
|
||||
// For loop declaration
|
||||
if (realObjects.size() ==
|
||||
1) // We write a slightly more simple ( and optimized ) output code
|
||||
// when only one object list is used.
|
||||
1) // We write a slightly more simple ( and optimized ) output code
|
||||
// when only one object list is used.
|
||||
outputCode +=
|
||||
"for (" + forEachIndexVar + " = 0;" + forEachIndexVar + " < " +
|
||||
codeGenerator.GetObjectListName(realObjects[0], parentContext) +
|
||||
@@ -775,11 +758,13 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
gd::String::From(j) + "_" +
|
||||
gd::String::From(context.GetContextDepth());
|
||||
|
||||
if (j != 0) count += "+";
|
||||
if (j != 0)
|
||||
count += "+";
|
||||
count += forEachCountVar;
|
||||
}
|
||||
|
||||
if (i != 0) outputCode += "else ";
|
||||
if (i != 0)
|
||||
outputCode += "else ";
|
||||
outputCode += "if (" + forEachIndexVar + " < " + count + ") {\n";
|
||||
outputCode +=
|
||||
" " +
|
||||
@@ -799,17 +784,16 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
}
|
||||
outputCode += "}\n";
|
||||
|
||||
outputCode += "}\n"; // End of for loop
|
||||
outputCode += "}\n"; // End of for loop
|
||||
|
||||
return outputCode;
|
||||
});
|
||||
|
||||
GetAllEvents()["BuiltinCommonInstructions::Group"].SetCodeGenerator(
|
||||
[](gd::BaseEvent& event_,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
[](gd::BaseEvent &event_, gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
gd::String outputCode;
|
||||
gd::GroupEvent& event = dynamic_cast<gd::GroupEvent&>(event_);
|
||||
gd::GroupEvent &event = dynamic_cast<gd::GroupEvent &>(event_);
|
||||
|
||||
outputCode +=
|
||||
codeGenerator.GenerateProfilerSectionBegin(event.GetName());
|
||||
@@ -820,16 +804,14 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
return outputCode;
|
||||
});
|
||||
|
||||
AddEvent("JsCode",
|
||||
_("Javascript code"),
|
||||
_("Insert some Javascript code into events"),
|
||||
"",
|
||||
AddEvent("JsCode", _("Javascript code"),
|
||||
_("Insert some Javascript code into events"), "",
|
||||
"res/source_cpp16.png",
|
||||
std::shared_ptr<gd::BaseEvent>(new JsCodeEvent))
|
||||
.SetCodeGenerator([](gd::BaseEvent& event_,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& parentContext) {
|
||||
JsCodeEvent& event = dynamic_cast<JsCodeEvent&>(event_);
|
||||
.SetCodeGenerator([](gd::BaseEvent &event_,
|
||||
gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &parentContext) {
|
||||
JsCodeEvent &event = dynamic_cast<JsCodeEvent &>(event_);
|
||||
|
||||
gd::String functionName = codeGenerator.GetCodeNamespaceAccessor() +
|
||||
"userFunc" + gd::String::From(&event);
|
||||
@@ -841,15 +823,14 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
}
|
||||
if (!codeGenerator.HasProjectAndLayout()) {
|
||||
functionParameters += ", eventsFunctionContext";
|
||||
callArguments +=
|
||||
", typeof eventsFunctionContext !== \'undefined\' ? "
|
||||
"eventsFunctionContext : undefined";
|
||||
callArguments += ", typeof eventsFunctionContext !== \'undefined\' ? "
|
||||
"eventsFunctionContext : undefined";
|
||||
}
|
||||
|
||||
// Generate the function code
|
||||
gd::String functionCode;
|
||||
functionCode +=
|
||||
functionName + " = function GDJSInlineCode(" + functionParameters + ") {\n";
|
||||
functionCode += functionName + " = function GDJSInlineCode(" +
|
||||
functionParameters + ") {\n";
|
||||
functionCode += event.IsUseStrict() ? "\"use strict\";\n" : "";
|
||||
functionCode += event.GetInlineCode();
|
||||
functionCode += "\n};\n";
|
||||
@@ -858,8 +839,10 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
// Generate the code to call the function
|
||||
gd::String callingCode;
|
||||
if (!event.GetParameterObjects().empty()) {
|
||||
std::vector<gd::String> realObjects = codeGenerator.GetObjectsContainersList().ExpandObjectName(
|
||||
event.GetParameterObjects(), parentContext.GetCurrentObject());
|
||||
std::vector<gd::String> realObjects =
|
||||
codeGenerator.GetObjectsContainersList().ExpandObjectName(
|
||||
event.GetParameterObjects(),
|
||||
parentContext.GetCurrentObject());
|
||||
|
||||
callingCode += "var objects = [];\n";
|
||||
for (unsigned int i = 0; i < realObjects.size(); ++i) {
|
||||
@@ -876,4 +859,59 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace gdjs
|
||||
void CommonInstructionsExtension::GenerateLocalVariablesInitializationCode(
|
||||
gd::VariablesContainer &variablesContainer,
|
||||
gd::EventsCodeGenerator &codeGenerator, gd::String &code) {
|
||||
code += "{\n";
|
||||
code += "const variables = new gdjs.VariablesContainer();\n";
|
||||
for (std::size_t i = 0; i < variablesContainer.Count(); i++) {
|
||||
auto &variable = variablesContainer.Get(i);
|
||||
code += "{\n";
|
||||
GenerateLocalVariableInitializationCode(variable, code);
|
||||
code += "variables._declare(" +
|
||||
EventsCodeGenerator::ConvertToStringExplicit(
|
||||
variablesContainer.GetNameAt(i)) +
|
||||
", variable);\n";
|
||||
code += "}\n";
|
||||
}
|
||||
code += codeGenerator.GenerateLocalVariablesStackAccessor() +
|
||||
".push(variables);\n";
|
||||
code += "}\n";
|
||||
}
|
||||
|
||||
void CommonInstructionsExtension::GenerateLocalVariableInitializationCode(
|
||||
gd::Variable &variable, gd::String &code, std::size_t depth) {
|
||||
const gd::String variableCodeName =
|
||||
"variable" + (depth == 0 ? "" : gd::String::From(depth));
|
||||
code += "const " + variableCodeName + " = new gdjs.Variable();\n";
|
||||
if (variable.GetType() == gd::Variable::Number) {
|
||||
code += variableCodeName + ".setNumber(" +
|
||||
gd::String::From(variable.GetValue()) + ");\n";
|
||||
} else if (variable.GetType() == gd::Variable::Boolean) {
|
||||
gd::String value = variable.GetBool() ? "true" : "false";
|
||||
code += variableCodeName + ".setBoolean(" + value + ");\n";
|
||||
} else if (variable.GetType() == gd::Variable::String) {
|
||||
code += variableCodeName + ".setString(" +
|
||||
EventsCodeGenerator::ConvertToStringExplicit(variable.GetString()) +
|
||||
");\n";
|
||||
} else if (variable.GetType() == gd::Variable::Structure ||
|
||||
variable.GetType() == gd::Variable::Array) {
|
||||
const auto &childrenNames = variable.GetAllChildrenNames();
|
||||
for (std::size_t i = 0; i < variable.GetChildrenCount(); i++) {
|
||||
auto &child = variable.GetAtIndex(i);
|
||||
|
||||
code += "{\n";
|
||||
GenerateLocalVariableInitializationCode(child, code, depth + 1);
|
||||
auto childCodeName = "variable" + gd::String::From(depth + 1);
|
||||
code += variableCodeName + ".addChild(" +
|
||||
EventsCodeGenerator::ConvertToStringExplicit(childrenNames[i]) +
|
||||
", " + childCodeName + ");\n";
|
||||
code += "}\n";
|
||||
}
|
||||
if (variable.GetType() == gd::Variable::Array) {
|
||||
code += variableCodeName + ".castTo('array');\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gdjs
|
||||
|
@@ -3,10 +3,13 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef COMMONINSTRUCTIONSEXTENSION_H
|
||||
#define COMMONINSTRUCTIONSEXTENSION_H
|
||||
#pragma once
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
|
||||
namespace gd {
|
||||
class Variable;
|
||||
class VariablesContainer;
|
||||
}
|
||||
namespace gdjs {
|
||||
|
||||
/**
|
||||
@@ -18,7 +21,13 @@ class CommonInstructionsExtension : public gd::PlatformExtension {
|
||||
public:
|
||||
CommonInstructionsExtension();
|
||||
virtual ~CommonInstructionsExtension(){};
|
||||
private:
|
||||
static void GenerateLocalVariablesInitializationCode(
|
||||
gd::VariablesContainer &variablesContainer,
|
||||
gd::EventsCodeGenerator &codeGenerator, gd::String &code);
|
||||
static void GenerateLocalVariableInitializationCode(gd::Variable &variable,
|
||||
gd::String &code,
|
||||
std::size_t depth = 0);
|
||||
};
|
||||
|
||||
} // namespace gdjs
|
||||
#endif // COMMONINSTRUCTIONSEXTENSION_H
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include "GDCore/Events/CodeGeneration/ExpressionCodeGenerator.h"
|
||||
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableNameFinder.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
@@ -22,6 +23,147 @@ namespace gdjs {
|
||||
VariablesExtension::VariablesExtension() {
|
||||
gd::BuiltinExtensionsImplementer::ImplementsVariablesExtension(*this);
|
||||
|
||||
GetAllConditions()["NumberVariable"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableNumber");
|
||||
GetAllConditions()["StringVariable"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableString");
|
||||
GetAllConditions()["BooleanVariable"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableBoolean");
|
||||
|
||||
GetAllStrExpressions()["VariableFirstString"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getFirstVariableString");
|
||||
GetAllExpressions()["VariableFirstNumber"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getFirstVariableNumber");
|
||||
GetAllStrExpressions()["VariableLastString"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getLastVariableString");
|
||||
GetAllExpressions()["VariableLastNumber"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getLastVariableNumber");
|
||||
|
||||
GetAllExpressions()["VariableChildCount"].SetCustomCodeGenerator(
|
||||
[](const std::vector<gd::Expression> ¶meters, gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
auto &variableExpression = parameters[0];
|
||||
const auto variableName =
|
||||
gd::ExpressionVariableNameFinder::GetVariableName(
|
||||
*variableExpression.GetRootNode());
|
||||
|
||||
// This expression used to be declared with a scenevar parameter.
|
||||
gd::String variableParameterType =
|
||||
codeGenerator.GetProjectScopedContainers()
|
||||
.GetVariablesContainersList()
|
||||
.Has(variableName)
|
||||
? "variable"
|
||||
: "scenevar";
|
||||
|
||||
gd::String varGetter =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, variableParameterType,
|
||||
variableExpression.GetPlainString(), "", "AllowUndeclaredVariable");
|
||||
|
||||
return "gdjs.evtTools.variable.getVariableChildCount(" + varGetter + ")";
|
||||
});
|
||||
GetAllConditions()["VariableChildCount"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableChildCount");
|
||||
GetAllConditions()["VariableChildExists2"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.variableChildExists");
|
||||
GetAllActions()["RemoveVariableChild"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.variableRemoveChild");
|
||||
GetAllActions()["ClearVariableChildren"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.variableClearChildren");
|
||||
|
||||
GetAllActions()["PushVariable"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.variablePushCopy");
|
||||
GetAllActions()["PushString"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.valuePush");
|
||||
GetAllActions()["PushNumber"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.valuePush");
|
||||
GetAllActions()["PushBoolean"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.valuePush");
|
||||
GetAllActions()["RemoveVariableAt"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.variableRemoveAt");
|
||||
|
||||
GetAllActions()["SetBooleanVariable"].SetCustomCodeGenerator(
|
||||
[](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
gd::String varGetter =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"variable",
|
||||
instruction.GetParameters()[0].GetPlainString());
|
||||
|
||||
gd::String op = instruction.GetParameters()[1].GetPlainString();
|
||||
if (op == "True")
|
||||
return varGetter + ".setBoolean(true);\n";
|
||||
else if (op == "False")
|
||||
return varGetter + ".setBoolean(false);\n";
|
||||
else if (op == "Toggle")
|
||||
return "gdjs.evtTools.variable.toggleVariableBoolean(" + varGetter + ");\n";
|
||||
|
||||
return gd::String("");
|
||||
});
|
||||
|
||||
GetAllActions()["SetNumberVariable"].SetCustomCodeGenerator(
|
||||
[](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
gd::String expressionCode =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"number",
|
||||
instruction.GetParameters()[2].GetPlainString());
|
||||
gd::String varGetter =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"variable",
|
||||
instruction.GetParameters()[0].GetPlainString());
|
||||
|
||||
gd::String op = instruction.GetParameters()[1].GetPlainString();
|
||||
if (op == "=")
|
||||
return varGetter + ".setNumber(" + expressionCode + ");\n";
|
||||
else if (op == "+")
|
||||
return varGetter + ".add(" + expressionCode + ");\n";
|
||||
else if (op == "-")
|
||||
return varGetter + ".sub(" + expressionCode + ");\n";
|
||||
else if (op == "*")
|
||||
return varGetter + ".mul(" + expressionCode + ");\n";
|
||||
else if (op == "/")
|
||||
return varGetter + ".div(" + expressionCode + ");\n";
|
||||
|
||||
return gd::String("");
|
||||
});
|
||||
|
||||
GetAllActions()["SetStringVariable"].SetCustomCodeGenerator(
|
||||
[](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
gd::String expressionCode =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"string",
|
||||
instruction.GetParameters()[2].GetPlainString());
|
||||
gd::String varGetter =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"variable",
|
||||
instruction.GetParameters()[0].GetPlainString());
|
||||
|
||||
gd::String op = instruction.GetParameters()[1].GetPlainString();
|
||||
if (op == "=")
|
||||
return varGetter + ".setString(" + expressionCode + ");\n";
|
||||
else if (op == "+")
|
||||
return varGetter + ".concatenateString(" + expressionCode + ");\n";
|
||||
|
||||
return gd::String("");
|
||||
});
|
||||
|
||||
// Legacy instructions
|
||||
|
||||
GetAllConditions()["VarScene"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableNumber");
|
||||
GetAllConditions()["VarSceneTxt"].SetFunctionName(
|
||||
@@ -35,8 +177,6 @@ VariablesExtension::VariablesExtension() {
|
||||
GetAllConditions()["GlobalVariableAsBoolean"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableBoolean");
|
||||
|
||||
GetAllExpressions()["VariableChildCount"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableChildCount");
|
||||
GetAllExpressions()["GlobalVariableChildCount"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableChildCount");
|
||||
|
||||
|
@@ -597,6 +597,7 @@ namespace gdjs {
|
||||
*/
|
||||
export class LongLivedObjectsList {
|
||||
private objectsLists = new Map<string, Array<RuntimeObject>>();
|
||||
private localVariablesContainers: Array<gdjs.VariablesContainer> = [];
|
||||
private callbacks = new Map<RuntimeObject, () => void>();
|
||||
private parent: LongLivedObjectsList | null = null;
|
||||
|
||||
@@ -651,5 +652,17 @@ namespace gdjs {
|
||||
);
|
||||
this.callbacks.delete(runtimeObject);
|
||||
}
|
||||
|
||||
restoreLocalVariablesContainers(
|
||||
variablesContainers: Array<gdjs.VariablesContainer>
|
||||
): void {
|
||||
gdjs.copyArray(this.localVariablesContainers, variablesContainers);
|
||||
}
|
||||
|
||||
backupLocalVariablesContainers(
|
||||
variablesContainers: Array<gdjs.VariablesContainer>
|
||||
): void {
|
||||
gdjs.copyArray(variablesContainers, this.localVariablesContainers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -75,7 +75,9 @@ namespace gdjs {
|
||||
export class RuntimeGame {
|
||||
_resourcesLoader: gdjs.ResourceLoader;
|
||||
_variables: VariablesContainer;
|
||||
_variablesByExtensionName: Map<string, gdjs.VariablesContainer>;
|
||||
_data: ProjectData;
|
||||
_sceneAndExtensionsData: Array<SceneAndExtensionsData> = [];
|
||||
_eventsBasedObjectDatas: Map<String, EventsBasedObjectData>;
|
||||
_effectsManager: EffectsManager;
|
||||
_maxFPS: integer;
|
||||
@@ -144,7 +146,20 @@ namespace gdjs {
|
||||
constructor(data: ProjectData, options?: RuntimeGameOptions) {
|
||||
this._options = options || {};
|
||||
this._variables = new gdjs.VariablesContainer(data.variables);
|
||||
this._variablesByExtensionName = new Map<
|
||||
string,
|
||||
gdjs.VariablesContainer
|
||||
>();
|
||||
for (const extensionData of data.eventsFunctionsExtensions) {
|
||||
if (extensionData.globalVariables.length > 0) {
|
||||
this._variablesByExtensionName.set(
|
||||
extensionData.name,
|
||||
new gdjs.VariablesContainer(extensionData.globalVariables)
|
||||
);
|
||||
}
|
||||
}
|
||||
this._data = data;
|
||||
this._updateSceneAndExtensionsData();
|
||||
|
||||
this._resourcesLoader = new gdjs.ResourceLoader(
|
||||
this,
|
||||
@@ -230,6 +245,7 @@ namespace gdjs {
|
||||
*/
|
||||
setProjectData(projectData: ProjectData): void {
|
||||
this._data = projectData;
|
||||
this._updateSceneAndExtensionsData();
|
||||
this._resourcesLoader.setResources(
|
||||
projectData.resources.resources,
|
||||
getGlobalResourceNames(projectData),
|
||||
@@ -237,6 +253,16 @@ namespace gdjs {
|
||||
);
|
||||
}
|
||||
|
||||
private _updateSceneAndExtensionsData(): void {
|
||||
const usedExtensionsWithVariablesData = this._data.eventsFunctionsExtensions.filter(
|
||||
(extensionData) => extensionData.sceneVariables.length > 0
|
||||
);
|
||||
this._sceneAndExtensionsData = this._data.layouts.map((sceneData) => ({
|
||||
sceneData,
|
||||
usedExtensionsWithVariablesData,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the additional options passed to the RuntimeGame when created.
|
||||
* @returns The additional options, if any.
|
||||
@@ -257,6 +283,15 @@ namespace gdjs {
|
||||
return this._variables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extension's global variables.
|
||||
* @param extensionName The extension name.
|
||||
* @returns The extension's global variables.
|
||||
*/
|
||||
getVariablesForExtension(extensionName: string) {
|
||||
return this._variablesByExtensionName.get(extensionName) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the gdjs.SoundManager of the RuntimeGame.
|
||||
* @return The sound manager.
|
||||
@@ -368,19 +403,18 @@ namespace gdjs {
|
||||
* @param sceneName The name of the scene. If not defined, the first scene will be returned.
|
||||
* @return The data associated to the scene.
|
||||
*/
|
||||
getSceneData(sceneName?: string): LayoutData | null {
|
||||
let scene: LayoutData | null = null;
|
||||
getSceneData(sceneName?: string): SceneAndExtensionsData | null {
|
||||
for (let i = 0, len = this._data.layouts.length; i < len; ++i) {
|
||||
const sceneData = this._data.layouts[i];
|
||||
if (sceneName === undefined || sceneData.name === sceneName) {
|
||||
scene = sceneData;
|
||||
break;
|
||||
const sceneAndExtensionsData = this._sceneAndExtensionsData[i];
|
||||
if (
|
||||
sceneName === undefined ||
|
||||
sceneAndExtensionsData.sceneData.name === sceneName
|
||||
) {
|
||||
return sceneAndExtensionsData;
|
||||
}
|
||||
}
|
||||
if (scene === null) {
|
||||
logger.error('The game has no scene called "' + sceneName + '"');
|
||||
}
|
||||
return scene;
|
||||
logger.error('The game has no scene called "' + sceneName + '"');
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -390,15 +424,13 @@ namespace gdjs {
|
||||
* @return true if the scene exists. If sceneName is undefined, true if the game has a scene.
|
||||
*/
|
||||
hasScene(sceneName?: string): boolean {
|
||||
let isTrue = false;
|
||||
for (let i = 0, len = this._data.layouts.length; i < len; ++i) {
|
||||
const sceneData = this._data.layouts[i];
|
||||
if (sceneName === undefined || sceneData.name == sceneName) {
|
||||
isTrue = true;
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return isTrue;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -16,6 +16,7 @@ namespace gdjs {
|
||||
_renderer: RuntimeSceneRenderer;
|
||||
_debuggerRenderer: gdjs.DebuggerRenderer;
|
||||
_variables: gdjs.VariablesContainer;
|
||||
_variablesByExtensionName: Map<string, gdjs.VariablesContainer>;
|
||||
_runtimeGame: gdjs.RuntimeGame;
|
||||
_lastId: integer = 0;
|
||||
_name: string = '';
|
||||
@@ -52,6 +53,10 @@ namespace gdjs {
|
||||
super();
|
||||
this._runtimeGame = runtimeGame;
|
||||
this._variables = new gdjs.VariablesContainer();
|
||||
this._variablesByExtensionName = new Map<
|
||||
string,
|
||||
gdjs.VariablesContainer
|
||||
>();
|
||||
this._timeManager = new gdjs.TimeManager();
|
||||
this._onceTriggers = new gdjs.OnceTriggers();
|
||||
this._requestedChange = SceneChangeRequest.CONTINUE;
|
||||
@@ -111,11 +116,15 @@ namespace gdjs {
|
||||
* @param sceneData An object containing the scene data.
|
||||
* @see gdjs.RuntimeGame#getSceneData
|
||||
*/
|
||||
loadFromScene(sceneData: LayoutData | null) {
|
||||
if (!sceneData) {
|
||||
loadFromScene(sceneAndExtensionsData: SceneAndExtensionsData | null) {
|
||||
if (!sceneAndExtensionsData) {
|
||||
logger.error('loadFromScene was called without a scene');
|
||||
return;
|
||||
}
|
||||
const {
|
||||
sceneData,
|
||||
usedExtensionsWithVariablesData,
|
||||
} = sceneAndExtensionsData;
|
||||
|
||||
if (this._isLoaded) {
|
||||
this.unloadScene();
|
||||
@@ -133,8 +142,14 @@ namespace gdjs {
|
||||
this.addLayer(sceneData.layers[i]);
|
||||
}
|
||||
|
||||
//Load variables
|
||||
// Load variables
|
||||
this._variables = new gdjs.VariablesContainer(sceneData.variables);
|
||||
for (const extensionData of usedExtensionsWithVariablesData) {
|
||||
this._variablesByExtensionName.set(
|
||||
extensionData.name,
|
||||
new gdjs.VariablesContainer(extensionData.sceneVariables)
|
||||
);
|
||||
}
|
||||
|
||||
//Cache the initial shared data of the behaviors
|
||||
for (
|
||||
@@ -290,6 +305,10 @@ namespace gdjs {
|
||||
// ensuring that all memory related to the RuntimeScene is released immediately.
|
||||
super._destroy();
|
||||
this._variables = new gdjs.VariablesContainer();
|
||||
this._variablesByExtensionName = new Map<
|
||||
string,
|
||||
gdjs.VariablesContainer
|
||||
>();
|
||||
this._initialBehaviorSharedData = new Hashtable();
|
||||
this._eventsFunction = null;
|
||||
this._lastId = 0;
|
||||
@@ -624,6 +643,15 @@ namespace gdjs {
|
||||
return this._variables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extension's variables for this scene.
|
||||
* @param extensionName The extension name.
|
||||
* @returns The extension's variables for this scene.
|
||||
*/
|
||||
getVariablesForExtension(extensionName: string) {
|
||||
return this._variablesByExtensionName.get(extensionName) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TimeManager of the scene.
|
||||
* @return The gdjs.TimeManager of the scene.
|
||||
|
12
GDJS/Runtime/types/project-data.d.ts
vendored
12
GDJS/Runtime/types/project-data.d.ts
vendored
@@ -20,6 +20,11 @@ declare interface ProjectData {
|
||||
eventsFunctionsExtensions: EventsFunctionsExtensionData[];
|
||||
}
|
||||
|
||||
declare interface EventsFunctionsVariablesData {
|
||||
name: string;
|
||||
variables: RootVariableData[];
|
||||
}
|
||||
|
||||
/** Object containing initial properties for all objects extending {@link gdjs.RuntimeObject}. */
|
||||
declare type ObjectData = {
|
||||
/** The name of the object. During the game, objects can be queried by their name (see {@link gdjs.RuntimeScene.prototype.getObjects} for example). */
|
||||
@@ -90,6 +95,13 @@ declare interface LayoutData {
|
||||
declare interface EventsFunctionsExtensionData {
|
||||
name: string;
|
||||
eventsBasedObjects: EventsBasedObjectData[];
|
||||
globalVariables: RootVariableData[];
|
||||
sceneVariables: RootVariableData[];
|
||||
}
|
||||
|
||||
declare interface SceneAndExtensionsData {
|
||||
sceneData: LayoutData;
|
||||
usedExtensionsWithVariablesData: EventsFunctionsExtensionData[];
|
||||
}
|
||||
|
||||
declare interface EventsBasedObjectData {
|
||||
|
@@ -449,6 +449,13 @@ namespace gdjs {
|
||||
this._bool = !!newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the value of the variable, considered as a boolean.
|
||||
*/
|
||||
toggle() {
|
||||
this.setBoolean(!this.getAsBoolean());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the primitive value using the setter of the current type.
|
||||
* @param newValue The primitive value of the variable.
|
||||
|
@@ -86,6 +86,18 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Declare a new variable.
|
||||
* This should only be used by generated code.
|
||||
*
|
||||
* @param name Variable name
|
||||
* @param newVariable The variable to be declared
|
||||
*/
|
||||
_declare(name: string, newVariable: gdjs.Variable): void {
|
||||
this._variables.put(name, newVariable);
|
||||
this._variablesArray.push(newVariable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new variable.
|
||||
* This can be costly, don't use in performance sensitive paths.
|
||||
@@ -205,6 +217,9 @@ namespace gdjs {
|
||||
add: function () {
|
||||
return;
|
||||
},
|
||||
_declare: function () {
|
||||
return;
|
||||
},
|
||||
initFrom: function () {
|
||||
return;
|
||||
},
|
||||
@@ -241,6 +256,7 @@ namespace gdjs {
|
||||
return true;
|
||||
},
|
||||
setValue: () => {},
|
||||
toggle: () => {},
|
||||
getValue: () => 0,
|
||||
getChild: () => gdjs.VariablesContainer.badVariable,
|
||||
getChildAt: () => gdjs.VariablesContainer.badVariable,
|
||||
|
@@ -113,6 +113,8 @@ gdjs.getPixiRuntimeGameWithAssets = () => {
|
||||
],
|
||||
},
|
||||
],
|
||||
sceneVariables: [],
|
||||
globalVariables: [],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
4
GDJS/tests/tests/effects.js
vendored
4
GDJS/tests/tests/effects.js
vendored
@@ -67,7 +67,7 @@ describe('gdjs.EffectsManager', () => {
|
||||
|
||||
it('can add effects on a runtime layer', () => {
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
runtimeScene.loadFromScene({sceneData: {
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
@@ -107,7 +107,7 @@ describe('gdjs.EffectsManager', () => {
|
||||
objects: [],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
});
|
||||
}, usedExtensionsWithVariablesData: []});
|
||||
|
||||
const runtimeLayer = runtimeScene.getLayer('');
|
||||
|
||||
|
@@ -5,13 +5,13 @@
|
||||
describe('gdjs.InputManager', () => {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
runtimeScene.loadFromScene({sceneData: {
|
||||
layers: [{ name: '', visibility: true, effects: [] }],
|
||||
variables: [],
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
});
|
||||
}, usedExtensionsWithVariablesData: []});
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
const inputTools = gdjs.evtTools.input;
|
||||
|
||||
@@ -351,13 +351,13 @@ describe('gdjs.InputManager', () => {
|
||||
describe('gdjs.RuntimeObject.cursorOnObject', () => {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
var runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
runtimeScene.loadFromScene({sceneData: {
|
||||
layers: [{ name: '', visibility: true, effects: [] }],
|
||||
variables: [],
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
});
|
||||
}, usedExtensionsWithVariablesData: []});
|
||||
|
||||
var object = new gdjs.RuntimeObject(runtimeScene, {
|
||||
name: 'obj1',
|
||||
|
@@ -8,7 +8,7 @@ describe('gdjs.RuntimeScene integration tests', function () {
|
||||
it('should properly create and destroy object, including the behaviors', function () {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
runtimeScene.loadFromScene({sceneData: {
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
@@ -47,7 +47,7 @@ describe('gdjs.RuntimeScene integration tests', function () {
|
||||
],
|
||||
instances: [],
|
||||
usedResources: [],
|
||||
});
|
||||
}, usedExtensionsWithVariablesData: []});
|
||||
|
||||
const object = runtimeScene.createObject('Object1');
|
||||
if (!object) {
|
||||
@@ -82,7 +82,7 @@ describe('gdjs.RuntimeScene integration tests', function () {
|
||||
it('should handle objects on layers', () => {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
runtimeScene.loadFromScene({sceneData: {
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
@@ -128,7 +128,7 @@ describe('gdjs.RuntimeScene integration tests', function () {
|
||||
},
|
||||
],
|
||||
instances: [],
|
||||
});
|
||||
}, usedExtensionsWithVariablesData: []});
|
||||
|
||||
expect(runtimeScene.hasLayer('')).to.be(true);
|
||||
expect(runtimeScene.hasLayer('MyLayer')).to.be(true);
|
||||
|
@@ -135,7 +135,7 @@ interface EventsVariablesFinder {
|
||||
|
||||
[Const, Value] SetString STATIC_FindAllGlobalVariables([Const, Ref] Platform platform, [Const, Ref] Project project);
|
||||
[Const, Value] SetString STATIC_FindAllLayoutVariables([Const, Ref] Platform platform, [Const, Ref] Project project, [Const, Ref] Layout layout);
|
||||
[Const, Value] SetString STATIC_FindAllObjectVariables([Const, Ref] Platform platform, [Const, Ref] Project project, [Const, Ref] Layout layout, [Const, Ref] gdObject obj);
|
||||
[Const, Value] SetString STATIC_FindAllObjectVariables([Const, Ref] Platform platform, [Const, Ref] Project project, [Const, Ref] Layout layout, [Const] DOMString objectName);
|
||||
|
||||
//Inherited from ExpressionParser2NodeWorker:
|
||||
};
|
||||
@@ -225,6 +225,7 @@ interface PairStringVariable {
|
||||
};
|
||||
|
||||
enum Variable_Type {
|
||||
"Variable::Unknown",
|
||||
"Variable::String",
|
||||
"Variable::Number",
|
||||
"Variable::Boolean",
|
||||
@@ -232,6 +233,23 @@ enum Variable_Type {
|
||||
"Variable::Array"
|
||||
};
|
||||
|
||||
interface VariableInstructionSwitcher {
|
||||
boolean STATIC_IsSwitchableVariableInstruction([Const] DOMString instructionType);
|
||||
boolean STATIC_IsSwitchableObjectVariableInstruction([Const] DOMString instructionType);
|
||||
[Const, Ref] DOMString STATIC_GetSwitchableVariableInstructionIdentifier([Const] DOMString instructionType);
|
||||
[Const] Variable_Type STATIC_GetSwitchableInstructionVariableType([Const] DOMString instructionType);
|
||||
void STATIC_SwitchVariableInstructionType(
|
||||
[Ref] Instruction instruction, [Const] Variable_Type variableType);
|
||||
[Const] Variable_Type STATIC_GetVariableTypeFromParameters(
|
||||
[Const, Ref] Platform platform,
|
||||
[Const, Ref] ProjectScopedContainers projectScopedContainers,
|
||||
[Const, Ref] Instruction instruction);
|
||||
void STATIC_SwitchBetweenUnifiedInstructionIfNeeded(
|
||||
[Const, Ref] Platform platform,
|
||||
[Const, Ref] ProjectScopedContainers projectScopedContainers,
|
||||
[Ref] Instruction instruction);
|
||||
};
|
||||
|
||||
interface Variable {
|
||||
void Variable();
|
||||
|
||||
@@ -273,8 +291,21 @@ interface Variable {
|
||||
[Ref] Variable ClearPersistentUuid();
|
||||
};
|
||||
|
||||
enum VariablesContainer_SourceType {
|
||||
"VariablesContainer::Unknown",
|
||||
"VariablesContainer::Global",
|
||||
"VariablesContainer::Scene",
|
||||
"VariablesContainer::Object",
|
||||
"VariablesContainer::Local",
|
||||
"VariablesContainer::ExtensionGlobal",
|
||||
"VariablesContainer::ExtensionScene"
|
||||
};
|
||||
|
||||
interface VariablesContainer {
|
||||
void VariablesContainer();
|
||||
void VariablesContainer(VariablesContainer_SourceType sourceType);
|
||||
|
||||
VariablesContainer_SourceType GetSourceType();
|
||||
|
||||
boolean Has([Const] DOMString name);
|
||||
[Ref] Variable Get([Const] DOMString name);
|
||||
@@ -298,10 +329,12 @@ interface VariablesContainer {
|
||||
};
|
||||
|
||||
interface VariablesContainersList {
|
||||
[Value] VariablesContainersList STATIC_MakeNewVariablesContainersListForProjectAndLayout(
|
||||
[Const, Ref] Project project,
|
||||
[Const, Ref] Layout layout);
|
||||
[Value] VariablesContainersList STATIC_MakeNewEmptyVariablesContainersList();
|
||||
boolean Has([Const] DOMString name);
|
||||
[Const, Ref] Variable Get([Const] DOMString name);
|
||||
[Const, Ref] VariablesContainer GetVariablesContainerFromVariableName([Const] DOMString variableName);
|
||||
|
||||
[Const, Ref] VariablesContainer GetVariablesContainer(unsigned long index);
|
||||
unsigned long GetVariablesContainersCount();
|
||||
};
|
||||
|
||||
interface ObjectGroup {
|
||||
@@ -588,6 +621,13 @@ interface Project {
|
||||
[Ref] ObjectGroupsContainer GetObjectGroups();
|
||||
};
|
||||
|
||||
enum ObjectsContainersList_VariableExistence {
|
||||
"ObjectsContainersList::DoesNotExist",
|
||||
"ObjectsContainersList::Exists",
|
||||
"ObjectsContainersList::GroupIsEmpty",
|
||||
"ObjectsContainersList::ExistsOnlyOnSomeObjectsOfTheGroup"
|
||||
};
|
||||
|
||||
interface ObjectsContainersList {
|
||||
[Value] ObjectsContainersList STATIC_MakeNewObjectsContainersListForProjectAndLayout(
|
||||
[Const, Ref] Project project,
|
||||
@@ -600,15 +640,38 @@ interface ObjectsContainersList {
|
||||
[Const, Value] DOMString GetTypeOfBehavior([Const] DOMString name, boolean searchInGroups);
|
||||
[Value] VectorString GetBehaviorsOfObject([Const] DOMString name, boolean searchInGroups);
|
||||
[Const, Value] DOMString GetTypeOfBehaviorInObjectOrGroup([Const] DOMString objectOrGroupName, [Const] DOMString behaviorName, boolean searchInGroups);
|
||||
|
||||
ObjectsContainersList_VariableExistence HasObjectOrGroupWithVariableNamed([Const] DOMString objectName, [Const] DOMString variableName);
|
||||
};
|
||||
|
||||
interface ProjectScopedContainers {
|
||||
[Value] ProjectScopedContainers STATIC_MakeNewProjectScopedContainersForProjectAndLayout(
|
||||
[Const, Ref] Project project,
|
||||
[Const, Ref] Layout layout);
|
||||
[Value] ProjectScopedContainers STATIC_MakeNewProjectScopedContainersFor(
|
||||
[Const, Ref] ObjectsContainer globalObjectsContainer,
|
||||
[Const, Ref] ObjectsContainer objectsContainer);
|
||||
|
||||
[Value] ProjectScopedContainers STATIC_MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
[Const, Ref] Project project,
|
||||
[Const, Ref] EventsFunctionsExtension eventsFunctionsExtension,
|
||||
[Const, Ref] EventsFunction eventsFunction,
|
||||
[Ref] ObjectsContainer parameterObjectsContainer);
|
||||
|
||||
[Value] ProjectScopedContainers STATIC_MakeNewProjectScopedContainersForBehaviorEventsFunction(
|
||||
[Const, Ref] Project project,
|
||||
[Const, Ref] EventsFunctionsExtension eventsFunctionsExtension,
|
||||
[Const, Ref] EventsBasedBehavior eventsBasedBehavior,
|
||||
[Const, Ref] EventsFunction eventsFunction,
|
||||
[Ref] ObjectsContainer parameterObjectsContainer);
|
||||
|
||||
[Value] ProjectScopedContainers STATIC_MakeNewProjectScopedContainersForObjectEventsFunction(
|
||||
[Const, Ref] Project project,
|
||||
[Const, Ref] EventsFunctionsExtension eventsFunctionsExtension,
|
||||
[Const, Ref] EventsBasedObject eventsBasedObject,
|
||||
[Const, Ref] EventsFunction eventsFunction,
|
||||
[Ref] ObjectsContainer parameterObjectsContainer);
|
||||
|
||||
[Value] ProjectScopedContainers STATIC_MakeNewProjectScopedContainersWithLocalVariables(
|
||||
[Const, Ref] ProjectScopedContainers projectScopedContainers,
|
||||
[Const, Ref] BaseEvent event);
|
||||
|
||||
[Ref] ProjectScopedContainers AddPropertiesContainer(
|
||||
[Const, Ref] PropertiesContainer propertiesContainer);
|
||||
@@ -1651,12 +1714,6 @@ interface ParameterMetadataTools {
|
||||
unsigned long STATIC_GetObjectParameterIndexFor([Const, Ref] VectorParameterMetadata parameters, unsigned long parameterIndex);
|
||||
};
|
||||
|
||||
interface EventsFunctionTools {
|
||||
void STATIC_FreeEventsFunctionToObjectsContainer([Ref] Project project, [Const, Ref] EventsFunctionsContainer functionsContainer, [Const, Ref] EventsFunction eventsFunction, [Ref] ObjectsContainer outputGlobalObjectsContainer, [Ref] ObjectsContainer outputObjectsContainer);
|
||||
void STATIC_BehaviorEventsFunctionToObjectsContainer([Ref] Project project, [Const, Ref] EventsBasedBehavior eventsBasedBehavior, [Const, Ref] EventsFunction eventsFunction, [Ref] ObjectsContainer outputGlobalObjectsContainer, [Ref] ObjectsContainer outputObjectsContainer);
|
||||
void STATIC_ObjectEventsFunctionToObjectsContainer([Ref] Project project, [Const, Ref] EventsBasedObject eventsBasedObject, [Const, Ref] EventsFunction eventsFunction, [Ref] ObjectsContainer outputGlobalObjectsContainer, [Ref] ObjectsContainer outputObjectsContainer);
|
||||
};
|
||||
|
||||
interface ObjectMetadata {
|
||||
[Const, Ref] DOMString GetName();
|
||||
[Const, Ref] DOMString GetFullName();
|
||||
@@ -2054,9 +2111,15 @@ interface BaseEvent {
|
||||
[Const, Ref] DOMString GetType();
|
||||
void SetType([Const] DOMString type);
|
||||
boolean IsExecutable();
|
||||
|
||||
boolean CanHaveSubEvents();
|
||||
boolean HasSubEvents();
|
||||
[Ref] EventsList GetSubEvents();
|
||||
|
||||
boolean CanHaveVariables();
|
||||
boolean HasVariables();
|
||||
[Ref] VariablesContainer GetVariables();
|
||||
|
||||
boolean IsDisabled();
|
||||
void SetDisabled(boolean disable);
|
||||
boolean IsFolded();
|
||||
@@ -2071,23 +2134,8 @@ interface StandardEvent {
|
||||
|
||||
[Ref] InstructionsList GetConditions();
|
||||
[Ref] InstructionsList GetActions();
|
||||
|
||||
//Inherited from BaseEvent:
|
||||
StandardEvent Clone();
|
||||
[Const, Ref] DOMString GetType();
|
||||
void SetType([Const] DOMString type);
|
||||
boolean IsExecutable();
|
||||
boolean CanHaveSubEvents();
|
||||
boolean HasSubEvents();
|
||||
[Ref] EventsList GetSubEvents();
|
||||
boolean IsDisabled();
|
||||
void SetDisabled(boolean disable);
|
||||
boolean IsFolded();
|
||||
void SetFolded(boolean folded);
|
||||
|
||||
void SerializeTo([Ref] SerializerElement element);
|
||||
void UnserializeFrom([Ref] Project project, [Const, Ref] SerializerElement element);
|
||||
};
|
||||
StandardEvent implements BaseEvent;
|
||||
|
||||
interface RepeatEvent {
|
||||
void RepeatEvent();
|
||||
@@ -2096,23 +2144,8 @@ interface RepeatEvent {
|
||||
[Ref] InstructionsList GetActions();
|
||||
void SetRepeatExpression([Const] DOMString expr);
|
||||
[Const, Ref] DOMString GetRepeatExpression();
|
||||
|
||||
//Inherited from BaseEvent:
|
||||
RepeatEvent Clone();
|
||||
[Const, Ref] DOMString GetType();
|
||||
void SetType([Const] DOMString type);
|
||||
boolean IsExecutable();
|
||||
boolean CanHaveSubEvents();
|
||||
boolean HasSubEvents();
|
||||
[Ref] EventsList GetSubEvents();
|
||||
boolean IsDisabled();
|
||||
void SetDisabled(boolean disable);
|
||||
boolean IsFolded();
|
||||
void SetFolded(boolean folded);
|
||||
|
||||
void SerializeTo([Ref] SerializerElement element);
|
||||
void UnserializeFrom([Ref] Project project, [Const, Ref] SerializerElement element);
|
||||
};
|
||||
RepeatEvent implements BaseEvent;
|
||||
|
||||
interface WhileEvent {
|
||||
void WhileEvent();
|
||||
@@ -2120,23 +2153,8 @@ interface WhileEvent {
|
||||
[Ref] InstructionsList GetConditions();
|
||||
[Ref] InstructionsList GetWhileConditions();
|
||||
[Ref] InstructionsList GetActions();
|
||||
|
||||
//Inherited from BaseEvent:
|
||||
WhileEvent Clone();
|
||||
[Const, Ref] DOMString GetType();
|
||||
void SetType([Const] DOMString type);
|
||||
boolean IsExecutable();
|
||||
boolean CanHaveSubEvents();
|
||||
boolean HasSubEvents();
|
||||
[Ref] EventsList GetSubEvents();
|
||||
boolean IsDisabled();
|
||||
void SetDisabled(boolean disable);
|
||||
boolean IsFolded();
|
||||
void SetFolded(boolean folded);
|
||||
|
||||
void SerializeTo([Ref] SerializerElement element);
|
||||
void UnserializeFrom([Ref] Project project, [Const, Ref] SerializerElement element);
|
||||
};
|
||||
WhileEvent implements BaseEvent;
|
||||
|
||||
interface ForEachEvent {
|
||||
void ForEachEvent();
|
||||
@@ -2145,23 +2163,8 @@ interface ForEachEvent {
|
||||
[Const, Ref] DOMString GetObjectToPick();
|
||||
[Ref] InstructionsList GetConditions();
|
||||
[Ref] InstructionsList GetActions();
|
||||
|
||||
//Inherited from BaseEvent:
|
||||
ForEachEvent Clone();
|
||||
[Const, Ref] DOMString GetType();
|
||||
void SetType([Const] DOMString type);
|
||||
boolean IsExecutable();
|
||||
boolean CanHaveSubEvents();
|
||||
boolean HasSubEvents();
|
||||
[Ref] EventsList GetSubEvents();
|
||||
boolean IsDisabled();
|
||||
void SetDisabled(boolean disable);
|
||||
boolean IsFolded();
|
||||
void SetFolded(boolean folded);
|
||||
|
||||
void SerializeTo([Ref] SerializerElement element);
|
||||
void UnserializeFrom([Ref] Project project, [Const, Ref] SerializerElement element);
|
||||
};
|
||||
ForEachEvent implements BaseEvent;
|
||||
|
||||
interface ForEachChildVariableEvent {
|
||||
void ForEachChildVariableEvent();
|
||||
@@ -2175,23 +2178,8 @@ interface ForEachChildVariableEvent {
|
||||
void SetIterableVariableName([Const] DOMString newName);
|
||||
void SetKeyIteratorVariableName([Const] DOMString newName);
|
||||
void SetValueIteratorVariableName([Const] DOMString newName);
|
||||
|
||||
//Inherited from BaseEvent:
|
||||
ForEachChildVariableEvent Clone();
|
||||
[Const, Ref] DOMString GetType();
|
||||
void SetType([Const] DOMString type);
|
||||
boolean IsExecutable();
|
||||
boolean CanHaveSubEvents();
|
||||
boolean HasSubEvents();
|
||||
[Ref] EventsList GetSubEvents();
|
||||
boolean IsDisabled();
|
||||
void SetDisabled(boolean disable);
|
||||
boolean IsFolded();
|
||||
void SetFolded(boolean folded);
|
||||
|
||||
void SerializeTo([Ref] SerializerElement element);
|
||||
void UnserializeFrom([Ref] Project project, [Const, Ref] SerializerElement element);
|
||||
};
|
||||
ForEachChildVariableEvent implements BaseEvent;
|
||||
|
||||
interface CommentEvent {
|
||||
void CommentEvent();
|
||||
@@ -2208,23 +2196,8 @@ interface CommentEvent {
|
||||
unsigned long GetTextColorRed();
|
||||
unsigned long GetTextColorGreen();
|
||||
unsigned long GetTextColorBlue();
|
||||
|
||||
//Inherited from BaseEvent:
|
||||
CommentEvent Clone();
|
||||
[Const, Ref] DOMString GetType();
|
||||
void SetType([Const] DOMString type);
|
||||
boolean IsExecutable();
|
||||
boolean CanHaveSubEvents();
|
||||
boolean HasSubEvents();
|
||||
[Ref] EventsList GetSubEvents();
|
||||
boolean IsDisabled();
|
||||
void SetDisabled(boolean disable);
|
||||
boolean IsFolded();
|
||||
void SetFolded(boolean folded);
|
||||
|
||||
void SerializeTo([Ref] SerializerElement element);
|
||||
void UnserializeFrom([Ref] Project project, [Const, Ref] SerializerElement element);
|
||||
};
|
||||
CommentEvent implements BaseEvent;
|
||||
|
||||
interface GroupEvent {
|
||||
void GroupEvent();
|
||||
@@ -2240,23 +2213,8 @@ interface GroupEvent {
|
||||
[Ref] VectorString GetCreationParameters();
|
||||
unsigned long GetCreationTimestamp();
|
||||
void SetCreationTimestamp(unsigned long ts);
|
||||
|
||||
//Inherited from BaseEvent:
|
||||
GroupEvent Clone();
|
||||
[Const, Ref] DOMString GetType();
|
||||
void SetType([Const] DOMString type);
|
||||
boolean IsExecutable();
|
||||
boolean CanHaveSubEvents();
|
||||
boolean HasSubEvents();
|
||||
[Ref] EventsList GetSubEvents();
|
||||
boolean IsDisabled();
|
||||
void SetDisabled(boolean disable);
|
||||
boolean IsFolded();
|
||||
void SetFolded(boolean folded);
|
||||
|
||||
void SerializeTo([Ref] SerializerElement element);
|
||||
void UnserializeFrom([Ref] Project project, [Const, Ref] SerializerElement element);
|
||||
};
|
||||
GroupEvent implements BaseEvent;
|
||||
|
||||
interface LinkEvent {
|
||||
void LinkEvent();
|
||||
@@ -2271,23 +2229,8 @@ interface LinkEvent {
|
||||
void SetIncludeStartAndEnd(unsigned long start, unsigned long end);
|
||||
unsigned long GetIncludeStart();
|
||||
unsigned long GetIncludeEnd();
|
||||
|
||||
//Inherited from BaseEvent:
|
||||
LinkEvent Clone();
|
||||
[Const, Ref] DOMString GetType();
|
||||
void SetType([Const] DOMString type);
|
||||
boolean IsExecutable();
|
||||
boolean CanHaveSubEvents();
|
||||
boolean HasSubEvents();
|
||||
[Ref] EventsList GetSubEvents();
|
||||
boolean IsDisabled();
|
||||
void SetDisabled(boolean disable);
|
||||
boolean IsFolded();
|
||||
void SetFolded(boolean folded);
|
||||
|
||||
void SerializeTo([Ref] SerializerElement element);
|
||||
void UnserializeFrom([Ref] Project project, [Const, Ref] SerializerElement element);
|
||||
};
|
||||
LinkEvent implements BaseEvent;
|
||||
|
||||
interface EventsRemover {
|
||||
void EventsRemover();
|
||||
@@ -2358,7 +2301,7 @@ interface VariablesChangeset {
|
||||
};
|
||||
|
||||
interface WholeProjectRefactorer {
|
||||
[Value] VariablesChangeset STATIC_ComputeChangesetForVariablesContainer([Ref] Project project,
|
||||
[Value] VariablesChangeset STATIC_ComputeChangesetForVariablesContainer(
|
||||
[Const, Ref] SerializerElement oldSerializedVariablesContainer,
|
||||
[Const, Ref] VariablesContainer newVariablesContainer);
|
||||
void STATIC_ApplyRefactoringForVariablesContainer([Ref] Project project,
|
||||
@@ -2595,7 +2538,8 @@ interface ExpressionValidator {
|
||||
void ExpressionValidator(
|
||||
[Const, Ref] Platform platform,
|
||||
[Const, Ref] ProjectScopedContainers projectScopedContainers,
|
||||
[Const] DOMString rootType);
|
||||
[Const] DOMString rootType,
|
||||
[Const] DOMString extraInfo);
|
||||
|
||||
[Const, Ref] VectorExpressionParserDiagnostic GetAllErrors();
|
||||
[Const, Ref] VectorExpressionParserDiagnostic GetFatalErrors();
|
||||
@@ -2890,6 +2834,9 @@ interface EventsFunctionsExtension {
|
||||
void RemoveDependencyAt(unsigned long index);
|
||||
[Ref] VectorDependencyMetadata GetAllDependencies();
|
||||
|
||||
[Ref] VariablesContainer GetGlobalVariables();
|
||||
[Ref] VariablesContainer GetSceneVariables();
|
||||
|
||||
[Ref] EventsBasedBehaviorsList GetEventsBasedBehaviors();
|
||||
[Ref] EventsBasedObjectsList GetEventsBasedObjects();
|
||||
|
||||
@@ -3512,7 +3459,13 @@ interface LayoutCodeGenerator {
|
||||
[Prefix="gdjs::"]
|
||||
interface BehaviorCodeGenerator {
|
||||
void BehaviorCodeGenerator([Ref] Project project);
|
||||
[Const, Value] DOMString GenerateRuntimeBehaviorCompleteCode([Const] DOMString extensionName, [Const, Ref] EventsBasedBehavior eventsBasedBehavior, [Const] DOMString codeNamespace, [Const, Ref] MapStringString behaviorMethodMangledNames, [Ref] SetString includes, boolean compilationForRuntime);
|
||||
[Const, Value] DOMString GenerateRuntimeBehaviorCompleteCode(
|
||||
[Const, Ref] EventsFunctionsExtension eventsFunctionsExtension,
|
||||
[Const, Ref] EventsBasedBehavior eventsBasedBehavior,
|
||||
[Const] DOMString codeNamespace,
|
||||
[Const, Ref] MapStringString behaviorMethodMangledNames,
|
||||
[Ref] SetString includes,
|
||||
boolean compilationForRuntime);
|
||||
[Const, Value] DOMString STATIC_GetBehaviorPropertyGetterName([Const] DOMString propertyName);
|
||||
[Const, Value] DOMString STATIC_GetBehaviorPropertySetterName([Const] DOMString propertyName);
|
||||
[Const, Value] DOMString STATIC_GetBehaviorPropertyToggleFunctionName([Const] DOMString propertyName);
|
||||
@@ -3524,7 +3477,13 @@ interface BehaviorCodeGenerator {
|
||||
[Prefix="gdjs::"]
|
||||
interface ObjectCodeGenerator {
|
||||
void ObjectCodeGenerator([Ref] Project project);
|
||||
[Const, Value] DOMString GenerateRuntimeObjectCompleteCode([Const] DOMString extensionName, [Const, Ref] EventsBasedObject eventsBasedObject, [Const] DOMString codeNamespace, [Const, Ref] MapStringString objectMethodMangledNames, [Ref] SetString includes, boolean compilationForRuntime);
|
||||
[Const, Value] DOMString GenerateRuntimeObjectCompleteCode(
|
||||
[Const, Ref] EventsFunctionsExtension eventsFunctionsExtension,
|
||||
[Const, Ref] EventsBasedObject eventsBasedObject,
|
||||
[Const] DOMString codeNamespace,
|
||||
[Const, Ref] MapStringString objectMethodMangledNames,
|
||||
[Ref] SetString includes,
|
||||
boolean compilationForRuntime);
|
||||
[Const, Value] DOMString STATIC_GetObjectPropertyGetterName([Const] DOMString propertyName);
|
||||
[Const, Value] DOMString STATIC_GetObjectPropertySetterName([Const] DOMString propertyName);
|
||||
[Const, Value] DOMString STATIC_GetObjectPropertyToggleFunctionName([Const] DOMString propertyName);
|
||||
|
@@ -57,6 +57,7 @@
|
||||
#include <GDCore/IDE/ProjectBrowserHelper.h>
|
||||
#include <GDCore/IDE/PropertyFunctionGenerator.h>
|
||||
#include <GDCore/IDE/UnfilledRequiredBehaviorPropertyProblem.h>
|
||||
#include <GDCore/IDE/VariableInstructionSwitcher.h>
|
||||
#include <GDCore/IDE/WholeProjectRefactorer.h>
|
||||
#include <GDCore/Project/Behavior.h>
|
||||
#include <GDCore/Project/CustomObjectConfiguration.h>
|
||||
@@ -445,6 +446,7 @@ typedef std::vector<gd::EventsFunction> VectorEventsFunction;
|
||||
typedef gd::Object gdObject; // To avoid clashing javascript Object in glue.js
|
||||
typedef ParticleEmitterObject::RendererType ParticleEmitterObject_RendererType;
|
||||
typedef EventsFunction::FunctionType EventsFunction_FunctionType;
|
||||
typedef ObjectsContainersList::VariableExistence ObjectsContainersList_VariableExistence;
|
||||
typedef EventsFunctionsContainer::FunctionOwner
|
||||
EventsFunctionsContainer_FunctionOwner;
|
||||
typedef std::unique_ptr<gd::Object> UniquePtrObject;
|
||||
@@ -463,6 +465,7 @@ typedef std::vector<gd::ExpressionCompletionDescription>
|
||||
typedef std::map<gd::String, std::map<gd::String, gd::PropertyDescriptor>>
|
||||
MapExtensionProperties;
|
||||
typedef gd::Variable::Type Variable_Type;
|
||||
typedef gd::VariablesContainer::SourceType VariablesContainer_SourceType;
|
||||
typedef std::map<gd::String, gd::SerializerValue> MapStringSerializerValue;
|
||||
typedef std::vector<std::pair<gd::String, std::shared_ptr<SerializerElement>>>
|
||||
VectorPairStringSharedPtrSerializerElement;
|
||||
@@ -556,18 +559,30 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
|
||||
#define STATIC_Get Get
|
||||
#define STATIC_GetAllUseless GetAllUseless
|
||||
#define STATIC_RemoveAllUseless RemoveAllUseless
|
||||
#define STATIC_MakeNewVariablesContainersListForProjectAndLayout \
|
||||
MakeNewVariablesContainersListForProjectAndLayout
|
||||
#define STATIC_MakeNewEmptyVariablesContainersList \
|
||||
MakeNewEmptyVariablesContainersList
|
||||
#define STATIC_MakeNewObjectsContainersListForProjectAndLayout \
|
||||
MakeNewObjectsContainersListForProjectAndLayout
|
||||
#define STATIC_MakeNewObjectsContainersListForContainers \
|
||||
MakeNewObjectsContainersListForContainers
|
||||
#define STATIC_MakeNewEmptyProjectScopedContainers \
|
||||
MakeNewEmptyProjectScopedContainers
|
||||
#define STATIC_MakeNewProjectScopedContainersForProjectAndLayout \
|
||||
MakeNewProjectScopedContainersForProjectAndLayout
|
||||
#define STATIC_MakeNewProjectScopedContainersFor \
|
||||
MakeNewProjectScopedContainersFor
|
||||
#define STATIC_MakeNewProjectScopedContainersForFreeEventsFunction \
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction
|
||||
#define STATIC_MakeNewProjectScopedContainersForBehaviorEventsFunction \
|
||||
MakeNewProjectScopedContainersForBehaviorEventsFunction
|
||||
#define STATIC_MakeNewProjectScopedContainersForObjectEventsFunction \
|
||||
MakeNewProjectScopedContainersForObjectEventsFunction
|
||||
#define STATIC_MakeNewProjectScopedContainersWithLocalVariables \
|
||||
MakeNewProjectScopedContainersWithLocalVariables
|
||||
#define STATIC_MakeNewProjectScopedContainersForFreeEventsFunction \
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction
|
||||
#define STATIC_MakeNewProjectScopedContainersForBehaviorEventsFunction \
|
||||
MakeNewProjectScopedContainersForBehaviorEventsFunction
|
||||
#define STATIC_MakeNewProjectScopedContainersForObjectEventsFunction \
|
||||
MakeNewProjectScopedContainersForObjectEventsFunction
|
||||
|
||||
#define STATIC_GetExtensionAndBehaviorMetadata GetExtensionAndBehaviorMetadata
|
||||
#define STATIC_GetExtensionAndObjectMetadata GetExtensionAndObjectMetadata
|
||||
@@ -666,6 +681,13 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
|
||||
#define STATIC_FindAllLayoutVariables FindAllLayoutVariables
|
||||
#define STATIC_FindAllObjectVariables FindAllObjectVariables
|
||||
#define STATIC_FindAllIdentifierExpressions FindAllIdentifierExpressions
|
||||
#define STATIC_SwitchVariableInstructionType SwitchVariableInstructionType
|
||||
#define STATIC_GetVariableTypeFromParameters GetVariableTypeFromParameters
|
||||
#define STATIC_SwitchBetweenUnifiedInstructionIfNeeded SwitchBetweenUnifiedInstructionIfNeeded
|
||||
#define STATIC_IsSwitchableVariableInstruction IsSwitchableVariableInstruction
|
||||
#define STATIC_IsSwitchableObjectVariableInstruction IsSwitchableObjectVariableInstruction
|
||||
#define STATIC_GetSwitchableVariableInstructionIdentifier GetSwitchableVariableInstructionIdentifier
|
||||
#define STATIC_GetSwitchableInstructionVariableType GetSwitchableInstructionVariableType
|
||||
|
||||
#define STATIC_IsFreeFunctionOnlyCallingItself IsFreeFunctionOnlyCallingItself
|
||||
#define STATIC_IsBehaviorFunctionOnlyCallingItself \
|
||||
@@ -678,12 +700,6 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
|
||||
#define STATIC_FoldAll FoldAll
|
||||
#define STATIC_UnfoldToLevel UnfoldToLevel
|
||||
|
||||
#define STATIC_FreeEventsFunctionToObjectsContainer \
|
||||
FreeEventsFunctionToObjectsContainer
|
||||
#define STATIC_BehaviorEventsFunctionToObjectsContainer \
|
||||
BehaviorEventsFunctionToObjectsContainer
|
||||
#define STATIC_ObjectEventsFunctionToObjectsContainer \
|
||||
ObjectEventsFunctionToObjectsContainer
|
||||
#define STATIC_ParametersToObjectsContainer ParametersToObjectsContainer
|
||||
#define STATIC_GetObjectParameterIndexFor GetObjectParameterIndexFor
|
||||
|
||||
|
@@ -22,8 +22,8 @@ endif()
|
||||
#
|
||||
# add_compile_options(-fsanitize=address) # Uncomment to auto-detect occurences of memory bugs (memory leak, use after free, overflows, ...) - also enable linking below!
|
||||
# add_compile_options(-fsanitize=undefined) # Uncomment to auto-detect occurences of undefined behavior - also enable linking below!
|
||||
# add_compile_options(-g) # Uncomment for debugging support
|
||||
# add_compile_options(--profiling) # Uncomment for profiling support
|
||||
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g --profiling") # Uncomment for debugging + profiling support
|
||||
# SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --profiling") # Uncomment for profiling support
|
||||
|
||||
# Common directories:
|
||||
#
|
||||
|
@@ -11,13 +11,39 @@ function generateCompiledEventsForEventsFunction(
|
||||
project,
|
||||
eventsFunction,
|
||||
logCode = false
|
||||
) {
|
||||
const extension = new gd.EventsFunctionsExtension();
|
||||
const runCompiledEventsFunction = generateCompiledEventsForEventsFunctionWithContext(
|
||||
gd,
|
||||
project,
|
||||
extension,
|
||||
eventsFunction,
|
||||
logCode
|
||||
);
|
||||
extension.delete();
|
||||
return runCompiledEventsFunction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the code from events (using GDJS platform)
|
||||
* and create a JavaScript function that runs it.
|
||||
*
|
||||
* The JavaScript function must be called with the `runtimeScene` to be used.
|
||||
* In this context, GDJS game engine does not exist, so you must pass a mock
|
||||
* to it to validate that the events are working properly.
|
||||
*/
|
||||
function generateCompiledEventsForEventsFunctionWithContext(
|
||||
gd,
|
||||
project,
|
||||
extension,
|
||||
eventsFunction,
|
||||
logCode = false
|
||||
) {
|
||||
const namespace = 'functionNamespace';
|
||||
const eventsFunctionsExtensionCodeGenerator =
|
||||
new gd.EventsFunctionsExtensionCodeGenerator(project);
|
||||
|
||||
const includeFiles = new gd.SetString();
|
||||
const extension = new gd.EventsFunctionsExtension();
|
||||
const code =
|
||||
eventsFunctionsExtensionCodeGenerator.generateFreeEventsFunctionCompleteCode(
|
||||
extension,
|
||||
@@ -28,7 +54,6 @@ function generateCompiledEventsForEventsFunction(
|
||||
);
|
||||
|
||||
eventsFunctionsExtensionCodeGenerator.delete();
|
||||
extension.delete();
|
||||
includeFiles.delete();
|
||||
|
||||
if (logCode) console.log(code);
|
||||
@@ -268,15 +293,13 @@ function generateCompiledEventsFromSerializedEvents(
|
||||
const { parameterTypes, groups } = configuration;
|
||||
if (groups) {
|
||||
for (const groupName in groups) {
|
||||
if (Object.hasOwnProperty.call(groups, groupName)) {
|
||||
const objectsNames = groups[groupName];
|
||||
const objectsNames = groups[groupName];
|
||||
|
||||
const group = eventsFunction
|
||||
.getObjectGroups()
|
||||
.insertNew(groupName, 0);
|
||||
for (const objectName of objectsNames) {
|
||||
group.addObject(objectName);
|
||||
}
|
||||
const group = eventsFunction
|
||||
.getObjectGroups()
|
||||
.insertNew(groupName, 0);
|
||||
for (const objectName of objectsNames) {
|
||||
group.addObject(objectName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -309,10 +332,72 @@ function generateCompiledEventsFromSerializedEvents(
|
||||
return runCompiledEvents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to create compiled events from serialized events, creating a project and the events function.
|
||||
* @param {*} gd
|
||||
* @param {gdEventsFunctionExtension} extension
|
||||
* @param {gdSerializerElement} eventsSerializerElement
|
||||
* @param {{parameterTypes: {[name: string]: string}, groups: {[name: string]: string[]}, logCode: boolean}?} configuration
|
||||
* @returns
|
||||
*/
|
||||
function generateCompiledEventsFunctionFromSerializedEvents(
|
||||
gd,
|
||||
extension,
|
||||
eventsSerializerElement,
|
||||
configuration
|
||||
) {
|
||||
const project = new gd.ProjectHelper.createNewGDJSProject();
|
||||
const eventsFunction = new gd.EventsFunction();
|
||||
eventsFunction.getEvents().unserializeFrom(project, eventsSerializerElement);
|
||||
|
||||
if (configuration) {
|
||||
const { parameterTypes, groups } = configuration;
|
||||
if (groups) {
|
||||
for (const groupName in groups) {
|
||||
const objectsNames = groups[groupName];
|
||||
|
||||
const group = eventsFunction
|
||||
.getObjectGroups()
|
||||
.insertNew(groupName, 0);
|
||||
for (const objectName of objectsNames) {
|
||||
group.addObject(objectName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parameterTypes) {
|
||||
for (const parameterName in parameterTypes) {
|
||||
if (Object.hasOwnProperty.call(parameterTypes, parameterName)) {
|
||||
const parameterType = parameterTypes[parameterName];
|
||||
|
||||
const parameter = new gd.ParameterMetadata();
|
||||
parameter.setType(parameterType);
|
||||
parameter.setName(parameterName);
|
||||
eventsFunction.getParameters().push_back(parameter);
|
||||
parameter.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const runCompiledEvents = generateCompiledEventsForEventsFunctionWithContext(
|
||||
gd,
|
||||
project,
|
||||
extension,
|
||||
eventsFunction,
|
||||
configuration && configuration.logCode
|
||||
);
|
||||
|
||||
eventsFunction.delete();
|
||||
project.delete();
|
||||
|
||||
return runCompiledEvents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a function to run the compiled events of a layout.
|
||||
*/
|
||||
function generateCompiledEventsForLayout(gd, project, layout) {
|
||||
function generateCompiledEventsForLayout(gd, project, layout, logCode = false) {
|
||||
const includeFiles = new gd.SetString();
|
||||
const layoutCodeGenerator = new gd.LayoutCodeGenerator(project);
|
||||
|
||||
@@ -325,6 +410,8 @@ function generateCompiledEventsForLayout(gd, project, layout) {
|
||||
layoutCodeGenerator.delete();
|
||||
includeFiles.delete();
|
||||
|
||||
if (logCode) console.log(code);
|
||||
|
||||
// Create a function running the generated code.
|
||||
const compiledFunction = new Function(
|
||||
'gdjs',
|
||||
@@ -340,6 +427,7 @@ function generateCompiledEventsForLayout(gd, project, layout) {
|
||||
module.exports = {
|
||||
generateCompiledEventsForEventsFunction,
|
||||
generateCompiledEventsFromSerializedEvents,
|
||||
generateCompiledEventsFunctionFromSerializedEvents,
|
||||
generateCompiledEventsForSerializedEventsBasedExtension,
|
||||
generateCompiledEventsForLayout,
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user