Compare commits

..

66 Commits

Author SHA1 Message Date
AlexandreSi
5eb5fb3af9 Add checkbox to improve discoverability of tilemap hitboxes 2024-07-19 10:41:07 +02:00
AlexandreSi
cd80872fca Rename existing tilemap object adding external mention in the name 2024-07-19 10:19:49 +02:00
AlexandreSi
61cb6dde0e Replace path painting with rectangle painting 2024-07-19 09:29:52 +02:00
AlexandreSi
29c8de0987 Refactor 2024-07-18 15:41:05 +02:00
AlexandreSi
802e9a5128 Add possibility to select hitboxes using a rectangle 2024-07-18 14:46:38 +02:00
AlexandreSi
c82602919b Update collision mask when tilemap is dirty 2024-07-18 13:40:12 +02:00
AlexandreSi
80cbb8f542 Make it possible to select tiles with a rectangle when setting hit boxes 2024-07-18 11:11:45 +02:00
AlexandreSi
a9ceba7bef Rename file 2024-07-18 10:31:05 +02:00
AlexandreSi
7d9e72c876 Prevent having tile with ids outside of tile set 2024-07-17 16:18:43 +02:00
AlexandreSi
3baf5903d3 Clean a few things 2024-07-17 16:00:42 +02:00
AlexandreSi
6008e1045d Change width and height and opacity from network sync only if different 2024-07-17 15:16:28 +02:00
AlexandreSi
9dda9a89c5 Remove selected instance fill color when painting 2024-07-17 15:16:28 +02:00
AlexandreSi
814c6aec4f Handle rendered instance of tilemap when tilemap is empty 2024-07-17 15:16:28 +02:00
AlexandreSi
84e4158407 Fix typing 2024-07-17 15:16:28 +02:00
AlexandreSi
aa6c3bc1c8 Recompute tile set on tilemap object parameters changes 2024-07-17 15:16:28 +02:00
AlexandreSi
41dc6d0966 Improve runtime typing 2024-07-17 15:16:28 +02:00
AlexandreSi
9c19865dec Fix typing 2024-07-17 15:16:28 +02:00
AlexandreSi
bbfb7f63f0 Save to history when changing tilemap 2024-07-17 15:16:28 +02:00
AlexandreSi
2f8304c2dd Deactivate painting when pressing escape 2024-07-17 15:16:28 +02:00
AlexandreSi
c1aa88861d Add cancel painting action on press escape 2024-07-17 15:16:28 +02:00
AlexandreSi
254ab0350b Display info about tiles with hitboxes 2024-07-17 15:16:28 +02:00
AlexandreSi
b0a3c34803 Use object configuration to set hit boxes 2024-07-17 15:16:28 +02:00
AlexandreSi
63a3265310 Store tiles with hitbox in object configuration 2024-07-17 15:16:28 +02:00
AlexandreSi
d19292f43d Initiate SimpleTileMap object editor 2024-07-17 15:16:28 +02:00
AlexandreSi
3646d05b65 Simplify TileMapPainter component and types 2024-07-17 15:16:28 +02:00
AlexandreSi
25a4d04896 Remove useless react fragment 2024-07-17 15:16:28 +02:00
AlexandreSi
2df6c13ed7 Make opacity setting work for simple tile maps 2024-07-17 15:16:28 +02:00
AlexandreSi
93f84a14cb Implement missing methods for collisions to work 2024-07-17 15:16:28 +02:00
AlexandreSi
02e0ebf63b Post rebase changes 2024-07-17 15:16:28 +02:00
AlexandreSi
da3abb331a Add collision tilemap to simple tile map object 2024-07-17 15:16:28 +02:00
AlexandreSi
a5a9524ed6 Add possibility to set flipping options in tile setting action 2024-07-17 15:16:28 +02:00
AlexandreSi
c9cc1f6fdc Use reusable float point 2024-07-17 15:16:28 +02:00
AlexandreSi
de140f1190 Reposition tilemap when setting/removing tiles 2024-07-17 15:16:28 +02:00
AlexandreSi
9a82fda7fe Use affine transformation in runtime actions 2024-07-17 15:16:28 +02:00
AlexandreSi
eac92704fa Display tile id as title when hovering tileset 2024-07-17 15:16:28 +02:00
AlexandreSi
dc607d85c3 Use AffineTransformation to display tile preview and set tile at coordinates 2024-07-17 15:16:28 +02:00
AlexandreSi
e96269d899 Aff AffineTransformation util from runtime 2024-07-17 15:16:27 +02:00
AlexandreSi
05d622c5c0 Add TODO 2024-07-17 15:16:27 +02:00
AlexandreSi
0758397196 Use flipping controls when painting and previewing the tile to be set 2024-07-17 15:16:27 +02:00
AlexandreSi
65293ddd99 Update tilemap painter with icons and flipping selectors 2024-07-17 15:16:27 +02:00
AlexandreSi
225a3a67c6 Add TODO 2024-07-17 15:16:27 +02:00
AlexandreSi
a96171aacd Add actions to change change tiles in the runtime 2024-07-17 15:16:27 +02:00
AlexandreSi
1a21a0bfb3 Actually hide tilemap instance property 2024-07-17 15:16:27 +02:00
AlexandreSi
cc23301875 Initiate SimpleTileMap runtime object 2024-07-17 15:16:27 +02:00
AlexandreSi
aa513c04e6 Store tilemap on instance instead of object 2024-07-17 15:16:27 +02:00
AlexandreSi
a4e8e8c00b Add method to check if tilemap is empty 2024-07-17 15:16:27 +02:00
AlexandreSi
0d34680fcd Resize and reposition tilemap after trimming tilemap 2024-07-17 15:16:27 +02:00
AlexandreSi
4abdb9dca6 Add methods to trim tilemap from empty rows and columns 2024-07-17 15:16:27 +02:00
AlexandreSi
db05a07023 Add possibility to erase tile from the tilemap 2024-07-17 15:16:27 +02:00
AlexandreSi
78ebe58713 Add possibility to paint with click + drag 2024-07-17 15:16:27 +02:00
AlexandreSi
420c7a4429 Adapt state to support more than one tile selected 2024-07-17 15:16:27 +02:00
AlexandreSi
1442a2772e Support tilemaps with custom heights and widths 2024-07-17 15:16:27 +02:00
AlexandreSi
ce18bdd5a7 Reposition instance after adding columns/rows in negative indices 2024-07-17 15:16:27 +02:00
AlexandreSi
2f2cc1bbe3 Support setting tiles in negative indices 2024-07-17 15:16:27 +02:00
AlexandreSi
097ad4fff5 Make it possible to paint outside of the tilemap dimensions (positive) 2024-07-17 15:16:27 +02:00
AlexandreSi
2112ed789a Set tilemap attribute on object when painting 2024-07-17 15:16:27 +02:00
AlexandreSi
a41a1c14a0 Modify tilemap when clicking on scene when tile is selected 2024-07-17 15:16:27 +02:00
AlexandreSi
771d3264bb Load simple tilemap into editable tile map for scene editor renderer 2024-07-17 15:16:27 +02:00
AlexandreSi
9fa1e552e0 Complete unknown instance rectangle 2024-07-17 15:16:27 +02:00
AlexandreSi
503a0873d9 Make tile map preview position on grid 2024-07-17 15:16:27 +02:00
AlexandreSi
715480bdef Tile map tile preview in Scene editor 2024-07-17 15:16:27 +02:00
AlexandreSi
869fd7eb08 Transfer selected tile map tile data to scene editor 2024-07-17 15:16:26 +02:00
AlexandreSi
e0cb8e4953 Improve object declaration and setup tilemap painter 2024-07-17 15:16:26 +02:00
AlexandreSi
0ef4953241 WIP: Add TileMapPainter 2024-07-17 15:16:26 +02:00
AlexandreSi
d154384164 WIP introduce simple tile map object 2024-07-17 15:16:26 +02:00
AlexandreSi
504df2e0a3 Fix comment 2024-07-17 15:16:26 +02:00
614 changed files with 12610 additions and 29189 deletions

View File

@@ -107,7 +107,7 @@
"description": "Define a parameter in a GDevelop extension definition.",
"prefix": "gdparam",
"body": [
".addParameter('${1|string,expression,object,behavior,yesorno,stringWithSelector,scenevar,globalvar,objectvar,objectList,objectListWithoutPicking,color,key,sceneName,file,layer,relationalOperator,operator,trueorfalse,musicfile,soundfile,mouse,passwordjoyaxis,camera,objectPtr,forceMultiplier|}', '${2:Parameter description}', '${3:Optional parameter data}', /*parameterIsOptional=*/${4|false,true|})"
".addParameter('${1|string,expression,object,behavior,yesorno,stringWithSelector,scenevar,globalvar,objectvar,objectList,objectListWithoutPicking,color,key,sceneName,file,layer,relationalOperator,operator,trueorfalse,musicfile,soundfile,police,mouse,passwordjoyaxis,camera,objectPtr,forceMultiplier|}', '${2:Parameter description}', '${3:Optional parameter data}', /*parameterIsOptional=*/${4|false,true|})"
]
},
"Add code only parameter": {

View File

@@ -11,11 +11,6 @@ set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1)
set(GDCORE_include_dir ${GD_base_dir}/Core PARENT_SCOPE)
set(GDCORE_lib_dir ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME} PARENT_SCOPE)
# Create VersionPriv.h - only useful for testing.
if (NOT EMSCRIPTEN)
file(WRITE "${GD_base_dir}/Core/GDCore/Tools/VersionPriv.h" "#define GD_VERSION_STRING \"0.0.0-0\"")
endif()
# Dependencies on external libraries:
#

View File

