Compare commits

..

22 Commits

Author SHA1 Message Date
Florian Rival
0ffaefaf1d Merge branch 'master' into pr/5429 2023-12-05 17:10:25 +01:00
Arthur Pacaud (arthuro555)
034e6ac839 Merge branch 'experimental-build/emscripten-upgrade' into gdcore-ts 2023-11-30 22:31:03 +01:00
Florian Rival
afc2d284c1 Fix missing distutils 2023-11-21 18:27:45 +01:00
Florian Rival
c2ed4e9910 Fix test not finishing on CircleCI Linux machines 2023-11-21 16:19:05 +01:00
Florian Rival
8d2341bd21 Try forceExit 2023-11-21 15:36:56 +01:00
Florian Rival
b187d9ec98 Merge branch 'master' into emsdk-update 2023-11-21 14:45:46 +01:00
Florian Rival
d2da102830 Add --detectOpenHandles 2023-11-21 14:45:06 +01:00
Florian Rival
a6c4f742c2 Comment debugging options to see if the test in the CI pass 2023-09-08 14:40:43 +02:00
Florian Rival
e6935206c0 Try without wasm-exceptions flag 2023-09-08 14:18:35 +02:00
Florian Rival
00190de683 Revert to Node 16 on Travis for now 2023-09-07 10:52:10 +02:00
Florian Rival
7a8c359379 Upgrade CircleCI/AppVeyor to Emscripten 3.1.21 2023-09-07 09:24:01 +02:00
Florian Rival
29aa2479f6 Upgrade Travis to Emscripten 3.1.21 and Node.js 18 2023-09-07 09:20:46 +02:00
Arthur Pacaud
7010b6880d Update Emscripten version 2023-09-07 04:31:09 +02:00
Arthur Pacaud
2a9d826ab5 Try a package-lock v1 2023-07-21 00:40:00 +02:00
Florian Rival
5b255e46c6 Regenerate again package-lock.json 2023-07-20 22:04:47 +02:00
Arthur Pacaud
5043baa367 Regenerate package-lock.json 2023-07-18 09:31:32 +02:00
Arthur Pacaud
66ff2d5b55 Add missing enum type generation 2023-07-15 02:04:40 +02:00
Arthur Pacaud
3a015f6696 Fix constructors generation regression 2023-07-15 01:51:14 +02:00
Arthur Pacaud
647f3e1cfa Fix method type generation 2023-07-15 01:33:06 +02:00
Arthur Pacaud
52c3241f44 Apply review instructions 2023-07-15 01:23:13 +02:00
Arthur Pacaud
0ae40e0911 Merge remote-tracking branch 'origin/master' into gdcore-ts 2023-07-15 01:17:28 +02:00
Arthur Pacaud
0f788b4913 Autogenerate TS typedefs for Core 2023-06-21 15:12:29 +02:00
1462 changed files with 56763 additions and 107661 deletions

View File

@@ -19,7 +19,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 20
node-version: 16
cache: "npm"
cache-dependency-path: "newIDE/app/package-lock.json"
@@ -58,7 +58,7 @@ jobs:
working-directory: newIDE/app
- name: Create a Pull Request with the changes
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v5
with:
commit-message: Update translations [skip ci]
branch: chore/update-translations

View File

@@ -56,7 +56,6 @@ blocks:
- name: GDJS typing and documentation generation
commands:
- checkout
- cache restore newIDE-app-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum newIDE/app/package-lock.json)
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
- cache restore GDJS-tests-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/tests/package-lock.json)
- cd GDJS

1
.vscode/tasks.json vendored
View File