@@ -42,15 +42,14 @@ gd::String EventsCodeGenerator::GenerateRelationalOperatorCall(
const vector<gd::String>& arguments,
const gd::String& callStartString,
std::size_t startFromArgument) {
std::size_t relationalOperatorIndex = instrInfos.parameters.GetParametersCount();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.GetParametersCount();
std::size_t relationalOperatorIndex = instrInfos.parameters.size();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.size();
++i) {
if (instrInfos.parameters.GetParameter(i).GetType() == "relationalOperator") {
if (instrInfos.parameters[i].GetType() == "relationalOperator")
relationalOperatorIndex = i;
}
}
// Ensure that there is at least one parameter after the relational operator
if (relationalOperatorIndex + 1 >= instrInfos.parameters.GetParametersCount()) {
if (relationalOperatorIndex + 1 >= instrInfos.parameters.size()) {
ReportError();
return "";
}
@@ -77,11 +76,11 @@ gd::String EventsCodeGenerator::GenerateRelationalOperatorCall(
/**
* @brief Generate a relational operation
*
*
* @param relationalOperator the operator
* @param lhs the left hand operand
* @param rhs the right hand operand
* @return gd::String
* @return gd::String
*/
gd::String EventsCodeGenerator::GenerateRelationalOperation(
const gd::String& relationalOperator,
@@ -123,16 +122,14 @@ gd::String EventsCodeGenerator::GenerateOperatorCall(
const gd::String& callStartString,
const gd::String& getterStartString,
std::size_t startFromArgument) {
std::size_t operatorIndex = instrInfos.parameters.GetParametersCount();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.GetParametersCount();
std::size_t operatorIndex = instrInfos.parameters.size();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.size();
++i) {
if (instrInfos.parameters.GetParameter(i).GetType() == "operator") {
operatorIndex = i;
}
if (instrInfos.parameters[i].GetType() == "operator") operatorIndex = i;
}
// Ensure that there is at least one parameter after the operator
if (operatorIndex + 1 >= instrInfos.parameters.GetParametersCount()) {
if (operatorIndex + 1 >= instrInfos.parameters.size()) {
ReportError();
return "";
}
@@ -194,16 +191,14 @@ gd::String EventsCodeGenerator::GenerateCompoundOperatorCall(
const vector<gd::String>& arguments,
const gd::String& callStartString,
std::size_t startFromArgument) {
std::size_t operatorIndex = instrInfos.parameters.GetParametersCount();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.GetParametersCount();
std::size_t operatorIndex = instrInfos.parameters.size();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.size();
++i) {
if (instrInfos.parameters.GetParameter(i).GetType() == "operator") {
operatorIndex = i;
}
if (instrInfos.parameters[i].GetType() == "operator") operatorIndex = i;
}
// Ensure that there is at least one parameter after the operator
if (operatorIndex + 1 >= instrInfos.parameters.GetParametersCount()) {
if (operatorIndex + 1 >= instrInfos.parameters.size()) {
ReportError();
return "";
}
@@ -247,16 +242,14 @@ gd::String EventsCodeGenerator::GenerateMutatorCall(
const vector<gd::String>& arguments,
const gd::String& callStartString,
std::size_t startFromArgument) {
std::size_t operatorIndex = instrInfos.parameters.GetParametersCount();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.GetParametersCount();
std::size_t operatorIndex = instrInfos.parameters.size();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.size();
++i) {
if (instrInfos.parameters.GetParameter(i).GetType() == "operator") {
operatorIndex = i;
}
if (instrInfos.parameters[i].GetType() == "operator") operatorIndex = i;
}
// Ensure that there is at least one parameter after the operator
if (operatorIndex + 1 >= instrInfos.parameters.GetParametersCount()) {
if (operatorIndex + 1 >= instrInfos.parameters.size()) {
ReportError();
return "";
}
@@ -323,7 +316,7 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
}
// Insert code only parameters and be sure there is no lack of parameter.
while (condition.GetParameters().size() < instrInfos.parameters.GetParametersCount()) {
while (condition.GetParameters().size() < instrInfos.parameters.size()) {
vector<gd::Expression> parameters = condition.GetParameters();
parameters.push_back(gd::Expression(""));
condition.SetParameters(parameters);
@@ -331,13 +324,13 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
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.GetParametersCount(); ++pNb) {
if (ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType())) {
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.GetParameter(pNb).GetExtraInfo();
instrInfos.parameters[pNb].GetExtraInfo();
const auto &actualObjectType =
GetObjectsContainersList().GetTypeOfObject(objectInParameter);
if (!GetObjectsContainersList().HasObjectOrGroupNamed(
@@ -360,7 +353,7 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
if (instrInfos.IsObjectInstruction()) {
gd::String objectName = condition.GetParameter(0).GetPlainString();
if (!objectName.empty() && instrInfos.parameters.GetParametersCount() > 0) {
if (!objectName.empty() && !instrInfos.parameters.empty()) {
std::vector<gd::String> realObjects =
GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
for (std::size_t i = 0; i < realObjects.size(); ++i) {
@@ -388,7 +381,7 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
}
}
} else if (instrInfos.IsBehaviorInstruction()) {
if (instrInfos.parameters.GetParametersCount() >= 2) {
if (instrInfos.parameters.size() >= 2) {
const gd::String &objectName = condition.GetParameter(0).GetPlainString();
const gd::String &behaviorName =
condition.GetParameter(1).GetPlainString();
@@ -546,7 +539,7 @@ gd::String EventsCodeGenerator::GenerateActionCode(
: instrInfos.codeExtraInformation.functionCallName;
// Be sure there is no lack of parameter.
while (action.GetParameters().size() < instrInfos.parameters.GetParametersCount()) {
while (action.GetParameters().size() < instrInfos.parameters.size()) {
vector<gd::Expression> parameters = action.GetParameters();
parameters.push_back(gd::Expression(""));
action.SetParameters(parameters);
@@ -554,12 +547,12 @@ gd::String EventsCodeGenerator::GenerateActionCode(
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.GetParametersCount(); ++pNb) {
if (ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType())) {
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.GetParameter(pNb).GetExtraInfo();
instrInfos.parameters[pNb].GetExtraInfo();
const auto &actualObjectType =
GetObjectsContainersList().GetTypeOfObject(objectInParameter);
if (!GetObjectsContainersList().HasObjectOrGroupNamed(
@@ -584,7 +577,7 @@ gd::String EventsCodeGenerator::GenerateActionCode(
if (instrInfos.IsObjectInstruction()) {
gd::String objectName = action.GetParameter(0).GetPlainString();
if (instrInfos.parameters.GetParametersCount() > 0) {
if (!instrInfos.parameters.empty()) {
std::vector<gd::String> realObjects =
GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
for (std::size_t i = 0; i < realObjects.size(); ++i) {
@@ -612,7 +605,7 @@ gd::String EventsCodeGenerator::GenerateActionCode(
}
}
} else if (instrInfos.IsBehaviorInstruction()) {
if (instrInfos.parameters.GetParametersCount() >= 2) {
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 =
@@ -828,7 +821,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
metadata.GetType() == "spineResource" ||
// Deprecated, old parameter names:
metadata.GetType() == "password" || metadata.GetType() == "musicfile" ||
metadata.GetType() == "soundfile") {
metadata.GetType() == "soundfile" || metadata.GetType() == "police") {
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
} else if (metadata.GetType() == "mouse") {
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
@@ -870,7 +863,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
vector<gd::String> EventsCodeGenerator::GenerateParametersCodes(
const vector<gd::Expression>& parameters,
const ParameterMetadataContainer& parametersInfo,
const vector<gd::ParameterMetadata>& parametersInfo,
EventsCodeGenerationContext& context,
std::vector<std::pair<gd::String, gd::String> >*
supplementaryParametersTypes) {
@@ -1007,7 +1000,7 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(
output += "\n" + scopeBegin + "\n" + declarationsCode + "\n" +
eventCoreCode + "\n" + scopeEnd + "\n";
if (event.HasVariables()) {
GetProjectScopedContainers().GetVariablesContainersList().Pop();
}
@@ -1107,10 +1100,10 @@ gd::String EventsCodeGenerator::GenerateFreeCondition(
// Add logical not if needed
bool conditionAlreadyTakeCareOfInversion = false;
for (std::size_t i = 0; i < instrInfos.parameters.GetParametersCount();
for (std::size_t i = 0; i < instrInfos.parameters.size();
++i) // Some conditions already have a "conditionInverted" parameter
{
if (instrInfos.parameters.GetParameter(i).GetType() == "conditionInverted")
if (instrInfos.parameters[i].GetType() == "conditionInverted")
conditionAlreadyTakeCareOfInversion = true;
}
if (!conditionAlreadyTakeCareOfInversion && conditionInverted)
@@ -1131,7 +1124,7 @@ gd::String EventsCodeGenerator::GenerateObjectCondition(
// Prepare call
// Add a static_cast if necessary
gd::String objectFunctionCallNamePart =
(!instrInfos.parameters.GetParameter(0).GetExtraInfo().empty())
(!instrInfos.parameters[0].GetExtraInfo().empty())
? "static_cast<" + objInfo.className + "*>(" +
GetObjectListName(objectName, context) + "[i])->" +
instrInfos.codeExtraInformation.functionCallName
@@ -1186,13 +1179,8 @@ gd::String EventsCodeGenerator::GenerateFreeAction(
// Generate call
gd::String call;
if (instrInfos.codeExtraInformation.type == "number" ||
instrInfos.codeExtraInformation.type == "string" ||
// Boolean actions declared with addExpressionAndConditionAndAction uses
// MutatorAndOrAccessor even though they don't declare an operator parameter.
// Boolean operators are only used with SetMutators or SetCustomCodeGenerator.
(instrInfos.codeExtraInformation.type == "boolean" &&
instrInfos.codeExtraInformation.accessType ==
gd::InstructionMetadata::ExtraInformation::AccessType::Mutators)) {
instrInfos.codeExtraInformation.type == "string" ||
instrInfos.codeExtraInformation.type == "boolean") {
if (instrInfos.codeExtraInformation.accessType ==
gd::InstructionMetadata::ExtraInformation::MutatorAndOrAccessor)
call = GenerateOperatorCall(

View File

@@ -128,7 +128,7 @@ class GD_CORE_API EventsCodeGenerator {
*/
std::vector<gd::String> GenerateParametersCodes(
const std::vector<gd::Expression>& parameters,
const ParameterMetadataContainer& parametersInfo,
const std::vector<gd::ParameterMetadata>& parametersInfo,
EventsCodeGenerationContext& context,
std::vector<std::pair<gd::String, gd::String> >*
supplementaryParametersTypes = 0);
@@ -528,7 +528,7 @@ protected:
parameter -> string
* - operator : Used to update a value using a setter and a getter -> string
* - key, mouse, objectvar, scenevar, globalvar, password, musicfile,
soundfile -> string
soundfile, police -> string
* - trueorfalse, yesorno -> boolean ( See GenerateTrue/GenerateFalse ).
*
* <br><br>
@@ -849,7 +849,7 @@ 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;
};

View File

@@ -430,11 +430,11 @@ gd::String ExpressionCodeGenerator::GenerateParametersCodes(
size_t nonCodeOnlyParameterIndex = 0;
gd::String parametersCode;
for (std::size_t i = initialParameterIndex;
i < expressionMetadata.GetParameters().GetParametersCount();
i < expressionMetadata.parameters.size();
++i) {
if (i != initialParameterIndex) parametersCode += ", ";
auto& parameterMetadata = expressionMetadata.GetParameters().GetParameter(i);
auto& parameterMetadata = expressionMetadata.parameters[i];
if (!parameterMetadata.IsCodeOnly()) {
if (nonCodeOnlyParameterIndex < parameters.size()) {
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),

View File

@@ -182,10 +182,10 @@ void EventsListSerialization::UpdateInstructionsFromGD2x(
// Common updates for some parameters
const std::vector<gd::Expression>& parameters = instr.GetParameters();
for (std::size_t j = 0;
j < parameters.size() && j < metadata.parameters.GetParametersCount();
j < parameters.size() && j < metadata.parameters.size();
++j) {
if (metadata.parameters.GetParameter(j).GetType() == "relationalOperator" ||
metadata.parameters.GetParameter(j).GetType() == "operator") {
if (metadata.parameters[j].GetType() == "relationalOperator" ||
metadata.parameters[j].GetType() == "operator") {
if (j == parameters.size() - 1) {
std::cout << "ERROR: No more parameters after a [relational]operator "
"when trying to update an instruction from GD2.x";

View File

@@ -116,13 +116,6 @@ void SpriteAnimationList::ExposeResources(gd::ArbitraryResourceWorker& worker) {
}
}
bool SpriteAnimationList::HasAnimationNamed(const gd::String &name) const {
return !name.empty() && (find_if(animations.begin(), animations.end(),
[&name](const Animation &animation) {
return animation.GetName() == name;
}) != animations.end());
}
const Animation& SpriteAnimationList::GetAnimation(std::size_t nb) const {
if (nb >= animations.size()) return badAnimation;

View File

@@ -51,11 +51,6 @@ class GD_CORE_API SpriteAnimationList {
*/
std::size_t GetAnimationsCount() const { return animations.size(); };
/**
* \brief Return true if an animation exists for a given name.
*/
bool HasAnimationNamed(const gd::String &name) const;
/**
* \brief Add an animation at the end of the existing ones.
*/

View File

@@ -24,23 +24,18 @@
namespace gd {
SpriteObject::SpriteObject()
: updateIfNotVisible(false),
preScale(1) {}
: updateIfNotVisible(false) {}
SpriteObject::~SpriteObject(){};
void SpriteObject::DoUnserializeFrom(gd::Project& project,
const gd::SerializerElement& element) {
updateIfNotVisible = element.GetBoolAttribute("updateIfNotVisible", true);
preScale = element.GetDoubleAttribute("preScale", 1);
animations.UnserializeFrom(element);
}
void SpriteObject::DoSerializeTo(gd::SerializerElement& element) const {
element.SetAttribute("updateIfNotVisible", updateIfNotVisible);
if (preScale != 1) {
element.SetAttribute("preScale", preScale);
}
animations.SerializeTo(element);
}
@@ -92,19 +87,6 @@ bool SpriteObject::UpdateInitialInstanceProperty(
return true;
}
size_t SpriteObject::GetAnimationsCount() const {
return animations.GetAnimationsCount();
}
const gd::String &SpriteObject::GetAnimationName(size_t index) const {
return animations.GetAnimation(index).GetName();
}
bool SpriteObject::HasAnimationNamed(
const gd::String &name) const {
return animations.HasAnimationNamed(name);
}
const SpriteAnimationList& SpriteObject::GetAnimations() const {
return animations;
}

View File

@@ -52,12 +52,6 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
const gd::String& name,
const gd::String& value) override;
size_t GetAnimationsCount() const override;
const gd::String &GetAnimationName(size_t index) const override;
bool HasAnimationNamed(const gd::String &animationName) const override;
/**
* \brief Return the animation configuration.
*/
@@ -82,23 +76,6 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
*/
bool GetUpdateIfNotVisible() const { return updateIfNotVisible; }
/**
* \brief Return the scale applied to object to evaluate the default dimensions.
*/
double GetPreScale() { return preScale; }
/**
* \brief Set the scale applied to object to evaluate the default dimensions.
*
* Its value must be strictly positive.
*/
void SetPreScale(double preScale_) {
if (preScale_ <= 0) {
return;
}
preScale = preScale_;
}
private:
void DoUnserializeFrom(gd::Project& project,
const gd::SerializerElement& element) override;
@@ -109,7 +86,6 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
bool updateIfNotVisible; ///< If set to true, ask the game engine to play
///< object animation even if hidden or far from
///< the screen.
double preScale;
};
} // namespace gd

View File

@@ -37,8 +37,7 @@ BehaviorMetadata::BehaviorMetadata(
className(className_),
iconFilename(icon24x24),
instance(instance_),
sharedDatasInstance(sharedDatasInstance_),
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {
sharedDatasInstance(sharedDatasInstance_) {
SetFullName(gd::String(fullname_));
SetDescription(gd::String(description_));
SetDefaultName(gd::String(defaultName_));
@@ -425,7 +424,7 @@ std::map<gd::String, gd::PropertyDescriptor> BehaviorMetadata::GetProperties() c
return instance->GetProperties();
}
gd::BehaviorsSharedData* BehaviorMetadata::GetSharedDataInstance() const {
gd::BehaviorsSharedData* BehaviorMetadata::GetSharedDataInstance() const {
return sharedDatasInstance.get();
}

View File

@@ -12,7 +12,6 @@
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/String.h"
#include "GDCore/Project/QuickCustomization.h"
namespace gd {
class Behavior;
class BehaviorsSharedData;
@@ -42,10 +41,10 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
const gd::String& className_,
std::shared_ptr<gd::Behavior> instance,
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance);
/**
* \brief Construct a behavior metadata, without "blueprint" behavior.
*
*
* \note This is used by events based behaviors.
*/
BehaviorMetadata(
@@ -298,18 +297,9 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
return *this;
}
QuickCustomization::Visibility GetQuickCustomizationVisibility() const {
return quickCustomizationVisibility;
}
BehaviorMetadata &SetQuickCustomizationVisibility(QuickCustomization::Visibility visibility) {
quickCustomizationVisibility = visibility;
return *this;
}
/**
* \brief Return the associated gd::Behavior, handling behavior contents.
*
*
* \note Returns a dumb Behavior for events based behaviors as CustomBehavior
* are using EventBasedBehavior.
*/
@@ -327,7 +317,7 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
/**
* \brief Return the associated gd::BehaviorsSharedData, handling behavior
* shared data, if any (nullptr if none).
*
*
* \note Returns nullptr for events based behaviors as they don't declare
* shared data yet.
*/
@@ -384,7 +374,6 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
mutable std::vector<gd::String> requiredBehaviors;
bool isPrivate = false;
bool isHidden = false;
QuickCustomization::Visibility quickCustomizationVisibility;
// TODO: Nitpicking: convert these to std::unique_ptr to clarify ownership.
std::shared_ptr<gd::Behavior> instance;

View File

@@ -38,12 +38,12 @@ gd::ExpressionMetadata& ExpressionMetadata::AddParameter(
const gd::String& description,
const gd::String& supplementaryInformation,
bool parameterIsOptional) {
parameters.AddNewParameter("")
.SetType(type)
.SetDescription(description)
.SetCodeOnly(false)
.SetOptional(parameterIsOptional)
.SetExtraInfo(
gd::ParameterMetadata info;
info.SetType(type);
info.description = description;
info.codeOnly = false;
info.SetOptional(parameterIsOptional);
info.SetExtraInfo(
// For objects/behavior, the supplementary information
// parameter is an object/behavior type...
((gd::ParameterMetadata::IsObject(type) ||
@@ -59,16 +59,22 @@ gd::ExpressionMetadata& ExpressionMetadata::AddParameter(
// TODO: Assert against supplementaryInformation === "emsc" (when running with
// Emscripten), and warn about a missing argument when calling addParameter.
parameters.push_back(info);
return *this;
}
gd::ExpressionMetadata &ExpressionMetadata::AddCodeOnlyParameter(
const gd::String &type, const gd::String &supplementaryInformation) {
parameters.AddNewParameter("").SetType(type).SetCodeOnly().SetExtraInfo(
supplementaryInformation);
gd::ExpressionMetadata& ExpressionMetadata::AddCodeOnlyParameter(
const gd::String& type, const gd::String& supplementaryInformation) {
gd::ParameterMetadata info;
info.SetType(type);
info.codeOnly = true;
info.SetExtraInfo(supplementaryInformation);
parameters.push_back(info);
return *this;
}
gd::ExpressionMetadata& ExpressionMetadata::SetRequiresBaseObjectCapability(
const gd::String& capability) {
requiredBaseObjectCapability = capability;

View File

@@ -193,9 +193,8 @@ class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
* \see AddParameter
*/
ExpressionMetadata &SetDefaultValue(const gd::String &defaultValue) override {
if (parameters.GetParametersCount() > 0) {
parameters.GetInternalVector().back()->SetDefaultValue(defaultValue);
}
if (!parameters.empty())
parameters.back().SetDefaultValue(defaultValue);
return *this;
};
@@ -207,9 +206,8 @@ class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
*/
ExpressionMetadata &
SetParameterLongDescription(const gd::String &longDescription) override {
if (parameters.GetParametersCount() > 0) {
parameters.GetInternalVector().back()->SetLongDescription(longDescription);
}
if (!parameters.empty())
parameters.back().SetLongDescription(longDescription);
return *this;
};
@@ -222,9 +220,7 @@ class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
*/
ExpressionMetadata &SetParameterExtraInfo(
const gd::String &extraInfo) override {
if (parameters.GetParametersCount() > 0) {
parameters.GetInternalVector().back()->SetExtraInfo(extraInfo);
}
if (!parameters.empty()) parameters.back().SetExtraInfo(extraInfo);
return *this;
}
@@ -252,16 +248,19 @@ class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
const gd::String& GetGroup() const { return group; }
const gd::String& GetSmallIconFilename() const { return smallIconFilename; }
const gd::ParameterMetadata& GetParameter(std::size_t id) const {
return parameters.GetParameter(id);
return parameters[id];
};
gd::ParameterMetadata& GetParameter(std::size_t id) {
return parameters.GetParameter(id);
return parameters[id];
};
std::size_t GetParametersCount() const { return parameters.GetParametersCount(); };
const gd::ParameterMetadataContainer& GetParameters() const {
std::size_t GetParametersCount() const { return parameters.size(); };
const std::vector<gd::ParameterMetadata>& GetParameters() const {
return parameters;
};
std::vector<gd::ParameterMetadata> parameters;
/**
* \brief Set the function name which will be used when generating the code.
* \param functionName the name of the function to call
@@ -369,8 +368,6 @@ class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
bool isPrivate;
gd::String requiredBaseObjectCapability;
gd::String relevantContext;
gd::ParameterMetadataContainer parameters;
};
} // namespace gd

View File

@@ -9,7 +9,6 @@
#include "GDCore/CommonTools.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/ParameterMetadataContainer.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/Log.h"
@@ -78,7 +77,7 @@ InstructionMetadata& InstructionMetadata::AddParameter(
// TODO: Assert against supplementaryInformation === "emsc" (when running with
// Emscripten), and warn about a missing argument when calling addParameter.
parameters.AddParameter(info);
parameters.push_back(info);
return *this;
}
@@ -89,7 +88,7 @@ InstructionMetadata& InstructionMetadata::AddCodeOnlyParameter(
info.codeOnly = true;
info.SetExtraInfo(supplementaryInformation);
parameters.AddParameter(info);
parameters.push_back(info);
return *this;
}
@@ -103,7 +102,7 @@ InstructionMetadata& InstructionMetadata::UseStandardOperatorParameters(
AddParameter(
"yesorno",
options.description.empty() ? _("New value") : options.description);
size_t valueParamIndex = parameters.GetParametersCount() - 1;
size_t valueParamIndex = parameters.size() - 1;
if (isObjectInstruction || isBehaviorInstruction) {
gd::String templateSentence = _("Set _PARAM0_ as <subject>: <value>");
@@ -128,8 +127,8 @@ InstructionMetadata& InstructionMetadata::UseStandardOperatorParameters(
options.description.empty() ? _("Value") : options.description,
options.typeExtraInfo);
size_t operatorParamIndex = parameters.GetParametersCount() - 2;
size_t valueParamIndex = parameters.GetParametersCount() - 1;
size_t operatorParamIndex = parameters.size() - 2;
size_t valueParamIndex = parameters.size() - 1;
if (isObjectInstruction || isBehaviorInstruction) {
gd::String templateSentence = _("Change <subject> of _PARAM0_: <operator> <value>");
@@ -182,8 +181,8 @@ InstructionMetadata::UseStandardRelationalOperatorParameters(
AddParameter(type,
options.description.empty() ? _("Value to compare") : options.description,
options.typeExtraInfo);
size_t operatorParamIndex = parameters.GetParametersCount() - 2;
size_t valueParamIndex = parameters.GetParametersCount() - 1;
size_t operatorParamIndex = parameters.size() - 2;
size_t valueParamIndex = parameters.size() - 1;
if (isObjectInstruction || isBehaviorInstruction) {
gd::String templateSentence = _("<subject> of _PARAM0_ <operator> <value>");

View File

@@ -14,7 +14,6 @@
#include <memory>
#include "GDCore/Events/Instruction.h"
#include "GDCore/Project/ParameterMetadataContainer.h"
#include "GDCore/String.h"
#include "ParameterMetadata.h"
#include "ParameterOptions.h"
@@ -62,12 +61,12 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
const gd::String &GetDescription() const { return description; }
const gd::String &GetSentence() const { return sentence; }
const gd::String &GetGroup() const { return group; }
ParameterMetadata &GetParameter(size_t i) { return parameters.GetParameter(i); }
ParameterMetadata &GetParameter(size_t i) { return parameters[i]; }
const ParameterMetadata &GetParameter(size_t i) const {
return parameters.GetParameter(i);
return parameters[i];
}
size_t GetParametersCount() const { return parameters.GetParametersCount(); }
const ParameterMetadataContainer &GetParameters() const {
size_t GetParametersCount() const { return parameters.size(); }
const std::vector<ParameterMetadata> &GetParameters() const {
return parameters;
}
const gd::String &GetIconFilename() const { return iconFilename; }
@@ -257,9 +256,7 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
* \see AddParameter
*/
InstructionMetadata &SetDefaultValue(const gd::String &defaultValue_) override {
if (parameters.GetParametersCount() > 0) {
parameters.GetInternalVector().back()->SetDefaultValue(defaultValue_);
}
if (!parameters.empty()) parameters.back().SetDefaultValue(defaultValue_);
return *this;
};
@@ -271,9 +268,8 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
*/
InstructionMetadata &SetParameterLongDescription(
const gd::String &longDescription) override {
if (parameters.GetParametersCount() > 0) {
parameters.GetInternalVector().back()->SetLongDescription(longDescription);
}
if (!parameters.empty())
parameters.back().SetLongDescription(longDescription);
return *this;
}
@@ -285,9 +281,7 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
* \see AddParameter
*/
InstructionMetadata &SetParameterExtraInfo(const gd::String &extraInfo) override {
if (parameters.GetParametersCount() > 0) {
parameters.GetInternalVector().back()->SetExtraInfo(extraInfo);
}
if (!parameters.empty()) parameters.back().SetExtraInfo(extraInfo);
return *this;
}
@@ -566,7 +560,7 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
*/
InstructionMetadata &GetCodeExtraInformation() { return *this; }
ParameterMetadataContainer parameters;
std::vector<ParameterMetadata> parameters;
private:
gd::String fullname;

View File

@@ -454,12 +454,11 @@ const gd::ParameterMetadata* MetadataProvider::GetFunctionCallParameterMetadata(
// TODO use a badMetadata instead of a nullptr?
const gd::ParameterMetadata* parameterMetadata = nullptr;
while (metadataParameterIndex <
metadata.GetParameters().GetParametersCount()) {
if (!metadata.GetParameters().GetParameter(metadataParameterIndex)
metadata.parameters.size()) {
if (!metadata.parameters[metadataParameterIndex]
.IsCodeOnly()) {
if (visibleParameterIndex == parameterIndex) {
parameterMetadata =
&metadata.GetParameters().GetParameter(metadataParameterIndex);
parameterMetadata = &metadata.parameters[metadataParameterIndex];
}
visibleParameterIndex++;
}

View File

@@ -4,8 +4,8 @@
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef PARAMETER_METADATA_H
#define PARAMETER_METADATA_H
#include <map>
#include <memory>
@@ -29,12 +29,6 @@ class GD_CORE_API ParameterMetadata {
ParameterMetadata();
virtual ~ParameterMetadata(){};
/**
* \brief Return a pointer to a new ParameterMetadata constructed from
* this one.
*/
ParameterMetadata* Clone() const { return new ParameterMetadata(*this); };
/**
* \brief Return the metadata of the parameter type.
*/
@@ -254,3 +248,5 @@ class GD_CORE_API ParameterMetadata {
};
} // namespace gd
#endif // PARAMETER_METADATA_H

View File

@@ -9,7 +9,6 @@
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/ObjectsContainersList.h"
#include "GDCore/Project/ParameterMetadataContainer.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
#include "InstructionMetadata.h"
@@ -21,13 +20,13 @@ const ParameterMetadata ParameterMetadataTools::badParameterMetadata;
void ParameterMetadataTools::ParametersToObjectsContainer(
const gd::Project& project,
const ParameterMetadataContainer& parameters,
const std::vector<gd::ParameterMetadata>& parameters,
gd::ObjectsContainer& outputObjectsContainer) {
outputObjectsContainer.GetObjects().clear();
gd::String lastObjectName;
for (std::size_t i = 0; i < parameters.GetParametersCount(); ++i) {
const auto& parameter = parameters.GetParameter(i);
for (std::size_t i = 0; i < parameters.size(); ++i) {
const auto& parameter = parameters[i];
if (parameter.GetName().empty()) continue;
if (gd::ParameterMetadata::IsObject(parameter.GetType())) {
@@ -62,34 +61,31 @@ void ParameterMetadataTools::ParametersToObjectsContainer(
}
void ParameterMetadataTools::ForEachParameterMatchingSearch(
const std::vector<const ParameterMetadataContainer*>&
const std::vector<const std::vector<gd::ParameterMetadata>*>&
parametersVectorsList,
const gd::String& search,
std::function<void(const gd::ParameterMetadata&)> cb) {
for (auto it = parametersVectorsList.rbegin();
it != parametersVectorsList.rend();
++it) {
const ParameterMetadataContainer* parametersVector = *it;
const std::vector<gd::ParameterMetadata>* parametersVector = *it;
for (const auto &parameterMetadata :
parametersVector->GetInternalVector()) {
if (parameterMetadata->GetName().FindCaseInsensitive(search) !=
gd::String::npos)
cb(*parameterMetadata);
for (const auto& parameterMetadata: *parametersVector) {
if (parameterMetadata.GetName().FindCaseInsensitive(search) != gd::String::npos) cb(parameterMetadata);
}
}
}
bool ParameterMetadataTools::Has(
const std::vector<const ParameterMetadataContainer*>& parametersVectorsList,
const std::vector<const std::vector<gd::ParameterMetadata>*>& parametersVectorsList,
const gd::String& parameterName) {
for (auto it = parametersVectorsList.rbegin();
it != parametersVectorsList.rend();
++it) {
const ParameterMetadataContainer* parametersVector = *it;
const std::vector<gd::ParameterMetadata>* parametersVector = *it;
for (const auto& parameterMetadata: parametersVector->GetInternalVector()) {
if (parameterMetadata->GetName() == parameterName) return true;
for (const auto& parameterMetadata: *parametersVector) {
if (parameterMetadata.GetName() == parameterName) return true;
}
}
@@ -97,18 +93,16 @@ bool ParameterMetadataTools::Has(
}
const gd::ParameterMetadata& ParameterMetadataTools::Get(
const std::vector<const ParameterMetadataContainer*>&
const std::vector<const std::vector<gd::ParameterMetadata>*>&
parametersVectorsList,
const gd::String& parameterName) {
for (auto it = parametersVectorsList.rbegin();
it != parametersVectorsList.rend();
++it) {
const ParameterMetadataContainer* parametersVector = *it;
const std::vector<gd::ParameterMetadata>* parametersVector = *it;
for (const auto &parameterMetadata :
parametersVector->GetInternalVector()) {
if (parameterMetadata->GetName() == parameterName)
return *parameterMetadata;
for (const auto& parameterMetadata: *parametersVector) {
if (parameterMetadata.GetName() == parameterName) return parameterMetadata;
}
}
@@ -117,7 +111,7 @@ const gd::ParameterMetadata& ParameterMetadataTools::Get(
void ParameterMetadataTools::IterateOverParameters(
const std::vector<gd::Expression>& parameters,
const ParameterMetadataContainer& parametersMetadata,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
std::function<void(const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
const gd::String& lastObjectName)> fn) {
@@ -134,17 +128,15 @@ void ParameterMetadataTools::IterateOverParameters(
void ParameterMetadataTools::IterateOverParametersWithIndex(
const std::vector<gd::Expression>& parameters,
const ParameterMetadataContainer& parametersMetadata,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
std::function<void(const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
size_t parameterIndex,
const gd::String& lastObjectName)> fn) {
gd::String lastObjectName = "";
for (std::size_t pNb = 0; pNb < parametersMetadata.GetParametersCount();
++pNb) {
const gd::ParameterMetadata &parameterMetadata =
parametersMetadata.GetParameter(pNb);
const gd::Expression &parameterValue =
for (std::size_t pNb = 0; pNb < parametersMetadata.size(); ++pNb) {
const gd::ParameterMetadata& parameterMetadata = parametersMetadata[pNb];
const gd::Expression& parameterValue =
pNb < parameters.size() ? parameters[pNb].GetPlainString() : "";
const gd::Expression& parameterValueOrDefault =
parameterValue.GetPlainString().empty() && parameterMetadata.IsOptional()
@@ -187,10 +179,10 @@ void ParameterMetadataTools::IterateOverParametersWithIndex(
size_t parameterIndex = 0;
for (size_t metadataIndex = (isObjectFunction ? 1 : 0);
metadataIndex < metadata.GetParameters().GetParametersCount() &&
metadataIndex < metadata.parameters.size() &&
parameterIndex < node.parameters.size();
++metadataIndex) {
auto &parameterMetadata = metadata.GetParameters().GetParameter(metadataIndex);
auto &parameterMetadata = metadata.parameters[metadataIndex];
if (parameterMetadata.IsCodeOnly()) {
continue;
}
@@ -212,17 +204,16 @@ void ParameterMetadataTools::IterateOverParametersWithIndex(
}
size_t ParameterMetadataTools::GetObjectParameterIndexFor(
const ParameterMetadataContainer& parametersMetadata,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
size_t parameterIndex) {
// By convention, parameters that require
// an object (mainly, "objectvar" and "behavior") should be placed after
// the object in the list of parameters (if possible, just after).
// Search "lastObjectName" in the codebase for other place where this
// convention is enforced.
for (std::size_t pNb = parameterIndex;
pNb < parametersMetadata.GetParametersCount(); pNb--) {
if (gd::ParameterMetadata::IsObject(
parametersMetadata.GetParameter(pNb).GetType())) {
for (std::size_t pNb = parameterIndex; pNb < parametersMetadata.size();
pNb--) {
if (gd::ParameterMetadata::IsObject(parametersMetadata[pNb].GetType())) {
return pNb;
}
}

View File

@@ -15,7 +15,6 @@ class ObjectsContainer;
class ObjectsContainersList;
class ParameterMetadata;
class Expression;
class ParameterMetadataContainer;
struct FunctionCallNode;
struct ExpressionNode;
} // namespace gd
@@ -25,20 +24,20 @@ class GD_CORE_API ParameterMetadataTools {
public:
static void ParametersToObjectsContainer(
const gd::Project& project,
const ParameterMetadataContainer& parameters,
const std::vector<gd::ParameterMetadata>& parameters,
gd::ObjectsContainer& outputObjectsContainer);
static void ForEachParameterMatchingSearch(
const std::vector<const ParameterMetadataContainer*>& parametersVectorsList,
const std::vector<const std::vector<gd::ParameterMetadata>*>& parametersVectorsList,
const gd::String& search,
std::function<void(const gd::ParameterMetadata&)> cb);
static bool Has(
const std::vector<const ParameterMetadataContainer*>& parametersVectorsList,
const std::vector<const std::vector<gd::ParameterMetadata>*>& parametersVectorsList,
const gd::String& parameterName);
static const gd::ParameterMetadata& Get(
const std::vector<const ParameterMetadataContainer*>& parametersVectorsList,
const std::vector<const std::vector<gd::ParameterMetadata>*>& parametersVectorsList,
const gd::String& parameterName);
/**
@@ -48,7 +47,7 @@ class GD_CORE_API ParameterMetadataTools {
*/
static void IterateOverParameters(
const std::vector<gd::Expression>& parameters,
const ParameterMetadataContainer& parametersMetadata,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
std::function<void(const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
const gd::String& lastObjectName)> fn);
@@ -60,7 +59,7 @@ class GD_CORE_API ParameterMetadataTools {
*/
static void IterateOverParametersWithIndex(
const std::vector<gd::Expression>& parameters,
const ParameterMetadataContainer& parametersMetadata,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
std::function<void(const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
size_t parameterIndex,
@@ -85,7 +84,7 @@ class GD_CORE_API ParameterMetadataTools {
* it's linked to.
*/
static size_t GetObjectParameterIndexFor(
const ParameterMetadataContainer& parametersMetadata,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
size_t parameterIndex);
private:

View File

@@ -210,8 +210,8 @@ class GD_CORE_API ValueTypeMetadata {
parameterType == "scenevar";
} else if (type == "resource") {
return parameterType == "fontResource" ||
parameterType == "audioResource" ||
parameterType == "videoResource" ||
parameterType == "soundfile" ||
parameterType == "musicfile" ||
parameterType == "bitmapFontResource" ||
parameterType == "imageResource" ||
parameterType == "jsonResource" ||
@@ -219,10 +219,7 @@ class GD_CORE_API ValueTypeMetadata {
parameterType == "tilesetResource" ||
parameterType == "model3DResource" ||
parameterType == "atlasResource" ||
parameterType == "spineResource" ||
// Deprecated, old parameter types:
parameterType == "soundfile" ||
parameterType == "musicfile";
parameterType == "spineResource";
}
return false;
}

View File

@@ -72,12 +72,12 @@ public:
gd::String lastObjectParameter = "";
const gd::InstructionMetadata &instrInfos =
MetadataProvider::GetActionMetadata(platform, instruction.GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters.GetParameter(pNb).GetType()) ||
"number", instrInfos.parameters[pNb].GetType()) ||
ParameterMetadata::IsExpression(
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
"string", instrInfos.parameters[pNb].GetType())) {
auto node = instruction.GetParameter(pNb).GetRootNode();
node->Visit(*this);
}

View File

@@ -86,11 +86,9 @@ class GD_CORE_API IdentifierFinderExpressionNodeWorker
}
size_t parameterIndex = 0;
for (size_t metadataIndex = (isObjectFunction ? 1 : 0);
metadataIndex < metadata.GetParameters().GetParametersCount() &&
parameterIndex < node.parameters.size();
++metadataIndex) {
auto& parameterMetadata = metadata.GetParameters().GetParameter(metadataIndex);
for (size_t metadataIndex = (isObjectFunction ? 1 : 0); metadataIndex < metadata.parameters.size()
&& parameterIndex < node.parameters.size(); ++metadataIndex) {
auto& parameterMetadata = metadata.parameters[metadataIndex];
if (parameterMetadata.IsCodeOnly()) {
continue;
}
@@ -146,10 +144,10 @@ class GD_CORE_API IdentifierFinderEventWorker
platform, instruction.GetType())
: MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
// The parameter has the searched type...
if (instrInfos.parameters.GetParameter(pNb).GetType() == "identifier"
&& instrInfos.parameters.GetParameter(pNb).GetExtraInfo() == identifierType) {
if (instrInfos.parameters[pNb].GetType() == "identifier"
&& instrInfos.parameters[pNb].GetExtraInfo() == identifierType) {
//...remember the value of the parameter.
if (objectName.empty() || lastObjectParameter == objectName) {
results.insert(instruction.GetParameter(pNb).GetPlainString());
@@ -157,9 +155,9 @@ class GD_CORE_API IdentifierFinderEventWorker
}
// Search in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters.GetParameter(pNb).GetType()) ||
"number", instrInfos.parameters[pNb].GetType()) ||
ParameterMetadata::IsExpression(
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
"string", instrInfos.parameters[pNb].GetType())) {
auto node = instruction.GetParameter(pNb).GetRootNode();
IdentifierFinderExpressionNodeWorker searcher(
@@ -172,7 +170,7 @@ class GD_CORE_API IdentifierFinderEventWorker
}
// Remember the value of the last "object" parameter.
else if (gd::ParameterMetadata::IsObject(
instrInfos.parameters.GetParameter(pNb).GetType())) {
instrInfos.parameters[pNb].GetType())) {
lastObjectParameter =
instruction.GetParameter(pNb).GetPlainString();
}

View File

@@ -305,14 +305,14 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
for (std::size_t aId = 0; aId < actions.size(); ++aId) {
const gd::InstructionMetadata& instrInfos =
MetadataProvider::GetActionMetadata(platform, actions[aId].GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
// Replace object's name in parameters
if (gd::ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType()) &&
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType()) &&
actions[aId].GetParameter(pNb).GetPlainString() == oldName)
actions[aId].SetParameter(pNb, gd::Expression(newName));
// Replace object's name in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters.GetParameter(pNb).GetType())) {
"number", instrInfos.parameters[pNb].GetType())) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
@@ -322,7 +322,7 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
"string", instrInfos.parameters[pNb].GetType())) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
@@ -357,14 +357,14 @@ bool EventsRefactorer::RenameObjectInConditions(
const gd::InstructionMetadata& instrInfos =
MetadataProvider::GetConditionMetadata(platform,
conditions[cId].GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
// Replace object's name in parameters
if (gd::ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType()) &&
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType()) &&
conditions[cId].GetParameter(pNb).GetPlainString() == oldName)
conditions[cId].SetParameter(pNb, gd::Expression(newName));
// Replace object's name in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters.GetParameter(pNb).GetType())) {
"number", instrInfos.parameters[pNb].GetType())) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
@@ -374,7 +374,7 @@ bool EventsRefactorer::RenameObjectInConditions(
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
"string", instrInfos.parameters[pNb].GetType())) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
@@ -485,16 +485,16 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
const gd::InstructionMetadata& instrInfos =
MetadataProvider::GetActionMetadata(platform, actions[aId].GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
// Find object's name in parameters
if (gd::ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType()) &&
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType()) &&
actions[aId].GetParameter(pNb).GetPlainString() == name) {
deleteMe = true;
break;
}
// Find object's name in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters.GetParameter(pNb).GetType())) {
"number", instrInfos.parameters[pNb].GetType())) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, projectScopedContainers, "number", *node, name)) {
@@ -504,7 +504,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
}
// Find object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
"string", instrInfos.parameters[pNb].GetType())) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, projectScopedContainers, "string", *node, name)) {
@@ -543,16 +543,16 @@ bool EventsRefactorer::RemoveObjectInConditions(
const gd::InstructionMetadata& instrInfos =
MetadataProvider::GetConditionMetadata(platform,
conditions[cId].GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
// Find object's name in parameters
if (gd::ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType()) &&
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType()) &&
conditions[cId].GetParameter(pNb).GetPlainString() == name) {
deleteMe = true;
break;
}
// Find object's name in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters.GetParameter(pNb).GetType())) {
"number", instrInfos.parameters[pNb].GetType())) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, projectScopedContainers, "number", *node, name)) {
@@ -562,7 +562,7 @@ bool EventsRefactorer::RemoveObjectInConditions(
}
// Find object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
"string", instrInfos.parameters[pNb].GetType())) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, projectScopedContainers, "string", *node, name)) {

View File

@@ -31,8 +31,6 @@
namespace gd {
VariablesContainer EventsVariableInstructionTypeSwitcher::nullVariablesContainer;
bool EventsVariableInstructionTypeSwitcher::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
const auto& metadata = isCondition
@@ -84,8 +82,7 @@ bool EventsVariableInstructionTypeSwitcher::DoVisitInstruction(gd::Instruction&
// 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 ||
lastObjectName == groupName) {
if (variablesContainer == &targetVariablesContainer) {
if (typeChangedVariableNames.find(variableName) !=
typeChangedVariableNames.end()) {
gd::VariableInstructionSwitcher::

View File

@@ -17,7 +17,7 @@
namespace gd {
class VariablesContainer;
class Platform;
} // namespace gd
} // namespace gd
namespace gd {
/**
@@ -33,36 +33,21 @@ class GD_CORE_API EventsVariableInstructionTypeSwitcher
public:
EventsVariableInstructionTypeSwitcher(
const gd::Platform &platform_,
const std::unordered_set<gd::String> &typeChangedVariableNames_,
const gd::VariablesContainer &targetVariablesContainer_)
const gd::VariablesContainer &targetVariablesContainer_,
const std::unordered_set<gd::String> &typeChangedVariableNames_)
: platform(platform_),
typeChangedVariableNames(typeChangedVariableNames_),
targetVariablesContainer(targetVariablesContainer_), groupName(""){};
EventsVariableInstructionTypeSwitcher(
const gd::Platform &platform_,
const std::unordered_set<gd::String> &typeChangedVariableNames_,
const gd::String &groupName_)
: platform(platform_),
typeChangedVariableNames(typeChangedVariableNames_),
targetVariablesContainer(nullVariablesContainer),
groupName(groupName_){};
targetVariablesContainer(targetVariablesContainer_),
typeChangedVariableNames(typeChangedVariableNames_){};
virtual ~EventsVariableInstructionTypeSwitcher();
private:
private:
bool DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) override;
const gd::Platform &platform;
const gd::VariablesContainer &targetVariablesContainer;
/**
* Groups don't have VariablesContainer, so `targetVariablesContainer` will be
* pointing to `nullVariablesContainer` and the group name is use instead to
* check which instruction to modify.
*/
const gd::String groupName;
gd::String objectName;
const std::unordered_set<gd::String> &typeChangedVariableNames;
static VariablesContainer nullVariablesContainer;
};
} // namespace gd

View File

@@ -32,8 +32,6 @@
namespace gd {
VariablesContainer EventsVariableReplacer::nullVariablesContainer;
/**
* \brief Go through the nodes and rename variables,
* or signal if the instruction must be renamed if a removed variable is used.
@@ -46,26 +44,22 @@ class GD_CORE_API ExpressionVariableReplacer
ExpressionVariableReplacer(
const gd::Platform& platform_,
const gd::ProjectScopedContainers& projectScopedContainers_,
const VariablesRenamingChangesetNode& variablesRenamingChangesetRoot_,
const std::unordered_set<gd::String>& removedVariableNames_,
const gd::VariablesContainer& targetVariablesContainer_,
const gd::String &groupName_,
const gd::String &forcedInitialObjectName)
const VariablesRenamingChangesetNode& variablesRenamingChangesetRoot_,
const std::unordered_set<gd::String>& removedVariableNames_)
: hasDoneRenaming(false),
removedVariableUsed(false),
platform(platform_),
projectScopedContainers(projectScopedContainers_),
forcedVariablesContainer(nullptr),
forcedObjectName(forcedInitialObjectName),
variablesRenamingChangesetRoot(variablesRenamingChangesetRoot_),
removedVariableNames(removedVariableNames_),
forcedInitialVariablesContainer(nullptr),
targetVariablesContainer(targetVariablesContainer_),
targetGroupName(groupName_){};
variablesRenamingChangesetRoot(variablesRenamingChangesetRoot_),
removedVariableNames(removedVariableNames_){};
virtual ~ExpressionVariableReplacer(){};
void SetForcedInitialVariablesContainer(
const gd::VariablesContainer* forcedInitialVariablesContainer_) {
forcedVariablesContainer = forcedInitialVariablesContainer_;
forcedInitialVariablesContainer = forcedInitialVariablesContainer_;
}
bool HasDoneRenaming() const { return hasDoneRenaming; }
@@ -88,13 +82,12 @@ class GD_CORE_API ExpressionVariableReplacer
// The node represents a variable or an object name on which a variable
// will be accessed.
if (forcedVariablesContainer) {
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 (forcedVariablesContainer == &targetVariablesContainer ||
IsTargetingObjectGroup(forcedObjectName)) {
if (forcedInitialVariablesContainer == &targetVariablesContainer) {
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
}
@@ -157,8 +150,7 @@ class GD_CORE_API ExpressionVariableReplacer
// This is always true because MatchIdentifierWithName is used to get
// objectNameToUseForVariableAccessor.
if (objectsContainersList.HasObjectOrGroupVariablesContainer(
objectNameToUseForVariableAccessor, targetVariablesContainer) ||
IsTargetingObjectGroup(objectNameToUseForVariableAccessor)) {
objectNameToUseForVariableAccessor, targetVariablesContainer)) {
objectNameToUseForVariableAccessor = "";
// The node represents an object variable, and this object variables are
// the target. Do the replacement or removals:
@@ -205,11 +197,10 @@ class GD_CORE_API ExpressionVariableReplacer
// (and if it's a variable reference or a value does not have any importance
// here).
if (forcedVariablesContainer) {
if (forcedInitialVariablesContainer) {
// A scope was forced. Honor it: it means this node represents a variable
// of the forced variables container.
if (forcedVariablesContainer == &targetVariablesContainer ||
IsTargetingObjectGroup(forcedObjectName)) {
if (forcedInitialVariablesContainer == &targetVariablesContainer) {
renameVariableAndChild();
}
return;
@@ -222,8 +213,7 @@ class GD_CORE_API ExpressionVariableReplacer
[&]() {
// This represents an object.
if (objectsContainersList.HasObjectOrGroupVariablesContainer(
node.identifierName, targetVariablesContainer) ||
IsTargetingObjectGroup(node.identifierName)) {
node.identifierName, targetVariablesContainer)) {
// The node represents an object variable, and this object variables
// are the target. Do the replacement or removals:
PushVariablesRenamingChangesetRoot();
@@ -271,33 +261,31 @@ class GD_CORE_API ExpressionVariableReplacer
// force the "scope" at which starts the evalution of variables.
if (parameterMetadata && parameterMetadata->GetValueTypeMetadata()
.IsLegacyPreScopedVariable()) {
const gd::VariablesContainer *oldForcedVariablesContainer =
forcedVariablesContainer;
const gd::String &oldForcedObjectName = forcedObjectName;
const gd::VariablesContainer* oldForcedInitialVariablesContainer =
forcedInitialVariablesContainer;
forcedVariablesContainer = nullptr;
forcedObjectName = "";
forcedInitialVariablesContainer = nullptr;
if (parameterMetadata->GetType() == "globalvar") {
forcedVariablesContainer =
forcedInitialVariablesContainer =
projectScopedContainers.GetVariablesContainersList()
.GetTopMostVariablesContainer();
} else if (parameterMetadata->GetType() == "scenevar") {
forcedVariablesContainer =
forcedInitialVariablesContainer =
projectScopedContainers.GetVariablesContainersList()
.GetBottomMostVariablesContainer();
} else if (parameterMetadata->GetType() == "objectvar") {
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
platform, projectScopedContainers.GetObjectsContainersList(),
node.objectName, *node.parameters[parameterIndex].get());
forcedVariablesContainer =
platform,
projectScopedContainers.GetObjectsContainersList(),
node.objectName,
*node.parameters[parameterIndex].get());
forcedInitialVariablesContainer =
projectScopedContainers.GetObjectsContainersList()
.GetObjectOrGroupVariablesContainer(objectName);
forcedObjectName = objectName;
}
node.parameters[parameterIndex]->Visit(*this);
forcedVariablesContainer = oldForcedVariablesContainer;
forcedObjectName = oldForcedObjectName;
forcedInitialVariablesContainer = oldForcedInitialVariablesContainer;
} else {
// For any other parameter, there is no special treatment being needed.
node.parameters[parameterIndex]->Visit(*this);
@@ -310,10 +298,6 @@ class GD_CORE_API ExpressionVariableReplacer
bool hasDoneRenaming;
bool removedVariableUsed;
bool IsTargetingObjectGroup(const gd::String &objectGroupName) {
return !targetGroupName.empty() && objectGroupName == targetGroupName;
}
bool RenameOrRemoveVariableOfTargetVariableContainer(
gd::String& variableName) {
const auto *currentVariablesRenamingChangesetNode =
@@ -398,17 +382,10 @@ class GD_CORE_API ExpressionVariableReplacer
// Scope:
const gd::Platform& platform;
const gd::ProjectScopedContainers& projectScopedContainers;
const gd::VariablesContainer* forcedVariablesContainer;
gd::String forcedObjectName;
const gd::VariablesContainer* forcedInitialVariablesContainer;
// Renaming or removing to do:
const gd::VariablesContainer& targetVariablesContainer;
/**
* Groups don't have VariablesContainer, so `targetVariablesContainer` will be
* pointing to `nullVariablesContainer` and the group name is use instead to
* check which variable accesses to modify in expressions.
*/
const gd::String& targetGroupName;
const VariablesRenamingChangesetNode &variablesRenamingChangesetRoot;
const std::unordered_set<gd::String>& removedVariableNames;
@@ -420,7 +397,7 @@ const gd::VariablesContainer*
EventsVariableReplacer::FindForcedVariablesContainerIfAny(
const gd::String& type, const gd::String& lastObjectName) {
// Handle legacy pre-scoped variable parameters: in this case, we
// force the "scope" at which starts the evaluation of variables.
// force the "scope" at which starts the evalution of variables.
if (type == "objectvar") {
return GetProjectScopedContainers()
.GetObjectsContainersList()
@@ -465,11 +442,9 @@ bool EventsVariableReplacer::DoVisitInstruction(gd::Instruction& instruction,
if (node) {
ExpressionVariableReplacer renamer(platform,
GetProjectScopedContainers(),
variablesRenamingChangesetRoot,
removedVariableNames,
targetVariablesContainer,
targetGroupName,
type == "objectvar" ? lastObjectName : "");
variablesRenamingChangesetRoot,
removedVariableNames);
renamer.SetForcedInitialVariablesContainer(
FindForcedVariablesContainerIfAny(type, lastObjectName));
node->Visit(renamer);
@@ -499,11 +474,9 @@ bool EventsVariableReplacer::DoVisitEventExpression(
if (node) {
ExpressionVariableReplacer renamer(platform,
GetProjectScopedContainers(),
variablesRenamingChangesetRoot,
removedVariableNames,
targetVariablesContainer,
targetGroupName,
"");
variablesRenamingChangesetRoot,
removedVariableNames);
renamer.SetForcedInitialVariablesContainer(
FindForcedVariablesContainerIfAny(type, ""));
node->Visit(renamer);

View File

@@ -35,24 +35,13 @@ class GD_CORE_API EventsVariableReplacer
public:
EventsVariableReplacer(
const gd::Platform &platform_,
const gd::VariablesContainer &targetVariablesContainer_,
const VariablesRenamingChangesetNode &variablesRenamingChangesetRoot_,
const std::unordered_set<gd::String> &removedVariableNames_,
const gd::VariablesContainer &targetVariablesContainer_)
const std::unordered_set<gd::String> &removedVariableNames_)
: platform(platform_),
variablesRenamingChangesetRoot(variablesRenamingChangesetRoot_),
removedVariableNames(removedVariableNames_),
targetVariablesContainer(targetVariablesContainer_),
targetGroupName("") {};
EventsVariableReplacer(
const gd::Platform &platform_,
const VariablesRenamingChangesetNode &variablesRenamingChangesetRoot_,
const std::unordered_set<gd::String> &removedVariableNames_,
const gd::String &targetGroupName_)
: platform(platform_),
variablesRenamingChangesetRoot(variablesRenamingChangesetRoot_),
removedVariableNames(removedVariableNames_),
targetVariablesContainer(nullVariablesContainer),
targetGroupName(targetGroupName_) {};
removedVariableNames(removedVariableNames_) {};
virtual ~EventsVariableReplacer();
private:
@@ -66,16 +55,9 @@ class GD_CORE_API EventsVariableReplacer
const gd::Platform &platform;
const gd::VariablesContainer &targetVariablesContainer;
/**
* Groups don't have VariablesContainer, so `targetVariablesContainer` will be
* pointing to `nullVariablesContainer` and the group name is use instead to
* check which variable accesses to modify in expressions.
*/
const gd::String targetGroupName;
gd::String objectName;
const VariablesRenamingChangesetNode &variablesRenamingChangesetRoot;
const std::unordered_set<gd::String> &removedVariableNames;
static VariablesContainer nullVariablesContainer;
};
} // namespace gd

View File

@@ -93,11 +93,9 @@ class GD_CORE_API VariableFinderExpressionNodeWorker
}
size_t parameterIndex = 0;
for (size_t metadataIndex = (isObjectFunction ? 1 : 0);
metadataIndex < metadata.GetParameters().GetParametersCount() &&
parameterIndex < node.parameters.size();
++metadataIndex) {
auto& parameterMetadata = metadata.GetParameters().GetParameter(metadataIndex);
for (size_t metadataIndex = (isObjectFunction ? 1 : 0); metadataIndex < metadata.parameters.size()
&& parameterIndex < node.parameters.size(); ++metadataIndex) {
auto& parameterMetadata = metadata.parameters[metadataIndex];
if (parameterMetadata.IsCodeOnly()) {
continue;
}
@@ -152,18 +150,18 @@ class GD_CORE_API VariableFinderEventWorker
platform, instruction.GetType())
: MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
// The parameter has the searched type...
if (instrInfos.parameters.GetParameter(pNb).GetType() == parameterType) {
if (instrInfos.parameters[pNb].GetType() == parameterType) {
//...remember the value of the parameter.
if (objectName.empty() || lastObjectParameter == objectName)
results.insert(instruction.GetParameter(pNb).GetPlainString());
}
// Search in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters.GetParameter(pNb).GetType()) ||
"number", instrInfos.parameters[pNb].GetType()) ||
ParameterMetadata::IsExpression(
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
"string", instrInfos.parameters[pNb].GetType())) {
auto node = instruction.GetParameter(pNb).GetRootNode();
VariableFinderExpressionNodeWorker searcher(
@@ -176,7 +174,7 @@ class GD_CORE_API VariableFinderEventWorker
}
// Remember the value of the last "object" parameter.
else if (gd::ParameterMetadata::IsObject(
instrInfos.parameters.GetParameter(pNb).GetType())) {
instrInfos.parameters[pNb].GetType())) {
lastObjectParameter =
instruction.GetParameter(pNb).GetPlainString();
}

View File

@@ -463,15 +463,11 @@ class GD_CORE_API ExpressionCompletionFinder
MetadataProvider::GetFunctionCallMetadata(
platform, objectsContainersList, *functionCall);
const gd::ParameterMetadata *parameterMetadata = nullptr;
while (metadataParameterIndex <
metadata.GetParameters().GetParametersCount()) {
if (!metadata.GetParameters()
.GetParameter(metadataParameterIndex)
.IsCodeOnly()) {
const gd::ParameterMetadata* parameterMetadata = nullptr;
while (metadataParameterIndex < metadata.parameters.size()) {
if (!metadata.parameters[metadataParameterIndex].IsCodeOnly()) {
if (visibleParameterIndex == parameterIndex) {
parameterMetadata =
&metadata.GetParameters().GetParameter(metadataParameterIndex);
parameterMetadata = &metadata.parameters[metadataParameterIndex];
}
visibleParameterIndex++;
}

View File

@@ -36,15 +36,13 @@ namespace {
* (by convention, 1 for object functions and 2 for behavior functions).
*/
size_t GetMinimumParametersNumber(
const gd::ParameterMetadataContainer& parameters,
const std::vector<gd::ParameterMetadata>& parameters,
size_t initialParameterIndex) {
size_t nb = 0;
for (std::size_t i = initialParameterIndex;
i < parameters.GetParametersCount(); ++i) {
if (!parameters.GetParameter(i).IsOptional() &&
!parameters.GetParameter(i).IsCodeOnly())
nb++;
for (std::size_t i = initialParameterIndex; i < parameters.size(); ++i) {
if (!parameters[i].IsOptional() && !parameters[i].codeOnly) nb++;
}
return nb;
}
@@ -53,14 +51,13 @@ size_t GetMinimumParametersNumber(
* (by convention, 1 for object functions and 2 for behavior functions).
*/
size_t GetMaximumParametersNumber(
const gd::ParameterMetadataContainer& parameters,
const std::vector<gd::ParameterMetadata>& parameters,
size_t initialParameterIndex) {
size_t nb = 0;
for (std::size_t i = initialParameterIndex;
i < parameters.GetParametersCount(); ++i) {
if (!parameters.GetParameter(i).IsCodeOnly())
nb++;
for (std::size_t i = initialParameterIndex; i < parameters.size(); ++i) {
if (!parameters[i].codeOnly) nb++;
}
return nb;
}
@@ -325,11 +322,11 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
// Validate parameters count
size_t minParametersCount = GetMinimumParametersNumber(
metadata.GetParameters(),
metadata.parameters,
ExpressionParser2::WrittenParametersFirstIndex(function.objectName,
function.behaviorName));
size_t maxParametersCount = GetMaximumParametersNumber(
metadata.GetParameters(),
metadata.parameters,
ExpressionParser2::WrittenParametersFirstIndex(function.objectName,
function.behaviorName));
if (function.parameters.size() < minParametersCount ||
@@ -369,11 +366,11 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
for (int parameterIndex = 0; parameterIndex < function.parameters.size();
parameterIndex++) {
auto& parameter = function.parameters[parameterIndex];
while (metadata.GetParameters().GetParameter(metadataIndex).IsCodeOnly()) {
while (metadata.GetParameters()[metadataIndex].IsCodeOnly()) {
// The sizes are already checked above.
metadataIndex++;
}
auto& parameterMetadata = metadata.GetParameters().GetParameter(metadataIndex);
auto& parameterMetadata = metadata.GetParameters()[metadataIndex];
if (!parameterMetadata.IsOptional() ||
dynamic_cast<EmptyNode*>(parameter.get()) == nullptr) {

View File

@@ -144,10 +144,10 @@ bool ExpressionsParameterMover::DoVisitInstruction(gd::Instruction& instruction,
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
for (std::size_t pNb = 0; pNb < metadata.parameters.GetParametersCount() &&
for (std::size_t pNb = 0; pNb < metadata.parameters.size() &&
pNb < instruction.GetParametersCount();
++pNb) {
const gd::String& type = metadata.parameters.GetParameter(pNb).GetType();
const gd::String& type = metadata.parameters[pNb].GetType();
const gd::Expression& expression = instruction.GetParameter(pNb);
auto node = expression.GetRootNode();

View File

@@ -151,7 +151,7 @@ bool ExpressionsRenamer::DoVisitInstruction(gd::Instruction& instruction,
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
for (std::size_t pNb = 0; pNb < metadata.parameters.GetParametersCount() &&
for (std::size_t pNb = 0; pNb < metadata.parameters.size() &&
pNb < instruction.GetParametersCount();
++pNb) {
const gd::Expression& expression = instruction.GetParameter(pNb);

View File

@@ -43,7 +43,7 @@ InstructionSentenceFormatter::GetAsFormattedText(
parse = false;
size_t firstParamPosition = gd::String::npos;
size_t firstParamIndex = gd::String::npos;
for (std::size_t i = 0; i < metadata.parameters.GetParametersCount(); ++i) {
for (std::size_t i = 0; i < metadata.parameters.size(); ++i) {
size_t paramPosition =
sentence.find("_PARAM" + gd::String::From(i) + "_");
if (paramPosition < firstParamPosition) {

View File

@@ -1,196 +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 "GroupVariableHelper.h"
#include "GDCore/IDE/WholeProjectRefactorer.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectGroup.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/ObjectsContainersList.h"
#include "GDCore/Project/Variable.h"
#include "GDCore/Project/VariablesContainer.h"
#include "GDCore/String.h"
namespace gd {
void GroupVariableHelper::FillAnyVariableBetweenObjects(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer,
const gd::ObjectGroup &objectGroup) {
const auto &objectNames = objectGroup.GetAllObjectsNames();
for (const gd::String &sourceObjectName : objectNames) {
const bool hasObject = objectsContainer.HasObjectNamed(sourceObjectName);
if (!hasObject &&
!globalObjectsContainer.HasObjectNamed(sourceObjectName)) {
continue;
}
const auto &sourceObject =
hasObject ? objectsContainer.GetObject(sourceObjectName)
: globalObjectsContainer.GetObject(sourceObjectName);
const auto &sourceVariablesContainer = sourceObject.GetVariables();
for (const gd::String &destinationObjectName : objectNames) {
if (sourceObjectName == destinationObjectName) {
continue;
}
const bool hasObject =
objectsContainer.HasObjectNamed(destinationObjectName);
if (!hasObject &&
!globalObjectsContainer.HasObjectNamed(destinationObjectName)) {
continue;
}
auto &destinationObject =
hasObject ? objectsContainer.GetObject(destinationObjectName)
: globalObjectsContainer.GetObject(destinationObjectName);
auto &destinationVariablesContainer = destinationObject.GetVariables();
for (std::size_t sourceVariableIndex = 0;
sourceVariableIndex < sourceVariablesContainer.Count();
++sourceVariableIndex) {
auto &sourceVariable =
sourceVariablesContainer.Get(sourceVariableIndex);
const auto &variableName =
sourceVariablesContainer.GetNameAt(sourceVariableIndex);
if (!destinationVariablesContainer.Has(variableName)) {
destinationVariablesContainer.Insert(
variableName, sourceVariable,
destinationVariablesContainer.Count());
}
}
}
}
}
gd::VariablesContainer GroupVariableHelper::MergeVariableContainers(
const gd::ObjectsContainersList &objectsContainersList,
const gd::ObjectGroup &objectGroup) {
gd::VariablesContainer mergedVariablesContainer;
const auto &objectNames = objectGroup.GetAllObjectsNames();
std::size_t objectIndex = 0;
bool isFirstObjectFound = false;
for (; objectIndex < objectNames.size() && !isFirstObjectFound;
objectIndex++) {
const gd::String &objectName = objectNames[objectIndex];
if (!objectsContainersList.HasObjectOrGroupNamed(objectName)) {
continue;
}
isFirstObjectFound = true;
mergedVariablesContainer =
*objectsContainersList.GetObjectOrGroupVariablesContainer(objectName);
}
for (; objectIndex < objectNames.size(); objectIndex++) {
const gd::String &objectName = objectNames[objectIndex];
if (!objectsContainersList.HasObjectOrGroupNamed(objectName)) {
continue;
}
const auto &variablesContainer =
*objectsContainersList.GetObjectOrGroupVariablesContainer(objectName);
for (std::size_t variableIndex = 0;
variableIndex < mergedVariablesContainer.Count(); ++variableIndex) {
auto &mergedVariable = mergedVariablesContainer.Get(variableIndex);
const auto &variableName =
mergedVariablesContainer.GetNameAt(variableIndex);
if (variablesContainer.Has(variableName)) {
auto &variable = variablesContainer.Get(variableName);
if (mergedVariable.GetType() != variable.GetType()) {
mergedVariable.CastTo(gd::Variable::Type::MixedTypes);
} else if (mergedVariable != variable) {
mergedVariable.MarkAsMixedValues();
}
} else {
mergedVariablesContainer.Remove(variableName);
variableIndex--;
}
}
}
return mergedVariablesContainer;
}
void GroupVariableHelper::FillMissingGroupVariablesToObjects(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer, const gd::ObjectGroup &objectGroup,
const gd::SerializerElement &originalSerializedVariables) {
gd::VariablesContainer groupVariablesContainer;
groupVariablesContainer.UnserializeFrom(originalSerializedVariables);
// Add missing variables to objects added in the group.
for (const gd::String &objectName : objectGroup.GetAllObjectsNames()) {
const bool hasObject = objectsContainer.HasObjectNamed(objectName);
if (!hasObject && !globalObjectsContainer.HasObjectNamed(objectName)) {
continue;
}
auto &object = hasObject ? objectsContainer.GetObject(objectName)
: globalObjectsContainer.GetObject(objectName);
auto &variablesContainer = object.GetVariables();
for (std::size_t variableIndex = 0;
variableIndex < groupVariablesContainer.Count(); ++variableIndex) {
auto &groupVariable = groupVariablesContainer.Get(variableIndex);
const auto &variableName =
groupVariablesContainer.GetNameAt(variableIndex);
if (!variablesContainer.Has(variableName)) {
variablesContainer.Insert(variableName, groupVariable,
variablesContainer.Count());
}
}
}
};
// TODO Handle position changes for group variables.
// We could try to change the order of object variables in a way that the next
// call to MergeVariableContainers rebuild them in the same order.
void GroupVariableHelper::ApplyChangesToObjects(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer,
const gd::VariablesContainer &groupVariablesContainer,
const gd::ObjectGroup &objectGroup,
const gd::VariablesChangeset &changeset) {
for (const gd::String &objectName : objectGroup.GetAllObjectsNames()) {
const bool hasObject = objectsContainer.HasObjectNamed(objectName);
if (!hasObject && !globalObjectsContainer.HasObjectNamed(objectName)) {
continue;
}
auto &object = hasObject ? objectsContainer.GetObject(objectName)
: globalObjectsContainer.GetObject(objectName);
auto &variablesContainer = object.GetVariables();
for (const gd::String &variableName : changeset.removedVariableNames) {
variablesContainer.Remove(variableName);
}
for (const gd::String &variableName : changeset.addedVariableNames) {
if (variablesContainer.Has(variableName)) {
// It can happens if an object already had the variable but it was not
// shared by other object of the group.
continue;
}
variablesContainer.Insert(variableName,
groupVariablesContainer.Get(variableName),
variablesContainer.Count());
}
for (const auto &pair : changeset.oldToNewVariableNames) {
const gd::String &oldVariableName = pair.first;
const gd::String &newVariableName = pair.second;
if (variablesContainer.Has(newVariableName)) {
// It can happens if an object already had the variable but it was not
// shared by other object of the group.
variablesContainer.Remove(oldVariableName);
} else {
variablesContainer.Rename(oldVariableName, newVariableName);
}
}
// Apply type and value changes
for (const gd::String &variableName : changeset.valueChangedVariableNames) {
size_t index = variablesContainer.GetPosition(variableName);
variablesContainer.Remove(variableName);
variablesContainer.Insert(
variableName, groupVariablesContainer.Get(variableName), index);
}
}
}
} // namespace gd

View File

@@ -1,75 +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/Project/VariablesContainer.h"
namespace gd {
class ObjectsContainersList;
class ObjectsContainer;
class ObjectGroup;
class VariablesContainer;
struct VariablesChangeset;
} // namespace gd
namespace gd {
/**
* Help handling variables of group objects as a whole.
*
* This is used by the object group variable editor.
*/
class GD_CORE_API GroupVariableHelper {
public:
/**
* Copy every variable from every object of the group to the other objects
* if they don't have it already.
*
* In the editor, when an object group is created, users can choose between:
* - doing no change and only see variables that are already shared by any
* objects of the group
* - applying this function and see every variable
*/
static void
FillAnyVariableBetweenObjects(gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer,
const gd::ObjectGroup &objectGroup);
/**
* Build a variable container with the intersection of variables from the
* every objects of the given group.
*/
static gd::VariablesContainer MergeVariableContainers(
const gd::ObjectsContainersList &objectsContainersList,
const gd::ObjectGroup &objectGroup);
/**
* @brief Copy the variables of the group to all objects.
*
* Objects can be added during the group edition and may not necessarily have
* all the variables initially shared by the group.
*
* \see gd::GroupVariableHelper::MergeVariableContainers
*/
static void FillMissingGroupVariablesToObjects(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer,
const gd::ObjectGroup &objectGroup,
const gd::SerializerElement &originalSerializedVariables);
/**
* @brief Apply the changes done with the variables editor to the objects of
* the group.
*/
static void
ApplyChangesToObjects(gd::ObjectsContainer &globalObjectsContainers,
gd::ObjectsContainer &objectsContainers,
const gd::VariablesContainer &groupVariablesContainer,
const gd::ObjectGroup &objectGroup,
const gd::VariablesChangeset &changeset);
};
} // namespace gd

View File

@@ -225,7 +225,9 @@ bool ResourceWorkerInEventsWorker::DoVisitInstruction(gd::Instruction& instructi
size_t parameterIndex,
const gd::String& lastObjectName) {
const String& parameterValue = parameterExpression.GetPlainString();
if (parameterMetadata.GetType() == "fontResource") {
if (parameterMetadata.GetType() ==
"police" || // Should be renamed fontResource
parameterMetadata.GetType() == "fontResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeFont(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);

View File

@@ -15,10 +15,10 @@ namespace gd {
void FunctionParameterBehaviorTypeRenamer::DoVisitEventsFunction(
gd::EventsFunction &eventsFunction) {
for (auto &&parameter : eventsFunction.GetParameters().GetInternalVector()) {
if (gd::ParameterMetadata::IsBehavior(parameter->GetType()) &&
parameter->GetExtraInfo() == oldBehaviorType) {
parameter->SetExtraInfo(newBehaviorType);
for (auto &&parameter : eventsFunction.GetParameters()) {
if (gd::ParameterMetadata::IsBehavior(parameter.GetType()) &&
parameter.GetExtraInfo() == oldBehaviorType) {
parameter.SetExtraInfo(newBehaviorType);
}
}
}

View File

@@ -15,10 +15,10 @@ namespace gd {
void FunctionParameterObjectTypeRenamer::DoVisitEventsFunction(
gd::EventsFunction &eventsFunction) {
for (auto &&parameter : eventsFunction.GetParameters().GetInternalVector()) {
if (gd::ParameterMetadata::IsObject(parameter->GetType()) &&
parameter->GetExtraInfo() == oldObjectType) {
parameter->SetExtraInfo(newObjectType);
for (auto &&parameter : eventsFunction.GetParameters()) {
if (gd::ParameterMetadata::IsObject(parameter.GetType()) &&
parameter.GetExtraInfo() == oldObjectType) {
parameter.SetExtraInfo(newObjectType);
}
}
}

View File

@@ -153,7 +153,7 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
extension.GetName(), eventsBasedEntity.GetName());
objectParameter.SetExtraInfo(objectFullType);
}
setter.GetParameters().AddParameter(objectParameter);
setter.GetParameters().push_back(objectParameter);
if (isBehavior) {
gd::ParameterMetadata behaviorParameter;
gd::String behaviorFullType =
@@ -163,7 +163,7 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
.SetName("Behavior")
.SetDescription("Behavior")
.SetExtraInfo(behaviorFullType);
setter.GetParameters().AddParameter(behaviorParameter);
setter.GetParameters().push_back(behaviorParameter);
}
gd::ParameterMetadata valueParameter;
valueParameter.SetType("yesorno")
@@ -171,7 +171,7 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
.SetDescription(capitalizedName)
.SetOptional(true)
.SetDefaultValue("yes");
setter.GetParameters().AddParameter(valueParameter);
setter.GetParameters().push_back(valueParameter);
} else {
setter.SetFunctionType(gd::EventsFunction::ActionWithOperator);
setter.SetGetterName(getterName);

View File

@@ -11,23 +11,22 @@
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/DependenciesAnalyzer.h"
#include "GDCore/IDE/GroupVariableHelper.h"
#include "GDCore/IDE/EventBasedBehaviorBrowser.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Events/BehaviorParametersFiller.h"
#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/EventsVariableInstructionTypeSwitcher.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"
@@ -102,17 +101,17 @@ void WholeProjectRefactorer::EnsureBehaviorEventsFunctionsProperParameters(
for (auto &eventsFunction :
eventsBasedBehavior.GetEventsFunctions().GetInternalVector()) {
auto &parameters = eventsFunction->GetParameters();
while (parameters.GetParametersCount() < 2) {
while (parameters.size() < 2) {
gd::ParameterMetadata newParameter;
parameters.AddParameter(newParameter);
parameters.push_back(newParameter);
}
parameters.GetParameter(0)
parameters[0]
.SetType("object")
.SetName(behaviorObjectParameterName)
.SetDescription("Object")
.SetExtraInfo(eventsBasedBehavior.GetObjectType());
parameters.GetParameter(1)
parameters[1]
.SetType("behavior")
.SetName("Behavior")
.SetDescription("Behavior")
@@ -127,12 +126,12 @@ void WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
for (auto &eventsFunction :
eventsBasedObject.GetEventsFunctions().GetInternalVector()) {
auto &parameters = eventsFunction->GetParameters();
while (parameters.GetParametersCount() < 1) {
while (parameters.size() < 1) {
gd::ParameterMetadata newParameter;
parameters.AddParameter(newParameter);
parameters.push_back(newParameter);
}
parameters.GetParameter(0)
parameters[0]
.SetType("object")
.SetName(parentObjectParameterName)
.SetDescription("Object")
@@ -174,7 +173,6 @@ WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
removedUuidAndNames.find(variable.GetPersistentUuid());
if (existingOldVariableUuidAndName == removedUuidAndNames.end()) {
// This is a new variable.
changeset.addedVariableNames.insert(variableName);
} else {
const gd::String &oldName = existingOldVariableUuidAndName->second;
@@ -184,15 +182,9 @@ WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
}
const auto &oldVariable = oldVariablesContainer.Get(oldName);
if (gd::WholeProjectRefactorer::HasAnyVariableTypeChanged(oldVariable,
variable)) {
if (gd::WholeProjectRefactorer::HasAnyVariableTypeChanged(oldVariable, variable)) {
changeset.typeChangedVariableNames.insert(variableName);
}
if (oldVariable != variable
// Mixed values are never equals, but they must not override anything.
&& !variable.HasMixedValues()) {
changeset.valueChangedVariableNames.insert(variableName);
}
const auto &variablesRenamingChangesetNode =
gd::WholeProjectRefactorer::ComputeChangesetForVariable(oldVariable,
@@ -318,8 +310,8 @@ void WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
// Rename and remove variables
gd::EventsVariableReplacer eventsVariableReplacer(
project.GetCurrentPlatform(), changeset, changeset.removedVariableNames,
variablesContainer);
project.GetCurrentPlatform(), variablesContainer,
changeset, changeset.removedVariableNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsVariableReplacer);
@@ -329,83 +321,8 @@ void WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
// Switch types of instructions
gd::EventsVariableInstructionTypeSwitcher
eventsVariableInstructionTypeSwitcher(project.GetCurrentPlatform(),
changeset.typeChangedVariableNames,
variablesContainer);
gd::ProjectBrowserHelper::ExposeProjectEvents(
project, eventsVariableInstructionTypeSwitcher);
}
void WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
gd::Project &project, gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer,
const gd::VariablesContainer &groupVariablesContainer,
const gd::ObjectGroup &objectGroup,
const gd::VariablesChangeset &changeset,
const gd::SerializerElement &originalSerializedVariables) {
// While we support refactoring that would remove all references (actions, conditions...)
// it's both a bit dangerous for the user and we would need to show the user what
// will be removed before doing so. For now, just clear the removed variables so they don't
// trigger any refactoring.
std::unordered_set<gd::String> removedVariableNames;
// Rename variables in events for the objects of the group.
for (const gd::String &objectName : objectGroup.GetAllObjectsNames()) {
const bool hasObject = objectsContainer.HasObjectNamed(objectName);
if (!hasObject && !globalObjectsContainer.HasObjectNamed(objectName)) {
continue;
}
auto &object = hasObject ? objectsContainer.GetObject(objectName)
: globalObjectsContainer.GetObject(objectName);
auto &variablesContainer = object.GetVariables();
gd::EventsVariableReplacer eventsVariableReplacer(
project.GetCurrentPlatform(), changeset,
removedVariableNames, variablesContainer);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsVariableReplacer);
}
// Rename variables in events for the group.
gd::EventsVariableReplacer eventsVariableReplacer(
project.GetCurrentPlatform(), changeset, removedVariableNames,
objectGroup.GetName());
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsVariableReplacer);
// Apply changes to objects.
gd::GroupVariableHelper::FillMissingGroupVariablesToObjects(
globalObjectsContainer,
objectsContainer,
objectGroup,
originalSerializedVariables);
gd::GroupVariableHelper::ApplyChangesToObjects(
globalObjectsContainer, objectsContainer, groupVariablesContainer,
objectGroup, changeset);
// Switch types of instructions for the group objects.
for (const gd::String &objectName : objectGroup.GetAllObjectsNames()) {
const bool hasObject = objectsContainer.HasObjectNamed(objectName);
if (!hasObject && !globalObjectsContainer.HasObjectNamed(objectName)) {
continue;
}
auto &object = hasObject ? objectsContainer.GetObject(objectName)
: globalObjectsContainer.GetObject(objectName);
auto &variablesContainer = object.GetVariables();
gd::EventsVariableInstructionTypeSwitcher
eventsVariableInstructionTypeSwitcher(
project.GetCurrentPlatform(), changeset.typeChangedVariableNames,
variablesContainer);
gd::ProjectBrowserHelper::ExposeProjectEvents(
project, eventsVariableInstructionTypeSwitcher);
}
// Switch types of instructions for the group.
gd::EventsVariableInstructionTypeSwitcher
eventsVariableInstructionTypeSwitcher(project.GetCurrentPlatform(),
changeset.typeChangedVariableNames,
objectGroup.GetName());
variablesContainer,
changeset.typeChangedVariableNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(
project, eventsVariableInstructionTypeSwitcher);
}
@@ -932,8 +849,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
oldPropertyName, newPropertyName);
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
project, eventsFunctionsExtension, eventsBasedBehavior,
behaviorRenamer);
project, eventsFunctionsExtension, eventsBasedBehavior, behaviorRenamer);
} else {
// Properties that represent primitive values will be used through
// their related actions/conditions/expressions. Rename these.
@@ -1003,8 +919,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
oldPropertyName, newPropertyName);
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
project, eventsFunctionsExtension, eventsBasedBehavior,
behaviorRenamer);
project, eventsFunctionsExtension, eventsBasedBehavior, behaviorRenamer);
} else {
// Properties that represent primitive values will be used through
// their related actions/conditions/expressions. Rename these.
@@ -1603,7 +1518,7 @@ void WholeProjectRefactorer::DoRenameObject(
projectBrowser.ExposeFunctions(project, objectParameterRenamer);
}
void WholeProjectRefactorer::ObjectRemovedInScene(
void WholeProjectRefactorer::ObjectRemovedInLayout(
gd::Project &project, gd::Layout &layout, const gd::String &objectName) {
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
@@ -1625,7 +1540,7 @@ void WholeProjectRefactorer::ObjectRemovedInScene(
}
}
void WholeProjectRefactorer::BehaviorsAddedToObjectInScene(
void WholeProjectRefactorer::BehaviorsAddedToObjectInLayout(
gd::Project &project, gd::Layout &layout, const gd::String &objectName) {
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
@@ -1635,7 +1550,7 @@ void WholeProjectRefactorer::BehaviorsAddedToObjectInScene(
project, layout, behaviorParameterFiller);
}
void WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
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())
@@ -1726,150 +1641,81 @@ void WholeProjectRefactorer::RenameExternalEvents(gd::Project &project,
linkEventTargetRenamer);
}
void WholeProjectRefactorer::RenameLayerInScene(gd::Project &project,
gd::Layout &scene,
const gd::String &oldName,
const gd::String &newName) {
void WholeProjectRefactorer::RenameLayer(gd::Project &project,
gd::Layout &layout,
const gd::String &oldName,
const gd::String &newName) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
gd::ProjectElementRenamer projectElementRenamer(project.GetCurrentPlatform(),
"layer", oldName, newName);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, scene, projectElementRenamer);
scene.GetInitialInstances().MoveInstancesToLayer(oldName, newName);
project, layout, projectElementRenamer);
layout.GetInitialInstances().MoveInstancesToLayer(oldName, newName);
std::vector<gd::String> externalLayoutsNames =
GetAssociatedExternalLayouts(project, scene);
GetAssociatedExternalLayouts(project, layout);
for (gd::String name : externalLayoutsNames) {
auto &externalLayout = project.GetExternalLayout(name);
externalLayout.GetInitialInstances().MoveInstancesToLayer(oldName, newName);
}
}
void WholeProjectRefactorer::RenameLayerInEventsBasedObject(
gd::Project &project,
gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedObject &eventsBasedObject, const gd::String &oldName,
const gd::String &newName) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
gd::ProjectElementRenamer projectElementRenamer(project.GetCurrentPlatform(),
"layer", oldName, newName);
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
project, eventsFunctionsExtension, eventsBasedObject,
projectElementRenamer);
eventsBasedObject.GetInitialInstances().MoveInstancesToLayer(oldName,
newName);
}
void WholeProjectRefactorer::RenameLayerEffectInScene(
gd::Project &project, gd::Layout &scene, gd::Layer &layer,
const gd::String &oldName, const gd::String &newName) {
void WholeProjectRefactorer::RenameLayerEffect(gd::Project &project,
gd::Layout &layout,
gd::Layer &layer,
const gd::String &oldName,
const gd::String &newName) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "layerEffectName", oldName, newName);
projectElementRenamer.SetLayerConstraint(layer.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, scene, projectElementRenamer);
project, layout, projectElementRenamer);
}
void WholeProjectRefactorer::RenameLayerEffectInEventsBasedObject(
gd::Project &project,
gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedObject &eventsBasedObject, gd::Layer &layer,
const gd::String &oldName, const gd::String &newName) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "layerEffectName", oldName, newName);
projectElementRenamer.SetLayerConstraint(layer.GetName());
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
project, eventsFunctionsExtension, eventsBasedObject,
projectElementRenamer);
}
void WholeProjectRefactorer::RenameObjectAnimationInScene(
gd::Project &project, gd::Layout &scene, gd::Object &object,
const gd::String &oldName, const gd::String &newName) {
void WholeProjectRefactorer::RenameObjectAnimation(gd::Project &project,
gd::Layout &layout,
gd::Object &object,
const gd::String &oldName,
const gd::String &newName) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "objectAnimationName", oldName, newName);
projectElementRenamer.SetObjectConstraint(object.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, scene, projectElementRenamer);
project, layout, projectElementRenamer);
}
void WholeProjectRefactorer::RenameObjectAnimationInEventsBasedObject(
gd::Project &project,
gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedObject &eventsBasedObject, gd::Object &object,
const gd::String &oldName, const gd::String &newName) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "objectAnimationName", oldName, newName);
projectElementRenamer.SetObjectConstraint(object.GetName());
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
project, eventsFunctionsExtension, eventsBasedObject,
projectElementRenamer);
}
void WholeProjectRefactorer::RenameObjectPointInScene(
gd::Project &project, gd::Layout &scene, gd::Object &object,
const gd::String &oldName, const gd::String &newName) {
void WholeProjectRefactorer::RenameObjectPoint(gd::Project &project,
gd::Layout &layout,
gd::Object &object,
const gd::String &oldName,
const gd::String &newName) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "objectPointName", oldName, newName);
projectElementRenamer.SetObjectConstraint(object.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, scene, projectElementRenamer);
project, layout, projectElementRenamer);
}
void WholeProjectRefactorer::RenameObjectPointInEventsBasedObject(
gd::Project &project,
gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedObject &eventsBasedObject, gd::Object &object,
const gd::String &oldName, const gd::String &newName) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "objectPointName", oldName, newName);
projectElementRenamer.SetObjectConstraint(object.GetName());
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
project, eventsFunctionsExtension, eventsBasedObject,
projectElementRenamer);
}
void WholeProjectRefactorer::RenameObjectEffectInScene(
gd::Project &project, gd::Layout &scene, gd::Object &object,
const gd::String &oldName, const gd::String &newName) {
void WholeProjectRefactorer::RenameObjectEffect(gd::Project &project,
gd::Layout &layout,
gd::Object &object,
const gd::String &oldName,
const gd::String &newName) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "objectEffectName", oldName, newName);
projectElementRenamer.SetObjectConstraint(object.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, scene, projectElementRenamer);
}
void WholeProjectRefactorer::RenameObjectEffectInEventsBasedObject(
gd::Project &project,
gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedObject &eventsBasedObject, gd::Object &object,
const gd::String &oldName, const gd::String &newName) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "objectEffectName", oldName, newName);
projectElementRenamer.SetObjectConstraint(object.GetName());
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
project, eventsFunctionsExtension, eventsBasedObject,
projectElementRenamer);
project, layout, projectElementRenamer);
}
void WholeProjectRefactorer::ObjectRemovedInEventsBasedObject(
@@ -1947,9 +1793,10 @@ void WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
bool isObjectGroup) {
// Object groups can't be in other groups
if (!isObjectGroup) {
for (std::size_t g = 0; g < project.GetObjects().GetObjectGroups().size();
++g) {
project.GetObjects().GetObjectGroups()[g].RenameObject(oldName, newName);
for (std::size_t g = 0;
g < project.GetObjects().GetObjectGroups().size(); ++g) {
project.GetObjects().GetObjectGroups()[g].RenameObject(oldName,
newName);
}
}
@@ -1958,13 +1805,13 @@ void WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
if (layout.GetObjects().HasObjectNamed(oldName))
continue;
ObjectOrGroupRenamedInScene(project, layout, oldName, newName,
ObjectOrGroupRenamedInLayout(project, layout, oldName, newName,
isObjectGroup);
}
}
void WholeProjectRefactorer::GlobalObjectRemoved(gd::Project &project,
const gd::String &objectName) {
void WholeProjectRefactorer::GlobalObjectRemoved(
gd::Project &project, const gd::String &objectName) {
auto &globalGroups = project.GetObjects().GetObjectGroups();
for (std::size_t g = 0; g < globalGroups.size(); ++g) {
globalGroups[g].RemoveObject(objectName);
@@ -1975,7 +1822,7 @@ void WholeProjectRefactorer::GlobalObjectRemoved(gd::Project &project,
if (layout.GetObjects().HasObjectNamed(objectName))
continue;
ObjectRemovedInScene(project, layout, objectName);
ObjectRemovedInLayout(project, layout, objectName);
}
}
@@ -1986,13 +1833,13 @@ void WholeProjectRefactorer::BehaviorsAddedToGlobalObject(
if (layout.GetObjects().HasObjectNamed(objectName))
continue;
BehaviorsAddedToObjectInScene(project, layout, objectName);
BehaviorsAddedToObjectInLayout(project, layout, objectName);
}
}
void WholeProjectRefactorer::RemoveLayerInScene(gd::Project &project,
gd::Layout &scene,
const gd::String &layerName) {
gd::Layout &scene,
const gd::String &layerName) {
if (layerName.empty())
return;
@@ -2006,14 +1853,15 @@ void WholeProjectRefactorer::RemoveLayerInScene(gd::Project &project,
}
}
void WholeProjectRefactorer::MergeLayersInScene(
gd::Project &project, gd::Layout &scene, const gd::String &originLayerName,
const gd::String &targetLayerName) {
void WholeProjectRefactorer::MergeLayersInScene(gd::Project &project,
gd::Layout &scene,
const gd::String &originLayerName,
const gd::String &targetLayerName) {
if (originLayerName == targetLayerName || originLayerName.empty())
return;
scene.GetInitialInstances().MoveInstancesToLayer(originLayerName,
targetLayerName);
targetLayerName);
std::vector<gd::String> externalLayoutsNames =
GetAssociatedExternalLayouts(project, scene);

View File

@@ -19,7 +19,6 @@ class Project;
class Layout;
class Layer;
class Object;
class ObjectGroup;
class String;
class EventsFunctionsExtension;
class EventsFunction;
@@ -59,8 +58,6 @@ struct VariablesChangeset : VariablesRenamingChangesetNode {
* would take more time than checking the instruction type is rightly set.
*/
std::unordered_set<gd::String> typeChangedVariableNames;
std::unordered_set<gd::String> valueChangedVariableNames;
std::unordered_set<gd::String> addedVariableNames;
bool HasRemovedVariables() { return !removedVariableNames.empty(); }
@@ -71,7 +68,7 @@ struct VariablesChangeset : VariablesRenamingChangesetNode {
* \brief Tool functions to do refactoring on the whole project after
* changes like deletion or renaming of an object.
*
* \TODO Ideally ObjectOrGroupRenamedInScene, ObjectRemovedInScene,
* \TODO Ideally ObjectOrGroupRenamedInLayout, ObjectRemovedInLayout,
* GlobalObjectOrGroupRenamed, GlobalObjectRemoved would be implemented
* using ExposeProjectEvents.
*/
@@ -94,18 +91,6 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::VariablesChangeset &changeset,
const gd::SerializerElement &originalSerializedVariables);
/**
* \brief Refactor the project according to the changes (renaming or deletion)
* made to variables of a group.
*/
static void ApplyRefactoringForGroupVariablesContainer(
gd::Project &project, gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer,
const gd::VariablesContainer &groupVariablesContainer,
const gd::ObjectGroup &objectGroup,
const gd::VariablesChangeset &changeset,
const gd::SerializerElement &originalSerializedVariables);
/**
* \brief Refactor the project **before** an events function extension is
* renamed.
@@ -354,103 +339,52 @@ class GD_CORE_API WholeProjectRefactorer {
static void RenameExternalEvents(gd::Project &project,
const gd::String &oldName,
const gd::String &newName);
/**
* \brief Refactor the project after a layer is renamed.
*/
static void RenameLayerInScene(gd::Project &project, gd::Layout &scene,
const gd::String &oldName,
static void RenameLayer(gd::Project &project, gd::Layout &layout,
const gd::String &oldName, const gd::String &newName);
/**
* \brief Refactor the project after a layer effect is renamed.
*/
static void RenameLayerEffect(gd::Project &project, gd::Layout &layout,
gd::Layer &layer, const gd::String &oldName,
const gd::String &newName);
/**
* \brief Refactor the project after an object animation is renamed.
*/
static void RenameObjectAnimation(gd::Project &project, gd::Layout &layout,
gd::Object &object,
const gd::String &oldName,
const gd::String &newName);
/**
* \brief Refactor the project after an object point is renamed.
*/
static void RenameObjectPoint(gd::Project &project, gd::Layout &layout,
gd::Object &object, const gd::String &oldName,
const gd::String &newName);
/**
* \brief Refactor the project after an object effect is renamed.
*/
static void RenameObjectEffect(gd::Project &project, gd::Layout &layout,
gd::Object &object, const gd::String &oldName,
const gd::String &newName);
/**
* \brief Refactor the project after a layer is renamed.
*/
static void RenameLayerInEventsBasedObject(
gd::Project &project,
gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedObject &eventsBasedObject, const gd::String &oldName,
const gd::String &newName);
/**
* \brief Refactor the project after a layer effect is renamed.
*/
static void RenameLayerEffectInScene(gd::Project &project, gd::Layout &scene,
gd::Layer &layer,
const gd::String &oldName,
const gd::String &newName);
/**
* \brief Refactor the project after a layer effect is renamed.
*/
static void RenameLayerEffectInEventsBasedObject(
gd::Project &project,
gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedObject &eventsBasedObject, gd::Layer &layer,
const gd::String &oldName, const gd::String &newName);
/**
* \brief Refactor the project after an object animation is renamed.
*/
static void RenameObjectAnimationInScene(gd::Project &project,
gd::Layout &scene,
gd::Object &object,
const gd::String &oldName,
const gd::String &newName);
/**
* \brief Refactor the project after an object animation is renamed.
*/
static void RenameObjectAnimationInEventsBasedObject(
gd::Project &project,
gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedObject &eventsBasedObject, gd::Object &object,
const gd::String &oldName, const gd::String &newName);
/**
* \brief Refactor the project after an object point is renamed.
*/
static void RenameObjectPointInScene(gd::Project &project, gd::Layout &scene,
gd::Object &object,
const gd::String &oldName,
const gd::String &newName);
/**
* \brief Refactor the project after an object point is renamed.
*/
static void RenameObjectPointInEventsBasedObject(
gd::Project &project,
gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedObject &eventsBasedObject, gd::Object &object,
const gd::String &oldName, const gd::String &newName);
/**
* \brief Refactor the project after an object effect is renamed.
*/
static void RenameObjectEffectInScene(gd::Project &project, gd::Layout &scene,
gd::Object &object,
const gd::String &oldName,
const gd::String &newName);
/**
* \brief Refactor the project after an object effect is renamed.
*/
static void RenameObjectEffectInEventsBasedObject(
gd::Project &project,
gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedObject &eventsBasedObject, gd::Object &object,
const gd::String &oldName, const gd::String &newName);
/**
* \brief Refactor the project after an object is renamed in a layout
*
* This will update the layout, all external layouts associated with it
* and all external events associated with it.
*/
static void ObjectOrGroupRenamedInScene(gd::Project &project,
gd::Layout &scene,
const gd::String &oldName,
const gd::String &newName,
bool isObjectGroup);
static void ObjectOrGroupRenamedInLayout(gd::Project& project,
gd::Layout& layout,
const gd::String& oldName,
const gd::String& newName,
bool isObjectGroup);
/**
* \brief Refactor the project after an object is removed in a layout
@@ -458,8 +392,9 @@ 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 ObjectRemovedInScene(gd::Project &project, gd::Layout &scene,
const gd::String &objectName);
static void ObjectRemovedInLayout(gd::Project& project,
gd::Layout& layout,
const gd::String& objectName);
/**
* \brief Refactor the project after behaviors are added to an object in a
@@ -469,9 +404,9 @@ class GD_CORE_API WholeProjectRefactorer {
* The refactor is actually applied to all objects because it allow to handle
* groups.
*/
static void BehaviorsAddedToObjectInScene(gd::Project &project,
gd::Layout &layout,
const gd::String &objectName);
static void BehaviorsAddedToObjectInLayout(gd::Project &project,
gd::Layout &layout,
const gd::String &objectName);
/**
* \brief Refactor the project after an object is removed in an events-based

View File

@@ -9,7 +9,6 @@
#include <map>
#include <memory>
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Project/QuickCustomization.h"
#include "GDCore/String.h"
namespace gd {
@@ -32,10 +31,10 @@ namespace gd {
*/
class GD_CORE_API BehaviorConfigurationContainer {
public:
BehaviorConfigurationContainer() : folded(false), quickCustomizationVisibility(QuickCustomization::Visibility::Default){};
BehaviorConfigurationContainer() : folded(false){};
BehaviorConfigurationContainer(const gd::String& name_,
const gd::String& type_)
: name(name_), type(type_), folded(false), quickCustomizationVisibility(QuickCustomization::Visibility::Default){};
: name(name_), type(type_), folded(false){};
virtual ~BehaviorConfigurationContainer();
virtual BehaviorConfigurationContainer* Clone() const { return new BehaviorConfigurationContainer(*this); }
@@ -115,13 +114,6 @@ class GD_CORE_API BehaviorConfigurationContainer {
*/
bool IsFolded() const { return folded; }
void SetQuickCustomizationVisibility(QuickCustomization::Visibility visibility) {
quickCustomizationVisibility = visibility;
}
QuickCustomization::Visibility GetQuickCustomizationVisibility() const {
return quickCustomizationVisibility;
}
protected:
/**
@@ -168,7 +160,6 @@ protected:
gd::SerializerElement content; // Storage for the behavior properties
bool folded;
QuickCustomization::Visibility quickCustomizationVisibility;
};
} // namespace gd

View File

@@ -26,7 +26,7 @@ void CustomConfigurationHelper::InitializeContent(
if (propertyType == "String" || propertyType == "Choice" ||
propertyType == "Color" || propertyType == "Behavior" ||
propertyType == "Resource") {
propertyType == "resource") {
element.SetStringValue(property->GetValue());
} else if (propertyType == "Number") {
element.SetDoubleValue(property->GetValue().To<double>());
@@ -39,21 +39,21 @@ void CustomConfigurationHelper::InitializeContent(
std::map<gd::String, gd::PropertyDescriptor> CustomConfigurationHelper::GetProperties(
const gd::PropertiesContainer &properties,
const gd::SerializerElement &configurationContent) {
auto objectProperties = std::map<gd::String, gd::PropertyDescriptor>();
auto behaviorProperties = std::map<gd::String, gd::PropertyDescriptor>();
for (auto &property : properties.GetInternalVector()) {
const auto &propertyName = property->GetName();
const auto &propertyType = property->GetType();
// Copy the property
objectProperties[propertyName] = *property;
behaviorProperties[propertyName] = *property;
auto &newProperty = objectProperties[propertyName];
auto &newProperty = behaviorProperties[propertyName];
if (configurationContent.HasChild(propertyName)) {
if (propertyType == "String" || propertyType == "Choice" ||
propertyType == "Color" || propertyType == "Behavior" ||
propertyType == "Resource") {
propertyType == "resource") {
newProperty.SetValue(
configurationContent.GetChild(propertyName).GetStringValue());
} else if (propertyType == "Number") {
@@ -71,7 +71,7 @@ std::map<gd::String, gd::PropertyDescriptor> CustomConfigurationHelper::GetPrope
}
}
return objectProperties;
return behaviorProperties;
}
bool CustomConfigurationHelper::UpdateProperty(
@@ -89,7 +89,7 @@ bool CustomConfigurationHelper::UpdateProperty(
if (propertyType == "String" || propertyType == "Choice" ||
propertyType == "Color" || propertyType == "Behavior" ||
propertyType == "Resource") {
propertyType == "resource") {
element.SetStringValue(newValue);
} else if (propertyType == "Number") {
element.SetDoubleValue(newValue.To<double>());

View File

@@ -21,9 +21,6 @@ void CustomObjectConfiguration::Init(const gd::CustomObjectConfiguration& object
project = objectConfiguration.project;
objectContent = objectConfiguration.objectContent;
animations = objectConfiguration.animations;
isMarkedAsOverridingEventsBasedObjectChildrenConfiguration =
objectConfiguration
.isMarkedAsOverridingEventsBasedObjectChildrenConfiguration;
// There is no default copy for a map of unique_ptr like childObjectConfigurations.
childObjectConfigurations.clear();
@@ -45,26 +42,6 @@ const gd::EventsBasedObject* CustomObjectConfiguration::GetEventsBasedObject() c
return &project->GetEventsBasedObject(GetType());
}
bool CustomObjectConfiguration::
IsForcedToOverrideEventsBasedObjectChildrenConfiguration() const {
const auto *eventsBasedObject = GetEventsBasedObject();
if (!eventsBasedObject) {
// True is safer because nothing will be lost when serializing.
return true;
}
return eventsBasedObject->GetInitialInstances().GetInstancesCount() == 0;
}
bool CustomObjectConfiguration::
IsOverridingEventsBasedObjectChildrenConfiguration() const {
return isMarkedAsOverridingEventsBasedObjectChildrenConfiguration ||
IsForcedToOverrideEventsBasedObjectChildrenConfiguration();
}
void CustomObjectConfiguration::ClearChildrenConfiguration() {
childObjectConfigurations.clear();
}
gd::ObjectConfiguration &CustomObjectConfiguration::GetChildObjectConfiguration(const gd::String &objectName) {
const auto *eventsBasedObject = GetEventsBasedObject();
if (!eventsBasedObject) {
@@ -78,18 +55,6 @@ gd::ObjectConfiguration &CustomObjectConfiguration::GetChildObjectConfiguration(
}
auto &childObject = eventsBasedObject->GetObjects().GetObject(objectName);
if (!IsOverridingEventsBasedObjectChildrenConfiguration()) {
// It should be fine because the editor doesn't allow to edit values when
// the default values from the events-based object is used.
//
// Resource refactor operations may modify it but they will do the same
// thing on the custom object as on the event-based object children so it
// shouldn't have any side effect.
return const_cast<gd::ObjectConfiguration &>(
childObject.GetConfiguration());
}
auto configurationPosition = childObjectConfigurations.find(objectName);
if (configurationPosition == childObjectConfigurations.end()) {
childObjectConfigurations.insert(std::make_pair(
@@ -102,7 +67,7 @@ gd::ObjectConfiguration &CustomObjectConfiguration::GetChildObjectConfiguration(
auto &configuration = pair.second;
return *configuration;
}
}
}
std::map<gd::String, gd::PropertyDescriptor> CustomObjectConfiguration::GetProperties() const {
auto objectProperties = std::map<gd::String, gd::PropertyDescriptor>();
@@ -163,14 +128,26 @@ void CustomObjectConfiguration::DoSerializeTo(SerializerElement& element) const
animations.SerializeTo(animatableElement);
}
if (IsOverridingEventsBasedObjectChildrenConfiguration()) {
auto &childrenContentElement = element.AddChild("childrenContent");
for (auto &pair : childObjectConfigurations) {
auto &childName = pair.first;
auto &childConfiguration = pair.second;
auto &childElement = childrenContentElement.AddChild(childName);
childConfiguration->SerializeTo(childElement);
}
auto &childrenContentElement = element.AddChild("childrenContent");
for (auto &pair : childObjectConfigurations) {
auto &childName = pair.first;
auto &childConfiguration = pair.second;
auto &childElement = childrenContentElement.AddChild(childName);
childConfiguration->SerializeTo(childElement);
}
const auto *eventsBasedObject = GetEventsBasedObject();
if (eventsBasedObject) {
eventsBasedObject->GetInitialInstances().SerializeTo(
element.AddChild("instances"));
eventsBasedObject->GetLayers().SerializeLayersTo(
element.AddChild("layers"));
element.SetIntAttribute("areaMinX", eventsBasedObject->GetAreaMinX());
element.SetIntAttribute("areaMinY", eventsBasedObject->GetAreaMinY());
element.SetIntAttribute("areaMinZ", eventsBasedObject->GetAreaMinZ());
element.SetIntAttribute("areaMaxX", eventsBasedObject->GetAreaMaxX());
element.SetIntAttribute("areaMaxY", eventsBasedObject->GetAreaMaxY());
element.SetIntAttribute("areaMaxZ", eventsBasedObject->GetAreaMaxZ());
}
}
void CustomObjectConfiguration::DoUnserializeFrom(Project& project,
@@ -182,16 +159,12 @@ void CustomObjectConfiguration::DoUnserializeFrom(Project& project,
animations.UnserializeFrom(animatableElement);
}
isMarkedAsOverridingEventsBasedObjectChildrenConfiguration =
element.HasChild("childrenContent");
if (isMarkedAsOverridingEventsBasedObjectChildrenConfiguration) {
auto &childrenContentElement = element.GetChild("childrenContent");
for (auto &pair : childrenContentElement.GetAllChildren()) {
auto &childName = pair.first;
auto &childElement = pair.second;
auto &childConfiguration = GetChildObjectConfiguration(childName);
childConfiguration.UnserializeFrom(project, *childElement);
}
auto &childrenContentElement = element.GetChild("childrenContent");
for (auto &pair : childrenContentElement.GetAllChildren()) {
auto &childName = pair.first;
auto &childElement = pair.second;
auto &childConfiguration = GetChildObjectConfiguration(childName);
childConfiguration.UnserializeFrom(project, *childElement);
}
}
@@ -251,20 +224,6 @@ void CustomObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker& wor
}
}
std::size_t CustomObjectConfiguration::GetAnimationsCount() const {
return animations.GetAnimationsCount();
}
const gd::String &
CustomObjectConfiguration::GetAnimationName(size_t index) const {
return animations.GetAnimation(index).GetName();
}
bool CustomObjectConfiguration::HasAnimationNamed(
const gd::String &name) const {
return animations.HasAnimationNamed(name);
}
const SpriteAnimationList& CustomObjectConfiguration::GetAnimations() const {
return animations;
}

View File

@@ -30,7 +30,7 @@ namespace gd {
class CustomObjectConfiguration : public gd::ObjectConfiguration {
public:
CustomObjectConfiguration(const Project& project_, const String& type_)
: project(&project_), isMarkedAsOverridingEventsBasedObjectChildrenConfiguration(false) {
: project(&project_) {
SetType(type_);
}
std::unique_ptr<gd::ObjectConfiguration> Clone() const override;
@@ -65,28 +65,7 @@ class CustomObjectConfiguration : public gd::ObjectConfiguration {
void ExposeResources(gd::ArbitraryResourceWorker& worker) override;
bool IsForcedToOverrideEventsBasedObjectChildrenConfiguration() const;
bool IsMarkedAsOverridingEventsBasedObjectChildrenConfiguration() const {
return isMarkedAsOverridingEventsBasedObjectChildrenConfiguration;
}
void SetMarkedAsOverridingEventsBasedObjectChildrenConfiguration(
bool isOverridingEventsBasedObjectChildrenConfiguration_) {
isMarkedAsOverridingEventsBasedObjectChildrenConfiguration =
isOverridingEventsBasedObjectChildrenConfiguration_;
}
void ClearChildrenConfiguration();
gd::ObjectConfiguration &
GetChildObjectConfiguration(const gd::String &objectName);
std::size_t GetAnimationsCount() const override;
const gd::String &GetAnimationName(size_t index) const override;
bool HasAnimationNamed(const gd::String &animationName) const override;
gd::ObjectConfiguration &GetChildObjectConfiguration(const gd::String& objectName);
/**
* \brief Return the animation configuration for Animatable custom objects.
@@ -105,14 +84,10 @@ protected:
private:
const gd::EventsBasedObject* GetEventsBasedObject() const;
bool IsOverridingEventsBasedObjectChildrenConfiguration() const;
const Project* project; ///< The project is used to get the
///< EventBasedObject from the fullType.
gd::SerializerElement objectContent;
bool isMarkedAsOverridingEventsBasedObjectChildrenConfiguration;
mutable std::map<gd::String, std::unique_ptr<gd::ObjectConfiguration>> childObjectConfigurations;
std::map<gd::String, std::unique_ptr<gd::ObjectConfiguration>> childObjectConfigurations;
static gd::ObjectConfiguration badObjectConfiguration;

View File

@@ -4,7 +4,6 @@
* reserved. This project is released under the MIT License.
*/
#include "EventsBasedBehavior.h"
#include "EventsFunctionsContainer.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/MakeUnique.h"
@@ -13,10 +12,9 @@ namespace gd {
EventsBasedBehavior::EventsBasedBehavior()
: AbstractEventsBasedEntity(
"MyBehavior", gd::EventsFunctionsContainer::FunctionOwner::Behavior),
sharedPropertyDescriptors(
gd::EventsFunctionsContainer::FunctionOwner::Behavior),
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {}
"MyBehavior",
gd::EventsFunctionsContainer::FunctionOwner::Behavior),
sharedPropertyDescriptors(gd::EventsFunctionsContainer::FunctionOwner::Behavior) {}
void EventsBasedBehavior::SerializeTo(SerializerElement& element) const {
AbstractEventsBasedEntity::SerializeTo(element);
@@ -26,13 +24,6 @@ void EventsBasedBehavior::SerializeTo(SerializerElement& element) const {
}
sharedPropertyDescriptors.SerializeElementsTo(
"propertyDescriptor", element.AddChild("sharedPropertyDescriptors"));
if (quickCustomizationVisibility != QuickCustomization::Visibility::Default) {
element.SetStringAttribute(
"quickCustomizationVisibility",
quickCustomizationVisibility == QuickCustomization::Visibility::Visible
? "visible"
: "hidden");
}
}
void EventsBasedBehavior::UnserializeFrom(gd::Project& project,
@@ -42,14 +33,6 @@ void EventsBasedBehavior::UnserializeFrom(gd::Project& project,
isPrivate = element.GetBoolAttribute("private");
sharedPropertyDescriptors.UnserializeElementsFrom(
"propertyDescriptor", element.GetChild("sharedPropertyDescriptors"));
if (element.HasChild("quickCustomizationVisibility")) {
quickCustomizationVisibility =
element.GetStringAttribute("quickCustomizationVisibility") == "visible"
? QuickCustomization::Visibility::Visible
: QuickCustomization::Visibility::Hidden;
} else {
quickCustomizationVisibility = QuickCustomization::Visibility::Default;
}
}
} // namespace gd

View File

@@ -11,7 +11,6 @@
#include "GDCore/Project/NamedPropertyDescriptor.h"
#include "GDCore/Project/PropertiesContainer.h"
#include "GDCore/Project/EventsFunctionsContainer.h"
#include "GDCore/Project/QuickCustomization.h"
#include "GDCore/String.h"
namespace gd {
class SerializerElement;
@@ -89,15 +88,6 @@ class GD_CORE_API EventsBasedBehavior: public AbstractEventsBasedEntity {
return *this;
}
QuickCustomization::Visibility GetQuickCustomizationVisibility() const {
return quickCustomizationVisibility;
}
EventsBasedBehavior& SetQuickCustomizationVisibility(QuickCustomization::Visibility visibility) {
quickCustomizationVisibility = visibility;
return *this;
}
/**
* \brief Return a reference to the list of shared properties.
*/
@@ -151,7 +141,6 @@ class GD_CORE_API EventsBasedBehavior: public AbstractEventsBasedEntity {
gd::String objectType;
bool isPrivate = false;
gd::PropertiesContainer sharedPropertyDescriptors;
QuickCustomization::Visibility quickCustomizationVisibility;
};
} // namespace gd

View File

@@ -16,7 +16,6 @@ EventsBasedObject::EventsBasedObject()
isRenderedIn3D(false),
isAnimatable(false),
isTextContainer(false),
isInnerAreaFollowingParentSize(false),
areaMinX(0),
areaMinY(0),
areaMinZ(0),
@@ -38,9 +37,6 @@ void EventsBasedObject::SerializeTo(SerializerElement& element) const {
if (isTextContainer) {
element.SetBoolAttribute("isTextContainer", true);
}
if (isInnerAreaFollowingParentSize) {
element.SetBoolAttribute("isInnerAreaFollowingParentSize", true);
}
element.SetIntAttribute("areaMinX", areaMinX);
element.SetIntAttribute("areaMinY", areaMinY);
element.SetIntAttribute("areaMinZ", areaMinZ);
@@ -63,8 +59,6 @@ void EventsBasedObject::UnserializeFrom(gd::Project& project,
isRenderedIn3D = element.GetBoolAttribute("is3D", false);
isAnimatable = element.GetBoolAttribute("isAnimatable", false);
isTextContainer = element.GetBoolAttribute("isTextContainer", false);
isInnerAreaFollowingParentSize =
element.GetBoolAttribute("isInnerAreaFollowingParentSize", false);
areaMinX = element.GetIntAttribute("areaMinX", 0);
areaMinY = element.GetIntAttribute("areaMinY", 0);
areaMinZ = element.GetIntAttribute("areaMinZ", 0);

View File

@@ -101,35 +101,11 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
/**
* \brief Declare a TextContainer capability.
*/
EventsBasedObject &MarkAsTextContainer(bool isTextContainer_) {
EventsBasedObject& MarkAsTextContainer(bool isTextContainer_) {
isTextContainer = isTextContainer_;
return *this;
}
/**
* \brief Declare that the parent scale will always be 1 and children will
* adapt there size. This is removing the ScalableCapability.
*/
EventsBasedObject &
MarkAsInnerAreaExpandingWithParent(bool isInnerAreaExpandingWithParent_) {
isInnerAreaFollowingParentSize = isInnerAreaExpandingWithParent_;
return *this;
}
/**
* \brief Return true if objects handle size changes on their own and
* don't have the ScalableCapability.
*
* When the parent dimensions change:
* - if `false`, the object is stretch proportionally while children local
* positions stay the same.
* - if `true`, the children local positions need to be adapted by events
* to follow their parent size.
*/
bool IsInnerAreaFollowingParentSize() const {
return isInnerAreaFollowingParentSize;
}
/**
* \brief Return true if the object needs a TextContainer capability.
*/
@@ -303,7 +279,6 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
bool isRenderedIn3D;
bool isAnimatable;
bool isTextContainer;
bool isInnerAreaFollowingParentSize;
gd::InitialInstancesContainer initialInstances;
gd::LayersContainer layers;
gd::ObjectsContainer objectsContainer;

View File

@@ -16,41 +16,41 @@ EventsFunction::EventsFunction() : functionType(Action) {
expressionType.SetName("expression");
}
const gd::ParameterMetadataContainer &EventsFunction::GetParametersForEvents(
const gd::EventsFunctionsContainer &functionsContainer) const {
const std::vector<gd::ParameterMetadata>& EventsFunction::GetParametersForEvents(
const gd::EventsFunctionsContainer& functionsContainer) const {
if (functionType != FunctionType::ActionWithOperator) {
// For most function types, the parameters are specified in the function.
return parameters;
}
// For ActionWithOperator, the parameters are auto generated.
actionWithOperationParameters.ClearParameters();
actionWithOperationParameters.clear();
if (!functionsContainer.HasEventsFunctionNamed(getterName)) {
return actionWithOperationParameters;
}
const auto &expression = functionsContainer.GetEventsFunction(getterName);
const auto &expressionParameters = expression.parameters;
const auto& expression = functionsContainer.GetEventsFunction(getterName);
const auto& expressionParameters = expression.parameters;
const auto functionsSource = functionsContainer.GetOwner();
const int expressionValueParameterIndex =
functionsSource == gd::EventsFunctionsContainer::FunctionOwner::Behavior
? 2
: functionsSource == gd::EventsFunctionsContainer::FunctionOwner::Object
? 1
: 0;
for (size_t i = 0; i < expressionValueParameterIndex &&
i < expressionParameters.GetParametersCount();
i++) {
actionWithOperationParameters.AddParameter(
expressionParameters.GetParameter(i));
functionsSource == gd::EventsFunctionsContainer::FunctionOwner::Behavior ?
2 :
functionsSource == gd::EventsFunctionsContainer::FunctionOwner::Object ?
1 :
0;
for (size_t i = 0;
i < expressionValueParameterIndex && i < expressionParameters.size();
i++)
{
actionWithOperationParameters.push_back(expressionParameters[i]);
}
gd::ParameterMetadata parameterMetadata;
parameterMetadata.SetName("Value").SetValueTypeMetadata(
expression.expressionType);
actionWithOperationParameters.AddParameter(parameterMetadata);
parameterMetadata.SetName("Value").SetValueTypeMetadata(expression.expressionType);
actionWithOperationParameters.push_back(parameterMetadata);
for (size_t i = expressionValueParameterIndex;
i < expressionParameters.GetParametersCount(); i++) {
actionWithOperationParameters.AddParameter(
expressionParameters.GetParameter(i));
i < expressionParameters.size();
i++)
{
actionWithOperationParameters.push_back(expressionParameters[i]);
}
return actionWithOperationParameters;
@@ -101,7 +101,10 @@ void EventsFunction::SerializeTo(SerializerElement& element) const {
expressionType.SerializeTo(element.AddChild("expressionType"));
}
gd::SerializerElement& parametersElement = element.AddChild("parameters");
parameters.SerializeParametersTo(parametersElement);
parametersElement.ConsiderAsArrayOf("parameter");
for (const auto& parameter : parameters) {
parameter.SerializeTo(parametersElement.AddChild("parameter"));
}
objectGroups.SerializeTo(element.AddChild("objectGroups"));
}
@@ -143,9 +146,15 @@ void EventsFunction::UnserializeFrom(gd::Project& project,
else
functionType = Action;
const gd::SerializerElement &parametersElement =
const gd::SerializerElement& parametersElement =
element.GetChild("parameters");
parameters.UnserializeParametersFrom(parametersElement);
parameters.clear();
parametersElement.ConsiderAsArrayOf("parameter");
for (std::size_t i = 0; i < parametersElement.GetChildrenCount(); ++i) {
ParameterMetadata parameter;
parameter.UnserializeFrom(parametersElement.GetChild(i));
parameters.push_back(parameter);
}
objectGroups.UnserializeFrom(element.GetChild("objectGroups"));
}

View File

@@ -3,13 +3,14 @@
* 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_EVENTSFUNCTION_H
#define GDCORE_EVENTSFUNCTION_H
#include <vector>
#include "GDCore/Events/EventsList.h"
#include "GDCore/Project/ObjectGroupsContainer.h"
#include "GDCore/Project/ParameterMetadataContainer.h"
#include "GDCore/String.h"
#include "GDCore/Extensions/Metadata/ValueTypeMetadata.h"
// TODO: In theory (for separation of concerns between Project and
@@ -240,7 +241,7 @@ class GD_CORE_API EventsFunction {
* to the generated function, like "runtimeScene" and "eventsFunctionContext".
* This should be transparent to the user.
*/
const gd::ParameterMetadataContainer& GetParametersForEvents(
const std::vector<gd::ParameterMetadata>& GetParametersForEvents(
const gd::EventsFunctionsContainer& functionsContainer) const;
/**
@@ -253,14 +254,14 @@ class GD_CORE_API EventsFunction {
* to the generated function, like "runtimeScene" and "eventsFunctionContext".
* This should be transparent to the user.
*/
const ParameterMetadataContainer& GetParameters() const {
const std::vector<gd::ParameterMetadata>& GetParameters() const {
return parameters;
};
/**
* \brief Return the parameters.
*/
ParameterMetadataContainer& GetParameters() { return parameters; };
std::vector<gd::ParameterMetadata>& GetParameters() { return parameters; };
/**
* \brief Return a reference to the object groups that can be used in the
@@ -299,11 +300,14 @@ class GD_CORE_API EventsFunction {
gd::ValueTypeMetadata expressionType;
gd::EventsList events;
FunctionType functionType;
ParameterMetadataContainer parameters;
mutable gd::ParameterMetadataContainer actionWithOperationParameters;
std::vector<gd::ParameterMetadata> parameters;
mutable std::vector<gd::ParameterMetadata> actionWithOperationParameters;
gd::ObjectGroupsContainer objectGroups;
bool isPrivate = false;
bool isAsync = false;
};
} // namespace gd
#endif // GDCORE_EVENTSFUNCTION_H
#endif

View File

@@ -14,7 +14,6 @@
#include "GDCore/Tools/Log.h"
namespace gd {
gd::String ObjectConfiguration::badAnimationName;
ObjectConfiguration::~ObjectConfiguration() {}

View File

@@ -165,36 +165,7 @@ class GD_CORE_API ObjectConfiguration {
void UnserializeFrom(gd::Project& project, const SerializerElement& element);
///@}
/** \name Animations
* Members functions related to object animations
*/
///@{
/**
* \brief Return the number of animations declared in this object
* configuration.
*/
virtual size_t GetAnimationsCount() const {
return 0;
};
/**
* \brief Return the name of an animation declared in this object
* configuration.
*/
virtual const gd::String &GetAnimationName(size_t index) const {
return badAnimationName;
}
/**
* \brief Return true if an animation is declared in this object
* configuration for a given name.
*/
virtual bool HasAnimationNamed(const gd::String &animationName) const {
return false;
}
///@}
protected:
protected:
gd::String type; ///< Which type of object is represented by this
///< configuration.
@@ -210,9 +181,6 @@ protected:
* custom attributes.
*/
virtual void DoSerializeTo(SerializerElement& element) const {};
private:
static gd::String badAnimationName;
};
} // namespace gd

View File

@@ -19,20 +19,13 @@ namespace gd {
ObjectFolderOrObject ObjectFolderOrObject::badObjectFolderOrObject;
ObjectFolderOrObject::ObjectFolderOrObject()
: folderName("__NULL"),
object(nullptr),
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {}
: folderName("__NULL"), object(nullptr) {}
ObjectFolderOrObject::ObjectFolderOrObject(gd::String folderName_,
ObjectFolderOrObject* parent_)
: folderName(folderName_),
parent(parent_),
object(nullptr),
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {}
: folderName(folderName_), parent(parent_), object(nullptr) {}
ObjectFolderOrObject::ObjectFolderOrObject(gd::Object* object_,
ObjectFolderOrObject* parent_)
: object(object_),
parent(parent_),
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {}
: object(object_), parent(parent_) {}
ObjectFolderOrObject::~ObjectFolderOrObject() {}
bool ObjectFolderOrObject::HasObjectNamed(const gd::String& name) {
@@ -73,8 +66,7 @@ ObjectFolderOrObject& ObjectFolderOrObject::GetChildAt(std::size_t index) {
if (index >= children.size()) return badObjectFolderOrObject;
return *children[index];
}
const ObjectFolderOrObject& ObjectFolderOrObject::GetChildAt(
std::size_t index) const {
const ObjectFolderOrObject& ObjectFolderOrObject::GetChildAt(std::size_t index) const {
if (index >= children.size()) return badObjectFolderOrObject;
return *children[index];
}
@@ -214,14 +206,6 @@ void ObjectFolderOrObject::SerializeTo(SerializerElement& element) const {
} else {
element.SetAttribute("objectName", GetObject().GetName());
}
if (quickCustomizationVisibility != QuickCustomization::Visibility::Default) {
element.SetStringAttribute(
"quickCustomizationVisibility",
quickCustomizationVisibility == QuickCustomization::Visibility::Visible
? "visible"
: "hidden");
}
}
void ObjectFolderOrObject::UnserializeFrom(
@@ -259,15 +243,6 @@ void ObjectFolderOrObject::UnserializeFrom(
object = nullptr;
}
}
if (element.HasChild("quickCustomizationVisibility")) {
quickCustomizationVisibility =
element.GetStringAttribute("quickCustomizationVisibility") == "visible"
? QuickCustomization::Visibility::Visible
: QuickCustomization::Visibility::Hidden;
} else {
quickCustomizationVisibility = QuickCustomization::Visibility::Default;
}
};
} // namespace gd

View File

@@ -10,7 +10,6 @@
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
#include "GDCore/Project/QuickCustomization.h"
namespace gd {
class Project;
@@ -167,11 +166,6 @@ class GD_CORE_API ObjectFolderOrObject {
gd::ObjectFolderOrObject& newParentFolder,
std::size_t newPosition);
QuickCustomization::Visibility GetQuickCustomizationVisibility() const { return quickCustomizationVisibility; }
void SetQuickCustomizationVisibility(QuickCustomization::Visibility visibility) {
quickCustomizationVisibility = visibility;
}
/** \name Saving and loading
* Members functions related to saving and loading the objects of the class.
*/
@@ -194,7 +188,6 @@ class GD_CORE_API ObjectFolderOrObject {
gd::ObjectFolderOrObject*
parent; // nullptr if root folder, points to the parent folder otherwise.
QuickCustomization::Visibility quickCustomizationVisibility;
// Representing an object:
gd::Object* object; // nullptr if folderName is set.

View File

@@ -73,15 +73,6 @@ bool ObjectsContainersList::HasObjectNamed(const gd::String& name) const {
return false;
}
const gd::Object* ObjectsContainersList::GetObject(const gd::String& name) const {
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
++it) {
if ((*it)->HasObjectNamed(name)) return &(*it)->GetObject(name);
}
return nullptr;
}
ObjectsContainersList::VariableExistence
ObjectsContainersList::HasObjectOrGroupWithVariableNamed(
const gd::String& objectOrGroupName, const gd::String& variableName) const {
@@ -377,7 +368,7 @@ std::vector<gd::String> ObjectsContainersList::ExpandObjectName(
}
// Ensure that all returned objects actually exists (i.e: if some groups have
// names referring to non existing objects, don't return them).
// names refering to non existing objects, don't return them).
for (std::size_t i = 0; i < realObjects.size();) {
if (!HasObjectNamed(realObjects[i]))
realObjects.erase(realObjects.begin() + i);
@@ -530,72 +521,4 @@ std::vector<gd::String> ObjectsContainersList::GetBehaviorsOfObject(
*objectsContainers[0], *objectsContainers[1], objectName, searchInGroups);
}
std::vector<gd::String> ObjectsContainersList::GetAnimationNamesOfObject(
const gd::String &objectOrGroupName) const {
std::vector<gd::String> animationNames;
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
++it) {
if ((*it)->HasObjectNamed(objectOrGroupName)) {
const auto &objectConfiguration =
(*it)->GetObject(objectOrGroupName).GetConfiguration();
for (size_t index = 0; index < objectConfiguration.GetAnimationsCount();
index++) {
animationNames.push_back(objectConfiguration.GetAnimationName(index));
}
return animationNames;
}
if ((*it)->GetObjectGroups().Has(objectOrGroupName)) {
const auto &objectGroup = (*it)->GetObjectGroups().Get(objectOrGroupName);
const auto &objectNames = objectGroup.GetAllObjectsNames();
std::size_t objectIndex = 0;
bool isFirstObjectFound = false;
for (; objectIndex < objectNames.size() && !isFirstObjectFound;
objectIndex++) {
const gd::String &objectName = objectNames[objectIndex];
if (!HasObjectNamed(objectName)) {
continue;
}
isFirstObjectFound = true;
const auto &objectConfiguration =
GetObject(objectName)->GetConfiguration();
for (size_t index = 0; index < objectConfiguration.GetAnimationsCount();
index++) {
animationNames.push_back(objectConfiguration.GetAnimationName(index));
}
}
for (; objectIndex < objectNames.size(); objectIndex++) {
const gd::String &objectName = objectNames[objectIndex];
if (!HasObjectNamed(objectName)) {
continue;
}
const auto &objectConfiguration =
GetObject(objectName)->GetConfiguration();
for (size_t animationIndex = 0; animationIndex < animationNames.size();
animationIndex++) {
if (!objectConfiguration.HasAnimationNamed(
animationNames[animationIndex])) {
animationNames.erase(animationNames.begin() + animationIndex);
animationIndex--;
}
}
}
return animationNames;
}
}
return animationNames;
}
const gd::ObjectsContainer &
ObjectsContainersList::GetObjectsContainer(std::size_t index) const {
return *objectsContainers[index];
}
std::size_t ObjectsContainersList::GetObjectsContainersCount() const {
return objectsContainers.size();
}
} // namespace gd

View File

@@ -129,17 +129,7 @@ class GD_CORE_API ObjectsContainersList {
const gd::String& objectName, bool searchInGroups = true) const;
/**
* \brief Get the animation names of an object/group.
* \note The animation names of a group are the animation names common to
* every object of the group.
*
* @return The names of animations
*/
std::vector<gd::String>
GetAnimationNamesOfObject(const gd::String &objectOrGroupName) const;
/**
* \brief Return a list containing all objects referred to by the group.
* \brief Return a list containing all objects refered to by the group.
* If an object name is passed, then only this object name is returned.
*
* If \a onlyObjectToSelectIfPresent is set and present in the group(s),
@@ -173,16 +163,6 @@ class GD_CORE_API ObjectsContainersList {
std::function<void(const gd::String& variableName,
const gd::Variable& variable)> fn) const;
/**
* \brief Return a the objects container at position \a index.
*/
const gd::ObjectsContainer &GetObjectsContainer(std::size_t index) const;
/**
* \brief Return the number of objects containers.
*/
std::size_t GetObjectsContainersCount() const;
/** Do not use - should be private but accessible to let Emscripten create a
* temporary. */
ObjectsContainersList(){};
@@ -190,8 +170,6 @@ class GD_CORE_API ObjectsContainersList {
private:
bool HasObjectNamed(const gd::String& name) const;
const gd::Object* GetObject(const gd::String& name) const;
bool HasObjectWithVariableNamed(const gd::String& objectName,
const gd::String& variableName) const;

View File

@@ -1,148 +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/Extensions/Metadata/ParameterMetadata.h"
#include "GDCore/String.h"
#include "GDCore/Tools/SerializableWithNameList.h"
#include <vector>
namespace gd {
class SerializerElement;
}
namespace gd {
/**
* \brief Used as a base class for classes that will own events-backed
* functions.
*
* \see gd::ParameterMetadata
* \ingroup PlatformDefinition
*/
class GD_CORE_API ParameterMetadataContainer
: private SerializableWithNameList<gd::ParameterMetadata> {
public:
ParameterMetadataContainer() {}
/** \name Events Functions management
*/
///@{
/**
* \brief Check if the function with the specified name exists.
*/
bool HasParameterNamed(const gd::String &name) const { return Has(name); }
/**
* \brief Get the function with the specified name.
*
* \warning Trying to access to a not existing function will result in
* undefined behavior.
*/
gd::ParameterMetadata &GetParameter(const gd::String &name) {
return Get(name);
}
/**
* \brief Get the function with the specified name.
*
* \warning Trying to access to a not existing function will result in
* undefined behavior.
*/
const gd::ParameterMetadata &GetParameter(const gd::String &name) const {
return Get(name);
}
/**
* \brief Get the function at the specified index in the list.
*
* \warning Trying to access to a not existing function will result in
* undefined behavior.
*/
gd::ParameterMetadata &GetParameter(std::size_t index) { return Get(index); }
/**
* \brief Get the function at the specified index in the list.
*
* \warning Trying to access to a not existing function will result in
* undefined behavior.
*/
const gd::ParameterMetadata &GetParameter(std::size_t index) const {
return Get(index);
}
/**
* \brief Return the number of functions.
*/
std::size_t GetParametersCount() const { return GetCount(); }
gd::ParameterMetadata &InsertNewParameter(const gd::String &name,
std::size_t position) {
return InsertNew(name, position);
}
gd::ParameterMetadata &InsertParameter(const gd::ParameterMetadata &object,
std::size_t position) {
return Insert(object, position);
}
gd::ParameterMetadata &AddNewParameter(const gd::String &name) {
return InsertNew(name, GetCount());
}
gd::ParameterMetadata &AddParameter(const gd::ParameterMetadata &object) {
return Insert(object, GetCount());
}
void RemoveParameter(const gd::String &name) { return Remove(name); }
void ClearParameters() { return Clear(); }
void MoveParameter(std::size_t oldIndex, std::size_t newIndex) {
return Move(oldIndex, newIndex);
};
std::size_t
GetParameterPosition(const gd::ParameterMetadata &parameterMetadata) {
return GetPosition(parameterMetadata);
};
/**
* \brief Provide a raw access to the vector containing the functions.
*/
const std::vector<std::unique_ptr<gd::ParameterMetadata>> &
GetInternalVector() const {
return elements;
};
/**
* \brief Provide a raw access to the vector containing the functions.
*/
std::vector<std::unique_ptr<gd::ParameterMetadata>> &GetInternalVector() {
return elements;
};
///@}
/** \name Serialization
*/
///@{
/**
* \brief Serialize events functions.
*/
void SerializeParametersTo(SerializerElement &element) const {
return SerializeElementsTo("parameters", element);
};
/**
* \brief Unserialize the events functions.
*/
void UnserializeParametersFrom(const SerializerElement &element) {
return UnserializeElementsFrom("parameters", element);
};
///@}
protected:
/**
* Initialize object using another object. Used by copy-ctor and assign-op.
* Don't forget to update me if members were changed!
*/
void Init(const gd::ParameterMetadataContainer &other) {
return SerializableWithNameList<gd::ParameterMetadata>::Init(other);
};
};
} // namespace gd

View File

@@ -13,7 +13,6 @@ class ObjectsContainersList;
class VariablesContainersList;
class PropertiesContainersList;
class NamedPropertyDescriptor;
class ParameterMetadataContainer;
class BaseEvent;
class EventsFunctionsExtension;
class EventsFunction;
@@ -132,7 +131,7 @@ class ProjectScopedContainers {
}
ProjectScopedContainers &AddParameters(
const ParameterMetadataContainer &parameters) {
const std::vector<gd::ParameterMetadata> &parameters) {
parametersVectorsList.push_back(&parameters);
return *this;
@@ -225,7 +224,7 @@ class ProjectScopedContainers {
return propertiesContainersList;
};
const std::vector<const ParameterMetadataContainer *> &GetParametersVectorsList() const {
const std::vector<const std::vector<gd::ParameterMetadata> *> &GetParametersVectorsList() const {
return parametersVectorsList;
};
@@ -237,7 +236,7 @@ class ProjectScopedContainers {
gd::ObjectsContainersList objectsContainersList;
gd::VariablesContainersList variablesContainersList;
gd::PropertiesContainersList propertiesContainersList;
std::vector<const ParameterMetadataContainer *> parametersVectorsList;
std::vector<const std::vector<gd::ParameterMetadata> *> parametersVectorsList;
};
} // namespace gd

View File

@@ -38,13 +38,6 @@ void PropertyDescriptor::SerializeTo(SerializerElement& element) const {
if (advanced) {
element.AddChild("advanced").SetBoolValue(advanced);
}
if (quickCustomizationVisibility != QuickCustomization::Visibility::Default) {
element.AddChild("quickCustomizationVisibility")
.SetStringValue(quickCustomizationVisibility ==
QuickCustomization::Visibility::Visible
? "visible"
: "hidden");
}
}
void PropertyDescriptor::UnserializeFrom(const SerializerElement& element) {
@@ -74,21 +67,11 @@ void PropertyDescriptor::UnserializeFrom(const SerializerElement& element) {
? element.GetChild("hidden").GetBoolValue()
: false;
deprecated = element.HasChild("deprecated")
? element.GetChild("deprecated").GetBoolValue()
: false;
? element.GetChild("deprecated").GetBoolValue()
: false;
advanced = element.HasChild("advanced")
? element.GetChild("advanced").GetBoolValue()
: false;
if (element.HasChild("quickCustomizationVisibility")) {
quickCustomizationVisibility =
element.GetChild("quickCustomizationVisibility").GetStringValue() ==
"visible"
? QuickCustomization::Visibility::Visible
: QuickCustomization::Visibility::Hidden;
} else {
quickCustomizationVisibility = QuickCustomization::Visibility::Default;
}
? element.GetChild("advanced").GetBoolValue()
: false;
}
void PropertyDescriptor::SerializeValuesTo(SerializerElement& element) const {

View File

@@ -9,7 +9,6 @@
#include "GDCore/String.h"
#include "GDCore/Project/MeasurementUnit.h"
#include "GDCore/Project/QuickCustomization.h"
namespace gd {
class SerializerElement;
@@ -33,16 +32,14 @@ class GD_CORE_API PropertyDescriptor {
PropertyDescriptor(gd::String propertyValue)
: currentValue(propertyValue), type("string"), label(""), hidden(false),
deprecated(false), advanced(false),
measurementUnit(gd::MeasurementUnit::GetUndefined()),
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {}
measurementUnit(gd::MeasurementUnit::GetUndefined()) {}
/**
* \brief Empty constructor creating an empty property to be displayed.
*/
PropertyDescriptor()
: hidden(false), deprecated(false), advanced(false),
measurementUnit(gd::MeasurementUnit::GetUndefined()),
quickCustomizationVisibility(QuickCustomization::Visibility::Default){};
measurementUnit(gd::MeasurementUnit::GetUndefined()){};
/**
* \brief Destructor
@@ -112,7 +109,7 @@ class GD_CORE_API PropertyDescriptor {
extraInformation.push_back(info);
return *this;
}
/**
* \brief Change the unit of measurement of the property value.
*/
@@ -131,7 +128,7 @@ class GD_CORE_API PropertyDescriptor {
const std::vector<gd::String>& GetExtraInfo() const {
return extraInformation;
}
std::vector<gd::String>& GetExtraInfo() {
return extraInformation;
}
@@ -175,13 +172,6 @@ class GD_CORE_API PropertyDescriptor {
*/
bool IsAdvanced() const { return advanced; }
QuickCustomization::Visibility GetQuickCustomizationVisibility() const { return quickCustomizationVisibility; }
PropertyDescriptor& SetQuickCustomizationVisibility(QuickCustomization::Visibility visibility) {
quickCustomizationVisibility = visibility;
return *this;
}
/** \name Serialization
*/
///@{
@@ -222,7 +212,6 @@ class GD_CORE_API PropertyDescriptor {
bool deprecated;
bool advanced;
gd::MeasurementUnit measurementUnit; //< The unit of measurement of the property vale.
QuickCustomization::Visibility quickCustomizationVisibility;
};
} // namespace gd

View File

@@ -1,16 +0,0 @@
#pragma once
namespace gd {
class QuickCustomization {
public:
enum Visibility {
/** Visibility based on the parent or editor heuristics (probably visible). */
Default,
/** Visible in the quick customization editor. */
Visible,
/** Not visible in the quick customization editor. */
Hidden
};
};
} // namespace gd

View File

@@ -30,8 +30,6 @@ gd::String Variable::TypeAsString(Type t) {
return "structure";
case Type::Array:
return "array";
case Type::MixedTypes:
return "mixed";
default:
return "error-type";
}
@@ -48,8 +46,6 @@ Variable::Type Variable::StringAsType(const gd::String& str) {
return Type::Structure;
else if (str == "array")
return Type::Array;
else if (str == "mixed")
return Type::MixedTypes;
// Default to number
return Type::Number;
@@ -60,7 +56,6 @@ bool Variable::IsPrimitive(const Type type) {
}
void Variable::CastTo(const Type newType) {
hasMixedValues = false;
if (newType == Type::Number)
SetValue(GetValue());
else if (newType == Type::String)
@@ -90,9 +85,6 @@ void Variable::CastTo(const Type newType) {
type = Type::Array;
// Free now unused memory
children.clear();
} else if (newType == Type::MixedTypes) {
type = Type::MixedTypes;
hasMixedValues = true;
}
}
@@ -150,7 +142,6 @@ Variable& Variable::GetChild(const gd::String& name) {
if (it != children.end()) return *it->second;
type = Type::Structure;
hasMixedValues = false;
children[name] = std::make_shared<gd::Variable>();
return *children[name];
}
@@ -211,7 +202,6 @@ Variable& Variable::PushNew() {
const size_t count = GetChildrenCount();
auto& variable = GetAtIndex(count);
if (type == Type::Array && count > 0) {
hasMixedValues = false;
const auto childType = GetAtIndex(count - 1).type;
variable.type = childType;
if (childType == Type::Number) {
@@ -234,7 +224,6 @@ void Variable::RemoveAtIndex(const size_t index) {
bool Variable::InsertAtIndex(const gd::Variable& variable, const size_t index) {
if (type != Type::Array) return false;
hasMixedValues = false;
auto newVariable = std::make_shared<gd::Variable>(variable);
if (index < childrenArray.size()) {
childrenArray.insert(childrenArray.begin() + index, newVariable);
@@ -249,7 +238,6 @@ bool Variable::InsertChild(const gd::String& name,
if (type != Type::Structure || HasChild(name)) {
return false;
}
hasMixedValues = false;
children[name] = std::make_shared<gd::Variable>(variable);
return true;
};
@@ -282,9 +270,6 @@ void Variable::SerializeTo(SerializerElement& element) const {
child->SerializeTo(childrenElement.AddChild("variable"));
}
}
if (hasMixedValues) {
element.SetBoolAttribute("hasMixedValues", true);
}
}
void Variable::UnserializeFrom(const SerializerElement& element) {
@@ -328,9 +313,6 @@ void Variable::UnserializeFrom(const SerializerElement& element) {
PushNew().UnserializeFrom(childElement);
}
}
if (element.GetBoolAttribute("hasMixedValues", false)) {
MarkAsMixedValues();
}
}
Variable& Variable::ResetPersistentUuid() {
@@ -402,8 +384,7 @@ Variable::Variable(const Variable& other)
folded(other.folded),
boolVal(other.boolVal),
type(other.type),
persistentUuid(other.persistentUuid),
hasMixedValues(other.hasMixedValues) {
persistentUuid(other.persistentUuid) {
CopyChildren(other);
}
@@ -415,7 +396,6 @@ Variable& Variable::operator=(const Variable& other) {
boolVal = other.boolVal;
type = other.type;
persistentUuid = other.persistentUuid;
hasMixedValues = other.hasMixedValues;
CopyChildren(other);
}
@@ -431,61 +411,4 @@ void Variable::CopyChildren(const gd::Variable& other) {
childrenArray.push_back(std::make_shared<gd::Variable>(*child.get()));
}
}
bool Variable::operator==(const gd::Variable &variable) const {
if (type != variable.type || hasMixedValues || variable.hasMixedValues) {
return false;
}
if (type == Variable::Type::Number) {
return value == variable.value;
}
if (type == Variable::Type::String) {
return str == variable.str;
}
if (type == Variable::Type::Boolean) {
return boolVal == variable.boolVal;
}
if (type == Variable::Type::Structure) {
if (children.size() != variable.children.size()) {
return false;
}
for (auto &pair : children) {
const gd::String &name = pair.first;
const auto &child = pair.second;
auto it = variable.children.find(name);
if (it == variable.children.end()) {
return false;
}
auto &otherChild = it->second;
if (*child != *otherChild) {
return false;
}
}
return true;
}
if (type == Variable::Type::Array) {
if (childrenArray.size() != variable.childrenArray.size()) {
return false;
}
for (int i = 0; i < childrenArray.size(); ++i) {
if (*childrenArray[i] != *variable.childrenArray[i]) {
return false;
}
}
return true;
}
// MixedTypes variables can't equal another variable.
return false;
}
bool Variable::operator!=(const gd::Variable &variable) const {
return !(*this == variable);
}
void Variable::MarkAsMixedValues() {
hasMixedValues = true;
ClearChildren();
}
} // namespace gd

View File

@@ -4,8 +4,8 @@
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef GDCORE_VARIABLE_H
#define GDCORE_VARIABLE_H
#include <cmath>
#include <map>
#include <memory>
@@ -31,8 +31,6 @@ class GD_CORE_API Variable {
static gd::Variable badVariable;
enum Type {
Unknown,
/** Used when objects of a group have different types for a variable. */
MixedTypes,
// Primitive types
String,
@@ -52,7 +50,7 @@ class GD_CORE_API Variable {
/**
* \brief Default constructor creating a variable with 0 as value.
*/
Variable() : value(0), type(Type::Number), hasMixedValues(false) {};
Variable() : value(0), type(Type::Number){};
Variable(const Variable&);
virtual ~Variable(){};
@@ -89,7 +87,6 @@ class GD_CORE_API Variable {
void SetString(const gd::String& newStr) {
str = newStr;
type = Type::String;
hasMixedValues = false;
}
/**
@@ -105,7 +102,6 @@ class GD_CORE_API Variable {
// NaN values are not supported by GDevelop nor the serializer.
if (std::isnan(value)) value = 0.0;
type = Type::Number;
hasMixedValues = false;
}
/**
@@ -119,23 +115,8 @@ class GD_CORE_API Variable {
void SetBool(bool val) {
boolVal = val;
type = Type::Boolean;
hasMixedValues = false;
}
/**
* \brief Return true when objects of a group have different values for a
* variable.
*/
bool HasMixedValues() const {
return hasMixedValues;
}
/**
* \brief Return true when objects of a group have different values for a
* variable.
*/
void MarkAsMixedValues();
// Operators are overloaded to allow accessing to variable using a simple
// int-like semantic.
void operator=(double val) { SetValue(val); };
@@ -187,9 +168,6 @@ class GD_CORE_API Variable {
bool operator==(const bool val) const { return GetBool() == val; };
bool operator!=(const bool val) const { return GetBool() != val; };
bool operator==(const gd::Variable& variable) const;
bool operator!=(const gd::Variable& variable) const;
///@}
/** \name Collection types
@@ -398,7 +376,6 @@ class GD_CORE_API Variable {
mutable gd::String str;
mutable double value;
mutable bool boolVal;
mutable bool hasMixedValues;
mutable std::map<gd::String, std::shared_ptr<Variable>>
children; ///< Children, when the variable is considered as a structure.
mutable std::vector<std::shared_ptr<Variable>>
@@ -415,3 +392,5 @@ class GD_CORE_API Variable {
};
} // namespace gd
#endif // GDCORE_VARIABLE_H

View File

@@ -323,7 +323,6 @@ class GD_CORE_API SerializerElement {
gd::String deprecatedName = "") const;
/**
* \deprecated Use HasChild instead. This should be removed from the codebase.
* \brief Return true if the specified attribute exists.
* \param name The name of the attribute to find.
*/

View File

@@ -1 +0,0 @@
VersionPriv.h

View File

@@ -0,0 +1,8 @@
// Deprecated version number that was used for GDevelop 4, but still
// used to version the project files.
// Might be a good idea to refactor this at some point to make it
// clearer this is used for the versioning of the project files.
#define GD_VERSION_STRING "4.0.99-0-release"
#define GD_VERSION_RC 4,0,99,0-0-release
#define GD_VERSION_RC_STRING "4, 0, 99, 0-0-release\0"
#define GD_DATE_STRING __DATE__

View File

@@ -24,6 +24,15 @@ int VersionWrapper::Revision() {
: 0;
}
gd::String VersionWrapper::FullString() { return GD_VERSION_STRING; }
gd::String VersionWrapper::Date() {
return gd::String(GD_DATE_STRING).substr(4, 2);
}
gd::String VersionWrapper::Month() {
return gd::String(GD_DATE_STRING).substr(0, 3);
}
gd::String VersionWrapper::Year() {
return gd::String(GD_DATE_STRING).substr(7, 4);
}
gd::String VersionWrapper::Status() {
return Revision() == 0 ? "Release" : "Dev";
}

View File

@@ -46,6 +46,21 @@ class GD_CORE_API VersionWrapper {
*/
static gd::String Status();
/**
* \brief Get Year of the release
*/
static gd::String Year();
/**
* \brief Get Month of the release
*/
static gd::String Month();
/**
* \brief Get Day of the release
*/
static gd::String Date();
/**
* \brief Return true if the first version is older
* than the second version.

View File

@@ -527,9 +527,15 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
}
}
SECTION("Parameters (1 level)") {
gd::ParameterMetadataContainer parameters;
parameters.InsertNewParameter("MyParameter1", 0).SetType("number");
parameters.InsertNewParameter("MyParameter2", 1).SetType("string");
std::vector<gd::ParameterMetadata> parameters;
gd::ParameterMetadata param1;
param1.SetName("MyParameter1");
param1.SetType("number");
gd::ParameterMetadata param2;
param2.SetName("MyParameter2");
param2.SetType("string");
parameters.push_back(param1);
parameters.push_back(param2);
auto projectScopedContainersWithParameters = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
projectScopedContainersWithParameters.AddParameters(parameters);
@@ -562,10 +568,19 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
}
}
SECTION("Parameters (1 level, number|string)") {
gd::ParameterMetadataContainer parameters;
parameters.InsertNewParameter("MyNumberParameter", 0).SetType("number");
parameters.InsertNewParameter("MyStringParameter", 1).SetType("string");
parameters.InsertNewParameter("MyBooleanParameter", 2).SetType("yesorno");
std::vector<gd::ParameterMetadata> parameters;
gd::ParameterMetadata param1;
param1.SetName("MyNumberParameter");
param1.SetType("number");
gd::ParameterMetadata param2;
param2.SetName("MyStringParameter");
param2.SetType("string");
gd::ParameterMetadata param3;
param3.SetName("MyBooleanParameter");
param3.SetType("yesorno");
parameters.push_back(param1);
parameters.push_back(param2);
parameters.push_back(param3);
auto projectScopedContainersWithParameters = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
projectScopedContainersWithParameters.AddParameters(parameters);

View File

@@ -55,8 +55,8 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Object or expression completions when type is string") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, string, 3, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
"{ 3, no type, 3, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
"{ 0, string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
"{ 3, no type, 2, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("string", "My", 0, 2).ToString()
};
// clang-format on
@@ -67,8 +67,8 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Object or expression completions when type is number") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, number, 3, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
"{ 3, no type, 3, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
"{ 0, number, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
"{ 3, no type, 2, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("number", "My", 0, 2).ToString()
};
// clang-format on
@@ -79,8 +79,8 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Object or expression completions when type is number|string") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, number|string, 3, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
"{ 3, no type, 3, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
"{ 0, number|string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
"{ 3, no type, 2, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("number|string", "My", 0, 2).ToString()
};
// clang-format on
@@ -94,8 +94,8 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Object or expression completions in a variable name") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, string, 3, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
"{ 3, no type, 3, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
"{ 0, string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
"{ 3, no type, 2, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("string", "My", 0, 2).ToString()
};
// clang-format on
@@ -115,8 +115,8 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Object or expression completions in a variable index") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, number, 3, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
"{ 3, no type, 3, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
"{ 0, number, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
"{ 3, no type, 2, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("number", "My", 0, 2).ToString()
};
// clang-format on
@@ -136,7 +136,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Object when type is an object") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, object, 3, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
"{ 0, object, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
};
// clang-format on
REQUIRE(getCompletionsFor("object", "My", 0) == expectedCompletions);
@@ -149,7 +149,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
// result in different code generation):
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, objectPtr, 3, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
"{ 0, objectPtr, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
};
// clang-format on
REQUIRE(getCompletionsFor("objectPtr", "My", 0) == expectedCompletions);
@@ -204,8 +204,8 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, unknown, 3, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
"{ 3, no type, 3, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
"{ 0, unknown, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
"{ 3, no type, 2, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("unknown", "My", 9, 10).ToString()
};
// clang-format on
@@ -215,7 +215,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Function with a Variable as argument") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 3, no type, 3, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
"{ 3, no type, 2, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
};
// clang-format on
REQUIRE(getCompletionsFor("number",
@@ -225,7 +225,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Object function with a Variable as argument") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 3, no type, 3, no prefix, myObjectVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
"{ 3, no type, 2, no prefix, myObjectVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
};
// clang-format on
REQUIRE(getCompletionsFor("number",
@@ -254,7 +254,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Test with string type") {
// clang-format off
std::vector<gd::String> expectedObjectCompletions{
"{ 0, string, 3, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
"{ 0, string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
};
std::vector<gd::String> expectedBehaviorOrFunctionCompletions{
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("Func", 9, 13, "MyObject").ToString(),
@@ -277,7 +277,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Test with 'number|string' type") {
// clang-format off
std::vector<gd::String> expectedObjectCompletions{
"{ 0, number|string, 3, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
"{ 0, number|string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
};
std::vector<gd::String> expectedBehaviorOrFunctionCompletions{
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("Func", 9, 13, "MyObject").ToString(),
@@ -303,7 +303,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Test 1") {
// clang-format off
std::vector<gd::String> expectedObjectCompletions{
"{ 0, string, 3, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
"{ 0, string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
};
std::vector<gd::String> expectedBehaviorOrFunctionCompletions{
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("Func", 9, 13, "MyObject").ToString(),
@@ -336,7 +336,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Test 1") {
// clang-format off
std::vector<gd::String> expectedObjectCompletions{
"{ 0, string, 3, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
"{ 0, string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
};
std::vector<gd::String> expectedBehaviorCompletions{
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("MyBehavior", 9, 19, "MyObject").ToString()};
@@ -366,7 +366,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Test 2") {
// clang-format off
std::vector<gd::String> expectedObjectCompletions{
"{ 0, string, 3, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
"{ 0, string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
};
std::vector<gd::String> expectedBehaviorCompletions{
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("MyBehavior", 9, 19, "MyObject").ToString()
@@ -396,7 +396,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Test 1") {
// clang-format off
std::vector<gd::String> expectedObjectCompletions{
"{ 0, string, 3, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
"{ 0, string, 2, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
};
std::vector<gd::String> expectedBehaviorCompletions{
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("MyBehavior", 9, 19, "MyObject").ToString()

View File

@@ -1031,10 +1031,25 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
}
}
SECTION("Numbers and texts mismatches ('number|string' type, with a parameter first)") {
gd::ParameterMetadataContainer parameters;
parameters.InsertNewParameter("MyNumberParameter", 0).SetType("number");
parameters.InsertNewParameter("MyStringParameter", 1).SetType("string");
parameters.InsertNewParameter("MyBooleanParameter", 2).SetType("yesorno");
std::vector<gd::ParameterMetadata> parameters;
{
gd::ParameterMetadata param;
param.SetName("MyNumberParameter");
param.SetType("number");
parameters.push_back(param);
}
{
gd::ParameterMetadata param;
param.SetName("MyStringParameter");
param.SetType("string");
parameters.push_back(param);
}
{
gd::ParameterMetadata param;
param.SetName("MyBooleanParameter");
param.SetType("yesorno");
parameters.push_back(param);
}
auto projectScopedContainersWithParameters = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
projectScopedContainersWithParameters.AddParameters(parameters);
@@ -2002,10 +2017,19 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
}
SECTION("Valid parameter") {
gd::ParameterMetadataContainer parameters;
parameters.InsertNewParameter("MyParameter1", 0).SetType("number");
parameters.InsertNewParameter("MyParameter2", 1).SetType("string");
parameters.InsertNewParameter("MyParameter3", 2).SetType("yesorno");
std::vector<gd::ParameterMetadata> parameters;
gd::ParameterMetadata param1;
param1.SetName("MyParameter1");
param1.SetType("number");
gd::ParameterMetadata param2;
param2.SetName("MyParameter2");
param2.SetType("string");
gd::ParameterMetadata param3;
param3.SetName("MyParameter3");
param3.SetType("yesorno");
parameters.push_back(param1);
parameters.push_back(param2);
parameters.push_back(param3);
auto projectScopedContainersWithParameters = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
projectScopedContainersWithParameters.AddParameters(parameters);
@@ -2074,9 +2098,15 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
SECTION("Invalid parameter (wrong type)") {
{
gd::ParameterMetadataContainer parameters;
parameters.InsertNewParameter("MyParameter1", 0).SetType("number");
parameters.InsertNewParameter("MyParameter2", 1).SetType("audioResource");
std::vector<gd::ParameterMetadata> parameters;
gd::ParameterMetadata param1;
param1.SetName("MyParameter1");
param1.SetType("number");
gd::ParameterMetadata param2;
param2.SetName("MyParameter2");
param2.SetType("audioResource");
parameters.push_back(param1);
parameters.push_back(param2);
auto projectScopedContainersWithParameters = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
projectScopedContainersWithParameters.AddParameters(parameters);
@@ -2093,9 +2123,15 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
SECTION("Invalid parameter (non existing name)") {
{
gd::ParameterMetadataContainer parameters;
parameters.InsertNewParameter("MyParameter1", 0).SetType("number");
parameters.InsertNewParameter("MyParameter2", 1).SetType("string");
std::vector<gd::ParameterMetadata> parameters;
gd::ParameterMetadata param1;
param1.SetName("MyParameter1");
param1.SetType("number");
gd::ParameterMetadata param2;
param2.SetName("MyParameter2");
param2.SetType("string");
parameters.push_back(param1);
parameters.push_back(param2);
auto projectScopedContainersWithParameters = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
projectScopedContainersWithParameters.AddParameters(parameters);
@@ -2112,9 +2148,15 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
SECTION("Invalid parameter (unsupported child syntax, 1 level)") {
{
gd::ParameterMetadataContainer parameters;
parameters.InsertNewParameter("MyParameter1", 0).SetType("number");
parameters.InsertNewParameter("MyParameter2", 1).SetType("string");
std::vector<gd::ParameterMetadata> parameters;
gd::ParameterMetadata param1;
param1.SetName("MyParameter1");
param1.SetType("number");
gd::ParameterMetadata param2;
param2.SetName("MyParameter2");
param2.SetType("string");
parameters.push_back(param1);
parameters.push_back(param2);
auto projectScopedContainersWithParameters = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
projectScopedContainersWithParameters.AddParameters(parameters);
@@ -2130,9 +2172,15 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
}
SECTION("Invalid parameter (unsupported child syntax, 2 levels)") {
{
gd::ParameterMetadataContainer parameters;
parameters.InsertNewParameter("MyParameter1", 0).SetType("number");
parameters.InsertNewParameter("MyParameter2", 1).SetType("string");
std::vector<gd::ParameterMetadata> parameters;
gd::ParameterMetadata param1;
param1.SetName("MyParameter1");
param1.SetType("number");
gd::ParameterMetadata param2;
param2.SetName("MyParameter2");
param2.SetType("string");
parameters.push_back(param1);
parameters.push_back(param2);
auto projectScopedContainersWithParameters = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
projectScopedContainersWithParameters.AddParameters(parameters);
@@ -3056,10 +3104,25 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
}
}
SECTION("Valid type inferred from expressions with type 'number|string', with a parameter first") {
gd::ParameterMetadataContainer parameters;
parameters.InsertNewParameter("MyNumberParameter", 0).SetType("number");
parameters.InsertNewParameter("MyStringParameter", 1).SetType("string");
parameters.InsertNewParameter("MyBooleanParameter", 2).SetType("yesorno");
std::vector<gd::ParameterMetadata> parameters;
{
gd::ParameterMetadata param;
param.SetName("MyNumberParameter");
param.SetType("number");
parameters.push_back(param);
}
{
gd::ParameterMetadata param;
param.SetName("MyStringParameter");
param.SetType("string");
parameters.push_back(param);
}
{
gd::ParameterMetadata param;
param.SetName("MyBooleanParameter");
param.SetType("yesorno");
parameters.push_back(param);
}
auto projectScopedContainersWithParameters = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
projectScopedContainersWithParameters.AddParameters(parameters);

136
Core/tests/Layout.cpp Normal file
View File

@@ -0,0 +1,136 @@
/*
* GDevelop Core
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
/**
* @file Tests covering layout content helper methods.
*/
#include "GDCore/Project/Layout.h"
#include "DummyPlatform.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/Project.h"
#include "catch.hpp"
using namespace gd;
TEST_CASE("Layout", "[common]") {
SECTION("Find the type of a behavior in a object") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
object.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(
project.GetObjects(), layout.GetObjects(),
"MyObject", "MyBehavior", true) == "MyExtension::MyBehavior");
}
SECTION("Give an empty type for an object that doesn't have the behavior") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(
project.GetObjects(), layout.GetObjects(),
"MyObject", "MyBehavior", true) == "");
}
SECTION("Find the type of a behavior in a group") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
gd::Object &object2 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject2", 0);
object2.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
auto &group =
layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(
project.GetObjects(), layout.GetObjects(),
"MyGroup", "MyBehavior", true) == "MyExtension::MyBehavior");
}
SECTION(
"Give an empty type for a group with an object missing the behavior") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
gd::Object &object2 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject2", 0);
// object2 doesn't have the behavior.
auto &group =
layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(
project.GetObjects(), layout.GetObjects(),
"MyGroup", "MyBehavior", true) == "");
}
SECTION("Give an empty type for a group with behaviors of same name but "
"different types") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
gd::Object &object2 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject2", 0);
object2.AddNewBehavior(project, "MyExtension::MyOtherBehavior",
"MyBehavior");
auto &group =
layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(
project.GetObjects(), layout.GetObjects(),
"MyGroup", "MyBehavior", true) == "");
}
SECTION("Give an empty type for an empty group") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
auto &group =
layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(
project.GetObjects(), layout.GetObjects(),
"MyGroup", "MyBehavior", true) == "");
}
}

View File

@@ -1,488 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
/**
* @file Tests covering layout content helper methods.
*/
#include "GDCore/Project/ObjectsContainersList.h"
#include "DummyPlatform.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Tools/MakeUnique.h"
#include "catch.hpp"
#include <algorithm>
#include <vector>
using namespace gd;
TEST_CASE("ObjectContainersList (HasObjectOrGroupNamed)", "[common]") {
SECTION("Can check an object exists") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.HasObjectOrGroupNamed("MyObject"));
REQUIRE(!objectsContainersList.HasObjectOrGroupNamed("MyWrongObject"));
}
SECTION("Can check a group exists") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
auto &group = layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.HasObjectOrGroupNamed("MyGroup"));
}
}
TEST_CASE("ObjectContainersList (HasObjectOrGroupWithVariableNamed)", "[common]") {
SECTION("Can check a variable exists in an object") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
object.GetVariables().InsertNew("MyVariable", 0);
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.HasObjectOrGroupWithVariableNamed("MyObject", "MyVariable"));
REQUIRE(!objectsContainersList.HasObjectOrGroupWithVariableNamed("MyObject", "MyWrongVariable"));
}
SECTION("Can check a variable exists in a group") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject1", 0);
object1.GetVariables().InsertNew("MyVariable", 0);
// This variable is only in one of the 2 objects.
object1.GetVariables().InsertNew("MyOtherVariable", 0);
gd::Object &object2 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject2", 0);
object1.GetVariables().InsertNew("MyVariable", 0);
auto &group = layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.HasObjectOrGroupWithVariableNamed("MyGroup", "MyVariable"));
REQUIRE(!objectsContainersList.HasObjectOrGroupWithVariableNamed("MyGroup", "MyWrongVariable"));
}
}
TEST_CASE("ObjectContainersList (GetTypeOfObject)", "[common]") {
SECTION("Find the type of an object") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
object.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.GetTypeOfObject("MyObject") == "MyExtension::Sprite");
}
SECTION("Find the object type of a group") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject1", 0);
gd::Object &object2 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject2", 0);
auto &group = layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.GetTypeOfObject("MyGroup") == "MyExtension::Sprite");
}
SECTION("Give an empty type for groups with mixed object types") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject1", 0);
gd::Object &object2 = layout.GetObjects().InsertNewObject(
project, "FakeObjectWithDefaultBehavior", "MyObject2", 0);
auto &group = layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.GetTypeOfObject("MyGroup") == "");
}
SECTION("Give an empty type for an empty group") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
auto &group = layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.GetTypeOfObject(
"MyGroup") == "");
}
}
TEST_CASE("ObjectContainersList (GetTypeOfBehaviorInObjectOrGroup)",
"[common]") {
SECTION("Find the type of a behavior in an object") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
object.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.GetTypeOfBehaviorInObjectOrGroup(
"MyObject", "MyBehavior", true) == "MyExtension::MyBehavior");
}
SECTION("Give an empty type for an object that doesn't have the behavior") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.GetTypeOfBehaviorInObjectOrGroup(
"MyObject", "MyBehavior", true) == "");
}
SECTION("Find the type of a behavior in a group") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
gd::Object &object2 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject2", 0);
object2.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
auto &group = layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.GetTypeOfBehaviorInObjectOrGroup(
"MyGroup", "MyBehavior", true) == "MyExtension::MyBehavior");
}
SECTION(
"Give an empty type for a group with an object missing the behavior") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
gd::Object &object2 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject2", 0);
// object2 doesn't have the behavior.
auto &group = layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.GetTypeOfBehaviorInObjectOrGroup(
"MyGroup", "MyBehavior", true) == "");
}
SECTION("Give an empty type for a group with behaviors of same name but different types") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
gd::Object &object2 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject2", 0);
object2.AddNewBehavior(project, "MyExtension::MyOtherBehavior",
"MyBehavior");
auto &group = layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.GetTypeOfBehaviorInObjectOrGroup(
"MyGroup", "MyBehavior", true) == "");
}
SECTION("Give an empty type for an empty group") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
auto &group = layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.GetTypeOfBehaviorInObjectOrGroup(
"MyGroup", "MyBehavior", true) == "");
}
}
TEST_CASE("ObjectContainersList (HasBehaviorInObjectOrGroup)", "[common]") {
SECTION("Can check a behavior exists in an object") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
object.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.HasBehaviorInObjectOrGroup("MyObject", "MyBehavior"));
REQUIRE(!objectsContainersList.HasBehaviorInObjectOrGroup("MyObject", "MyWrongBehavior"));
}
SECTION("Can check a behavior exists in a group") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
// This behavior is only in one of the 2 objects.
object1.AddNewBehavior(project, "MyExtension::MyOtherBehavior",
"MyOtherBehavior");
gd::Object &object2 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject2", 0);
object2.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
auto &group = layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
REQUIRE(objectsContainersList.HasBehaviorInObjectOrGroup("MyGroup", "MyBehavior"));
REQUIRE(!objectsContainersList.HasBehaviorInObjectOrGroup("MyGroup", "MyOtherBehavior"));
}
}
TEST_CASE("ObjectContainersList (GetBehaviorsOfObject)", "[common]") {
SECTION("Find the behaviors in an object") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
object.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
const auto behaviors =
objectsContainersList.GetBehaviorsOfObject("MyObject", true);
REQUIRE(behaviors.size() == 1);
REQUIRE(behaviors[0] == "MyBehavior");
}
SECTION("Find the behaviors in a group") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
// This behavior is only in one of the 2 objects.
object1.AddNewBehavior(project, "MyExtension::MyOtherBehavior",
"MyOtherBehavior");
gd::Object &object2 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject2", 0);
object2.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
auto &group = layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
const auto behaviors =
objectsContainersList.GetBehaviorsOfObject("MyGroup", true);
REQUIRE(behaviors.size() == 1);
REQUIRE(behaviors[0] == "MyBehavior");
}
}
namespace {
gd::SpriteObject BuildSpriteWithAnimations(gd::String animationName1 = "!",
gd::String animationName2 = "!",
gd::String animationName3 = "!") {
gd::SpriteObject configuration;
gd::SpriteAnimationList &animations = configuration.GetAnimations();
if (animationName1 != "!") {
gd::Animation animation;
animation.SetName(animationName1);
animations.AddAnimation(animation);
if (animationName2 != "!") {
gd::Animation animation;
animation.SetName(animationName2);
animations.AddAnimation(animation);
}
if (animationName3 != "!") {
gd::Animation animation;
animation.SetName(animationName3);
animations.AddAnimation(animation);
}
}
return configuration;
}
bool Contains(const std::vector<gd::String> &vector, const gd::String &value) {
return std::find(vector.begin(), vector.end(), value) !=
vector.end();
}
} // namespace
TEST_CASE("ObjectContainersList (GetAnimationNamesOfObject)", "[common]") {
SECTION("Find the animation names in a sprite") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object object("MyObject", "Sprite",
gd::make_unique<gd::SpriteObject>(
BuildSpriteWithAnimations("Idle", "Run")));
layout.GetObjects().InsertObject(object, 0);
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
const auto animationNames =
objectsContainersList.GetAnimationNamesOfObject("MyObject");
REQUIRE(Contains(animationNames, "Idle"));
REQUIRE(Contains(animationNames, "Run"));
REQUIRE(animationNames.size() == 2);
}
SECTION("Find the animation names in a group of sprite") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object object1("MyObject1", "Sprite",
gd::make_unique<gd::SpriteObject>(
BuildSpriteWithAnimations("Idle", "Jump", "Run")));
layout.GetObjects().InsertObject(object1, 0);
gd::Object object2("MyObject2", "Sprite",
gd::make_unique<gd::SpriteObject>(
BuildSpriteWithAnimations("Run", "Idle", "Climb")));
layout.GetObjects().InsertObject(object2, 0);
auto &group = layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
auto objectsContainersList = gd::ObjectsContainersList::
MakeNewObjectsContainersListForProjectAndLayout(project, layout);
const auto animationNames =
objectsContainersList.GetAnimationNamesOfObject("MyGroup");
REQUIRE(Contains(animationNames, "Idle"));
REQUIRE(Contains(animationNames, "Run"));
REQUIRE(animationNames.size() == 2);
}
}

View File

@@ -79,7 +79,7 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
"angle of the trajectory direction.");
REQUIRE(getter.GetSentence() == "the movement angle");
// Object and behavior parameters are added automatically.
REQUIRE(getter.GetParameters().GetParametersCount() == 0);
REQUIRE(getter.GetParameters().size() == 0);
REQUIRE(getter.GetEvents().GetEventsCount() == 1);
REQUIRE(getter.GetEvents().GetEvent(0).GetType() ==
@@ -106,7 +106,7 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
REQUIRE(setter.GetDescription() == "");
REQUIRE(setter.GetSentence() == "");
// Object and behavior parameters are added automatically.
REQUIRE(setter.GetParameters().GetParametersCount() == 0);
REQUIRE(setter.GetParameters().size() == 0);
REQUIRE(setter.GetEvents().GetEventsCount() == 1);
REQUIRE(setter.GetEvents().GetEvent(0).GetType() ==
@@ -195,7 +195,7 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
"this behavior only.");
REQUIRE(getter.GetSentence() == "_PARAM0_ rotate object");
// Object and behavior parameters are added automatically.
REQUIRE(getter.GetParameters().GetParametersCount() == 0);
REQUIRE(getter.GetParameters().size() == 0);
REQUIRE(getter.GetEvents().GetEventsCount() == 1);
REQUIRE(getter.GetEvents().GetEvent(0).GetType() ==
@@ -232,16 +232,16 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
REQUIRE(setter.GetSentence() == "_PARAM0_ rotate object: _PARAM2_");
// To generate the value parameter, object and behavior parameters has to
// be declared too.
REQUIRE(setter.GetParameters().GetParametersCount() == 3);
auto &objectParameter = setter.GetParameters().GetParameter(0);
REQUIRE(setter.GetParameters().size() == 3);
auto &objectParameter = setter.GetParameters().at(0);
REQUIRE(objectParameter.GetName() == "Object");
REQUIRE(objectParameter.GetType() == "object");
auto &behaviorParameter = setter.GetParameters().GetParameter(1);
auto &behaviorParameter = setter.GetParameters().at(1);
REQUIRE(behaviorParameter.GetName() == "Behavior");
REQUIRE(behaviorParameter.GetType() == "behavior");
REQUIRE(behaviorParameter.GetExtraInfo() ==
"MyEventsExtension::MyEventsBasedBehavior");
auto &valueParameter = setter.GetParameters().GetParameter(2);
auto &valueParameter = setter.GetParameters().at(2);
REQUIRE(valueParameter.GetName() == "Value");
REQUIRE(valueParameter.GetType() == "yesorno");
@@ -329,7 +329,7 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
"angle of the trajectory direction.");
REQUIRE(getter.GetSentence() == "the movement angle");
// Object parameter is added automatically.
REQUIRE(getter.GetParameters().GetParametersCount() == 0);
REQUIRE(getter.GetParameters().size() == 0);
REQUIRE(getter.GetEvents().GetEventsCount() == 1);
REQUIRE(getter.GetEvents().GetEvent(0).GetType() ==
@@ -356,7 +356,7 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
REQUIRE(setter.GetDescription() == "");
REQUIRE(setter.GetSentence() == "");
// Object parameter is added automatically.
REQUIRE(setter.GetParameters().GetParametersCount() == 0);
REQUIRE(setter.GetParameters().size() == 0);
REQUIRE(setter.GetEvents().GetEventsCount() == 1);
REQUIRE(setter.GetEvents().GetEvent(0).GetType() ==
@@ -443,7 +443,7 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
"this object.");
REQUIRE(getter.GetSentence() == "_PARAM0_ rotate object");
// The Object parameter is added automatically.
REQUIRE(getter.GetParameters().GetParametersCount() == 0);
REQUIRE(getter.GetParameters().size() == 0);
REQUIRE(getter.GetEvents().GetEventsCount() == 1);
REQUIRE(getter.GetEvents().GetEvent(0).GetType() ==
@@ -478,13 +478,13 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
REQUIRE(setter.GetSentence() == "_PARAM0_ rotate object: _PARAM1_");
// To generate the value parameter, the object parameter has to
// be declared too.
REQUIRE(setter.GetParameters().GetParametersCount() == 2);
auto &objectParameter = setter.GetParameters().GetParameter(0);
REQUIRE(setter.GetParameters().size() == 2);
auto &objectParameter = setter.GetParameters().at(0);
REQUIRE(objectParameter.GetName() == "Object");
REQUIRE(objectParameter.GetType() == "object");
REQUIRE(objectParameter.GetExtraInfo() ==
"MyEventsExtension::MyEventsBasedObject");
auto &valueParameter = setter.GetParameters().GetParameter(1);
auto &valueParameter = setter.GetParameters().at(1);
REQUIRE(valueParameter.GetName() == "Value");
REQUIRE(valueParameter.GetType() == "yesorno");

View File

@@ -91,49 +91,4 @@ TEST_CASE("Variable", "[common][variables]") {
"Hello second copied World");
REQUIRE(variable3.GetChild("Child2").GetValue() == 44);
}
SECTION("Can find identical number variables") {
gd::Variable variable;
variable.SetValue(123);
gd::Variable otherVariable;
otherVariable.SetValue(123);
REQUIRE(variable == otherVariable);
}
SECTION("Can find different number variables") {
gd::Variable variable;
variable.SetValue(123);
gd::Variable otherVariable;
otherVariable.SetValue(456);
REQUIRE(variable != otherVariable);
}
SECTION("Can find identical structure variables") {
gd::Variable variable;
variable.GetChild("MyChild").SetValue(123);
gd::Variable otherVariable;
otherVariable.GetChild("MyChild").SetValue(123);
REQUIRE(variable == otherVariable);
}
SECTION("Can find structure with different child value") {
gd::Variable variable;
variable.GetChild("MyChild").SetValue(123);
gd::Variable otherVariable;
otherVariable.GetChild("MyChild").SetValue(456);
REQUIRE(variable != otherVariable);
}
SECTION("Can find structure with different child name") {
gd::Variable variable;
variable.GetChild("MyChild").SetValue(123);
gd::Variable otherVariable;
otherVariable.GetChild("MyOtherChild").SetValue(123);
REQUIRE(variable != otherVariable);
}
}

View File

@@ -867,22 +867,26 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
auto &behaviorEventsFunctions = eventsBasedBehavior.GetEventsFunctions();
auto &behaviorAction = behaviorEventsFunctions.InsertNewEventsFunction(
"MyBehaviorEventsFunction", 0);
behaviorAction.GetParameters()
.InsertNewParameter("Object", 0)
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject");
behaviorAction.GetParameters()
.InsertNewParameter("Behavior", 1)
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior");
behaviorAction.GetParameters()
.InsertNewParameter("ObjectWithMyBehavior", 2)
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject");
behaviorAction.GetParameters()
.InsertNewParameter("OtherBehavior", 3)
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior");
behaviorAction.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Object")
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
behaviorAction.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Behavior")
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
behaviorAction.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("ObjectWithMyBehavior")
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
behaviorAction.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("OtherBehavior")
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
auto &group = behaviorAction.GetObjectGroups().InsertNew("GroupWithMyBehavior");
group.AddObject("ObjectWithMyBehavior");
@@ -890,32 +894,36 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
behaviorEventsFunctions
.InsertNewEventsFunction("MyBehaviorEventsFunctionExpression", 1)
.SetFunctionType(gd::EventsFunction::Expression);
behaviorExpression.GetParameters()
.InsertNewParameter("Object", 0)
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject");
behaviorExpression.GetParameters()
.InsertNewParameter("Behavior", 1)
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior");
behaviorExpression.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Object")
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
behaviorExpression.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Behavior")
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
auto &behaviorExpressionAndCondition =
behaviorEventsFunctions
.InsertNewEventsFunction("MyBehaviorEventsFunctionExpressionAndCondition", 2)
.SetFunctionType(gd::EventsFunction::ExpressionAndCondition);
behaviorExpressionAndCondition.GetParameters()
.InsertNewParameter("Object", 0)
.SetType("object");
behaviorExpressionAndCondition.GetParameters()
.InsertNewParameter("Behavior", 1)
.SetType("behavior")
.SetExtraInfo("MyExtension::MyEventsBasedBehavior");
behaviorExpressionAndCondition.GetParameters()
.InsertNewParameter("Value1", 2)
.SetType("expression");
behaviorExpressionAndCondition.GetParameters()
.InsertNewParameter("Value2", 3)
.SetType("expression");
behaviorExpressionAndCondition.GetParameters().push_back(
gd::ParameterMetadata().SetName("Object").SetType("object"));
behaviorExpressionAndCondition.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Behavior")
.SetType("behavior")
.SetExtraInfo("MyExtension::MyEventsBasedBehavior"));
behaviorExpressionAndCondition.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Value1")
.SetType("expression"));
behaviorExpressionAndCondition.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Value2")
.SetType("expression"));
behaviorEventsFunctions
.InsertNewEventsFunction("MyBehaviorEventsFunctionActionWithOperator", 2)
@@ -948,41 +956,46 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
auto &objectEventsFunctions = eventsBasedObject.GetEventsFunctions();
auto &objectAction = objectEventsFunctions.InsertNewEventsFunction(
"MyObjectEventsFunction", 0);
objectAction.GetParameters()
.InsertNewParameter("Object", 0)
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject");
objectAction.GetParameters()
.InsertNewParameter("OtherObject", 1)
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject");
objectAction.GetParameters()
.InsertNewParameter("OtherBehavior", 2)
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior");
objectAction.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Object")
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
objectAction.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("OtherObject")
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
objectAction.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("OtherBehavior")
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
auto &objectExpression =
objectEventsFunctions
.InsertNewEventsFunction("MyObjectEventsFunctionExpression", 1)
.SetFunctionType(gd::EventsFunction::Expression);
objectExpression.GetParameters().InsertNewParameter("Object", 0)
objectExpression.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Object")
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject");
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
auto &objectExpressionAndCondition =
objectEventsFunctions
.InsertNewEventsFunction(
"MyObjectEventsFunctionExpressionAndCondition", 2)
.InsertNewEventsFunction("MyObjectEventsFunctionExpressionAndCondition", 2)
.SetFunctionType(gd::EventsFunction::ExpressionAndCondition);
objectExpressionAndCondition.GetParameters()
.InsertNewParameter("Object", 0)
.SetType("object");
objectExpressionAndCondition.GetParameters()
.InsertNewParameter("Value1", 1)
.SetType("expression");
objectExpressionAndCondition.GetParameters()
.InsertNewParameter("Value2", 2)
.SetType("expression");
objectExpressionAndCondition.GetParameters().push_back(
gd::ParameterMetadata().SetName("Object").SetType("object"));
objectExpressionAndCondition.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Value1")
.SetType("expression"));
objectExpressionAndCondition.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Value2")
.SetType("expression"));
objectEventsFunctions
.InsertNewEventsFunction("MyObjectEventsFunctionActionWithOperator", 2)
@@ -1009,27 +1022,32 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
auto &behaviorEventsFunctions = eventsBasedBehavior.GetEventsFunctions();
auto &behaviorAction = behaviorEventsFunctions.InsertNewEventsFunction(
"MyBehaviorEventsFunction", 0);
behaviorAction.GetParameters()
.InsertNewParameter("Object", 0)
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject");
behaviorAction.GetParameters()
.InsertNewParameter("Behavior", 1)
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior");
behaviorAction.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Object")
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
behaviorAction.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Behavior")
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
// Define the same objects as in the layout to be consistent with events.
behaviorAction.GetParameters()
.InsertNewParameter("ObjectWithMyBehavior", 2)
.SetType("object")
.SetExtraInfo("MyExtension::Sprite");
behaviorAction.GetParameters()
.InsertNewParameter("MyBehavior", 3)
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior");
behaviorAction.GetParameters()
.InsertNewParameter("MyCustomObject", 4)
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject");
behaviorAction.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("ObjectWithMyBehavior")
.SetType("object")
.SetExtraInfo("MyExtension::Sprite"));
behaviorAction.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("MyBehavior")
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
behaviorAction.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("MyCustomObject")
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
}
// Add an other events based object that uses previously defined events based
@@ -1044,10 +1062,11 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
auto &objectEventsFunctions = eventsBasedObject.GetEventsFunctions();
auto &objectAction = objectEventsFunctions.InsertNewEventsFunction(
"MyObjectEventsFunction", 0);
objectAction.GetParameters()
.InsertNewParameter("Object", 0)
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyOtherEventsBasedObject");
objectAction.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Object")
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyOtherEventsBasedObject"));
// Add a child-object with the same names the one from the scene
// to be able to use the same events list.
@@ -1072,33 +1091,39 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
{
auto &action =
eventsExtension.InsertNewEventsFunction("MyEventsFunction", 0);
action.GetParameters()
.InsertNewParameter("currentScene", 0)
.SetType("")
.SetCodeOnly(true);
action.GetParameters()
.InsertNewParameter("Object", 1)
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject");
action.GetParameters()
.InsertNewParameter("Behavior", 2)
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior");
action.GetParameters().push_back(gd::ParameterMetadata()
.SetName("currentScene")
.SetType("")
.SetCodeOnly(true));
action.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Object")
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
action.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Behavior")
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
auto &expression =
eventsExtension.InsertNewEventsFunction("MyEventsFunctionExpression", 1)
.SetFunctionType(gd::EventsFunction::Expression);
expression.GetParameters()
.InsertNewParameter("currentScene", 0)
.SetType("")
.SetCodeOnly(true);
expression.GetParameters().push_back(gd::ParameterMetadata()
.SetName("currentScene")
.SetType("")
.SetCodeOnly(true));
auto &freeExpressionAndCondition = eventsExtension.InsertNewEventsFunction("MyEventsFunctionExpressionAndCondition", 2)
.SetFunctionType(gd::EventsFunction::ExpressionAndCondition);
freeExpressionAndCondition.GetParameters().InsertNewParameter("Value1", 0)
.SetType("expression");
freeExpressionAndCondition.GetParameters().InsertNewParameter("Value2", 1)
.SetType("expression");
freeExpressionAndCondition.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Value1")
.SetType("expression"));
freeExpressionAndCondition.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("Value2")
.SetType("expression"));
eventsExtension.InsertNewEventsFunction("MyEventsFunctionActionWithOperator", 2)
.SetFunctionType(gd::EventsFunction::ActionWithOperator)
@@ -1112,18 +1137,21 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
auto &action =
eventsExtension.InsertNewEventsFunction("MyOtherEventsFunction", 0);
// Define the same objects as in the layout to be consistent with events.
action.GetParameters()
.InsertNewParameter("ObjectWithMyBehavior", 0)
.SetType("object")
.SetExtraInfo("MyExtension::Sprite");
action.GetParameters()
.InsertNewParameter("MyBehavior", 1)
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior");
action.GetParameters()
.InsertNewParameter("MyCustomObject", 2)
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject");
action.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("ObjectWithMyBehavior")
.SetType("object")
.SetExtraInfo("MyExtension::Sprite"));
action.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("MyBehavior")
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
action.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("MyCustomObject")
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
auto &group = action.GetObjectGroups().InsertNew("GroupWithMyBehavior");
group.AddObject("ObjectWithMyBehavior");
}
@@ -1200,7 +1228,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object2", 0);
gd::WholeProjectRefactorer::ObjectRemovedInScene(project, layout1,
gd::WholeProjectRefactorer::ObjectRemovedInLayout(project, layout1,
"Object1");
gd::WholeProjectRefactorer::GlobalObjectRemoved(project, "GlobalObject1");
REQUIRE(layout1.GetObjects().GetObjectGroups()[0].Find(
@@ -1234,7 +1262,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
layout1.GetInitialInstances().InsertInitialInstance(instance2);
layout1.GetInitialInstances().InsertInitialInstance(instance3);
gd::WholeProjectRefactorer::ObjectRemovedInScene(
gd::WholeProjectRefactorer::ObjectRemovedInLayout(
project, layout1, "Object1");
gd::WholeProjectRefactorer::GlobalObjectRemoved(
project, "GlobalObject1");
@@ -1278,7 +1306,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
externalLayout2.GetInitialInstances().InsertInitialInstance(instance2);
externalLayout2.GetInitialInstances().InsertInitialInstance(instance3);
gd::WholeProjectRefactorer::ObjectRemovedInScene(
gd::WholeProjectRefactorer::ObjectRemovedInLayout(
project, layout1, "Object1");
gd::WholeProjectRefactorer::GlobalObjectRemoved(
project, "GlobalObject1");
@@ -1316,7 +1344,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object2", 0);
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
project, layout1, "Object1", "Object3", /* isObjectGroup =*/false);
gd::WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
project, "GlobalObject1", "GlobalObject3", /* isObjectGroup =*/false);
@@ -1353,7 +1381,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
layout1.GetInitialInstances().InsertInitialInstance(instance2);
layout1.GetInitialInstances().InsertInitialInstance(instance3);
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
project, layout1, "Object1", "Object3", /* isObjectGroup =*/false);
gd::WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
project, "GlobalObject1", "GlobalObject3", /* isObjectGroup =*/false);
@@ -1399,7 +1427,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
externalLayout2.GetInitialInstances().InsertInitialInstance(instance2);
externalLayout2.GetInitialInstances().InsertInitialInstance(instance3);
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
project, layout1, "Object1", "Object3", /* isObjectGroup =*/false);
gd::WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
project, "GlobalObject1", "GlobalObject3", /* isObjectGroup =*/false);
@@ -1434,7 +1462,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
auto &layout = project.GetLayout("Scene");
// Trigger the refactoring after the renaming of an object
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
project, layout, "ObjectWithMyBehavior",
"RenamedObjectWithMyBehavior",
/* isObjectGroup=*/false);
@@ -1462,7 +1490,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
auto &layout = project.GetLayout("Scene");
// Trigger the refactoring after the renaming of a group
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
project, layout, "GroupWithMyBehavior", "RenamedGroupWithMyBehavior",
/* isObjectGroup=*/true);
@@ -1506,7 +1534,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
// Attach the behavior to the object.
object.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
gd::WholeProjectRefactorer::BehaviorsAddedToObjectInScene(project, scene,
gd::WholeProjectRefactorer::BehaviorsAddedToObjectInLayout(project, scene,
"Object");
// The behavior parameter is now filled.
@@ -2043,9 +2071,9 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
auto &myEventsFunction =
project.GetEventsFunctionsExtension("MyEventsExtension")
.GetEventsFunction("MyEventsFunction");
REQUIRE(myEventsFunction.GetParameters().GetParameter(1).GetExtraInfo() ==
REQUIRE(myEventsFunction.GetParameters().at(1).GetExtraInfo() ==
"MyRenamedExtension::MyEventsBasedObject");
REQUIRE(myEventsFunction.GetParameters().GetParameter(2).GetExtraInfo() ==
REQUIRE(myEventsFunction.GetParameters().at(2).GetExtraInfo() ==
"MyRenamedExtension::MyEventsBasedBehavior");
// Behavior function
@@ -2056,12 +2084,9 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
.Get("MyEventsBasedBehavior")
.GetEventsFunctions()
.GetEventsFunction("MyBehaviorEventsFunction");
REQUIRE(myBehaviorEventsFunction.GetParameters()
.GetParameter(2)
.GetExtraInfo() == "MyRenamedExtension::MyEventsBasedObject");
REQUIRE(myBehaviorEventsFunction.GetParameters()
.GetParameter(3)
.GetExtraInfo() ==
REQUIRE(myBehaviorEventsFunction.GetParameters().at(2).GetExtraInfo() ==
"MyRenamedExtension::MyEventsBasedObject");
REQUIRE(myBehaviorEventsFunction.GetParameters().at(3).GetExtraInfo() ==
"MyRenamedExtension::MyEventsBasedBehavior");
}
@@ -2073,12 +2098,9 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
.Get("MyEventsBasedObject")
.GetEventsFunctions()
.GetEventsFunction("MyObjectEventsFunction");
REQUIRE(myBehaviorEventsFunction.GetParameters()
.GetParameter(1)
.GetExtraInfo() == "MyRenamedExtension::MyEventsBasedObject");
REQUIRE(myBehaviorEventsFunction.GetParameters()
.GetParameter(2)
.GetExtraInfo() ==
REQUIRE(myBehaviorEventsFunction.GetParameters().at(1).GetExtraInfo() ==
"MyRenamedExtension::MyEventsBasedObject");
REQUIRE(myBehaviorEventsFunction.GetParameters().at(2).GetExtraInfo() ==
"MyRenamedExtension::MyEventsBasedBehavior");
}
}
@@ -2321,7 +2343,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
auto &myEventsFunction =
project.GetEventsFunctionsExtension("MyEventsExtension")
.GetEventsFunction("MyEventsFunction");
REQUIRE(myEventsFunction.GetParameters().GetParameter(2).GetExtraInfo() ==
REQUIRE(myEventsFunction.GetParameters().at(2).GetExtraInfo() ==
"MyEventsExtension::MyRenamedEventsBasedBehavior");
// Behavior function
@@ -2332,9 +2354,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
.Get("MyEventsBasedBehavior")
.GetEventsFunctions()
.GetEventsFunction("MyBehaviorEventsFunction");
REQUIRE(myBehaviorEventsFunction.GetParameters()
.GetParameter(3)
.GetExtraInfo() ==
REQUIRE(myBehaviorEventsFunction.GetParameters().at(3).GetExtraInfo() ==
"MyEventsExtension::MyRenamedEventsBasedBehavior");
}
@@ -2346,9 +2366,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
.Get("MyEventsBasedObject")
.GetEventsFunctions()
.GetEventsFunction("MyObjectEventsFunction");
REQUIRE(myBehaviorEventsFunction.GetParameters()
.GetParameter(2)
.GetExtraInfo() ==
REQUIRE(myBehaviorEventsFunction.GetParameters().at(2).GetExtraInfo() ==
"MyEventsExtension::MyRenamedEventsBasedBehavior");
}
}
@@ -2431,7 +2449,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
auto &myEventsFunction =
project.GetEventsFunctionsExtension("MyEventsExtension")
.GetEventsFunction("MyEventsFunction");
REQUIRE(myEventsFunction.GetParameters().GetParameter(1).GetExtraInfo() ==
REQUIRE(myEventsFunction.GetParameters().at(1).GetExtraInfo() ==
"MyEventsExtension::MyRenamedEventsBasedObject");
// Behavior function
@@ -2442,9 +2460,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
.Get("MyEventsBasedBehavior")
.GetEventsFunctions()
.GetEventsFunction("MyBehaviorEventsFunction");
REQUIRE(myBehaviorEventsFunction.GetParameters()
.GetParameter(2)
.GetExtraInfo() ==
REQUIRE(myBehaviorEventsFunction.GetParameters().at(2).GetExtraInfo() ==
"MyEventsExtension::MyRenamedEventsBasedObject");
}
@@ -2456,9 +2472,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
.Get("MyEventsBasedObject")
.GetEventsFunctions()
.GetEventsFunction("MyObjectEventsFunction");
REQUIRE(myBehaviorEventsFunction.GetParameters()
.GetParameter(1)
.GetExtraInfo() ==
REQUIRE(myBehaviorEventsFunction.GetParameters().at(1).GetExtraInfo() ==
"MyEventsExtension::MyRenamedEventsBasedObject");
}
}
@@ -3570,7 +3584,7 @@ CreateExpressionWithLayerParameter(gd::Project &project,
} // namespace
TEST_CASE("RenameLayer", "[common]") {
SECTION("Can update layer names in scene events") {
SECTION("Can update layer names in events") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
@@ -3602,7 +3616,7 @@ TEST_CASE("RenameLayer", "[common]") {
auto &otherExternalExpression = CreateExpressionWithLayerParameter(
project, otherExternalEvents.GetEvents(), "My layer");
gd::WholeProjectRefactorer::RenameLayerInScene(project, layout, "My layer",
gd::WholeProjectRefactorer::RenameLayer(project, layout, "My layer",
"My renamed layer");
REQUIRE(layoutAction.GetParameter(3).GetPlainString() ==
@@ -3630,38 +3644,6 @@ TEST_CASE("RenameLayer", "[common]") {
"MyExtension::CameraCenterX(\"My layer\")");
}
SECTION("Can update layer names in event-based object events") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &eventsBasedObject = eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
auto &eventsFunction =
eventsBasedObject.GetEventsFunctions().InsertNewEventsFunction(
"MyEventsFunction", 0);
gd::WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
eventsExtension, eventsBasedObject);
auto &action =
CreateActionWithLayerParameter(project, eventsFunction.GetEvents());
auto &expression = CreateExpressionWithLayerParameter(
project, eventsFunction.GetEvents(), "My layer");
gd::WholeProjectRefactorer::RenameLayerInEventsBasedObject(
project, eventsExtension, eventsBasedObject, "My layer",
"My renamed layer");
REQUIRE(action.GetParameter(3).GetPlainString() == "\"My renamed layer\"");
REQUIRE(expression.GetParameter(0).GetPlainString() ==
"MyExtension::CameraCenterX(\"My renamed layer\") + "
"MyExtension::CameraCenterX(\"My renamed layer\")");
}
SECTION("Can update layer names in expressions with a smaller name") {
gd::Project project;
gd::Platform platform;
@@ -3672,7 +3654,7 @@ TEST_CASE("RenameLayer", "[common]") {
auto &layoutExpression =
CreateExpressionWithLayerParameter(project, layout.GetEvents(), "My layer");
gd::WholeProjectRefactorer::RenameLayerInScene(project, layout, "My layer",
gd::WholeProjectRefactorer::RenameLayer(project, layout, "My layer",
"layerA");
REQUIRE(layoutExpression.GetParameter(0).GetPlainString() ==
@@ -3680,7 +3662,7 @@ TEST_CASE("RenameLayer", "[common]") {
"MyExtension::CameraCenterX(\"layerA\")");
}
SECTION("Renaming a layer also moves the instances on this layer in its scene and associated external layouts") {
SECTION("Renaming a layer also moves the instances on this layer and of the associated external layouts") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
@@ -3731,7 +3713,7 @@ TEST_CASE("RenameLayer", "[common]") {
REQUIRE(otherInitialInstance1.GetLayer() == "My layer");
REQUIRE(otherExternalInitialInstance1.GetLayer() == "My layer");
gd::WholeProjectRefactorer::RenameLayerInScene(project, layout, "My layer", "My new layer");
gd::WholeProjectRefactorer::RenameLayer(project, layout, "My layer", "My new layer");
// Instances on the renamed layer are moved to the new layer.
REQUIRE(initialInstance1.GetLayer() == "My new layer");
@@ -3746,46 +3728,6 @@ TEST_CASE("RenameLayer", "[common]") {
REQUIRE(otherExternalInitialInstance1.GetLayer() == "My layer");
}
SECTION("Renaming a layer also moves the instances on this layer in its "
"event-based object") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &eventsBasedObject = eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
auto &eventsFunction =
eventsBasedObject.GetEventsFunctions().InsertNewEventsFunction(
"MyEventsFunction", 0);
gd::WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
eventsExtension, eventsBasedObject);
eventsBasedObject.GetLayers().InsertNewLayer("My layer", 0);
auto &initialInstances = eventsBasedObject.GetInitialInstances();
auto &initialInstance1 = initialInstances.InsertNewInitialInstance();
initialInstance1.SetLayer("My layer");
auto &initialInstance2 = initialInstances.InsertNewInitialInstance();
initialInstance2.SetLayer("My layer");
auto &initialInstance3 = initialInstances.InsertNewInitialInstance();
initialInstance3.SetLayer("");
REQUIRE(initialInstance1.GetLayer() == "My layer");
REQUIRE(initialInstance2.GetLayer() == "My layer");
REQUIRE(initialInstance3.GetLayer() == "");
gd::WholeProjectRefactorer::RenameLayerInEventsBasedObject(
project, eventsExtension, eventsBasedObject, "My layer",
"My new layer");
// Instances on the renamed layer are moved to the new layer.
REQUIRE(initialInstance1.GetLayer() == "My new layer");
REQUIRE(initialInstance2.GetLayer() == "My new layer");
REQUIRE(initialInstance3.GetLayer() == "");
}
SECTION("Can rename a layer when a layer parameter is empty") {
gd::Project project;
gd::Platform platform;
@@ -3796,7 +3738,7 @@ TEST_CASE("RenameLayer", "[common]") {
auto &layoutAction =
CreateActionWithEmptyLayerParameter(project, layout.GetEvents());
gd::WholeProjectRefactorer::RenameLayerInScene(project, layout, "My layer",
gd::WholeProjectRefactorer::RenameLayer(project, layout, "My layer",
"layerA");
REQUIRE(layoutAction.GetParameter(0).GetPlainString() == "");
@@ -3812,7 +3754,7 @@ TEST_CASE("RenameLayer", "[common]") {
auto &layoutExpression =
CreateExpressionWithLayerParameter(project, layout.GetEvents(), "My layer");
gd::WholeProjectRefactorer::RenameLayerInScene(project, layout, "My layer",
gd::WholeProjectRefactorer::RenameLayer(project, layout, "My layer",
"");
REQUIRE(layoutExpression.GetParameter(0).GetPlainString() ==
@@ -3830,7 +3772,7 @@ TEST_CASE("RenameLayer", "[common]") {
auto &layoutExpression =
CreateExpressionWithLayerParameter(project, layout.GetEvents(), "");
gd::WholeProjectRefactorer::RenameLayerInScene(project, layout, "", "My layer");
gd::WholeProjectRefactorer::RenameLayer(project, layout, "", "My layer");
REQUIRE(layoutExpression.GetParameter(0).GetPlainString() ==
"MyExtension::CameraCenterX(\"\") + "
@@ -3871,7 +3813,7 @@ CreateExpressionWithAnimationParameter(gd::Project &project,
} // namespace
TEST_CASE("RenameObjectAnimation", "[common]") {
SECTION("Can update object animation names in scene events") {
SECTION("Can update object animation names in event") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
@@ -3913,7 +3855,7 @@ TEST_CASE("RenameObjectAnimation", "[common]") {
auto &wrongObjectExpression =
CreateExpressionWithAnimationParameter(project, layout.GetEvents(), "MySprite2");
gd::WholeProjectRefactorer::RenameObjectAnimationInScene(project, layout, object, "My animation",
gd::WholeProjectRefactorer::RenameObjectAnimation(project, layout, object, "My animation",
"My renamed animation");
REQUIRE(layoutAction.GetParameter(1).GetPlainString() ==
@@ -3945,53 +3887,6 @@ TEST_CASE("RenameObjectAnimation", "[common]") {
"MySprite2.AnimationFrameCount(\"My animation\") + "
"MySprite2.AnimationFrameCount(\"My animation\")");
}
SECTION("Can update object animation names in events-based object events") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &eventsBasedObject = eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
auto &eventsFunction =
eventsBasedObject.GetEventsFunctions().InsertNewEventsFunction(
"MyEventsFunction", 0);
gd::WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
eventsExtension, eventsBasedObject);
auto &object = eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MySprite", 0);
eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MySprite2", 1);
auto &action = CreateActionWithAnimationParameter(
project, eventsFunction.GetEvents(), "MySprite");
auto &wrongObjectAction = CreateActionWithAnimationParameter(
project, eventsFunction.GetEvents(), "MySprite2");
auto &expression = CreateExpressionWithAnimationParameter(
project, eventsFunction.GetEvents(), "MySprite");
auto &wrongObjectExpression = CreateExpressionWithAnimationParameter(
project, eventsFunction.GetEvents(), "MySprite2");
gd::WholeProjectRefactorer::RenameObjectAnimationInEventsBasedObject(
project, eventsExtension, eventsBasedObject, object, "My animation",
"My renamed animation");
REQUIRE(action.GetParameter(1).GetPlainString() ==
"\"My renamed animation\"");
REQUIRE(wrongObjectAction.GetParameter(1).GetPlainString() ==
"\"My animation\"");
REQUIRE(expression.GetParameter(0).GetPlainString() ==
"MySprite.AnimationFrameCount(\"My renamed animation\") + "
"MySprite.AnimationFrameCount(\"My renamed animation\")");
REQUIRE(wrongObjectExpression.GetParameter(0).GetPlainString() ==
"MySprite2.AnimationFrameCount(\"My animation\") + "
"MySprite2.AnimationFrameCount(\"My animation\")");
}
}
namespace {
@@ -4027,7 +3922,7 @@ CreateExpressionWithLayerEffectParameter(gd::Project &project,
} // namespace
TEST_CASE("RenameLayerEffect", "[common]") {
SECTION("Can update layer effect names in scene events") {
SECTION("Can update layer effect names in event") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
@@ -4071,7 +3966,7 @@ TEST_CASE("RenameLayerEffect", "[common]") {
auto &wrongLayerExpression =
CreateExpressionWithLayerEffectParameter(project, layout.GetEvents(), "My layer 2");
gd::WholeProjectRefactorer::RenameLayerEffectInScene(project, layout, layer, "My effect",
gd::WholeProjectRefactorer::RenameLayerEffect(project, layout, layer, "My effect",
"My renamed effect");
REQUIRE(layoutAction.GetParameter(2).GetPlainString() ==
@@ -4103,61 +3998,10 @@ TEST_CASE("RenameLayerEffect", "[common]") {
"MyExtension::LayerEffectParameter(\"My layer 2\", \"My effect\") + "
"MyExtension::LayerEffectParameter(\"My layer 2\", \"My effect\")");
}
SECTION("Can update layer effect names in events-based object events") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &eventsBasedObject = eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
auto &eventsFunction =
eventsBasedObject.GetEventsFunctions().InsertNewEventsFunction(
"MyEventsFunction", 0);
gd::WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
eventsExtension, eventsBasedObject);
eventsBasedObject.GetLayers().InsertNewLayer("My layer", 0);
auto &layer = eventsBasedObject.GetLayers().GetLayer("My layer");
auto &object = eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MySprite", 0);
eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MySprite2", 1);
auto &action = CreateActionWithLayerEffectParameter(
project, eventsFunction.GetEvents(), "My layer");
auto &wrongLayerAction = CreateActionWithLayerEffectParameter(
project, eventsFunction.GetEvents(), "My layer 2");
auto &expression = CreateExpressionWithLayerEffectParameter(
project, eventsFunction.GetEvents(), "My layer");
auto &wrongLayerExpression = CreateExpressionWithLayerEffectParameter(
project, eventsFunction.GetEvents(), "My layer 2");
gd::WholeProjectRefactorer::RenameLayerEffectInEventsBasedObject(
project, eventsExtension, eventsBasedObject, layer, "My effect",
"My renamed effect");
REQUIRE(action.GetParameter(2).GetPlainString() == "\"My renamed effect\"");
REQUIRE(wrongLayerAction.GetParameter(2).GetPlainString() ==
"\"My effect\"");
REQUIRE(expression.GetParameter(0).GetPlainString() ==
"MyExtension::LayerEffectParameter(\"My layer\", \"My renamed "
"effect\") + "
"MyExtension::LayerEffectParameter(\"My layer\", \"My renamed "
"effect\")");
REQUIRE(
wrongLayerExpression.GetParameter(0).GetPlainString() ==
"MyExtension::LayerEffectParameter(\"My layer 2\", \"My effect\") + "
"MyExtension::LayerEffectParameter(\"My layer 2\", \"My effect\")");
}
}
TEST_CASE("RemoveLayer", "[common]") {
SECTION("Can remove instances from a layer (in a scene and its associated external layouts)") {
SECTION("Can remove instances from a layer (in a scene and their associated external layouts)") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
@@ -4242,7 +4086,7 @@ TEST_CASE("RemoveLayer", "[common]") {
}
TEST_CASE("MergeLayers", "[common]") {
SECTION("Can merge instances from a layer into another layer (in a scene and its associated external layouts)") {
SECTION("Can merge instances from a layer into another layer (in a scene and their associated external layouts)") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);

View File

@@ -304,15 +304,8 @@ namespace gdjs {
*/
setDepth(depth: float): void {
const unscaledDepth = this.getUnscaledDepth();
if (unscaledDepth === 0) {
return;
}
const scaleZ = depth / unscaledDepth;
if (this._innerArea && this._isInnerAreaFollowingParentSize) {
this._innerArea.min[2] *= scaleZ;
this._innerArea.max[2] *= scaleZ;
} else {
this.setScaleZ(scaleZ);
if (unscaledDepth !== 0) {
this.setScaleZ(depth / unscaledDepth);
}
}
@@ -332,10 +325,6 @@ namespace gdjs {
* @param newScale The new scale (must be greater than 0).
*/
setScaleZ(newScale: number): void {
if (this._innerArea && this._isInnerAreaFollowingParentSize) {
// The scale is always 1;
return;
}
if (newScale < 0) {
newScale = 0;
}

View File

@@ -235,19 +235,6 @@ void Model3DObjectConfiguration::ExposeResources(
worker.ExposeModel3D(modelResourceName);
}
const gd::String &
Model3DObjectConfiguration::GetAnimationName(size_t index) const {
return GetAnimation(index).GetName();
}
bool Model3DObjectConfiguration::HasAnimationNamed(
const gd::String &name) const {
return !name.empty() && (find_if(animations.begin(), animations.end(),
[&name](const Model3DAnimation &animation) {
return animation.GetName() == name;
}) != animations.end());
}
Model3DAnimation Model3DObjectConfiguration::badAnimation;
const Model3DAnimation &
@@ -265,6 +252,14 @@ Model3DAnimation &Model3DObjectConfiguration::GetAnimation(std::size_t nb) {
return animations[nb];
}
bool Model3DObjectConfiguration::HasAnimationNamed(
const gd::String &name) const {
return !name.empty() && (find_if(animations.begin(), animations.end(),
[&name](const Model3DAnimation &animation) {
return animation.GetName() == name;
}) != animations.end());
}
void Model3DObjectConfiguration::AddAnimation(
const Model3DAnimation &animation) {
animations.push_back(animation);

View File

@@ -85,12 +85,6 @@ public:
* Methods related to animations management
*/
///@{
std::size_t GetAnimationsCount() const override { return animations.size(); };
const gd::String &GetAnimationName(size_t index) const override;
bool HasAnimationNamed(const gd::String &animationName) const override;
/**
* \brief Return the animation at the specified index.
* If the index is out of bound, a "bad animation" object is returned.
@@ -103,6 +97,16 @@ public:
*/
Model3DAnimation &GetAnimation(std::size_t nb);
/**
* \brief Return the number of animations this object has.
*/
std::size_t GetAnimationsCount() const { return animations.size(); };
/**
* \brief Return true if the animation called "name" exists.
*/
bool HasAnimationNamed(const gd::String& name) const;
/**
* \brief Add an animation at the end of the existing ones.
*/

View File

@@ -118,19 +118,6 @@ namespace gdjs {
this._materialType = this._convertMaterialType(
objectData.content.materialType
);
this.onModelChanged(objectData);
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
this.onCreated();
}
/**
* To be called after the renderer loaded a Model resource:
* - After the renderer was instantiated
* - After reloading the model
*/
private onModelChanged(objectData) {
this._updateModel(objectData);
if (this._animations.length > 0) {
this._renderer.playAnimation(
@@ -138,6 +125,9 @@ namespace gdjs {
this._animations[0].loop
);
}
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
this.onCreated();
}
updateFromObjectData(
@@ -145,21 +135,7 @@ namespace gdjs {
newObjectData: Model3DObjectData
): boolean {
super.updateFromObjectData(oldObjectData, newObjectData);
if (
oldObjectData.content.materialType !==
newObjectData.content.materialType
) {
this._materialType = this._convertMaterialType(
newObjectData.content.materialType
);
}
if (
oldObjectData.content.modelResourceName !==
newObjectData.content.modelResourceName
) {
this._reloadModel(newObjectData);
} else if (
oldObjectData.content.width !== newObjectData.content.width ||
oldObjectData.content.height !== newObjectData.content.height ||
oldObjectData.content.depth !== newObjectData.content.depth ||
@@ -167,12 +143,19 @@ namespace gdjs {
oldObjectData.content.rotationY !== newObjectData.content.rotationY ||
oldObjectData.content.rotationZ !== newObjectData.content.rotationZ ||
oldObjectData.content.keepAspectRatio !==
newObjectData.content.keepAspectRatio ||
oldObjectData.content.materialType !==
newObjectData.content.materialType
newObjectData.content.keepAspectRatio
) {
this._updateModel(newObjectData);
}
if (
oldObjectData.content.materialType !==
newObjectData.content.materialType
) {
this._materialType = this._convertMaterialType(
newObjectData.content.materialType
);
this._updateModel(newObjectData);
}
if (
oldObjectData.content.originLocation !==
newObjectData.content.originLocation
@@ -235,12 +218,6 @@ namespace gdjs {
}
}
_reloadModel(objectData: Model3DObjectData) {
this._modelResourceName = objectData.content.modelResourceName;
this._renderer._reloadModel(this, this._runtimeScene);
this.onModelChanged(objectData);
}
_updateModel(objectData: Model3DObjectData) {
const rotationX = objectData.content.rotationX || 0;
const rotationY = objectData.content.rotationY || 0;

View File

@@ -236,20 +236,6 @@ namespace gdjs {
}
}
/**
* `_updateModel` should always be called after this method.
* Ideally, use `Model3DRuntimeObject#_reloadModel` instead.
*/
_reloadModel(
runtimeObject: Model3DRuntimeObject,
instanceContainer: gdjs.RuntimeInstanceContainer
) {
this._originalModel = instanceContainer
.getGame()
.getModel3DManager()
.getModel(runtimeObject._modelResourceName);
}
_updateModel(
rotationX: float,
rotationY: float,

View File

@@ -38,7 +38,7 @@ module.exports = {
.setName('Consent Cordova plugin')
.setDependencyType('cordova')
.setExportName('cordova-plugin-consent')
.setVersion('3.0.0-alpha.8')
.setVersion('2.4.0')
.onlyIfOtherDependencyIsExported('AdMob Cordova plugin');
extension
@@ -58,7 +58,7 @@ module.exports = {
.setName('AdMob Cordova plugin')
.setDependencyType('cordova')
.setExportName('admob-plus-cordova')
.setVersion('2.0.0-alpha.18')
.setVersion('1.28.0')
.setExtraSetting(
'APP_ID_ANDROID',
new gd.PropertyDescriptor('AdMobAppIdAndroid').setType(
@@ -166,11 +166,11 @@ module.exports = {
)
.addParameter('string', _('Android app open ID'), '', false)
.setParameterLongDescription(
'Get it from your AdMob account. You can use `"ca-app-pub-3940256099942544/9257395921"` for loading a test app open.'
'Get it from your AdMob account. You can use `"ca-app-pub-3940256099942544/3419835294"` for loading a test app open.'
)
.addParameter('string', _('iOS app open ID'), '', false)
.setParameterLongDescription(
'Get it from your AdMob account. You can use `"ca-app-pub-3940256099942544/5575463023"` for loading a test app open.'
'Get it from your AdMob account. You can use `"ca-app-pub-3940256099942544/5662855259"` for loading a test app open.'
)
.addParameter(
'yesorno',

View File

@@ -7,8 +7,8 @@ namespace gdjs {
const testAdIds = {
appOpen: {
android: 'ca-app-pub-3940256099942544/9257395921',
ios: 'ca-app-pub-3940256099942544/5575463023',
android: 'ca-app-pub-3940256099942544/3419835294',
ios: 'ca-app-pub-3940256099942544/5662855259',
},
banner: {
android: 'ca-app-pub-3940256099942544/6300978111',
@@ -67,7 +67,6 @@ namespace gdjs {
// Admob does not initialize automatically, so we store a flag to know if it's initialized.
let admobStarted = false;
let isStarting = false;
let isUsingTestAds = false;
// Banner
@@ -116,13 +115,9 @@ namespace gdjs {
async () => {
// Obtain user consent ?
logger.info('Starting AdMob.');
isStarting = true;
await admob.start();
logger.info('AdMob successfully started.');
isStarting = false;
admobStarted = true;
},
false
@@ -131,32 +126,15 @@ namespace gdjs {
/**
* Helper to know if we are on mobile and admob is correctly initialized.
*/
const checkIfAdMobIsAvailable = async () => {
const checkIfAdMobIsAvailable = () => {
if (typeof cordova === 'undefined') {
logger.warn('We are not on mobile, AdMob will not be available.');
return false;
}
if (typeof admob === 'undefined') {
logger.warn('AdMob has not been configured properly.');
if (typeof admob === 'undefined' || !admobStarted) {
logger.warn('AdMob has not been configured or started properly.');
return false;
}
if (!admobStarted) {
if (isStarting) {
// Delay the call until AdMob is started, up to 5 seconds.
let time = 0;
while (!admobStarted && time < 5000) {
await new Promise((resolve) => setTimeout(resolve, 100));
time += 100;
}
}
if (!admobStarted) {
logger.warn('AdMob is not started.');
return false;
}
}
return true;
};
@@ -186,10 +164,8 @@ namespace gdjs {
* charging advertisers. If you click on too many ads without being in test mode, you risk your
* account being flagged for invalid activity.
*/
export const setTestMode = async (enable: boolean) => {
if (!(await checkIfAdMobIsAvailable())) return;
logger.info('Setting AdMob test mode to:', enable);
export const setTestMode = (enable: boolean) => {
if (!checkIfAdMobIsAvailable()) return;
isUsingTestAds = enable;
};
@@ -209,7 +185,7 @@ namespace gdjs {
displayLandscape,
displayWhenLoaded
) => {
if (!(await checkIfAdMobIsAvailable())) return;
if (!checkIfAdMobIsAvailable()) return;
// If an appOpen is already loading or showing, we don't stop it.
if (appOpenLoading || appOpenShowing) {
return;
@@ -266,7 +242,7 @@ namespace gdjs {
/** Show the loaded appOpen. */
export const showAppOpen = async () => {
if (!(await checkIfAdMobIsAvailable())) return;
if (!checkIfAdMobIsAvailable()) return;
if (!appOpen) {
logger.warn('App Open has not been set up, call loadAppOpen first.');
@@ -317,7 +293,7 @@ namespace gdjs {
* If a banner is already set up, it will be hidden and replaced by the new one.
*/
export const setupBanner = async (androidAdUnitId, iosAdUnitId, atTop) => {
if (!(await checkIfAdMobIsAvailable())) return;
if (!checkIfAdMobIsAvailable()) return;
const adUnitId = getAdUnitId(androidAdUnitId, iosAdUnitId, 'banner');
if (!adUnitId) return;
@@ -333,7 +309,6 @@ namespace gdjs {
adUnitId,
position: atTop ? 'top' : 'bottom',
size: bannerRequestedAdSizeType,
offset: 0,
});
banner.on('load', () => {
@@ -379,7 +354,7 @@ namespace gdjs {
/** Hide the banner shown on screen. */
export const hideBanner = async () => {
if (!(await checkIfAdMobIsAvailable())) return;
if (!checkIfAdMobIsAvailable()) return;
if (!banner || !bannerShowing) {
logger.warn('No banner is being shown.');
@@ -406,7 +381,7 @@ namespace gdjs {
iosAdUnitId,
displayWhenLoaded
) => {
if (!(await checkIfAdMobIsAvailable())) return;
if (!checkIfAdMobIsAvailable()) return;
// If an interstitial is already loading or showing, we don't stop it.
if (interstitialLoading || interstitialShowing) {
return;
@@ -465,7 +440,7 @@ namespace gdjs {
/** Show the loaded interstitial. */
export const showInterstitial = async () => {
if (!(await checkIfAdMobIsAvailable())) return;
if (!checkIfAdMobIsAvailable()) return;
if (!interstitial) {
logger.warn(
@@ -520,7 +495,7 @@ namespace gdjs {
iosAdUnitID,
displayWhenLoaded
) => {
if (!(await checkIfAdMobIsAvailable())) return;
if (!checkIfAdMobIsAvailable()) return;
if (rewardedInterstitialLoading || rewardedInterstitialShowing) {
return;
}
@@ -582,7 +557,7 @@ namespace gdjs {
/** Show the loaded reward interstitial. */
export const showRewardedInterstitial = async () => {
if (!(await checkIfAdMobIsAvailable())) return;
if (!checkIfAdMobIsAvailable()) return;
if (!rewardedInterstitial) {
logger.warn(
@@ -639,7 +614,7 @@ namespace gdjs {
iosAdUnitID,
displayWhenLoaded
) => {
if (!(await checkIfAdMobIsAvailable())) return;
if (!checkIfAdMobIsAvailable()) return;
if (rewardedVideoLoading || rewardedVideoShowing) {
return;
}
@@ -697,7 +672,7 @@ namespace gdjs {
/** Show the loaded reward video. */
export const showRewardedVideo = async () => {
if (!(await checkIfAdMobIsAvailable())) return;
if (!checkIfAdMobIsAvailable()) return;
if (!rewardedVideo) {
logger.warn('Video has not been set up, call loadRewardedVideo first.');

View File

@@ -25,6 +25,7 @@ void AnchorBehavior::InitializeContent(gd::SerializerElement& content) {
content.SetAttribute("useLegacyBottomAndRightAnchors", false);
}
#if defined(GD_IDE_ONLY)
namespace {
gd::String GetAnchorAsString(AnchorBehavior::HorizontalAnchor anchor) {
if (anchor == AnchorBehavior::ANCHOR_HORIZONTAL_WINDOW_LEFT)
@@ -33,8 +34,6 @@ gd::String GetAnchorAsString(AnchorBehavior::HorizontalAnchor anchor) {
return _("Window right");
else if (anchor == AnchorBehavior::ANCHOR_HORIZONTAL_PROPORTIONAL)
return _("Proportional");
else if (anchor == AnchorBehavior::ANCHOR_HORIZONTAL_WINDOW_CENTER)
return _("Window center");
else
return _("No anchor");
}
@@ -46,8 +45,6 @@ gd::String GetAnchorAsString(AnchorBehavior::VerticalAnchor anchor) {
return _("Window bottom");
else if (anchor == AnchorBehavior::ANCHOR_VERTICAL_PROPORTIONAL)
return _("Proportional");
else if (anchor == AnchorBehavior::ANCHOR_VERTICAL_WINDOW_CENTER)
return _("Window center");
else
return _("No anchor");
}
@@ -72,7 +69,6 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
.SetType("Choice")
.AddExtraInfo(_("No anchor"))
.AddExtraInfo(_("Window left"))
.AddExtraInfo(_("Window center"))
.AddExtraInfo(_("Window right"))
.AddExtraInfo(_("Proportional"))
.SetDescription(_("Anchor the left edge of the object on X axis."));
@@ -83,7 +79,6 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
.SetType("Choice")
.AddExtraInfo(_("No anchor"))
.AddExtraInfo(_("Window left"))
.AddExtraInfo(_("Window center"))
.AddExtraInfo(_("Window right"))
.AddExtraInfo(_("Proportional"))
.SetDescription(_("Anchor the right edge of the object on X axis."));
@@ -94,7 +89,6 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
.SetType("Choice")
.AddExtraInfo(_("No anchor"))
.AddExtraInfo(_("Window top"))
.AddExtraInfo(_("Window center"))
.AddExtraInfo(_("Window bottom"))
.AddExtraInfo(_("Proportional"))
.SetDescription(_("Anchor the top edge of the object on Y axis."));
@@ -105,7 +99,6 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
.SetType("Choice")
.AddExtraInfo(_("No anchor"))
.AddExtraInfo(_("Window top"))
.AddExtraInfo(_("Window center"))
.AddExtraInfo(_("Window bottom"))
.AddExtraInfo(_("Proportional"))
.SetDescription(_("Anchor the bottom edge of the object on Y axis."));
@@ -134,8 +127,6 @@ AnchorBehavior::HorizontalAnchor GetHorizontalAnchorFromString(
return AnchorBehavior::ANCHOR_HORIZONTAL_WINDOW_RIGHT;
else if (value == _("Proportional"))
return AnchorBehavior::ANCHOR_HORIZONTAL_PROPORTIONAL;
else if (value == _("Window center"))
return AnchorBehavior::ANCHOR_HORIZONTAL_WINDOW_CENTER;
else
return AnchorBehavior::ANCHOR_HORIZONTAL_NONE;
}
@@ -148,8 +139,6 @@ AnchorBehavior::VerticalAnchor GetVerticalAnchorFromString(
return AnchorBehavior::ANCHOR_VERTICAL_WINDOW_BOTTOM;
else if (value == _("Proportional"))
return AnchorBehavior::ANCHOR_VERTICAL_PROPORTIONAL;
else if (value == _("Window center"))
return AnchorBehavior::ANCHOR_VERTICAL_WINDOW_CENTER;
else
return AnchorBehavior::ANCHOR_VERTICAL_NONE;
}
@@ -183,3 +172,4 @@ bool AnchorBehavior::UpdateProperty(gd::SerializerElement& behaviorContent,
return true;
}
#endif

View File

@@ -3,8 +3,8 @@ GDevelop - Anchor Behavior Extension
Copyright (c) 2016 Victor Levasseur (victorlevasseur52@gmail.com)
This project is released under the MIT License.
*/
#pragma once
#ifndef ANCHORBEHAVIOR_H
#define ANCHORBEHAVIOR_H
#include <vector>
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/Object.h"
@@ -22,16 +22,14 @@ class GD_EXTENSION_API AnchorBehavior : public gd::Behavior {
ANCHOR_HORIZONTAL_NONE = 0,
ANCHOR_HORIZONTAL_WINDOW_LEFT = 1,
ANCHOR_HORIZONTAL_WINDOW_RIGHT = 2,
ANCHOR_HORIZONTAL_PROPORTIONAL = 3,
ANCHOR_HORIZONTAL_WINDOW_CENTER = 4
ANCHOR_HORIZONTAL_PROPORTIONAL = 3
};
enum VerticalAnchor {
ANCHOR_VERTICAL_NONE = 0,
ANCHOR_VERTICAL_WINDOW_TOP = 1,
ANCHOR_VERTICAL_WINDOW_BOTTOM = 2,
ANCHOR_VERTICAL_PROPORTIONAL = 3,
ANCHOR_VERTICAL_WINDOW_CENTER = 4
ANCHOR_VERTICAL_PROPORTIONAL = 3
};
AnchorBehavior() {};
@@ -49,3 +47,5 @@ class GD_EXTENSION_API AnchorBehavior : public gd::Behavior {
virtual void InitializeContent(
gd::SerializerElement& behaviorContent) override;
};
#endif // ANCHORBEHAVIOR_H

View File

@@ -30,6 +30,5 @@ void DeclareAnchorBehaviorExtension(gd::PlatformExtension& extension) {
"CppPlatform/Extensions/AnchorIcon.png",
"AnchorBehavior",
std::make_shared<AnchorBehavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden);
std::make_shared<gd::BehaviorsSharedData>());
}

View File

@@ -4,25 +4,10 @@ Copyright (c) 2013-2016 Florian Rival (Florian.Rival@gmail.com)
*/
namespace gdjs {
const enum HorizontalAnchor {
None = 0,
WindowLeft,
WindowRight,
Proportional,
WindowCenter,
}
const enum VerticalAnchor {
None = 0,
WindowTop,
WindowBottom,
Proportional,
WindowCenter,
}
export class AnchorRuntimeBehavior extends gdjs.RuntimeBehavior {
_relativeToOriginalWindowSize: any;
_leftEdgeAnchor: HorizontalAnchor;
_rightEdgeAnchor: HorizontalAnchor;
_leftEdgeAnchor: any;
_rightEdgeAnchor: any;
_topEdgeAnchor: any;
_bottomEdgeAnchor: any;
_invalidDistances: boolean = true;
@@ -89,25 +74,14 @@ namespace gdjs {
gdjs.AnchorRuntimeBehavior.prototype.doStepPreEvents
) as FloatPoint;
// TODO EBO Make it work with event based objects or hide this behavior for them.
let parentMinX = instanceContainer.getUnrotatedViewportMinX();
let parentMinY = instanceContainer.getUnrotatedViewportMinY();
let parentMaxX = instanceContainer.getUnrotatedViewportMaxX();
let parentMaxY = instanceContainer.getUnrotatedViewportMaxY();
let parentCenterX = (parentMaxX + parentMinX) / 2;
let parentCenterY = (parentMaxY + parentMinY) / 2;
let parentWidth = parentMaxX - parentMinX;
let parentHeight = parentMaxY - parentMinY;
const game = instanceContainer.getGame();
let rendererWidth = game.getGameResolutionWidth();
let rendererHeight = game.getGameResolutionHeight();
const layer = instanceContainer.getLayer(this.owner.getLayer());
if (this._invalidDistances) {
if (this._relativeToOriginalWindowSize) {
parentMinX = instanceContainer.getInitialUnrotatedViewportMinX();
parentMinY = instanceContainer.getInitialUnrotatedViewportMinY();
parentMaxX = instanceContainer.getInitialUnrotatedViewportMaxX();
parentMaxY = instanceContainer.getInitialUnrotatedViewportMaxY();
parentCenterX = (parentMaxX + parentMinX) / 2;
parentCenterY = (parentMaxY + parentMinY) / 2;
parentWidth = parentMaxX - parentMinX;
parentHeight = parentMaxY - parentMinY;
rendererWidth = game.getOriginalWidth();
rendererHeight = game.getOriginalHeight();
}
//Calculate the distances from the window's bounds.
@@ -118,28 +92,49 @@ namespace gdjs {
workingPoint
);
// Left edge
if (this._leftEdgeAnchor === HorizontalAnchor.WindowLeft) {
this._leftEdgeDistance = topLeftPixel[0] - parentMinX;
} else if (this._leftEdgeAnchor === HorizontalAnchor.WindowRight) {
this._leftEdgeDistance = topLeftPixel[0] - parentMaxX;
} else if (this._leftEdgeAnchor === HorizontalAnchor.Proportional) {
this._leftEdgeDistance = (topLeftPixel[0] - parentMinX) / parentWidth;
} else if (this._leftEdgeAnchor === HorizontalAnchor.WindowCenter) {
this._leftEdgeDistance = topLeftPixel[0] - parentCenterX;
//Left edge
if (
this._leftEdgeAnchor ===
AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_LEFT
) {
this._leftEdgeDistance = topLeftPixel[0];
} else {
if (
this._leftEdgeAnchor ===
AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_RIGHT
) {
this._leftEdgeDistance = rendererWidth - topLeftPixel[0];
} else {
if (
this._leftEdgeAnchor ===
AnchorRuntimeBehavior.HorizontalAnchor.PROPORTIONAL
) {
this._leftEdgeDistance = topLeftPixel[0] / rendererWidth;
}
}
}
// Top edge
if (this._topEdgeAnchor === VerticalAnchor.WindowTop) {
this._topEdgeDistance = topLeftPixel[1] - parentMinY;
} else if (this._topEdgeAnchor === VerticalAnchor.WindowBottom) {
this._topEdgeDistance = topLeftPixel[1] - parentMaxY;
} else if (this._topEdgeAnchor === VerticalAnchor.Proportional) {
this._topEdgeDistance = (topLeftPixel[1] - parentMinY) / parentHeight;
} else if (this._topEdgeAnchor === VerticalAnchor.WindowCenter) {
this._topEdgeDistance = topLeftPixel[1] - parentCenterY;
//Top edge
if (
this._topEdgeAnchor ===
AnchorRuntimeBehavior.VerticalAnchor.WINDOW_TOP
) {
this._topEdgeDistance = topLeftPixel[1];
} else {
if (
this._topEdgeAnchor ===
AnchorRuntimeBehavior.VerticalAnchor.WINDOW_BOTTOM
) {
this._topEdgeDistance = rendererHeight - topLeftPixel[1];
} else {
if (
this._topEdgeAnchor ===
AnchorRuntimeBehavior.VerticalAnchor.PROPORTIONAL
) {
this._topEdgeDistance = topLeftPixel[1] / rendererHeight;
}
}
}
// It's fine to reuse workingPoint as topLeftPixel is no longer used.
const bottomRightPixel = layer.convertCoords(
this.owner.getDrawableX() + this.owner.getWidth(),
@@ -148,30 +143,49 @@ namespace gdjs {
workingPoint
);
// Right edge
if (this._rightEdgeAnchor === HorizontalAnchor.WindowLeft) {
this._rightEdgeDistance = bottomRightPixel[0] - parentMinX;
} else if (this._rightEdgeAnchor === HorizontalAnchor.WindowRight) {
this._rightEdgeDistance = bottomRightPixel[0] - parentMaxX;
} else if (this._rightEdgeAnchor === HorizontalAnchor.Proportional) {
this._rightEdgeDistance =
(bottomRightPixel[0] - parentMinX) / parentWidth;
} else if (this._rightEdgeAnchor === HorizontalAnchor.WindowCenter) {
this._rightEdgeDistance = bottomRightPixel[0] - parentCenterX;
//Right edge
if (
this._rightEdgeAnchor ===
AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_LEFT
) {
this._rightEdgeDistance = bottomRightPixel[0];
} else {
if (
this._rightEdgeAnchor ===
AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_RIGHT
) {
this._rightEdgeDistance = rendererWidth - bottomRightPixel[0];
} else {
if (
this._rightEdgeAnchor ===
AnchorRuntimeBehavior.HorizontalAnchor.PROPORTIONAL
) {
this._rightEdgeDistance = bottomRightPixel[0] / rendererWidth;
}
}
}
// Bottom edge
if (this._bottomEdgeAnchor === VerticalAnchor.WindowTop) {
this._bottomEdgeDistance = bottomRightPixel[1] - parentMinY;
} else if (this._bottomEdgeAnchor === VerticalAnchor.WindowBottom) {
this._bottomEdgeDistance = bottomRightPixel[1] - parentMaxY;
} else if (this._bottomEdgeAnchor === VerticalAnchor.Proportional) {
this._bottomEdgeDistance =
(bottomRightPixel[1] - parentMinY) / parentHeight;
} else if (this._bottomEdgeAnchor === VerticalAnchor.WindowCenter) {
this._bottomEdgeDistance = bottomRightPixel[1] - parentCenterY;
//Bottom edge
if (
this._bottomEdgeAnchor ===
AnchorRuntimeBehavior.VerticalAnchor.WINDOW_TOP
) {
this._bottomEdgeDistance = bottomRightPixel[1];
} else {
if (
this._bottomEdgeAnchor ===
AnchorRuntimeBehavior.VerticalAnchor.WINDOW_BOTTOM
) {
this._bottomEdgeDistance = rendererHeight - bottomRightPixel[1];
} else {
if (
this._bottomEdgeAnchor ===
AnchorRuntimeBehavior.VerticalAnchor.PROPORTIONAL
) {
this._bottomEdgeDistance = bottomRightPixel[1] / rendererHeight;
}
}
}
this._invalidDistances = false;
} else {
//Move and resize the object if needed
@@ -180,50 +194,93 @@ namespace gdjs {
let rightPixel = 0;
let bottomPixel = 0;
// Left edge
if (this._leftEdgeAnchor === HorizontalAnchor.WindowLeft) {
leftPixel = parentMinX + this._leftEdgeDistance;
} else if (this._leftEdgeAnchor === HorizontalAnchor.WindowRight) {
leftPixel = parentMaxX + this._leftEdgeDistance;
} else if (this._leftEdgeAnchor === HorizontalAnchor.Proportional) {
leftPixel = parentMinX + this._leftEdgeDistance * parentWidth;
} else if (this._leftEdgeAnchor === HorizontalAnchor.WindowCenter) {
leftPixel = parentCenterX + this._leftEdgeDistance;
//Left edge
if (
this._leftEdgeAnchor ===
AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_LEFT
) {
leftPixel = this._leftEdgeDistance;
} else {
if (
this._leftEdgeAnchor ===
AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_RIGHT
) {
leftPixel = rendererWidth - this._leftEdgeDistance;
} else {
if (
this._leftEdgeAnchor ===
AnchorRuntimeBehavior.HorizontalAnchor.PROPORTIONAL
) {
leftPixel = this._leftEdgeDistance * rendererWidth;
}
}
}
// Top edge
if (this._topEdgeAnchor === VerticalAnchor.WindowTop) {
topPixel = parentMinY + this._topEdgeDistance;
} else if (this._topEdgeAnchor === VerticalAnchor.WindowBottom) {
topPixel = parentMaxY + this._topEdgeDistance;
} else if (this._topEdgeAnchor === VerticalAnchor.Proportional) {
topPixel = parentMinY + this._topEdgeDistance * parentHeight;
} else if (this._topEdgeAnchor === VerticalAnchor.WindowCenter) {
topPixel = parentCenterY + this._topEdgeDistance;
//Top edge
if (
this._topEdgeAnchor ===
AnchorRuntimeBehavior.VerticalAnchor.WINDOW_TOP
) {
topPixel = this._topEdgeDistance;
} else {
if (
this._topEdgeAnchor ===
AnchorRuntimeBehavior.VerticalAnchor.WINDOW_BOTTOM
) {
topPixel = rendererHeight - this._topEdgeDistance;
} else {
if (
this._topEdgeAnchor ===
AnchorRuntimeBehavior.VerticalAnchor.PROPORTIONAL
) {
topPixel = this._topEdgeDistance * rendererHeight;
}
}
}
// Right edge
if (this._rightEdgeAnchor === HorizontalAnchor.WindowLeft) {
rightPixel = parentMinX + this._rightEdgeDistance;
} else if (this._rightEdgeAnchor === HorizontalAnchor.WindowRight) {
rightPixel = parentMaxX + this._rightEdgeDistance;
} else if (this._rightEdgeAnchor === HorizontalAnchor.Proportional) {
rightPixel = parentMinX + this._rightEdgeDistance * parentWidth;
} else if (this._rightEdgeAnchor === HorizontalAnchor.WindowCenter) {
rightPixel = parentCenterX + this._rightEdgeDistance;
//Right edge
if (
this._rightEdgeAnchor ===
AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_LEFT
) {
rightPixel = this._rightEdgeDistance;
} else {
if (
this._rightEdgeAnchor ===
AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_RIGHT
) {
rightPixel = rendererWidth - this._rightEdgeDistance;
} else {
if (
this._rightEdgeAnchor ===
AnchorRuntimeBehavior.HorizontalAnchor.PROPORTIONAL
) {
rightPixel = this._rightEdgeDistance * rendererWidth;
}
}
}
// Bottom edge
if (this._bottomEdgeAnchor === VerticalAnchor.WindowTop) {
bottomPixel = parentMinY + this._bottomEdgeDistance;
} else if (this._bottomEdgeAnchor === VerticalAnchor.WindowBottom) {
bottomPixel = parentMaxY + this._bottomEdgeDistance;
} else if (this._bottomEdgeAnchor === VerticalAnchor.Proportional) {
bottomPixel = parentMinY + this._bottomEdgeDistance * parentHeight;
} else if (this._bottomEdgeAnchor === VerticalAnchor.WindowCenter) {
bottomPixel = parentCenterY + this._bottomEdgeDistance;
//Bottom edge
if (
this._bottomEdgeAnchor ===
AnchorRuntimeBehavior.VerticalAnchor.WINDOW_TOP
) {
bottomPixel = this._bottomEdgeDistance;
} else {
if (
this._bottomEdgeAnchor ===
AnchorRuntimeBehavior.VerticalAnchor.WINDOW_BOTTOM
) {
bottomPixel = rendererHeight - this._bottomEdgeDistance;
} else {
if (
this._bottomEdgeAnchor ===
AnchorRuntimeBehavior.VerticalAnchor.PROPORTIONAL
) {
bottomPixel = this._bottomEdgeDistance * rendererHeight;
}
}
}
// It's fine to reuse workingPoint as topLeftPixel is no longer used.
const topLeftCoord = layer.convertInverseCoords(
leftPixel,
@@ -246,18 +303,27 @@ namespace gdjs {
// Compatibility with GD <= 5.0.133
if (this._useLegacyBottomAndRightAnchors) {
//Move and resize the object according to the anchors
if (this._rightEdgeAnchor !== HorizontalAnchor.None) {
if (
this._rightEdgeAnchor !==
AnchorRuntimeBehavior.HorizontalAnchor.NONE
) {
this.owner.setWidth(right - left);
}
if (this._bottomEdgeAnchor !== VerticalAnchor.None) {
if (
this._bottomEdgeAnchor !== AnchorRuntimeBehavior.VerticalAnchor.NONE
) {
this.owner.setHeight(bottom - top);
}
if (this._leftEdgeAnchor !== HorizontalAnchor.None) {
if (
this._leftEdgeAnchor !== AnchorRuntimeBehavior.HorizontalAnchor.NONE
) {
this.owner.setX(
left + this.owner.getX() - this.owner.getDrawableX()
);
}
if (this._topEdgeAnchor !== VerticalAnchor.None) {
if (
this._topEdgeAnchor !== AnchorRuntimeBehavior.VerticalAnchor.NONE
) {
this.owner.setY(
top + this.owner.getY() - this.owner.getDrawableY()
);
@@ -267,18 +333,25 @@ namespace gdjs {
else {
// Resize if right and left anchors are set
if (
this._rightEdgeAnchor !== HorizontalAnchor.None &&
this._leftEdgeAnchor !== HorizontalAnchor.None
this._rightEdgeAnchor !==
AnchorRuntimeBehavior.HorizontalAnchor.NONE &&
this._leftEdgeAnchor !== AnchorRuntimeBehavior.HorizontalAnchor.NONE
) {
this.owner.setWidth(right - left);
this.owner.setX(left);
} else {
if (this._leftEdgeAnchor !== HorizontalAnchor.None) {
if (
this._leftEdgeAnchor !==
AnchorRuntimeBehavior.HorizontalAnchor.NONE
) {
this.owner.setX(
left + this.owner.getX() - this.owner.getDrawableX()
);
}
if (this._rightEdgeAnchor !== HorizontalAnchor.None) {
if (
this._rightEdgeAnchor !==
AnchorRuntimeBehavior.HorizontalAnchor.NONE
) {
this.owner.setX(
right +
this.owner.getX() -
@@ -289,18 +362,24 @@ namespace gdjs {
}
// Resize if top and bottom anchors are set
if (
this._bottomEdgeAnchor !== VerticalAnchor.None &&
this._topEdgeAnchor !== VerticalAnchor.None
this._bottomEdgeAnchor !==
AnchorRuntimeBehavior.VerticalAnchor.NONE &&
this._topEdgeAnchor !== AnchorRuntimeBehavior.VerticalAnchor.NONE
) {
this.owner.setHeight(bottom - top);
this.owner.setY(top);
} else {
if (this._topEdgeAnchor !== VerticalAnchor.None) {
if (
this._topEdgeAnchor !== AnchorRuntimeBehavior.VerticalAnchor.NONE
) {
this.owner.setY(
top + this.owner.getY() - this.owner.getDrawableY()
);
}
if (this._bottomEdgeAnchor !== VerticalAnchor.None) {
if (
this._bottomEdgeAnchor !==
AnchorRuntimeBehavior.VerticalAnchor.NONE
) {
this.owner.setY(
bottom +
this.owner.getY() -
@@ -314,6 +393,19 @@ namespace gdjs {
}
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}
static HorizontalAnchor = {
NONE: 0,
WINDOW_LEFT: 1,
WINDOW_RIGHT: 2,
PROPORTIONAL: 3,
};
static VerticalAnchor = {
NONE: 0,
WINDOW_TOP: 1,
WINDOW_BOTTOM: 2,
PROPORTIONAL: 3,
};
}
gdjs.registerBehavior(
'AnchorBehavior::AnchorBehavior',

View File

@@ -36,13 +36,6 @@ describe('gdjs.AnchorRuntimeBehavior', function () {
usedExtensionsWithVariablesData: [],
});
const setGameResolutionSizeAndStep = (width, height) => {
runtimeGame.setGameResolutionSize(width, height);
// This method is called by the main loop:
runtimeScene.onGameResolutionResized();
runtimeScene.renderAndStep(1000 / 60);
};
function createObject(behaviorProperties) {
const object = new gdjs.TestRuntimeObject(runtimeScene, {
name: 'obj1',
@@ -74,10 +67,13 @@ describe('gdjs.AnchorRuntimeBehavior', function () {
['rightEdgeAnchor', 'leftEdgeAnchor'].forEach((objectEdge) => {
it(`anchors the ${objectEdge} edge of object to window left (fixed)`, function () {
const object = createObject({ [objectEdge]: 1 });
runtimeGame.setGameResolutionSize(1000, 1000);
object.setPosition(500, 500);
runtimeScene.renderAndStep(1000 / 60);
setGameResolutionSizeAndStep(2000, 2000);
runtimeGame.setGameResolutionSize(2000, 2000);
runtimeScene.renderAndStep(1000 / 60);
expect(object.getX()).to.equal(500);
expect(object.getY()).to.equal(500);
@@ -87,36 +83,29 @@ describe('gdjs.AnchorRuntimeBehavior', function () {
['rightEdgeAnchor', 'leftEdgeAnchor'].forEach((objectEdge) => {
it(`anchors the ${objectEdge} edge of object to window right (fixed)`, function () {
const object = createObject({ [objectEdge]: 2 });
runtimeGame.setGameResolutionSize(1000, 1000);
object.setPosition(500, 500);
runtimeScene.renderAndStep(1000 / 60);
setGameResolutionSizeAndStep(2000, 2000);
runtimeGame.setGameResolutionSize(2000, 2000);
runtimeScene.renderAndStep(1000 / 60);
expect(object.getX()).to.equal(1500);
expect(object.getY()).to.equal(500);
expect(object.getWidth()).to.equal(10);
});
});
['rightEdgeAnchor', 'leftEdgeAnchor'].forEach((objectEdge) => {
it(`anchors the ${objectEdge} edge of object to window center (fixed)`, function () {
const object = createObject({ [objectEdge]: 4 });
object.setPosition(500, 500);
runtimeScene.renderAndStep(1000 / 60);
setGameResolutionSizeAndStep(2000, 2000);
expect(object.getX()).to.equal(1000);
expect(object.getY()).to.equal(500);
expect(object.getWidth()).to.equal(10);
});
});
it('anchors the right and left edge of object (fixed)', function () {
const object = createObject({ leftEdgeAnchor: 1, rightEdgeAnchor: 2 });
runtimeGame.setGameResolutionSize(1000, 1000);
object.setPosition(500, 500);
runtimeScene.renderAndStep(1000 / 60);
setGameResolutionSizeAndStep(2000, 2000);
runtimeGame.setGameResolutionSize(2000, 2000);
runtimeScene.renderAndStep(1000 / 60);
expect(object.getX()).to.equal(500);
expect(object.getY()).to.equal(500);
@@ -125,10 +114,13 @@ describe('gdjs.AnchorRuntimeBehavior', function () {
it('anchors the left edge of object (proportional)', function () {
const object = createObject({ leftEdgeAnchor: 3 });
runtimeGame.setGameResolutionSize(1000, 1000);
object.setPosition(500, 500);
runtimeScene.renderAndStep(1000 / 60);
setGameResolutionSizeAndStep(2000, 2000);
runtimeGame.setGameResolutionSize(2000, 2000);
runtimeScene.renderAndStep(1000 / 60);
expect(object.getX()).to.equal(1000);
expect(object.getY()).to.equal(500);
@@ -140,10 +132,13 @@ describe('gdjs.AnchorRuntimeBehavior', function () {
['topEdgeAnchor', 'bottomEdgeAnchor'].forEach((objectEdge) => {
it(`anchors the ${objectEdge} edge of object to window top (fixed)`, function () {
const object = createObject({ [objectEdge]: 1 });
runtimeGame.setGameResolutionSize(1000, 1000);
object.setPosition(500, 500);
runtimeScene.renderAndStep(1000 / 60);
setGameResolutionSizeAndStep(2000, 2000);
runtimeGame.setGameResolutionSize(2000, 2000);
runtimeScene.renderAndStep(1000 / 60);
expect(object.getX()).to.equal(500);
expect(object.getY()).to.equal(500);
@@ -153,36 +148,29 @@ describe('gdjs.AnchorRuntimeBehavior', function () {
['topEdgeAnchor', 'bottomEdgeAnchor'].forEach((objectEdge) => {
it(`anchors the ${objectEdge} edge of object to window bottom (fixed)`, function () {
const object = createObject({ [objectEdge]: 2 });
runtimeGame.setGameResolutionSize(1000, 1000);
object.setPosition(500, 500);
runtimeScene.renderAndStep(1000 / 60);
setGameResolutionSizeAndStep(2000, 2000);
runtimeGame.setGameResolutionSize(2000, 2000);
runtimeScene.renderAndStep(1000 / 60);
expect(object.getX()).to.equal(500);
expect(object.getY()).to.equal(1500);
expect(object.getWidth()).to.equal(10);
});
});
['topEdgeAnchor', 'bottomEdgeAnchor'].forEach((objectEdge) => {
it(`anchors the ${objectEdge} edge of object to window center (fixed)`, function () {
const object = createObject({ [objectEdge]: 4 });
object.setPosition(500, 500);
runtimeScene.renderAndStep(1000 / 60);
setGameResolutionSizeAndStep(2000, 2000);
expect(object.getX()).to.equal(500);
expect(object.getY()).to.equal(1000);
expect(object.getWidth()).to.equal(10);
});
});
it('anchors the top and bottom edge of object (fixed)', function () {
const object = createObject({ topEdgeAnchor: 1, bottomEdgeAnchor: 2 });
runtimeGame.setGameResolutionSize(1000, 1000);
object.setPosition(500, 500);
runtimeScene.renderAndStep(1000 / 60);
setGameResolutionSizeAndStep(2000, 2000);
runtimeGame.setGameResolutionSize(2000, 2000);
runtimeScene.renderAndStep(1000 / 60);
expect(object.getX()).to.equal(500);
expect(object.getY()).to.equal(500);
@@ -191,10 +179,13 @@ describe('gdjs.AnchorRuntimeBehavior', function () {
it('anchors the top edge of object (proportional)', function () {
const object = createObject({ topEdgeAnchor: 3 });
runtimeGame.setGameResolutionSize(1000, 1000);
object.setPosition(500, 500);
runtimeScene.renderAndStep(1000 / 60);
setGameResolutionSizeAndStep(2000, 2000);
runtimeGame.setGameResolutionSize(2000, 2000);
runtimeScene.renderAndStep(1000 / 60);
expect(object.getX()).to.equal(500);
expect(object.getY()).to.equal(1000);

View File

@@ -34,8 +34,7 @@ void DeclareDestroyOutsideBehaviorExtension(gd::PlatformExtension& extension) {
"CppPlatform/Extensions/destroyoutsideicon.png",
"DestroyOutsideBehavior",
std::make_shared<DestroyOutsideBehavior>(),
std::shared_ptr<gd::BehaviorsSharedData>())
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden);
std::shared_ptr<gd::BehaviorsSharedData>());
aut.AddCondition("ExtraBorder",
_("Additional border"),

View File

@@ -52,7 +52,7 @@ module.exports = {
.setType('number');
adjustmentProperties
.getOrCreate('saturation')
.setValue('1')
.setValue('2')
.setLabel(_('Saturation (between 0 and 5)'))
.setType('number');
adjustmentProperties
@@ -77,7 +77,7 @@ module.exports = {
.setType('number');
adjustmentProperties
.getOrCreate('blue')
.setValue('1')
.setValue('0.6')
.setLabel(_('Blue (between 0 and 5)'))
.setType('number');
adjustmentProperties

View File

@@ -369,36 +369,6 @@ module.exports = {
'gdjs.multiplayerMessageManager.hasCustomMessageBeenReceived'
);
extension
.addExpressionAndConditionAndAction(
'number',
'ObjectsSynchronizationRate',
_('Objects synchronization rate'),
_(
'objects synchronization rate (between 1 and 60, default is 30 times per second)'
),
_('objects synchronization rate'),
_('Advanced'),
'JsPlatform/Extensions/multiplayer.svg'
)
.useStandardParameters(
'number',
gd.ParameterOptions.makeNewOptions().setDescription(_('Sync rate'))
)
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayer.setObjectsSynchronizationRate')
.setGetter('gdjs.multiplayer.getObjectsSynchronizationRate');
extension
.addCondition(
'IsPlayerHost',
@@ -422,13 +392,13 @@ module.exports = {
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayer.isCurrentPlayerHost');
.setFunctionName('gdjs.multiplayer.isPlayerHost');
extension
.addCondition(
'HasAnyPlayerLeft',
_('Any player has left'),
_('Check if any player has left the lobby game.'),
_('Check if any player has left the lobby.'),
_('Any player has left'),
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg',
@@ -447,13 +417,13 @@ module.exports = {
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayerMessageManager.hasAnyPlayerJustLeft');
.setFunctionName('gdjs.multiplayerMessageManager.hasAnyPlayerLeft');
extension
.addCondition(
'HasPlayerLeft',
_('Player has left'),
_('Check if the player has left the lobby game.'),
_('Check if the player has left the lobby.'),
_('Player _PARAM0_ has left'),
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg',
@@ -473,167 +443,7 @@ module.exports = {
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayerMessageManager.hasPlayerJustLeft');
extension
.addExpression(
'LastLeftPlayerNumber',
_('Player number that just left'),
_(
'Returns the player number of the player that has just left the lobby.'
),
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName(
'gdjs.multiplayerMessageManager.getLatestPlayerWhoJustLeft'
);
extension
.addCondition(
'HasAnyPlayerJoined',
_('Any player has joined'),
_('Check if any player has joined the lobby.'),
_('Any player has joined'),
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayerMessageManager.hasAnyPlayerJustJoined');
extension
.addCondition(
'HasPlayerJoined',
_('Player has joined'),
_('Check if the player has joined the lobby.'),
_('Player _PARAM0_ has joined'),
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
.getCodeExtraInformation()
.addParameter('number', _('Player number'), '', false)
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayerMessageManager.hasPlayerJustJoined');
extension
.addExpression(
'LastJoinedPlayerNumber',
_('Player number that just joined'),
_(
'Returns the player number of the player that has just joined the lobby.'
),
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName(
'gdjs.multiplayerMessageManager.getLatestPlayerWhoJustJoined'
);
extension
.addCondition(
'IsMigratingHost',
_('Host is migrating'),
_(
'Check if the host is migrating, in order to adapt the game state (like pausing the game).'
),
_('Host is migrating'),
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayer.isMigratingHost');
extension
.addAction(
'EndLobbyWhenHostLeaves',
_('Configure lobby game to end when host leaves'),
_(
'Configure the lobby game to end when the host leaves. This will trigger the "Lobby game has just ended" condition. (Default behavior is to migrate the host)'
),
_('Configure lobby game to end when host leaves'),
_('Advanced'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
.addParameter('yesorno', _('End lobby game when host leaves'), '', false)
.setHelpPath('/all-features/multiplayer')
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayer.endLobbyWhenHostLeaves');
.setFunctionName('gdjs.multiplayerMessageManager.hasPlayerLeft');
extension
.addStrExpression(
@@ -710,37 +520,6 @@ module.exports = {
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setFunctionName('gdjs.multiplayer.getPlayersInLobbyCount');
extension
.addCondition(
'IsPlayerConnected',
_('Player is connected'),
_('Check if the specified player is connected to the lobby.'),
_('Player _PARAM0_ is connected'),
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
.addParameter(
'number',
_('The position of the player in the lobby (1, 2, ...)'),
'',
false
)
.setHelpPath('/all-features/multiplayer')
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayer.isPlayerConnected');
extension
.addExpressionAndCondition(
'number',
@@ -1086,7 +865,6 @@ module.exports = {
multiplayerObjectBehavior,
sharedData
)
.setQuickCustomizationVisibility(gd.QuickCustomization.Hidden)
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(

File diff suppressed because it is too large Load Diff

View File

@@ -208,10 +208,7 @@ namespace gdjs {
};
const handleChangeVariableOwnerMessagesToSend = function () {
if (
!gdjs.multiplayer.isLobbyGameRunning() ||
!gdjs.multiplayer.isReadyToSendOrReceiveGameUpdateMessages()
) {
if (!gdjs.multiplayer.isLobbyGameRunning()) {
return;
}

View File

@@ -11,8 +11,6 @@ namespace gdjs {
let canLobbyBeClosed = true;
const notificationContainerIds: string[] = [];
export const getDomElementContainer = (
runtimeScene: gdjs.RuntimeScene
): HTMLDivElement | null => {
@@ -389,7 +387,7 @@ namespace gdjs {
// to allow the player to leave the lobby.
setTimeout(() => {
closeContainer.style.visibility = 'inherit';
}, 10000);
}, 5000);
};
/**
@@ -398,12 +396,12 @@ namespace gdjs {
export const displayErrorNotification = function (
runtimeScene: gdjs.RuntimeScene
) {
showNotification({
showNotification(
runtimeScene,
content:
'An error occurred while displaying the game lobbies, please try again.',
type: 'error',
});
'error-notification',
'An error occurred while displaying the game lobbies, please try again.',
'error'
);
};
/**
@@ -413,138 +411,37 @@ namespace gdjs {
runtimeScene: gdjs.RuntimeScene,
playerName: string
) {
showNotification({
showNotification(
runtimeScene,
content: `${playerName} left.`,
type: 'warning',
});
};
/**
* Create, display, and hide a notification when a player joins the game.
*/
export const displayPlayerJoinedNotification = function (
runtimeScene: gdjs.RuntimeScene,
playerName: string
) {
showNotification({
runtimeScene,
content: `${playerName} joined.`,
type: 'success',
});
};
/**
* Create, display, and hide a notification when an error happens on connection.
*/
export const displayConnectionErrorNotification = function (
runtimeScene: gdjs.RuntimeScene
) {
showNotification({
runtimeScene,
content: 'Could not connect to other players.',
type: 'error',
});
'player-left-notification',
`${playerName} has left the game.`,
'warning'
);
};
/**
* Create, display, and hide a notification when a player leaves the game.
*/
export const displayHostMigrationNotification = function (
export const displayConnectionErrorNotification = function (
runtimeScene: gdjs.RuntimeScene
) {
showNotification({
showNotification(
runtimeScene,
content: `Migrating host...`,
type: 'warning',
id: 'migrating-host',
persist: true,
});
};
export const showHostMigrationFinishedNotification = function (
runtimeScene: gdjs.RuntimeScene
) {
removeNotificationAndShiftOthers('migrating-host');
showNotification({
runtimeScene,
content: `Host migrated!`,
type: 'success',
});
};
export const showHostMigrationFailedNotification = function (
runtimeScene: gdjs.RuntimeScene
) {
removeNotificationAndShiftOthers('migrating-host');
showNotification({
runtimeScene,
content: `Host migration failed.`,
type: 'error',
});
};
const removeNotificationAndShiftOthers = function (
notificationContainerId: string
) {
const notification = document.getElementById(notificationContainerId);
if (!notification) {
logger.warn(
`Notification ${notificationContainerId} not found. skipping`
);
return;
}
const index = notificationContainerIds.indexOf(notificationContainerId);
if (index !== -1) {
notificationContainerIds.splice(index, 1);
}
notification.remove();
// Shift the notifications that are below the one that was removed up.
for (let i = index; i < notificationContainerIds.length; i++) {
const notification = document.getElementById(
notificationContainerIds[i]
);
if (!notification) {
logger.error('Notification not found.');
continue;
}
notification.style.top = `${12 + i * 32}px`;
}
'connection-error-notification',
'Could not connect to other players.',
'error'
);
};
/**
* Helper to show a notification to the user, that disappears automatically.
*/
export const showNotification = function ({
runtimeScene,
content,
type,
id,
persist,
}: {
runtimeScene: gdjs.RuntimeScene;
content: string;
type: 'success' | 'warning' | 'error';
id?: string;
persist?: boolean;
}) {
// When we show a notification, we add it below the other ones.
// We also remove the oldest one if there are too many > 5.
if (notificationContainerIds.length > 5) {
const oldestNotificationId = notificationContainerIds.shift();
if (!oldestNotificationId) {
logger.error('No oldest notification ID found.');
return;
}
removeNotificationAndShiftOthers(oldestNotificationId);
}
// We generate a random ID for the notification, so they can stack.
const notificationId =
id || `notification-${Math.random().toString(36).substring(7)}`;
export const showNotification = function (
runtimeScene: gdjs.RuntimeScene,
id: string,
content: string,
type: 'success' | 'warning' | 'error'
) {
const domContainer = runtimeScene
.getGame()
.getRenderer()
@@ -555,7 +452,7 @@ namespace gdjs {
}
const divContainer = document.createElement('div');
divContainer.id = notificationId;
divContainer.id = id;
divContainer.style.position = 'absolute';
divContainer.style.pointerEvents = 'all';
divContainer.style.backgroundColor =
@@ -564,8 +461,7 @@ namespace gdjs {
: type === 'warning'
? '#FFA500'
: '#FF0000';
// Space the notifications vertically, based on how many there are.
divContainer.style.top = `${12 + notificationContainerIds.length * 32}px`;
divContainer.style.top = '12px';
divContainer.style.right = '16px';
divContainer.style.padding = '6px 32px 6px 6px';
// Use zIndex 1 to make sure it is below the iframe.
@@ -600,15 +496,10 @@ namespace gdjs {
loggedText.style.margin = '0px';
divContainer.appendChild(loggedText);
domContainer.appendChild(divContainer);
notificationContainerIds.push(notificationId);
if (persist) {
return;
}
const animationTime = 700;
const notificationTime = 3000;
const notificationTime = 5000;
setTimeout(() => {
try {
divContainer.animate(
@@ -627,7 +518,7 @@ namespace gdjs {
}, notificationTime);
// Use timeout because onanimationend listener does not work.
setTimeout(() => {
removeNotificationAndShiftOthers(notificationId);
divContainer.remove();
}, notificationTime + animationTime);
};

View File

@@ -24,46 +24,48 @@ namespace gdjs {
actionOnPlayerDisconnect: string;
// The last time the object has been synchronized.
// This is to avoid synchronizing the object too often, see _objectMaxSyncRate.
// This is to avoid synchronizing the object too often, see _objectMaxTickRate.
_lastObjectSyncTimestamp: number = 0;
// The number of times per second the object should be synchronized if it keeps changing.
_objectMaxTickRate: number = 60;
// The last time the basic object info has been synchronized.
_lastBasicObjectSyncTimestamp: number = 0;
// The number of times per second the object basic info should be synchronized when it doesn't change.
_objectBasicInfoSyncRate: number = 5;
_objectBasicInfoTickRate: number = 5;
// The last data sent to synchronize the basic info of the object.
_lastSentBasicObjectSyncData: BasicObjectNetworkSyncData | undefined;
// When we know that the basic info of the object has been updated, we can force sending them
// on the max SyncRate for a number of times to ensure they are received, without the need of an acknowledgment.
// on the max tickrate for a number of times to ensure they are received, without the need of an acknowledgment.
_numberOfForcedBasicObjectUpdates: number = 0;
// The last time the variables have been synchronized.
_lastVariablesSyncTimestamp: number = 0;
// The number of times per second the variables should be synchronized.
_variablesSyncRate: number = 1;
_variablesTickRate: number = 1;
// The last data sent to synchronize the variables.
_lastSentVariableSyncData: VariableNetworkSyncData[] | undefined;
// When we know that the variables have been updated, we can force sending them
// on the same syncRate as the object update for a number of times
// on the same tickrate as the object update for a number of times
// to ensure they are received, without the need of an acknowledgment.
_numberOfForcedVariablesUpdates: number = 0;
// The last time the effects have been synchronized.
_lastEffectsSyncTimestamp: number = 0;
// The number of times per second the effects should be synchronized.
_effectsSyncRate: number = 1;
_effectsTickRate: number = 1;
// The last data sent to synchronize the effects.
_lastSentEffectSyncData:
| { [effectName: string]: EffectNetworkSyncData }
| undefined;
// When we know that the effects have been updated, we can force sending them
// on the same syncRate as the object update for a number of times
// on the same tickrate as the object update for a number of times
// to ensure they are received, without the need of an acknowledgment.
_numberOfForcedEffectsUpdates: number = 0;
// To avoid seeing too many logs.
_lastLogTimestamp: number = 0;
_logSyncRate: number = 1;
_logTickRate: number = 1;
// Clock to be incremented every time we send a message, to ensure they are ordered
// and old messages are ignored.
_clock: number = 0;
@@ -90,14 +92,9 @@ namespace gdjs {
// To handle this case and avoid having an object not synchronized, we set a timeout to destroy the object
// if it has not been assigned a networkId after a short delay.
this._destroyInstanceTimeoutId = setTimeout(() => {
const sceneNetworkId = this.owner.getRuntimeScene().networkId;
if (
!owner.networkId &&
gdjs.multiplayer.isLobbyGameRunning() &&
sceneNetworkId
) {
if (!owner.networkId && gdjs.multiplayer.isLobbyGameRunning()) {
debugLogger.info(
`Lobby game is running on a synced scene and object ${owner.getName()} has not been assigned a networkId after a short delay, destroying it.`
`Lobby game is running and object ${owner.getName()} has not been assigned a networkId after a short delay, destroying it.`
);
owner.deleteFromScene(instanceContainer);
}
@@ -129,35 +126,35 @@ namespace gdjs {
}
private _hasObjectBeenSyncedWithinMaxRate() {
const objectMaxSyncRate = gdjs.multiplayer.getObjectsSynchronizationRate();
return (
getTimeNow() - this._lastObjectSyncTimestamp < 1000 / objectMaxSyncRate
getTimeNow() - this._lastObjectSyncTimestamp <
1000 / this._objectMaxTickRate
);
}
private _hasObjectBasicInfoBeenSyncedRecently() {
return (
getTimeNow() - this._lastBasicObjectSyncTimestamp <
1000 / this._objectBasicInfoSyncRate
1000 / this._objectBasicInfoTickRate
);
}
private _haveVariablesBeenSyncedRecently() {
return (
getTimeNow() - this._lastVariablesSyncTimestamp <
1000 / this._variablesSyncRate
1000 / this._variablesTickRate
);
}
private _haveEffectsBeenSyncedRecently() {
return (
getTimeNow() - this._lastEffectsSyncTimestamp <
1000 / this._effectsSyncRate
1000 / this._effectsTickRate
);
}
// private _logToConsoleWithThrottle(message: string) {
// if (getTimeNow() - this._lastLogTimestamp > 1000 / this._logSyncRate) {
// if (getTimeNow() - this._lastLogTimestamp > 1000 / this._logTickRate) {
// logger.info(message);
// this._lastLogTimestamp = getTimeNow();
// }
@@ -165,9 +162,12 @@ namespace gdjs {
private _getOrCreateInstanceNetworkId() {
if (!this.owner.networkId) {
// No ID for this object, let's generate one so it can be identified by other players.
// no ID for this object, let's generate one so it can be identified by other players.
// Either use the persistentUuid if it exists, or generate a new one.
// Keep it short to avoid sending too much data.
const newID = gdjs.makeUuid().substring(0, 8);
const newID = this.owner.persistentUuid
? this.owner.persistentUuid.substring(0, 8)
: gdjs.makeUuid().substring(0, 8);
this.owner.networkId = newID;
}
@@ -250,8 +250,7 @@ namespace gdjs {
return;
}
// If game is running and the object belongs to a player who is not connected, destroy the object.
// As the game may create objects before the lobby game starts, we don't want to destroy them if it's not running.
// If game is running and object belong to a player that is not connected, destroy the object.
if (
this.playerNumber !== 0 && // Host is always connected.
!gdjs.multiplayerMessageManager.isPlayerConnected(this.playerNumber)
@@ -406,17 +405,15 @@ namespace gdjs {
this._destroyInstanceTimeoutId = null;
}
// If the lobby game is not running, no need to send a message to destroy the object.
// If the lobby game is not running, do not try to destroy the object,
// as the game may create objects before the lobby game starts, and we don't want to destroy them.
if (!gdjs.multiplayer.isLobbyGameRunning()) {
return;
}
// For destruction of objects, we allow the host to destroy the object even if it is not the owner.
// This is particularly helpful when a player disconnects, so the host can destroy the object they were owning.
if (
!this._isOwnerAsPlayerOrHost() &&
!gdjs.multiplayer.isCurrentPlayerHost()
) {
if (!this._isOwnerAsPlayerOrHost() && !gdjs.multiplayer.isPlayerHost()) {
return;
}

File diff suppressed because it is too large Load Diff

View File

@@ -254,11 +254,6 @@ namespace gdjs {
connection.on('close', () => {
_onDisconnect(connection.peer);
});
connection.on('iceStateChanged', (state) => {
if (state === 'disconnected') {
_onDisconnect(connection.peer);
}
});
// Regularly check for disconnection as the built in way is not reliable.
(function disconnectChecker() {
@@ -433,7 +428,7 @@ namespace gdjs {
export const isReady = () => ready;
/**
* Return peers that have disconnected in the frame.
* Return any disconnected peers.
*/
export const getJustDisconnectedPeers = () => justDisconnectedPeers;

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