@@ -8,7 +8,6 @@
"group": "build",
"label": "Start development server",
"detail": "Starts the GDevelop development server.",
"options": { "env": { "NODE_OPTIONS": "--max-old-space-size=8192" } },
"problemMatcher": [
{
"owner": "cra",

View File

@@ -49,8 +49,7 @@ vector<pair<gd::Expression*, gd::ParameterMetadata> >
ForEachChildVariableEvent::GetAllExpressionsWithMetadata() {
vector<pair<gd::Expression*, gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("variable");
metadata.SetExtraInfo("AllowUndeclaredVariable");
auto metadata = gd::ParameterMetadata().SetType("scenevar");
allExpressionsWithMetadata.push_back(
std::make_pair(&iterableVariableName, metadata));
allExpressionsWithMetadata.push_back(
@@ -64,8 +63,7 @@ vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
ForEachChildVariableEvent::GetAllExpressionsWithMetadata() const {
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("variable");
metadata.SetExtraInfo("AllowUndeclaredVariable");
auto metadata = gd::ParameterMetadata().SetType("scenevar");
allExpressionsWithMetadata.push_back(
std::make_pair(&iterableVariableName, metadata));
allExpressionsWithMetadata.push_back(

View File

@@ -4,8 +4,8 @@
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef GDCORE_REPEATEVENT_H
#define GDCORE_REPEATEVENT_H
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
namespace gd {
@@ -36,10 +36,10 @@ class GD_CORE_API RepeatEvent : public gd::BaseEvent {
const gd::InstructionsList& GetActions() const { return actions; };
gd::InstructionsList& GetActions() { return actions; };
const gd::Expression& GetRepeatExpression() const {
return repeatNumberExpression;
const gd::String& GetRepeatExpression() const {
return repeatNumberExpression.GetPlainString();
};
void SetRepeatExpressionPlainString(gd::String repeatNumberExpression_) {
void SetRepeatExpression(gd::String repeatNumberExpression_) {
repeatNumberExpression = gd::Expression(repeatNumberExpression_);
};
@@ -68,3 +68,5 @@ class GD_CORE_API RepeatEvent : public gd::BaseEvent {
};
} // namespace gd
#endif // GDCORE_REPEATEVENT_H

View File

@@ -15,8 +15,7 @@ using namespace std;
namespace gd {
StandardEvent::StandardEvent()
: BaseEvent(), variables(gd::VariablesContainer::SourceType::Local) {}
StandardEvent::StandardEvent() : BaseEvent() {}
StandardEvent::~StandardEvent(){};
@@ -58,9 +57,6 @@ 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,
@@ -75,11 +71,6 @@ 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

View File

@@ -4,13 +4,13 @@
* reserved. This project is released under the MIT License.
*/
#pragma once
#if defined(GD_IDE_ONLY)
#ifndef GDCORE_STANDARDEVENT_H
#define GDCORE_STANDARDEVENT_H
#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,10 +33,6 @@ 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; };
@@ -57,7 +53,9 @@ 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

View File

@@ -1,117 +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/String.h"
#include "GDCore/Tools/MakeUnique.h"
namespace gd {
/**
* \brief
*/
class GD_CORE_API ProjectDiagnostic {
public:
enum ErrorType {
UndeclaredVariable,
MissingBehavior,
UnknownObject,
MismatchedObjectType,
};
ProjectDiagnostic(ErrorType type_, const gd::String &message_,
const gd::String &actualValue_,
const gd::String &expectedValue_, const gd::String &objectName_ = "")
: type(type_), message(message_), actualValue(actualValue_), expectedValue(expectedValue_),
objectName(objectName_){};
virtual ~ProjectDiagnostic(){};
ErrorType GetType() const { return type; };
const gd::String &GetMessage() const { return message; }
const gd::String &GetObjectName() const { return objectName; }
const gd::String &GetActualValue() const { return actualValue; }
const gd::String &GetExpectedValue() const { return expectedValue; }
private:
ErrorType type;
gd::String message;
gd::String objectName;
gd::String actualValue;
gd::String expectedValue;
};
/**
* \brief
*/
class GD_CORE_API DiagnosticReport {
public:
DiagnosticReport(){};
virtual ~DiagnosticReport(){};
void Add(const gd::ProjectDiagnostic &projectDiagnostic) {
projectDiagnostics.push_back(
gd::make_unique<gd::ProjectDiagnostic>(projectDiagnostic));
};
const ProjectDiagnostic &Get(std::size_t index) const {
return *projectDiagnostics[index].get();
};
std::size_t Count() const { return projectDiagnostics.size(); };
const gd::String &GetSceneName() const { return sceneName; }
void SetSceneName(const gd::String &sceneName_) {
sceneName = sceneName_;
}
private:
std::vector<std::unique_ptr<gd::ProjectDiagnostic>> projectDiagnostics;
gd::String sceneName;
};
/**
* \brief
*/
class GD_CORE_API WholeProjectDiagnosticReport {
public:
WholeProjectDiagnosticReport(){};
virtual ~WholeProjectDiagnosticReport(){};
const DiagnosticReport &Get(std::size_t index) const {
return *diagnosticReports[index].get();
};
void Clear() {
diagnosticReports.clear();
};
DiagnosticReport& AddNewDiagnosticReportForScene(const gd::String &sceneName) {
auto diagnosticReport = gd::make_unique<gd::DiagnosticReport>();
diagnosticReport->SetSceneName(sceneName);
diagnosticReports.push_back(std::move(diagnosticReport));
return *diagnosticReports[diagnosticReports.size() - 1].get();
};
std::size_t Count() const { return diagnosticReports.size(); };
bool HasAnyIssue() {
for (auto& diagnosticReport : diagnosticReports) {
if (diagnosticReport->Count() > 0) {
return true;
}
}
return false;
}
private:
std::vector<std::unique_ptr<gd::DiagnosticReport>> diagnosticReports;
};
} // namespace gd

View File

@@ -3,8 +3,8 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef EVENTSCODEGENERATIONCONTEXT_H
#define EVENTSCODEGENERATIONCONTEXT_H
#include <map>
#include <memory>
#include <set>
@@ -325,3 +325,4 @@ class GD_CORE_API EventsCodeGenerationContext {
};
} // namespace gd
#endif // EVENTSCODEGENERATIONCONTEXT_H

View File

@@ -14,7 +14,6 @@
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/Events/ExpressionVariableNameFinder.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/ObjectsContainersList.h"
@@ -255,12 +254,12 @@ gd::String EventsCodeGenerator::GenerateMutatorCall(
}
gd::String operatorStr = arguments[operatorIndex];
if (operatorStr.size() > 2 && operatorStr[0] == '\"') {
if (operatorStr.size() > 2)
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()) {
@@ -280,9 +279,6 @@ gd::String EventsCodeGenerator::GenerateMutatorCall(
argumentsStr += arguments[i];
}
}
if (instrInfos.GetManipulatedType() == "boolean") {
return callStartString + "(" + argumentsStr + ")." + mutator->second;
}
return callStartString + "(" + argumentsStr + ")." + mutator->second + "(" +
rhs + ")";
@@ -322,30 +318,17 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
condition.SetParameters(parameters);
}
gd::EventsCodeGenerator::CheckBehaviorParameters(condition, instrInfos);
// Verify that there are no mismatches between object type in parameters.
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
if (ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType())) {
gd::String objectInParameter =
condition.GetParameter(pNb).GetPlainString();
const auto &expectedObjectType =
instrInfos.parameters[pNb].GetExtraInfo();
const auto &actualObjectType =
GetObjectsContainersList().GetTypeOfObject(objectInParameter);
if (!GetObjectsContainersList().HasObjectOrGroupNamed(
objectInParameter)) {
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::UnknownObject, "",
objectInParameter, "");
diagnosticReport->Add(projectDiagnostic);
if (!GetObjectsContainersList().HasObjectOrGroupNamed(objectInParameter)) {
return "/* Unknown object - skipped. */";
} else if (!expectedObjectType.empty() &&
actualObjectType != expectedObjectType) {
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::MismatchedObjectType, "",
actualObjectType, expectedObjectType, objectInParameter);
diagnosticReport->Add(projectDiagnostic);
} else if (!instrInfos.parameters[pNb].GetExtraInfo().empty() &&
GetObjectsContainersList().GetTypeOfObject(objectInParameter) !=
instrInfos.parameters[pNb].GetExtraInfo()) {
return "/* Mismatched object type - skipped. */";
}
}
@@ -381,22 +364,15 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
}
}
} else if (instrInfos.IsBehaviorInstruction()) {
gd::String objectName = condition.GetParameter(0).GetPlainString();
gd::String behaviorType = GetObjectsContainersList().GetTypeOfBehavior(condition.GetParameter(1).GetPlainString());
if (instrInfos.parameters.size() >= 2) {
const gd::String &objectName = condition.GetParameter(0).GetPlainString();
const gd::String &behaviorName =
condition.GetParameter(1).GetPlainString();
const gd::String &actualBehaviorType =
GetObjectsContainersList().GetTypeOfBehavior(behaviorName);
std::vector<gd::String> realObjects =
GetObjectsContainersList().ExpandObjectName(
objectName, context.GetCurrentObject());
const BehaviorMetadata &autoInfo =
MetadataProvider::GetBehaviorMetadata(platform, actualBehaviorType);
GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
for (std::size_t i = 0; i < realObjects.size(); ++i) {
// Setup context
const BehaviorMetadata& autoInfo =
MetadataProvider::GetBehaviorMetadata(platform, behaviorType);
AddIncludeFiles(autoInfo.includeFiles);
context.SetCurrentObject(realObjects[i]);
context.ObjectsListNeeded(realObjects[i]);
@@ -406,7 +382,7 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
condition.GetParameters(), instrInfos.parameters, context);
conditionCode += GenerateBehaviorCondition(
realObjects[i],
behaviorName,
condition.GetParameter(1).GetPlainString(),
autoInfo,
arguments,
instrInfos,
@@ -481,33 +457,6 @@ gd::String EventsCodeGenerator::GenerateConditionsListCode(
return outputCode;
}
void EventsCodeGenerator::CheckBehaviorParameters(
const gd::Instruction &instruction,
const gd::InstructionMetadata &instrInfos) {
gd::ParameterMetadataTools::IterateOverParameters(
instruction.GetParameters(), instrInfos.parameters,
[this](const gd::ParameterMetadata &parameterMetadata,
const gd::Expression &parameterValue,
const gd::String &lastObjectName) {
if (ParameterMetadata::IsBehavior(parameterMetadata.GetType())) {
const gd::String &behaviorName = parameterValue.GetPlainString();
const gd::String &actualBehaviorType =
GetObjectsContainersList().GetTypeOfBehaviorInObjectOrGroup(
lastObjectName, behaviorName);
const gd::String &expectedBehaviorType =
parameterMetadata.GetExtraInfo();
if (!expectedBehaviorType.empty() &&
actualBehaviorType != expectedBehaviorType) {
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::MissingBehavior, "",
actualBehaviorType, expectedBehaviorType, lastObjectName);
diagnosticReport->Add(projectDiagnostic);
}
}
});
}
/**
* Generate code for an action.
*/
@@ -545,29 +494,15 @@ gd::String EventsCodeGenerator::GenerateActionCode(
action.SetParameters(parameters);
}
gd::EventsCodeGenerator::CheckBehaviorParameters(action, instrInfos);
// Verify that there are no mismatches between object type in parameters.
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
if (ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType())) {
gd::String objectInParameter = action.GetParameter(pNb).GetPlainString();
const auto &expectedObjectType =
instrInfos.parameters[pNb].GetExtraInfo();
const auto &actualObjectType =
GetObjectsContainersList().GetTypeOfObject(objectInParameter);
if (!GetObjectsContainersList().HasObjectOrGroupNamed(
objectInParameter)) {
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::UnknownObject, "",
objectInParameter, "");
diagnosticReport->Add(projectDiagnostic);
if (!GetObjectsContainersList().HasObjectOrGroupNamed(objectInParameter)) {
return "/* Unknown object - skipped. */";
} else if (!expectedObjectType.empty() &&
actualObjectType != expectedObjectType) {
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::MismatchedObjectType, "",
actualObjectType, expectedObjectType, objectInParameter);
diagnosticReport->Add(projectDiagnostic);
} else if (!instrInfos.parameters[pNb].GetExtraInfo().empty() &&
GetObjectsContainersList().GetTypeOfObject(objectInParameter) !=
instrInfos.parameters[pNb].GetExtraInfo()) {
return "/* Mismatched object type - skipped. */";
}
}
@@ -605,22 +540,17 @@ gd::String EventsCodeGenerator::GenerateActionCode(
}
}
} else if (instrInfos.IsBehaviorInstruction()) {
gd::String objectName = action.GetParameter(0).GetPlainString();
gd::String behaviorType = GetObjectsContainersList().GetTypeOfBehavior(action.GetParameter(1).GetPlainString());
if (instrInfos.parameters.size() >= 2) {
const gd::String &objectName = action.GetParameter(0).GetPlainString();
const gd::String &behaviorName = action.GetParameter(1).GetPlainString();
const gd::String &actualBehaviorType =
GetObjectsContainersList().GetTypeOfBehavior(behaviorName);
std::vector<gd::String> realObjects =
GetObjectsContainersList().ExpandObjectName(
objectName, context.GetCurrentObject());
const BehaviorMetadata &autoInfo =
MetadataProvider::GetBehaviorMetadata(platform, actualBehaviorType);
AddIncludeFiles(autoInfo.includeFiles);
GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
for (std::size_t i = 0; i < realObjects.size(); ++i) {
// Setup context
const BehaviorMetadata& autoInfo =
MetadataProvider::GetBehaviorMetadata(platform, behaviorType);
AddIncludeFiles(autoInfo.includeFiles);
context.SetCurrentObject(realObjects[i]);
context.ObjectsListNeeded(realObjects[i]);
@@ -629,7 +559,7 @@ gd::String EventsCodeGenerator::GenerateActionCode(
action.GetParameters(), instrInfos.parameters, context);
actionCode +=
GenerateBehaviorAction(realObjects[i],
behaviorName,
action.GetParameter(1).GetPlainString(),
autoInfo,
functionCallName,
arguments,
@@ -653,29 +583,6 @@ gd::String EventsCodeGenerator::GenerateActionCode(
return actionCode;
}
gd::String EventsCodeGenerator::GenerateLocalVariablesStackAccessor() {
return (HasProjectAndLayout() ? GetCodeNamespace()
: "eventsFunctionContext") +
".localVariables";
}
gd::String EventsCodeGenerator::GenerateAnyOrSceneVariableGetter(
const gd::Expression &variableExpression,
EventsCodeGenerationContext &context) {
const auto variableName = gd::ExpressionVariableNameFinder::GetVariableName(
*variableExpression.GetRootNode());
gd::String variableParameterType =
GetProjectScopedContainers().GetVariablesContainersList().Has(
variableName)
? "variable"
: "scenevar";
return gd::ExpressionCodeGenerator::GenerateExpressionCode(
*this, context, variableParameterType,
variableExpression.GetPlainString(), "", "AllowUndeclaredVariable");
}
const EventsCodeGenerator::CallbackDescriptor
EventsCodeGenerator::GenerateCallback(
const gd::String& callbackID,
@@ -700,20 +607,14 @@ 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" +
restoreLocalVariablesCode +
actionsDeclarationsCode + actionsCode + "}\n";
const gd::String callbackCode = callbackFunctionName + " = function (" +
GenerateEventsParameters(callbackContext) +
") {\n" + actionsDeclarationsCode +
actionsCode + "}\n";
AddCustomCodeOutsideMain(callbackCode);
@@ -776,13 +677,13 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
if (ParameterMetadata::IsExpression("number", metadata.GetType())) {
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
*this, context, "number", parameter, lastObjectName, metadata.GetExtraInfo());
*this, context, "number", parameter, lastObjectName);
} else if (ParameterMetadata::IsExpression("string", metadata.GetType())) {
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
*this, context, "string", parameter, lastObjectName, metadata.GetExtraInfo());
*this, context, "string", parameter, lastObjectName);
} else if (ParameterMetadata::IsExpression("variable", metadata.GetType())) {
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
*this, context, metadata.GetType(), parameter, lastObjectName, metadata.GetExtraInfo());
*this, context, metadata.GetType(), parameter, lastObjectName);
} 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.
@@ -794,8 +695,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
} else if (metadata.GetType() == "operator") {
argOutput += parameter.GetPlainString();
if (argOutput != "=" && argOutput != "+" && argOutput != "-" &&
argOutput != "/" && argOutput != "*" && argOutput != "True" &&
argOutput != "False" && argOutput != "Toggle") {
argOutput != "/" && argOutput != "*") {
cout << "Warning: Bad operator: Set to = by default." << endl;
argOutput = "=";
}
@@ -814,8 +714,6 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
metadata.GetType() == "tilesetResource" ||
metadata.GetType() == "videoResource" ||
metadata.GetType() == "model3DResource" ||
metadata.GetType() == "atlasResource" ||
metadata.GetType() == "spineResource" ||
// Deprecated, old parameter names:
metadata.GetType() == "password" || metadata.GetType() == "musicfile" ||
metadata.GetType() == "soundfile" || metadata.GetType() == "police") {
@@ -965,11 +863,6 @@ 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;
@@ -990,17 +883,13 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(
auto& context = reuseParentContext ? reusedContext : newContext;
gd::String eventCoreCode = event.GenerateEventCode(*this, context);
gd::String eventCoreCode = events[eId].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;
@@ -1176,8 +1065,7 @@ gd::String EventsCodeGenerator::GenerateFreeAction(
// Generate call
gd::String call;
if (instrInfos.codeExtraInformation.type == "number" ||
instrInfos.codeExtraInformation.type == "string" ||
instrInfos.codeExtraInformation.type == "boolean") {
instrInfos.codeExtraInformation.type == "string") {
if (instrInfos.codeExtraInformation.accessType ==
gd::InstructionMetadata::ExtraInformation::MutatorAndOrAccessor)
call = GenerateOperatorCall(
@@ -1361,8 +1249,7 @@ EventsCodeGenerator::EventsCodeGenerator(const gd::Project& project_,
compilationForRuntime(false),
maxCustomConditionsDepth(0),
maxConditionsListsSize(0),
eventsListNextUniqueId(0),
diagnosticReport(nullptr){};
eventsListNextUniqueId(0){};
EventsCodeGenerator::EventsCodeGenerator(
const gd::Platform& platform_,
@@ -1376,7 +1263,6 @@ EventsCodeGenerator::EventsCodeGenerator(
compilationForRuntime(false),
maxCustomConditionsDepth(0),
maxConditionsListsSize(0),
eventsListNextUniqueId(0),
diagnosticReport(nullptr){};
eventsListNextUniqueId(0){};
} // namespace gd

View File

@@ -3,7 +3,8 @@
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef GDCORE_EVENTSCODEGENERATOR_H
#define GDCORE_EVENTSCODEGENERATOR_H
#include <set>
#include <utility>
@@ -11,10 +12,8 @@
#include "GDCore/Events/Event.h"
#include "GDCore/Events/Instruction.h"
#include "GDCore/Events/CodeGeneration/DiagnosticReport.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/String.h"
namespace gd {
class EventsList;
class Expression;
@@ -337,16 +336,6 @@ 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.
@@ -383,14 +372,6 @@ class GD_CORE_API EventsCodeGenerator {
*/
size_t GetMaxConditionsListsSize() const { return maxConditionsListsSize; }
void SetDiagnosticReport(gd::DiagnosticReport* diagnosticReport_) {
diagnosticReport = diagnosticReport_;
}
gd::DiagnosticReport* GetDiagnosticReport() {
return diagnosticReport;
}
/**
* \brief Generate the full name for accessing to a boolean variable used for
* conditions.
@@ -467,7 +448,7 @@ class GD_CORE_API EventsCodeGenerator {
*/
virtual gd::String GetCodeNamespace() { return ""; };
enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE, ANY_VARIABLE };
enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE };
/**
* Generate a single unique number for the specified instruction.
@@ -497,20 +478,7 @@ 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();
/**
* \brief Generate an any variable getter that fallbacks on scene variable for
* compatibility reason.
*/
gd::String
GenerateAnyOrSceneVariableGetter(const gd::Expression &variableExpression,
EventsCodeGenerationContext &context);
protected:
protected:
virtual const gd::String GenerateRelationalOperatorCodes(
const gd::String& operatorString);
@@ -566,15 +534,11 @@ protected:
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 + ")";
@@ -815,10 +779,6 @@ protected:
virtual gd::String GenerateGetBehaviorNameCode(
const gd::String& behaviorName);
void CheckBehaviorParameters(
const gd::Instruction &instruction,
const gd::InstructionMetadata &instrInfos);
const gd::Platform& platform; ///< The platform being used.
gd::ProjectScopedContainers projectScopedContainers;
@@ -849,9 +809,8 @@ protected:
instructionUniqueIds; ///< The unique ids generated for instructions.
size_t eventsListNextUniqueId; ///< The next identifier to use for an events
///< list function name.
gd::DiagnosticReport* diagnosticReport;
};
} // namespace gd
#endif // GDCORE_EVENTSCODEGENERATOR_H

View File

@@ -31,7 +31,6 @@
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
#include "GDCore/Events/CodeGeneration/DiagnosticReport.h"
namespace gd {
@@ -40,8 +39,7 @@ gd::String ExpressionCodeGenerator::GenerateExpressionCode(
EventsCodeGenerationContext& context,
const gd::String& rootType,
const gd::Expression& expression,
const gd::String& rootObjectName,
const gd::String& extraInfo) {
const gd::String& rootObjectName) {
ExpressionCodeGenerator generator(rootType, rootObjectName, codeGenerator, context);
auto node = expression.GetRootNode();
@@ -54,34 +52,13 @@ gd::String ExpressionCodeGenerator::GenerateExpressionCode(
gd::ExpressionValidator validator(codeGenerator.GetPlatform(),
codeGenerator.GetProjectScopedContainers(),
rootType,
extraInfo);
rootType);
node->Visit(validator);
if (!validator.GetFatalErrors().empty()) {
std::cout << "Error: \"" << validator.GetFatalErrors()[0]->GetMessage()
<< "\" in: \"" << expression.GetPlainString() << "\" ("
<< rootType << ")" << std::endl;
auto *diagnosticReport = codeGenerator.GetDiagnosticReport();
if (diagnosticReport) {
for (auto *error : validator.GetFatalErrors()) {
if (error->GetType() ==
gd::ExpressionParserError::ErrorType::UndeclaredVariable ||
error->GetType() ==
gd::ExpressionParserError::ErrorType::UnknownIdentifier) {
const auto& variableName = error->GetActualValue();
if (!variableName.empty()) {
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::UndeclaredVariable,
error->GetMessage(), error->GetActualValue(),
"", error->GetObjectName());
diagnosticReport->Add(projectDiagnostic);
}
}
}
}
return generator.GenerateDefaultValue(rootType);
}
@@ -133,13 +110,11 @@ 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 == "variable"
? gd::EventsCodeGenerator::ANY_VARIABLE
: type == "globalvar"
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(),
@@ -162,8 +137,19 @@ void ExpressionCodeGenerator::OnVisitVariableNode(VariableNode& node) {
output += codeGenerator.GenerateVariableValueAs(type);
}, [&]() {
output += codeGenerator.GenerateGetVariable(
node.name, gd::EventsCodeGenerator::ANY_VARIABLE, context, "");
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, "");
if (node.child) node.child->Visit(*this);
output += codeGenerator.GenerateVariableValueAs(type);
}, [&]() {
@@ -223,13 +209,11 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
codeGenerator.GenerateObject(node.identifierName, type, context);
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
EventsCodeGenerator::VariableScope scope =
type == "variable"
? gd::EventsCodeGenerator::ANY_VARIABLE
: type == "globalvar"
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(),
@@ -252,9 +236,19 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
node.childIdentifierName, gd::EventsCodeGenerator::OBJECT_VARIABLE, context, node.identifierName);
output += codeGenerator.GenerateVariableValueAs(type);
}, [&]() {
output += codeGenerator.GenerateGetVariable(
node.identifierName, gd::EventsCodeGenerator::ANY_VARIABLE, context,
"");
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, "");
if (!node.childIdentifierName.empty()) {
output += codeGenerator.GenerateVariableAccessor(node.childIdentifierName);
}

View File

@@ -59,8 +59,7 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
EventsCodeGenerationContext& context,
const gd::String& type,
const gd::Expression& expression,
const gd::String& objectName = "",
const gd::String& extraInfo = "");
const gd::String& objectName = "");
const gd::String& GetOutput() { return output; };

View File

@@ -17,7 +17,6 @@
namespace gd {
EventsList BaseEvent::badSubEvents;
VariablesContainer BaseEvent::badLocalVariables;
std::vector<gd::String> BaseEvent::emptyDependencies;
gd::String BaseEvent::emptySourceFile;
@@ -29,8 +28,6 @@ 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) {

View File

@@ -3,7 +3,9 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#if defined(GD_IDE_ONLY)
#ifndef GDCORE_EVENT_H
#define GDCORE_EVENT_H
#include <iostream>
#include <memory>
@@ -24,7 +26,6 @@ class SerializerElement;
class Instruction;
class EventVisitor;
class ReadOnlyEventVisitor;
class VariablesContainer;
} // namespace gd
namespace gd {
@@ -91,32 +92,6 @@ 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.
@@ -326,7 +301,6 @@ 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;
};
@@ -351,3 +325,6 @@ class EmptyEvent : public BaseEvent {
};
} // namespace gd
#endif // GDCORE_EVENT_H
#endif

View File

@@ -38,7 +38,7 @@ using namespace gd::GrammarTerminals;
* parser by refactoring out the dependency on gd::MetadataProvider (injecting
* instead functions to be called to query supported functions).
*
* \see gd::ExpressionParserError
* \see gd::ExpressionParserDiagnostic
* \see gd::ExpressionNode
*/
class GD_CORE_API ExpressionParser2 {
@@ -547,28 +547,28 @@ class GD_CORE_API ExpressionParser2 {
}
///@}
std::unique_ptr<ExpressionParserError> ValidateOperator(
std::unique_ptr<ExpressionParserDiagnostic> ValidateOperator(
gd::String::value_type operatorChar) {
if (operatorChar == '+' || operatorChar == '-' || operatorChar == '/' ||
operatorChar == '*') {
return std::unique_ptr<ExpressionParserError>(nullptr);
return gd::make_unique<ExpressionParserDiagnostic>();
}
return gd::make_unique<ExpressionParserError>(
gd::ExpressionParserError::ErrorType::InvalidOperator,
"invalid_operator",
_("You've used an operator that is not supported. Operator should be "
"either +, -, / or *."),
GetCurrentPosition());
}
std::unique_ptr<ExpressionParserError> ValidateUnaryOperator(
std::unique_ptr<ExpressionParserDiagnostic> ValidateUnaryOperator(
gd::String::value_type operatorChar,
size_t position) {
if (operatorChar == '+' || operatorChar == '-') {
return std::unique_ptr<ExpressionParserError>(nullptr);
return gd::make_unique<ExpressionParserDiagnostic>();
}
return gd::make_unique<ExpressionParserError>(
gd::ExpressionParserError::ErrorType::InvalidOperator,
"invalid_operator",
_("You've used an \"unary\" operator that is not supported. Operator "
"should be "
"either + or -."),
@@ -719,15 +719,13 @@ class GD_CORE_API ExpressionParser2 {
std::unique_ptr<ExpressionParserError> RaiseSyntaxError(
const gd::String &message) {
return std::move(gd::make_unique<ExpressionParserError>(
gd::ExpressionParserError::ErrorType::SyntaxError, message,
GetCurrentPosition()));
"syntax_error", message, GetCurrentPosition()));
}
std::unique_ptr<ExpressionParserError> RaiseTypeError(
const gd::String &message, size_t beginningPosition) {
return std::move(gd::make_unique<ExpressionParserError>(
gd::ExpressionParserError::ErrorType::MismatchedType, message,
beginningPosition, GetCurrentPosition()));
"type_error", message, beginningPosition, GetCurrentPosition()));
}
///@}

View File

@@ -6,5 +6,5 @@
#include "ExpressionParser2Node.h"
namespace gd {
gd::String ExpressionParserDiagnostic::noMessage = "";
}

View File

@@ -3,14 +3,14 @@
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef GDCORE_EXPRESSIONPARSER2NODES_H
#define GDCORE_EXPRESSIONPARSER2NODES_H
#include <memory>
#include <vector>
#include "ExpressionParser2NodeWorker.h"
#include "GDCore/String.h"
namespace gd {
class Expression;
class ObjectsContainer;
@@ -40,56 +40,50 @@ struct GD_CORE_API ExpressionParserLocation {
size_t endPosition;
};
/**
* \brief A diagnostic that can be attached to a gd::ExpressionNode.
*/
struct GD_CORE_API ExpressionParserDiagnostic {
virtual ~ExpressionParserDiagnostic() = default;
virtual bool IsError() { return false; }
virtual const gd::String &GetMessage() { return noMessage; }
virtual size_t GetStartPosition() { return 0; }
virtual size_t GetEndPosition() { return 0; }
private:
static gd::String noMessage;
};
/**
* \brief An error that can be attached to a gd::ExpressionNode.
*/
struct GD_CORE_API ExpressionParserError {
enum ErrorType {
SyntaxError,
InvalidOperator,
MismatchedType,
UndeclaredVariable,
UnknownIdentifier,
BracketsNotAllowedForObjects,
TooFewParameters,
TooManyParameters,
InvalidFunctionName,
MalformedVariableParameter,
MalformedObjectParameter,
UnknownParameterType,
MissingBehavior,
};
ExpressionParserError(gd::ExpressionParserError::ErrorType type_,
struct GD_CORE_API ExpressionParserError : public ExpressionParserDiagnostic {
ExpressionParserError(const gd::String &type_,
const gd::String &message_,
const ExpressionParserLocation &location_,
const gd::String &actualValue_ = "",
const gd::String &objectName_ = "")
: type(type_), message(message_), location(location_),
actualValue(actualValue_), objectName(objectName_){};
ExpressionParserError(gd::ExpressionParserError::ErrorType type_,
const gd::String &message_, size_t position_)
const ExpressionParserLocation &location_)
: type(type_), message(message_), location(location_){};
ExpressionParserError(const gd::String &type_,
const gd::String &message_,
size_t position_)
: type(type_), message(message_), location(position_){};
ExpressionParserError(gd::ExpressionParserError::ErrorType type_,
const gd::String &message_, size_t startPosition_,
ExpressionParserError(const gd::String &type_,
const gd::String &message_,
size_t startPosition_,
size_t endPosition_)
: type(type_), message(message_),
: type(type_),
message(message_),
location(startPosition_, endPosition_){};
virtual ~ExpressionParserError(){};
gd::ExpressionParserError::ErrorType GetType() { return type; }
const gd::String &GetMessage() { return message; }
const gd::String &GetObjectName() { return objectName; }
const gd::String &GetActualValue() { return actualValue; }
size_t GetStartPosition() { return location.GetStartPosition(); }
size_t GetEndPosition() { return location.GetEndPosition(); }
bool IsError() override { return true; }
const gd::String &GetMessage() override { return message; }
size_t GetStartPosition() override { return location.GetStartPosition(); }
size_t GetEndPosition() override { return location.GetEndPosition(); }
private:
gd::ExpressionParserError::ErrorType type;
private:
gd::String type;
gd::String message;
ExpressionParserLocation location;
gd::String objectName;
gd::String actualValue;
};
/**
@@ -101,7 +95,7 @@ struct GD_CORE_API ExpressionNode {
virtual ~ExpressionNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker){};
std::unique_ptr<ExpressionParserError> diagnostic;
std::unique_ptr<ExpressionParserDiagnostic> diagnostic;
ExpressionParserLocation location; ///< The location of the entire node. Some
/// nodes might have other locations
/// stored inside them. For example, a
@@ -431,3 +425,5 @@ struct GD_CORE_API EmptyNode : public FunctionCallOrObjectFunctionNameOrEmptyNod
};
} // namespace gd
#endif

View File

@@ -66,7 +66,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
// Deprecated
extension
.AddAction("CopyArgumentToVariable",
_("Copy function parameter to variable"),
@@ -79,25 +78,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
.SetHelpPath("/events/functions/return")
.AddParameter("functionParameterName", _("Parameter name"), "variable")
.AddParameter("scenevar", _("Scene variable"))
.SetHidden()
.MarkAsAdvanced();
extension
.AddAction("CopyArgumentToVariable2",
_("Copy function parameter to variable"),
_("Copy a function parameter (also called \"argument\") to a variable. "
"The parameter type must be a variable."),
_("Copy the parameter _PARAM0_ into the variable _PARAM1_"),
"",
"res/function32.png",
"res/function32.png")
.SetHelpPath("/events/functions/return")
.AddParameter("functionParameterName", _("Parameter name"), "variable")
.AddParameter("variable", _("Variable"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
// Deprecated
extension
.AddAction("CopyVariableToArgument",
_("Copy variable to function parameter"),
@@ -110,21 +93,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
.SetHelpPath("/events/functions/return")
.AddParameter("functionParameterName", _("Parameter name"), "variable")
.AddParameter("scenevar", _("Scene variable"))
.SetHidden()
.MarkAsAdvanced();
extension
.AddAction("CopyVariableToArgument2",
_("Copy variable to function parameter"),
_("Copy a variable to function parameter (also called \"argument\"). "
"The parameter type must be a variable."),
_("Copy the variable _PARAM1_ into the parameter _PARAM0_"),
"",
"res/function32.png",
"res/function32.png")
.SetHelpPath("/events/functions/return")
.AddParameter("functionParameterName", _("Parameter name"), "variable")
.AddParameter("variable", _("Variable"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();

View File

@@ -417,93 +417,6 @@ 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."),
@@ -515,8 +428,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
ParameterOptions::MakeNewOptions());
obj.AddAction("ModVarObjetTxt",
_("Change text variable"),
@@ -529,8 +441,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardOperatorParameters("string",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
ParameterOptions::MakeNewOptions());
obj.AddAction("SetObjectVariableAsBoolean",
_("Change boolean variable"),
@@ -543,8 +454,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.AddParameter("trueorfalse", _("New Value:"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("trueorfalse", _("New Value:"));
obj.AddAction(
"ToggleObjectVariableAsBoolean",
@@ -559,8 +469,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("objectvar", _("Variable"));
obj.AddCondition("ObjectVariableChildExists",
_("Child existence"),
@@ -748,8 +657,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
"number", ParameterOptions::MakeNewOptions());
obj.AddCondition("VarObjetTxt",
_("Text variable"),
@@ -762,8 +670,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"string", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
"string", ParameterOptions::MakeNewOptions());
obj.AddCondition("ObjectVariableAsBoolean",
_("Boolean variable"),
@@ -776,8 +683,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true")
.SetRelevantForFunctionEventsOnly();
.SetDefaultValue("true");
obj.AddCondition("VarObjetDef",
"Variable defined",
@@ -791,48 +697,6 @@ 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();
// Deprecated
obj.AddAction(
"ObjectVariablePush",
_("Add existing variable"),
@@ -844,23 +708,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("scenevar", _("Scene variable with the content to add"))
.SetParameterLongDescription(_("The content of the object variable will "
"*be copied* and added at the "
"end of the array."))
.MarkAsAdvanced()
.SetHidden();
obj.AddAction(
"ObjectVariablePush2",
_("Add existing variable"),
_("Adds an existing variable to the end of an object array variable."),
_("Add variable _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("variable", _("Scene variable with the content to add"))
.SetParameterLongDescription(_("The content of the object variable will "
"*be copied* and added at the "
"end of the array."))
@@ -877,8 +724,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("string", _("Text to add"))
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
.MarkAsAdvanced();
obj.AddAction("ObjectVariablePushNumber",
_("Add number variable"),
@@ -890,8 +736,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("expression", _("Number to add"))
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
.MarkAsAdvanced();
obj.AddAction(
"ObjectVariablePushBool",
@@ -904,8 +749,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("trueorfalse", _("Boolean to add"))
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
.MarkAsAdvanced();
obj.AddAction(
"ObjectVariableRemoveAt",
@@ -1359,8 +1203,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Variables"),
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("objectvar", _("Variable"));
obj.AddExpression(
"VariableChildCount",
@@ -1438,8 +1281,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Enable an effect on the object"),
_("Enable effect _PARAM1_ on _PARAM0_: _PARAM2_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("yesorno", _("Enable?"))
@@ -1454,8 +1297,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"names) in the effects window."),
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
@@ -1472,8 +1315,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"names) in the effects window."),
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
@@ -1489,8 +1332,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"names) in the effects window."),
_("Enable _PARAM2_ for effect _PARAM1_ of _PARAM0_: _PARAM3_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
@@ -1504,8 +1347,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Check if the effect on an object is enabled."),
_("Effect _PARAM1_ of _PARAM0_ is enabled"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.MarkAsSimple()

View File

@@ -27,7 +27,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
extension.AddInstructionOrExpressionGroupMetadata(_("Layers and cameras"))
.SetIcon("res/conditions/camera24.png");
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
.SetIcon("res/actions/effect_black.svg");
.SetIcon("res/actions/effect24.png");
extension
.AddExpressionAndConditionAndAction(
@@ -450,8 +450,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of layer _PARAM1_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
@@ -469,8 +469,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of layer _PARAM1_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
@@ -488,8 +488,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"names) in the effects window."),
_("Enable _PARAM3_ for effect _PARAM2_ of layer _PARAM1_: _PARAM4_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
@@ -504,8 +504,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
_("The effect on a layer is enabled"),
_("Effect _PARAM2_ on layer _PARAM1_ is enabled"),
_(""),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
@@ -518,8 +518,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
_("Enable an effect on a layer"),
_("Enable effect _PARAM2_ on layer _PARAM1_: _PARAM3_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")

View File

@@ -24,7 +24,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
"Open source (MIT License)")
.SetExtensionHelpPath("/objects");
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
.SetIcon("res/actions/effect_black.svg");
.SetIcon("res/actions/effect24.png");
gd::BehaviorMetadata& aut = extension.AddBehavior(
"EffectBehavior",
@@ -32,7 +32,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
"Effect",
_("Apply visual effects to objects."),
"",
"res/actions/effect_black.svg",
"res/actions/effect24.png",
"EffectBehavior",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
@@ -43,8 +43,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
_("Enable an effect on the object"),
_("Enable effect _PARAM2_ on _PARAM0_: _PARAM3_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
@@ -58,8 +58,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
@@ -75,8 +75,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
@@ -91,8 +91,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
"names) in the effects window."),
_("Enable _PARAM3_ for effect _PARAM2_ of _PARAM0_: _PARAM4_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
@@ -105,8 +105,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
_("Check if the effect on an object is enabled."),
_("Effect _PARAM2_ of _PARAM0_ is enabled"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))

View File

@@ -24,7 +24,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFlippableExtension(
"Open source (MIT License)")
.SetExtensionHelpPath("/objects");
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
.SetIcon("res/actions/effect_black.svg");
.SetIcon("res/actions/effect24.png");
gd::BehaviorMetadata& aut = extension.AddBehavior(
"FlippableBehavior",

View File

@@ -68,22 +68,19 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
extension
.AddStrExpression("ToJSON",
_("Convert variable to JSON"),
_("Convert a variable to JSON"),
_("Convert scene variable to JSON"),
_("Convert a scene variable to JSON"),
_("JSON"),
"res/conditions/toujours24_black.png")
.AddParameter("variable", _("The variable to be stringified"),
"AllowUndeclaredVariable");
.AddParameter("scenevar", _("Scene variable to be stringified"));
// Deprecated
extension
.AddStrExpression("GlobalVarToJSON",
_("Convert global variable to JSON"),
_("Convert a global variable to JSON"),
_("JSON"),
"res/conditions/toujours24_black.png")
.AddParameter("globalvar", _("The global variable to be stringified"))
.SetHidden();
.AddParameter("globalvar", _("The global variable to be stringified"));
extension
.AddStrExpression("ObjectVarToJSON",
@@ -94,7 +91,6 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
.AddParameter("objectPtr", _("The object with the variable"))
.AddParameter("objectvar", _("The object variable to be stringified"));
// Deprecated
extension
.AddAction(
"JSONToVariableStructure",
@@ -106,10 +102,8 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
"res/actions/net.png")
.AddParameter("string", _("JSON string"))
.AddParameter("scenevar", _("Variable where store the JSON object"))
.MarkAsAdvanced()
.SetHidden();
.MarkAsAdvanced();
// Deprecated
extension
.AddAction("JSONToGlobalVariableStructure",
_("Convert JSON to global variable"),
@@ -122,20 +116,6 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
.AddParameter("string", _("JSON string"))
.AddParameter("globalvar",
_("Global variable where store the JSON object"))
.MarkAsAdvanced()
.SetHidden();
extension
.AddAction(
"JSONToVariableStructure2",
_("Convert JSON to a variable"),
_("Parse a JSON object and store it into a variable"),
_("Convert JSON string _PARAM0_ and store it into variable _PARAM1_"),
"",
"res/actions/net24.png",
"res/actions/net.png")
.AddParameter("string", _("JSON string"))
.AddParameter("variable", _("Variable where to store the JSON object"))
.MarkAsAdvanced();
extension

View File

@@ -98,7 +98,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
.AddParameter("string", _("Group"))
.AddParameter("string", _("Text"));
// Deprecated
extension
.AddAction(
"LireFichierExp",
@@ -115,27 +114,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
.AddParameter("string", _("Storage name"))
.AddParameter("string", _("Group"))
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("scenevar", _("Scene variable"))
.SetHidden();
.AddParameter("scenevar", _("Scene variables"));
extension
.AddAction(
"ReadNumberFromStorage",
_("Load a value"),
_("Load the value saved in the specified element and store it in a "
"variable.\nSpecify the structure leading to the element using / "
"(example : Root/Level/Current)\nSpaces are forbidden in element "
"names."),
_("Load _PARAM1_ from storage _PARAM0_ and store value in _PARAM3_"),
"",
"res/actions/fichier24.png",
"res/actions/fichier.png")
.AddParameter("string", _("Storage name"))
.AddParameter("string", _("Group"))
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("variable", _("Variable"));
// Deprecated
extension
.AddAction(
"LireFichierTxt",
@@ -153,26 +133,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
.AddParameter("string", _("Storage name"))
.AddParameter("string", _("Group"))
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("scenevar", _("Scene variable"))
.SetHidden();
extension
.AddAction(
"ReadStringFromStorage",
_("Load a text"),
_("Load the text saved in the specified element and store it in a "
"variable.\nSpecify the structure leading to the element using / "
"(example : Root/Level/Current)\nSpaces are forbidden in element "
"names."),
_("Load _PARAM1_ from storage _PARAM0_ and store as text in "
"_PARAM3_"),
"",
"res/actions/fichier24.png",
"res/actions/fichier.png")
.AddParameter("string", _("Storage name"))
.AddParameter("string", _("Group"))
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("variable", _("Variable"));
.AddParameter("scenevar", _("Scene variables"));
extension
.AddAction("DeleteGroupFichier",

View File

@@ -6,6 +6,8 @@
#include "GDCore/Extensions/Builtin/SpriteExtension/Animation.h"
#include <vector>
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
#include "GDCore/String.h"
namespace gd {

View File

@@ -4,11 +4,13 @@
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef GDCORE_ANIMATION_H
#define GDCORE_ANIMATION_H
#include <vector>
#include "GDCore/String.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
namespace gd {
class Direction;
}
namespace gd {
@@ -91,3 +93,4 @@ class GD_CORE_API Animation {
};
} // namespace gd
#endif // GDCORE_ANIMATION_H

View File

@@ -3,12 +3,12 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef GDCORE_DIRECTION_H
#define GDCORE_DIRECTION_H
#include <vector>
#include "GDCore/String.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
namespace gd {
class Sprite;
class SerializerElement;
}
@@ -142,3 +142,4 @@ class GD_CORE_API Direction {
};
} // namespace gd
#endif // GDCORE_DIRECTION_H

View File

@@ -1,157 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteAnimationList.h"
#include <algorithm>
#include "GDCore/CommonTools.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Animation.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/Project/InitialInstance.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/Localization.h"
namespace gd {
Animation SpriteAnimationList::badAnimation;
SpriteAnimationList::SpriteAnimationList()
: adaptCollisionMaskAutomatically(true) {}
SpriteAnimationList::~SpriteAnimationList(){};
void SpriteAnimationList::UnserializeFrom(const gd::SerializerElement& element) {
adaptCollisionMaskAutomatically =
element.GetBoolAttribute("adaptCollisionMaskAutomatically", false);
RemoveAllAnimations();
const gd::SerializerElement& animationsElement =
element.GetChild("animations", 0, "Animations");
animationsElement.ConsiderAsArrayOf("animation", "Animation");
for (std::size_t i = 0; i < animationsElement.GetChildrenCount(); ++i) {
const gd::SerializerElement& animationElement =
animationsElement.GetChild(i);
Animation newAnimation;
newAnimation.useMultipleDirections = animationElement.GetBoolAttribute(
"useMultipleDirections", false, "typeNormal");
newAnimation.SetName(animationElement.GetStringAttribute("name", ""));
// Compatibility with GD <= 3.3
if (animationElement.HasChild("Direction")) {
for (std::size_t j = 0;
j < animationElement.GetChildrenCount("Direction");
++j) {
Direction direction;
direction.UnserializeFrom(animationElement.GetChild("Direction", j));
newAnimation.SetDirectionsCount(newAnimation.GetDirectionsCount() + 1);
newAnimation.SetDirection(direction,
newAnimation.GetDirectionsCount() - 1);
}
}
// End of compatibility code
else {
const gd::SerializerElement& directionsElement =
animationElement.GetChild("directions");
directionsElement.ConsiderAsArrayOf("direction");
for (std::size_t j = 0; j < directionsElement.GetChildrenCount(); ++j) {
Direction direction;
direction.UnserializeFrom(directionsElement.GetChild(j));
newAnimation.SetDirectionsCount(newAnimation.GetDirectionsCount() + 1);
newAnimation.SetDirection(direction,
newAnimation.GetDirectionsCount() - 1);
}
}
AddAnimation(newAnimation);
}
}
void SpriteAnimationList::SerializeTo(gd::SerializerElement& element) const {
element.SetAttribute("adaptCollisionMaskAutomatically",
adaptCollisionMaskAutomatically);
// Animations
gd::SerializerElement& animationsElement = element.AddChild("animations");
animationsElement.ConsiderAsArrayOf("animation");
for (std::size_t k = 0; k < GetAnimationsCount(); k++) {
gd::SerializerElement& animationElement =
animationsElement.AddChild("animation");
animationElement.SetAttribute("useMultipleDirections",
GetAnimation(k).useMultipleDirections);
animationElement.SetAttribute("name", GetAnimation(k).GetName());
gd::SerializerElement& directionsElement =
animationElement.AddChild("directions");
directionsElement.ConsiderAsArrayOf("direction");
for (std::size_t l = 0; l < GetAnimation(k).GetDirectionsCount(); l++) {
GetAnimation(k).GetDirection(l).SerializeTo(
directionsElement.AddChild("direction"));
}
}
}
void SpriteAnimationList::ExposeResources(gd::ArbitraryResourceWorker& worker) {
for (std::size_t j = 0; j < GetAnimationsCount(); j++) {
for (std::size_t k = 0; k < GetAnimation(j).GetDirectionsCount(); k++) {
for (std::size_t l = 0;
l < GetAnimation(j).GetDirection(k).GetSpritesCount();
l++) {
worker.ExposeImage(
GetAnimation(j).GetDirection(k).GetSprite(l).GetImageName());
}
}
}
}
const Animation& SpriteAnimationList::GetAnimation(std::size_t nb) const {
if (nb >= animations.size()) return badAnimation;
return animations[nb];
}
Animation& SpriteAnimationList::GetAnimation(std::size_t nb) {
if (nb >= animations.size()) return badAnimation;
return animations[nb];
}
void SpriteAnimationList::AddAnimation(const Animation& animation) {
animations.push_back(animation);
}
bool SpriteAnimationList::RemoveAnimation(std::size_t nb) {
if (nb >= GetAnimationsCount()) return false;
animations.erase(animations.begin() + nb);
return true;
}
void SpriteAnimationList::SwapAnimations(std::size_t firstIndex,
std::size_t secondIndex) {
if (firstIndex < animations.size() && secondIndex < animations.size() &&
firstIndex != secondIndex)
std::swap(animations[firstIndex], animations[secondIndex]);
}
void SpriteAnimationList::MoveAnimation(std::size_t oldIndex, std::size_t newIndex) {
if (oldIndex >= animations.size() || newIndex >= animations.size()) return;
auto animation = animations[oldIndex];
animations.erase(animations.begin() + oldIndex);
animations.insert(animations.begin() + newIndex, animation);
}
} // namespace gd

View File

@@ -1,119 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include "GDCore/Extensions/Builtin/SpriteExtension/Animation.h"
namespace gd {
class InitialInstance;
class SerializerElement;
class PropertyDescriptor;
class ArbitraryResourceWorker;
} // namespace gd
namespace gd {
/**
* \brief A list of animations, containing directions with images and collision mask.
*
* It's used in the configuration of object that implements image-based animations.
*
* \see Animation
* \see Direction
* \see Sprite
* \ingroup SpriteObjectExtension
*/
class GD_CORE_API SpriteAnimationList {
public:
SpriteAnimationList();
virtual ~SpriteAnimationList();
void ExposeResources(gd::ArbitraryResourceWorker& worker);
/**
* \brief Return the animation at the specified index.
* If the index is out of bound, a "bad animation" object is returned.
*/
const Animation& GetAnimation(std::size_t nb) const;
/**
* \brief Return the animation at the specified index.
* If the index is out of bound, a "bad animation" object is returned.
*/
Animation& GetAnimation(std::size_t nb);
/**
* \brief Return the number of animations this object has.
*/
std::size_t GetAnimationsCount() const { return animations.size(); };
/**
* \brief Add an animation at the end of the existing ones.
*/
void AddAnimation(const Animation& animation);
/**
* \brief Remove an animation.
*/
bool RemoveAnimation(std::size_t nb);
/**
* \brief Remove all animations.
*/
void RemoveAllAnimations() { animations.clear(); }
/**
* \brief Return true if the object hasn't any animation.
*/
bool HasNoAnimations() const { return animations.empty(); }
/**
* \brief Swap the position of two animations
*/
void SwapAnimations(std::size_t firstIndex, std::size_t secondIndex);
/**
* \brief Change the position of the specified animation
*/
void MoveAnimation(std::size_t oldIndex, std::size_t newIndex);
/**
* \brief Return a read-only reference to the vector containing all the
* animation of the object.
*/
const std::vector<Animation>& GetAllAnimations() const { return animations; }
/**
* @brief Check if the collision mask adapts automatically to the animation.
*/
bool AdaptCollisionMaskAutomatically() const {
return adaptCollisionMaskAutomatically;
}
/**
* @brief Set if the collision mask adapts automatically to the animation.
*/
void SetAdaptCollisionMaskAutomatically(bool enable) {
adaptCollisionMaskAutomatically = enable;
}
void UnserializeFrom(const gd::SerializerElement& element);
void SerializeTo(gd::SerializerElement& element) const;
private:
mutable std::vector<Animation> animations;
static Animation badAnimation; //< Bad animation when an out of bound
// animation is requested.
bool adaptCollisionMaskAutomatically; ///< If set to true, the collision
///< mask will be automatically
///< adapted to the animation of the
///< object.
};
} // namespace gd

View File

@@ -23,20 +23,88 @@
namespace gd {
Animation SpriteObject::badAnimation;
SpriteObject::SpriteObject()
: updateIfNotVisible(false) {}
: updateIfNotVisible(false), adaptCollisionMaskAutomatically(true) {}
SpriteObject::~SpriteObject(){};
void SpriteObject::DoUnserializeFrom(gd::Project& project,
const gd::SerializerElement& element) {
updateIfNotVisible = element.GetBoolAttribute("updateIfNotVisible", true);
animations.UnserializeFrom(element);
adaptCollisionMaskAutomatically =
element.GetBoolAttribute("adaptCollisionMaskAutomatically", false);
RemoveAllAnimations();
const gd::SerializerElement& animationsElement =
element.GetChild("animations", 0, "Animations");
animationsElement.ConsiderAsArrayOf("animation", "Animation");
for (std::size_t i = 0; i < animationsElement.GetChildrenCount(); ++i) {
const gd::SerializerElement& animationElement =
animationsElement.GetChild(i);
Animation newAnimation;
newAnimation.useMultipleDirections = animationElement.GetBoolAttribute(
"useMultipleDirections", false, "typeNormal");
newAnimation.SetName(animationElement.GetStringAttribute("name", ""));
// Compatibility with GD <= 3.3
if (animationElement.HasChild("Direction")) {
for (std::size_t j = 0;
j < animationElement.GetChildrenCount("Direction");
++j) {
Direction direction;
direction.UnserializeFrom(animationElement.GetChild("Direction", j));
newAnimation.SetDirectionsCount(newAnimation.GetDirectionsCount() + 1);
newAnimation.SetDirection(direction,
newAnimation.GetDirectionsCount() - 1);
}
}
// End of compatibility code
else {
const gd::SerializerElement& directionsElement =
animationElement.GetChild("directions");
directionsElement.ConsiderAsArrayOf("direction");
for (std::size_t j = 0; j < directionsElement.GetChildrenCount(); ++j) {
Direction direction;
direction.UnserializeFrom(directionsElement.GetChild(j));
newAnimation.SetDirectionsCount(newAnimation.GetDirectionsCount() + 1);
newAnimation.SetDirection(direction,
newAnimation.GetDirectionsCount() - 1);
}
}
AddAnimation(newAnimation);
}
}
void SpriteObject::DoSerializeTo(gd::SerializerElement& element) const {
element.SetAttribute("updateIfNotVisible", updateIfNotVisible);
animations.SerializeTo(element);
element.SetAttribute("adaptCollisionMaskAutomatically",
adaptCollisionMaskAutomatically);
// Animations
gd::SerializerElement& animationsElement = element.AddChild("animations");
animationsElement.ConsiderAsArrayOf("animation");
for (std::size_t k = 0; k < GetAnimationsCount(); k++) {
gd::SerializerElement& animationElement =
animationsElement.AddChild("animation");
animationElement.SetAttribute("useMultipleDirections",
GetAnimation(k).useMultipleDirections);
animationElement.SetAttribute("name", GetAnimation(k).GetName());
gd::SerializerElement& directionsElement =
animationElement.AddChild("directions");
directionsElement.ConsiderAsArrayOf("direction");
for (std::size_t l = 0; l < GetAnimation(k).GetDirectionsCount(); l++) {
GetAnimation(k).GetDirection(l).SerializeTo(
directionsElement.AddChild("direction"));
}
}
}
std::map<gd::String, gd::PropertyDescriptor> SpriteObject::GetProperties()
@@ -59,7 +127,16 @@ bool SpriteObject::UpdateProperty(const gd::String& name,
}
void SpriteObject::ExposeResources(gd::ArbitraryResourceWorker& worker) {
animations.ExposeResources(worker);
for (std::size_t j = 0; j < GetAnimationsCount(); j++) {
for (std::size_t k = 0; k < GetAnimation(j).GetDirectionsCount(); k++) {
for (std::size_t l = 0;
l < GetAnimation(j).GetDirection(k).GetSpritesCount();
l++) {
worker.ExposeImage(
GetAnimation(j).GetDirection(k).GetSprite(l).GetImageName());
}
}
}
}
std::map<gd::String, gd::PropertyDescriptor>
@@ -91,12 +168,42 @@ bool SpriteObject::UpdateInitialInstanceProperty(
return true;
}
const SpriteAnimationList& SpriteObject::GetAnimations() const {
return animations;
const Animation& SpriteObject::GetAnimation(std::size_t nb) const {
if (nb >= animations.size()) return badAnimation;
return animations[nb];
}
SpriteAnimationList& SpriteObject::GetAnimations() {
return animations;
Animation& SpriteObject::GetAnimation(std::size_t nb) {
if (nb >= animations.size()) return badAnimation;
return animations[nb];
}
void SpriteObject::AddAnimation(const Animation& animation) {
animations.push_back(animation);
}
bool SpriteObject::RemoveAnimation(std::size_t nb) {
if (nb >= GetAnimationsCount()) return false;
animations.erase(animations.begin() + nb);
return true;
}
void SpriteObject::SwapAnimations(std::size_t firstIndex,
std::size_t secondIndex) {
if (firstIndex < animations.size() && secondIndex < animations.size() &&
firstIndex != secondIndex)
std::swap(animations[firstIndex], animations[secondIndex]);
}
void SpriteObject::MoveAnimation(std::size_t oldIndex, std::size_t newIndex) {
if (oldIndex >= animations.size() || newIndex >= animations.size()) return;
auto animation = animations[oldIndex];
animations.erase(animations.begin() + oldIndex);
animations.insert(animations.begin() + newIndex, animation);
}
} // namespace gd

View File

@@ -4,15 +4,18 @@
* reserved. This project is released under the MIT License.
*/
#pragma once
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteAnimationList.h"
#ifndef GDCORE_SPRITEOBJECT_H
#define GDCORE_SPRITEOBJECT_H
#include "GDCore/Extensions/Builtin/SpriteExtension/Animation.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
#include "GDCore/Project/Object.h"
namespace gd {
class InitialInstance;
class Object;
class Layout;
class Sprite;
class Animation;
class SerializerElement;
class PropertyDescriptor;
} // namespace gd
@@ -56,15 +59,76 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
gd::Project& project,
gd::Layout& scene) override;
/**
* \brief Return the animation configuration.
/** \name Animations
* Methods related to animations management
*/
const SpriteAnimationList& GetAnimations() const;
///@{
/**
* \brief Return the animation at the specified index.
* If the index is out of bound, a "bad animation" object is returned.
*/
const Animation& GetAnimation(std::size_t nb) const;
/**
* @brief Return the animation configuration.
* \brief Return the animation at the specified index.
* If the index is out of bound, a "bad animation" object is returned.
*/
SpriteAnimationList& GetAnimations();
Animation& GetAnimation(std::size_t nb);
/**
* \brief Return the number of animations this object has.
*/
std::size_t GetAnimationsCount() const { return animations.size(); };
/**
* \brief Add an animation at the end of the existing ones.
*/
void AddAnimation(const Animation& animation);
/**
* \brief Remove an animation.
*/
bool RemoveAnimation(std::size_t nb);
/**
* \brief Remove all animations.
*/
void RemoveAllAnimations() { animations.clear(); }
/**
* \brief Return true if the object hasn't any animation.
*/
bool HasNoAnimations() const { return animations.empty(); }
/**
* \brief Swap the position of two animations
*/
void SwapAnimations(std::size_t firstIndex, std::size_t secondIndex);
/**
* \brief Change the position of the specified animation
*/
void MoveAnimation(std::size_t oldIndex, std::size_t newIndex);
/**
* \brief Return a read-only reference to the vector containing all the
* animation of the object.
*/
const std::vector<Animation>& GetAllAnimations() const { return animations; }
/**
* @brief Check if the collision mask adapts automatically to the animation.
*/
bool AdaptCollisionMaskAutomatically() const {
return adaptCollisionMaskAutomatically;
}
/**
* @brief Set if the collision mask adapts automatically to the animation.
*/
void SetAdaptCollisionMaskAutomatically(bool enable) {
adaptCollisionMaskAutomatically = enable;
}
/**
* \brief Set if the object animation should be played even if the object is
@@ -79,17 +143,25 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
* is hidden or far from the camera (false by default).
*/
bool GetUpdateIfNotVisible() const { return updateIfNotVisible; }
///@}
private:
void DoUnserializeFrom(gd::Project& project,
const gd::SerializerElement& element) override;
void DoSerializeTo(gd::SerializerElement& element) const override;
SpriteAnimationList animations;
mutable std::vector<Animation> animations;
bool updateIfNotVisible; ///< If set to true, ask the game engine to play
///< object animation even if hidden or far from
///< the screen.
static Animation badAnimation; //< Bad animation when an out of bound
// animation is requested.
bool adaptCollisionMaskAutomatically; ///< If set to true, the collision
///< mask will be automatically
///< adapted to the animation of the
///< object.
};
} // namespace gd
#endif // GDCORE_SPRITEOBJECT_H

View File

@@ -25,275 +25,29 @@ 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_"),
_("External variables/Scene variables"),
_("Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
"number", ParameterOptions::MakeNewOptions());
extension
.AddCondition("VarSceneTxt",
_("Text variable"),
_("Compare the text (string) of a scene variable."),
_("The text of scene variable _PARAM0_"),
_("External variables/Scene variables"),
_("Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"string", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
"string", ParameterOptions::MakeNewOptions());
extension
.AddCondition(
@@ -301,13 +55,12 @@ 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_"),
_("External variables/Scene variables"),
_("Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true")
.SetRelevantForFunctionEventsOnly();
.SetDefaultValue("true");
extension
.AddCondition("VariableChildExists",
@@ -315,12 +68,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Check if the specified child of the scene structure "
"variable exists."),
_("Child _PARAM1_ of scene variable _PARAM0_ exists"),
_("External variables/Scene variables/Arrays and structures"),
_("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
@@ -329,12 +81,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Check if the specified child of the global structure "
"variable exists."),
_("Child _PARAM1_ of global variable _PARAM0_ exists"),
_("External variables/Global variables/Arrays and structures"),
_("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
@@ -342,7 +93,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"Variable defined",
"Test if the scene variable exists.",
"Scene variable _PARAM0_ is defined",
_("External variables/Scene variables"),
_("Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddCodeOnlyParameter("currentScene", "")
@@ -354,13 +105,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Number variable"),
_("Compare the number value of a global variable."),
_("the global variable _PARAM0_"),
_("External variables/Global variables"),
_("Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -368,13 +118,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Text variable"),
_("Compare the text (string) of a global variable."),
_("the text of the global variable _PARAM0_"),
_("External variables/Global variables"),
_("Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"string", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -383,20 +132,19 @@ 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_"),
_("External variables/Global variables"),
_("Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true")
.SetRelevantForFunctionEventsOnly();
.SetDefaultValue("true");
extension
.AddCondition("VarGlobalDef",
"Variable defined",
"Test if a global variable exists.",
"Global variable _PARAM0_ is defined",
_("External variables/Global variables"),
_("Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddCodeOnlyParameter("currentScene", "")
@@ -409,26 +157,24 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Change number variable"),
_("Modify the number value of a scene variable."),
_("the scene variable _PARAM0_"),
_("External variables/Scene variables"),
_("Scene variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
ParameterOptions::MakeNewOptions());
extension
.AddAction("ModVarSceneTxt",
_("Change text variable"),
_("Modify the text (string) of a scene variable."),
_("the text of scene variable _PARAM0_"),
_("External variables/Scene variables"),
_("Scene variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardOperatorParameters("string",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
ParameterOptions::MakeNewOptions());
extension
.AddAction(
@@ -436,12 +182,11 @@ 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_"),
_("External variables/Scene variables"),
_("Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.AddParameter("trueorfalse", _("New Value:"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("trueorfalse", _("New Value:"));
extension
.AddAction("ToggleSceneVariableAsBoolean",
@@ -450,24 +195,22 @@ 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_"),
_("External variables/Scene variables"),
_("Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("scenevar", _("Variable"));
extension
.AddAction("ModVarGlobal",
_("Change number variable"),
_("Modify the number value of a global variable."),
_("the global variable _PARAM0_"),
_("External variables/Global variables"),
_("Global variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -475,13 +218,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Change text variable"),
_("Modify the text (string) of a global variable."),
_("the text of global variable _PARAM0_"),
_("External variables/Global variables"),
_("Global variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardOperatorParameters("string",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -490,12 +232,11 @@ 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_"),
_("External variables/Global variables"),
_("Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.AddParameter("trueorfalse", _("New Value:"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("trueorfalse", _("New Value:"));
extension
.AddAction("ToggleGlobalVariableAsBoolean",
@@ -504,11 +245,10 @@ 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_"),
_("External variables/Global variables"),
_("Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("globalvar", _("Variable"));
extension
.AddAction(
@@ -516,13 +256,12 @@ 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_"),
_("External variables/Scene variables/Arrays and structures"),
_("Scene variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Structure variable"))
.AddParameter("string", _("Child's name"))
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
.MarkAsAdvanced();
extension
.AddAction(
@@ -530,13 +269,12 @@ 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_"),
_("External variables/Global variables/Arrays and structures"),
_("Global variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Structure variable"))
.AddParameter("string", _("Child's name"))
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
.MarkAsAdvanced();
extension
.AddAction("VariableClearChildren",
@@ -544,11 +282,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Remove all the children from the scene structure or array "
"variable."),
_("Clear children from scene variable _PARAM0_"),
_("External variables/Scene variables/Arrays and structures"),
_("Scene variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Structure or array variable"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -557,11 +294,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Remove all the children from the global structure or array "
"variable."),
_("Clear children from global variable _PARAM0_"),
_("External variables/Global variables/Arrays and structures"),
_("Global variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Structure or array variable"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -570,7 +306,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_"),
_("External variables/Scene variables/Arrays and structures"),
_("Scene variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
@@ -578,7 +314,6 @@ 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
@@ -587,12 +322,11 @@ 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_"),
_("External variables/Scene variables/Arrays and structures"),
_("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
@@ -600,12 +334,11 @@ 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_"),
_("External variables/Scene variables/Arrays and structures"),
_("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
@@ -613,12 +346,11 @@ 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_"),
_("External variables/Scene variables/Arrays and structures"),
_("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
@@ -628,12 +360,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"variable."),
_("Remove variable at index _PARAM1_ from scene array "
"variable _PARAM0_"),
_("External variables/Scene variables/Arrays and structures"),
_("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
@@ -642,13 +373,12 @@ 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_"),
_("External variables/Scene variables/Arrays and structures"),
_("Scene variables/Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Array variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -657,10 +387,9 @@ 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)."),
_("External variables/Scene variables/Arrays and structures"),
_("Scene variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("scenevar", _("Array variable"));
extension
.AddExpression(
@@ -668,10 +397,9 @@ 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."),
_("External variables/Scene variables/Arrays and structures"),
_("Scene variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("scenevar", _("Array variable"));
extension
.AddStrExpression(
@@ -679,10 +407,9 @@ 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)."),
_("External variables/Scene variables/Arrays and structures"),
_("Scene variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("scenevar", _("Array variable"));
extension
.AddExpression(
@@ -690,10 +417,9 @@ 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."),
_("External variables/Scene variables/Arrays and structures"),
_("Scene variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("scenevar", _("Array variable"));
extension
.AddAction(
@@ -701,7 +427,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_"),
_("External variables/Global variables/Arrays and structures"),
_("Global variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
@@ -709,7 +435,6 @@ 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
@@ -719,12 +444,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"array variable."),
_("Remove variable at index _PARAM1_ from global array "
"variable _PARAM0_"),
_("External variables/Global variables/Arrays and structures"),
_("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
@@ -733,12 +457,11 @@ 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_"),
_("External variables/Global variables/Arrays and structures"),
_("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
@@ -746,12 +469,11 @@ 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_"),
_("External variables/Global variables/Arrays and structures"),
_("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
@@ -759,12 +481,11 @@ 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_"),
_("External variables/Global variables/Arrays and structures"),
_("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
@@ -773,13 +494,12 @@ 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_"),
_("External variables/Global variables/Arrays and structures"),
_("Global variables/Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Array variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -787,20 +507,18 @@ 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."),
_("External variables/Global variables/Arrays and structures"),
_("Global variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("globalvar", _("Array variable"));
extension
.AddExpression("GlobalVariableFirstNumber",
_("First number child"),
_("Value of the first element of a global array "
"variable, if it is a number variable"),
_("External variables/Global variables/Arrays and structures"),
_("Global variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("globalvar", _("Array variable"));
extension
.AddStrExpression(
@@ -808,10 +526,9 @@ 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."),
_("External variables/Global variables/Arrays and structures"),
_("Global variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("globalvar", _("Array variable"));
extension
.AddExpression(
@@ -819,65 +536,59 @@ 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"),
_("External variables/Global variables/Arrays and structures"),
_("Global variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("globalvar", _("Array variable"));
extension
.AddExpression("GlobalVariableChildCount",
_("Number of children"),
_("Number of children in a global array or "
"structure variable"),
_("External variables/Global variables/Arrays and structures"),
_("Global variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array or structure variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("globalvar", _("Array or structure variable"));
extension
.AddExpression("VariableChildCount",
_("Number of children"),
_("Number of children in a scene array or "
"structure variable"),
_("External variables/Scene variables/Arrays and structures"),
_("Scene variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("variable", _("Array or structure variable"), "AllowUndeclaredVariable");
.AddParameter("scenevar", _("Array or structure variable"));
extension
.AddExpression("Variable",
_("Number variable"),
_("Number value of a scene variable"),
_("External variables/Scene variables"),
_("Scene variables"),
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("scenevar", _("Variable"));
extension
.AddStrExpression("VariableString",
_("Text variable"),
_("Text of a scene variable"),
_("External variables/Scene variables"),
_("Scene variables"),
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("scenevar", _("Variable"));
extension
.AddExpression("GlobalVariable",
_("Number variable"),
_("Number value of a global variable"),
_("External variables/Global variables"),
_("Global variables"),
"res/actions/var.png")
.AddParameter("globalvar", _("Name of the global variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("globalvar", _("Name of the global variable"));
extension
.AddStrExpression("GlobalVariableString",
_("Text variable"),
_("Text of a global variable"),
_("External variables/Global variables"),
_("Global variables"),
"res/actions/var.png")
.AddParameter("globalvar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.AddParameter("globalvar", _("Variable"));
}
} // namespace gd

View File

@@ -114,8 +114,6 @@ public:
/**
* \brief Erase any existing include file and add the specified include.
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
virtual AbstractFunctionMetadata &
SetIncludeFile(const gd::String &includeFile) = 0;

View File

@@ -13,15 +13,12 @@
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/BehaviorsSharedData.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/MakeUnique.h"
#include "GDCore/Tools/Log.h"
namespace gd {
const std::map<gd::String, gd::PropertyDescriptor> BehaviorMetadata::badProperties;
BehaviorMetadata::BehaviorMetadata(
const gd::String& extensionNamespace_,
const gd::String& nameWithNamespace,
@@ -50,14 +47,8 @@ BehaviorMetadata::BehaviorMetadata(
"BehaviorMetadata is valid for: " + nameWithNamespace);
}
if (instance) {
instance->SetTypeName(nameWithNamespace);
instance->InitializeContent();
}
if (sharedDatasInstance) {
sharedDatasInstance->SetTypeName(nameWithNamespace);
sharedDatasInstance->InitializeContent();
}
if (instance) instance->SetTypeName(nameWithNamespace);
if (sharedDatasInstance) sharedDatasInstance->SetTypeName(nameWithNamespace);
}
gd::InstructionMetadata& BehaviorMetadata::AddCondition(
@@ -414,30 +405,10 @@ gd::Behavior& BehaviorMetadata::Get() const {
return *instance;
}
std::map<gd::String, gd::PropertyDescriptor> BehaviorMetadata::GetProperties() const {
if (!instance) {
return badProperties;
}
// TODO Properties should be declared on BehaviorMetadata directly.
// - Add 2 `properties` members (one for shared properties)
// - Add methods to declare new properties
return instance->GetProperties();
}
gd::BehaviorsSharedData* BehaviorMetadata::GetSharedDataInstance() const {
return sharedDatasInstance.get();
}
std::map<gd::String, gd::PropertyDescriptor> BehaviorMetadata::GetSharedProperties() const {
if (!sharedDatasInstance) {
return badProperties;
}
// TODO Properties should be declared on BehaviorMetadata directly.
// - Add 2 `properties` members (one for shared properties)
// - Add methods to declare new properties
return sharedDatasInstance->GetProperties();
}
const std::vector<gd::String>& BehaviorMetadata::GetRequiredBehaviorTypes() const {
requiredBehaviors.clear();
for (auto& property : Get().GetProperties()) {

View File

@@ -18,7 +18,6 @@ class BehaviorsSharedData;
class MultipleInstructionMetadata;
class InstructionMetadata;
class ExpressionMetadata;
class PropertyDescriptor;
} // namespace gd
namespace gd {
@@ -205,8 +204,6 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
* \brief Erase any existing include file and add the specified include.
* \note The requirement may vary depending on the platform: Most of the time,
* the include file contains the declaration of the behavior.
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
BehaviorMetadata& SetIncludeFile(const gd::String& includeFile) override;
@@ -305,15 +302,6 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
*/
gd::Behavior& Get() const;
/**
* \brief Called when the IDE wants to know about the custom properties of the
* behavior.
*
* \return a std::map with properties names as key.
* \see gd::PropertyDescriptor
*/
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
/**
* \brief Return the associated gd::BehaviorsSharedData, handling behavior
* shared data, if any (nullptr if none).
@@ -323,15 +311,6 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
*/
gd::BehaviorsSharedData* GetSharedDataInstance() const;
/**
* \brief Called when the IDE wants to know about the custom shared properties
* of the behavior.
*
* \return a std::map with properties names as key.
* \see gd::PropertyDescriptor
*/
std::map<gd::String, gd::PropertyDescriptor> GetSharedProperties() const;
/**
* \brief Return a reference to a map containing the names of the actions
* (as keys) and the metadata associated with (as values).
@@ -378,8 +357,6 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
// TODO: Nitpicking: convert these to std::unique_ptr to clarify ownership.
std::shared_ptr<gd::Behavior> instance;
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance;
static const std::map<gd::String, gd::PropertyDescriptor> badProperties;
};
} // namespace gd

View File

@@ -65,8 +65,6 @@ class GD_CORE_API EffectMetadata {
/**
* \brief Clear any existing include file and add the specified include file.
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
EffectMetadata& SetIncludeFile(const gd::String& includeFile);

View File

@@ -50,11 +50,11 @@ gd::ExpressionMetadata& ExpressionMetadata::AddParameter(
gd::ParameterMetadata::IsBehavior(type))
// Prefix with the namespace if it's not already there.
&& (supplementaryInformation.find(
PlatformExtension::GetNamespaceSeparator()) == gd::String::npos)
? (supplementaryInformation.empty()
PlatformExtension::GetNamespaceSeparator()) != gd::String::npos)
? supplementaryInformation
: (supplementaryInformation.empty()
? ""
: extensionNamespace + supplementaryInformation)
: supplementaryInformation));
: extensionNamespace + supplementaryInformation)));
// TODO: Assert against supplementaryInformation === "emsc" (when running with
// Emscripten), and warn about a missing argument when calling addParameter.

View File

@@ -288,8 +288,6 @@ class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
/**
* \brief Erase any existing include file and add the specified include.
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
ExpressionMetadata& SetIncludeFile(
const gd::String& includeFile) override {

View File

@@ -68,11 +68,11 @@ InstructionMetadata& InstructionMetadata::AddParameter(
gd::ParameterMetadata::IsBehavior(type))
// Prefix with the namespace if it's not already there.
&& (supplementaryInformation.find(
PlatformExtension::GetNamespaceSeparator()) == gd::String::npos)
? (supplementaryInformation.empty()
PlatformExtension::GetNamespaceSeparator()) != gd::String::npos)
? supplementaryInformation
: (supplementaryInformation.empty()
? ""
: extensionNamespace + supplementaryInformation)
: supplementaryInformation));
: extensionNamespace + supplementaryInformation)));
// TODO: Assert against supplementaryInformation === "emsc" (when running with
// Emscripten), and warn about a missing argument when calling addParameter.

View File

@@ -456,15 +456,6 @@ 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
@@ -503,8 +494,6 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
/**
* \brief Erase any existing include file and add the specified include.
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
InstructionMetadata &SetIncludeFile(const gd::String &includeFile) override {
codeExtraInformation.includeFiles.clear();

View File

@@ -142,8 +142,6 @@ public:
* \brief Erase any existing include file and add the specified include.
* \note The requirement may vary depending on the platform: Most of the time,
* the include file contains the declaration of the behavior.
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
virtual InstructionOrExpressionContainerMetadata &
SetIncludeFile(const gd::String &includeFile) = 0;

View File

@@ -150,10 +150,6 @@ class GD_CORE_API MultipleInstructionMetadata : public AbstractFunctionMetadata
return *this;
}
/**
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
MultipleInstructionMetadata &SetIncludeFile(const gd::String &includeFile) override {
if (expression)
expression->SetIncludeFile(includeFile);

View File

@@ -264,8 +264,6 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
* \brief Erase any existing include file and add the specified include.
* \note The requirement may vary depending on the platform: Most of the time,
* the include file contains the declaration of the object.
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
ObjectMetadata& SetIncludeFile(const gd::String& includeFile) override;

View File

@@ -217,9 +217,7 @@ class GD_CORE_API ValueTypeMetadata {
parameterType == "jsonResource" ||
parameterType == "tilemapResource" ||
parameterType == "tilesetResource" ||
parameterType == "model3DResource" ||
parameterType == "atlasResource" ||
parameterType == "spineResource";
parameterType == "model3DResource";
}
return false;
}

View File

@@ -285,6 +285,22 @@ class GD_CORE_API PlatformExtension {
std::shared_ptr<gd::Behavior> instance,
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance);
/**
* \brief Declare a new events based behavior as being part of the extension.
*
* \param name The name of the behavior
* \param fullname The user friendly name of the behavior
* \param description The user friendly description of the behavior
* \param group The behavior category label
* \param icon The icon of the behavior.
*/
gd::BehaviorMetadata& AddEventsBasedBehavior(
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& group_,
const gd::String& icon_);
/**
* \brief Declare a new effect as being part of the extension.
* \param name The internal name of the effect (also called effect type).

View File

@@ -26,7 +26,7 @@ void EventBasedBehaviorBrowser::ExposeEvents(
void EventBasedBehaviorBrowser::ExposeEvents(
gd::Project &project, gd::ArbitraryEventsWorkerWithContext &worker) const {
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
project, eventsFunctionsExtension, eventsBasedBehavior, worker);
project, eventsBasedBehavior, worker);
}
void EventBasedBehaviorBrowser::ExposeObjects(

View File

@@ -29,11 +29,8 @@ namespace gd {
*/
class GD_CORE_API EventBasedBehaviorBrowser : public ProjectBrowser {
public:
EventBasedBehaviorBrowser(
const gd::EventsFunctionsExtension &eventsFunctionsExtension_,
gd::EventsBasedBehavior &eventsBasedBehavior_)
: eventsFunctionsExtension(eventsFunctionsExtension_),
eventsBasedBehavior(eventsBasedBehavior_) {}
EventBasedBehaviorBrowser(gd::EventsBasedBehavior &eventsBasedBehavior_)
: eventsBasedBehavior(eventsBasedBehavior_) {}
/**
* \brief Call the specified worker on all events of the event-based
@@ -51,7 +48,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;
/**
@@ -83,7 +80,6 @@ public:
gd::ArbitraryBehaviorSharedDataWorker &worker) const override;
private:
const gd::EventsFunctionsExtension &eventsFunctionsExtension;
gd::EventsBasedBehavior &eventsBasedBehavior;
};

View File

@@ -14,27 +14,29 @@
#include "GDCore/Events/Expression.h"
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
using namespace std;
namespace gd {
AbstractArbitraryEventsWorker::~AbstractArbitraryEventsWorker() {}
ArbitraryEventsWorker::~ArbitraryEventsWorker() {}
void AbstractArbitraryEventsWorker::VisitEventList(gd::EventsList& events) {
void ArbitraryEventsWorker::VisitEventList(gd::EventsList& events) {
DoVisitEventList(events);
for (std::size_t i = 0; i < events.size();) {
if (events[i].AcceptVisitor(*this))
events.RemoveEvent(i);
else {
if (events[i].CanHaveSubEvents())
VisitEventList(events[i].GetSubEvents());
++i;
}
}
}
bool AbstractArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
bool ArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
bool shouldDelete = DoVisitEvent(event);
if (shouldDelete) return true;
@@ -53,17 +55,15 @@ bool AbstractArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
*expressionAndMetadata.first, expressionAndMetadata.second);
}
if (!shouldDelete && event.CanHaveSubEvents()) {
VisitEventList(event.GetSubEvents());
}
return shouldDelete;
}
bool AbstractArbitraryEventsWorker::VisitLinkEvent(gd::LinkEvent& linkEvent) {
bool ArbitraryEventsWorker::VisitLinkEvent(gd::LinkEvent& linkEvent) {
return DoVisitLinkEvent(linkEvent);
}
void AbstractArbitraryEventsWorker::VisitInstructionList(
void ArbitraryEventsWorker::VisitInstructionList(
gd::InstructionsList& instructions, bool areConditions) {
DoVisitInstructionList(instructions, areConditions);
@@ -79,19 +79,22 @@ void AbstractArbitraryEventsWorker::VisitInstructionList(
}
}
bool AbstractArbitraryEventsWorker::VisitInstruction(gd::Instruction& instruction,
bool ArbitraryEventsWorker::VisitInstruction(gd::Instruction& instruction,
bool isCondition) {
return DoVisitInstruction(instruction, isCondition);
}
bool AbstractArbitraryEventsWorker::VisitEventExpression(gd::Expression& expression,
bool ArbitraryEventsWorker::VisitEventExpression(gd::Expression& expression,
const gd::ParameterMetadata& metadata) {
return DoVisitEventExpression(expression, metadata);
}
AbstractReadOnlyArbitraryEventsWorker::~AbstractReadOnlyArbitraryEventsWorker() {}
ArbitraryEventsWorkerWithContext::~ArbitraryEventsWorkerWithContext() {}
void AbstractReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events) {
ReadOnlyArbitraryEventsWorker::~ReadOnlyArbitraryEventsWorker() {}
void ReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events) {
DoVisitEventList(events);
for (std::size_t i = 0; i < events.size(); ++i) {
@@ -106,7 +109,7 @@ void AbstractReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList&
}
}
void AbstractReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
void ReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
DoVisitEvent(event);
const vector<const gd::InstructionsList*> conditionsVectors =
@@ -127,11 +130,11 @@ void AbstractReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& even
}
}
void AbstractReadOnlyArbitraryEventsWorker::VisitLinkEvent(const gd::LinkEvent& linkEvent) {
void ReadOnlyArbitraryEventsWorker::VisitLinkEvent(const gd::LinkEvent& linkEvent) {
DoVisitLinkEvent(linkEvent);
}
void AbstractReadOnlyArbitraryEventsWorker::VisitInstructionList(
void ReadOnlyArbitraryEventsWorker::VisitInstructionList(
const gd::InstructionsList& instructions, bool areConditions) {
DoVisitInstructionList(instructions, areConditions);
@@ -147,73 +150,21 @@ void AbstractReadOnlyArbitraryEventsWorker::VisitInstructionList(
}
}
void AbstractReadOnlyArbitraryEventsWorker::VisitInstruction(const gd::Instruction& instruction,
void ReadOnlyArbitraryEventsWorker::VisitInstruction(const gd::Instruction& instruction,
bool isCondition) {
DoVisitInstruction(instruction, isCondition);
}
void AbstractReadOnlyArbitraryEventsWorker::VisitEventExpression(const gd::Expression& expression,
void ReadOnlyArbitraryEventsWorker::VisitEventExpression(const gd::Expression& expression,
const gd::ParameterMetadata& metadata) {
DoVisitEventExpression(expression, metadata);
}
void AbstractReadOnlyArbitraryEventsWorker::StopAnyEventIteration() {
void ReadOnlyArbitraryEventsWorker::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

View File

@@ -3,8 +3,8 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef GDCORE_ARBITRARYEVENTSWORKER_H
#define GDCORE_ARBITRARYEVENTSWORKER_H
#include <map>
#include <memory>
#include <vector>
@@ -12,7 +12,6 @@
#include "GDCore/Events/EventVisitor.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/String.h"
namespace gd {
class Instruction;
class BaseEvent;
@@ -26,24 +25,27 @@ class ParameterMetadata;
namespace gd {
/**
* \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.
* \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::ArbitraryEventsWorker
* \see gd::ArbitraryEventsWorkerWithContext
*
* \ingroup IDE
*/
class GD_CORE_API AbstractArbitraryEventsWorker : private EventVisitor {
class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
public:
AbstractArbitraryEventsWorker(){};
virtual ~AbstractArbitraryEventsWorker();
ArbitraryEventsWorker(){};
virtual ~ArbitraryEventsWorker();
protected:
virtual bool VisitEvent(gd::BaseEvent& event) override;
void VisitEventList(gd::EventsList& events);
/**
* \brief Launch the worker on the specified events list.
*/
void Launch(gd::EventsList& events) { VisitEventList(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);
@@ -99,31 +101,6 @@ protected:
}
};
/**
* \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.
@@ -133,10 +110,10 @@ private:
* \ingroup IDE
*/
class GD_CORE_API ArbitraryEventsWorkerWithContext
: public AbstractArbitraryEventsWorker {
: public ArbitraryEventsWorker {
public:
ArbitraryEventsWorkerWithContext()
: currentProjectScopedContainers(nullptr){};
: projectScopedContainers(nullptr){};
virtual ~ArbitraryEventsWorkerWithContext();
/**
@@ -144,50 +121,53 @@ 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) {
currentProjectScopedContainers = &projectScopedContainers;
AbstractArbitraryEventsWorker::VisitEventList(events);
const gd::ProjectScopedContainers& projectScopedContainers_) {
projectScopedContainers = &projectScopedContainers_;
ArbitraryEventsWorker::Launch(events);
};
protected:
void Launch(gd::EventsList& events) = delete;
protected:
const gd::ProjectScopedContainers& GetProjectScopedContainers() {
// Pointers are guaranteed to be not nullptr after
// Launch was called.
return *currentProjectScopedContainers;
return *projectScopedContainers;
};
const gd::ObjectsContainersList& GetObjectsContainersList() {
// Pointers are guaranteed to be not nullptr after
// Launch was called.
return currentProjectScopedContainers->GetObjectsContainersList();
return projectScopedContainers->GetObjectsContainersList();
};
private:
bool VisitEvent(gd::BaseEvent& event) override;
const gd::ProjectScopedContainers* currentProjectScopedContainers;
const gd::ProjectScopedContainers* projectScopedContainers;
};
/**
* \brief ReadOnlyArbitraryEventsWorker is an abstract class used to browse events (and
* instructions). It must not be inherited directly.
* instructions). It can be used to implement autocompletion for example.
*
* \see gd::ReadOnlyArbitraryEventsWorker
* \see gd::ReadOnlyArbitraryEventsWorkerWithContext
*
* \ingroup IDE
*/
class GD_CORE_API AbstractReadOnlyArbitraryEventsWorker : private ReadOnlyEventVisitor {
class GD_CORE_API ReadOnlyArbitraryEventsWorker : private ReadOnlyEventVisitor {
public:
AbstractReadOnlyArbitraryEventsWorker() : shouldStopIteration(false) {};
virtual ~AbstractReadOnlyArbitraryEventsWorker();
ReadOnlyArbitraryEventsWorker() : shouldStopIteration(false) {};
virtual ~ReadOnlyArbitraryEventsWorker();
/**
* \brief Launch the worker on the specified events list.
*/
void Launch(const gd::EventsList& events) { VisitEventList(events); };
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);
@@ -233,31 +213,6 @@ 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.
@@ -267,10 +222,10 @@ private:
* \ingroup IDE
*/
class GD_CORE_API ReadOnlyArbitraryEventsWorkerWithContext
: public AbstractReadOnlyArbitraryEventsWorker {
: public ReadOnlyArbitraryEventsWorker {
public:
ReadOnlyArbitraryEventsWorkerWithContext()
: currentProjectScopedContainers(nullptr){};
: projectScopedContainers(nullptr){};
virtual ~ReadOnlyArbitraryEventsWorkerWithContext();
/**
@@ -278,22 +233,24 @@ 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) {
currentProjectScopedContainers = &projectScopedContainers;
AbstractReadOnlyArbitraryEventsWorker::VisitEventList(events);
const gd::ProjectScopedContainers& projectScopedContainers_) {
projectScopedContainers = &projectScopedContainers_;
ReadOnlyArbitraryEventsWorker::Launch(events);
};
protected:
void Launch(gd::EventsList& events) = delete;
protected:
const gd::ProjectScopedContainers& GetProjectScopedContainers() {
// Pointers are guaranteed to be not nullptr after
// Launch was called.
return *currentProjectScopedContainers;
return *projectScopedContainers;
};
private:
void VisitEvent(const gd::BaseEvent& event) override;
const gd::ProjectScopedContainers* currentProjectScopedContainers;
const gd::ProjectScopedContainers* projectScopedContainers;
};
} // namespace gd
#endif // GDCORE_ARBITRARYEVENTSWORKER_H

View File

@@ -1,65 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2024 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "BehaviorParametersFiller.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Instruction.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
namespace gd {
bool BehaviorParametersFiller::DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) {
const auto &metadata = isCondition
? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
instruction.GetParameters(), metadata.GetParameters(),
[&](const gd::ParameterMetadata &parameterMetadata,
const gd::Expression &parameterValue, size_t parameterIndex,
const gd::String &lastObjectName) {
if (parameterMetadata.GetValueTypeMetadata().IsBehavior() &&
parameterValue.GetPlainString().length() == 0) {
auto &expectedBehaviorTypeName =
parameterMetadata.GetValueTypeMetadata().GetExtraInfo();
auto &objectsContainersList =
projectScopedContainers.GetObjectsContainersList();
auto behaviorNames =
objectsContainersList.GetBehaviorsOfObject(lastObjectName, true);
gd::String foundBehaviorName = "";
for (auto &behaviorName : behaviorNames) {
auto behaviorTypeName =
objectsContainersList.GetTypeOfBehavior(behaviorName, false);
if (behaviorTypeName == expectedBehaviorTypeName) {
foundBehaviorName = behaviorName;
break;
}
}
if (!foundBehaviorName.empty()) {
instruction.SetParameter(parameterIndex,
gd::Expression(foundBehaviorName));
}
}
});
return false;
}
BehaviorParametersFiller::~BehaviorParametersFiller() {}
} // namespace gd

View File

@@ -1,45 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2024 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
#include <map>
#include <memory>
#include <vector>
namespace gd {
class Instruction;
class Platform;
class ProjectScopedContainers;
} // namespace gd
namespace gd {
/**
* \brief Fill empty behavior parameters with any behavior that matches the
* required behavior type.
*
* \ingroup IDE
*/
class GD_CORE_API BehaviorParametersFiller : public ArbitraryEventsWorker {
public:
BehaviorParametersFiller(
const gd::Platform &platform_,
const gd::ProjectScopedContainers &projectScopedContainers_)
: platform(platform_),
projectScopedContainers(projectScopedContainers_){};
virtual ~BehaviorParametersFiller();
private:
bool DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) override;
const gd::Platform &platform;
const gd::ProjectScopedContainers &projectScopedContainers;
};
} // namespace gd

View File

@@ -588,6 +588,31 @@ bool EventsRefactorer::RemoveObjectInConditions(
return somethingModified;
}
void EventsRefactorer::RemoveObjectInEvents(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::EventsList& events,
gd::String name) {
for (std::size_t i = 0; i < events.size(); ++i) {
vector<gd::InstructionsList*> conditionsVectors =
events[i].GetAllConditionsVectors();
for (std::size_t j = 0; j < conditionsVectors.size(); ++j) {
bool conditionsModified = RemoveObjectInConditions(
platform, projectScopedContainers, *conditionsVectors[j], name);
}
vector<gd::InstructionsList*> actionsVectors =
events[i].GetAllActionsVectors();
for (std::size_t j = 0; j < actionsVectors.size(); ++j) {
bool actionsModified = RemoveObjectInActions(
platform, projectScopedContainers, *actionsVectors[j], name);
}
if (events[i].CanHaveSubEvents())
RemoveObjectInEvents(
platform, projectScopedContainers, events[i].GetSubEvents(), name);
}
}
gd::String ReplaceAllOccurrencesCaseInsensitive(gd::String context,
const gd::String& from,
const gd::String& to) {

View File

@@ -86,6 +86,14 @@ class GD_CORE_API EventsRefactorer {
gd::String oldName,
gd::String newName);
/**
* Remove all actions or conditions using an object
*/
static void RemoveObjectInEvents(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::EventsList& events,
gd::String name);
/**
* Search for a gd::String in events
*

View File

@@ -1,100 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/EventsVariableInstructionTypeSwitcher.h"
#include <map>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
#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"
#include "GDCore/Project/VariablesContainer.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
namespace gd {
bool EventsVariableInstructionTypeSwitcher::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
const auto& metadata = isCondition
? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
instruction.GetParameters(),
metadata.GetParameters(),
[&](const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
size_t parameterIndex,
const gd::String& lastObjectName) {
const gd::String& type = parameterMetadata.GetType();
if (!gd::ParameterMetadata::IsExpression("variable", type) ||
!gd::VariableInstructionSwitcher::IsSwitchableVariableInstruction(
instruction.GetType())) {
return;
}
const auto variableName =
gd::ExpressionVariableNameFinder::GetVariableName(
*parameterValue.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 false;
}
EventsVariableInstructionTypeSwitcher::~EventsVariableInstructionTypeSwitcher() {}
} // namespace gd

View File

@@ -1,53 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2024 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <map>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class VariablesContainer;
class Platform;
} // namespace gd
namespace gd {
/**
* \brief Switch the types of variable instructions for a given set of
* variables.
*
* \see gd::VariableInstructionSwitcher
*
* \ingroup IDE
*/
class GD_CORE_API EventsVariableInstructionTypeSwitcher
: public ArbitraryEventsWorkerWithContext {
public:
EventsVariableInstructionTypeSwitcher(
const gd::Platform &platform_,
const gd::VariablesContainer &targetVariablesContainer_,
const std::unordered_set<gd::String> &typeChangedVariableNames_)
: platform(platform_),
targetVariablesContainer(targetVariablesContainer_),
typeChangedVariableNames(typeChangedVariableNames_){};
virtual ~EventsVariableInstructionTypeSwitcher();
private:
bool DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) override;
const gd::Platform &platform;
const gd::VariablesContainer &targetVariablesContainer;
gd::String objectName;
const std::unordered_set<gd::String> &typeChangedVariableNames;
};
} // namespace gd

View File

@@ -20,9 +20,6 @@
#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/IDE/WholeProjectRefactorer.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ProjectScopedContainers.h"
@@ -45,7 +42,7 @@ class GD_CORE_API ExpressionVariableReplacer
const gd::Platform& platform_,
const gd::ProjectScopedContainers& projectScopedContainers_,
const gd::VariablesContainer& targetVariablesContainer_,
const VariablesRenamingChangesetNode& variablesRenamingChangesetRoot_,
const std::unordered_map<gd::String, gd::String>& oldToNewVariableNames_,
const std::unordered_set<gd::String>& removedVariableNames_)
: hasDoneRenaming(false),
removedVariableUsed(false),
@@ -53,7 +50,7 @@ class GD_CORE_API ExpressionVariableReplacer
projectScopedContainers(projectScopedContainers_),
forcedInitialVariablesContainer(nullptr),
targetVariablesContainer(targetVariablesContainer_),
variablesRenamingChangesetRoot(variablesRenamingChangesetRoot_),
oldToNewVariableNames(oldToNewVariableNames_),
removedVariableNames(removedVariableNames_){};
virtual ~ExpressionVariableReplacer(){};
@@ -83,28 +80,20 @@ class GD_CORE_API ExpressionVariableReplacer
// will be accessed.
if (forcedInitialVariablesContainer) {
const gd::String oldVariableName = node.name;
PushVariablesRenamingChangesetRoot();
// A scope was forced. Honor it: it means this node represents a variable
// of the forced variables container.
if (forcedInitialVariablesContainer == &targetVariablesContainer) {
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
}
if (node.child) {
bool hasBeenPushed =
PushVariablesRenamingChangesetNodeForVariable(oldVariableName);
node.child->Visit(*this);
PopVariablesRenamingChangesetNode(hasBeenPushed);
}
PopVariablesRenamingChangesetNode(true);
if (node.child) node.child->Visit(*this);
return;
}
// Match the potential *new* name of the variable, because refactorings are
// done after changes in the variables container.
projectScopedContainers.MatchIdentifierWithName<void>(
node.name,
GetPotentialNewName(node.name),
[&]() {
// This represents an object.
// Remember the object name.
@@ -114,21 +103,14 @@ class GD_CORE_API ExpressionVariableReplacer
},
[&]() {
// This is a variable.
if (&projectScopedContainers.GetVariablesContainersList()
.GetVariablesContainerFromVariableName(node.name) ==
&targetVariablesContainer) {
if (projectScopedContainers.GetVariablesContainersList()
.HasVariablesContainer(targetVariablesContainer)) {
// The node represents a variable, that can come from the target
// (because the target is in the scope), replace or remove it:
PushVariablesRenamingChangesetRoot();
RenameVariableAndVisitChild(node.name, node.child.get());
PopVariablesRenamingChangesetNode(true);
} else {
if (node.child) {
PushVariablesRenamingChangesetNodeForIgnoredVariables();
node.child->Visit(*this);
PopVariablesRenamingChangesetNode(true);
}
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
}
if (node.child) node.child->Visit(*this);
},
[&]() {
// This is a property.
@@ -139,7 +121,14 @@ class GD_CORE_API ExpressionVariableReplacer
if (node.child) node.child->Visit(*this);
},
[&]() {
// This is something else.
// This is something else - potentially a deleted variable.
if (projectScopedContainers.GetVariablesContainersList()
.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);
}
if (node.child) node.child->Visit(*this);
});
}
@@ -147,49 +136,25 @@ class GD_CORE_API ExpressionVariableReplacer
auto& objectsContainersList =
projectScopedContainers.GetObjectsContainersList();
if (!objectNameToUseForVariableAccessor.empty()) {
// This is always true because MatchIdentifierWithName is used to get
// objectNameToUseForVariableAccessor.
if (objectsContainersList.HasObjectOrGroupVariablesContainer(
objectNameToUseForVariableAccessor, targetVariablesContainer)) {
objectNameToUseForVariableAccessor = "";
// The node represents an object variable, and this object variables are
// the target. Do the replacement or removals:
PushVariablesRenamingChangesetRoot();
RenameVariableAndVisitChild(node.name, node.child.get());
PopVariablesRenamingChangesetNode(true);
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
}
} else {
RenameVariableAndVisitChild(node.name, node.child.get());
}
objectNameToUseForVariableAccessor = "";
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
objectNameToUseForVariableAccessor = "";
// TODO Literal expressions could be checked to handle renaming in
// `expression` and in `child`.
node.expression->Visit(*this);
if (node.child) {
PushVariablesRenamingChangesetNodeForIgnoredVariables();
node.child->Visit(*this);
PopVariablesRenamingChangesetNode(true);
}
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode &node) override {
auto renameVariableAndChild = [this, &node]() {
PushVariablesRenamingChangesetRoot();
const gd::String oldVariableName = node.identifierName;
RenameOrRemoveVariableOfTargetVariableContainer(node.identifierName);
if (!node.childIdentifierName.empty()) {
bool hasBeenPushed =
PushVariablesRenamingChangesetNodeForVariable(oldVariableName);
RenameOrRemoveVariableOfTargetVariableContainer(
node.childIdentifierName);
PopVariablesRenamingChangesetNode(hasBeenPushed);
}
PopVariablesRenamingChangesetNode(true);
};
void OnVisitIdentifierNode(IdentifierNode& node) override {
auto& objectsContainersList =
projectScopedContainers.GetObjectsContainersList();
@@ -201,7 +166,7 @@ class GD_CORE_API ExpressionVariableReplacer
// A scope was forced. Honor it: it means this node represents a variable
// of the forced variables container.
if (forcedInitialVariablesContainer == &targetVariablesContainer) {
renameVariableAndChild();
RenameOrRemoveVariableOfTargetVariableContainer(node.identifierName);
}
return;
}
@@ -209,27 +174,25 @@ class GD_CORE_API ExpressionVariableReplacer
// Match the potential *new* name of the variable, because refactorings are
// done after changes in the variables container.
projectScopedContainers.MatchIdentifierWithName<void>(
node.identifierName,
GetPotentialNewName(node.identifierName),
[&]() {
// This represents an object.
if (objectsContainersList.HasObjectOrGroupVariablesContainer(
node.identifierName, targetVariablesContainer)) {
// The node represents an object variable, and this object variables
// are the target. Do the replacement or removals:
PushVariablesRenamingChangesetRoot();
RenameOrRemoveVariableOfTargetVariableContainer(
node.childIdentifierName);
PopVariablesRenamingChangesetNode(true);
}
},
[&]() {
// This is a variable.
if (&projectScopedContainers.GetVariablesContainersList()
.GetVariablesContainerFromVariableName(
node.identifierName) == &targetVariablesContainer) {
if (projectScopedContainers.GetVariablesContainersList()
.HasVariablesContainer(targetVariablesContainer)) {
// The node represents a variable, that can come from the target
// (because the target is in the scope), replace or remove it:
renameVariableAndChild();
RenameOrRemoveVariableOfTargetVariableContainer(
node.identifierName);
}
},
[&]() {
@@ -239,7 +202,14 @@ class GD_CORE_API ExpressionVariableReplacer
// This is a parameter.
},
[&]() {
// This is something else.
// This is something else - potentially a deleted variable.
if (projectScopedContainers.GetVariablesContainersList()
.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.identifierName);
}
});
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
@@ -298,24 +268,19 @@ class GD_CORE_API ExpressionVariableReplacer
bool hasDoneRenaming;
bool removedVariableUsed;
const gd::String& GetPotentialNewName(const gd::String& oldName) {
return oldToNewVariableNames.count(oldName) >= 1
? oldToNewVariableNames.find(oldName)->second
: oldName;
}
bool RenameOrRemoveVariableOfTargetVariableContainer(
gd::String& variableName) {
const auto *currentVariablesRenamingChangesetNode =
GetCurrentVariablesRenamingChangesetNode();
if (!currentVariablesRenamingChangesetNode) {
return false;
}
const auto &oldToNewVariableNames =
currentVariablesRenamingChangesetNode->oldToNewVariableNames;
if (oldToNewVariableNames.count(variableName) >= 1) {
variableName = oldToNewVariableNames.find(variableName)->second;
hasDoneRenaming = true;
return true;
} else if (
// Only the root variable is checked for removing.
currentVariablesRenamingChangesetNode ==
&variablesRenamingChangesetRoot &&
removedVariableNames.count(variableName) >= 1) {
} else if (removedVariableNames.count(variableName) >= 1) {
removedVariableUsed = true;
return true;
}
@@ -323,62 +288,6 @@ class GD_CORE_API ExpressionVariableReplacer
return false; // Nothing was changed or done.
}
void RenameVariableAndVisitChild(gd::String &variableName,
ExpressionNode *childNode) {
// `variableName` is modified by
// `RenameOrRemoveVariableOfTargetVariableContainer`.
const gd::String oldVariableName = variableName;
RenameOrRemoveVariableOfTargetVariableContainer(variableName);
if (childNode) {
bool hasBeenPushed =
PushVariablesRenamingChangesetNodeForVariable(oldVariableName);
childNode->Visit(*this);
PopVariablesRenamingChangesetNode(hasBeenPushed);
}
}
void PushVariablesRenamingChangesetRoot() {
variablesRenamingChangesetNodeStack.push_back(&variablesRenamingChangesetRoot);
}
void PushVariablesRenamingChangesetNodeForIgnoredVariables() {
variablesRenamingChangesetNodeStack.push_back(nullptr);
}
const gd::VariablesRenamingChangesetNode *GetCurrentVariablesRenamingChangesetNode() {
return variablesRenamingChangesetNodeStack.size() == 0 ?
&variablesRenamingChangesetRoot :
variablesRenamingChangesetNodeStack
[variablesRenamingChangesetNodeStack.size() - 1];
}
bool PushVariablesRenamingChangesetNodeForVariable(const gd::String& variableName) {
const auto *currentVariablesRenamingChangesetNode = GetCurrentVariablesRenamingChangesetNode();
if (!currentVariablesRenamingChangesetNode) {
// There were already no more change on a parent.
return false;
}
const auto &childVariablesRenamingChangesetNodeItr =
currentVariablesRenamingChangesetNode->modifiedVariables.find(
variableName);
if (childVariablesRenamingChangesetNodeItr ==
currentVariablesRenamingChangesetNode->modifiedVariables.end()) {
// There is no more change on the current variable child.
variablesRenamingChangesetNodeStack.push_back(nullptr);
}
else {
variablesRenamingChangesetNodeStack.push_back(
childVariablesRenamingChangesetNodeItr->second.get());
}
return true;
}
void PopVariablesRenamingChangesetNode(bool hasBeenPushed) {
if (hasBeenPushed) {
variablesRenamingChangesetNodeStack.pop_back();
}
}
// Scope:
const gd::Platform& platform;
const gd::ProjectScopedContainers& projectScopedContainers;
@@ -386,11 +295,10 @@ class GD_CORE_API ExpressionVariableReplacer
// Renaming or removing to do:
const gd::VariablesContainer& targetVariablesContainer;
const VariablesRenamingChangesetNode &variablesRenamingChangesetRoot;
const std::unordered_map<gd::String, gd::String>& oldToNewVariableNames;
const std::unordered_set<gd::String>& removedVariableNames;
gd::String objectNameToUseForVariableAccessor;
std::vector<const VariablesRenamingChangesetNode*> variablesRenamingChangesetNodeStack;
};
const gd::VariablesContainer*
@@ -443,7 +351,7 @@ bool EventsVariableReplacer::DoVisitInstruction(gd::Instruction& instruction,
ExpressionVariableReplacer renamer(platform,
GetProjectScopedContainers(),
targetVariablesContainer,
variablesRenamingChangesetRoot,
oldToNewVariableNames,
removedVariableNames);
renamer.SetForcedInitialVariablesContainer(
FindForcedVariablesContainerIfAny(type, lastObjectName));
@@ -475,7 +383,7 @@ bool EventsVariableReplacer::DoVisitEventExpression(
ExpressionVariableReplacer renamer(platform,
GetProjectScopedContainers(),
targetVariablesContainer,
variablesRenamingChangesetRoot,
oldToNewVariableNames,
removedVariableNames);
renamer.SetForcedInitialVariablesContainer(
FindForcedVariablesContainerIfAny(type, ""));

View File

@@ -4,7 +4,6 @@
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <map>
#include <memory>
#include <unordered_map>
@@ -13,13 +12,11 @@
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class BaseEvent;
class VariablesContainer;
class EventsList;
class Platform;
struct VariablesRenamingChangesetNode;
} // namespace gd
namespace gd {
@@ -36,12 +33,12 @@ class GD_CORE_API EventsVariableReplacer
EventsVariableReplacer(
const gd::Platform &platform_,
const gd::VariablesContainer &targetVariablesContainer_,
const VariablesRenamingChangesetNode &variablesRenamingChangesetRoot_,
const std::unordered_map<gd::String, gd::String> &oldToNewVariableNames_,
const std::unordered_set<gd::String> &removedVariableNames_)
: platform(platform_),
targetVariablesContainer(targetVariablesContainer_),
variablesRenamingChangesetRoot(variablesRenamingChangesetRoot_),
removedVariableNames(removedVariableNames_) {};
oldToNewVariableNames(oldToNewVariableNames_),
removedVariableNames(removedVariableNames_){};
virtual ~EventsVariableReplacer();
private:
@@ -56,7 +53,7 @@ class GD_CORE_API EventsVariableReplacer
const gd::Platform &platform;
const gd::VariablesContainer &targetVariablesContainer;
gd::String objectName;
const VariablesRenamingChangesetNode &variablesRenamingChangesetRoot;
const std::unordered_map<gd::String, gd::String> &oldToNewVariableNames;
const std::unordered_set<gd::String> &removedVariableNames;
};

View File

@@ -229,7 +229,7 @@ std::set<gd::String> EventsVariablesFinder::FindAllObjectVariables(
const gd::Platform& platform,
const gd::Project& project,
const gd::Layout& layout,
const gd::String& objectName) {
const gd::Object& object) {
std::set<gd::String> results;
FindArgumentsInEventsAndDependencies(
@@ -238,7 +238,7 @@ std::set<gd::String> EventsVariablesFinder::FindAllObjectVariables(
project,
layout,
"objectvar",
objectName);
object.GetName());
return results;
}

View File

@@ -63,14 +63,14 @@ class EventsVariablesFinder {
*
* \param project The project
* \param layout The layout to use.
* \param objectName The name of the object to be scanned
* \param object 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::String& objectName);
const gd::Object& object);
private:

View File

@@ -3,7 +3,8 @@
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
#define GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
#include <memory>
#include <vector>
@@ -19,7 +20,7 @@
#include "GDCore/IDE/Events/ExpressionNodeLocationFinder.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
#include "GDCore/IDE/Events/ExpressionVariablePathFinder.h"
#include "GDCore/IDE/Events/ExpressionVariableParentFinder.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/Project/Variable.h"
@@ -146,19 +147,6 @@ struct GD_CORE_API ExpressionCompletionDescription {
return *this;
}
/**
* \brief Return the scope of the variable, for a variable completion.
*/
gd::VariablesContainer::SourceType GetVariableScope() const {
return variableScope;
}
ExpressionCompletionDescription &
SetVariableScope(gd::VariablesContainer::SourceType variableScope_) {
variableScope = variableScope_;
return *this;
}
/**
* \brief Return the prefix that must be completed.
*/
@@ -327,7 +315,6 @@ struct GD_CORE_API ExpressionCompletionDescription {
size_t replacementEndPosition_)
: completionKind(completionKind_),
variableType(gd::Variable::Number),
variableScope(gd::VariablesContainer::Unknown),
replacementStartPosition(replacementStartPosition_),
replacementEndPosition(replacementEndPosition_),
isExact(false),
@@ -338,7 +325,6 @@ struct GD_CORE_API ExpressionCompletionDescription {
private:
CompletionKind completionKind;
gd::Variable::Type variableType;
gd::VariablesContainer::SourceType variableScope;
gd::String type;
gd::String prefix;
gd::String completion;
@@ -539,7 +525,7 @@ class GD_CORE_API ExpressionCompletionFinder
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
VariableAndItsParent variableAndItsParent =
gd::ExpressionVariablePathFinder::GetLastParentOfNode(
gd::ExpressionVariableParentFinder::GetLastParentOfNode(
platform, projectScopedContainers, node);
// If no child, we're at the end of a variable (like `GrandChild` in
@@ -680,7 +666,7 @@ class GD_CORE_API ExpressionCompletionFinder
[&]() {
// This is a variable.
VariableAndItsParent variableAndItsParent =
gd::ExpressionVariablePathFinder::GetLastParentOfNode(
gd::ExpressionVariableParentFinder::GetLastParentOfNode(
platform, projectScopedContainers, node);
AddCompletionsForChildrenVariablesOf(
@@ -947,7 +933,6 @@ class GD_CORE_API ExpressionCompletionFinder
location.GetEndPosition());
description.SetCompletion(variableName);
description.SetVariableType(variable.GetType());
description.SetVariableScope(variablesContainer.GetSourceType());
completions.push_back(description);
if (eagerlyCompleteIfExactMatch && variableName == search) {
@@ -973,7 +958,6 @@ class GD_CORE_API ExpressionCompletionFinder
location.GetEndPosition());
description.SetCompletion(variableName);
description.SetVariableType(variable.GetType());
description.SetVariableScope(gd::VariablesContainer::Object);
completions.push_back(description);
if (eagerlyCompleteIfExactMatch && variableName == search) {
@@ -1028,10 +1012,6 @@ class GD_CORE_API ExpressionCompletionFinder
location.GetEndPosition());
description.SetCompletion(variableName);
description.SetVariableType(variable.GetType());
description.SetVariableScope(
projectScopedContainers.GetVariablesContainersList()
.GetVariablesContainerFromVariableName(variableName)
.GetSourceType());
completions.push_back(description);
if (eagerlyCompleteIfExactMatch && variableName == search) {
@@ -1080,10 +1060,6 @@ class GD_CORE_API ExpressionCompletionFinder
location.GetEndPosition());
description.SetCompletion(variableName);
description.SetVariableType(variable.GetType());
description.SetVariableScope(
projectScopedContainers.GetVariablesContainersList()
.GetVariablesContainerFromVariableName(variableName)
.GetSourceType());
completions.push_back(description);
if (eagerlyCompleteIfExactMatch && variableName == search) {
@@ -1137,3 +1113,5 @@ class GD_CORE_API ExpressionCompletionFinder
};
} // namespace gd
#endif // GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H

View File

@@ -106,20 +106,20 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
auto variableExistence = objectsContainersList.HasObjectOrGroupWithVariableNamed(identifier.identifierName, identifier.childIdentifierName);
if (variableExistence == gd::ObjectsContainersList::DoesNotExist) {
RaiseUndeclaredVariableError(_("This variable does not exist on this object or group."),
identifier.childIdentifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
RaiseTypeError(_("This variable does not exist on this object or group."),
identifier.childIdentifierNameLocation);
return true; // We should have found a variable.
}
else if (variableExistence == gd::ObjectsContainersList::ExistsOnlyOnSomeObjectsOfTheGroup) {
RaiseUndeclaredVariableError(_("This variable only exists on some objects of the group. It must be declared for all objects."),
identifier.childIdentifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
RaiseTypeError(_("This variable only exists on some objects of the group. It must be declared for all objects."),
identifier.childIdentifierNameLocation);
return true; // We should have found a variable.
}
else if (variableExistence == gd::ObjectsContainersList::GroupIsEmpty) {
RaiseUndeclaredVariableError(_("This group is empty. Add an object to this group first."),
identifier.identifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
RaiseTypeError(_("This group is empty. Add an object to this group first."),
identifier.identifierNameLocation);
return true; // We should have found a variable.
}
@@ -166,7 +166,8 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
return true; // We found a property, even if the child is not allowed.
}
const gd::NamedPropertyDescriptor& property = propertiesContainersList.Get(identifier.identifierName).second;
const gd::NamedPropertyDescriptor& property = projectScopedContainers
.GetPropertiesContainersList().Get(identifier.identifierName).second;
if (property.GetType() == "Number") {
childType = Type::Number;
@@ -247,10 +248,9 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
if (!function.behaviorName.empty() &&
!objectsContainersList.HasBehaviorInObjectOrGroup(function.objectName,
function.behaviorName)) {
RaiseError(gd::ExpressionParserError::ErrorType::MissingBehavior,
_("This behavior is not attached to this object."),
function.behaviorNameLocation,
/*isFatal=*/false, function.behaviorName, function.objectName);
RaiseTypeError(_("This behavior is not attached to this object."),
function.behaviorNameLocation,
/*isFatal=*/false);
return returnType;
}
@@ -264,11 +264,11 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
if (function.functionName.empty()) {
RaiseError(gd::ExpressionParserError::ErrorType::InvalidFunctionName,
RaiseError("invalid_function_name",
_("Enter the name of the function to call."),
function.location);
} else {
RaiseError(gd::ExpressionParserError::ErrorType::InvalidFunctionName,
RaiseError("invalid_function_name",
_("Cannot find an expression with this name: ") +
function.functionName + "\n" +
_("Double check that you've not made any typo in the name."),
@@ -341,13 +341,13 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
if (function.parameters.size() < minParametersCount) {
RaiseError(
gd::ExpressionParserError::ErrorType::TooFewParameters,
"too_few_parameters",
_("You have not entered enough parameters for the expression.") +
" " + expectedCountMessage,
function.location);
} else {
RaiseError(
gd::ExpressionParserError::ErrorType::TooManyParameters,
"extra_parameter",
_("This parameter was not expected by this expression. Remove it "
"or verify that you've entered the proper expression name.") +
" " + expectedCountMessage,
@@ -376,10 +376,7 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
dynamic_cast<EmptyNode*>(parameter.get()) == nullptr) {
auto currentParentType = parentType;
parentType = StringToType(parameterMetadata.GetType());
auto parentParameterExtraInfo = currentParameterExtraInfo;
currentParameterExtraInfo = &parameterMetadata.GetExtraInfo();
parameter->Visit(*this);
currentParameterExtraInfo = parentParameterExtraInfo;
parentType = currentParentType;
const gd::String& expectedParameterType = parameterMetadata.GetType();
@@ -387,7 +384,7 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
ExpressionValidator::variableTypeString, expectedParameterType)) {
if (dynamic_cast<IdentifierNode*>(parameter.get()) == nullptr &&
dynamic_cast<VariableNode*>(parameter.get()) == nullptr) {
RaiseError(gd::ExpressionParserError::ErrorType::MalformedVariableParameter,
RaiseError("malformed_variable_parameter",
_("A variable name was expected but something else was "
"written. Enter just the name of the variable for this "
"parameter."),
@@ -395,7 +392,7 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
}
} else if (gd::ParameterMetadata::IsObject(expectedParameterType)) {
if (dynamic_cast<IdentifierNode*>(parameter.get()) == nullptr) {
RaiseError(gd::ExpressionParserError::ErrorType::MalformedObjectParameter,
RaiseError("malformed_object_parameter",
_("An object name was expected but something else was "
"written. Enter just the name of the object for this "
"parameter."),
@@ -409,7 +406,7 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
!gd::ParameterMetadata::IsExpression(
ExpressionValidator::stringTypeString,
expectedParameterType)) {
RaiseError(gd::ExpressionParserError::ErrorType::UnknownParameterType,
RaiseError("unknown_parameter_type",
_("This function is improperly set up. Reach out to the "
"extension developer or a GDevelop maintainer to fix "
"this issue"),
@@ -443,10 +440,6 @@ 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:
@@ -473,12 +466,7 @@ ExpressionValidator::Type ExpressionValidator::StringToType(
if (type == ExpressionValidator::variableTypeString ||
gd::ParameterMetadata::IsExpression(
ExpressionValidator::variableTypeString, type)) {
if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
return Type::LegacyVariable;
}
else {
return Type::Variable;
}
return Type::Variable;
}
if (type == ExpressionValidator::objectTypeString ||
gd::ParameterMetadata::IsObject(type)) {

View File

@@ -3,7 +3,8 @@
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef GDCORE_EXPRESSIONVALIDATOR_H
#define GDCORE_EXPRESSIONVALIDATOR_H
#include <memory>
#include <vector>
@@ -38,14 +39,12 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
public:
ExpressionValidator(const gd::Platform &platform_,
const gd::ProjectScopedContainers & projectScopedContainers_,
const gd::String &rootType_,
const gd::String &extraInfo_ = "")
const gd::String &rootType_)
: platform(platform_),
projectScopedContainers(projectScopedContainers_),
parentType(StringToType(gd::ParameterMetadata::GetExpressionValueType(rootType_))),
childType(Type::Unknown),
forbidsUsageOfBracketsBecauseParentIsObject(false),
currentParameterExtraInfo(&extraInfo_) {};
forbidsUsageOfBracketsBecauseParentIsObject(false) {};
virtual ~ExpressionValidator(){};
/**
@@ -66,7 +65,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
*
* Expressions with fatal error can't be generated.
*/
const std::vector<ExpressionParserError*>& GetFatalErrors() {
const std::vector<ExpressionParserDiagnostic*>& GetFatalErrors() {
return fatalErrors;
};
@@ -75,7 +74,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
*
* No errors means that the expression is valid.
*/
const std::vector<ExpressionParserError*>& GetAllErrors() {
const std::vector<ExpressionParserDiagnostic*>& GetAllErrors() {
return allErrors;
};
@@ -87,21 +86,19 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
void OnVisitOperatorNode(OperatorNode& node) override {
ReportAnyError(node);
// The "required" type ("parentType") will be used when visiting the first operand.
// Note that it may be refined thanks to this first operand (see later).
node.leftHandSide->Visit(*this);
const Type leftType = childType; // Store the type of the first operand.
const Type leftType = childType;
if (leftType == Type::Number) {
if (node.op == ' ') {
RaiseError(gd::ExpressionParserError::ErrorType::SyntaxError,
RaiseError("syntax_error",
"No operator found. Did you forget to enter an operator (like +, -, "
"* or /) between numbers or expressions?", node.rightHandSide->location);
}
}
else if (leftType == Type::String) {
if (node.op == ' ') {
RaiseError(gd::ExpressionParserError::ErrorType::SyntaxError,
RaiseError("syntax_error",
"You must add the operator + between texts or expressions. For "
"example: \"Your name: \" + VariableString(PlayerName).", node.rightHandSide->location);
}
@@ -116,26 +113,22 @@ 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 || leftType == Type::LegacyVariable) {
} else if (leftType == Type::Variable) {
RaiseOperatorError(
_("Operators (+, -, /, *) can't be used in variable names. Remove "
"the operator from the variable name."),
node.rightHandSide->location);
}
// The "required" type ("parentType") of the second operator is decided by:
// - the parent type. Unless it can (`number|string`) or should (`unknown`) be refined, then:
// - the first operand.
parentType = ShouldTypeBeRefined(parentType) ? leftType : parentType;
parentType = leftType;
node.rightHandSide->Visit(*this);
const Type rightType = childType;
// The type of the overall operator ("childType") is decided by:
// - the parent type. Unless it can (`number|string`) or should (`unknown`) be refined, then:
// - the first operand. Unless it can (`number|string`) or should (`unknown`) be refined, then:
// - the right operand (which got visited knowing the type of the first operand, so it's
// The type is decided by the first operand, unless it can (`number|string`)
// or should (`unknown`) be refined, in which case we go for the right
// operand (which got visited knowing the type of the first operand, so it's
// equal or strictly more precise than the left operand).
childType = ShouldTypeBeRefined(parentType) ? (ShouldTypeBeRefined(leftType) ? leftType : rightType) : parentType;
childType = (leftType == Type::Unknown || leftType == Type::NumberOrString) ? leftType : rightType;
}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
ReportAnyError(node);
@@ -163,7 +156,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 || rightType == Type::LegacyVariable) {
} else if (rightType == Type::Variable) {
RaiseTypeError(
_("Operators (+, -) can't be used in variable names. Remove "
"the operator from the variable name."),
@@ -201,20 +194,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
ReportAnyError(node);
if (parentType == Type::Variable) {
childType = parentType;
if (!currentParameterExtraInfo || *currentParameterExtraInfo != "AllowUndeclaredVariable") {
const auto& variablesContainersList = projectScopedContainers.GetVariablesContainersList();
if (!variablesContainersList.Has(node.name)) {
RaiseUndeclaredVariableError(_("No variable with this name found."), node.location, node.name);
}
}
if (node.child) {
node.child->Visit(*this);
}
} else if (parentType == Type::LegacyVariable) {
childType = parentType;
childType = Type::Variable;
if (node.child) {
node.child->Visit(*this);
@@ -284,7 +264,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
ReportAnyError(node);
if (forbidsUsageOfBracketsBecauseParentIsObject) {
RaiseError(gd::ExpressionParserError::ErrorType::BracketsNotAllowedForObjects,
RaiseError("brackets_not_allowed_for_objects",
_("You can't use the brackets to access an object variable. "
"Use a dot followed by the variable name, like this: "
"`MyObject.MyVariable`."),
@@ -294,10 +274,7 @@ 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) {
@@ -310,7 +287,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
if (!ValidateObjectVariableOrVariableOrProperty(node)) {
// The identifier is not a variable, so either the variable is not properly declared
// or it's a text without quotes.
RaiseUnknownIdentifierError(_("You must wrap your text inside double quotes "
RaiseTypeError(_("You must wrap your text inside double quotes "
"(example: \"Hello world\")."),
node.location);
}
@@ -318,27 +295,20 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
else if (parentType == Type::Number) {
if (!ValidateObjectVariableOrVariableOrProperty(node)) {
// The identifier is not a variable, so the variable is not properly declared.
RaiseUnknownIdentifierError(_("You must enter a number."), node.location);
RaiseTypeError(
_("You must enter a number."), node.location);
}
}
else if (parentType == Type::NumberOrString) {
if (!ValidateObjectVariableOrVariableOrProperty(node)) {
// The identifier is not a variable, so either the variable is not properly declared
// or it's a text without quotes.
RaiseUnknownIdentifierError(
RaiseTypeError(
_("You must enter a number or a text, wrapped inside double quotes (example: \"Hello world\"), or a variable name."),
node.location);
}
}
else if (parentType == Type::Variable) {
if (!currentParameterExtraInfo || *currentParameterExtraInfo != "AllowUndeclaredVariable") {
const auto& variablesContainersList = projectScopedContainers.GetVariablesContainersList();
if (!variablesContainersList.Has(node.identifierName)) {
RaiseUndeclaredVariableError(_("No variable with this name found."), node.location, node.identifierName);
}
}
}
else if (parentType != Type::Object && parentType != Type::LegacyVariable) {
else if (parentType != Type::Object && parentType != Type::Variable) {
// It can't happen.
RaiseTypeError(
_("You've entered a name, but this type was expected:") + " " + TypeToString(parentType),
@@ -362,7 +332,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 || parentType == Type::LegacyVariable) {
} else if (parentType == Type::Variable) {
message = _("You must enter a variable name.");
} else if (parentType == Type::Object) {
message = _("You must enter a valid object name.");
@@ -375,12 +345,12 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
}
private:
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, LegacyVariable, Object, Empty};
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, Object, Empty};
Type ValidateFunction(const gd::FunctionCallNode& function);
bool ValidateObjectVariableOrVariableOrProperty(const gd::IdentifierNode& identifier);
void ReportAnyError(const ExpressionNode& node, bool isFatal = true) {
if (node.diagnostic) {
if (node.diagnostic && node.diagnostic->IsError()) {
// Syntax errors are holden by the AST nodes.
// It's fine to give pointers on them as the AST live longer than errors
// handling.
@@ -391,13 +361,10 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
}
}
void RaiseError(gd::ExpressionParserError::ErrorType type,
const gd::String &message,
const ExpressionParserLocation &location, bool isFatal = true,
const gd::String &actualValue = "",
const gd::String &objectName = "") {
void RaiseError(const gd::String &type,
const gd::String &message, const ExpressionParserLocation &location, bool isFatal = true) {
auto diagnostic = gd::make_unique<ExpressionParserError>(
type, message, location, actualValue, objectName);
type, message, location);
allErrors.push_back(diagnostic.get());
if (isFatal) {
fatalErrors.push_back(diagnostic.get());
@@ -408,31 +375,14 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
supplementalErrors.push_back(std::move(diagnostic));
}
void RaiseUnknownIdentifierError(const gd::String &message,
const ExpressionParserLocation &location) {
RaiseError(gd::ExpressionParserError::ErrorType::UnknownIdentifier, message,
location);
void RaiseTypeError(
const gd::String &message, const ExpressionParserLocation &location, bool isFatal = true) {
RaiseError("type_error", message, location, isFatal);
}
void RaiseUndeclaredVariableError(const gd::String &message,
const ExpressionParserLocation &location,
const gd::String &variableName,
const gd::String &objectName = "") {
RaiseError(gd::ExpressionParserError::ErrorType::UndeclaredVariable,
message, location, true, variableName, objectName);
}
void RaiseTypeError(const gd::String &message,
const ExpressionParserLocation &location,
bool isFatal = true) {
RaiseError(gd::ExpressionParserError::ErrorType::MismatchedType, message,
location, isFatal);
}
void RaiseOperatorError(const gd::String &message,
const ExpressionParserLocation &location) {
RaiseError(gd::ExpressionParserError::ErrorType::InvalidOperator, message,
location);
void RaiseOperatorError(
const gd::String &message, const ExpressionParserLocation &location) {
RaiseError("invalid_operator", message, location);
}
void ReadChildTypeFromVariable(gd::Variable::Type variableType) {
@@ -445,10 +395,6 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
}
}
static bool ShouldTypeBeRefined(Type type) {
return (type == Type::Unknown || type == Type::NumberOrString);
}
static Type StringToType(const gd::String &type);
static const gd::String &TypeToString(Type type);
static const gd::String unknownTypeString;
@@ -456,21 +402,20 @@ 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;
std::vector<ExpressionParserError*> fatalErrors;
std::vector<ExpressionParserError*> allErrors;
std::vector<std::unique_ptr<ExpressionParserError>> supplementalErrors;
std::vector<ExpressionParserDiagnostic*> fatalErrors;
std::vector<ExpressionParserDiagnostic*> allErrors;
std::vector<std::unique_ptr<ExpressionParserDiagnostic>> supplementalErrors;
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

View File

@@ -1,55 +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 "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

View File

@@ -0,0 +1,370 @@
/*
* 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){};
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 = &currentVariable->GetAtIndex(0);
} else {
currentVariable =
currentVariable->GetAllChildren().begin()->second.get();
}
} else {
if (!currentVariable->HasChild(childName)) {
// Non existing child - there is no "parent".
return {};
}
currentVariable = &currentVariable->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

View File

@@ -1,195 +0,0 @@
/*
* 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

View File

@@ -1,357 +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/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);
if (variable && variable->GetType() != gd::Variable::Array) {
return gd::Variable::Unknown;
}
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 = &currentVariable->GetAtIndex(0);
} else {
currentVariable =
currentVariable->GetAllChildren().begin()->second.get();
}
} else {
if (!currentVariable->HasChild(childName)) {
// Non existing child - there is no "parent".
return nullptr;
}
currentVariable = &currentVariable->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 = &currentVariable->GetAtIndex(0);
} else {
currentVariable =
currentVariable->GetAllChildren().begin()->second.get();
}
} else {
if (!currentVariable->HasChild(childName)) {
// Non existing child - there is no "parent".
return {};
}
currentVariable = &currentVariable->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

View File

@@ -22,7 +22,12 @@ 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();
@@ -40,11 +45,13 @@ 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...
@@ -76,11 +83,13 @@ 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".

View File

@@ -3,11 +3,11 @@
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#if defined(GD_IDE_ONLY)
#ifndef EventsFunctionTools_H
#define EventsFunctionTools_H
#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,6 +67,10 @@ 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

View File

@@ -1,111 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "ObjectAssetSerializer.h"
#include <algorithm>
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/Project/AssetResourcePathCleaner.h"
#include "GDCore/IDE/Project/ResourcesInUseHelper.h"
#include "GDCore/IDE/Project/ResourcesRenamer.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/CustomBehavior.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/Log.h"
namespace gd {
gd::String
ObjectAssetSerializer::GetObjectExtensionName(const gd::Object &object) {
const gd::String &type = object.GetType();
const auto separatorIndex =
type.find(PlatformExtension::GetNamespaceSeparator());
return separatorIndex != std::string::npos ? type.substr(0, separatorIndex)
: "";
}
void ObjectAssetSerializer::SerializeTo(
gd::Project &project, const gd::Object &object,
const gd::String &objectFullName, SerializerElement &element,
std::vector<gd::String> &usedResourceNames) {
auto cleanObject = object.Clone();
cleanObject->GetVariables().Clear();
cleanObject->GetEffects().Clear();
for (auto &&behaviorName : cleanObject->GetAllBehaviorNames()) {
cleanObject->RemoveBehavior(behaviorName);
}
gd::String extensionName = GetObjectExtensionName(*cleanObject);
element.SetAttribute("id", "");
element.SetAttribute("name", "");
element.SetAttribute("license", "");
if (project.HasEventsFunctionsExtensionNamed(extensionName)) {
auto &extension = project.GetEventsFunctionsExtension(extensionName);
element.SetAttribute("description", extension.GetShortDescription());
}
element.SetAttribute("gdevelopVersion", "");
element.SetAttribute("version", "");
element.SetIntAttribute("animationsCount", 1);
element.SetIntAttribute("maxFramesCount", 1);
// TODO Find the right object dimensions.
element.SetIntAttribute("width", 0);
element.SetIntAttribute("height", 0);
SerializerElement &authorsElement = element.AddChild("authors");
authorsElement.ConsiderAsArrayOf("author");
SerializerElement &tagsElement = element.AddChild("tags");
tagsElement.ConsiderAsArrayOf("tag");
SerializerElement &objectAssetsElement = element.AddChild("objectAssets");
objectAssetsElement.ConsiderAsArrayOf("objectAsset");
SerializerElement &objectAssetElement =
objectAssetsElement.AddChild("objectAsset");
cleanObject->SerializeTo(objectAssetElement.AddChild("object"));
SerializerElement &resourcesElement =
objectAssetElement.AddChild("resources");
resourcesElement.ConsiderAsArrayOf("resource");
auto &resourcesManager = project.GetResourcesManager();
gd::ResourcesInUseHelper resourcesInUse(resourcesManager);
cleanObject->GetConfiguration().ExposeResources(resourcesInUse);
for (auto &&resourceName : resourcesInUse.GetAllResources()) {
if (resourceName.length() == 0) {
continue;
}
usedResourceNames.push_back(resourceName);
auto &resource = resourcesManager.GetResource(resourceName);
SerializerElement &resourceElement = resourcesElement.AddChild("resource");
resource.SerializeTo(resourceElement);
resourceElement.SetAttribute("kind", resource.GetKind());
resourceElement.SetAttribute("name", resource.GetName());
}
SerializerElement &requiredExtensionsElement =
objectAssetElement.AddChild("requiredExtensions");
requiredExtensionsElement.ConsiderAsArrayOf("requiredExtension");
if (project.HasEventsFunctionsExtensionNamed(extensionName)) {
SerializerElement &requiredExtensionElement =
requiredExtensionsElement.AddChild("requiredExtension");
requiredExtensionElement.SetAttribute("extensionName", extensionName);
requiredExtensionElement.SetAttribute("extensionVersion", "1.0.0");
}
// TODO This can be removed when the asset script no longer require it.
SerializerElement &customizationElement =
objectAssetElement.AddChild("customization");
customizationElement.ConsiderAsArrayOf("empty");
}
} // namespace gd

View File

@@ -1,57 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <map>
#include <vector>
#include "GDCore/String.h"
namespace gd {
class Object;
class ExtensionDependency;
class PropertyDescriptor;
class Project;
class Layout;
class ArbitraryResourceWorker;
class InitialInstance;
class SerializerElement;
class EffectsContainer;
class AbstractFileSystem;
} // namespace gd
namespace gd {
/**
* \brief Serialize objects into an asset for the store.
*
* \ingroup IDE
*/
class GD_CORE_API ObjectAssetSerializer {
public:
/**
* \brief Serialize an object into an asset.
*
* \param project The project that contains the object and its resources.
* It's not actually modified.
* \param object The object to serialize as an asset.
* \param objectFullName The object name with spaces instead of PascalCase.
* \param element The element where the asset is serialize.
* \param usedResourceNames Return the names of the resources used by the asset.
*/
static void
SerializeTo(gd::Project &project, const gd::Object &object,
const gd::String &objectFullName, SerializerElement &element,
std::vector<gd::String> &usedResourceNames);
~ObjectAssetSerializer(){};
private:
ObjectAssetSerializer(){};
static gd::String GetObjectExtensionName(const gd::Object &object);
};
} // namespace gd

View File

@@ -52,16 +52,6 @@ void ArbitraryResourceWorker::ExposeModel3D(gd::String& resourceName){
// do.
};
void ArbitraryResourceWorker::ExposeAtlas(gd::String& resourceName){
// Nothing to do by default - each child class can define here the action to
// do.
};
void ArbitraryResourceWorker::ExposeSpine(gd::String& resourceName){
// Nothing to do by default - each child class can define here the action to
// do.
};
void ArbitraryResourceWorker::ExposeVideo(gd::String& videoName){
// Nothing to do by default - each child class can define here the action to
// do.
@@ -130,7 +120,6 @@ void ArbitraryResourceWorker::ExposeEmbeddeds(gd::String& resourceName) {
gd::String potentiallyUpdatedTargetResourceName = targetResourceName;
ExposeResourceWithType(targetResource.GetKind(), potentiallyUpdatedTargetResourceName);
ExposeEmbeddeds(potentiallyUpdatedTargetResourceName);
if (potentiallyUpdatedTargetResourceName != targetResourceName) {
// The resource name was renamed. Also update the mapping.
@@ -187,14 +176,6 @@ void ArbitraryResourceWorker::ExposeResourceWithType(
ExposeVideo(resourceName);
return;
}
if (resourceType == "atlas") {
ExposeAtlas(resourceName);
return;
}
if (resourceType == "spine") {
ExposeSpine(resourceName);
return;
}
gd::LogError("Unexpected resource type: " + resourceType + " for: " + resourceName);
return;
}
@@ -263,14 +244,6 @@ bool ResourceWorkerInEventsWorker::DoVisitInstruction(gd::Instruction& instructi
gd::String updatedParameterValue = parameterValue;
worker.ExposeModel3D(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
} else if (parameterMetadata.GetType() == "atlasResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeAtlas(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
} else if (parameterMetadata.GetType() == "spineResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeSpine(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
}
});

View File

@@ -96,16 +96,6 @@ public:
* \brief Expose a 3D model, which is always a reference to a "model3D" resource.
*/
virtual void ExposeModel3D(gd::String &resourceName);
/**
* \brief Expose an atlas, which is always a reference to a "atlas" resource.
*/
virtual void ExposeAtlas(gd::String &resourceName);
/**
* \brief Expose an spine, which is always a reference to a "spine" resource.
*/
virtual void ExposeSpine(gd::String &resourceName);
/**
* \brief Expose a video, which is always a reference to a "video" resource.
@@ -133,15 +123,14 @@ public:
*/
virtual void ExposeEmbeddeds(gd::String &resourceName);
protected:
gd::ResourcesManager * resourcesManager;
private:
/**
* \brief Expose a resource: resources that have a file are
* exposed as file (see ExposeFile).
*/
void ExposeResource(gd::Resource &resource);
gd::ResourcesManager * resourcesManager;
};
/**

View File

@@ -1,74 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "AssetResourcePathCleaner.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ResourcesManager.h"
#include "GDCore/String.h"
namespace gd {
void AssetResourcePathCleaner::ExposeImage(gd::String &imageName) {
ExposeResourceAsFile(imageName);
}
void AssetResourcePathCleaner::ExposeAudio(gd::String &audioName) {
ExposeResourceAsFile(audioName);
}
void AssetResourcePathCleaner::ExposeFont(gd::String &fontName) {
ExposeResourceAsFile(fontName);
}
void AssetResourcePathCleaner::ExposeJson(gd::String &jsonName) {
ExposeResourceAsFile(jsonName);
}
void AssetResourcePathCleaner::ExposeTilemap(gd::String &tilemapName) {
ExposeResourceAsFile(tilemapName);
}
void AssetResourcePathCleaner::ExposeTileset(gd::String &tilesetName) {
ExposeResourceAsFile(tilesetName);
}
void AssetResourcePathCleaner::ExposeVideo(gd::String &videoName) {
ExposeResourceAsFile(videoName);
}
void AssetResourcePathCleaner::ExposeBitmapFont(gd::String &bitmapFontName) {
ExposeResourceAsFile(bitmapFontName);
}
void AssetResourcePathCleaner::ExposeResourceAsFile(gd::String &resourceName) {
auto &resource = resourcesManager->GetResource(resourceName);
gd::String file = resource.GetFile();
ExposeFile(file);
resourcesNameReverseMap[file] = resourceName;
resourceName = file;
}
void AssetResourcePathCleaner::ExposeFile(gd::String &resourceFilePath) {
size_t slashPos = resourceFilePath.find_last_of("/");
size_t antiSlashPos = resourceFilePath.find_last_of("\\");
size_t baseNamePos =
slashPos == String::npos
? antiSlashPos == String::npos ? 0 : (antiSlashPos + 1)
: antiSlashPos == String::npos ? (slashPos + 1)
: slashPos > antiSlashPos ? (slashPos + 1)
: (antiSlashPos + 1);
gd::String baseName =
baseNamePos != 0
? resourceFilePath.substr(baseNamePos, resourceFilePath.length())
: resourceFilePath;
resourcesFileNameMap[resourceFilePath] = baseName;
resourceFilePath = baseName;
}
} // namespace gd

View File

@@ -1,65 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/IDE/Project/ResourcesMergingHelper.h"
#include "GDCore/String.h"
#include <map>
#include <memory>
#include <vector>
namespace gd {
class AbstractFileSystem;
class Project;
} // namespace gd
namespace gd {
/**
* \brief AssetResourcePathCleaner is used when exporting an object as an asset.
* It removes the folder from the path.
*
* \see ArbitraryResourceWorker
*
* \ingroup IDE
*/
class GD_CORE_API AssetResourcePathCleaner : public ArbitraryResourceWorker {
public:
AssetResourcePathCleaner(
gd::ResourcesManager &resourcesManager,
std::map<gd::String, gd::String> &resourcesFileNameMap_,
std::map<gd::String, gd::String> &resourcesNameReverseMap_)
: ArbitraryResourceWorker(resourcesManager),
resourcesFileNameMap(resourcesFileNameMap_),
resourcesNameReverseMap(resourcesNameReverseMap_){};
virtual ~AssetResourcePathCleaner(){};
void ExposeImage(gd::String &imageName) override;
void ExposeAudio(gd::String &audioName) override;
void ExposeFont(gd::String &fontName) override;
void ExposeJson(gd::String &jsonName) override;
void ExposeTilemap(gd::String &tilemapName) override;
void ExposeTileset(gd::String &tilesetName) override;
void ExposeVideo(gd::String &videoName) override;
void ExposeBitmapFont(gd::String &bitmapFontName) override;
void ExposeFile(gd::String &resource) override;
protected:
void ExposeResourceAsFile(gd::String &resourceName);
/**
* New file names that can be accessed by their original name.
*/
std::map<gd::String, gd::String> &resourcesFileNameMap;
/**
* Original resource names that can be accessed by their new name.
*/
std::map<gd::String, gd::String> &resourcesNameReverseMap;
};
} // namespace gd

View File

@@ -79,12 +79,6 @@ public:
virtual void ExposeModel3D(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
virtual void ExposeAtlas(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
virtual void ExposeSpine(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
void MatchResourceName(gd::String& otherResourceName) {
if (otherResourceName == resourceName) matchesResourceName = true;

View File

@@ -3,10 +3,9 @@
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef PROJECTRESOURCESCOPIER_H
#define PROJECTRESOURCESCOPIER_H
#include "GDCore/String.h"
namespace gd {
class Project;
class AbstractFileSystem;
@@ -48,7 +47,6 @@ class GD_CORE_API ProjectResourcesCopier {
bool updateOriginalProject,
bool preserveAbsoluteFilenames = true,
bool preserveDirectoryStructure = true);
private:
static bool CopyAllResourcesTo(gd::Project& originalProject,
gd::Project& clonedProject,
@@ -59,3 +57,5 @@ private:
};
} // namespace gd
#endif // PROJECTRESOURCESCOPIER_H

View File

@@ -1,25 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "ResourcesInUseHelper.h"
namespace gd {
const std::vector<gd::String> ResourcesInUseHelper::resourceTypes = {
"image", "audio", "font", "json", "tilemap",
"tileset", "video", "bitmapFont", "model3D"};
const std::vector<gd::String> &ResourcesInUseHelper::GetAllResources() {
allResources.clear();
for (auto &&resourceType : gd::ResourcesInUseHelper::resourceTypes) {
for (auto &&resourceName : GetAll(resourceType)) {
allResources.push_back(resourceName);
}
}
return allResources;
}
} // namespace gd

View File

@@ -4,7 +4,9 @@
* reserved. This project is released under the MIT License.
*/
#pragma once
#if defined(GD_IDE_ONLY)
#ifndef IMAGESUSEDINVENTORIZER_H
#define IMAGESUSEDINVENTORIZER_H
#include <set>
#include <vector>
@@ -36,7 +38,6 @@ public:
: gd::ArbitraryResourceWorker(resourcesManager){};
virtual ~ResourcesInUseHelper(){};
const std::vector<gd::String>& GetAllResources();
std::set<gd::String>& GetAllImages() { return GetAll("image"); };
std::set<gd::String>& GetAllAudios() { return GetAll("audio"); };
std::set<gd::String>& GetAllFonts() { return GetAll("font"); };
@@ -46,8 +47,6 @@ public:
std::set<gd::String>& GetAllVideos() { return GetAll("video"); };
std::set<gd::String>& GetAllBitmapFonts() { return GetAll("bitmapFont"); };
std::set<gd::String>& GetAll3DModels() { return GetAll("model3D"); };
std::set<gd::String>& GetAllAtlases() { return GetAll("atlas"); };
std::set<gd::String>& GetAllSpines() { return GetAll("spine"); };
std::set<gd::String>& GetAll(const gd::String& resourceType) {
if (resourceType == "image") return allImages;
if (resourceType == "audio") return allAudios;
@@ -58,8 +57,6 @@ public:
if (resourceType == "video") return allVideos;
if (resourceType == "bitmapFont") return allBitmapFonts;
if (resourceType == "model3D") return allModel3Ds;
if (resourceType == "atlas") return allAtlases;
if (resourceType == "spine") return allSpines;
return emptyResources;
};
@@ -67,42 +64,35 @@ public:
virtual void ExposeFile(gd::String& resource) override{
/*Don't care, we just list resource names*/
};
virtual void ExposeImage(gd::String& resourceName) override {
allImages.insert(resourceName);
virtual void ExposeImage(gd::String& imageResourceName) override {
allImages.insert(imageResourceName);
};
virtual void ExposeAudio(gd::String& resourceName) override {
allAudios.insert(resourceName);
virtual void ExposeAudio(gd::String& audioResourceName) override {
allAudios.insert(audioResourceName);
};
virtual void ExposeFont(gd::String& resourceName) override {
allFonts.insert(resourceName);
virtual void ExposeFont(gd::String& fontResourceName) override {
allFonts.insert(fontResourceName);
};
virtual void ExposeJson(gd::String& resourceName) override {
allJsons.insert(resourceName);
virtual void ExposeJson(gd::String& jsonResourceName) override {
allJsons.insert(jsonResourceName);
};
virtual void ExposeTilemap(gd::String& resourceName) override {
allTilemaps.insert(resourceName);
virtual void ExposeTilemap(gd::String& tilemapResourceName) override {
allTilemaps.insert(tilemapResourceName);
};
virtual void ExposeTileset(gd::String& resourceName) override {
allTilesets.insert(resourceName);
virtual void ExposeTileset(gd::String& tilesetResourceName) override {
allTilesets.insert(tilesetResourceName);
};
virtual void ExposeVideo(gd::String& resourceName) override {
allVideos.insert(resourceName);
virtual void ExposeVideo(gd::String& videoResourceName) override {
allVideos.insert(videoResourceName);
};
virtual void ExposeBitmapFont(gd::String& resourceName) override {
allBitmapFonts.insert(resourceName);
virtual void ExposeBitmapFont(gd::String& bitmapFontResourceName) override {
allBitmapFonts.insert(bitmapFontResourceName);
};
virtual void ExposeModel3D(gd::String& resourceName) override {
allModel3Ds.insert(resourceName);
};
virtual void ExposeAtlas(gd::String& resourceName) override {
allAtlases.insert(resourceName);
};
virtual void ExposeSpine(gd::String& resourceName) override {
allSpines.insert(resourceName);
};
protected:
std::vector<gd::String> allResources;
std::set<gd::String> allImages;
std::set<gd::String> allAudios;
std::set<gd::String> allFonts;
@@ -112,11 +102,10 @@ public:
std::set<gd::String> allVideos;
std::set<gd::String> allBitmapFonts;
std::set<gd::String> allModel3Ds;
std::set<gd::String> allAtlases;
std::set<gd::String> allSpines;
std::set<gd::String> emptyResources;
static const std::vector<gd::String> resourceTypes;
};
} // namespace gd
#endif // IMAGESUSEDINVENTORIZER_H
#endif

View File

@@ -28,7 +28,7 @@ void ResourcesMergingHelper::ExposeFile(gd::String& resourceFilename) {
auto stripToFilenameOnly = [&]() {
fs.MakeAbsolute(resourceFullFilename, baseDirectory);
SetNewFilename(resourceFullFilename, fs.FileNameFrom(resourceFullFilename));
resourceFilename = newFilenames[resourceFullFilename];
resourceFilename = oldFilenames[resourceFullFilename];
};
// if we do not want to preserve the folders at all,
@@ -45,7 +45,7 @@ void ResourcesMergingHelper::ExposeFile(gd::String& resourceFilename) {
gd::String relativeFilename = resourceFullFilename;
if (fs.MakeRelative(relativeFilename, baseDirectory)) {
SetNewFilename(resourceFullFilename, relativeFilename);
resourceFilename = newFilenames[resourceFullFilename];
resourceFilename = oldFilenames[resourceFullFilename];
} else {
// The filename cannot be made relative. Consider that it is absolute.
// Just strip the filename to its file part
@@ -63,7 +63,7 @@ void ResourcesMergingHelper::ExposeFile(gd::String& resourceFilename) {
void ResourcesMergingHelper::SetNewFilename(gd::String oldFilename,
gd::String newFilename) {
if (newFilenames.find(oldFilename) != newFilenames.end()) return;
if (oldFilenames.find(oldFilename) != oldFilenames.end()) return;
// Extract baseName and extension from the new filename
size_t extensionPos = newFilename.find_last_of(".");
@@ -80,13 +80,13 @@ void ResourcesMergingHelper::SetNewFilename(gd::String oldFilename,
gd::NewNameGenerator::Generate(
baseName,
[this, extension](const gd::String& newBaseName) {
return oldFilenames.find(newBaseName + extension) !=
oldFilenames.end();
return newFilenames.find(newBaseName + extension) !=
newFilenames.end();
}) +
extension;
newFilenames[oldFilename] = finalFilename;
oldFilenames[finalFilename] = oldFilename;
oldFilenames[oldFilename] = finalFilename;
newFilenames[finalFilename] = oldFilename;
}
void ResourcesMergingHelper::SetBaseDirectory(

View File

@@ -64,25 +64,19 @@ public:
* the Base Directory.
*/
std::map<gd::String, gd::String>& GetAllResourcesOldAndNewFilename() {
return newFilenames;
return oldFilenames;
};
/**
* Resources merging helper collects all resources filenames and update these
* filenames.
*/
void ExposeFile(gd::String& resource) override;
virtual void ExposeFile(gd::String& resource) override;
protected:
void SetNewFilename(gd::String oldFilename, gd::String newFilename);
/**
* Original file names that can be accessed by their new name.
*/
std::map<gd::String, gd::String> oldFilenames;
/**
* New file names that can be accessed by their original name.
*/
std::map<gd::String, gd::String> newFilenames;
gd::String baseDirectory;
bool preserveDirectoriesStructure; ///< If set to true, the directory

View File

@@ -65,12 +65,6 @@ class ResourcesRenamer : public gd::ArbitraryResourceWorker {
virtual void ExposeModel3D(gd::String& resourceName) override {
RenameIfNeeded(resourceName);
};
virtual void ExposeAtlas(gd::String& resourceName) override {
RenameIfNeeded(resourceName);
};
virtual void ExposeSpine(gd::String& resourceName) override {
RenameIfNeeded(resourceName);
};
private:
void RenameIfNeeded(gd::String& resourceName) {

View File

@@ -80,12 +80,6 @@ private:
void ExposeModel3D(gd::String &resourceName) override {
AddUsedResource(resourceName);
};
void ExposeAtlas(gd::String &resourceName) override {
AddUsedResource(resourceName);
};
void ExposeSpine(gd::String &resourceName) override {
AddUsedResource(resourceName);
};
std::set<gd::String> resourceNames;
};

View File

@@ -148,6 +148,12 @@ 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());
}
@@ -170,11 +176,14 @@ void ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
gd::ArbitraryEventsWorkerWithContext &worker) {
// Add (free) events functions
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
gd::ObjectsContainer parameterObjectsContainer;
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForFreeEventsFunction(
project, eventsFunctionsExtension, *eventsFunction,
parameterObjectsContainer);
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));
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
}
@@ -183,13 +192,13 @@ void ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
for (auto &&eventsBasedBehavior :
eventsFunctionsExtension.GetEventsBasedBehaviors()
.GetInternalVector()) {
ExposeEventsBasedBehaviorEvents(project, eventsFunctionsExtension, *eventsBasedBehavior, worker);
ExposeEventsBasedBehaviorEvents(project, *eventsBasedBehavior, worker);
}
// Add (object) events functions
for (auto &&eventsBasedObject :
eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) {
ExposeEventsBasedObjectEvents(project, eventsFunctionsExtension, *eventsBasedObject, worker);
ExposeEventsBasedObjectEvents(project, *eventsBasedObject, worker);
}
}
@@ -203,17 +212,20 @@ void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
}
void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedBehavior &eventsBasedBehavior,
gd::Project &project, const gd::EventsBasedBehavior &eventsBasedBehavior,
gd::ArbitraryEventsWorkerWithContext &worker) {
auto &behaviorEventsFunctions = eventsBasedBehavior.GetEventsFunctions();
for (auto &&eventsFunction : behaviorEventsFunctions.GetInternalVector()) {
gd::ObjectsContainer parameterObjectsContainers;
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForBehaviorEventsFunction(
project, eventsFunctionsExtension, eventsBasedBehavior,
*eventsFunction, parameterObjectsContainers);
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()));
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
}
@@ -224,23 +236,30 @@ 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::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedObject &eventsBasedObject,
gd::Project &project, const gd::EventsBasedObject &eventsBasedObject,
gd::ArbitraryEventsWorkerWithContext &worker) {
auto &objectEventsFunctions = eventsBasedObject.GetEventsFunctions();
for (auto &&eventsFunction : objectEventsFunctions.GetInternalVector()) {
gd::ObjectsContainer parameterObjectsContainers;
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForObjectEventsFunction(
project, eventsFunctionsExtension, eventsBasedObject,
*eventsFunction, parameterObjectsContainers);
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()));
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
}

View File

@@ -122,9 +122,7 @@ public:
* event-based behavior.
*/
static void ExposeEventsBasedBehaviorEvents(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedBehavior &eventsBasedBehavior,
gd::Project &project, const gd::EventsBasedBehavior &eventsBasedBehavior,
gd::ArbitraryEventsWorkerWithContext &worker);
/**
@@ -146,11 +144,10 @@ 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::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedObject &eventsBasedObject,
gd::ArbitraryEventsWorkerWithContext &worker);
static void
ExposeEventsBasedObjectEvents(gd::Project &project,
const gd::EventsBasedObject &eventsBasedObject,
gd::ArbitraryEventsWorkerWithContext &worker);
/**
* \brief Call the specified worker on all ObjectContainers of the project

View File

@@ -30,26 +30,14 @@ 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);
extension.SetFullName("");
extension.SetShortDescription("");
extension.SetDescription("");
extension.SetHelpPath("");
extension.SetIconUrl("");
extension.SetPreviewIconUrl("");
extension.SetOrigin("", "");
extension.SetVersion("");
auto &eventsBasedObjects = extension.GetEventsBasedObjects();
if (eventsBasedObjects.size() == 0 &&
extension.GetGlobalVariables().Count() == 0 &&
extension.GetSceneVariables().Count() == 0) {
if (eventsBasedObjects.size() == 0) {
project.RemoveEventsFunctionsExtension(extension.GetName());
extensionIndex--;
continue;
@@ -63,7 +51,6 @@ void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project &project) {
eventsBasedObject.GetPropertyDescriptors().GetInternalVector().clear();
}
extension.GetEventsBasedBehaviors().Clear();
extension.ClearEventsFunctions();
}
}

View File

@@ -1,241 +0,0 @@
/*
* 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

View File

@@ -1,91 +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 "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

View File

@@ -16,17 +16,15 @@
#include "GDCore/IDE/Events/BehaviorTypeRenamer.h"
#include "GDCore/IDE/Events/CustomObjectTypeRenamer.h"
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
#include "GDCore/IDE/Events/EventsPropertyReplacer.h"
#include "GDCore/IDE/Events/EventsRefactorer.h"
#include "GDCore/IDE/Events/EventsPropertyReplacer.h"
#include "GDCore/IDE/Events/EventsVariableReplacer.h"
#include "GDCore/IDE/Events/EventsVariableInstructionTypeSwitcher.h"
#include "GDCore/IDE/Events/ExpressionsParameterMover.h"
#include "GDCore/IDE/Events/ExpressionsRenamer.h"
#include "GDCore/IDE/Events/InstructionsParameterMover.h"
#include "GDCore/IDE/Events/InstructionsTypeRenamer.h"
#include "GDCore/IDE/Events/LinkEventTargetRenamer.h"
#include "GDCore/IDE/Events/ProjectElementRenamer.h"
#include "GDCore/IDE/Events/BehaviorParametersFiller.h"
#include "GDCore/IDE/EventsFunctionTools.h"
#include "GDCore/IDE/Project/ArbitraryBehaviorSharedDataWorker.h"
#include "GDCore/IDE/Project/ArbitraryEventBasedBehaviorsWorker.h"
@@ -140,8 +138,8 @@ void WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
}
}
VariablesChangeset
WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
VariablesChangeset WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
gd::Project &project,
const gd::SerializerElement &oldSerializedVariablesContainer,
const gd::VariablesContainer &newVariablesContainer) {
gd::VariablesChangeset changeset;
@@ -151,9 +149,9 @@ WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
if (oldVariablesContainer.GetPersistentUuid() !=
newVariablesContainer.GetPersistentUuid()) {
gd::LogWarning(_(
"Called ComputeChangesetForVariablesContainer on variables containers "
"that are different - they can't be compared."));
gd::LogWarning(
_("Called ComputeChangesetForVariablesContainer on variables containers "
"that are different - they can't be compared."));
return changeset;
}
@@ -181,20 +179,6 @@ WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
changeset.oldToNewVariableNames[oldName] = variableName;
}
const auto &oldVariable = oldVariablesContainer.Get(oldName);
if (gd::WholeProjectRefactorer::HasAnyVariableTypeChanged(oldVariable, variable)) {
changeset.typeChangedVariableNames.insert(variableName);
}
const auto &variablesRenamingChangesetNode =
gd::WholeProjectRefactorer::ComputeChangesetForVariable(oldVariable,
variable);
if (variablesRenamingChangesetNode) {
changeset.modifiedVariables[oldName] =
std::move(variablesRenamingChangesetNode);
}
// Renamed or not, this is not a removed variable.
removedUuidAndNames.erase(variable.GetPersistentUuid());
}
@@ -207,124 +191,17 @@ WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
return changeset;
}
std::shared_ptr<VariablesRenamingChangesetNode>
WholeProjectRefactorer::ComputeChangesetForVariable(
const gd::Variable &oldVariable, const gd::Variable &newVariable) {
if (newVariable.GetChildrenCount() == 0 ||
oldVariable.GetChildrenCount() == 0) {
return std::shared_ptr<VariablesRenamingChangesetNode>(nullptr);
}
std::unordered_map<gd::String, gd::String> oldVariableNamesByUuid;
for (const auto &pair : oldVariable.GetAllChildren()) {
const auto &oldName = pair.first;
const auto oldChild = pair.second;
// All variables are candidate to be removed.
oldVariableNamesByUuid[oldChild->GetPersistentUuid()] = oldName;
}
auto changeset = std::make_shared<VariablesRenamingChangesetNode>();
for (const auto &pair : newVariable.GetAllChildren()) {
const auto &newName = pair.first;
const auto newChild = pair.second;
auto existingOldVariableUuidAndName =
oldVariableNamesByUuid.find(newChild->GetPersistentUuid());
if (existingOldVariableUuidAndName == oldVariableNamesByUuid.end()) {
// This is a new variable.
continue;
}
const gd::String &oldName = existingOldVariableUuidAndName->second;
const auto &oldChild = oldVariable.GetChild(oldName);
if (oldName != newName) {
// This is a renamed child.
changeset->oldToNewVariableNames[oldName] = newName;
}
const auto &childChangeset =
gd::WholeProjectRefactorer::ComputeChangesetForVariable(oldChild,
*newChild);
if (childChangeset) {
changeset->modifiedVariables[oldName] = std::move(childChangeset);
}
}
if (changeset->modifiedVariables.size() == 0 &&
changeset->oldToNewVariableNames.size() == 0) {
return std::shared_ptr<VariablesRenamingChangesetNode>(nullptr);
}
return std::move(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> oldVariableNamesByUuid;
for (const auto &pair : oldVariable.GetAllChildren()) {
const auto &oldName = pair.first;
const auto oldChild = pair.second;
// All variables are candidate to be removed.
oldVariableNamesByUuid[oldChild->GetPersistentUuid()] = oldName;
}
for (const auto &pair : newVariable.GetAllChildren()) {
const auto &newName = pair.first;
const auto newChild = pair.second;
auto existingOldVariableUuidAndName =
oldVariableNamesByUuid.find(newChild->GetPersistentUuid());
if (existingOldVariableUuidAndName == oldVariableNamesByUuid.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, gd::VariablesContainer &variablesContainer,
const gd::VariablesChangeset &changeset,
const gd::SerializerElement &originalSerializedVariables) {
// Revert changes
gd::SerializerElement editedSerializedVariables;
variablesContainer.SerializeTo(editedSerializedVariables);
variablesContainer.UnserializeFrom(originalSerializedVariables);
// Rename and remove variables
gd::Project &project,
const gd::VariablesContainer &newVariablesContainer,
const gd::VariablesChangeset& changeset) {
gd::EventsVariableReplacer eventsVariableReplacer(
project.GetCurrentPlatform(), variablesContainer,
changeset, changeset.removedVariableNames);
project.GetCurrentPlatform(),
newVariablesContainer,
changeset.oldToNewVariableNames,
changeset.removedVariableNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsVariableReplacer);
// Apply back changes
variablesContainer.UnserializeFrom(editedSerializedVariables);
// Switch types of instructions
gd::EventsVariableInstructionTypeSwitcher
eventsVariableInstructionTypeSwitcher(project.GetCurrentPlatform(),
variablesContainer,
changeset.typeChangedVariableNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(
project, eventsVariableInstructionTypeSwitcher);
}
void WholeProjectRefactorer::UpdateExtensionNameInEventsBasedBehavior(
@@ -333,7 +210,7 @@ void WholeProjectRefactorer::UpdateExtensionNameInEventsBasedBehavior(
gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::String &sourceExtensionName) {
const EventBasedBehaviorBrowser eventBasedBehaviorExposer(
eventsFunctionsExtension, eventsBasedBehavior);
eventsBasedBehavior);
WholeProjectRefactorer::RenameEventsFunctionsExtension(
project, eventsFunctionsExtension, sourceExtensionName,
eventsFunctionsExtension.GetName(), eventBasedBehaviorExposer);
@@ -849,7 +726,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
oldPropertyName, newPropertyName);
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
project, eventsFunctionsExtension, eventsBasedBehavior, behaviorRenamer);
project, eventsBasedBehavior, behaviorRenamer);
} else {
// Properties that represent primitive values will be used through
// their related actions/conditions/expressions. Rename these.
@@ -866,14 +743,14 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
{oldPropertyName, newPropertyName}};
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {{oldPropertyName, newPropertyName}};
std::unordered_set<gd::String> removedPropertyNames;
gd::EventsPropertyReplacer eventsPropertyReplacer(
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsPropertyReplacer);
project.GetCurrentPlatform(),
properties,
oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventsPropertyReplacer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -919,7 +796,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
oldPropertyName, newPropertyName);
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
project, eventsFunctionsExtension, eventsBasedBehavior, behaviorRenamer);
project, eventsBasedBehavior, behaviorRenamer);
} else {
// Properties that represent primitive values will be used through
// their related actions/conditions/expressions. Rename these.
@@ -936,14 +813,14 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
EventsBasedBehavior::GetSharedPropertyExpressionName(newPropertyName));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
{oldPropertyName, newPropertyName}};
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {{oldPropertyName, newPropertyName}};
std::unordered_set<gd::String> removedPropertyNames;
gd::EventsPropertyReplacer eventsPropertyReplacer(
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsPropertyReplacer);
project.GetCurrentPlatform(),
properties,
oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventsPropertyReplacer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -993,14 +870,14 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
EventsBasedObject::GetPropertyExpressionName(newPropertyName));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
{oldPropertyName, newPropertyName}};
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {{oldPropertyName, newPropertyName}};
std::unordered_set<gd::String> removedPropertyNames;
gd::EventsPropertyReplacer eventsPropertyReplacer(
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsPropertyReplacer);
project.GetCurrentPlatform(),
properties,
oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventsPropertyReplacer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -1474,6 +1351,7 @@ void WholeProjectRefactorer::DoRenameBehavior(
gd::Project &project, const gd::String &oldBehaviorType,
const gd::String &newBehaviorType,
const gd::ProjectBrowser &projectBrowser) {
// Rename behavior in required behavior properties
auto requiredBehaviorRenamer =
gd::RequiredBehaviorRenamer(oldBehaviorType, newBehaviorType);
@@ -1500,6 +1378,7 @@ void WholeProjectRefactorer::DoRenameBehavior(
void WholeProjectRefactorer::DoRenameObject(
gd::Project &project, const gd::String &oldObjectType,
const gd::String &newObjectType, const gd::ProjectBrowser &projectBrowser) {
// Rename object type in objects lists.
auto customObjectTypeRenamer =
gd::CustomObjectTypeRenamer(oldObjectType, newObjectType);
@@ -1516,46 +1395,59 @@ void WholeProjectRefactorer::DoRenameObject(
projectBrowser.ExposeFunctions(project, objectParameterRenamer);
}
void WholeProjectRefactorer::ObjectRemovedInLayout(
gd::Project &project, gd::Layout &layout, const gd::String &objectName) {
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
void WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
gd::Project &project, gd::Layout &layout, const gd::String &objectName,
bool isObjectGroup, bool removeEventsAndGroups) {
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
// Object groups can't have instances or be in other groups
for (std::size_t g = 0; g < layout.GetObjectGroups().size(); ++g) {
if (layout.GetObjectGroups()[g].Find(objectName))
layout.GetObjectGroups()[g].RemoveObject(objectName);
// Remove object in the current layout
if (removeEventsAndGroups) {
gd::EventsRefactorer::RemoveObjectInEvents(project.GetCurrentPlatform(),
projectScopedContainers,
layout.GetEvents(), objectName);
}
if (!isObjectGroup) { // Object groups can't have instances or be in other
// groups
if (removeEventsAndGroups) {
for (std::size_t g = 0; g < layout.GetObjectGroups().size(); ++g) {
if (layout.GetObjectGroups()[g].Find(objectName))
layout.GetObjectGroups()[g].RemoveObject(objectName);
}
}
layout.GetInitialInstances().RemoveInitialInstancesOfObject(objectName);
}
// Remove object in external events
if (removeEventsAndGroups) {
for (auto &externalEventsName :
GetAssociatedExternalEvents(project, layout.GetName())) {
auto &externalEvents = project.GetExternalEvents(externalEventsName);
gd::EventsRefactorer::RemoveObjectInEvents(
project.GetCurrentPlatform(), projectScopedContainers,
externalEvents.GetEvents(), objectName);
}
}
layout.GetInitialInstances().RemoveInitialInstancesOfObject(objectName);
// Remove object in external layouts
std::vector<gd::String> externalLayoutsNames =
GetAssociatedExternalLayouts(project, layout);
for (gd::String name : externalLayoutsNames) {
auto &externalLayout = project.GetExternalLayout(name);
externalLayout.GetInitialInstances().RemoveInitialInstancesOfObject(
objectName);
if (!isObjectGroup) { // Object groups can't have instances
std::vector<gd::String> externalLayoutsNames =
GetAssociatedExternalLayouts(project, layout);
for (gd::String name : externalLayoutsNames) {
auto &externalLayout = project.GetExternalLayout(name);
externalLayout.GetInitialInstances().RemoveInitialInstancesOfObject(
objectName);
}
}
}
void WholeProjectRefactorer::BehaviorsAddedToObjectInLayout(
gd::Project &project, gd::Layout &layout, const gd::String &objectName) {
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
gd::BehaviorParametersFiller behaviorParameterFiller(
project.GetCurrentPlatform(), projectScopedContainers);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, behaviorParameterFiller);
}
void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
gd::Project &project, gd::Layout &layout, const gd::String &oldName,
const gd::String &newName, bool isObjectGroup) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
// Rename object in the current layout
gd::EventsRefactorer::RenameObjectInEvents(
@@ -1644,19 +1536,10 @@ void WholeProjectRefactorer::RenameLayer(gd::Project &project,
const gd::String &newName) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
gd::ProjectElementRenamer projectElementRenamer(project.GetCurrentPlatform(),
"layer", oldName, newName);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, projectElementRenamer);
layout.GetInitialInstances().MoveInstancesToLayer(oldName, newName);
std::vector<gd::String> externalLayoutsNames =
GetAssociatedExternalLayouts(project, layout);
for (gd::String name : externalLayoutsNames) {
auto &externalLayout = project.GetExternalLayout(name);
externalLayout.GetInitialInstances().MoveInstancesToLayer(oldName, newName);
}
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
projectElementRenamer);
}
void WholeProjectRefactorer::RenameLayerEffect(gd::Project &project,
@@ -1669,8 +1552,8 @@ void WholeProjectRefactorer::RenameLayerEffect(gd::Project &project,
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "layerEffectName", oldName, newName);
projectElementRenamer.SetLayerConstraint(layer.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, projectElementRenamer);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
projectElementRenamer);
}
void WholeProjectRefactorer::RenameObjectAnimation(gd::Project &project,
@@ -1683,8 +1566,8 @@ void WholeProjectRefactorer::RenameObjectAnimation(gd::Project &project,
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "objectAnimationName", oldName, newName);
projectElementRenamer.SetObjectConstraint(object.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, projectElementRenamer);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
projectElementRenamer);
}
void WholeProjectRefactorer::RenameObjectPoint(gd::Project &project,
@@ -1697,8 +1580,8 @@ void WholeProjectRefactorer::RenameObjectPoint(gd::Project &project,
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "objectPointName", oldName, newName);
projectElementRenamer.SetObjectConstraint(object.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, projectElementRenamer);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
projectElementRenamer);
}
void WholeProjectRefactorer::RenameObjectEffect(gd::Project &project,
@@ -1711,32 +1594,46 @@ void WholeProjectRefactorer::RenameObjectEffect(gd::Project &project,
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "objectEffectName", oldName, newName);
projectElementRenamer.SetObjectConstraint(object.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, projectElementRenamer);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
projectElementRenamer);
}
void WholeProjectRefactorer::ObjectRemovedInEventsBasedObject(
void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsBasedObject(
gd::Project &project, gd::EventsBasedObject &eventsBasedObject,
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer, const gd::String &objectName) {
gd::ObjectsContainer &objectsContainer, const gd::String &objectName,
bool isObjectGroup, bool removeEventsAndGroups) {
for (auto &functionUniquePtr :
eventsBasedObject.GetEventsFunctions().GetInternalVector()) {
auto function = functionUniquePtr.get();
WholeProjectRefactorer::ObjectRemovedInEventsFunction(
WholeProjectRefactorer::ObjectOrGroupRemovedInEventsFunction(
project, *function, globalObjectsContainer, objectsContainer,
objectName);
objectName, isObjectGroup, isObjectGroup);
}
}
void WholeProjectRefactorer::ObjectRemovedInEventsFunction(
void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsFunction(
gd::Project &project, gd::EventsFunction &eventsFunction,
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer, const gd::String &objectName) {
gd::ObjectsContainer &objectsContainer, const gd::String &objectName,
bool isObjectGroup, bool removeEventsAndGroups) {
// In theory we should pass a ProjectScopedContainers to this function so it does not have to construct one.
// In practice, this is ok because we only deal with objects.
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsContainer, objectsContainer);
for (std::size_t g = 0; g < eventsFunction.GetObjectGroups().size();
++g) {
if (eventsFunction.GetObjectGroups()[g].Find(objectName))
eventsFunction.GetObjectGroups()[g].RemoveObject(objectName);
if (removeEventsAndGroups) {
gd::EventsRefactorer::RemoveObjectInEvents(
project.GetCurrentPlatform(), projectScopedContainers,
eventsFunction.GetEvents(), objectName);
}
if (!isObjectGroup) { // Object groups can't be in other groups
if (removeEventsAndGroups) {
for (std::size_t g = 0; g < eventsFunction.GetObjectGroups().size();
++g) {
if (eventsFunction.GetObjectGroups()[g].Find(objectName))
eventsFunction.GetObjectGroups()[g].RemoveObject(objectName);
}
}
}
}
@@ -1758,19 +1655,15 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer, const gd::String &oldName,
const gd::String &newName, bool isObjectGroup) {
// In theory we should pass a ProjectScopedContainers to this function so it
// does not have to construct one. In practice, this is ok because we only
// deal with objects.
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(
globalObjectsContainer, objectsContainer);
// In theory we should pass a ProjectScopedContainers to this function so it does not have to construct one.
// In practice, this is ok because we only deal with objects.
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsContainer, objectsContainer);
gd::EventsRefactorer::RenameObjectInEvents(
project.GetCurrentPlatform(), projectScopedContainers,
eventsFunction.GetEvents(), oldName, newName);
// Object groups can't be in other groups
if (!isObjectGroup) {
if (!isObjectGroup) { // Object groups can't be in other groups
for (std::size_t g = 0; g < eventsFunction.GetObjectGroups().size(); ++g) {
eventsFunction.GetObjectGroups()[g].RenameObject(oldName, newName);
}
@@ -1780,8 +1673,7 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
void WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
gd::Project &project, const gd::String &oldName, const gd::String &newName,
bool isObjectGroup) {
// Object groups can't be in other groups
if (!isObjectGroup) {
if (!isObjectGroup) { // Object groups can't be in other groups
for (std::size_t g = 0; g < project.GetObjectGroups().size(); ++g) {
project.GetObjectGroups()[g].RenameObject(oldName, newName);
}
@@ -1797,10 +1689,15 @@ void WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
}
}
void WholeProjectRefactorer::GlobalObjectRemoved(
gd::Project &project, const gd::String &objectName) {
for (std::size_t g = 0; g < project.GetObjectGroups().size(); ++g) {
project.GetObjectGroups()[g].RemoveObject(objectName);
void WholeProjectRefactorer::GlobalObjectOrGroupRemoved(
gd::Project &project, const gd::String &objectName, bool isObjectGroup,
bool removeEventsAndGroups) {
if (!isObjectGroup) { // Object groups can't be in other groups
if (removeEventsAndGroups) {
for (std::size_t g = 0; g < project.GetObjectGroups().size(); ++g) {
project.GetObjectGroups()[g].RemoveObject(objectName);
}
}
}
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
@@ -1808,18 +1705,8 @@ void WholeProjectRefactorer::GlobalObjectRemoved(
if (layout.HasObjectNamed(objectName))
continue;
ObjectRemovedInLayout(project, layout, objectName);
}
}
void WholeProjectRefactorer::BehaviorsAddedToGlobalObject(
gd::Project &project, const gd::String &objectName) {
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
gd::Layout &layout = project.GetLayout(i);
if (layout.HasObjectNamed(objectName))
continue;
BehaviorsAddedToObjectInLayout(project, layout, objectName);
ObjectOrGroupRemovedInLayout(project, layout, objectName, isObjectGroup,
removeEventsAndGroups);
}
}
@@ -1866,8 +1753,7 @@ size_t WholeProjectRefactorer::GetLayoutAndExternalLayoutLayerInstancesCount(
GetAssociatedExternalLayouts(project, layout);
for (gd::String name : externalLayoutsNames) {
auto &externalLayout = project.GetExternalLayout(name);
count +=
externalLayout.GetInitialInstances().GetLayerInstancesCount(layerName);
count += externalLayout.GetInitialInstances().GetLayerInstancesCount(layerName);
}
return count;
}

View File

@@ -9,10 +9,7 @@
#include <unordered_set>
#include <unordered_map>
#include <vector>
#include <memory>
#include "GDCore/String.h"
#include "GDCore/Project/Variable.h"
namespace gd {
class Platform;
class Project;
@@ -37,26 +34,13 @@ class BehaviorMetadata;
class UnfilledRequiredBehaviorPropertyProblem;
class ProjectBrowser;
class SerializerElement;
struct VariablesRenamingChangesetNode;
} // namespace gd
namespace gd {
struct VariablesRenamingChangesetNode {
std::unordered_map<gd::String, gd::String> oldToNewVariableNames;
std::unordered_map<gd::String, std::shared_ptr<gd::VariablesRenamingChangesetNode>>
modifiedVariables;
};
struct VariablesChangeset : VariablesRenamingChangesetNode {
struct VariablesChangeset {
std::unordered_set<gd::String> removedVariableNames;
/**
* 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;
std::unordered_map<gd::String, gd::String> oldToNewVariableNames;
bool HasRemovedVariables() { return !removedVariableNames.empty(); }
@@ -67,8 +51,8 @@ struct VariablesChangeset : VariablesRenamingChangesetNode {
* \brief Tool functions to do refactoring on the whole project after
* changes like deletion or renaming of an object.
*
* \TODO Ideally ObjectOrGroupRenamedInLayout, ObjectRemovedInLayout,
* GlobalObjectOrGroupRenamed, GlobalObjectRemoved would be implemented
* \TODO Ideally ObjectOrGroupRenamedInLayout, ObjectOrGroupRemovedInLayout,
* GlobalObjectOrGroupRenamed, GlobalObjectOrGroupRemoved would be implemented
* using ExposeProjectEvents.
*/
class GD_CORE_API WholeProjectRefactorer {
@@ -78,6 +62,7 @@ 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);
@@ -86,9 +71,9 @@ class GD_CORE_API WholeProjectRefactorer {
* made to variables.
*/
static void ApplyRefactoringForVariablesContainer(
gd::Project &project, gd::VariablesContainer &variablesContainer,
const gd::VariablesChangeset &changeset,
const gd::SerializerElement &originalSerializedVariables);
gd::Project &project,
const gd::VariablesContainer &newVariablesContainer,
const gd::VariablesChangeset& changeset);
/**
* \brief Refactor the project **before** an events function extension is
@@ -391,21 +376,11 @@ class GD_CORE_API WholeProjectRefactorer {
* This will update the layout, all external layouts associated with it
* and all external events associated with it.
*/
static void ObjectRemovedInLayout(gd::Project& project,
static void ObjectOrGroupRemovedInLayout(gd::Project& project,
gd::Layout& layout,
const gd::String& objectName);
/**
* \brief Refactor the project after behaviors are added to an object in a
* layout.
*
* This will update the layout, all external events associated with it.
* The refactor is actually applied to all objects because it allow to handle
* groups.
*/
static void BehaviorsAddedToObjectInLayout(gd::Project &project,
gd::Layout &layout,
const gd::String &objectName);
const gd::String& objectName,
bool isObjectGroup,
bool removeEventsAndGroups = true);
/**
* \brief Refactor the project after an object is removed in an events-based
@@ -413,12 +388,14 @@ class GD_CORE_API WholeProjectRefactorer {
*
* This will update the events of the function and groups.
*/
static void ObjectRemovedInEventsBasedObject(
static void ObjectOrGroupRemovedInEventsBasedObject(
gd::Project& project,
gd::EventsBasedObject& eventsBasedObject,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
const gd::String& objectName);
const gd::String& objectName,
bool isObjectGroup,
bool removeEventsAndGroups);
/**
* \brief Refactor the events function after an object or group is renamed
@@ -452,12 +429,14 @@ class GD_CORE_API WholeProjectRefactorer {
*
* This will update the events of the function and groups.
*/
static void ObjectRemovedInEventsFunction(
static void ObjectOrGroupRemovedInEventsFunction(
gd::Project& project,
gd::EventsFunction& eventsFunction,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
const gd::String& objectName);
const gd::String& objectName,
bool isObjectGroup,
bool removeEventsAndGroups = true);
/**
* \brief Refactor the project after a global object is renamed.
@@ -476,18 +455,10 @@ class GD_CORE_API WholeProjectRefactorer {
* This will update all the layouts, all external layouts associated with them
* and all external events used by the layouts.
*/
static void GlobalObjectRemoved(gd::Project& project,
const gd::String& objectName);
/**
* \brief Refactor the project after behaviors are added a global object.
*
* This will update all the layouts, all external events associated with them.
* The refactor is actually applied to all objects because it allow to handle
* groups.
*/
void BehaviorsAddedToGlobalObject(gd::Project &project,
const gd::String &objectName);
static void GlobalObjectOrGroupRemoved(gd::Project& project,
const gd::String& objectName,
bool isObjectGroup,
bool removeEventsAndGroups = true);
/**
* \brief Return the set of all the types of the objects that are using the
@@ -584,13 +555,6 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& behaviorName,
std::unordered_set<gd::String>& dependentBehaviorNames);
static std::shared_ptr<VariablesRenamingChangesetNode>
ComputeChangesetForVariable(const gd::Variable &oldVariable,
const gd::Variable &newVariable);
static bool HasAnyVariableTypeChanged(const gd::Variable &oldVariable,
const gd::Variable &newVariable);
static const gd::String behaviorObjectParameterName;
static const gd::String parentObjectParameterName;

View File

@@ -4,6 +4,8 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Project/Behavior.h"
#include <iostream>
#include "GDCore/Project/PropertyDescriptor.h"
namespace gd {

View File

@@ -13,14 +13,12 @@
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/Log.h"
#include "GDCore/Project/CustomConfigurationHelper.h"
#include "GDCore/Project/InitialInstance.h"
using namespace gd;
void CustomObjectConfiguration::Init(const gd::CustomObjectConfiguration& objectConfiguration) {
project = objectConfiguration.project;
objectContent = objectConfiguration.objectContent;
animations = objectConfiguration.animations;
// There is no default copy for a map of unique_ptr like childObjectConfigurations.
childObjectConfigurations.clear();
@@ -90,38 +88,23 @@ bool CustomObjectConfiguration::UpdateProperty(const gd::String& propertyName,
std::map<gd::String, gd::PropertyDescriptor>
CustomObjectConfiguration::GetInitialInstanceProperties(
const gd::InitialInstance &initialInstance, gd::Project &project,
gd::Layout &scene) {
std::map<gd::String, gd::PropertyDescriptor> properties;
if (!animations.HasNoAnimations()) {
properties["animation"] =
gd::PropertyDescriptor(
gd::String::From(initialInstance.GetRawDoubleProperty("animation")))
.SetLabel(_("Animation"))
.SetType("number");
}
return properties;
const gd::InitialInstance& instance,
gd::Project& project,
gd::Layout& scene) {
return std::map<gd::String, gd::PropertyDescriptor>();
}
bool CustomObjectConfiguration::UpdateInitialInstanceProperty(
gd::InitialInstance &initialInstance, const gd::String &name,
const gd::String &value, gd::Project &project, gd::Layout &scene) {
if (name == "animation") {
initialInstance.SetRawDoubleProperty(
"animation", std::max(0, value.empty() ? 0 : value.To<int>()));
}
return true;
gd::InitialInstance& instance,
const gd::String& name,
const gd::String& value,
gd::Project& project,
gd::Layout& scene) {
return false;
}
void CustomObjectConfiguration::DoSerializeTo(SerializerElement& element) const {
element.AddChild("content") = objectContent;
if (!animations.HasNoAnimations()) {
auto &animatableElement = element.AddChild("animatable");
animations.SerializeTo(animatableElement);
}
auto &childrenContentElement = element.AddChild("childrenContent");
for (auto &pair : childObjectConfigurations) {
auto &childName = pair.first;
@@ -133,12 +116,6 @@ void CustomObjectConfiguration::DoSerializeTo(SerializerElement& element) const
void CustomObjectConfiguration::DoUnserializeFrom(Project& project,
const SerializerElement& element) {
objectContent = element.GetChild("content");
if (element.HasChild("animatable")) {
auto &animatableElement = element.GetChild("animatable");
animations.UnserializeFrom(animatableElement);
}
auto &childrenContentElement = element.GetChild("childrenContent");
for (auto &pair : childrenContentElement.GetAllChildren()) {
auto &childName = pair.first;
@@ -149,8 +126,6 @@ void CustomObjectConfiguration::DoUnserializeFrom(Project& project,
}
void CustomObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker& worker) {
animations.ExposeResources(worker);
std::map<gd::String, gd::PropertyDescriptor> properties = GetProperties();
for (auto& property : properties) {
@@ -180,10 +155,6 @@ void CustomObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker& wor
worker.ExposeBitmapFont(newPropertyValue);
} else if (resourceType == "model3D") {
worker.ExposeModel3D(newPropertyValue);
} else if (resourceType == "atlas") {
worker.ExposeAtlas(newPropertyValue);
} else if (resourceType == "spine") {
worker.ExposeSpine(newPropertyValue);
}
if (newPropertyValue != oldPropertyValue) {
@@ -203,11 +174,3 @@ void CustomObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker& wor
configuration.ExposeResources(worker);
}
}
const SpriteAnimationList& CustomObjectConfiguration::GetAnimations() const {
return animations;
}
SpriteAnimationList& CustomObjectConfiguration::GetAnimations() {
return animations;
}

View File

@@ -3,7 +3,8 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef GDCORE_CUSTOMOBJECTCONFIGURATION_H
#define GDCORE_CUSTOMOBJECTCONFIGURATION_H
#include "GDCore/Project/ObjectConfiguration.h"
@@ -15,7 +16,7 @@
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteAnimationList.h"
using namespace gd;
@@ -71,17 +72,7 @@ class CustomObjectConfiguration : public gd::ObjectConfiguration {
gd::ObjectConfiguration &GetChildObjectConfiguration(const gd::String& objectName);
/**
* \brief Return the animation configuration for Animatable custom objects.
*/
const SpriteAnimationList& GetAnimations() const;
/**
* @brief Return the animation configuration for Animatable custom objects.
*/
SpriteAnimationList& GetAnimations();
protected:
protected:
void DoSerializeTo(SerializerElement& element) const override;
void DoUnserializeFrom(Project& project, const SerializerElement& element) override;
@@ -93,8 +84,6 @@ protected:
static gd::ObjectConfiguration badObjectConfiguration;
SpriteAnimationList animations;
/**
* Initialize configuration using another configuration. Used by copy-ctor
* and assign-op.
@@ -106,5 +95,6 @@ protected:
*/
void Init(const gd::CustomObjectConfiguration& object);
};
} // namespace gd
#endif // GDCORE_CUSTOMOBJECTCONFIGURATION_H

View File

@@ -13,10 +13,7 @@ EventsBasedObject::EventsBasedObject()
: AbstractEventsBasedEntity(
"MyObject",
gd::EventsFunctionsContainer::FunctionOwner::Object),
ObjectsContainer(),
isRenderedIn3D(false),
isAnimatable(false),
isTextContainer(false) {
ObjectsContainer() {
}
EventsBasedObject::~EventsBasedObject() {}
@@ -33,12 +30,6 @@ void EventsBasedObject::SerializeTo(SerializerElement& element) const {
if (isRenderedIn3D) {
element.SetBoolAttribute("is3D", true);
}
if (isAnimatable) {
element.SetBoolAttribute("isAnimatable", true);
}
if (isTextContainer) {
element.SetBoolAttribute("isTextContainer", true);
}
AbstractEventsBasedEntity::SerializeTo(element);
SerializeObjectsTo(element.AddChild("objects"));
@@ -49,8 +40,6 @@ void EventsBasedObject::UnserializeFrom(gd::Project& project,
const SerializerElement& element) {
defaultName = element.GetStringAttribute("defaultName");
isRenderedIn3D = element.GetBoolAttribute("is3D", false);
isAnimatable = element.GetBoolAttribute("isAnimatable", false);
isTextContainer = element.GetBoolAttribute("isTextContainer", false);
AbstractEventsBasedEntity::UnserializeFrom(project, element);
UnserializeObjectsFrom(project, element.GetChild("objects"));

View File

@@ -85,32 +85,6 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public Ob
*/
bool IsRenderedIn3D() const { return isRenderedIn3D; }
/**
* \brief Declare an Animatable capability.
*/
EventsBasedObject& MarkAsAnimatable(bool isAnimatable_) {
isAnimatable = isAnimatable_;
return *this;
}
/**
* \brief Return true if the object needs an Animatable capability.
*/
bool IsAnimatable() const { return isAnimatable; }
/**
* \brief Declare a TextContainer capability.
*/
EventsBasedObject& MarkAsTextContainer(bool isTextContainer_) {
isTextContainer = isTextContainer_;
return *this;
}
/**
* \brief Return true if the object needs a TextContainer capability.
*/
bool IsTextContainer() const { return isTextContainer; }
void SerializeTo(SerializerElement& element) const override;
void UnserializeFrom(gd::Project& project,
@@ -119,8 +93,6 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public Ob
private:
gd::String defaultName;
bool isRenderedIn3D;
bool isAnimatable;
bool isTextContainer;
};
} // namespace gd

View File

@@ -107,7 +107,6 @@ 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);
};

View File

@@ -15,9 +15,7 @@ namespace gd {
EventsFunctionsExtension::EventsFunctionsExtension() :
gd::EventsFunctionsContainer(
gd::EventsFunctionsContainer::FunctionOwner::Extension),
globalVariables(gd::VariablesContainer::SourceType::ExtensionGlobal),
sceneVariables(gd::VariablesContainer::SourceType::ExtensionScene) {}
gd::EventsFunctionsContainer::FunctionOwner::Extension) {}
EventsFunctionsExtension::EventsFunctionsExtension(
const EventsFunctionsExtension& other) :
@@ -50,8 +48,6 @@ 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 {
@@ -86,9 +82,6 @@ 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"));
@@ -154,9 +147,6 @@ 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

View File

@@ -3,7 +3,8 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef GDCORE_EVENTSFUNCTIONEXTENSION_H
#define GDCORE_EVENTSFUNCTIONEXTENSION_H
#include <vector>
@@ -11,7 +12,6 @@
#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,41 +216,6 @@ 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
*/
///@{
@@ -333,9 +298,8 @@ 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

View File

@@ -15,7 +15,7 @@
namespace gd {
gd::String* InitialInstance::badStringPropertyValue = NULL;
gd::String* InitialInstance::badStringProperyValue = NULL;
InitialInstance::InitialInstance()
: objectName(""),
@@ -34,7 +34,6 @@ InitialInstance::InitialInstance()
depth(0),
locked(false),
sealed(false),
keepRatio(true),
persistentUuid(UUID::MakeUuid4()) {}
void InitialInstance::UnserializeFrom(const SerializerElement& element) {
@@ -59,7 +58,6 @@ void InitialInstance::UnserializeFrom(const SerializerElement& element) {
SetLayer(element.GetStringAttribute("layer"));
SetLocked(element.GetBoolAttribute("locked", false));
SetSealed(element.GetBoolAttribute("sealed", false));
SetShouldKeepRatio(element.GetBoolAttribute("keepRatio", false));
persistentUuid = element.GetStringAttribute("persistentUuid");
if (persistentUuid.empty()) ResetPersistentUuid();
@@ -122,7 +120,6 @@ void InitialInstance::SerializeTo(SerializerElement& element) const {
if (HasCustomDepth()) element.SetAttribute("depth", GetCustomDepth());
if (IsLocked()) element.SetAttribute("locked", IsLocked());
if (IsSealed()) element.SetAttribute("sealed", IsSealed());
if (ShouldKeepRatio()) element.SetAttribute("keepRatio", ShouldKeepRatio());
if (persistentUuid.empty()) persistentUuid = UUID::MakeUuid4();
element.SetStringAttribute("persistentUuid", persistentUuid);
@@ -191,10 +188,10 @@ double InitialInstance::GetRawDoubleProperty(const gd::String& name) const {
const gd::String& InitialInstance::GetRawStringProperty(
const gd::String& name) const {
if (!badStringPropertyValue) badStringPropertyValue = new gd::String("");
if (!badStringProperyValue) badStringProperyValue = new gd::String("");
const auto& it = stringProperties.find(name);
return it != stringProperties.end() ? it->second : *badStringPropertyValue;
return it != stringProperties.end() ? it->second : *badStringProperyValue;
}
void InitialInstance::SetRawDoubleProperty(const gd::String& name,

View File

@@ -206,17 +206,6 @@ class GD_CORE_API InitialInstance {
*/
void SetSealed(bool enable = true) { sealed = enable; }
/**
* \brief Return true if the dimensions (width, height and depth) should keep
* the same ratio.
*/
bool ShouldKeepRatio() const { return keepRatio; };
/**
* \brief Define if instance's dimensions should keep the same ratio.
*/
void SetShouldKeepRatio(bool enable = true) { keepRatio = enable; }
///@}
/** \name Variable management
@@ -351,13 +340,11 @@ class GD_CORE_API InitialInstance {
gd::VariablesContainer initialVariables; ///< Instance specific variables
bool locked; ///< True if the instance is locked
bool sealed; ///< True if the instance is sealed
bool keepRatio; ///< True if the instance's dimensions
/// should keep the same ratio.
mutable gd::String persistentUuid; ///< A persistent random version 4 UUID,
/// useful for hot reloading.
///< useful for hot reloading.
static gd::String*
badStringPropertyValue; ///< Empty string returned by GetRawStringProperty
badStringProperyValue; ///< Empty string returned by GetRawStringProperty
};
} // namespace gd

Some files were not shown because too many files have changed in this diff Show More