Compare commits
24 Commits
v5.1.157
...
limit-buil
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ba4a37813e | ||
![]() |
3f36054d54 | ||
![]() |
cdfd7a7ab1 | ||
![]() |
a944ac43db | ||
![]() |
b7a1a96e7b | ||
![]() |
29d71796cc | ||
![]() |
78a1361897 | ||
![]() |
e340784ad6 | ||
![]() |
511466f0b8 | ||
![]() |
3f4e372acb | ||
![]() |
a73a92d748 | ||
![]() |
6e131d8a17 | ||
![]() |
9ac4c021e0 | ||
![]() |
a1fbf91ac7 | ||
![]() |
3f8d01e25e | ||
![]() |
03b4170d74 | ||
![]() |
0146ad9c38 | ||
![]() |
fbb23f86cd | ||
![]() |
1fdaeea4f8 | ||
![]() |
32b97f2c40 | ||
![]() |
d61f8336a8 | ||
![]() |
3448cd57fe | ||
![]() |
b7333612aa | ||
![]() |
de82182b37 |
4
.github/workflows/build-storybook.yml
vendored
@@ -57,8 +57,8 @@ jobs:
|
||||
|
||||
- name: Log urls to the Storybook
|
||||
run: |
|
||||
echo "Find the latest Storybook for this branch on http://gdevelop-storybook.s3-website-us-east-1.amazonaws.com/$(git rev-parse --abbrev-ref HEAD)/latest/index.html"
|
||||
echo "Find the Storybook for this commit on http://gdevelop-storybook.s3-website-us-east-1.amazonaws.com/$(git rev-parse --abbrev-ref HEAD)/commit/$(git rev-parse HEAD)/index.html"
|
||||
echo "Find the latest Storybook for this branch on https://gdevelop-storybook.s3.amazonaws.com/$(git rev-parse --abbrev-ref HEAD)/latest/index.html"
|
||||
echo "Find the Storybook for this commit on https://gdevelop-storybook.s3.amazonaws.com/$(git rev-parse --abbrev-ref HEAD)/commit/$(git rev-parse HEAD)/index.html"
|
||||
|
||||
# Publish on Chromatic, only when manually launched (too costly to run on every commit).
|
||||
- name: Publish Storybook to Chromatic
|
||||
|
@@ -406,8 +406,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("ModVarObjet",
|
||||
_("Value of an object variable"),
|
||||
_("Change the value of an object variable."),
|
||||
_("Change number variable"),
|
||||
_("Modify the number value of an object variable."),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
@@ -419,8 +419,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
ParameterOptions::MakeNewOptions());
|
||||
|
||||
obj.AddAction("ModVarObjetTxt",
|
||||
_("Text of an object variable"),
|
||||
_("Change the text of an object variable."),
|
||||
_("Change text variable"),
|
||||
_("Modify the text of an object variable."),
|
||||
_("the text of variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
@@ -432,8 +432,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
ParameterOptions::MakeNewOptions());
|
||||
|
||||
obj.AddAction("SetObjectVariableAsBoolean",
|
||||
_("Boolean value of an object variable"),
|
||||
_("Change the boolean value of an object variable."),
|
||||
_("Change boolean variable"),
|
||||
_("Modify the boolean value of an object variable."),
|
||||
_("Set the boolean value of variable _PARAM1_ of "
|
||||
"_PARAM0_ to _PARAM2_"),
|
||||
_("Variables"),
|
||||
@@ -446,7 +446,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
|
||||
obj.AddAction(
|
||||
"ToggleObjectVariableAsBoolean",
|
||||
_("Toggle the boolean value of an object variable"),
|
||||
_("Toggle boolean variable"),
|
||||
_("Toggles the boolean value of an object variable.") + "\n" +
|
||||
_("If it was true, it will become false, and if it was false "
|
||||
"it will become true."),
|
||||
@@ -461,37 +461,39 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
|
||||
obj.AddCondition("ObjectVariableChildExists",
|
||||
_("Child existence"),
|
||||
_("Check if the specified child of the variable exists."),
|
||||
_("Check if the specified child of the object "
|
||||
"structure variable exists."),
|
||||
_("Child _PARAM2_ of variable _PARAM1_ of _PARAM0_ exists"),
|
||||
_("Variables/Collections/Structures"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("objectvar", _("Structure variable"))
|
||||
.AddParameter("string", _("Name of the child"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("ObjectVariableRemoveChild",
|
||||
_("Remove a child"),
|
||||
_("Remove a child from an object variable."),
|
||||
_("Remove a child from an object structure variable."),
|
||||
_("Remove child _PARAM2_ from variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Collections/Structures"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("objectvar", _("Structure variable"))
|
||||
.AddParameter("string", _("Child's name"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("ObjectVariableClearChildren",
|
||||
_("Clear variable"),
|
||||
_("Remove all the children from the object variable."),
|
||||
_("Clear children"),
|
||||
_("Remove all the children from the object array or structure "
|
||||
"variable."),
|
||||
_("Clear children from variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Collections"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("objectvar", _("Array or structure variable"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("Cache",
|
||||
@@ -619,8 +621,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddCondition("VarObjet",
|
||||
_("Value of an object variable"),
|
||||
_("Compare the value of an object variable."),
|
||||
_("Number variable"),
|
||||
_("Compare the number value of an object variable."),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
@@ -632,7 +634,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"number", ParameterOptions::MakeNewOptions());
|
||||
|
||||
obj.AddCondition("VarObjetTxt",
|
||||
_("Text of an object variable"),
|
||||
_("Text variable"),
|
||||
_("Compare the text of an object variable."),
|
||||
_("the text of variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
@@ -645,7 +647,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"string", ParameterOptions::MakeNewOptions());
|
||||
|
||||
obj.AddCondition("ObjectVariableAsBoolean",
|
||||
_("Boolean value of an object variable"),
|
||||
_("Boolean variable"),
|
||||
_("Compare the boolean value of an object variable."),
|
||||
_("The boolean value of variable _PARAM1_ of object "
|
||||
"_PARAM0_ is _PARAM2_"),
|
||||
@@ -659,7 +661,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
|
||||
obj.AddCondition("VarObjetDef",
|
||||
"Variable defined",
|
||||
"Check if the variable is defined.",
|
||||
"Check if the object variable is defined.",
|
||||
"Variable _PARAM1 of _PARAM0_ is defined",
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
@@ -667,78 +669,131 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("string", _("Variable"))
|
||||
.SetHidden();
|
||||
.SetHidden(); // Deprecated.
|
||||
|
||||
obj.AddAction(
|
||||
"ObjectVariablePush",
|
||||
_("Append variable to an object array"),
|
||||
_("Appends a variable to the end of an object array variable."),
|
||||
_("Append variable _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Collections/Arrays"),
|
||||
_("Add existing variable"),
|
||||
_("Adds an existing variable to the end of an object array variable."),
|
||||
_("Add variable _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("scenevar", _("Scene variable with the content to append"))
|
||||
.SetParameterLongDescription(
|
||||
_("The content of the variable will *be copied* and appended at the "
|
||||
"end of the array."))
|
||||
.AddParameter("scenevar", _("Scene variable with the content to add"))
|
||||
.SetParameterLongDescription(_("The content of the object variable will "
|
||||
"*be copied* and added at the "
|
||||
"end of the array."))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction(
|
||||
"ObjectVariablePushString",
|
||||
_("Append a string to an object array"),
|
||||
_("Appends a string to the end of an object array variable."),
|
||||
_("Append string _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Collections/Arrays"),
|
||||
_("Add text variable"),
|
||||
_("Adds a text (string) to the end of an object array variable."),
|
||||
_("Add text _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("string", _("String to append"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction(
|
||||
"ObjectVariablePushNumber",
|
||||
_("Append a number to an object array"),
|
||||
_("Appends a number to the end of an object array variable."),
|
||||
_("Append number _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Collections/Arrays"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
obj.AddAction("ObjectVariablePushNumber",
|
||||
_("Add number variable"),
|
||||
_("Adds a number to the end of an object array variable."),
|
||||
_("Add number _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to append"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction(
|
||||
"ObjectVariablePushBool",
|
||||
_("Append a boolean to an object array"),
|
||||
_("Appends a boolean to the end of an object array variable."),
|
||||
_("Append boolean _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Collections/Arrays"),
|
||||
_("Add boolean variable"),
|
||||
_("Adds a boolean to the end of an object array variable."),
|
||||
_("Add boolean _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to append"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction(
|
||||
"ObjectVariableRemoveAt",
|
||||
_("Remove variable from an object array (by index)"),
|
||||
_("Remove variable by index"),
|
||||
_("Removes a variable at the specified index of an object array "
|
||||
"variable."),
|
||||
_("Remove variable at index _PARAM2_ from array variable _PARAM1_ of "
|
||||
"_PARAM0_"),
|
||||
_("Variables/Collections/Arrays"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Index to remove"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddCondition(
|
||||
"ObjectVariableChildCount",
|
||||
_("Number of children"),
|
||||
_("Compare the number of children in an object array variable."),
|
||||
_("The number of children in the array variable _PARAM1_"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddStrExpression(
|
||||
"ArrayVariableFirstString",
|
||||
_("First text child"),
|
||||
_("Get the value of the first element of an object array variable, if "
|
||||
"it is a text (string) variable."),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"));
|
||||
|
||||
obj.AddExpression(
|
||||
"ArrayVariableFirstNumber",
|
||||
_("First number child"),
|
||||
_("Get the value of the first element of an object array variable, if "
|
||||
"it is a number variable."),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"));
|
||||
|
||||
obj.AddStrExpression(
|
||||
"ArrayVariableLastString",
|
||||
_("Last text child"),
|
||||
_("Get the value of the last element of an object array variable, if "
|
||||
"it is a text (string) variable."),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"));
|
||||
|
||||
obj.AddExpression(
|
||||
"ArrayVariableLastNumber",
|
||||
_("Last number child"),
|
||||
_("Get the value of the last element of an object array variable, if "
|
||||
"it is a number variable."),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"));
|
||||
|
||||
obj.AddCondition("BehaviorActivated",
|
||||
_("Behavior activated"),
|
||||
_("Check if the behavior is activated for the object."),
|
||||
@@ -1115,23 +1170,24 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("expression", _("Target Y position"));
|
||||
|
||||
obj.AddExpression("Variable",
|
||||
_("Value of an object variable"),
|
||||
_("Value of an object variable"),
|
||||
_("Number variable"),
|
||||
_("Number value of an object variable"),
|
||||
_("Variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"));
|
||||
|
||||
obj.AddExpression("VariableChildCount",
|
||||
_("Number of children of an object variable"),
|
||||
_("Number of children of an object variable"),
|
||||
_("Variables"),
|
||||
"res/actions/var.png")
|
||||
obj.AddExpression(
|
||||
"VariableChildCount",
|
||||
_("Number of children"),
|
||||
_("Number of children in an object array or structure variable"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"));
|
||||
.AddParameter("objectvar", _("Array or structure variable"));
|
||||
|
||||
obj.AddStrExpression("VariableString",
|
||||
_("Text of an object variable"),
|
||||
_("Text variable"),
|
||||
_("Text of an object variable"),
|
||||
_("Variables"),
|
||||
"res/actions/var.png")
|
||||
@@ -1293,7 +1349,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/actions/create24.png",
|
||||
"res/actions/create24.png")
|
||||
.AddCodeOnlyParameter("objectsContext", "")
|
||||
.AddParameter("objectListOrEmptyIfJustDeclared", _("Group of potential objects"))
|
||||
.AddParameter("objectListOrEmptyIfJustDeclared",
|
||||
_("Group of potential objects"))
|
||||
.SetParameterLongDescription(
|
||||
_("Group containing objects that can be created by the action."))
|
||||
.AddParameter("string", _("Name of the object to create"))
|
||||
|
@@ -27,9 +27,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
|
||||
extension
|
||||
.AddCondition("VarScene",
|
||||
_("Value of a scene variable"),
|
||||
_("Compare the value of a scene variable."),
|
||||
_("the scene variable _PARAM0_"),
|
||||
_("Number variable"),
|
||||
_("Compare the number value of a scene variable."),
|
||||
_("The number of scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
@@ -39,9 +39,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
|
||||
extension
|
||||
.AddCondition("VarSceneTxt",
|
||||
_("Text of a scene variable"),
|
||||
_("Compare the text of a scene variable."),
|
||||
_("the text of scene variable _PARAM0_"),
|
||||
_("Text variable"),
|
||||
_("Compare the text (string) of a scene variable."),
|
||||
_("The text of scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
@@ -52,7 +52,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
extension
|
||||
.AddCondition(
|
||||
"SceneVariableAsBoolean",
|
||||
_("Boolean value of a scene variable"),
|
||||
_("Boolean variable"),
|
||||
_("Compare the boolean value of a scene variable."),
|
||||
_("The boolean value of scene variable _PARAM0_ is _PARAM1_"),
|
||||
_("Scene variables"),
|
||||
@@ -63,14 +63,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
.SetDefaultValue("true");
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"VariableChildExists",
|
||||
_("Child existence"),
|
||||
_("Check if the specified child of the scene variable exists."),
|
||||
_("Child _PARAM1_ of scene variable _PARAM0_ exists"),
|
||||
_("Scene variables/Collections/Structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddCondition("VariableChildExists",
|
||||
_("Child existence"),
|
||||
_("Check if the specified child of the scene structure "
|
||||
"variable exists."),
|
||||
_("Child _PARAM1_ of scene variable _PARAM0_ exists"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddParameter("string", _("Name of the child"))
|
||||
.MarkAsAdvanced();
|
||||
@@ -78,10 +78,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
extension
|
||||
.AddCondition("GlobalVariableChildExists",
|
||||
_("Child existence"),
|
||||
_("Check if the specified child of the global "
|
||||
_("Check if the specified child of the global structure "
|
||||
"variable exists."),
|
||||
_("Child _PARAM1_ of global variable _PARAM0_ exists"),
|
||||
_("Global variables/Collections/Structures"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
@@ -90,7 +90,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
|
||||
extension
|
||||
.AddCondition("VarSceneDef",
|
||||
"Test if a scene variable is defined",
|
||||
"Variable defined",
|
||||
"Test if the scene variable exists.",
|
||||
"Scene variable _PARAM0_ is defined",
|
||||
_("Scene variables"),
|
||||
@@ -98,12 +98,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
"res/conditions/var.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("string", _("Variable"))
|
||||
.SetHidden();
|
||||
.SetHidden(); // Deprecated.
|
||||
|
||||
extension
|
||||
.AddCondition("VarGlobal",
|
||||
_("Value of a global variable"),
|
||||
_("Compare the value of a global variable."),
|
||||
_("Number variable"),
|
||||
_("Compare the number value of a global variable."),
|
||||
_("the global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
@@ -115,8 +115,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
|
||||
extension
|
||||
.AddCondition("VarGlobalTxt",
|
||||
_("Text of a global variable"),
|
||||
_("Compare the text of a global variable."),
|
||||
_("Text variable"),
|
||||
_("Compare the text (string) of a global variable."),
|
||||
_("the text of the global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
@@ -129,7 +129,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
extension
|
||||
.AddCondition(
|
||||
"GlobalVariableAsBoolean",
|
||||
_("Boolean value of a global variable"),
|
||||
_("Boolean variable"),
|
||||
_("Compare the boolean value of a global variable."),
|
||||
_("The boolean value of global variable _PARAM0_ is _PARAM1_"),
|
||||
_("Global variables"),
|
||||
@@ -141,8 +141,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
|
||||
extension
|
||||
.AddCondition("VarGlobalDef",
|
||||
"Test if a global variable is defined",
|
||||
"Test if a global variable exists",
|
||||
"Variable defined",
|
||||
"Test if a global variable exists.",
|
||||
"Global variable _PARAM0_ is defined",
|
||||
_("Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
@@ -150,12 +150,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("string", _("Variable"))
|
||||
.MarkAsAdvanced()
|
||||
.SetHidden();
|
||||
.SetHidden(); // Deprecated.
|
||||
|
||||
extension
|
||||
.AddAction("ModVarScene",
|
||||
_("Value of a scene variable"),
|
||||
_("Change the value of a scene variable."),
|
||||
_("Change number variable"),
|
||||
_("Modify the number value of a scene variable."),
|
||||
_("the scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
"res/actions/var24.png",
|
||||
@@ -166,8 +166,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
|
||||
extension
|
||||
.AddAction("ModVarSceneTxt",
|
||||
_("String of a scene variable"),
|
||||
_("Modify the text of a scene variable."),
|
||||
_("Change text variable"),
|
||||
_("Modify the text (string) of a scene variable."),
|
||||
_("the text of scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
"res/actions/var24.png",
|
||||
@@ -179,7 +179,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
extension
|
||||
.AddAction(
|
||||
"SetSceneVariableAsBoolean",
|
||||
_("Boolean value of a scene variable"),
|
||||
_("Change boolean variable"),
|
||||
_("Modify the boolean value of a scene variable."),
|
||||
_("Set the boolean value of scene variable _PARAM0_ to _PARAM1_"),
|
||||
_("Scene variables"),
|
||||
@@ -190,7 +190,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
|
||||
extension
|
||||
.AddAction("ToggleSceneVariableAsBoolean",
|
||||
_("Toggle boolean value of a scene variable"),
|
||||
_("Toggle boolean variable"),
|
||||
_("Toggle the boolean value of a scene variable.") + "\n" +
|
||||
_("If it was true, it will become false, and if it was "
|
||||
"false it will become true."),
|
||||
@@ -202,8 +202,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
|
||||
extension
|
||||
.AddAction("ModVarGlobal",
|
||||
_("Value of a global variable"),
|
||||
_("Change the value of a global variable"),
|
||||
_("Change number variable"),
|
||||
_("Modify the number value of a global variable."),
|
||||
_("the global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
"res/actions/var24.png",
|
||||
@@ -215,8 +215,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
|
||||
extension
|
||||
.AddAction("ModVarGlobalTxt",
|
||||
_("String of a global variable"),
|
||||
_("Modify the text of a global variable."),
|
||||
_("Change text variable"),
|
||||
_("Modify the text (string) of a global variable."),
|
||||
_("the text of global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
"res/actions/var24.png",
|
||||
@@ -229,7 +229,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
extension
|
||||
.AddAction(
|
||||
"SetGlobalVariableAsBoolean",
|
||||
_("Boolean value of a global variable"),
|
||||
_("Change boolean variable"),
|
||||
_("Modify the boolean value of a global variable."),
|
||||
_("Set the boolean value of global variable _PARAM0_ to _PARAM1_"),
|
||||
_("Global variables"),
|
||||
@@ -240,7 +240,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
|
||||
extension
|
||||
.AddAction("ToggleGlobalVariableAsBoolean",
|
||||
_("Toggle boolean value of a global variable"),
|
||||
_("Toggle boolean variable"),
|
||||
_("Toggle the boolean value of a global variable.") + "\n" +
|
||||
_("If it was true, it will become false, and if it was "
|
||||
"false it will become true."),
|
||||
@@ -251,202 +251,324 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
.AddParameter("globalvar", _("Variable"));
|
||||
|
||||
extension
|
||||
.AddAction("VariableRemoveChild",
|
||||
_("Remove a child"),
|
||||
_("Remove a child from a scene variable."),
|
||||
_("Remove child _PARAM1_ from scene variable _PARAM0_"),
|
||||
_("Scene variables/Collections/Structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddAction(
|
||||
"VariableRemoveChild",
|
||||
_("Remove a child"),
|
||||
_("Remove a child from a scene structure variable."),
|
||||
_("Remove child _PARAM1_ from scene structure variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Structure variable"))
|
||||
.AddParameter("string", _("Child's name"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("GlobalVariableRemoveChild",
|
||||
_("Remove a child"),
|
||||
_("Remove a child from a global variable."),
|
||||
_("Remove child _PARAM1_ from global variable _PARAM0_"),
|
||||
_("Global variables/Collections/Structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddAction(
|
||||
"GlobalVariableRemoveChild",
|
||||
_("Remove a child"),
|
||||
_("Remove a child from a global structure variable."),
|
||||
_("Remove child _PARAM1_ from global structure variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Structure variable"))
|
||||
.AddParameter("string", _("Child's name"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("VariableClearChildren",
|
||||
_("Clear scene variable"),
|
||||
_("Remove all the children from the scene variable."),
|
||||
_("Clear children"),
|
||||
_("Remove all the children from the scene structure or array "
|
||||
"variable."),
|
||||
_("Clear children from scene variable _PARAM0_"),
|
||||
_("Scene variables/Collections"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddParameter("scenevar", _("Structure or array variable"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("GlobalVariableClearChildren",
|
||||
_("Clear global variable"),
|
||||
_("Remove all the children from the global variable."),
|
||||
_("Clear children"),
|
||||
_("Remove all the children from the global structure or array "
|
||||
"variable."),
|
||||
_("Clear children from global variable _PARAM0_"),
|
||||
_("Global variables/Collections"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddParameter("globalvar", _("Structure or array variable"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("SceneVariablePush",
|
||||
_("Append variable to a scene array"),
|
||||
_("Appends a variable at the end of a scene array variable."),
|
||||
_("Append variable _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Collections/Arrays"),
|
||||
_("Add existing variable"),
|
||||
_("Adds an existing variable at the end of a scene array "
|
||||
"variable."),
|
||||
_("Add variable _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("scenevar", _("Scene variable with the content to append"))
|
||||
.SetParameterLongDescription(_("The content of the variable will *be copied* and appended at the end of the array."))
|
||||
.AddParameter("scenevar", _("Scene variable with the content to add"))
|
||||
.SetParameterLongDescription(
|
||||
_("The content of the variable will *be copied* and added at the "
|
||||
"end of the array."))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("SceneVariablePushString",
|
||||
_("Append a string to a scene array"),
|
||||
_("Appends a string at the end of a scene array variable."),
|
||||
_("Append string _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Collections/Arrays"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddAction(
|
||||
"SceneVariablePushString",
|
||||
_("Add text variable"),
|
||||
_("Adds a text (string) at the end of a scene array variable."),
|
||||
_("Add text _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("string", _("String to append"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("SceneVariablePushNumber",
|
||||
_("Append a number to a scene array"),
|
||||
_("Appends a number at the end of a scene array variable."),
|
||||
_("Append number _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Collections/Arrays"),
|
||||
_("Add number variable"),
|
||||
_("Adds a number at the end of a scene array variable."),
|
||||
_("Add number _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to append"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("SceneVariablePushBool",
|
||||
_("Append a boolean to a scene array"),
|
||||
_("Appends a boolean at the end of a scene array variable."),
|
||||
_("Append boolean _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Collections/Arrays"),
|
||||
_("Add boolean variable"),
|
||||
_("Adds a boolean at the end of a scene array variable."),
|
||||
_("Add boolean _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to append"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"SceneVariableRemoveAt",
|
||||
_("Remove variable from a scene array (by index)"),
|
||||
_("Removes a variable at the specified index of a scene array variable."),
|
||||
_("Remove variable at index _PARAM1_ from scene array variable _PARAM0_"),
|
||||
_("Scene variables/Collections/Arrays"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddAction("SceneVariableRemoveAt",
|
||||
_("Remove variable by index"),
|
||||
_("Removes a variable at the specified index of a scene array "
|
||||
"variable."),
|
||||
_("Remove variable at index _PARAM1_ from scene array "
|
||||
"variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("expression", _("Index to remove"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("GlobalVariablePush",
|
||||
_("Append variable to a global array"),
|
||||
_("Appends a variable at the end of a global array variable."),
|
||||
_("Append variable _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Collections/Arrays"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("scenevar", _("Scene variable with the content to append"))
|
||||
.SetParameterLongDescription(_("The content of the variable will *be copied* and appended at the end of the array."))
|
||||
.AddCondition(
|
||||
"SceneVariableChildCount",
|
||||
_("Number of children"),
|
||||
_("Compare the number of children in a scene array variable."),
|
||||
_("The number of children in the array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddStrExpression(
|
||||
"SceneVariableFirstString",
|
||||
_("First text child"),
|
||||
_("Get the value of the first element of a scene array variable, if "
|
||||
"it is a text (string)."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
"SceneVariableFirstNumber",
|
||||
_("First number child"),
|
||||
_("Get the value of the first element of a scene array variable, if "
|
||||
"it is a number."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
|
||||
extension
|
||||
.AddStrExpression(
|
||||
"SceneVariableLastString",
|
||||
_("Last text child"),
|
||||
_("Get the value of the last element of a scene array variable, if "
|
||||
"it is a text (string)."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
"SceneVariableLastNumber",
|
||||
_("Last number child"),
|
||||
_("Get the value of the last element of a scene array variable, if "
|
||||
"it is a number."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"GlobalVariableRemoveAt",
|
||||
_("Remove variable from a global array (by index)"),
|
||||
_("Removes a variable at the specified index of a global array variable."),
|
||||
_("Remove variable at index _PARAM1_ from global array variable _PARAM0_"),
|
||||
_("Global variables/Collections/Arrays"),
|
||||
"GlobalVariablePush",
|
||||
_("Add existing variable"),
|
||||
_("Adds an existing variable at the end of a global array variable."),
|
||||
_("Add variable _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("scenevar", _("Scene variable with the content to add"))
|
||||
.SetParameterLongDescription(
|
||||
_("The content of the variable will *be copied* and added at the "
|
||||
"end of the array."))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("GlobalVariableRemoveAt",
|
||||
_("Remove variable by index"),
|
||||
_("Removes a variable at the specified index of a global "
|
||||
"array variable."),
|
||||
_("Remove variable at index _PARAM1_ from global array "
|
||||
"variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Index to remove"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("GlobalVariablePushString",
|
||||
_("Append a string to a global array"),
|
||||
_("Appends a string at the end of a global array variable."),
|
||||
_("Append string _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Collections/Arrays"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddAction(
|
||||
"GlobalVariablePushString",
|
||||
_("Add text variable"),
|
||||
_("Adds a text (string) at the end of a global array variable."),
|
||||
_("Add text _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("string", _("String to append"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("GlobalVariablePushNumber",
|
||||
_("Append a number to a global array"),
|
||||
_("Appends a number at the end of a global array variable."),
|
||||
_("Append number _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Collections/Arrays"),
|
||||
_("Add number variable"),
|
||||
_("Adds a number at the end of a global array variable."),
|
||||
_("Add number _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to append"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("GlobalVariablePushBool",
|
||||
_("Append a boolean to a global array"),
|
||||
_("Appends a boolean at the end of a global array variable."),
|
||||
_("Append boolean _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Collections/Arrays"),
|
||||
_("Add boolean variable"),
|
||||
_("Adds a boolean at the end of a global array variable."),
|
||||
_("Add boolean _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to append"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddExpression("GlobalVariableChildCount",
|
||||
_("Number of children of a global variable"),
|
||||
_("Number of children of a global variable"),
|
||||
_("Global variables"),
|
||||
.AddCondition(
|
||||
"GlobalVariableChildCount",
|
||||
_("Number of children"),
|
||||
_("Compare the number of children in a global array variable."),
|
||||
_("The number of children of the array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddStrExpression("GlobalVariableFirstString",
|
||||
_("First text child"),
|
||||
_("Value of the first element of a global array "
|
||||
"variable, if it is a text (string) variable."),
|
||||
_("Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
|
||||
extension
|
||||
.AddExpression("GlobalVariableFirstNumber",
|
||||
_("First number child"),
|
||||
_("Value of the first element of a global array "
|
||||
"variable, if it is a number variable"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"));
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
|
||||
extension
|
||||
.AddStrExpression(
|
||||
"GlobalVariableLastString",
|
||||
_("Last text child"),
|
||||
_("Value of the last element of a global array variable, if "
|
||||
"it is a text (string) variable."),
|
||||
_("Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
"GlobalVariableLastNumber",
|
||||
_("Last number child"),
|
||||
_("Value of the last element of a global array variable, if "
|
||||
"it is a number variable"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
|
||||
extension
|
||||
.AddExpression("GlobalVariableChildCount",
|
||||
_("Number of children"),
|
||||
_("Number of children in a global array or "
|
||||
"structure variable"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array or structure variable"));
|
||||
|
||||
extension
|
||||
.AddExpression("VariableChildCount",
|
||||
_("Number of children of a scene variable"),
|
||||
_("Number of children of a scene variable"),
|
||||
_("Scene variables"),
|
||||
_("Number of children"),
|
||||
_("Number of children in a scene array or "
|
||||
"structure variable"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"));
|
||||
.AddParameter("scenevar", _("Array or structure variable"));
|
||||
|
||||
extension
|
||||
.AddExpression("Variable",
|
||||
_("Value of a scene variable"),
|
||||
_("Value of a scene variable"),
|
||||
_("Number variable"),
|
||||
_("Number value of a scene variable"),
|
||||
_("Scene variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"));
|
||||
|
||||
extension
|
||||
.AddStrExpression("VariableString",
|
||||
_("Text of a scene variable"),
|
||||
_("Text variable"),
|
||||
_("Text of a scene variable"),
|
||||
_("Scene variables"),
|
||||
"res/actions/var.png")
|
||||
@@ -454,15 +576,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
|
||||
extension
|
||||
.AddExpression("GlobalVariable",
|
||||
_("Value of a global variable"),
|
||||
_("Value of a global variable"),
|
||||
_("Number variable"),
|
||||
_("Number value of a global variable"),
|
||||
_("Global variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Name of the global variable"));
|
||||
|
||||
extension
|
||||
.AddStrExpression("GlobalVariableString",
|
||||
_("Text of a global variable"),
|
||||
_("Text variable"),
|
||||
_("Text of a global variable"),
|
||||
_("Global variables"),
|
||||
"res/actions/var.png")
|
||||
|
@@ -24,23 +24,23 @@ const variable = new gdjs.Variable().fromJSObject({
|
||||
it: ['is', true],
|
||||
});
|
||||
|
||||
/**
|
||||
* A firebase configuration of a project made only for those tests.
|
||||
*/
|
||||
const firebaseConfig = {
|
||||
apiKey: 'AIzaSyBwPnGpfEBXDjwQrWfU0wqgp4m9qEt7YM8',
|
||||
authDomain: 'gdtest-e11a5.firebaseapp.com',
|
||||
databaseURL: 'https://gdtest-e11a5.firebaseio.com',
|
||||
projectId: 'gdtest-e11a5',
|
||||
storageBucket: 'gdtest-e11a5.appspot.com',
|
||||
messagingSenderId: '254035412678',
|
||||
appId: '1:254035412678:web:2ddd6b83019b7f259b79c7',
|
||||
measurementId: 'G-4REML26L59',
|
||||
};
|
||||
|
||||
// The tests require an internet connection, as a real Firebase instance is used.
|
||||
const describeIfOnline = navigator.onLine ? describe : describe.skip;
|
||||
describeIfOnline('Firebase extension end-to-end tests', function () {
|
||||
/**
|
||||
* A firebase configuration of a project made only for those tests.
|
||||
*/
|
||||
const firebaseConfig = {
|
||||
apiKey: 'AIzaSyBwPnGpfEBXDjwQrWfU0wqgp4m9qEt7YM8',
|
||||
authDomain: 'gdtest-e11a5.firebaseapp.com',
|
||||
databaseURL: 'https://gdtest-e11a5.firebaseio.com',
|
||||
projectId: 'gdtest-e11a5',
|
||||
storageBucket: 'gdtest-e11a5.appspot.com',
|
||||
messagingSenderId: '254035412678',
|
||||
appId: '1:254035412678:web:2ddd6b83019b7f259b79c7',
|
||||
measurementId: 'G-4REML26L59',
|
||||
};
|
||||
|
||||
// Increase the timeout to work on low connections as well.
|
||||
this.timeout('5s');
|
||||
|
||||
@@ -48,8 +48,8 @@ describeIfOnline('Firebase extension end-to-end tests', function () {
|
||||
.toString()
|
||||
.replace('.', '-')}-${Date.now()}`;
|
||||
|
||||
before(function setupFirebase() {
|
||||
gdjs.evtTools.firebaseTools._setupFirebase({
|
||||
before(async function setupFirebase() {
|
||||
await gdjs.evtTools.firebaseTools._setupFirebase({
|
||||
getGame: () => ({
|
||||
getExtensionProperty: () => JSON.stringify(firebaseConfig),
|
||||
}),
|
||||
|
@@ -1294,9 +1294,8 @@ module.exports = {
|
||||
tilemapJsonFile,
|
||||
tilesetJsonFile
|
||||
) {
|
||||
let tileMapJsonData = null;
|
||||
try {
|
||||
tileMapJsonData = await this._pixiResourcesLoader.getResourceJsonData(
|
||||
const tileMapJsonData = await this._pixiResourcesLoader.getResourceJsonData(
|
||||
this._project,
|
||||
tilemapJsonFile
|
||||
);
|
||||
@@ -1320,6 +1319,7 @@ module.exports = {
|
||||
} catch (err) {
|
||||
console.error('Unable to load a Tilemap JSON data: ', err);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1540,34 +1540,38 @@ module.exports = {
|
||||
// GDJS doesn't use Promise to avoid allocation.
|
||||
RenderedCollisionMaskInstance.prototype._loadTiledMapWithCallback =
|
||||
function (tilemapJsonFile, tilesetJsonFile, callback) {
|
||||
this._loadTiledMap(tilemapJsonFile, tilesetJsonFile).then(callback);
|
||||
this._loadTileMap(tilemapJsonFile, tilesetJsonFile).then(callback);
|
||||
};
|
||||
|
||||
RenderedCollisionMaskInstance.prototype._loadTiledMap = async function (
|
||||
RenderedCollisionMaskInstance.prototype._loadTileMap = async function (
|
||||
tilemapJsonFile,
|
||||
tilesetJsonFile
|
||||
) {
|
||||
let tileMapJsonData = null;
|
||||
try {
|
||||
tileMapJsonData = await this._pixiResourcesLoader.getResourceJsonData(
|
||||
const tileMapJsonData = await this._pixiResourcesLoader.getResourceJsonData(
|
||||
this._project,
|
||||
tilemapJsonFile
|
||||
);
|
||||
|
||||
const tilesetJsonData = tilesetJsonFile
|
||||
? await this._pixiResourcesLoader.getResourceJsonData(
|
||||
this._project,
|
||||
tilesetJsonFile
|
||||
)
|
||||
: null;
|
||||
const tileMap = TilemapHelper.TileMapManager.identify(tileMapJsonData);
|
||||
|
||||
if (tilesetJsonData) {
|
||||
tileMapJsonData.tilesets = [tilesetJsonData];
|
||||
if (tileMap.kind === 'tiled') {
|
||||
const tilesetJsonData = tilesetJsonFile
|
||||
? await this._pixiResourcesLoader.getResourceJsonData(
|
||||
this._project,
|
||||
tilesetJsonFile
|
||||
)
|
||||
: null;
|
||||
|
||||
if (tilesetJsonData) {
|
||||
tileMapJsonData.tilesets = [tilesetJsonData];
|
||||
}
|
||||
}
|
||||
return tileMap;
|
||||
} catch (err) {
|
||||
console.error('Unable to load a Tilemap JSON data: ', err);
|
||||
}
|
||||
return tileMapJsonData;
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -67,7 +67,9 @@ namespace gdjs {
|
||||
tileMapJsonResourceName: string,
|
||||
tileSetJsonResourceName: string,
|
||||
levelIndex: number,
|
||||
callback: (tileMap: TileMapHelper.EditableTileMap | null) => void
|
||||
callback: (
|
||||
tileMapFileContent: TileMapHelper.EditableTileMap | null
|
||||
) => void
|
||||
): void {
|
||||
this._manager.getOrLoadTileMap(
|
||||
this._loadTileMap.bind(this),
|
||||
@@ -113,7 +115,9 @@ namespace gdjs {
|
||||
private _loadTileMap(
|
||||
tileMapJsonResourceName: string,
|
||||
tileSetJsonResourceName: string,
|
||||
callback: (tileMap: TileMapHelper.TileMap | null) => void
|
||||
callback: (
|
||||
tileMapFileContent: TileMapHelper.TileMapFileContent | null
|
||||
) => void
|
||||
): void {
|
||||
this._instanceContainer
|
||||
.getGame()
|
||||
@@ -127,14 +131,17 @@ namespace gdjs {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
const tileMap = TileMapHelper.TileMapManager.identify(
|
||||
const tileMapFileContent = TileMapHelper.TileMapManager.identify(
|
||||
tileMapJsonData
|
||||
);
|
||||
if (!tileMap) {
|
||||
if (!tileMapFileContent) {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
if (tileMap.kind === 'tiled' && tileSetJsonResourceName) {
|
||||
if (
|
||||
tileMapFileContent.kind === 'tiled' &&
|
||||
tileSetJsonResourceName
|
||||
) {
|
||||
this._instanceContainer
|
||||
.getGame()
|
||||
.getJsonManager()
|
||||
@@ -147,14 +154,14 @@ namespace gdjs {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
const tiledMap = tileMap.data;
|
||||
const tiledMap = tileMapFileContent.data;
|
||||
const tileSet = tileSetJsonData as TileMapHelper.TiledTileset;
|
||||
tileSet.firstgid = tiledMap.tilesets[0].firstgid;
|
||||
tiledMap.tilesets = [tileSet];
|
||||
callback(tileMap);
|
||||
callback(tileMapFileContent);
|
||||
});
|
||||
} else {
|
||||
callback(tileMap);
|
||||
callback(tileMapFileContent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
4
Extensions/TileMap/helper/TileMapHelper.d.ts
vendored
@@ -3,7 +3,7 @@ import {
|
||||
EditableTileMapLayer,
|
||||
PixiTileMapHelper,
|
||||
TileDefinition,
|
||||
TileMap,
|
||||
TileMapFileContent,
|
||||
TileMapManager,
|
||||
TileTextureCache,
|
||||
TiledTileset,
|
||||
@@ -16,7 +16,7 @@ declare global {
|
||||
EditableTileMapLayer,
|
||||
PixiTileMapHelper,
|
||||
TileDefinition,
|
||||
TileMap,
|
||||
TileMapFileContent,
|
||||
TileMapManager,
|
||||
TileTextureCache,
|
||||
TiledTileset,
|
||||
|
2
Extensions/TileMap/helper/dts/index.d.ts
vendored
@@ -10,7 +10,7 @@ export {
|
||||
export { TileMapManager } from './render/TileMapManager';
|
||||
export { TileTextureCache } from './render/TileTextureCache';
|
||||
export { PixiTileMapHelper } from './render/TileMapPixiHelper';
|
||||
export * from './types/index';
|
||||
export * from './load/TileMapFileContent';
|
||||
export * from './model/CommonTypes';
|
||||
export { TiledTileset } from './load/tiled/TiledFormat';
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
|
@@ -1 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,cAAc,GACf,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE/D,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC"}
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,cAAc,GACf,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE/D,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC"}
|
12
Extensions/TileMap/helper/dts/load/TileMapFileContent.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import { LDtkTileMap } from '../load/ldtk/LDtkFormat';
|
||||
import { TiledTileMap } from '../load/tiled/TiledFormat';
|
||||
export declare type TileMapFileContent =
|
||||
| {
|
||||
kind: 'tiled';
|
||||
data: TiledTileMap;
|
||||
}
|
||||
| {
|
||||
kind: 'ldtk';
|
||||
data: LDtkTileMap;
|
||||
};
|
||||
//# sourceMappingURL=TileMapFileContent.d.ts.map
|
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"TileMapFileContent.d.ts","sourceRoot":"","sources":["../../src/load/TileMapFileContent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,oBAAY,kBAAkB,GAC1B;IACE,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;CACpB,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC"}
|
@@ -1,16 +1,16 @@
|
||||
import type { EditableTileMap } from '../model/TileMapModel';
|
||||
import { TileMap } from '../types';
|
||||
import { TileMapFileContent } from './TileMapFileContent';
|
||||
export declare namespace TileMapLoader {
|
||||
/**
|
||||
* Create a {@link EditableTileMap} from the raw data.
|
||||
*
|
||||
* @param tiledMap The data exported from Tiled/LDtk.
|
||||
* @param tileMapFileContent The data exported from Tiled/LDtk.
|
||||
* @param levelIndex The level of the tile map to load from.
|
||||
* @param pako The zlib library.
|
||||
* @returns A {@link EditableTileMap}
|
||||
*/
|
||||
function load(
|
||||
tileMap: TileMap,
|
||||
tileMapFileContent: TileMapFileContent,
|
||||
levelIndex: number,
|
||||
pako: any
|
||||
): EditableTileMap | null;
|
||||
|
@@ -1 +1 @@
|
||||
{"version":3,"file":"TileMapLoader.d.ts","sourceRoot":"","sources":["../../src/load/TileMapLoader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAInC,yBAAiB,aAAa,CAAC;IAC7B;;;;;;;OAOG;IACH,SAAgB,IAAI,CAClB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,GAAG,GACR,eAAe,GAAG,IAAI,CAaxB;CACF"}
|
||||
{"version":3,"file":"TileMapLoader.d.ts","sourceRoot":"","sources":["../../src/load/TileMapLoader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAI1D,yBAAiB,aAAa,CAAC;IAC7B;;;;;;;OAOG;IACH,SAAgB,IAAI,CAClB,kBAAkB,EAAE,kBAAkB,EACtC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,GAAG,GACR,eAAe,GAAG,IAAI,CAaxB;CACF"}
|
@@ -2,7 +2,7 @@ import { integer } from '../../model/CommonTypes';
|
||||
/**
|
||||
* version 1.1.3 - https://github.com/deepnight/ldtk/blob/66fff7199932357f3ab9b044c2fc2a856f527831/docs/JSON_SCHEMA.json
|
||||
*/
|
||||
export type LDtkTileMap = {
|
||||
export declare type LDtkTileMap = {
|
||||
/** LDtk application build identifier.<br/> This is only used to identify the LDtk version that generated this particular project file, which can be useful for specific bug fixing. Note that the build identifier is just the date of the release, so it's not unique to each user (one single global ID per LDtk public release), and as a result, completely anonymous. */
|
||||
appBuildId: number;
|
||||
/** Number of backup files to keep, if the `backupOnSave` is TRUE */
|
||||
@@ -72,7 +72,7 @@ export type LDtkTileMap = {
|
||||
| null;
|
||||
};
|
||||
/** Auto-layer rule group */
|
||||
type LDtkAutoLayerRuleGroup = {
|
||||
declare type LDtkAutoLayerRuleGroup = {
|
||||
/** */
|
||||
active: boolean;
|
||||
/** *This field was removed in 1.0.0 and should no longer be used.* */
|
||||
@@ -87,9 +87,9 @@ type LDtkAutoLayerRuleGroup = {
|
||||
uid: integer;
|
||||
};
|
||||
/** This complex section isn't meant to be used by game devs at all, as these rules are completely resolved internally by the editor before any saving. You should just ignore this part. */
|
||||
type LDtkAutoRuleDef = {};
|
||||
declare type LDtkAutoRuleDef = {};
|
||||
/** If you're writing your own LDtk importer, you should probably just ignore *most* stuff in the `defs` section, as it contains data that are mostly important to the editor. To keep you away from the `defs` section and avoid some unnecessary JSON parsing, important data from definitions is often duplicated in fields prefixed with a double underscore (eg. `__identifier` or `__type`). The 2 only definition types you might need here are **Tilesets** and **Enums**. */
|
||||
type LDtkDefinition = {
|
||||
declare type LDtkDefinition = {
|
||||
/** All entities definitions, including their custom fields */
|
||||
entities: LDtkEntityDef[];
|
||||
/** All internal enums */
|
||||
@@ -104,7 +104,7 @@ type LDtkDefinition = {
|
||||
tilesets: LDtkTilesetDef[];
|
||||
};
|
||||
/** Entity definition */
|
||||
type LDtkEntityDef = {
|
||||
declare type LDtkEntityDef = {
|
||||
/** Base entity color */
|
||||
color: string;
|
||||
/** Array of field definitions */
|
||||
@@ -166,7 +166,7 @@ type LDtkEntityDef = {
|
||||
width: integer;
|
||||
};
|
||||
/** Entity instance */
|
||||
type LDtkEntityInstance = {
|
||||
declare type LDtkEntityInstance = {
|
||||
/** Grid-based coordinates (`[x,y]` format) */
|
||||
__grid: integer[];
|
||||
/** Entity definition identifier */
|
||||
@@ -193,7 +193,7 @@ type LDtkEntityInstance = {
|
||||
width: integer;
|
||||
};
|
||||
/** Enum definition */
|
||||
type LDtkEnumDef = {
|
||||
declare type LDtkEnumDef = {
|
||||
/** */
|
||||
externalFileChecksum: string | null;
|
||||
/** Relative path to the external file providing this Enum */
|
||||
@@ -210,7 +210,7 @@ type LDtkEnumDef = {
|
||||
values: LDtkEnumDefValues[];
|
||||
};
|
||||
/** Enum value definition */
|
||||
type LDtkEnumDefValues = {
|
||||
declare type LDtkEnumDefValues = {
|
||||
/** An array of 4 Int values that refers to the tile in the tileset image: `[ x, y, width, height ]` */
|
||||
__tileSrcRect: integer[] | null;
|
||||
/** Optional color */
|
||||
@@ -221,14 +221,14 @@ type LDtkEnumDefValues = {
|
||||
tileId: integer | null;
|
||||
};
|
||||
/** In a tileset definition, enum based tag infos */
|
||||
type LDtkEnumTagValue = {
|
||||
declare type LDtkEnumTagValue = {
|
||||
/** */
|
||||
enumValueId: string;
|
||||
/** */
|
||||
tileIds: integer[];
|
||||
};
|
||||
/** This section is mostly only intended for the LDtk editor app itself. You can safely ignore it. */
|
||||
type LDtkFieldDef = {
|
||||
declare type LDtkFieldDef = {
|
||||
/** Human readable value type. Possible values: `Int, Float, String, Bool, Color, ExternEnum.XXX, LocalEnum.XXX, Point, FilePath`.<br/> If the field is an array, this field will look like `Array<...>` (eg. `Array<Int>`, `Array<Point>` etc.)<br/> NOTE: if you enable the advanced option **Use Multilines type**, you will have \"*Multilines*\" instead of \"*String*\" when relevant. */
|
||||
__type: string;
|
||||
/** Optional list of accepted file extensions for FilePath value type. Includes the dot: `.ext` */
|
||||
@@ -310,7 +310,7 @@ type LDtkFieldDef = {
|
||||
useForSmartColor: boolean;
|
||||
};
|
||||
/** Field instance */
|
||||
type LDtkFieldInstance = {
|
||||
declare type LDtkFieldInstance = {
|
||||
/** Field definition identifier */
|
||||
__identifier: string;
|
||||
/** Optional TilesetRect used to display this field (this can be the field own Tile, or some other Tile guessed from the value, like an Enum). */
|
||||
@@ -324,7 +324,7 @@ type LDtkFieldInstance = {
|
||||
/** Editor internal raw values */
|
||||
realEditorValues: any[];
|
||||
};
|
||||
type LDtkFlag =
|
||||
declare type LDtkFlag =
|
||||
| 'DiscardPreCsvIntGrid'
|
||||
| 'ExportPreCsvIntGridFormat'
|
||||
| 'IgnoreBackupSuggest'
|
||||
@@ -332,7 +332,7 @@ type LDtkFlag =
|
||||
| 'MultiWorlds'
|
||||
| 'UseMultilinesType';
|
||||
/** IntGrid value definition */
|
||||
type LDtkIntGridValueDef = {
|
||||
declare type LDtkIntGridValueDef = {
|
||||
/** */
|
||||
color: string;
|
||||
/** User defined unique identifier */
|
||||
@@ -341,14 +341,14 @@ type LDtkIntGridValueDef = {
|
||||
value: integer;
|
||||
};
|
||||
/** IntGrid value instance */
|
||||
type LDtkIntGridValueInstance = {
|
||||
declare type LDtkIntGridValueInstance = {
|
||||
/** Coordinate ID in the layer grid */
|
||||
coordId: integer;
|
||||
/** IntGrid value */
|
||||
v: integer;
|
||||
};
|
||||
/** Layer definition */
|
||||
type LDtkLayerDef = {
|
||||
declare type LDtkLayerDef = {
|
||||
/** Type of the layer (*IntGrid, Entities, Tiles or AutoLayer*) */
|
||||
__type: string;
|
||||
/** Contains all the auto-layer rule definitions. */
|
||||
@@ -401,7 +401,7 @@ type LDtkLayerDef = {
|
||||
uid: integer;
|
||||
};
|
||||
/** Layer instance */
|
||||
type LDtkLayerInstance = {
|
||||
declare type LDtkLayerInstance = {
|
||||
/** Grid-based height */
|
||||
__cHei: integer;
|
||||
/** Grid-based width */
|
||||
@@ -452,7 +452,7 @@ type LDtkLayerInstance = {
|
||||
visible: boolean;
|
||||
};
|
||||
/** This section contains all the level data. It can be found in 2 distinct forms, depending on Project current settings: - If \"*Separate level files*\" is **disabled** (default): full level data is *embedded* inside the main Project JSON file, - If \"*Separate level files*\" is **enabled**: level data is stored in *separate* standalone `.ldtkl` files (one per level). In this case, the main Project JSON file will still contain most level data, except heavy sections, like the `layerInstances` array (which will be null). The `externalRelPath` string points to the `ldtkl` file. A `ldtkl` file is just a JSON file containing exactly what is described below. */
|
||||
type LDtkLevel = {
|
||||
declare type LDtkLevel = {
|
||||
/** Background color of the level (same as `bgColor`, except the default value is automatically used here if its value is `null`) */
|
||||
__bgColor: string;
|
||||
/** Position informations of the background image, if there is one. */
|
||||
@@ -497,7 +497,7 @@ type LDtkLevel = {
|
||||
worldY: integer;
|
||||
};
|
||||
/** Level background image position info */
|
||||
type LDtkLevelBgPosInfos = {
|
||||
declare type LDtkLevelBgPosInfos = {
|
||||
/** An array of 4 float values describing the cropped sub-rectangle of the displayed background image. This cropping happens when original is larger than the level bounds. Array format: `[ cropX, cropY, cropWidth, cropHeight ]` */
|
||||
cropRect: number[];
|
||||
/** An array containing the `[scaleX,scaleY]` values of the **cropped** background image, depending on `bgPos` option. */
|
||||
@@ -506,7 +506,7 @@ type LDtkLevelBgPosInfos = {
|
||||
topLeftPx: integer[];
|
||||
};
|
||||
/** Nearby level info */
|
||||
type LDtkNeighbourLevel = {
|
||||
declare type LDtkNeighbourLevel = {
|
||||
/** A single lowercase character tipping on the level location (`n`orth, `s`outh, `w`est, `e`ast). */
|
||||
dir: string;
|
||||
/** Neighbour Instance Identifier */
|
||||
@@ -515,7 +515,7 @@ type LDtkNeighbourLevel = {
|
||||
levelUid: integer;
|
||||
};
|
||||
/** This structure represents a single tile from a given Tileset. */
|
||||
type LDtkTile = {
|
||||
declare type LDtkTile = {
|
||||
/** Internal data used by the editor.<br/> For auto-layer tiles: `[ruleId, coordId]`.<br/> For tile-layer tiles: `[coordId]`. */
|
||||
d: integer[];
|
||||
/** \"Flip bits\", a 2-bits integer to represent the mirror transformations of the tile.<br/> - Bit 0 = X flip<br/> - Bit 1 = Y flip<br/> Examples: f=0 (no flip), f=1 (X flip only), f=2 (Y flip only), f=3 (both flips) */
|
||||
@@ -528,7 +528,7 @@ type LDtkTile = {
|
||||
t: integer;
|
||||
};
|
||||
/** The `Tileset` definition is the most important part among project definitions. It contains some extra informations about each integrated tileset. If you only had to parse one definition section, that would be the one. */
|
||||
export type LDtkTilesetDef = {
|
||||
export declare type LDtkTilesetDef = {
|
||||
/** Grid-based height */
|
||||
__cHei: integer;
|
||||
/** Grid-based width */
|
||||
@@ -565,14 +565,14 @@ export type LDtkTilesetDef = {
|
||||
uid: integer;
|
||||
};
|
||||
/** In a tileset definition, user defined meta-data of a tile. */
|
||||
type LDtkTileCustomMetadata = {
|
||||
declare type LDtkTileCustomMetadata = {
|
||||
/** */
|
||||
data: string;
|
||||
/** */
|
||||
tileId: integer;
|
||||
};
|
||||
/** This object represents a custom sub rectangle in a Tileset image. */
|
||||
type LDtkTilesetRect = {
|
||||
declare type LDtkTilesetRect = {
|
||||
/** Height in pixels */
|
||||
h: integer;
|
||||
/** UID of the tileset */
|
||||
@@ -584,6 +584,6 @@ type LDtkTilesetRect = {
|
||||
/** Y pixels coordinate of the top-left corner in the Tileset image */
|
||||
y: integer;
|
||||
};
|
||||
type LDtkWorld = {};
|
||||
declare type LDtkWorld = {};
|
||||
export {};
|
||||
//# sourceMappingURL=LDtkFormat.d.ts.map
|
||||
|
@@ -2,7 +2,7 @@ import { float, integer } from '../../model/CommonTypes';
|
||||
/**
|
||||
* Tiled JSON format (https://github.com/mapeditor/tiled/blob/master/docs/reference/json-map-format.rst).
|
||||
*/
|
||||
export type TiledTileMap = {
|
||||
export declare type TiledTileMap = {
|
||||
/** Hex-formatted color (#RRGGBB or #AARRGGBB) (optional) */
|
||||
backgroundcolor?: string;
|
||||
/** The compression level to use for tile layer data (defaults to -1, which means to use the algorithm default) */
|
||||
@@ -44,7 +44,7 @@ export type TiledTileMap = {
|
||||
/** Number of tile columns */
|
||||
width: integer;
|
||||
};
|
||||
export type TiledLayer = {
|
||||
export declare type TiledLayer = {
|
||||
/** Array of {@link TiledChunk} (optional). `tilelayer` only. */
|
||||
chunks?: Array<TiledChunk>;
|
||||
/** `zlib`, `gzip`, `zstd` (since Tiled 1.3) or empty (default). `tilelayer` only. */
|
||||
@@ -98,7 +98,7 @@ export type TiledLayer = {
|
||||
/** Vertical layer offset in tiles. Always 0. */
|
||||
y: integer;
|
||||
};
|
||||
export type TiledChunk = {
|
||||
export declare type TiledChunk = {
|
||||
/** Array of `unsigned` `integer` (GIDs) or base64-encoded data */
|
||||
data: Array<integer> | string;
|
||||
/** Height in tiles */
|
||||
@@ -110,7 +110,7 @@ export type TiledChunk = {
|
||||
/** Y coordinate in tiles */
|
||||
y: integer;
|
||||
};
|
||||
export type TiledObject = {
|
||||
export declare type TiledObject = {
|
||||
/** The class of the object (renamed from type since 1.9, optional) */
|
||||
class?: string;
|
||||
/** Used to mark an object as an ellipse */
|
||||
@@ -146,7 +146,7 @@ export type TiledObject = {
|
||||
/** Y coordinate in pixels */
|
||||
y: float;
|
||||
};
|
||||
export type TiledText = {
|
||||
export declare type TiledText = {
|
||||
/** Whether to use a bold font (default: `false`) */
|
||||
bold: boolean;
|
||||
/** Hex-formatted color (#RRGGBB or #AARRGGBB) (default: `#000000`) */
|
||||
@@ -172,7 +172,7 @@ export type TiledText = {
|
||||
/** Whether the text is wrapped within the object bounds (default: `false`) */
|
||||
wrap: boolean;
|
||||
};
|
||||
export type TiledTileset = {
|
||||
export declare type TiledTileset = {
|
||||
/** Hex-formatted color (#RRGGBB or #AARRGGBB) (optional) */
|
||||
backgroundcolor?: string;
|
||||
/** The number of tile columns in the tileset */
|
||||
@@ -224,7 +224,7 @@ export type TiledTileset = {
|
||||
/** Array of {@link TiledWangSet} (since 1.1.5) */
|
||||
wangsets?: Array<TiledWangSet>;
|
||||
};
|
||||
export type TiledGrid = {
|
||||
export declare type TiledGrid = {
|
||||
/** Cell height of tile grid */
|
||||
height: integer;
|
||||
/** `orthogonal` (default) or `isometric` */
|
||||
@@ -232,13 +232,13 @@ export type TiledGrid = {
|
||||
/** Cell width of tile grid */
|
||||
width: integer;
|
||||
};
|
||||
export type TileOffset = {
|
||||
export declare type TileOffset = {
|
||||
/** Horizontal offset in pixels */
|
||||
x: integer;
|
||||
/** Vertical offset in pixels (positive is down) */
|
||||
y: integer;
|
||||
};
|
||||
export type TiledTransformations = {
|
||||
export declare type TiledTransformations = {
|
||||
/** Tiles can be flipped horizontally */
|
||||
hflip: boolean;
|
||||
/** Tiles can be flipped vertically */
|
||||
@@ -248,7 +248,7 @@ export type TiledTransformations = {
|
||||
/** Whether untransformed tiles remain preferred, otherwise transformed tiles are used to produce more variations */
|
||||
preferuntransformed: boolean;
|
||||
};
|
||||
export type TiledTileDefinition = {
|
||||
export declare type TiledTileDefinition = {
|
||||
/** Array of {@link TiledTiles} */
|
||||
animation?: Array<TiledTileDefinition>;
|
||||
/** The class of the tile (renamed from type since 1.9, optional) */
|
||||
@@ -270,13 +270,13 @@ export type TiledTileDefinition = {
|
||||
/** Index of terrain for each corner of tile (optional) */
|
||||
terrain?: Array<integer>;
|
||||
};
|
||||
export type TiledFrame = {
|
||||
export declare type TiledFrame = {
|
||||
/** Frame duration in milliseconds */
|
||||
duration: integer;
|
||||
/** Local tile ID representing this frame */
|
||||
tileid: integer;
|
||||
};
|
||||
export type TiledTerrain = {
|
||||
export declare type TiledTerrain = {
|
||||
/** Name of terrain */
|
||||
name: string;
|
||||
/** Array of {@link TiledProperty} */
|
||||
@@ -284,7 +284,7 @@ export type TiledTerrain = {
|
||||
/** Local ID of tile representing terrain */
|
||||
tile: integer;
|
||||
};
|
||||
export type TiledWangSet = {
|
||||
export declare type TiledWangSet = {
|
||||
/** Array of {@link TiledWangColor} */
|
||||
colors: Array<TiledWangColor>;
|
||||
/** Name of the Wang set */
|
||||
@@ -296,7 +296,7 @@ export type TiledWangSet = {
|
||||
/** Array of {@link TiledWangTile} */
|
||||
wangtiles: Array<TiledWangTile>;
|
||||
};
|
||||
export type TiledWangColor = {
|
||||
export declare type TiledWangColor = {
|
||||
/** Hex-formatted color (#RRGGBB or #AARRGGBB) */
|
||||
color: string;
|
||||
/** Name of the Wang color */
|
||||
@@ -308,13 +308,13 @@ export type TiledWangColor = {
|
||||
/** Local ID of tile representing the Wang color */
|
||||
tile: integer;
|
||||
};
|
||||
export type TiledWangTile = {
|
||||
export declare type TiledWangTile = {
|
||||
/** Local ID of tile */
|
||||
tileid: integer;
|
||||
/** Array of Wang color indexes (`uchar[8]`) */
|
||||
wangid: Array<integer>;
|
||||
};
|
||||
export type TiledObjectTemplate = {
|
||||
export declare type TiledObjectTemplate = {
|
||||
/** `template` */
|
||||
type: string;
|
||||
/** External tileset used by the template (optional) */
|
||||
@@ -322,7 +322,7 @@ export type TiledObjectTemplate = {
|
||||
/** The object instantiated by this template */
|
||||
object: Object;
|
||||
};
|
||||
export type TiledProperty = {
|
||||
export declare type TiledProperty = {
|
||||
/** Name of the property */
|
||||
name: string;
|
||||
/** type of the property (`string` (default), `integer`, `float`, `boolean`, `color` or `file` (since 0.16, with `color` and `file` added in 0.17)) */
|
||||
@@ -330,7 +330,7 @@ export type TiledProperty = {
|
||||
/** Value of the property */
|
||||
value: string | number;
|
||||
};
|
||||
export type TiledPoint = {
|
||||
export declare type TiledPoint = {
|
||||
/** X coordinate in pixels */
|
||||
x: float;
|
||||
/** Y coordinate in pixels */
|
||||
|
@@ -12,7 +12,7 @@ export declare const decodeBase64LayerData: (
|
||||
pako: any,
|
||||
tiledLayer: TiledLayer
|
||||
) => number[];
|
||||
export type TiledGID = {
|
||||
export declare type TiledGID = {
|
||||
id: integer;
|
||||
flippedHorizontally: boolean;
|
||||
flippedVertically: boolean;
|
||||
|
@@ -1 +1 @@
|
||||
{"version":3,"file":"TiledTileMapLoaderHelper.d.ts","sourceRoot":"","sources":["../../../src/load/tiled/TiledTileMapLoaderHelper.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,SAAU,GAAG,cAAc,UAAU,aAgDtE,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,OAAO,CAAC;IACZ,mBAAmB,EAAE,OAAO,CAAC;IAC7B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,kBACvB,OAAO,KACrB,QAmBF,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,MAAM,GAAG,SAAS,CAEpB"}
|
||||
{"version":3,"file":"TiledTileMapLoaderHelper.d.ts","sourceRoot":"","sources":["../../../src/load/tiled/TiledTileMapLoaderHelper.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,SAAU,GAAG,cAAc,UAAU,aAgDtE,CAAC;AAEF,oBAAY,QAAQ,GAAG;IACrB,EAAE,EAAE,OAAO,CAAC;IACZ,mBAAmB,EAAE,OAAO,CAAC;IAC7B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,kBACvB,OAAO,KACrB,QAmBF,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,MAAM,GAAG,SAAS,CAEpB"}
|
@@ -1,5 +1,5 @@
|
||||
export declare type integer = number;
|
||||
export declare type float = number;
|
||||
export type FloatPoint = [float, float];
|
||||
export type PolygonVertices = FloatPoint[];
|
||||
export declare type FloatPoint = [float, float];
|
||||
export declare type PolygonVertices = FloatPoint[];
|
||||
//# sourceMappingURL=CommonTypes.d.ts.map
|
||||
|
@@ -1 +1 @@
|
||||
{"version":3,"file":"CommonTypes.d.ts","sourceRoot":"","sources":["../../src/model/CommonTypes.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,MAAM,OAAO,GAAG,MAAM,CAAC;AACrC,MAAM,CAAC,OAAO,MAAM,KAAK,GAAG,MAAM,CAAC;AACnC,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAExC,MAAM,MAAM,eAAe,GAAG,UAAU,EAAE,CAAC"}
|
||||
{"version":3,"file":"CommonTypes.d.ts","sourceRoot":"","sources":["../../src/model/CommonTypes.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,MAAM,OAAO,GAAG,MAAM,CAAC;AACrC,MAAM,CAAC,OAAO,MAAM,KAAK,GAAG,MAAM,CAAC;AACnC,oBAAY,UAAU,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAExC,oBAAY,eAAe,GAAG,UAAU,EAAE,CAAC"}
|
@@ -1,7 +1,7 @@
|
||||
import { EditableTileMap } from '../model/TileMapModel';
|
||||
import { TileTextureCache } from './TileTextureCache';
|
||||
import PIXI = GlobalPIXIModule.PIXI;
|
||||
import { TileMap } from '../types';
|
||||
import { TileMapFileContent } from '../load/TileMapFileContent';
|
||||
/**
|
||||
* A holder to share tile maps across the 2 extension objects.
|
||||
*
|
||||
@@ -23,7 +23,7 @@ export declare class TileMapManager {
|
||||
* @param data JSON data.
|
||||
* @returns The data enclosed with its detected kind.
|
||||
*/
|
||||
static identify(data: any): TileMap | null;
|
||||
static identify(data: any): TileMapFileContent | null;
|
||||
/**
|
||||
* @param loadTileMap The method that loads the Tiled JSON file in memory.
|
||||
* @param tileMapJsonResourceName The resource name of the tile map.
|
||||
@@ -36,7 +36,7 @@ export declare class TileMapManager {
|
||||
loadTileMap: (
|
||||
tileMapJsonResourceName: string,
|
||||
tileSetJsonResourceName: string,
|
||||
callback: (tileMap: TileMap | null) => void
|
||||
callback: (tileMapFileContent: TileMapFileContent | null) => void
|
||||
) => void,
|
||||
tileMapJsonResourceName: string,
|
||||
tileSetJsonResourceName: string,
|
||||
@@ -57,7 +57,7 @@ export declare class TileMapManager {
|
||||
loadTileMap: (
|
||||
tileMapJsonResourceName: string,
|
||||
tileSetJsonResourceName: string,
|
||||
callback: (tileMap: TileMap | null) => void
|
||||
callback: (tileMapFileContent: TileMapFileContent | null) => void
|
||||
) => void,
|
||||
getTexture: (textureName: string) => PIXI.BaseTexture<PIXI.Resource>,
|
||||
atlasImageResourceName: string,
|
||||
|
@@ -1 +1 @@
|
||||
{"version":3,"file":"TileMapManager.d.ts","sourceRoot":"","sources":["../../src/render/TileMapManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC;;;;;;;GAOG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,aAAa,CAAiC;IACtD,OAAO,CAAC,mBAAmB,CAAkC;;IAO7D;;;OAGG;IACH,MAAM,CAAC,UAAU,CAAC,cAAc,EAAE,MAAM,GAAG,cAAc;IAWzD;;;OAGG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,GAAG,IAAI;IAyB1C;;;;;;;OAOG;IACH,gBAAgB,CACd,WAAW,EAAE,CACX,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,KACxC,IAAI,EACT,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,GAAG,EACT,QAAQ,EAAE,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI,GAClD,IAAI;IAiCP;;;;;;;;OAQG;IACH,qBAAqB,CACnB,WAAW,EAAE,CACX,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,KACxC,IAAI,EACT,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,EACpE,sBAAsB,EAAE,MAAM,EAC9B,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,CAAC,YAAY,EAAE,gBAAgB,GAAG,IAAI,KAAK,IAAI,GACxD,IAAI;CAuCR"}
|
||||
{"version":3,"file":"TileMapManager.d.ts","sourceRoot":"","sources":["../../src/render/TileMapManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAEpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE;;;;;;;GAOG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,aAAa,CAAiC;IACtD,OAAO,CAAC,mBAAmB,CAAkC;;IAO7D;;;OAGG;IACH,MAAM,CAAC,UAAU,CAAC,cAAc,EAAE,MAAM,GAAG,cAAc;IAWzD;;;OAGG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,GAAG,kBAAkB,GAAG,IAAI;IAwBrD;;;;;;;OAOG;IACH,gBAAgB,CACd,WAAW,EAAE,CACX,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,QAAQ,EAAE,CAAC,kBAAkB,EAAE,kBAAkB,GAAG,IAAI,KAAK,IAAI,KAC9D,IAAI,EACT,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,GAAG,EACT,QAAQ,EAAE,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI,GAClD,IAAI;IAiCP;;;;;;;;OAQG;IACH,qBAAqB,CACnB,WAAW,EAAE,CACX,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,QAAQ,EAAE,CAAC,kBAAkB,EAAE,kBAAkB,GAAG,IAAI,KAAK,IAAI,KAC9D,IAAI,EACT,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,EACpE,sBAAsB,EAAE,MAAM,EAC9B,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,CAAC,YAAY,EAAE,gBAAgB,GAAG,IAAI,KAAK,IAAI,GACxD,IAAI;CAuCR"}
|
@@ -1,6 +1,6 @@
|
||||
import { integer, float } from '../model/CommonTypes';
|
||||
import { EditableTileMap } from '../model/TileMapModel';
|
||||
import { TileMap } from '../types';
|
||||
import { TileMapFileContent } from '../load/TileMapFileContent';
|
||||
import { TileTextureCache } from './TileTextureCache';
|
||||
import PIXI = GlobalPIXIModule.PIXI;
|
||||
export declare namespace PixiTileMapHelper {
|
||||
@@ -14,7 +14,7 @@ export declare namespace PixiTileMapHelper {
|
||||
* @returns A textures cache.
|
||||
*/
|
||||
function parseAtlas(
|
||||
tileMap: TileMap,
|
||||
tileMap: TileMapFileContent,
|
||||
levelIndex: number,
|
||||
atlasTexture: PIXI.BaseTexture<PIXI.Resource> | null,
|
||||
getTexture: (textureName: string) => PIXI.BaseTexture<PIXI.Resource>
|
||||
|
@@ -1 +1 @@
|
||||
{"version":3,"file":"TileMapPixiHelper.d.ts","sourceRoot":"","sources":["../../src/render/TileMapPixiHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAEL,eAAe,EAEhB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAEpC,yBAAiB,iBAAiB,CAAC;IACjC;;;;;;;;OAQG;IACH,SAAgB,UAAU,CACxB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,EACpD,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,GACnE,gBAAgB,GAAG,IAAI,CAuBzB;IAED;;;;;;;;;;;;OAYG;IACH,SAAgB,iBAAiB,CAC/B,kBAAkB,EAAE,GAAG,EACvB,OAAO,EAAE,eAAe,EACxB,YAAY,EAAE,gBAAgB,EAC9B,WAAW,EAAE,OAAO,GAAG,SAAS,GAAG,KAAK,EACxC,UAAU,EAAE,MAAM,GACjB,IAAI,CA0GN;IAED;;OAEG;IACH,SAAgB,uBAAuB,CACrC,YAAY,EAAE,IAAI,CAAC,QAAQ,EAC3B,OAAO,EAAE,eAAe,EACxB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,OAAO,EACpB,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,KAAK,EACrB,SAAS,EAAE,OAAO,EAClB,WAAW,EAAE,KAAK,GACjB,IAAI,CAgEN;CACF"}
|
||||
{"version":3,"file":"TileMapPixiHelper.d.ts","sourceRoot":"","sources":["../../src/render/TileMapPixiHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAEL,eAAe,EAEhB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAEpC,yBAAiB,iBAAiB,CAAC;IACjC;;;;;;;;OAQG;IACH,SAAgB,UAAU,CACxB,OAAO,EAAE,kBAAkB,EAC3B,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,EACpD,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,GACnE,gBAAgB,GAAG,IAAI,CAuBzB;IAED;;;;;;;;;;;;OAYG;IACH,SAAgB,iBAAiB,CAC/B,kBAAkB,EAAE,GAAG,EACvB,OAAO,EAAE,eAAe,EACxB,YAAY,EAAE,gBAAgB,EAC9B,WAAW,EAAE,OAAO,GAAG,SAAS,GAAG,KAAK,EACxC,UAAU,EAAE,MAAM,GACjB,IAAI,CA0GN;IAED;;OAEG;IACH,SAAgB,uBAAuB,CACrC,YAAY,EAAE,IAAI,CAAC,QAAQ,EAC3B,OAAO,EAAE,eAAe,EACxB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,OAAO,EACpB,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,KAAK,EACrB,SAAS,EAAE,OAAO,EAClB,WAAW,EAAE,KAAK,GACjB,IAAI,CAgEN;CACF"}
|
@@ -1,8 +1,10 @@
|
||||
import { TileTextureCache } from '../TileTextureCache';
|
||||
import { LDtkTileMap } from '../../load/ldtk/LDtkFormat';
|
||||
import PIXI = GlobalPIXIModule.PIXI;
|
||||
type Texture = PIXI.BaseTexture<PIXI.Resource>;
|
||||
type TextureLoader = (textureName: string) => PIXI.BaseTexture<PIXI.Resource>;
|
||||
declare type Texture = PIXI.BaseTexture<PIXI.Resource>;
|
||||
declare type TextureLoader = (
|
||||
textureName: string
|
||||
) => PIXI.BaseTexture<PIXI.Resource>;
|
||||
export declare namespace LDtkPixiHelper {
|
||||
/**
|
||||
* Split an atlas image into Pixi textures.
|
||||
|
@@ -1 +1 @@
|
||||
{"version":3,"file":"LDtkPixiHelper.d.ts","sourceRoot":"","sources":["../../../src/render/ldtk/LDtkPixiHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAkB,MAAM,4BAA4B,CAAC;AAEzE,OAAO,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAEpC,KAAK,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC/C,KAAK,aAAa,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAmC9E,yBAAiB,cAAc,CAAC;IAC9B;;;;;;;;OAQG;IACH,SAAgB,UAAU,CACxB,OAAO,EAAE,WAAW,EACpB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,OAAO,GAAG,IAAI,EAC5B,UAAU,EAAE,aAAa,GACxB,gBAAgB,GAAG,IAAI,CAoFzB;CACF"}
|
||||
{"version":3,"file":"LDtkPixiHelper.d.ts","sourceRoot":"","sources":["../../../src/render/ldtk/LDtkPixiHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAkB,MAAM,4BAA4B,CAAC;AAEzE,OAAO,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAEpC,aAAK,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC/C,aAAK,aAAa,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAmC9E,yBAAiB,cAAc,CAAC;IAC9B;;;;;;;;OAQG;IACH,SAAgB,UAAU,CACxB,OAAO,EAAE,WAAW,EACpB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,OAAO,GAAG,IAAI,EAC5B,UAAU,EAAE,aAAa,GACxB,gBAAgB,GAAG,IAAI,CAoFzB;CACF"}
|
@@ -1,6 +1,6 @@
|
||||
import { LDtkTileMap } from '../load/ldtk/LDtkFormat';
|
||||
import { TiledTileMap } from '../load/tiled/TiledFormat';
|
||||
export type TileMap =
|
||||
export declare type TileMap =
|
||||
| {
|
||||
kind: 'tiled';
|
||||
data: TiledTileMap;
|
||||
|
@@ -1 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,MAAM,MAAM,OAAO,GACf;IACE,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;CACpB,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC"}
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,oBAAY,OAAO,GACf;IACE,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;CACpB,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC"}
|
@@ -164,7 +164,7 @@ BaseObjectExtension::BaseObjectExtension() {
|
||||
objectConditions["CollisionPoint"]
|
||||
.SetFunctionName("isCollidingWithPoint")
|
||||
.SetIncludeFile("runtimeobject.js");
|
||||
objectConditions["ObjectTimer"] // deprecated
|
||||
objectConditions["ObjectTimer"] // deprecated
|
||||
.SetFunctionName("timerElapsedTime")
|
||||
.SetIncludeFile("runtimeobject.js");
|
||||
objectConditions["CompareObjectTimer"]
|
||||
@@ -223,6 +223,18 @@ BaseObjectExtension::BaseObjectExtension() {
|
||||
objectExpressions["VariableChildCount"]
|
||||
.SetFunctionName("gdjs.RuntimeObject.getVariableChildCount")
|
||||
.SetStatic();
|
||||
objectExpressions["ArrayVariableFirstNumber"]
|
||||
.SetFunctionName("gdjs.RuntimeObject.getFirstVariableNumber")
|
||||
.SetStatic();
|
||||
objectStrExpressions["ArrayVariableFirstString"]
|
||||
.SetFunctionName("gdjs.RuntimeObject.getFirstVariableString")
|
||||
.SetStatic();
|
||||
objectExpressions["ArrayVariableLastNumber"]
|
||||
.SetFunctionName("gdjs.RuntimeObject.getLastVariableNumber")
|
||||
.SetStatic();
|
||||
objectStrExpressions["ArrayVariableLastString"]
|
||||
.SetFunctionName("gdjs.RuntimeObject.getLastVariableString")
|
||||
.SetStatic();
|
||||
objectExpressions["ForceX"].SetFunctionName("getAverageForce().getX");
|
||||
objectExpressions["ForceY"].SetFunctionName("getAverageForce().getY");
|
||||
objectExpressions["ForceAngle"].SetFunctionName("getAverageForce().getAngle");
|
||||
@@ -254,9 +266,9 @@ BaseObjectExtension::BaseObjectExtension() {
|
||||
"gdjs.evtTools.object.createObjectFromGroupOnScene");
|
||||
|
||||
GetAllExpressions()["Count"].SetFunctionName(
|
||||
"gdjs.evtTools.object.pickedObjectsCount"); // Deprecated
|
||||
"gdjs.evtTools.object.pickedObjectsCount"); // Deprecated
|
||||
GetAllConditions()["NbObjet"].SetFunctionName(
|
||||
"gdjs.evtTools.object.pickedObjectsCount"); // Deprecated
|
||||
"gdjs.evtTools.object.pickedObjectsCount"); // Deprecated
|
||||
|
||||
GetAllExpressions()["SceneInstancesCount"].SetFunctionName(
|
||||
"gdjs.evtTools.object.getSceneInstancesCount");
|
||||
@@ -335,6 +347,9 @@ BaseObjectExtension::BaseObjectExtension() {
|
||||
objectActions["ObjectVariableRemoveAt"]
|
||||
.SetFunctionName("variableRemoveAt")
|
||||
.SetIncludeFile("runtimeobject.js");
|
||||
objectConditions["ObjectVariableChildCount"]
|
||||
.SetFunctionName("getVariableChildCount")
|
||||
.SetIncludeFile("runtimeobject.js");
|
||||
|
||||
GetAllActions()["MoveObjects"].codeExtraInformation.SetCustomCodeGenerator(
|
||||
[](gd::Instruction &,
|
||||
|
@@ -34,23 +34,46 @@ VariablesExtension::VariablesExtension() {
|
||||
"gdjs.evtTools.variable.getVariableString");
|
||||
GetAllConditions()["GlobalVariableAsBoolean"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableBoolean");
|
||||
GetAllExpressions()["Variable"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableNumber");
|
||||
GetAllStrExpressions()["VariableString"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableString");
|
||||
|
||||
GetAllExpressions()["VariableChildCount"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableChildCount");
|
||||
GetAllExpressions()["GlobalVariableChildCount"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableChildCount");
|
||||
|
||||
GetAllExpressions()["Variable"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableNumber");
|
||||
GetAllStrExpressions()["VariableString"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableString");
|
||||
GetAllExpressions()["GlobalVariable"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableNumber");
|
||||
GetAllStrExpressions()["GlobalVariableString"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableString");
|
||||
|
||||
GetAllStrExpressions()["GlobalVariableFirstString"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getFirstVariableString");
|
||||
GetAllExpressions()["GlobalVariableFirstNumber"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getFirstVariableNumber");
|
||||
GetAllStrExpressions()["GlobalVariableLastString"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getLastVariableString");
|
||||
GetAllExpressions()["GlobalVariableLastNumber"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getLastVariableNumber");
|
||||
GetAllStrExpressions()["SceneVariableFirstString"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getFirstVariableString");
|
||||
GetAllExpressions()["SceneVariableFirstNumber"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getFirstVariableNumber");
|
||||
GetAllStrExpressions()["SceneVariableLastString"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getLastVariableString");
|
||||
GetAllExpressions()["SceneVariableLastNumber"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getLastVariableNumber");
|
||||
|
||||
GetAllConditions()["VarSceneDef"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.sceneVariableExists");
|
||||
GetAllConditions()["VarGlobalDef"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.globalVariableExists");
|
||||
GetAllConditions()["SceneVariableChildCount"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableChildCount");
|
||||
GetAllConditions()["GlobalVariableChildCount"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.getVariableChildCount");
|
||||
|
||||
GetAllActions()["SetSceneVariableAsBoolean"].SetFunctionName(
|
||||
"gdjs.evtTools.variable.setVariableBoolean");
|
||||
|
@@ -170,6 +170,54 @@ namespace gdjs {
|
||||
): number {
|
||||
return variable.getChildrenCount();
|
||||
};
|
||||
|
||||
/**
|
||||
* Shortcut to get the first value of an array variable as a number.
|
||||
*/
|
||||
export const getFirstVariableNumber = function (
|
||||
array: gdjs.Variable
|
||||
): number {
|
||||
if (array.getChildrenCount() === 0) {
|
||||
return 0;
|
||||
}
|
||||
return array.getAllChildrenArray()[0].getAsNumber();
|
||||
};
|
||||
|
||||
/**
|
||||
* Shortcut to get the last value of an array variable as a string.
|
||||
*/
|
||||
export const getFirstVariableString = function (
|
||||
array: gdjs.Variable
|
||||
): string {
|
||||
if (array.getChildrenCount() === 0) {
|
||||
return '';
|
||||
}
|
||||
return array.getAllChildrenArray()[0].getAsString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Shortcut to get the last value of an array variable as a number.
|
||||
*/
|
||||
export const getLastVariableNumber = function (
|
||||
array: gdjs.Variable
|
||||
): number {
|
||||
const children = array.getAllChildrenArray();
|
||||
return children.length === 0
|
||||
? 0
|
||||
: children[children.length - 1].getAsNumber();
|
||||
};
|
||||
|
||||
/**
|
||||
* Shortcut to get the last value of an array variable as a string.
|
||||
*/
|
||||
export const getLastVariableString = function (
|
||||
array: gdjs.Variable
|
||||
): string {
|
||||
const children = array.getAllChildrenArray();
|
||||
return children.length === 0
|
||||
? ''
|
||||
: children[children.length - 1].getAsString();
|
||||
};
|
||||
}
|
||||
|
||||
export namespace common {
|
||||
|
@@ -940,6 +940,46 @@ namespace gdjs {
|
||||
array.removeAtIndex(index);
|
||||
};
|
||||
|
||||
/**
|
||||
* Shortcut to get the first value of an array variable as a string.
|
||||
*/
|
||||
static getFirstVariableString = function (array: gdjs.Variable): string {
|
||||
if (array.getChildrenCount() === 0) {
|
||||
return '';
|
||||
}
|
||||
return array.getAllChildrenArray()[0].getAsString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Shortcut to get the first value of an array variable as a number.
|
||||
*/
|
||||
static getFirstVariableNumber = function (array: gdjs.Variable): number {
|
||||
if (array.getChildrenCount() === 0) {
|
||||
return 0;
|
||||
}
|
||||
return array.getAllChildrenArray()[0].getAsNumber();
|
||||
};
|
||||
|
||||
/**
|
||||
* Shortcut to get the last value of an array variable as a string.
|
||||
*/
|
||||
static getLastVariableString = function (array: gdjs.Variable): string {
|
||||
const children = array.getAllChildrenArray();
|
||||
return children.length === 0
|
||||
? ''
|
||||
: children[children.length - 1].getAsString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Shortcut to get the last value of an array variable as a number.
|
||||
*/
|
||||
static getLastVariableNumber = function (array: gdjs.Variable): number {
|
||||
const children = array.getAllChildrenArray();
|
||||
return children.length === 0
|
||||
? 0
|
||||
: children[children.length - 1].getAsNumber();
|
||||
};
|
||||
|
||||
/**
|
||||
* Shortcut to test if a variable exists for the object.
|
||||
* @param name The variable to be tested
|
||||
@@ -2531,6 +2571,11 @@ namespace gdjs {
|
||||
setVariableString = RuntimeObject.setVariableString;
|
||||
getVariableBoolean = RuntimeObject.getVariableBoolean;
|
||||
setVariableBoolean = RuntimeObject.setVariableBoolean;
|
||||
getVariableChildCount = RuntimeObject.getVariableChildCount;
|
||||
getFirstVariableNumber = RuntimeObject.getFirstVariableNumber;
|
||||
getFirstVariableString = RuntimeObject.getFirstVariableString;
|
||||
getLastVariableNumber = RuntimeObject.getLastVariableNumber;
|
||||
getLastVariableString = RuntimeObject.getLastVariableString;
|
||||
toggleVariableBoolean = RuntimeObject.toggleVariableBoolean;
|
||||
variableChildExists = RuntimeObject.variableChildExists;
|
||||
variableRemoveChild = RuntimeObject.variableRemoveChild;
|
||||
|
@@ -13,6 +13,6 @@ export { TileMapManager } from "./render/TileMapManager";
|
||||
export { TileTextureCache } from "./render/TileTextureCache";
|
||||
export { PixiTileMapHelper } from "./render/TileMapPixiHelper";
|
||||
|
||||
export * from "./types/index";
|
||||
export * from "./load/TileMapFileContent";
|
||||
export * from "./model/CommonTypes";
|
||||
export { TiledTileset } from "./load/tiled/TiledFormat";
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { LDtkTileMap } from "../load/ldtk/LDtkFormat";
|
||||
import { TiledTileMap } from "../load/tiled/TiledFormat";
|
||||
|
||||
export type TileMap =
|
||||
export type TileMapFileContent =
|
||||
| {
|
||||
kind: "tiled";
|
||||
data: TiledTileMap;
|
@@ -1,5 +1,5 @@
|
||||
import type { EditableTileMap } from "../model/TileMapModel";
|
||||
import { TileMap } from "../types";
|
||||
import { TileMapFileContent } from "./TileMapFileContent";
|
||||
import { LDtkTileMapLoader } from "./ldtk/LDtkTileMapLoader";
|
||||
import { TiledTileMapLoader } from "./tiled/TiledTileMapLoader";
|
||||
|
||||
@@ -7,21 +7,21 @@ export namespace TileMapLoader {
|
||||
/**
|
||||
* Create a {@link EditableTileMap} from the raw data.
|
||||
*
|
||||
* @param tiledMap The data exported from Tiled/LDtk.
|
||||
* @param tileMapFileContent The data exported from Tiled/LDtk.
|
||||
* @param levelIndex The level of the tile map to load from.
|
||||
* @param pako The zlib library.
|
||||
* @returns A {@link EditableTileMap}
|
||||
*/
|
||||
export function load(
|
||||
tileMap: TileMap,
|
||||
tileMapFileContent: TileMapFileContent,
|
||||
levelIndex: number,
|
||||
pako: any
|
||||
): EditableTileMap | null {
|
||||
if (tileMap.kind === "ldtk") {
|
||||
return LDtkTileMapLoader.load(tileMap.data, levelIndex);
|
||||
if (tileMapFileContent.kind === "ldtk") {
|
||||
return LDtkTileMapLoader.load(tileMapFileContent.data, levelIndex);
|
||||
}
|
||||
if (tileMap.kind === "tiled") {
|
||||
return TiledTileMapLoader.load(tileMap.data, pako);
|
||||
if (tileMapFileContent.kind === "tiled") {
|
||||
return TiledTileMapLoader.load(tileMapFileContent.data, pako);
|
||||
}
|
||||
|
||||
console.warn(
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { integer } from '../../model/CommonTypes';
|
||||
import { EditableTileMap, TileDefinition } from '../../model/TileMapModel';
|
||||
import { getLDtkTileId } from './LDtkTileMapLoaderHelper';
|
||||
import { LDtkTileMap } from './LDtkFormat';
|
||||
import { getTileGID } from '../../model/GID';
|
||||
import { integer } from "../../model/CommonTypes";
|
||||
import { EditableTileMap, TileDefinition } from "../../model/TileMapModel";
|
||||
import { getLDtkTileId } from "./LDtkTileMapLoaderHelper";
|
||||
import { LDtkTileMap } from "./LDtkFormat";
|
||||
import { getTileGID } from "../../model/GID";
|
||||
|
||||
export namespace LDtkTileMapLoader {
|
||||
/**
|
||||
@@ -54,9 +54,9 @@ export namespace LDtkTileMapLoader {
|
||||
}
|
||||
|
||||
if (
|
||||
layer.__type === 'IntGrid' ||
|
||||
layer.__type === 'AutoLayer' ||
|
||||
layer.__type === 'Tiles'
|
||||
layer.__type === "IntGrid" ||
|
||||
layer.__type === "AutoLayer" ||
|
||||
layer.__type === "Tiles"
|
||||
) {
|
||||
if (gridSize === 0) {
|
||||
gridSize = layer.__gridSize;
|
||||
@@ -64,7 +64,7 @@ export namespace LDtkTileMapLoader {
|
||||
dimY = layer.__cHei;
|
||||
} else if (layer.__gridSize !== gridSize) {
|
||||
console.warn(
|
||||
'Grid size is different across layers. Only the first layer grid size will be followed.'
|
||||
"Grid size is different across layers. Only the first layer grid size will be followed."
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -124,7 +124,7 @@ export namespace LDtkTileMapLoader {
|
||||
const hash = `${oldTileDef
|
||||
.getStackedTiles()
|
||||
.map((tileId) => `${tileId}`)
|
||||
.join(';')};${tileGID}`;
|
||||
.join(";")};${tileGID}`;
|
||||
const tileDef = composedTileMap.get(hash);
|
||||
if (tileDef) {
|
||||
editableTileLayer.setTile(x, y, tileDef.getStackTileId());
|
||||
|
@@ -5,7 +5,7 @@ import { PixiTileMapHelper } from "./TileMapPixiHelper";
|
||||
|
||||
import PIXI = GlobalPIXIModule.PIXI;
|
||||
import { TileMapLoader } from "../load/TileMapLoader";
|
||||
import { TileMap } from "../types";
|
||||
import { TileMapFileContent } from "../load/TileMapFileContent";
|
||||
|
||||
/**
|
||||
* A holder to share tile maps across the 2 extension objects.
|
||||
@@ -43,7 +43,7 @@ export class TileMapManager {
|
||||
* @param data JSON data.
|
||||
* @returns The data enclosed with its detected kind.
|
||||
*/
|
||||
static identify(data: any): TileMap | null {
|
||||
static identify(data: any): TileMapFileContent | null {
|
||||
if (data.tiledversion) {
|
||||
console.info("Detected the json file was created in Tiled");
|
||||
return {
|
||||
@@ -63,7 +63,6 @@ export class TileMapManager {
|
||||
console.warn(
|
||||
"The loaded Tile Map data does not contain a 'tiledversion' or '__header__' key. Are you sure this file has been exported from Tiled (mapeditor.org) or LDtk (ldtk.io)?"
|
||||
);
|
||||
console.log("The data that failed Tile Map identification is: ", data);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -80,7 +79,7 @@ export class TileMapManager {
|
||||
loadTileMap: (
|
||||
tileMapJsonResourceName: string,
|
||||
tileSetJsonResourceName: string,
|
||||
callback: (tileMap: TileMap | null) => void
|
||||
callback: (tileMapFileContent: TileMapFileContent | null) => void
|
||||
) => void,
|
||||
tileMapJsonResourceName: string,
|
||||
tileSetJsonResourceName: string,
|
||||
@@ -101,14 +100,14 @@ export class TileMapManager {
|
||||
loadTileMap(
|
||||
tileMapJsonResourceName,
|
||||
tileSetJsonResourceName,
|
||||
(tileMap: TileMap | null) => {
|
||||
if (!tileMap) {
|
||||
(tileMapFileContent: TileMapFileContent | null) => {
|
||||
if (!tileMapFileContent) {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
const editableTileMap = TileMapLoader.load(
|
||||
tileMap,
|
||||
tileMapFileContent,
|
||||
levelIndex,
|
||||
pako
|
||||
);
|
||||
@@ -133,7 +132,7 @@ export class TileMapManager {
|
||||
loadTileMap: (
|
||||
tileMapJsonResourceName: string,
|
||||
tileSetJsonResourceName: string,
|
||||
callback: (tileMap: TileMap | null) => void
|
||||
callback: (tileMapFileContent: TileMapFileContent | null) => void
|
||||
) => void,
|
||||
getTexture: (textureName: string) => PIXI.BaseTexture<PIXI.Resource>,
|
||||
atlasImageResourceName: string,
|
||||
@@ -157,8 +156,8 @@ export class TileMapManager {
|
||||
loadTileMap(
|
||||
tileMapJsonResourceName,
|
||||
tileSetJsonResourceName,
|
||||
(tileMap: TileMap | null) => {
|
||||
if (!tileMap) {
|
||||
(tileMapFileContent: TileMapFileContent | null) => {
|
||||
if (!tileMapFileContent) {
|
||||
// loadTileMap already log errors.
|
||||
callback(null);
|
||||
return;
|
||||
@@ -168,7 +167,7 @@ export class TileMapManager {
|
||||
? getTexture(atlasImageResourceName)
|
||||
: null;
|
||||
const textureCache = PixiTileMapHelper.parseAtlas(
|
||||
tileMap,
|
||||
tileMapFileContent,
|
||||
levelIndex,
|
||||
atlasTexture,
|
||||
getTexture
|
||||
|
@@ -6,7 +6,7 @@ import {
|
||||
} from "../model/TileMapModel";
|
||||
import { TiledPixiHelper } from "./tiled/TiledPixiHelper";
|
||||
import { LDtkPixiHelper } from "./ldtk/LDtkPixiHelper";
|
||||
import { TileMap } from "../types";
|
||||
import { TileMapFileContent } from "../load/TileMapFileContent";
|
||||
import { TileTextureCache } from "./TileTextureCache";
|
||||
import { FlippingHelper, getPixiRotate } from "../model/GID";
|
||||
|
||||
@@ -23,7 +23,7 @@ export namespace PixiTileMapHelper {
|
||||
* @returns A textures cache.
|
||||
*/
|
||||
export function parseAtlas(
|
||||
tileMap: TileMap,
|
||||
tileMap: TileMapFileContent,
|
||||
levelIndex: number,
|
||||
atlasTexture: PIXI.BaseTexture<PIXI.Resource> | null,
|
||||
getTexture: (textureName: string) => PIXI.BaseTexture<PIXI.Resource>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# GDevelop IDE
|
||||
|
||||
This is the GDevelop 5 editor. It is based on [React](https://facebook.github.io/react/), [Material-UI](http://www.material-ui.com), [Pixi.js](https://github.com/pixijs/pixi.js) and [Electron](https://electron.atom.io/).
|
||||
This is the GDevelop 5 editor. It is based on [React](https://facebook.github.io/react/), [Material-UI](http://www.material-ui.com), [Pixi.js](https://github.com/pixijs/pixi.js) and [Electron](https://electron.atom.io/) for the desktop app.
|
||||
It uses GDevelop [core C++ classes compiled to Javascript](https://github.com/4ian/GDevelop.js) to work with GDevelop games.
|
||||
|
||||

|
||||
|
235
newIDE/app/flow-typed/npm/raven-js_v3.17.x.js
vendored
@@ -1,235 +0,0 @@
|
||||
// flow-typed signature: 4850a295b0a6cab60f9421a95997888f
|
||||
// flow-typed version: 5b150db5b6/raven-js_v3.17.x/flow_>=v0.38.x
|
||||
|
||||
type LogLevel = "critical" | "error" | "warning" | "info" | "debug";
|
||||
|
||||
type AutoBreadcrumbOptions = {
|
||||
xhr?: boolean,
|
||||
console?: boolean,
|
||||
dom?: boolean,
|
||||
location?: boolean
|
||||
};
|
||||
|
||||
type RavenInstrumentationOptions = {
|
||||
tryCatch?: boolean
|
||||
};
|
||||
|
||||
type Breadcrumb = {
|
||||
message?: string,
|
||||
category?: string,
|
||||
level?: LogLevel,
|
||||
data?: any,
|
||||
type?: BreadcrumbType
|
||||
};
|
||||
|
||||
type BreadcrumbType = "navigation" | "http";
|
||||
|
||||
type RavenOptions = {
|
||||
/** The log level associated with this event. Default: error */
|
||||
level?: LogLevel,
|
||||
|
||||
/** The name of the logger used by Sentry. Default: javascript */
|
||||
logger?: string,
|
||||
|
||||
/** The environment of the application you are monitoring with Sentry */
|
||||
environment?: string,
|
||||
|
||||
/** The release version of the application you are monitoring with Sentry */
|
||||
release?: string,
|
||||
|
||||
/** The name of the server or device that the client is running on */
|
||||
serverName?: string,
|
||||
|
||||
/** List of messages to be filtered out before being sent to Sentry. */
|
||||
ignoreErrors?: (RegExp | string)[],
|
||||
|
||||
/** Similar to ignoreErrors, but will ignore errors from whole urls patching a regex pattern. */
|
||||
ignoreUrls?: (RegExp | string)[],
|
||||
|
||||
/** The inverse of ignoreUrls. Only report errors from whole urls matching a regex pattern. */
|
||||
whitelistUrls?: (RegExp | string)[],
|
||||
|
||||
/** An array of regex patterns to indicate which urls are a part of your app. */
|
||||
includePaths?: (RegExp | string)[],
|
||||
|
||||
/** Additional data to be tagged onto the error. */
|
||||
tags?: {
|
||||
[id: string]: string
|
||||
},
|
||||
|
||||
/** set to true to get the stack trace of your message */
|
||||
stacktrace?: boolean,
|
||||
|
||||
extra?: any,
|
||||
|
||||
/** In some cases you may see issues where Sentry groups multiple events together when they should be separate entities. In other cases, Sentry simply doesn’t group events together because they’re so sporadic that they never look the same. */
|
||||
fingerprint?: string[],
|
||||
|
||||
/** A function which allows mutation of the data payload right before being sent to Sentry */
|
||||
dataCallback?: (data: any) => any,
|
||||
|
||||
/** A callback function that allows you to apply your own filters to determine if the message should be sent to Sentry. */
|
||||
shouldSendCallback?: (data: any) => boolean,
|
||||
|
||||
/** By default, Raven does not truncate messages. If you need to truncate characters for whatever reason, you may set this to limit the length. */
|
||||
maxMessageLength?: number,
|
||||
|
||||
/** By default, Raven will truncate URLs as they appear in breadcrumbs and other meta interfaces to 250 characters in order to minimize bytes over the wire. This does *not* affect URLs in stack traces. */
|
||||
maxUrlLength?: number,
|
||||
|
||||
/** Override the default HTTP data transport handler. */
|
||||
transport?: (options: RavenTransportOptions) => void,
|
||||
|
||||
/** Allow use of private/secretKey. */
|
||||
allowSecretKey?: boolean,
|
||||
|
||||
/** Enables/disables instrumentation of globals. */
|
||||
instrument?: boolean | RavenInstrumentationOptions,
|
||||
|
||||
/** Enables/disables automatic collection of breadcrumbs. */
|
||||
autoBreadcrumbs?: boolean | AutoBreadcrumbOptions
|
||||
};
|
||||
|
||||
type RavenTransportOptions = {
|
||||
url: string,
|
||||
data: any,
|
||||
auth: {
|
||||
sentry_version: string,
|
||||
sentry_client: string,
|
||||
sentry_key: string
|
||||
},
|
||||
onSuccess: () => void,
|
||||
onFailure: () => void
|
||||
};
|
||||
|
||||
declare module "raven-js" {
|
||||
declare type RavenPlugin = {
|
||||
(raven: Raven, ...args: any[]): Raven
|
||||
};
|
||||
|
||||
declare class Raven {
|
||||
/** Raven.js version. */
|
||||
VERSION: string,
|
||||
|
||||
Plugins: { [id: string]: RavenPlugin },
|
||||
|
||||
/*
|
||||
* Allow Raven to be configured as soon as it is loaded
|
||||
* It uses a global RavenConfig = {dsn: '...', config: {}}
|
||||
*/
|
||||
afterLoad(): void,
|
||||
|
||||
/*
|
||||
* Allow multiple versions of Raven to be installed.
|
||||
* Strip Raven from the global context and returns the instance.
|
||||
*/
|
||||
noConflict(): this,
|
||||
|
||||
/** Configure Raven with a DSN and extra options */
|
||||
config(dsn: string, options?: RavenOptions): this,
|
||||
|
||||
/*
|
||||
* Installs a global window.onerror error handler
|
||||
* to capture and report uncaught exceptions.
|
||||
* At this point, install() is required to be called due
|
||||
* to the way TraceKit is set up.
|
||||
*/
|
||||
install(): this,
|
||||
|
||||
/** Adds a plugin to Raven */
|
||||
addPlugin(plugin: RavenPlugin, ...pluginArgs: any[]): this,
|
||||
|
||||
/*
|
||||
* Wrap code within a context so Raven can capture errors
|
||||
* reliably across domains that is executed immediately.
|
||||
*/
|
||||
context(func: Function, ...args: any[]): void,
|
||||
context(options: RavenOptions, func: Function, ...args: any[]): void,
|
||||
|
||||
/** Wrap code within a context and returns back a new function to be executed */
|
||||
wrap(func: Function): Function,
|
||||
wrap(options: RavenOptions, func: Function): Function,
|
||||
wrap<T: Function>(func: T): T,
|
||||
wrap<T: Function>(options: RavenOptions, func: T): T,
|
||||
|
||||
/** Uninstalls the global error handler. */
|
||||
uninstall(): this,
|
||||
|
||||
/** Manually capture an exception and send it over to Sentry */
|
||||
captureException(ex: Error, options?: RavenOptions): this,
|
||||
|
||||
/** Manually send a message to Sentry */
|
||||
captureMessage(msg: string, options?: RavenOptions): this,
|
||||
|
||||
/** Log a breadcrumb */
|
||||
captureBreadcrumb(crumb: Breadcrumb): this,
|
||||
|
||||
/**
|
||||
* Clear the user context, removing the user data that would be sent to Sentry.
|
||||
*/
|
||||
setUserContext(): this,
|
||||
|
||||
/** Set a user to be sent along with the payload. */
|
||||
setUserContext(user: {
|
||||
id?: string,
|
||||
username?: string,
|
||||
email?: string
|
||||
}): this,
|
||||
|
||||
/** Merge extra attributes to be sent along with the payload. */
|
||||
setExtraContext(context: Object): this,
|
||||
|
||||
/** Merge tags to be sent along with the payload. */
|
||||
setTagsContext(tags: Object): this,
|
||||
|
||||
/** Clear all of the context. */
|
||||
clearContext(): this,
|
||||
|
||||
/** Get a copy of the current context. This cannot be mutated.*/
|
||||
getContext(): Object,
|
||||
|
||||
/** Override the default HTTP data transport handler. */
|
||||
setTransport(
|
||||
transportFunction: (options: RavenTransportOptions) => void
|
||||
): this,
|
||||
|
||||
/** Set environment of application */
|
||||
setEnvironment(environment: string): this,
|
||||
|
||||
/** Set release version of application */
|
||||
setRelease(release: string): this,
|
||||
|
||||
/** Get the latest raw exception that was captured by Raven.*/
|
||||
lastException(): Error,
|
||||
|
||||
/** An event id is a globally unique id for the event that was just sent. This event id can be used to find the exact event from within Sentry. */
|
||||
lastEventId(): string,
|
||||
|
||||
/** If you need to conditionally check if raven needs to be initialized or not, you can use the isSetup function. It will return true if Raven is already initialized. */
|
||||
isSetup(): boolean,
|
||||
|
||||
/** Specify a function that allows mutation of the data payload right before being sent to Sentry. */
|
||||
setDataCallback(data: any, orig?: any): this,
|
||||
|
||||
/** Specify a callback function that allows you to mutate or filter breadcrumbs when they are captured. */
|
||||
setBreadcrumbCallback(data: any, orig?: any): this,
|
||||
|
||||
/** Specify a callback function that allows you to apply your own filters to determine if the message should be sent to Sentry. */
|
||||
setShouldSendCallback(data: any, orig?: any): this,
|
||||
|
||||
/** Show Sentry user feedback dialog */
|
||||
showReportDialog(options?: {
|
||||
eventId?: string,
|
||||
dsn?: string,
|
||||
user?: {
|
||||
name?: string,
|
||||
email?: string
|
||||
}
|
||||
}): void,
|
||||
|
||||
/** Configure Raven DSN */
|
||||
setDSN(dsn: string): void
|
||||
}
|
||||
|
||||
declare export default Raven
|
||||
}
|
12
newIDE/app/package-lock.json
generated
@@ -36,7 +36,6 @@
|
||||
"pixi.js-legacy": "^6.1.2",
|
||||
"posthog-js": "^1.34.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"raven-js": "^3.19.1",
|
||||
"react": "16.14.0",
|
||||
"react-color": "2.13.8",
|
||||
"react-dnd": "7.7.0",
|
||||
@@ -33480,12 +33479,6 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/raven-js": {
|
||||
"version": "3.27.2",
|
||||
"resolved": "https://registry.npmjs.org/raven-js/-/raven-js-3.27.2.tgz",
|
||||
"integrity": "sha512-mFWQcXnhRFEQe5HeFroPaEghlnqy7F5E2J3Fsab189ondqUzcjwSVi7el7F36cr6PvQYXoZ1P2F5CSF2/azeMQ==",
|
||||
"deprecated": "Please upgrade to @sentry/browser. See the migration guide https://bit.ly/3ybOlo7"
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
@@ -67952,11 +67945,6 @@
|
||||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
||||
"dev": true
|
||||
},
|
||||
"raven-js": {
|
||||
"version": "3.27.2",
|
||||
"resolved": "https://registry.npmjs.org/raven-js/-/raven-js-3.27.2.tgz",
|
||||
"integrity": "sha512-mFWQcXnhRFEQe5HeFroPaEghlnqy7F5E2J3Fsab189ondqUzcjwSVi7el7F36cr6PvQYXoZ1P2F5CSF2/azeMQ=="
|
||||
},
|
||||
"raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
|
@@ -59,7 +59,6 @@
|
||||
"pixi.js-legacy": "^6.1.2",
|
||||
"posthog-js": "^1.34.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"raven-js": "^3.19.1",
|
||||
"react": "16.14.0",
|
||||
"react-color": "2.13.8",
|
||||
"react-dnd": "7.7.0",
|
||||
|
BIN
newIDE/app/public/res/asset-categories/Backgrounds.jpeg
Normal file
After Width: | Height: | Size: 152 KiB |
BIN
newIDE/app/public/res/asset-categories/Characters.jpeg
Normal file
After Width: | Height: | Size: 128 KiB |
BIN
newIDE/app/public/res/asset-categories/Full_game_pack.jpeg
Normal file
After Width: | Height: | Size: 154 KiB |
BIN
newIDE/app/public/res/asset-categories/Interface.jpeg
Normal file
After Width: | Height: | Size: 133 KiB |
BIN
newIDE/app/public/res/asset-categories/Prefabs.jpeg
Normal file
After Width: | Height: | Size: 206 KiB |
BIN
newIDE/app/public/res/asset-categories/Props.jpeg
Normal file
After Width: | Height: | Size: 103 KiB |
BIN
newIDE/app/public/res/asset-categories/Visual_Effects.jpeg
Normal file
After Width: | Height: | Size: 146 KiB |
@@ -365,7 +365,7 @@
|
||||
"value": "#93e500"
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"number": {
|
||||
"color": {
|
||||
"value": "#e8dc59"
|
||||
}
|
||||
|
@@ -66,7 +66,7 @@ export const AnnouncementsFeed = ({
|
||||
|
||||
return (
|
||||
<AlertMessage
|
||||
kind={announcement.type === 'warning' ? 'warning' : 'info'}
|
||||
kind={announcement.type}
|
||||
renderRightButton={
|
||||
buttonLabelByLocale && buttonUrl
|
||||
? () => (
|
||||
|
@@ -117,6 +117,7 @@ export const AssetStoreContext = React.createContext<AssetStoreState>({
|
||||
clearHistory: () => {},
|
||||
openSearchResultPage: () => {},
|
||||
openTagPage: tag => {},
|
||||
openAssetCategoryPage: category => {},
|
||||
openPackPage: assetPack => {},
|
||||
openDetailPage: assetShortHeader => {},
|
||||
openPrivateAssetPackInformationPage: privateAssetPackListingData => {},
|
||||
|
@@ -10,10 +10,12 @@ import { type PrivateAssetPackListingData } from '../Utils/GDevelopServices/Shop
|
||||
|
||||
export type AssetStorePageState = {|
|
||||
openedAssetPack: PublicAssetPack | PrivateAssetPack | null,
|
||||
openedAssetCategory: string | null,
|
||||
openedAssetShortHeader: ?AssetShortHeader,
|
||||
openedPrivateAssetPackListingData: ?PrivateAssetPackListingData,
|
||||
filtersState: FiltersState,
|
||||
scrollPosition?: ?number,
|
||||
displayAssets: boolean,
|
||||
|};
|
||||
|
||||
export type NavigationState = {|
|
||||
@@ -23,6 +25,7 @@ export type NavigationState = {|
|
||||
clearHistory: () => void,
|
||||
openSearchResultPage: () => void,
|
||||
openTagPage: string => void,
|
||||
openAssetCategoryPage: string => void,
|
||||
openPackPage: (PublicAssetPack | PrivateAssetPack) => void,
|
||||
openPrivateAssetPackInformationPage: PrivateAssetPackListingData => void,
|
||||
openDetailPage: AssetShortHeader => void,
|
||||
@@ -38,20 +41,31 @@ const noFilter: FiltersState = {
|
||||
|
||||
export const assetStoreHomePageState: AssetStorePageState = {
|
||||
openedAssetShortHeader: null,
|
||||
openedAssetCategory: null,
|
||||
openedAssetPack: null,
|
||||
openedPrivateAssetPackListingData: null,
|
||||
filtersState: noFilter,
|
||||
displayAssets: false,
|
||||
};
|
||||
|
||||
const searchPageState: AssetStorePageState = {
|
||||
openedAssetShortHeader: null,
|
||||
openedAssetCategory: null,
|
||||
openedAssetPack: null,
|
||||
openedPrivateAssetPackListingData: null,
|
||||
filtersState: noFilter,
|
||||
displayAssets: true,
|
||||
};
|
||||
|
||||
export const isHomePage = (pageState: AssetStorePageState) => {
|
||||
return pageState === assetStoreHomePageState;
|
||||
return (
|
||||
pageState === assetStoreHomePageState ||
|
||||
(!pageState.openedAssetShortHeader &&
|
||||
!pageState.openedPrivateAssetPackListingData &&
|
||||
!pageState.openedAssetPack &&
|
||||
pageState.filtersState === noFilter &&
|
||||
!pageState.displayAssets)
|
||||
);
|
||||
};
|
||||
|
||||
export const isSearchResultPage = (pageState: AssetStorePageState) => {
|
||||
@@ -122,8 +136,10 @@ export const useNavigation = (): NavigationState => {
|
||||
...previousHistory.previousPages,
|
||||
{
|
||||
openedAssetShortHeader: null,
|
||||
openedAssetCategory: null,
|
||||
openedAssetPack: null,
|
||||
openedPrivateAssetPackListingData: null,
|
||||
displayAssets: true,
|
||||
filtersState: {
|
||||
chosenCategory: {
|
||||
node: { name: tag, allChildrenTags: [], children: [] },
|
||||
@@ -138,33 +154,58 @@ export const useNavigation = (): NavigationState => {
|
||||
],
|
||||
}));
|
||||
},
|
||||
openPackPage: (assetPack: PublicAssetPack | PrivateAssetPack) => {
|
||||
openAssetCategoryPage: (category: string) => {
|
||||
setHistory(previousHistory => ({
|
||||
...previousHistory,
|
||||
previousPages: [
|
||||
...previousHistory.previousPages,
|
||||
{
|
||||
openedAssetShortHeader: null,
|
||||
openedAssetPack: assetPack,
|
||||
openedAssetCategory: category,
|
||||
openedAssetPack: null,
|
||||
openedPrivateAssetPackListingData: null,
|
||||
filtersState: {
|
||||
chosenCategory: {
|
||||
node: {
|
||||
name: assetPack.tag,
|
||||
allChildrenTags: [],
|
||||
children: [],
|
||||
},
|
||||
parentNodes: [],
|
||||
},
|
||||
chosenFilters: new Set(),
|
||||
addFilter: () => {},
|
||||
removeFilter: () => {},
|
||||
setChosenCategory: () => {},
|
||||
},
|
||||
filtersState: noFilter,
|
||||
displayAssets: false,
|
||||
},
|
||||
],
|
||||
}));
|
||||
},
|
||||
openPackPage: (assetPack: PublicAssetPack | PrivateAssetPack) => {
|
||||
setHistory(previousHistory => {
|
||||
const currentPage =
|
||||
previousHistory.previousPages[
|
||||
previousHistory.previousPages.length - 1
|
||||
];
|
||||
return {
|
||||
...previousHistory,
|
||||
previousPages: [
|
||||
...previousHistory.previousPages,
|
||||
{
|
||||
openedAssetShortHeader: null,
|
||||
openedAssetCategory:
|
||||
(currentPage && currentPage.openedAssetCategory) || null,
|
||||
openedAssetPack: assetPack,
|
||||
openedPrivateAssetPackListingData: null,
|
||||
displayAssets: true,
|
||||
filtersState: {
|
||||
chosenCategory: {
|
||||
node: {
|
||||
name: assetPack.tag,
|
||||
allChildrenTags: [],
|
||||
children: [],
|
||||
},
|
||||
parentNodes: [],
|
||||
},
|
||||
chosenFilters: new Set(),
|
||||
addFilter: () => {},
|
||||
removeFilter: () => {},
|
||||
setChosenCategory: () => {},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
},
|
||||
openPrivateAssetPackInformationPage: (
|
||||
assetPack: PrivateAssetPackListingData
|
||||
) => {
|
||||
@@ -174,9 +215,11 @@ export const useNavigation = (): NavigationState => {
|
||||
...previousHistory.previousPages,
|
||||
{
|
||||
openedAssetShortHeader: null,
|
||||
openedAssetCategory: null,
|
||||
openedAssetPack: null,
|
||||
openedPrivateAssetPackListingData: assetPack,
|
||||
filtersState: noFilter,
|
||||
displayAssets: false,
|
||||
},
|
||||
],
|
||||
}));
|
||||
@@ -188,9 +231,11 @@ export const useNavigation = (): NavigationState => {
|
||||
...previousHistory.previousPages,
|
||||
{
|
||||
openedAssetShortHeader: assetShortHeader,
|
||||
openedAssetCategory: null,
|
||||
openedAssetPack: null,
|
||||
openedPrivateAssetPackListingData: null,
|
||||
filtersState: noFilter,
|
||||
displayAssets: false,
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
@@ -19,12 +19,54 @@ import { useResponsiveWindowWidth } from '../UI/Reponsive/ResponsiveWindowMeasur
|
||||
import AuthenticatedUserContext from '../Profile/AuthenticatedUserContext';
|
||||
import Paper from '../UI/Paper';
|
||||
import { mergeArraysPerGroup } from '../Utils/Array';
|
||||
import { textEllipsisStyle } from '../UI/TextEllipsis';
|
||||
|
||||
const columns = 3;
|
||||
const columnsForSmallWindow = 1;
|
||||
const columnsForMediumWindow = 2;
|
||||
const categoryColumns = 4;
|
||||
const categoryColumnsForSmallWindow = 2;
|
||||
const categoryColumnsForMediumWindow = 3;
|
||||
const cellSpacing = 2;
|
||||
|
||||
export const assetCategories = {
|
||||
'full-game-pack': {
|
||||
title: <Trans>Full Game Packs</Trans>,
|
||||
imageAlt: 'Full game asset packs category',
|
||||
imageSource: 'res/asset-categories/Full_game_pack.jpeg',
|
||||
},
|
||||
character: {
|
||||
title: <Trans>Characters</Trans>,
|
||||
imageAlt: 'Characters asset packs category',
|
||||
imageSource: 'res/asset-categories/Characters.jpeg',
|
||||
},
|
||||
props: {
|
||||
title: <Trans>Props</Trans>,
|
||||
imageAlt: 'Props asset packs category',
|
||||
imageSource: 'res/asset-categories/Props.jpeg',
|
||||
},
|
||||
background: {
|
||||
title: <Trans>Backgrounds</Trans>,
|
||||
imageAlt: 'Backgrounds asset packs category',
|
||||
imageSource: 'res/asset-categories/Backgrounds.jpeg',
|
||||
},
|
||||
'visual-effect': {
|
||||
title: <Trans>Visual Effects</Trans>,
|
||||
imageAlt: 'Visual effects asset packs category',
|
||||
imageSource: 'res/asset-categories/Visual_Effects.jpeg',
|
||||
},
|
||||
interface: {
|
||||
title: <Trans>UI/Interface</Trans>,
|
||||
imageAlt: 'User Interface asset packs category',
|
||||
imageSource: 'res/asset-categories/Interface.jpeg',
|
||||
},
|
||||
prefab: {
|
||||
title: <Trans>Prefabs (Ready-to-use Objects)</Trans>,
|
||||
imageAlt: 'Prefabs asset packs category',
|
||||
imageSource: 'res/asset-categories/Prefabs.jpeg',
|
||||
},
|
||||
};
|
||||
|
||||
const styles = {
|
||||
grid: { margin: '0 10px' },
|
||||
priceTagContainer: {
|
||||
@@ -49,10 +91,8 @@ const styles = {
|
||||
margin: 4,
|
||||
},
|
||||
packTitle: {
|
||||
textOverflow: 'ellipsis',
|
||||
overflow: 'hidden',
|
||||
...textEllipsisStyle,
|
||||
overflowWrap: 'break-word',
|
||||
whiteSpace: 'nowrap',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -75,14 +115,13 @@ const PublicAssetPackTile = ({
|
||||
}: {|
|
||||
assetPack: PublicAssetPack,
|
||||
onSelect: () => void,
|
||||
/** Props needed so that GidList component can adjust tile size */
|
||||
/** Props needed so that GridList component can adjust tile size */
|
||||
style?: any,
|
||||
|}) => {
|
||||
const classesForGridListItem = useStylesForGridListItem();
|
||||
return (
|
||||
<GridListTile
|
||||
classes={classesForGridListItem}
|
||||
key={assetPack.tag}
|
||||
tabIndex={0}
|
||||
onKeyPress={(event: SyntheticKeyboardEvent<HTMLLIElement>): void => {
|
||||
if (shouldValidate(event)) {
|
||||
@@ -133,7 +172,6 @@ export const PrivateAssetPackTile = ({
|
||||
return (
|
||||
<GridListTile
|
||||
classes={classesForGridListItem}
|
||||
key={assetPackListingData.id}
|
||||
tabIndex={0}
|
||||
onKeyPress={(event: SyntheticKeyboardEvent<HTMLLIElement>): void => {
|
||||
if (shouldValidate(event)) {
|
||||
@@ -150,14 +188,13 @@ export const PrivateAssetPackTile = ({
|
||||
src={assetPackListingData.thumbnailUrls[0]}
|
||||
alt={`Preview image of asset pack ${assetPackListingData.name}`}
|
||||
/>
|
||||
{!owned && (
|
||||
<div style={styles.priceTagContainer}>
|
||||
<PriceTag
|
||||
value={assetPackListingData.prices[0].value}
|
||||
withOverlay
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div style={styles.priceTagContainer}>
|
||||
<PriceTag
|
||||
value={assetPackListingData.prices[0].value}
|
||||
withOverlay
|
||||
owned={owned}
|
||||
/>
|
||||
</div>
|
||||
<Column>
|
||||
<Line justifyContent="space-between" noMargin>
|
||||
<Text style={styles.packTitle} size="body2">
|
||||
@@ -173,6 +210,51 @@ export const PrivateAssetPackTile = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const CategoryTile = ({
|
||||
title,
|
||||
imageSource,
|
||||
imageAlt,
|
||||
onSelect,
|
||||
style,
|
||||
}: {|
|
||||
title: React.Node,
|
||||
imageSource: string,
|
||||
imageAlt: string,
|
||||
onSelect: () => void,
|
||||
/** Props needed so that GridList component can adjust tile size */
|
||||
style?: any,
|
||||
|}) => {
|
||||
const classesForGridListItem = useStylesForGridListItem();
|
||||
return (
|
||||
<GridListTile
|
||||
classes={classesForGridListItem}
|
||||
tabIndex={0}
|
||||
onKeyPress={(event: SyntheticKeyboardEvent<HTMLLIElement>): void => {
|
||||
if (shouldValidate(event)) {
|
||||
onSelect();
|
||||
}
|
||||
}}
|
||||
style={style}
|
||||
onClick={onSelect}
|
||||
>
|
||||
<Paper elevation={2} style={styles.paper} background="light">
|
||||
<CorsAwareImage
|
||||
style={styles.previewImage}
|
||||
src={imageSource}
|
||||
alt={imageAlt}
|
||||
/>
|
||||
<Column>
|
||||
<Line justifyContent="center" noMargin>
|
||||
<Text style={styles.packTitle} size="sub-title">
|
||||
{title}
|
||||
</Text>
|
||||
</Line>
|
||||
</Column>
|
||||
</Paper>
|
||||
</GridListTile>
|
||||
);
|
||||
};
|
||||
|
||||
export type AssetsHomeInterface = {|
|
||||
getScrollPosition: () => number,
|
||||
scrollToPosition: (y: number) => void,
|
||||
@@ -184,6 +266,8 @@ type Props = {|
|
||||
assetPackRandomOrdering: Array<number>,
|
||||
onPublicAssetPackSelection: PublicAssetPack => void,
|
||||
onPrivateAssetPackSelection: PrivateAssetPackListingData => void,
|
||||
onCategorySelection: string => void,
|
||||
openedAssetCategory: string | null,
|
||||
|};
|
||||
|
||||
export const AssetsHome = React.forwardRef<Props, AssetsHomeInterface>(
|
||||
@@ -194,6 +278,8 @@ export const AssetsHome = React.forwardRef<Props, AssetsHomeInterface>(
|
||||
assetPackRandomOrdering,
|
||||
onPublicAssetPackSelection,
|
||||
onPrivateAssetPackSelection,
|
||||
onCategorySelection,
|
||||
openedAssetCategory,
|
||||
}: Props,
|
||||
ref
|
||||
) => {
|
||||
@@ -219,18 +305,27 @@ export const AssetsHome = React.forwardRef<Props, AssetsHomeInterface>(
|
||||
},
|
||||
}));
|
||||
|
||||
const starterPacksTiles: Array<React.Node> = starterPacks.map(
|
||||
(assetPack, index) => (
|
||||
const starterPacksTiles: Array<React.Node> = starterPacks
|
||||
.filter(
|
||||
assetPack =>
|
||||
!openedAssetCategory ||
|
||||
assetPack.categories.includes(openedAssetCategory)
|
||||
)
|
||||
.map((assetPack, index) => (
|
||||
<PublicAssetPackTile
|
||||
assetPack={assetPack}
|
||||
onSelect={() => onPublicAssetPackSelection(assetPack)}
|
||||
key={`${assetPack.tag}-${index}`}
|
||||
/>
|
||||
)
|
||||
);
|
||||
));
|
||||
|
||||
const privateAssetPacksTiles: Array<React.Node> = privateAssetPacksListingData.map(
|
||||
assetPackListingData => (
|
||||
const privateAssetPacksTiles: Array<React.Node> = privateAssetPacksListingData
|
||||
.filter(
|
||||
assetPackListingData =>
|
||||
!openedAssetCategory ||
|
||||
assetPackListingData.categories.includes(openedAssetCategory)
|
||||
)
|
||||
.map(assetPackListingData => (
|
||||
<PrivateAssetPackTile
|
||||
assetPackListingData={assetPackListingData}
|
||||
onSelect={() => {
|
||||
@@ -244,8 +339,7 @@ export const AssetsHome = React.forwardRef<Props, AssetsHomeInterface>(
|
||||
}
|
||||
key={assetPackListingData.id}
|
||||
/>
|
||||
)
|
||||
);
|
||||
));
|
||||
|
||||
const allTiles = mergeArraysPerGroup(
|
||||
privateAssetPacksTiles,
|
||||
@@ -257,8 +351,63 @@ export const AssetsHome = React.forwardRef<Props, AssetsHomeInterface>(
|
||||
1
|
||||
);
|
||||
|
||||
const categoryTiles = Object.entries(assetCategories).map(
|
||||
// $FlowExpectedError - Object.entries does not infer well the type of the value.
|
||||
([id, { title, imageSource, imageAlt }]) => (
|
||||
<CategoryTile
|
||||
key={id}
|
||||
imageSource={imageSource}
|
||||
imageAlt={imageAlt}
|
||||
title={title}
|
||||
onSelect={() => {
|
||||
onCategorySelection(id);
|
||||
}}
|
||||
/>
|
||||
)
|
||||
);
|
||||
|
||||
const openedAssetCategoryTitle = openedAssetCategory
|
||||
? assetCategories[openedAssetCategory].title
|
||||
: null;
|
||||
|
||||
return (
|
||||
<ScrollView ref={scrollView}>
|
||||
{openedAssetCategory ? null : (
|
||||
<>
|
||||
<Column>
|
||||
<Line>
|
||||
<Text size="block-title">
|
||||
<Trans>Explore by category</Trans>
|
||||
</Text>
|
||||
</Line>
|
||||
</Column>
|
||||
<GridList
|
||||
cols={
|
||||
windowWidth === 'small'
|
||||
? categoryColumnsForSmallWindow
|
||||
: windowWidth === 'medium'
|
||||
? categoryColumnsForMediumWindow
|
||||
: categoryColumns
|
||||
}
|
||||
style={styles.grid}
|
||||
cellHeight="auto"
|
||||
spacing={cellSpacing}
|
||||
>
|
||||
{categoryTiles}
|
||||
</GridList>
|
||||
</>
|
||||
)}
|
||||
<Column>
|
||||
<Line>
|
||||
<Text size="block-title">
|
||||
{openedAssetCategoryTitle ? (
|
||||
openedAssetCategoryTitle
|
||||
) : (
|
||||
<Trans>All asset packs</Trans>
|
||||
)}
|
||||
</Text>
|
||||
</Line>
|
||||
</Column>
|
||||
<GridList
|
||||
cols={
|
||||
windowWidth === 'small'
|
||||
|
@@ -197,7 +197,7 @@ const getMergedInstalledWithDefaultEnumeratedObjectMetadataByCategory = ({
|
||||
name: 'PanelSpriteSlider::PanelSpriteSlider',
|
||||
fullName: i18n._(t`Slider`),
|
||||
description: i18n._(
|
||||
t`Let users select a numerical value byb dragging a slider.`
|
||||
t`Let users select a numerical value by dragging a slider.`
|
||||
),
|
||||
iconFilename:
|
||||
'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMy4wLjMsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iSWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgMzIgMzIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDMyIDMyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9DQo8L3N0eWxlPg0KPGNpcmNsZSBjbGFzcz0ic3QwIiBjeD0iMjMiIGN5PSI3IiByPSIzIi8+DQo8bGluZSBjbGFzcz0ic3QwIiB4MT0iMyIgeTE9IjciIHgyPSIyMCIgeTI9IjciLz4NCjxsaW5lIGNsYXNzPSJzdDAiIHgxPSIyOSIgeTE9IjciIHgyPSIyNiIgeTI9IjciLz4NCjxjaXJjbGUgY2xhc3M9InN0MCIgY3g9IjEyIiBjeT0iMTYiIHI9IjMiLz4NCjxsaW5lIGNsYXNzPSJzdDAiIHgxPSIzIiB5MT0iMTYiIHgyPSI5IiB5Mj0iMTYiLz4NCjxsaW5lIGNsYXNzPSJzdDAiIHgxPSIyOSIgeTE9IjE2IiB4Mj0iMTUiIHkyPSIxNiIvPg0KPGNpcmNsZSBjbGFzcz0ic3QwIiBjeD0iMjMiIGN5PSIyNSIgcj0iMyIvPg0KPGxpbmUgY2xhc3M9InN0MCIgeDE9IjMiIHkxPSIyNSIgeDI9IjIwIiB5Mj0iMjUiLz4NCjxsaW5lIGNsYXNzPSJzdDAiIHgxPSIyOSIgeTE9IjI1IiB4Mj0iMjYiIHkyPSIyNSIvPg0KPC9zdmc+DQo=',
|
||||
|
@@ -264,7 +264,9 @@ const PrivateAssetPackPurchaseDialog = ({
|
||||
<Line justifyContent="center" alignItems="center">
|
||||
<CircularProgress size={20} />
|
||||
<Spacer />
|
||||
<Text>Waiting for the purchase confirmation...</Text>
|
||||
<Text>
|
||||
<Trans>Waiting for the purchase confirmation...</Trans>
|
||||
</Text>
|
||||
</Line>
|
||||
<Spacer />
|
||||
<Line justifyContent="center">
|
||||
|
@@ -99,6 +99,7 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
const {
|
||||
openedAssetPack,
|
||||
openedAssetShortHeader,
|
||||
openedAssetCategory,
|
||||
openedPrivateAssetPackListingData,
|
||||
filtersState,
|
||||
} = navigationState.getCurrentPage();
|
||||
@@ -164,7 +165,11 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
return;
|
||||
}
|
||||
const scrollPosition = navigationState.getCurrentPage().scrollPosition;
|
||||
scrollPosition && scrollView.scrollToPosition(scrollPosition);
|
||||
if (scrollPosition) scrollView.scrollToPosition(scrollPosition);
|
||||
// If no saved scroll position, force scroll to 0 in case the displayed component
|
||||
// is the same as the previous page so the scroll is naturally kept between pages
|
||||
// although the user navigated and the scroll should be reset.
|
||||
else scrollView.scrollToPosition(0);
|
||||
hasAppliedSavedScrollPosition.current = true;
|
||||
},
|
||||
[getScrollView, navigationState]
|
||||
@@ -278,6 +283,14 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
[receivedAssetPacks, saveScrollPosition, navigationState, setSearchText]
|
||||
);
|
||||
|
||||
const selectAssetCategory = React.useCallback(
|
||||
(category: string) => {
|
||||
saveScrollPosition();
|
||||
navigationState.openAssetCategoryPage(category);
|
||||
},
|
||||
[navigationState, saveScrollPosition]
|
||||
);
|
||||
|
||||
// If the user has received the pack they are currently viewing,
|
||||
// we update the window to show it if they are not already on the pack page.
|
||||
React.useEffect(
|
||||
@@ -424,18 +437,15 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
/>
|
||||
</Column>
|
||||
</LineStackLayout>
|
||||
{!isOnHomePage && <Spacer />}
|
||||
<Spacer />
|
||||
<Column noMargin>
|
||||
<Line
|
||||
justifyContent="space-between"
|
||||
noMargin
|
||||
alignItems="center"
|
||||
>
|
||||
{isOnHomePage ? (
|
||||
<Text size="block-title">
|
||||
<Trans>Discover</Trans>
|
||||
</Text>
|
||||
) : (
|
||||
{(!isOnHomePage ||
|
||||
(isOnHomePage && !!openedAssetCategory)) && (
|
||||
<>
|
||||
<Column expand alignItems="flex-start" noMargin>
|
||||
<TextButton
|
||||
@@ -559,6 +569,8 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
assetPackRandomOrdering={assetPackRandomOrdering}
|
||||
onPublicAssetPackSelection={selectPublicAssetPack}
|
||||
onPrivateAssetPackSelection={selectPrivateAssetPack}
|
||||
onCategorySelection={selectAssetCategory}
|
||||
openedAssetCategory={openedAssetCategory}
|
||||
/>
|
||||
) : (
|
||||
<PlaceholderLoader />
|
||||
|
@@ -110,7 +110,11 @@ const MeasuresTable = (props: Props) => {
|
||||
) : (
|
||||
<div style={{ width: 24 }} />
|
||||
)}
|
||||
{rowData.name}
|
||||
{/*
|
||||
The name is wrapped in a span to prevent crashes when Google Translate
|
||||
translates the website. See https://github.com/4ian/GDevelop/issues/3453.
|
||||
*/}
|
||||
<span>{rowData.name}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@@ -325,6 +325,8 @@ export const ExtensionOptionsEditor = ({
|
||||
}}
|
||||
/>,
|
||||
]}
|
||||
flexColumnBody
|
||||
fullHeight
|
||||
open
|
||||
onRequestClose={() => {
|
||||
setResourceStoreOpen(false);
|
||||
|
@@ -162,7 +162,12 @@ const Instruction = (props: Props) => {
|
||||
}
|
||||
|
||||
const parameterMetadata = metadata.getParameter(parameterIndex);
|
||||
const parameterType = parameterMetadata.getType();
|
||||
// TODO Remove the ternary when any parameter declaration uses
|
||||
// 'number' instead of 'expression'.
|
||||
const parameterType: string =
|
||||
parameterMetadata.getType() === 'expression'
|
||||
? 'number'
|
||||
: parameterMetadata.getType();
|
||||
let expressionIsValid = true;
|
||||
if (
|
||||
gd.ParameterMetadata.isExpression('number', parameterType) ||
|
||||
|
@@ -27,6 +27,7 @@ import {
|
||||
tuneMatches,
|
||||
type SearchResult,
|
||||
sharedFuseConfiguration,
|
||||
getFuseSearchQueryForMultipleKeys,
|
||||
} from '../../../UI/Search/UseSearchStructuredItem';
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
@@ -107,17 +108,19 @@ export default class InstructionOrExpressionSelector<
|
||||
} = this.props;
|
||||
const { searchText } = this.state;
|
||||
|
||||
const extendSearchText = `'${searchText
|
||||
.trim()
|
||||
.split(' ')
|
||||
.join(" '")}`;
|
||||
|
||||
const displayedInstructionsList: Array<SearchResult<T>> =
|
||||
!!extendSearchText && this.searchApi
|
||||
? this.searchApi.search(extendSearchText).map(result => ({
|
||||
item: result.item,
|
||||
matches: tuneMatches(result, searchText),
|
||||
}))
|
||||
!!searchText && this.searchApi
|
||||
? this.searchApi
|
||||
.search(
|
||||
getFuseSearchQueryForMultipleKeys(searchText, [
|
||||
'displayedName',
|
||||
'fullGroupName',
|
||||
])
|
||||
)
|
||||
.map(result => ({
|
||||
item: result.item,
|
||||
matches: tuneMatches(result, searchText),
|
||||
}))
|
||||
: [];
|
||||
const hasResults = !searchText || !!displayedInstructionsList.length;
|
||||
|
||||
|
@@ -55,6 +55,8 @@ import {
|
||||
type SearchResult,
|
||||
tuneMatches,
|
||||
sharedFuseConfiguration,
|
||||
getFuseSearchQueryForSimpleArray,
|
||||
getFuseSearchQueryForMultipleKeys,
|
||||
} from '../../UI/Search/UseSearchStructuredItem';
|
||||
import { Column, Line } from '../../UI/Grid';
|
||||
|
||||
@@ -193,33 +195,37 @@ export default class InstructionOrObjectSelector extends React.PureComponent<
|
||||
_search = (searchText: string) => {
|
||||
if (searchText === '') return;
|
||||
|
||||
const extendSearchText = `'${searchText
|
||||
.trim()
|
||||
.split(' ')
|
||||
.join(" '")}`;
|
||||
const extendedSearchText = getFuseSearchQueryForSimpleArray(searchText);
|
||||
|
||||
this.setState({
|
||||
searchResults: {
|
||||
objects: this.objectSearchApi
|
||||
? this.objectSearchApi.search(extendSearchText).map(result => ({
|
||||
? this.objectSearchApi.search(extendedSearchText).map(result => ({
|
||||
item: result.item,
|
||||
matches: tuneMatches(result, searchText),
|
||||
}))
|
||||
: [],
|
||||
groups: this.groupSearchApi
|
||||
? this.groupSearchApi.search(extendSearchText).map(result => ({
|
||||
? this.groupSearchApi.search(extendedSearchText).map(result => ({
|
||||
item: result.item,
|
||||
matches: tuneMatches(result, searchText),
|
||||
}))
|
||||
: [],
|
||||
instructions: this.instructionSearchApi
|
||||
? this.instructionSearchApi.search(extendSearchText).map(result => ({
|
||||
item: result.item,
|
||||
matches: tuneMatches(result, searchText),
|
||||
}))
|
||||
? this.instructionSearchApi
|
||||
.search(
|
||||
getFuseSearchQueryForMultipleKeys(searchText, [
|
||||
'displayedName',
|
||||
'fullGroupName',
|
||||
])
|
||||
)
|
||||
.map(result => ({
|
||||
item: result.item,
|
||||
matches: tuneMatches(result, searchText),
|
||||
}))
|
||||
: [],
|
||||
tags: this.tagSearchApi
|
||||
? this.tagSearchApi.search(extendSearchText).map(result => ({
|
||||
? this.tagSearchApi.search(extendedSearchText).map(result => ({
|
||||
item: result.item,
|
||||
matches: tuneMatches(result, searchText),
|
||||
}))
|
||||
|
@@ -15,6 +15,7 @@ import { Column, Line, Spacer } from '../../../UI/Grid';
|
||||
import ObjectsRenderingService from '../../../ObjectsRendering/ObjectsRenderingService';
|
||||
import Paper from '../../../UI/Paper';
|
||||
import { mapVector } from '../../../Utils/MapFor';
|
||||
import { Trans } from '@lingui/macro';
|
||||
|
||||
const defaultTextStyle = {
|
||||
// Break words if they are too long to fit on a single line.
|
||||
@@ -414,7 +415,9 @@ export default function ExpressionAutocompletionsDisplayer({
|
||||
)}
|
||||
{remainingCount > 0 && (
|
||||
<Column justifyContent="flex-start">
|
||||
<Text>And others...</Text>
|
||||
<Text>
|
||||
<Trans>And others...</Trans>
|
||||
</Text>
|
||||
</Column>
|
||||
)}
|
||||
</ScrollView>
|
||||
|
@@ -26,6 +26,10 @@ import {
|
||||
ExplanationHeader,
|
||||
OnlineGameLink,
|
||||
} from '../GenericExporters/OnlineWebExport';
|
||||
import {
|
||||
hasValidSubscriptionPlan,
|
||||
onlineWebExportSizeOptions,
|
||||
} from '../../Utils/GDevelopServices/Usage';
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
type ExportState = null;
|
||||
@@ -152,12 +156,16 @@ export const browserOnlineWebExportPipeline: ExportPipeline<
|
||||
context: ExportPipelineContext<ExportState>,
|
||||
{ textFiles, blobFiles }: ResourcesDownloadOutput
|
||||
): Promise<Blob> => {
|
||||
const hasValidSubscription = hasValidSubscriptionPlan(context.subscription);
|
||||
return archiveFiles({
|
||||
blobFiles,
|
||||
textFiles,
|
||||
basePath: '/export/',
|
||||
onProgress: context.updateStepProgress,
|
||||
sizeLimit: 250 * 1000 * 1000,
|
||||
// Higher limit for users with a subscription.
|
||||
sizeOptions: hasValidSubscription
|
||||
? onlineWebExportSizeOptions.subscribed
|
||||
: onlineWebExportSizeOptions.guest,
|
||||
});
|
||||
},
|
||||
|
||||
|
@@ -257,6 +257,7 @@ export default class ExportLauncher extends Component<Props, State> {
|
||||
project,
|
||||
updateStepProgress: this._updateStepProgress,
|
||||
exportState: this.state.exportState,
|
||||
subscription: authenticatedUser.subscription,
|
||||
};
|
||||
setStep('export');
|
||||
this.setState({
|
||||
|
@@ -170,7 +170,7 @@ const ExportDialog = ({
|
||||
<TutorialButton
|
||||
key="tutorial"
|
||||
tutorialId="export-to-itch"
|
||||
label="How to export to Itch.io"
|
||||
label={<Trans>How to export to Itch.io"</Trans>}
|
||||
/>
|
||||
) : null,
|
||||
<FlatButton
|
||||
|
@@ -3,11 +3,13 @@ import * as React from 'react';
|
||||
import { type Build } from '../Utils/GDevelopServices/Build';
|
||||
import { type AuthenticatedUser } from '../Profile/AuthenticatedUserContext';
|
||||
import { type BuildStep } from './Builds/BuildStepsProgress';
|
||||
import { type Subscription } from '../Utils/GDevelopServices/Usage';
|
||||
|
||||
export type ExportPipelineContext<ExportState> = {|
|
||||
project: gdProject,
|
||||
exportState: ExportState,
|
||||
updateStepProgress: (count: number, total: number) => void,
|
||||
subscription: ?Subscription,
|
||||
|};
|
||||
|
||||
/**
|
||||
|
@@ -22,6 +22,10 @@ import {
|
||||
OnlineGameLink,
|
||||
} from '../GenericExporters/OnlineWebExport';
|
||||
import { downloadUrlsToLocalFiles } from '../../Utils/LocalFileDownloader';
|
||||
import {
|
||||
hasValidSubscriptionPlan,
|
||||
onlineWebExportSizeOptions,
|
||||
} from '../../Utils/GDevelopServices/Usage';
|
||||
const path = optionalRequire('path');
|
||||
const os = optionalRequire('os');
|
||||
const gd: libGDevelop = global.gd;
|
||||
@@ -156,11 +160,15 @@ export const localOnlineWebExportPipeline: ExportPipeline<
|
||||
context: ExportPipelineContext<ExportState>,
|
||||
{ temporaryOutputDir }: ResourcesDownloadOutput
|
||||
): Promise<CompressionOutput> => {
|
||||
const hasValidSubscription = hasValidSubscriptionPlan(context.subscription);
|
||||
const archiveOutputDir = os.tmpdir();
|
||||
return archiveLocalFolder({
|
||||
path: temporaryOutputDir,
|
||||
outputFilename: path.join(archiveOutputDir, 'game-archive.zip'),
|
||||
sizeLimit: 250 * 1000 * 1000,
|
||||
// Higher limit for users with a subscription.
|
||||
sizeOptions: hasValidSubscription
|
||||
? onlineWebExportSizeOptions.subscribed
|
||||
: onlineWebExportSizeOptions.guest,
|
||||
});
|
||||
},
|
||||
|
||||
|
@@ -23,7 +23,7 @@ import AuthenticatedUserContext from '../Profile/AuthenticatedUserContext';
|
||||
import PlaceholderError from '../UI/PlaceholderError';
|
||||
import SelectField from '../UI/SelectField';
|
||||
import SelectOption from '../UI/SelectOption';
|
||||
import { Chip } from '@material-ui/core';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import Builds from '../Export/Builds';
|
||||
import AlertMessage from '../UI/AlertMessage';
|
||||
import RaisedButton from '../UI/RaisedButton';
|
||||
@@ -431,6 +431,7 @@ export const GameDetailsDialog = ({
|
||||
undefined
|
||||
)
|
||||
}
|
||||
className="notranslate"
|
||||
label={username}
|
||||
color={index === 0 ? 'primary' : 'default'}
|
||||
/>
|
||||
|
@@ -194,7 +194,7 @@ export default class DocSearchArea extends React.Component<Props, State> {
|
||||
</React.Fragment>
|
||||
)}
|
||||
<Text align="right">
|
||||
This search is powered by{' '}
|
||||
<Trans>This search is powered by</Trans>{' '}
|
||||
<FlatButton
|
||||
onClick={() => Window.openExternalURL('http://algolia.com/')}
|
||||
label={'Algolia'}
|
||||
|
@@ -140,14 +140,18 @@ const LayerEditorDialog = (props: Props) => {
|
||||
</DismissableAlertMessage>
|
||||
) : null}
|
||||
<Text>
|
||||
There are {instancesCount} instances of objects on this layer.
|
||||
<Trans>
|
||||
There are {instancesCount} instances of objects on this layer.
|
||||
</Trans>
|
||||
</Text>
|
||||
{!props.project.getUseDeprecatedZeroAsDefaultZOrder() && (
|
||||
<Text>
|
||||
Objects created using events on this layer will be given a "Z
|
||||
order" of {highestZOrder + 1}, so that they appear in front of all
|
||||
objects of this layer. You can change this using the action to
|
||||
change an object Z order, after using an action to create it.
|
||||
<Trans>
|
||||
Objects created using events on this layer will be given a "Z
|
||||
order" of {highestZOrder + 1}, so that they appear in front of
|
||||
all objects of this layer. You can change this using the action
|
||||
to change an object Z order, after using an action to create it.
|
||||
</Trans>
|
||||
</Text>
|
||||
)}
|
||||
<InlineCheckbox
|
||||
|
@@ -179,7 +179,7 @@ export class ExternalEventsEditorContainer extends React.Component<
|
||||
<Line justifyContent="flex-start" noMargin>
|
||||
<TutorialButton
|
||||
tutorialId="Intermediate-externals"
|
||||
label="Watch the tutorial"
|
||||
label={<Trans>Watch tutorial</Trans>}
|
||||
renderIfNotFound={
|
||||
<HelpButton helpPagePath="/interface/events-editor/external-events" />
|
||||
}
|
||||
|
@@ -208,7 +208,7 @@ export class ExternalLayoutEditorContainer extends React.Component<
|
||||
<Line justifyContent="flex-start" noMargin>
|
||||
<TutorialButton
|
||||
tutorialId="Intermediate-externals"
|
||||
label="Watch the tutorial"
|
||||
label={<Trans>Watch tutorial</Trans>}
|
||||
renderIfNotFound={
|
||||
<HelpButton helpPagePath="/interface/events-editor/external-events" />
|
||||
}
|
||||
|
@@ -37,6 +37,7 @@ import PrivateAssetsAuthorizationProvider from '../AssetStore/PrivateAssets/Priv
|
||||
import InAppTutorialProvider from '../InAppTutorial/InAppTutorialProvider';
|
||||
import { SubscriptionSuggestionProvider } from '../Profile/Subscription/SubscriptionSuggestionContext';
|
||||
import { RouterContextProvider } from './RouterContext';
|
||||
import ErrorBoundary from '../UI/ErrorBoundary';
|
||||
|
||||
// Add the rtl plugin to the JSS instance to support RTL languages in material-ui components.
|
||||
const jss = create({
|
||||
@@ -82,52 +83,57 @@ const Providers = ({
|
||||
<GDevelopThemeContext.Provider value={theme.gdevelopTheme}>
|
||||
<StylesProvider jss={jss}>
|
||||
<ThemeProvider theme={theme.muiTheme}>
|
||||
<InAppTutorialProvider>
|
||||
<AuthenticatedUserProvider
|
||||
authentication={authentication}
|
||||
>
|
||||
<PublicProfileProvider>
|
||||
<I18n update>
|
||||
{({ i18n }) => (
|
||||
<EventsFunctionsExtensionsProvider
|
||||
i18n={i18n}
|
||||
makeEventsFunctionCodeWriter={
|
||||
makeEventsFunctionCodeWriter
|
||||
}
|
||||
eventsFunctionsExtensionWriter={
|
||||
eventsFunctionsExtensionWriter
|
||||
}
|
||||
eventsFunctionsExtensionOpener={
|
||||
eventsFunctionsExtensionOpener
|
||||
}
|
||||
>
|
||||
<AlertProvider>
|
||||
<SubscriptionSuggestionProvider>
|
||||
<CommandsContextProvider>
|
||||
<AssetStoreStateProvider>
|
||||
<ResourceStoreStateProvider>
|
||||
<ExampleStoreStateProvider>
|
||||
<ExtensionStoreStateProvider>
|
||||
<TutorialStateProvider>
|
||||
<AnnouncementsFeedStateProvider>
|
||||
<PrivateAssetsAuthorizationProvider>
|
||||
{children({ i18n })}
|
||||
</PrivateAssetsAuthorizationProvider>
|
||||
</AnnouncementsFeedStateProvider>
|
||||
</TutorialStateProvider>
|
||||
</ExtensionStoreStateProvider>
|
||||
</ExampleStoreStateProvider>
|
||||
</ResourceStoreStateProvider>
|
||||
</AssetStoreStateProvider>
|
||||
</CommandsContextProvider>
|
||||
</SubscriptionSuggestionProvider>
|
||||
</AlertProvider>
|
||||
</EventsFunctionsExtensionsProvider>
|
||||
)}
|
||||
</I18n>
|
||||
</PublicProfileProvider>
|
||||
</AuthenticatedUserProvider>
|
||||
</InAppTutorialProvider>
|
||||
<ErrorBoundary
|
||||
title="GDevelop encountered an issue"
|
||||
scope="app"
|
||||
>
|
||||
<InAppTutorialProvider>
|
||||
<AuthenticatedUserProvider
|
||||
authentication={authentication}
|
||||
>
|
||||
<PublicProfileProvider>
|
||||
<I18n update>
|
||||
{({ i18n }) => (
|
||||
<EventsFunctionsExtensionsProvider
|
||||
i18n={i18n}
|
||||
makeEventsFunctionCodeWriter={
|
||||
makeEventsFunctionCodeWriter
|
||||
}
|
||||
eventsFunctionsExtensionWriter={
|
||||
eventsFunctionsExtensionWriter
|
||||
}
|
||||
eventsFunctionsExtensionOpener={
|
||||
eventsFunctionsExtensionOpener
|
||||
}
|
||||
>
|
||||
<AlertProvider>
|
||||
<SubscriptionSuggestionProvider>
|
||||
<CommandsContextProvider>
|
||||
<AssetStoreStateProvider>
|
||||
<ResourceStoreStateProvider>
|
||||
<ExampleStoreStateProvider>
|
||||
<ExtensionStoreStateProvider>
|
||||
<TutorialStateProvider>
|
||||
<AnnouncementsFeedStateProvider>
|
||||
<PrivateAssetsAuthorizationProvider>
|
||||
{children({ i18n })}
|
||||
</PrivateAssetsAuthorizationProvider>
|
||||
</AnnouncementsFeedStateProvider>
|
||||
</TutorialStateProvider>
|
||||
</ExtensionStoreStateProvider>
|
||||
</ExampleStoreStateProvider>
|
||||
</ResourceStoreStateProvider>
|
||||
</AssetStoreStateProvider>
|
||||
</CommandsContextProvider>
|
||||
</SubscriptionSuggestionProvider>
|
||||
</AlertProvider>
|
||||
</EventsFunctionsExtensionsProvider>
|
||||
)}
|
||||
</I18n>
|
||||
</PublicProfileProvider>
|
||||
</AuthenticatedUserProvider>
|
||||
</InAppTutorialProvider>
|
||||
</ErrorBoundary>
|
||||
</ThemeProvider>
|
||||
</StylesProvider>
|
||||
</GDevelopThemeContext.Provider>
|
||||
|
@@ -2897,7 +2897,10 @@ const MainFrame = (props: Props) => {
|
||||
return (
|
||||
<TabContentContainer key={editorTab.key} active={isCurrentTab}>
|
||||
<CommandsContextScopedProvider active={isCurrentTab}>
|
||||
<ErrorBoundary>
|
||||
<ErrorBoundary
|
||||
title="This editor encountered a problem"
|
||||
scope="mainframe"
|
||||
>
|
||||
{editorTab.renderEditorContainer({
|
||||
isActive: isCurrentTab,
|
||||
extraEditorProps: editorTab.extraEditorProps,
|
||||
|
@@ -167,9 +167,11 @@ const PolygonSection = (props: PolygonSectionProps) => {
|
||||
<Accordion defaultExpanded>
|
||||
<AccordionHeader actions={polygonActions}>
|
||||
<Text displayInlineAsSpan>
|
||||
{verticesCount === 3 && `Triangle`}
|
||||
{verticesCount === 4 && `Quadrilateral`}
|
||||
{verticesCount >= 5 && `Polygon with ${verticesCount} vertices`}
|
||||
{verticesCount === 3 && <Trans>Triangle</Trans>}
|
||||
{verticesCount === 4 && <Trans>Quadrilateral</Trans>}
|
||||
{verticesCount >= 5 && (
|
||||
<Trans>Polygon with ${verticesCount} vertices</Trans>
|
||||
)}
|
||||
</Text>
|
||||
</AccordionHeader>
|
||||
<AccordionBody disableGutters>
|
||||
|
@@ -730,13 +730,13 @@ const ObjectsList = React.forwardRef<Props, ObjectsListInterface>(
|
||||
{
|
||||
label: i18n._(t`Tags`),
|
||||
submenu: buildTagsMenuTemplate({
|
||||
noTagLabel: 'No tags',
|
||||
noTagLabel: i18n._(t`No tags`),
|
||||
getAllTags: getAllObjectTags,
|
||||
selectedTags: getTagsFromString(object.getTags()),
|
||||
onChange: objectTags => {
|
||||
changeObjectTags(object, objectTags);
|
||||
},
|
||||
editTagsLabel: 'Add/edit tags...',
|
||||
editTagsLabel: i18n._(t`Add/edit tags...`),
|
||||
onEditTags: () => openEditTagDialog(object),
|
||||
}),
|
||||
},
|
||||
|
@@ -40,6 +40,10 @@ export type AuthenticatedUser = {|
|
||||
onSubscriptionUpdated: () => Promise<void>,
|
||||
onPurchaseSuccessful: () => Promise<void>,
|
||||
onSendEmailVerification: () => Promise<void>,
|
||||
onOpenEmailVerificationDialog: ({|
|
||||
sendEmailAutomatically: boolean,
|
||||
showSendEmailButton: boolean,
|
||||
|}) => void,
|
||||
onAcceptGameStatsEmail: () => Promise<void>,
|
||||
getAuthorizationHeader: () => Promise<string>,
|
||||
|};
|
||||
@@ -70,6 +74,7 @@ export const initialAuthenticatedUser = {
|
||||
onSubscriptionUpdated: async () => {},
|
||||
onPurchaseSuccessful: async () => {},
|
||||
onSendEmailVerification: async () => {},
|
||||
onOpenEmailVerificationDialog: () => {},
|
||||
onAcceptGameStatsEmail: async () => {},
|
||||
getAuthorizationHeader: () => Promise.reject(new Error('Unimplemented')),
|
||||
};
|
||||
|
@@ -3,12 +3,11 @@ import { Trans } from '@lingui/macro';
|
||||
|
||||
import * as React from 'react';
|
||||
import PlaceholderLoader from '../UI/PlaceholderLoader';
|
||||
import FlatButton from '../UI/FlatButton';
|
||||
import { ColumnStackLayout } from '../UI/Layout';
|
||||
import AlertMessage from '../UI/AlertMessage';
|
||||
import { type AuthenticatedUser } from './AuthenticatedUserContext';
|
||||
import { useIsMounted } from '../Utils/UseIsMounted';
|
||||
import ProfileDetails from './ProfileDetails';
|
||||
import RaisedButton from '../UI/RaisedButton';
|
||||
|
||||
type Props = {|
|
||||
onEditProfile: () => void,
|
||||
@@ -23,18 +22,14 @@ const AuthenticatedUserProfileDetails = ({
|
||||
}: Props) => {
|
||||
const profile = authenticatedUser.profile;
|
||||
const firebaseUser = authenticatedUser.firebaseUser;
|
||||
const isMounted = useIsMounted();
|
||||
const [emailSent, setEmailSent] = React.useState<boolean>(false);
|
||||
const sendEmail = React.useCallback(
|
||||
const openEmailVerificationDialog = React.useCallback(
|
||||
() => {
|
||||
authenticatedUser.onSendEmailVerification();
|
||||
setEmailSent(true);
|
||||
setTimeout(() => {
|
||||
if (!isMounted.current) return;
|
||||
setEmailSent(false);
|
||||
}, 3000);
|
||||
authenticatedUser.onOpenEmailVerificationDialog({
|
||||
sendEmailAutomatically: true,
|
||||
showSendEmailButton: false,
|
||||
});
|
||||
},
|
||||
[authenticatedUser, isMounted]
|
||||
[authenticatedUser]
|
||||
);
|
||||
|
||||
return firebaseUser && profile ? (
|
||||
@@ -43,23 +38,16 @@ const AuthenticatedUserProfileDetails = ({
|
||||
<AlertMessage
|
||||
kind="info"
|
||||
renderRightButton={() => (
|
||||
<FlatButton
|
||||
label={
|
||||
emailSent ? (
|
||||
<Trans>Email sent!</Trans>
|
||||
) : (
|
||||
<Trans>Send it again</Trans>
|
||||
)
|
||||
}
|
||||
onClick={sendEmail}
|
||||
disabled={emailSent}
|
||||
<RaisedButton
|
||||
label={<Trans>Send it again</Trans>}
|
||||
onClick={openEmailVerificationDialog}
|
||||
primary
|
||||
/>
|
||||
)}
|
||||
>
|
||||
<Trans>
|
||||
It looks like your email is not verified. Click on the link received
|
||||
by email to verify your account. Didn't receive it?
|
||||
You are missing out on asset store discounts and other benefits!
|
||||
Verify your email address. Didn't receive it?
|
||||
</Trans>
|
||||
</AlertMessage>
|
||||
)}
|
||||
|
@@ -26,7 +26,7 @@ import AuthenticatedUserContext, {
|
||||
import CreateAccountDialog from './CreateAccountDialog';
|
||||
import EditProfileDialog from './EditProfileDialog';
|
||||
import ChangeEmailDialog from './ChangeEmailDialog';
|
||||
import EmailVerificationPendingDialog from './EmailVerificationPendingDialog';
|
||||
import EmailVerificationDialog from './EmailVerificationDialog';
|
||||
import PreferencesContext, {
|
||||
type PreferencesValues,
|
||||
} from '../MainFrame/Preferences/PreferencesContext';
|
||||
@@ -58,7 +58,11 @@ type State = {|
|
||||
additionalUserInfoDialogOpen: boolean,
|
||||
authError: ?AuthError,
|
||||
resetPasswordDialogOpen: boolean,
|
||||
emailVerificationPendingDialogOpen: boolean,
|
||||
emailVerificationDialogOpen: boolean,
|
||||
emailVerificationDialogProps: {|
|
||||
sendEmailAutomatically: boolean,
|
||||
showSendEmailButton: boolean,
|
||||
|},
|
||||
forgotPasswordInProgress: boolean,
|
||||
changeEmailDialogOpen: boolean,
|
||||
changeEmailInProgress: boolean,
|
||||
@@ -80,7 +84,11 @@ export default class AuthenticatedUserProvider extends React.Component<
|
||||
additionalUserInfoDialogOpen: false,
|
||||
authError: null,
|
||||
resetPasswordDialogOpen: false,
|
||||
emailVerificationPendingDialogOpen: false,
|
||||
emailVerificationDialogOpen: false,
|
||||
emailVerificationDialogProps: {
|
||||
sendEmailAutomatically: false,
|
||||
showSendEmailButton: false,
|
||||
},
|
||||
forgotPasswordInProgress: false,
|
||||
changeEmailDialogOpen: false,
|
||||
changeEmailInProgress: false,
|
||||
@@ -88,6 +96,7 @@ export default class AuthenticatedUserProvider extends React.Component<
|
||||
};
|
||||
_automaticallyUpdateUserProfile = true;
|
||||
_hasNotifiedUserAboutAdditionalInfo = false;
|
||||
_hasNotifiedUserAboutEmailVerification = false;
|
||||
|
||||
componentDidMount() {
|
||||
this._resetAuthenticatedUser();
|
||||
@@ -152,12 +161,25 @@ export default class AuthenticatedUserProvider extends React.Component<
|
||||
onSubscriptionUpdated: this._fetchUserSubscriptionLimitsAndUsages,
|
||||
onPurchaseSuccessful: this._fetchUserAssets,
|
||||
onSendEmailVerification: this._doSendEmailVerification,
|
||||
onOpenEmailVerificationDialog: ({
|
||||
sendEmailAutomatically,
|
||||
showSendEmailButton,
|
||||
}: {|
|
||||
sendEmailAutomatically: boolean,
|
||||
showSendEmailButton: boolean,
|
||||
|}) =>
|
||||
this.openEmailVerificationDialog({
|
||||
open: true,
|
||||
sendEmailAutomatically,
|
||||
showSendEmailButton,
|
||||
}),
|
||||
onAcceptGameStatsEmail: this._doAcceptGameStatsEmail,
|
||||
getAuthorizationHeader: () =>
|
||||
this.props.authentication.getAuthorizationHeader(),
|
||||
},
|
||||
}));
|
||||
this._hasNotifiedUserAboutAdditionalInfo = false;
|
||||
this._hasNotifiedUserAboutEmailVerification = false;
|
||||
}
|
||||
|
||||
_reloadFirebaseProfile = async (): Promise<?FirebaseUser> => {
|
||||
@@ -359,17 +381,6 @@ export default class AuthenticatedUserProvider extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
// If the user has not filled their additional information, show
|
||||
// the dialog to fill it.
|
||||
// Use a state value to show the dialog only once.
|
||||
if (
|
||||
userProfile &&
|
||||
!this._hasNotifiedUserAboutAdditionalInfo &&
|
||||
shouldAskForAdditionalUserInfo(userProfile)
|
||||
) {
|
||||
setTimeout(() => this.openAdditionalUserInfoDialog(true), 1000);
|
||||
}
|
||||
|
||||
this.setState(({ authenticatedUser }) => ({
|
||||
authenticatedUser: {
|
||||
...authenticatedUser,
|
||||
@@ -377,6 +388,8 @@ export default class AuthenticatedUserProvider extends React.Component<
|
||||
loginState: 'done',
|
||||
},
|
||||
}));
|
||||
|
||||
this._notifyUserAboutEmailVerificationAndAdditionalInfo();
|
||||
};
|
||||
|
||||
_fetchUserSubscriptionLimitsAndUsages = async () => {
|
||||
@@ -528,6 +541,51 @@ export default class AuthenticatedUserProvider extends React.Component<
|
||||
}
|
||||
};
|
||||
|
||||
_notifyUserAboutEmailVerificationAndAdditionalInfo = () => {
|
||||
const { profile } = this.state.authenticatedUser;
|
||||
if (!profile) return;
|
||||
// If the user has not verified their email when logging in we show a dialog to do so.
|
||||
// - If they just registered, we don't send the email again as it will be sent automatically,
|
||||
// nor do we show a button to send again.
|
||||
// - If they are just logging in, we don't send the email but we show a button to send again.
|
||||
// Use a boolean to show the dialog only once.
|
||||
const accountAgeInMs = Date.now() - profile.createdAt;
|
||||
const hasJustCreatedAccount = accountAgeInMs < 1000 * 10; // 10 seconds.
|
||||
if (
|
||||
this.state.authenticatedUser.firebaseUser &&
|
||||
!this.state.authenticatedUser.firebaseUser.emailVerified &&
|
||||
!this._hasNotifiedUserAboutEmailVerification
|
||||
) {
|
||||
setTimeout(
|
||||
() =>
|
||||
this.openEmailVerificationDialog({
|
||||
open: true,
|
||||
sendEmailAutomatically: false,
|
||||
showSendEmailButton: !hasJustCreatedAccount,
|
||||
}),
|
||||
1000
|
||||
);
|
||||
} else {
|
||||
// If the user has not filled additional info, we show a dialog to do so.
|
||||
this._notifyUserAboutAdditionalInfo();
|
||||
}
|
||||
};
|
||||
|
||||
_notifyUserAboutAdditionalInfo = () => {
|
||||
const profile = this.state.authenticatedUser.profile;
|
||||
if (!profile) return;
|
||||
// If the user has not filled their additional information, show
|
||||
// the dialog to fill it, but ensure they have closed the email verification dialog first.
|
||||
// Use a boolean to show the dialog only once.
|
||||
if (
|
||||
profile &&
|
||||
!this._hasNotifiedUserAboutAdditionalInfo &&
|
||||
shouldAskForAdditionalUserInfo(profile)
|
||||
) {
|
||||
setTimeout(() => this.openAdditionalUserInfoDialog(true), 1000);
|
||||
}
|
||||
};
|
||||
|
||||
_doLogout = async () => {
|
||||
if (this.props.authentication) {
|
||||
await this.props.authentication.logout();
|
||||
@@ -704,7 +762,6 @@ export default class AuthenticatedUserProvider extends React.Component<
|
||||
if (!authentication) return;
|
||||
|
||||
await authentication.sendFirebaseEmailVerification();
|
||||
this.openEmailVerificationPendingDialog(true);
|
||||
};
|
||||
|
||||
_doAcceptGameStatsEmail = async () => {
|
||||
@@ -755,10 +812,28 @@ export default class AuthenticatedUserProvider extends React.Component<
|
||||
this._automaticallyUpdateUserProfile = true;
|
||||
};
|
||||
|
||||
openEmailVerificationPendingDialog = (open: boolean = true) => {
|
||||
openEmailVerificationDialog = ({
|
||||
open = true,
|
||||
sendEmailAutomatically = false,
|
||||
showSendEmailButton = false,
|
||||
}: {|
|
||||
open?: boolean,
|
||||
sendEmailAutomatically?: boolean,
|
||||
showSendEmailButton?: boolean,
|
||||
|}) => {
|
||||
this.setState({
|
||||
emailVerificationPendingDialogOpen: open,
|
||||
emailVerificationDialogOpen: open,
|
||||
emailVerificationDialogProps: {
|
||||
sendEmailAutomatically: open ? sendEmailAutomatically : false, // reset to false when closing dialog.
|
||||
showSendEmailButton: open ? showSendEmailButton : false, // reset to false when closing dialog.
|
||||
},
|
||||
});
|
||||
// We save the fact that the user has seen the dialog when they close it.
|
||||
// And we show them the additional info dialog if they haven't seen it yet.
|
||||
if (!open) {
|
||||
this._hasNotifiedUserAboutEmailVerification = true;
|
||||
this._notifyUserAboutAdditionalInfo();
|
||||
}
|
||||
};
|
||||
|
||||
openResetPassword = (open: boolean = true) => {
|
||||
@@ -787,7 +862,9 @@ export default class AuthenticatedUserProvider extends React.Component<
|
||||
|
||||
showUserSnackbar = ({ message }: { message: ?React.Node }) => {
|
||||
this.setState({
|
||||
userSnackbarMessage: message,
|
||||
// The message is wrapped here to prevent crashes when Google Translate
|
||||
// translates the website. See https://github.com/4ian/GDevelop/issues/3453.
|
||||
userSnackbarMessage: message ? <span>{message}</span> : null,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -875,17 +952,21 @@ export default class AuthenticatedUserProvider extends React.Component<
|
||||
updateInProgress={this.state.editInProgress}
|
||||
/>
|
||||
)}
|
||||
{this.state.emailVerificationPendingDialogOpen && (
|
||||
<EmailVerificationPendingDialog
|
||||
{this.state.emailVerificationDialogOpen && (
|
||||
<EmailVerificationDialog
|
||||
authenticatedUser={this.state.authenticatedUser}
|
||||
onClose={() => {
|
||||
this.openEmailVerificationPendingDialog(false);
|
||||
this.openEmailVerificationDialog({
|
||||
open: false,
|
||||
});
|
||||
this.state.authenticatedUser
|
||||
.onRefreshFirebaseProfile()
|
||||
.catch(() => {
|
||||
// Ignore any error, we can't do much.
|
||||
});
|
||||
}}
|
||||
{...this.state.emailVerificationDialogProps}
|
||||
onSendEmail={this._doSendEmailVerification}
|
||||
/>
|
||||
)}
|
||||
<Snackbar
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// @flow
|
||||
import { Trans } from '@lingui/macro';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import React from 'react';
|
||||
import FlatButton from '../UI/FlatButton';
|
||||
import Dialog, { DialogPrimaryButton } from '../UI/Dialog';
|
||||
import { User as FirebaseUser } from 'firebase/auth';
|
||||
@@ -13,6 +13,7 @@ import LeftLoader from '../UI/LeftLoader';
|
||||
import { ColumnStackLayout } from '../UI/Layout';
|
||||
import TextField from '../UI/TextField';
|
||||
import { getEmailErrorText } from './CreateAccountDialog';
|
||||
import { emailRegex } from './ForgotPasswordDialog';
|
||||
|
||||
type Props = {|
|
||||
firebaseUser: FirebaseUser,
|
||||
@@ -22,72 +23,88 @@ type Props = {|
|
||||
error: ?AuthError,
|
||||
|};
|
||||
|
||||
type State = {|
|
||||
form: ChangeEmailForm,
|
||||
|};
|
||||
const ChangeEmailDialog = ({
|
||||
onClose,
|
||||
onChangeEmail,
|
||||
firebaseUser,
|
||||
changeEmailInProgress,
|
||||
error,
|
||||
}: Props) => {
|
||||
const [email, setEmail] = React.useState(firebaseUser.email);
|
||||
const [isEmailValid, setIsEmailValid] = React.useState<boolean>(true);
|
||||
|
||||
export default class ChangeEmailDialog extends Component<Props, State> {
|
||||
state = {
|
||||
form: {
|
||||
email: this.props.firebaseUser.email,
|
||||
},
|
||||
const doChangeEmail = async () => {
|
||||
const trimmedEmail = email.trim();
|
||||
setEmail(trimmedEmail);
|
||||
setIsEmailValid(emailRegex.test(trimmedEmail));
|
||||
|
||||
if (changeEmailInProgress || !email || !isEmailValid) return;
|
||||
|
||||
await onChangeEmail({
|
||||
email,
|
||||
});
|
||||
};
|
||||
|
||||
_onChangeEmail = () => {
|
||||
if (this.props.changeEmailInProgress) return;
|
||||
|
||||
const { form } = this.state;
|
||||
this.props.onChangeEmail(form);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { onClose, changeEmailInProgress, error } = this.props;
|
||||
const actions = [
|
||||
<FlatButton
|
||||
label={<Trans>Back</Trans>}
|
||||
disabled={changeEmailInProgress}
|
||||
key="back"
|
||||
primary={false}
|
||||
onClick={onClose}
|
||||
/>,
|
||||
<LeftLoader isLoading={changeEmailInProgress} key="change-email">
|
||||
<DialogPrimaryButton
|
||||
label={<Trans>Save</Trans>}
|
||||
primary
|
||||
onClick={this._onChangeEmail}
|
||||
return (
|
||||
<Dialog
|
||||
title={<Trans>Change your email</Trans>}
|
||||
actions={[
|
||||
<FlatButton
|
||||
label={<Trans>Back</Trans>}
|
||||
disabled={changeEmailInProgress}
|
||||
/>
|
||||
</LeftLoader>,
|
||||
];
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
title={<Trans>Change your email</Trans>}
|
||||
actions={actions}
|
||||
maxWidth="sm"
|
||||
cannotBeDismissed={changeEmailInProgress}
|
||||
onRequestClose={onClose}
|
||||
onApply={this._onChangeEmail}
|
||||
open
|
||||
key="back"
|
||||
primary={false}
|
||||
onClick={onClose}
|
||||
/>,
|
||||
<LeftLoader isLoading={changeEmailInProgress} key="change-email">
|
||||
<DialogPrimaryButton
|
||||
label={<Trans>Save</Trans>}
|
||||
primary
|
||||
onClick={doChangeEmail}
|
||||
disabled={changeEmailInProgress}
|
||||
/>
|
||||
</LeftLoader>,
|
||||
]}
|
||||
maxWidth="xs"
|
||||
cannotBeDismissed={changeEmailInProgress}
|
||||
onRequestClose={onClose}
|
||||
onApply={doChangeEmail}
|
||||
open
|
||||
>
|
||||
<form
|
||||
onSubmit={event => {
|
||||
// Prevent browser to navigate on form submission.
|
||||
event.preventDefault();
|
||||
doChangeEmail();
|
||||
}}
|
||||
autoComplete="on"
|
||||
name="changeEmail"
|
||||
>
|
||||
<ColumnStackLayout noMargin>
|
||||
<TextField
|
||||
value={this.state.form.email}
|
||||
value={email}
|
||||
floatingLabelText={<Trans>Email</Trans>}
|
||||
errorText={getEmailErrorText(error)}
|
||||
errorText={
|
||||
getEmailErrorText(error) ||
|
||||
(!isEmailValid ? <Trans>Invalid email address</Trans> : null)
|
||||
}
|
||||
fullWidth
|
||||
disabled={changeEmailInProgress}
|
||||
required
|
||||
onChange={(e, value) => {
|
||||
this.setState({
|
||||
form: {
|
||||
...this.state.form,
|
||||
email: value,
|
||||
},
|
||||
});
|
||||
if (!isEmailValid) setIsEmailValid(true);
|
||||
setEmail(value);
|
||||
}}
|
||||
onBlur={event => {
|
||||
const trimmedEmail = event.currentTarget.value.trim();
|
||||
setEmail(trimmedEmail);
|
||||
setIsEmailValid(emailRegex.test(trimmedEmail));
|
||||
}}
|
||||
/>
|
||||
</ColumnStackLayout>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
</form>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChangeEmailDialog;
|
||||
|
@@ -121,7 +121,7 @@ const CreateAccountDialog = ({
|
||||
if (!canCreateAccount) return;
|
||||
try {
|
||||
await onCreateAccount({
|
||||
email,
|
||||
email: email.trim(),
|
||||
password,
|
||||
username,
|
||||
getNewsletterEmail,
|
||||
@@ -194,50 +194,68 @@ const CreateAccountDialog = ({
|
||||
</LineStackLayout>
|
||||
</Column>
|
||||
<div style={styles.formContainer}>
|
||||
<ColumnStackLayout noMargin>
|
||||
<UsernameField
|
||||
value={username}
|
||||
onChange={(e, value) => {
|
||||
setUsername(value);
|
||||
}}
|
||||
allowEmpty
|
||||
onAvailabilityChecked={setUsernameAvailability}
|
||||
onAvailabilityCheckLoading={setIsValidatingUsername}
|
||||
isValidatingUsername={isValidatingUsername}
|
||||
disabled={createAccountInProgress}
|
||||
/>
|
||||
<TextField
|
||||
value={email}
|
||||
floatingLabelText={<Trans>Email</Trans>}
|
||||
errorText={getEmailErrorText(error)}
|
||||
fullWidth
|
||||
required
|
||||
onChange={(e, value) => {
|
||||
setEmail(value);
|
||||
}}
|
||||
disabled={createAccountInProgress}
|
||||
/>
|
||||
<TextField
|
||||
value={password}
|
||||
floatingLabelText={<Trans>Password</Trans>}
|
||||
errorText={getPasswordErrorText(error)}
|
||||
type="password"
|
||||
fullWidth
|
||||
required
|
||||
onChange={(e, value) => {
|
||||
setPassword(value);
|
||||
}}
|
||||
disabled={createAccountInProgress}
|
||||
/>
|
||||
<Checkbox
|
||||
label={<Trans>I want to receive the GDevelop Newsletter</Trans>}
|
||||
checked={getNewsletterEmail}
|
||||
onCheck={(e, value) => {
|
||||
setGetNewsletterEmail(value);
|
||||
}}
|
||||
disabled={createAccountInProgress}
|
||||
/>
|
||||
</ColumnStackLayout>
|
||||
<form
|
||||
onSubmit={event => {
|
||||
// Prevent browser to navigate on form submission.
|
||||
event.preventDefault();
|
||||
createAccount();
|
||||
}}
|
||||
autoComplete="on"
|
||||
name="createAccount"
|
||||
>
|
||||
<ColumnStackLayout noMargin>
|
||||
<UsernameField
|
||||
value={username}
|
||||
onChange={(e, value) => {
|
||||
setUsername(value);
|
||||
}}
|
||||
allowEmpty
|
||||
onAvailabilityChecked={setUsernameAvailability}
|
||||
onAvailabilityCheckLoading={setIsValidatingUsername}
|
||||
isValidatingUsername={isValidatingUsername}
|
||||
disabled={createAccountInProgress}
|
||||
/>
|
||||
<TextField
|
||||
value={email}
|
||||
floatingLabelText={<Trans>Email</Trans>}
|
||||
errorText={getEmailErrorText(error)}
|
||||
fullWidth
|
||||
required
|
||||
onChange={(e, value) => {
|
||||
setEmail(value);
|
||||
}}
|
||||
onBlur={event => {
|
||||
setEmail(event.currentTarget.value.trim());
|
||||
}}
|
||||
disabled={createAccountInProgress}
|
||||
/>
|
||||
<TextField
|
||||
value={password}
|
||||
floatingLabelText={<Trans>Password</Trans>}
|
||||
errorText={getPasswordErrorText(error)}
|
||||
type="password"
|
||||
fullWidth
|
||||
required
|
||||
onChange={(e, value) => {
|
||||
setPassword(value);
|
||||
}}
|
||||
disabled={createAccountInProgress}
|
||||
/>
|
||||
<Checkbox
|
||||
label={<Trans>I want to receive the GDevelop Newsletter</Trans>}
|
||||
checked={getNewsletterEmail}
|
||||
onCheck={(e, value) => {
|
||||
setGetNewsletterEmail(value);
|
||||
}}
|
||||
disabled={createAccountInProgress}
|
||||
/>
|
||||
{/*
|
||||
This input is needed so that the browser submits the form when
|
||||
Enter key is pressed. See https://stackoverflow.com/questions/4196681/form-not-submitting-when-pressing-enter
|
||||
*/}
|
||||
<input type="submit" value="Submit" style={{ display: 'none' }} />
|
||||
</ColumnStackLayout>
|
||||
</form>
|
||||
</div>
|
||||
<BackgroundText>
|
||||
<MarkdownText
|
||||
|
@@ -5,6 +5,7 @@ import * as React from 'react';
|
||||
import RaisedButton from '../UI/RaisedButton';
|
||||
import { Column, Line } from '../UI/Grid';
|
||||
import {
|
||||
hasValidSubscriptionPlan,
|
||||
type CurrentUsage,
|
||||
type Subscription,
|
||||
} from '../Utils/GDevelopServices/Usage';
|
||||
@@ -27,8 +28,9 @@ const CurrentUsageDisplayer = ({
|
||||
SubscriptionSuggestionContext
|
||||
);
|
||||
if (!currentUsage) return <PlaceholderLoader />;
|
||||
const hasSubscription = subscription && !!subscription.planId;
|
||||
const noSubscription = subscription && !subscription.planId;
|
||||
const hasSubscription = hasValidSubscriptionPlan(subscription);
|
||||
const loadedButHasNoSubscription =
|
||||
subscription && !hasValidSubscriptionPlan(subscription);
|
||||
|
||||
return (
|
||||
<Column noMargin>
|
||||
@@ -58,14 +60,14 @@ const CurrentUsageDisplayer = ({
|
||||
/>
|
||||
</Line>
|
||||
)}
|
||||
{noSubscription && (
|
||||
{loadedButHasNoSubscription && (
|
||||
<Text>
|
||||
<Trans>
|
||||
You don't have a subscription. Get one to increase the limits!
|
||||
</Trans>
|
||||
</Text>
|
||||
)}
|
||||
{noSubscription && (
|
||||
{loadedButHasNoSubscription && (
|
||||
<Line justifyContent="center" alignItems="center">
|
||||
<RaisedButton
|
||||
label={<Trans>Get a subscription</Trans>}
|
||||
|
@@ -124,67 +124,82 @@ const EditProfileDialog = ({
|
||||
onApply={edit}
|
||||
open
|
||||
>
|
||||
<ColumnStackLayout noMargin>
|
||||
<UsernameField
|
||||
initialUsername={profile.username}
|
||||
value={username}
|
||||
onChange={(e, value) => {
|
||||
setUsername(value);
|
||||
}}
|
||||
errorText={getUsernameErrorText(error)}
|
||||
onAvailabilityChecked={setUsernameAvailability}
|
||||
onAvailabilityCheckLoading={setIsValidatingUsername}
|
||||
isValidatingUsername={isValidatingUsername}
|
||||
disabled={updateProfileInProgress}
|
||||
/>
|
||||
<TextField
|
||||
value={description}
|
||||
floatingLabelText={<Trans>Bio</Trans>}
|
||||
fullWidth
|
||||
multiline
|
||||
rows={3}
|
||||
rowsMax={5}
|
||||
translatableHintText={t`What are you using GDevelop for?`}
|
||||
onChange={(e, value) => {
|
||||
setDescription(value);
|
||||
}}
|
||||
disabled={updateProfileInProgress}
|
||||
floatingLabelFixed
|
||||
/>
|
||||
<TextField
|
||||
value={donateLink}
|
||||
floatingLabelText={<Trans>Donate link</Trans>}
|
||||
fullWidth
|
||||
translatableHintText={t`Do you have a Patreon? Ko-fi? Paypal?`}
|
||||
onChange={(e, value) => {
|
||||
setDonateLink(value);
|
||||
}}
|
||||
disabled={updateProfileInProgress}
|
||||
floatingLabelFixed
|
||||
helperMarkdownText={i18n._(
|
||||
t`Add a link to your donation page. It will be displayed on your Liluo.io profile and game pages.`
|
||||
)}
|
||||
errorText={donateLinkFormattingError}
|
||||
/>
|
||||
<Checkbox
|
||||
label={<Trans>I want to receive the GDevelop Newsletter</Trans>}
|
||||
checked={getNewsletterEmail}
|
||||
onCheck={(e, value) => {
|
||||
setGetNewsletterEmail(value);
|
||||
}}
|
||||
disabled={updateProfileInProgress}
|
||||
/>
|
||||
<Checkbox
|
||||
label={
|
||||
<Trans>I want to receive weekly stats about my games</Trans>
|
||||
}
|
||||
checked={getGameStatsEmail}
|
||||
onCheck={(e, value) => {
|
||||
setGetGameStatsEmail(value);
|
||||
}}
|
||||
disabled={updateProfileInProgress}
|
||||
/>
|
||||
</ColumnStackLayout>
|
||||
<form
|
||||
onSubmit={event => {
|
||||
// Prevent browser to navigate on form submission.
|
||||
event.preventDefault();
|
||||
edit();
|
||||
}}
|
||||
autoComplete="on"
|
||||
name="editProfile"
|
||||
>
|
||||
<ColumnStackLayout noMargin>
|
||||
<UsernameField
|
||||
initialUsername={profile.username}
|
||||
value={username}
|
||||
onChange={(e, value) => {
|
||||
setUsername(value);
|
||||
}}
|
||||
errorText={getUsernameErrorText(error)}
|
||||
onAvailabilityChecked={setUsernameAvailability}
|
||||
onAvailabilityCheckLoading={setIsValidatingUsername}
|
||||
isValidatingUsername={isValidatingUsername}
|
||||
disabled={updateProfileInProgress}
|
||||
/>
|
||||
<TextField
|
||||
value={description}
|
||||
floatingLabelText={<Trans>Bio</Trans>}
|
||||
fullWidth
|
||||
multiline
|
||||
rows={3}
|
||||
rowsMax={5}
|
||||
translatableHintText={t`What are you using GDevelop for?`}
|
||||
onChange={(e, value) => {
|
||||
setDescription(value);
|
||||
}}
|
||||
disabled={updateProfileInProgress}
|
||||
floatingLabelFixed
|
||||
/>
|
||||
<TextField
|
||||
value={donateLink}
|
||||
floatingLabelText={<Trans>Donate link</Trans>}
|
||||
fullWidth
|
||||
translatableHintText={t`Do you have a Patreon? Ko-fi? Paypal?`}
|
||||
onChange={(e, value) => {
|
||||
setDonateLink(value);
|
||||
}}
|
||||
disabled={updateProfileInProgress}
|
||||
floatingLabelFixed
|
||||
helperMarkdownText={i18n._(
|
||||
t`Add a link to your donation page. It will be displayed on your Liluo.io profile and game pages.`
|
||||
)}
|
||||
errorText={donateLinkFormattingError}
|
||||
/>
|
||||
<Checkbox
|
||||
label={<Trans>I want to receive the GDevelop Newsletter</Trans>}
|
||||
checked={getNewsletterEmail}
|
||||
onCheck={(e, value) => {
|
||||
setGetNewsletterEmail(value);
|
||||
}}
|
||||
disabled={updateProfileInProgress}
|
||||
/>
|
||||
<Checkbox
|
||||
label={
|
||||
<Trans>I want to receive weekly stats about my games</Trans>
|
||||
}
|
||||
checked={getGameStatsEmail}
|
||||
onCheck={(e, value) => {
|
||||
setGetGameStatsEmail(value);
|
||||
}}
|
||||
disabled={updateProfileInProgress}
|
||||
/>
|
||||
{/*
|
||||
This input is needed so that the browser submits the form when
|
||||
Enter key is pressed. See https://stackoverflow.com/questions/4196681/form-not-submitting-when-pressing-enter
|
||||
*/}
|
||||
<input type="submit" value="Submit" style={{ display: 'none' }} />
|
||||
</ColumnStackLayout>
|
||||
</form>
|
||||
</Dialog>
|
||||
)}
|
||||
</I18n>
|
||||
|
137
newIDE/app/src/Profile/EmailVerificationDialog.js
Normal file
@@ -0,0 +1,137 @@
|
||||
// @flow
|
||||
import { Trans } from '@lingui/macro';
|
||||
|
||||
import React from 'react';
|
||||
import FlatButton from '../UI/FlatButton';
|
||||
import Dialog, { DialogPrimaryButton } from '../UI/Dialog';
|
||||
import { type AuthenticatedUser } from './AuthenticatedUserContext';
|
||||
import BackgroundText from '../UI/BackgroundText';
|
||||
import Text from '../UI/Text';
|
||||
import { useInterval } from '../Utils/UseInterval';
|
||||
import CircularProgress from '../UI/CircularProgress';
|
||||
import GDevelopGLogo from '../UI/CustomSvgIcons/GDevelopGLogo';
|
||||
import { ColumnStackLayout, LineStackLayout } from '../UI/Layout';
|
||||
import RaisedButton from '../UI/RaisedButton';
|
||||
import UserVerified from '../UI/CustomSvgIcons/UserVerified';
|
||||
|
||||
type Props = {|
|
||||
onClose: () => void,
|
||||
authenticatedUser: AuthenticatedUser,
|
||||
sendEmailAutomatically: boolean,
|
||||
showSendEmailButton: boolean,
|
||||
onSendEmail: () => Promise<void>,
|
||||
|};
|
||||
|
||||
export default function EmailVerificationDialog({
|
||||
onClose,
|
||||
authenticatedUser,
|
||||
sendEmailAutomatically,
|
||||
showSendEmailButton,
|
||||
onSendEmail,
|
||||
}: Props) {
|
||||
const isVerified =
|
||||
!!authenticatedUser.firebaseUser &&
|
||||
!!authenticatedUser.firebaseUser.emailVerified;
|
||||
|
||||
const [hasSentEmailManually, setHasSentEmailManually] = React.useState(false);
|
||||
|
||||
// Send the email once on dialog opening if configured as so.
|
||||
React.useEffect(
|
||||
() => {
|
||||
if (!isVerified && sendEmailAutomatically) {
|
||||
onSendEmail();
|
||||
}
|
||||
},
|
||||
[isVerified, onSendEmail, sendEmailAutomatically]
|
||||
);
|
||||
|
||||
// Check every 5 seconds if the email has been verified.
|
||||
useInterval(
|
||||
() => {
|
||||
authenticatedUser.onRefreshFirebaseProfile().catch(() => {
|
||||
// Ignore any error, will be retried anyway.
|
||||
});
|
||||
},
|
||||
isVerified ? null : 5000
|
||||
);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
title={null} // This dialog has a custom design to be more welcoming, the title is set in the content.
|
||||
actions={[
|
||||
isVerified ? (
|
||||
<DialogPrimaryButton
|
||||
label={<Trans>Done!</Trans>}
|
||||
key="close"
|
||||
primary
|
||||
onClick={onClose}
|
||||
/>
|
||||
) : (
|
||||
<FlatButton
|
||||
label={<Trans>I'll do it later</Trans>}
|
||||
key="close"
|
||||
primary={false}
|
||||
onClick={onClose}
|
||||
/>
|
||||
),
|
||||
]}
|
||||
maxWidth="sm"
|
||||
open
|
||||
onRequestClose={onClose}
|
||||
onApply={onClose}
|
||||
>
|
||||
<ColumnStackLayout
|
||||
noMargin
|
||||
expand
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
>
|
||||
<GDevelopGLogo fontSize="large" />
|
||||
{!authenticatedUser.firebaseUser ? null : !authenticatedUser
|
||||
.firebaseUser.emailVerified ? (
|
||||
<ColumnStackLayout noMargin alignItems="center">
|
||||
<Text size="title" align="center">
|
||||
<Trans>Confirm your email</Trans>
|
||||
</Text>
|
||||
<Text align="center">
|
||||
<Trans>
|
||||
You will get access to special discounts on the GDevelop asset
|
||||
store, as well as weekly stats about your games.
|
||||
</Trans>
|
||||
</Text>
|
||||
{!hasSentEmailManually && showSendEmailButton ? (
|
||||
<RaisedButton
|
||||
primary
|
||||
label={<Trans>Send it again</Trans>}
|
||||
onClick={() => {
|
||||
setHasSentEmailManually(true);
|
||||
onSendEmail();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<BackgroundText>
|
||||
<LineStackLayout justifyContent="center" alignItems="center">
|
||||
<CircularProgress size={20} />
|
||||
<Text>
|
||||
<Trans>
|
||||
Email sent to
|
||||
{authenticatedUser.firebaseUser.email}, waiting for
|
||||
validation...
|
||||
</Trans>
|
||||
</Text>
|
||||
</LineStackLayout>
|
||||
</BackgroundText>
|
||||
)}
|
||||
</ColumnStackLayout>
|
||||
) : (
|
||||
<LineStackLayout justifyContent="center" alignItems="center">
|
||||
<UserVerified />
|
||||
<Text size="title" align="center">
|
||||
<Trans>Email verified</Trans>
|
||||
</Text>
|
||||
</LineStackLayout>
|
||||
)}
|
||||
</ColumnStackLayout>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
@@ -1,92 +0,0 @@
|
||||
// @flow
|
||||
import { Trans } from '@lingui/macro';
|
||||
|
||||
import React from 'react';
|
||||
import FlatButton from '../UI/FlatButton';
|
||||
import Dialog, { DialogPrimaryButton } from '../UI/Dialog';
|
||||
import { type AuthenticatedUser } from './AuthenticatedUserContext';
|
||||
import { Column, Line, Spacer } from '../UI/Grid';
|
||||
import BackgroundText from '../UI/BackgroundText';
|
||||
import VerifiedUser from '@material-ui/icons/VerifiedUser';
|
||||
import Text from '../UI/Text';
|
||||
import { useInterval } from '../Utils/UseInterval';
|
||||
import CircularProgress from '../UI/CircularProgress';
|
||||
|
||||
type Props = {|
|
||||
onClose: () => void,
|
||||
authenticatedUser: AuthenticatedUser,
|
||||
|};
|
||||
|
||||
export default function EmailVerificationPendingDialog({
|
||||
onClose,
|
||||
authenticatedUser,
|
||||
}: Props) {
|
||||
const isVerified =
|
||||
!!authenticatedUser &&
|
||||
!!authenticatedUser.firebaseUser &&
|
||||
!!authenticatedUser.firebaseUser.emailVerified;
|
||||
useInterval(
|
||||
() => {
|
||||
authenticatedUser.onRefreshFirebaseProfile().catch(() => {
|
||||
// Ignore any error, will be retried anyway.
|
||||
});
|
||||
},
|
||||
isVerified ? null : 3900
|
||||
);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
title={<Trans>Verifying your email</Trans>}
|
||||
actions={[
|
||||
isVerified ? (
|
||||
<DialogPrimaryButton
|
||||
label={<Trans>Done!</Trans>}
|
||||
key="close"
|
||||
primary
|
||||
onClick={onClose}
|
||||
/>
|
||||
) : (
|
||||
<FlatButton
|
||||
label={<Trans>Cancel and close</Trans>}
|
||||
key="close"
|
||||
primary={false}
|
||||
onClick={onClose}
|
||||
/>
|
||||
),
|
||||
]}
|
||||
maxWidth="sm"
|
||||
open
|
||||
onRequestClose={onClose}
|
||||
onApply={onClose}
|
||||
>
|
||||
{!isVerified ? (
|
||||
<Column>
|
||||
<Line justifyContent="center" alignItems="center">
|
||||
<CircularProgress size={20} />
|
||||
<Spacer />
|
||||
<Text>Waiting for the email verification...</Text>
|
||||
</Line>
|
||||
<Spacer />
|
||||
<Line justifyContent="center">
|
||||
<BackgroundText>
|
||||
<Trans>
|
||||
Check your inbox and click the link to verify your email address
|
||||
- and come back here when it's done.
|
||||
</Trans>
|
||||
</BackgroundText>
|
||||
</Line>
|
||||
</Column>
|
||||
) : (
|
||||
<Column>
|
||||
<Line justifyContent="center" alignItems="center">
|
||||
<VerifiedUser />
|
||||
<Spacer />
|
||||
<Text>
|
||||
<Trans>Your email is now verified!</Trans>
|
||||
</Text>
|
||||
</Line>
|
||||
</Column>
|
||||
)}
|
||||
</Dialog>
|
||||
);
|
||||
}
|
@@ -10,6 +10,8 @@ import { type ForgotPasswordForm } from '../Utils/GDevelopServices/Authenticatio
|
||||
import LeftLoader from '../UI/LeftLoader';
|
||||
import Text from '../UI/Text';
|
||||
|
||||
export const emailRegex = /^(.+)@(.+)$/;
|
||||
|
||||
type Props = {|
|
||||
onClose: () => void,
|
||||
onForgotPassword: ForgotPasswordForm => Promise<void>,
|
||||
@@ -19,10 +21,13 @@ const ForgotPasswordDialog = ({ onClose, onForgotPassword }: Props) => {
|
||||
const [email, setEmail] = React.useState('');
|
||||
const [resetDone, setResetDone] = React.useState(false);
|
||||
const [resetInProgress, setResetInProgress] = React.useState(false);
|
||||
const emailRegex = /^(.+)@(.+)$/;
|
||||
const isEmailValid = emailRegex.test(email);
|
||||
const [isEmailValid, setIsEmailValid] = React.useState<boolean>(true);
|
||||
|
||||
const doResetPassword = async () => {
|
||||
const trimmedEmail = email.trim();
|
||||
setEmail(trimmedEmail);
|
||||
setIsEmailValid(emailRegex.test(trimmedEmail));
|
||||
|
||||
if (resetInProgress || !email || !isEmailValid) return;
|
||||
setResetInProgress(true);
|
||||
|
||||
@@ -61,8 +66,8 @@ const ForgotPasswordDialog = ({ onClose, onForgotPassword }: Props) => {
|
||||
maxWidth="xs"
|
||||
onApply={doResetPassword}
|
||||
>
|
||||
<Column noMargin>
|
||||
{resetDone ? (
|
||||
{resetDone ? (
|
||||
<Column noMargin>
|
||||
<Text>
|
||||
<Trans>
|
||||
You should have received an email containing instructions to reset
|
||||
@@ -70,18 +75,43 @@ const ForgotPasswordDialog = ({ onClose, onForgotPassword }: Props) => {
|
||||
password in GDevelop.
|
||||
</Trans>
|
||||
</Text>
|
||||
) : (
|
||||
<TextField
|
||||
autoFocus="desktop"
|
||||
value={email}
|
||||
floatingLabelText={<Trans>Email</Trans>}
|
||||
onChange={(e, value) => {
|
||||
setEmail(value);
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
</Column>
|
||||
</Column>
|
||||
) : (
|
||||
<form
|
||||
onSubmit={event => {
|
||||
// Prevent browser to navigate on form submission.
|
||||
event.preventDefault();
|
||||
doResetPassword();
|
||||
}}
|
||||
autoComplete="on"
|
||||
name="resetPassword"
|
||||
>
|
||||
<Column noMargin>
|
||||
<TextField
|
||||
autoFocus="desktop"
|
||||
value={email}
|
||||
floatingLabelText={<Trans>Email</Trans>}
|
||||
onChange={(e, value) => {
|
||||
if (!isEmailValid) setIsEmailValid(true);
|
||||
setEmail(value);
|
||||
}}
|
||||
errorText={
|
||||
!isEmailValid ? (
|
||||
<Trans>Invalid email address.</Trans>
|
||||
) : (
|
||||
undefined
|
||||
)
|
||||
}
|
||||
fullWidth
|
||||
onBlur={event => {
|
||||
const trimmedEmail = event.currentTarget.value.trim();
|
||||
setEmail(trimmedEmail);
|
||||
setIsEmailValid(emailRegex.test(trimmedEmail));
|
||||
}}
|
||||
/>
|
||||
</Column>
|
||||
</form>
|
||||
)}
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
@@ -55,7 +55,7 @@ const LoginDialog = ({
|
||||
if (loginInProgress) return;
|
||||
|
||||
onLogin({
|
||||
email,
|
||||
email: email.trim(),
|
||||
password,
|
||||
});
|
||||
};
|
||||
@@ -105,7 +105,7 @@ const LoginDialog = ({
|
||||
alignItems="center"
|
||||
>
|
||||
<GDevelopGLogo fontSize="large" />
|
||||
<Text size="title">
|
||||
<Text size="title" align="center">
|
||||
<Trans>Log in to your account</Trans>
|
||||
</Text>
|
||||
<Column noMargin alignItems="center">
|
||||
@@ -123,30 +123,48 @@ const LoginDialog = ({
|
||||
</Link>
|
||||
</Column>
|
||||
<div style={styles.formContainer}>
|
||||
<ColumnStackLayout noMargin>
|
||||
<TextField
|
||||
autoFocus="desktop"
|
||||
value={email}
|
||||
floatingLabelText={<Trans>Email</Trans>}
|
||||
errorText={getEmailErrorText(error)}
|
||||
onChange={(e, value) => {
|
||||
setEmail(value);
|
||||
}}
|
||||
fullWidth
|
||||
disabled={loginInProgress}
|
||||
/>
|
||||
<TextField
|
||||
value={password}
|
||||
floatingLabelText={<Trans>Password</Trans>}
|
||||
errorText={getPasswordErrorText(error)}
|
||||
type="password"
|
||||
onChange={(e, value) => {
|
||||
setPassword(value);
|
||||
}}
|
||||
fullWidth
|
||||
disabled={loginInProgress}
|
||||
/>
|
||||
</ColumnStackLayout>
|
||||
<form
|
||||
onSubmit={event => {
|
||||
// Prevent browser to navigate on form submission.
|
||||
event.preventDefault();
|
||||
doLogin();
|
||||
}}
|
||||
autoComplete="on"
|
||||
name="login"
|
||||
>
|
||||
<ColumnStackLayout noMargin>
|
||||
<TextField
|
||||
autoFocus="desktop"
|
||||
value={email}
|
||||
floatingLabelText={<Trans>Email</Trans>}
|
||||
errorText={getEmailErrorText(error)}
|
||||
onChange={(e, value) => {
|
||||
setEmail(value);
|
||||
}}
|
||||
onBlur={event => {
|
||||
setEmail(event.currentTarget.value.trim());
|
||||
}}
|
||||
fullWidth
|
||||
disabled={loginInProgress}
|
||||
/>
|
||||
<TextField
|
||||
value={password}
|
||||
floatingLabelText={<Trans>Password</Trans>}
|
||||
errorText={getPasswordErrorText(error)}
|
||||
type="password"
|
||||
onChange={(e, value) => {
|
||||
setPassword(value);
|
||||
}}
|
||||
fullWidth
|
||||
disabled={loginInProgress}
|
||||
/>
|
||||
{/*
|
||||
This input is needed so that the browser submits the form when
|
||||
Enter key is pressed. See https://stackoverflow.com/questions/4196681/form-not-submitting-when-pressing-enter
|
||||
*/}
|
||||
<input type="submit" value="Submit" style={{ display: 'none' }} />
|
||||
</ColumnStackLayout>
|
||||
</form>
|
||||
</div>
|
||||
<Link
|
||||
href=""
|
||||
|
@@ -2,15 +2,15 @@
|
||||
import { I18n } from '@lingui/react';
|
||||
import { t, Trans } from '@lingui/macro';
|
||||
import React from 'react';
|
||||
import FlatButton from '../../UI/FlatButton';
|
||||
import Dialog, { DialogPrimaryButton } from '../../UI/Dialog';
|
||||
import { type AuthenticatedUser } from '../AuthenticatedUserContext';
|
||||
import { ColumnStackLayout } from '../../UI/Layout';
|
||||
import SemiControlledTextField from '../../UI/SemiControlledTextField';
|
||||
import LeftLoader from '../../UI/LeftLoader';
|
||||
import { redeemCode } from '../../Utils/GDevelopServices/Usage';
|
||||
import { extractGDevelopApiErrorStatusAndCode } from '../../Utils/GDevelopServices/Errors';
|
||||
import AlertMessage from '../../UI/AlertMessage';
|
||||
import FlatButton from '../UI/FlatButton';
|
||||
import Dialog, { DialogPrimaryButton } from '../UI/Dialog';
|
||||
import { type AuthenticatedUser } from './AuthenticatedUserContext';
|
||||
import { ColumnStackLayout } from '../UI/Layout';
|
||||
import SemiControlledTextField from '../UI/SemiControlledTextField';
|
||||
import LeftLoader from '../UI/LeftLoader';
|
||||
import { redeemCode } from '../Utils/GDevelopServices/Usage';
|
||||
import { extractGDevelopApiErrorStatusAndCode } from '../Utils/GDevelopServices/Errors';
|
||||
import AlertMessage from '../UI/AlertMessage';
|
||||
|
||||
type Props = {|
|
||||
onClose: (hasJustRedeemedCode: boolean) => Promise<void>,
|
||||
@@ -122,37 +122,49 @@ export default function RedeemCodeDialog({
|
||||
maxWidth="sm"
|
||||
open
|
||||
>
|
||||
<ColumnStackLayout noMargin>
|
||||
<SemiControlledTextField
|
||||
value={redemptionCode}
|
||||
onChange={setRedemptionCode}
|
||||
translatableHintText={t`Enter your code here`}
|
||||
floatingLabelText={<Trans>Redemption code</Trans>}
|
||||
floatingLabelFixed
|
||||
errorText={getRedeemCodeErrorText(error)}
|
||||
/>
|
||||
|
||||
{!subscription ||
|
||||
!subscription.planId ? null : !!subscription.redemptionCodeValidUntil ? (
|
||||
<AlertMessage kind="warning">
|
||||
<Trans>
|
||||
You currently have a subscription, applied thanks to a
|
||||
redemption code, valid until{' '}
|
||||
{i18n.date(subscription.redemptionCodeValidUntil)}. If you
|
||||
redeem another code, your existing subscription will be
|
||||
canceled and not redeemable anymore!
|
||||
</Trans>
|
||||
</AlertMessage>
|
||||
) : (
|
||||
<AlertMessage kind="info">
|
||||
<Trans>
|
||||
You currently have a subscription. If you redeem a code, the
|
||||
existing subscription will be cancelled and replaced by the
|
||||
one given by the code.
|
||||
</Trans>
|
||||
</AlertMessage>
|
||||
)}
|
||||
</ColumnStackLayout>
|
||||
<form
|
||||
onSubmit={event => {
|
||||
event.preventDefault();
|
||||
onRedeemCode();
|
||||
}}
|
||||
autoComplete="on"
|
||||
name="redeemSubscriptionCoupon"
|
||||
>
|
||||
<ColumnStackLayout noMargin>
|
||||
<SemiControlledTextField
|
||||
value={redemptionCode}
|
||||
onChange={setRedemptionCode}
|
||||
translatableHintText={t`Enter your code here`}
|
||||
floatingLabelText={<Trans>Redemption code</Trans>}
|
||||
floatingLabelFixed
|
||||
errorText={getRedeemCodeErrorText(error)}
|
||||
autoFocus="desktop"
|
||||
/>
|
||||
{!subscription ||
|
||||
!subscription.planId ? null : !!subscription.redemptionCodeValidUntil ? ( // No subscription, do not show a warning.
|
||||
subscription.redemptionCodeValidUntil > Date.now() ? ( // Has valid subscription.
|
||||
<AlertMessage kind="warning">
|
||||
<Trans>
|
||||
You currently have a subscription, applied thanks to a
|
||||
redemption code, valid until{' '}
|
||||
{i18n.date(subscription.redemptionCodeValidUntil)}. If you
|
||||
redeem another code, your existing subscription will be
|
||||
canceled and not redeemable anymore!
|
||||
</Trans>
|
||||
</AlertMessage>
|
||||
) : null // Has expired subscription, do not show a warning.
|
||||
) : (
|
||||
// Has a subscription, but not applied thanks to a redemption code.
|
||||
<AlertMessage kind="info">
|
||||
<Trans>
|
||||
You currently have a subscription. If you redeem a code, the
|
||||
existing subscription will be cancelled and replaced by the
|
||||
one given by the code.
|
||||
</Trans>
|
||||
</AlertMessage>
|
||||
)}
|
||||
</ColumnStackLayout>
|
||||
</form>
|
||||
</Dialog>
|
||||
)}
|
||||
</I18n>
|
@@ -14,6 +14,7 @@ import {
|
||||
} from '../../Utils/Analytics/EventSender';
|
||||
import { SubscriptionSuggestionContext } from './SubscriptionSuggestionContext';
|
||||
import Text from '../../UI/Text';
|
||||
import { hasValidSubscriptionPlan } from '../../Utils/GDevelopServices/Usage';
|
||||
|
||||
export type SubscriptionCheckerInterface = {|
|
||||
checkUserHasSubscription: () => boolean,
|
||||
@@ -51,12 +52,9 @@ const SubscriptionChecker = React.forwardRef<
|
||||
};
|
||||
|
||||
const checkUserHasSubscription = () => {
|
||||
if (authenticatedUser.subscription) {
|
||||
const hasPlan = !!authenticatedUser.subscription.planId;
|
||||
if (hasPlan) {
|
||||
setDialogOpen(false);
|
||||
return true;
|
||||
}
|
||||
if (hasValidSubscriptionPlan(authenticatedUser.subscription)) {
|
||||
setDialogOpen(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
setDialogOpen(true);
|
||||
|
@@ -37,6 +37,20 @@ type Props = {
|
||||
isManageSubscriptionLoading: boolean,
|
||||
};
|
||||
|
||||
/**
|
||||
* Here are the possible cases:
|
||||
* - Subscription null: loading. (The backend always return a subscription)
|
||||
* - Subscription with no plan: show a message to invite the user to subscribe.
|
||||
* - Subscription bought:
|
||||
* - with Stripe, they can easily manage it only as well as upgrade/downgrade.
|
||||
* - with Paypal, in order to upgrade/downgrade, the subscription need to be canceled first.
|
||||
* - Subscription with a redemption code:
|
||||
* - If the code is still valid, show a message to indicate when it will expire
|
||||
* and show a warning if trying to buy a new one as it will cancel the current one.
|
||||
* - If the code is expired, show a message to invite the user to re-subscribe.
|
||||
* We will need to cancel the current expired subscription, but don't show a warning.
|
||||
*/
|
||||
|
||||
const SubscriptionDetails = ({
|
||||
subscription,
|
||||
isManageSubscriptionLoading,
|
||||
@@ -57,28 +71,41 @@ const SubscriptionDetails = ({
|
||||
[subscription]
|
||||
);
|
||||
|
||||
return subscription ? (
|
||||
const redemptionCodeExpirationDate =
|
||||
subscription && subscription.redemptionCodeValidUntil;
|
||||
const isSubscriptionExpired =
|
||||
!!redemptionCodeExpirationDate && redemptionCodeExpirationDate < Date.now();
|
||||
|
||||
if (!subscription) return <PlaceholderLoader />;
|
||||
|
||||
return (
|
||||
<Column noMargin>
|
||||
<Line alignItems="center">
|
||||
<Text size="block-title">My online services subscription</Text>
|
||||
<Text size="block-title">
|
||||
<Trans>My online services subscription</Trans>
|
||||
</Text>
|
||||
</Line>
|
||||
{userPlan && userPlan.planId ? (
|
||||
{userPlan && userPlan.planId && !isSubscriptionExpired ? (
|
||||
<ColumnStackLayout noMargin>
|
||||
<PlanCard
|
||||
plan={userPlan}
|
||||
hidePrice={!!subscription.redemptionCodeValidUntil}
|
||||
hidePrice={!!redemptionCodeExpirationDate}
|
||||
actions={[
|
||||
<LeftLoader
|
||||
key="manage-online"
|
||||
isLoading={isManageSubscriptionLoading}
|
||||
>
|
||||
<FlatButton
|
||||
label={<Trans>Manage online</Trans>}
|
||||
primary
|
||||
onClick={onManageSubscription}
|
||||
disabled={isManageSubscriptionLoading}
|
||||
/>
|
||||
</LeftLoader>,
|
||||
!redemptionCodeExpirationDate ? (
|
||||
<LeftLoader
|
||||
key="manage-online"
|
||||
isLoading={isManageSubscriptionLoading}
|
||||
>
|
||||
<FlatButton
|
||||
label={<Trans>Manage online</Trans>}
|
||||
primary
|
||||
onClick={onManageSubscription}
|
||||
disabled={isManageSubscriptionLoading}
|
||||
/>
|
||||
</LeftLoader>
|
||||
) : (
|
||||
undefined
|
||||
),
|
||||
<RaisedButton
|
||||
key="manage"
|
||||
label={<Trans>Manage subscription</Trans>}
|
||||
@@ -88,11 +115,11 @@ const SubscriptionDetails = ({
|
||||
}
|
||||
disabled={isManageSubscriptionLoading}
|
||||
/>,
|
||||
]}
|
||||
].filter(Boolean)}
|
||||
isHighlighted={false}
|
||||
background="medium"
|
||||
/>
|
||||
{!!subscription.redemptionCodeValidUntil && (
|
||||
{!!redemptionCodeExpirationDate && (
|
||||
<I18n>
|
||||
{({ i18n }) => (
|
||||
<Paper background="dark" variant="outlined">
|
||||
@@ -118,12 +145,12 @@ const SubscriptionDetails = ({
|
||||
)}
|
||||
</ColumnStackLayout>
|
||||
) : (
|
||||
<>
|
||||
<Paper background="medium" variant="outlined" style={styles.paper}>
|
||||
<LineStackLayout alignItems="center">
|
||||
<img src="res/diamond.svg" style={styles.diamondIcon} alt="" />
|
||||
<Column expand>
|
||||
<Line>
|
||||
<Paper background="medium" variant="outlined" style={styles.paper}>
|
||||
<LineStackLayout alignItems="center">
|
||||
<img src="res/diamond.svg" style={styles.diamondIcon} alt="" />
|
||||
<Column expand>
|
||||
<Line>
|
||||
{!isSubscriptionExpired ? (
|
||||
<Column noMargin>
|
||||
<Text noMargin>
|
||||
<Trans>
|
||||
@@ -138,24 +165,30 @@ const SubscriptionDetails = ({
|
||||
</Trans>
|
||||
</Text>
|
||||
</Column>
|
||||
</Line>
|
||||
<Line justifyContent="flex-end">
|
||||
<RaisedButton
|
||||
label={<Trans>Choose a subscription</Trans>}
|
||||
primary
|
||||
onClick={() =>
|
||||
openSubscriptionDialog({ reason: 'Consult profile' })
|
||||
}
|
||||
/>
|
||||
</Line>
|
||||
</Column>
|
||||
</LineStackLayout>
|
||||
</Paper>
|
||||
</>
|
||||
) : (
|
||||
<Text noMargin>
|
||||
<Trans>
|
||||
Oh no! Your subscription from the redemption code has
|
||||
expired. You can renew it by redeeming a new code or
|
||||
getting a new subscription.
|
||||
</Trans>
|
||||
</Text>
|
||||
)}
|
||||
</Line>
|
||||
<Line justifyContent="flex-end">
|
||||
<RaisedButton
|
||||
label={<Trans>Choose a subscription</Trans>}
|
||||
primary
|
||||
onClick={() =>
|
||||
openSubscriptionDialog({ reason: 'Consult profile' })
|
||||
}
|
||||
/>
|
||||
</Line>
|
||||
</Column>
|
||||
</LineStackLayout>
|
||||
</Paper>
|
||||
)}
|
||||
</Column>
|
||||
) : (
|
||||
<PlaceholderLoader />
|
||||
);
|
||||
};
|
||||
|
||||
|
@@ -13,6 +13,7 @@ import {
|
||||
getRedirectToCheckoutUrl,
|
||||
canSeamlesslyChangeSubscription,
|
||||
businessPlan,
|
||||
hasValidSubscriptionPlan,
|
||||
} from '../../Utils/GDevelopServices/Usage';
|
||||
import EmptyMessage from '../../UI/EmptyMessage';
|
||||
import { showErrorBox } from '../../UI/Messages/MessageBox';
|
||||
@@ -60,11 +61,17 @@ const seamlesslyChangeConfirmationTexts = {
|
||||
dismissButtonLabel: t`Go back`,
|
||||
};
|
||||
const cancelAndChangeConfirmationTexts = {
|
||||
title: t`Cancel then get a new subscription`,
|
||||
message: t`To get a new subscription, we need to cancel your existing one before you can pay for the new one. The change will be immediate but your payment will NOT be pro-rated (you will have to pay as for a new subscription).`,
|
||||
title: t`Update your subscription`,
|
||||
message: t`To get this new subscription, we need to cancel your existing one before you can pay for the new one. The change will be immediate but your payment will NOT be pro-rated (you will have to pay as for a new subscription).`,
|
||||
confirmButtonLabel: t`Cancel my subscription`,
|
||||
dismissButtonLabel: t`Go back`,
|
||||
};
|
||||
const cancelAndChangeWithValidRedeemedCodeConfirmationTexts = {
|
||||
title: t`Update your subscription`,
|
||||
message: t`To get this new subscription, we need to cancel your existing one before you can pay for the new one. The change will be immediate. You will also lose your redeemed code.`,
|
||||
confirmButtonLabel: t`Update my subscription`,
|
||||
dismissButtonLabel: t`Go back`,
|
||||
};
|
||||
|
||||
type Props = {|
|
||||
open: boolean,
|
||||
@@ -100,7 +107,7 @@ export default function SubscriptionDialog({
|
||||
[open, analyticsMetadata]
|
||||
);
|
||||
|
||||
const choosePlan = async (
|
||||
const buyUpdateOrCancelPlan = async (
|
||||
i18n: I18nType,
|
||||
plan: { planId: null | string }
|
||||
) => {
|
||||
@@ -108,7 +115,7 @@ export default function SubscriptionDialog({
|
||||
if (!profile || !subscription) return;
|
||||
sendChoosePlanClicked(plan.planId);
|
||||
|
||||
// Subscribing from an account without a subscription.
|
||||
// Subscribing from an account without a subscription
|
||||
if (!subscription.planId) {
|
||||
setSubscriptionPendingDialogOpen(true);
|
||||
Window.openExternalURL(
|
||||
@@ -146,16 +153,33 @@ export default function SubscriptionDialog({
|
||||
setIsChangingSubscription(false);
|
||||
}
|
||||
} else {
|
||||
const needToCancelSubscription = !canSeamlesslyChangeSubscription(
|
||||
subscription
|
||||
);
|
||||
const hasValidRedeemedSubscription =
|
||||
!!subscription.redemptionCodeValidUntil &&
|
||||
subscription.redemptionCodeValidUntil > Date.now();
|
||||
const hasExpiredRedeemedSubscription =
|
||||
!!subscription.redemptionCodeValidUntil &&
|
||||
subscription.redemptionCodeValidUntil < Date.now();
|
||||
const shouldShowAlert =
|
||||
(needToCancelSubscription && !hasExpiredRedeemedSubscription) || // we don't show an alert if the redeemed code is expired
|
||||
hasValidRedeemedSubscription;
|
||||
|
||||
// Changing the existing subscription.
|
||||
const isSeamlessChange = canSeamlesslyChangeSubscription(subscription);
|
||||
const confirmDialogTexts = isSeamlessChange
|
||||
? seamlesslyChangeConfirmationTexts
|
||||
: cancelAndChangeConfirmationTexts;
|
||||
const confirmDialogTexts =
|
||||
!needToCancelSubscription || hasExpiredRedeemedSubscription
|
||||
? seamlesslyChangeConfirmationTexts
|
||||
: hasValidRedeemedSubscription
|
||||
? cancelAndChangeWithValidRedeemedCodeConfirmationTexts
|
||||
: cancelAndChangeConfirmationTexts;
|
||||
|
||||
const answer = await showConfirmation(confirmDialogTexts);
|
||||
if (!answer) return;
|
||||
if (shouldShowAlert) {
|
||||
const answer = await showConfirmation(confirmDialogTexts);
|
||||
if (!answer) return;
|
||||
}
|
||||
|
||||
if (isSeamlessChange) {
|
||||
if (!needToCancelSubscription) {
|
||||
// Changing the existing subscription without asking for payment details again.
|
||||
setIsChangingSubscription(true);
|
||||
try {
|
||||
@@ -212,6 +236,8 @@ export default function SubscriptionDialog({
|
||||
!authenticatedUser.profile ||
|
||||
isChangingSubscription;
|
||||
|
||||
const isPlanValid = hasValidSubscriptionPlan(authenticatedUser.subscription);
|
||||
|
||||
return (
|
||||
<I18n>
|
||||
{({ i18n }) => (
|
||||
@@ -262,13 +288,16 @@ export default function SubscriptionDialog({
|
||||
!!authenticatedUser.subscription &&
|
||||
authenticatedUser.subscription.planId === plan.planId;
|
||||
// If no plan (free usage), do not display button.
|
||||
const button = !plan.planId ? null : isCurrentPlan ? (
|
||||
const button = !plan.planId ? null : isCurrentPlan &&
|
||||
isPlanValid ? (
|
||||
<React.Fragment key="cancel">
|
||||
<LeftLoader isLoading={isLoading}>
|
||||
<FlatButton
|
||||
disabled={isLoading}
|
||||
label={<Trans>Cancel your subscription</Trans>}
|
||||
onClick={() => choosePlan(i18n, { planId: null })}
|
||||
onClick={() =>
|
||||
buyUpdateOrCancelPlan(i18n, { planId: null })
|
||||
}
|
||||
/>
|
||||
</LeftLoader>
|
||||
</React.Fragment>
|
||||
@@ -279,7 +308,7 @@ export default function SubscriptionDialog({
|
||||
primary
|
||||
disabled={isLoading}
|
||||
label={<Trans>Choose this plan</Trans>}
|
||||
onClick={() => choosePlan(i18n, plan)}
|
||||
onClick={() => buyUpdateOrCancelPlan(i18n, plan)}
|
||||
/>
|
||||
</LeftLoader>
|
||||
</React.Fragment>
|
||||
@@ -290,7 +319,7 @@ export default function SubscriptionDialog({
|
||||
plan={plan}
|
||||
actions={[button]}
|
||||
isPending={isLoading}
|
||||
isHighlighted={isCurrentPlan}
|
||||
isHighlighted={isCurrentPlan} // highlight the plan even if it's expired.
|
||||
background="medium"
|
||||
/>
|
||||
);
|
||||
@@ -351,8 +380,11 @@ export default function SubscriptionDialog({
|
||||
]}
|
||||
>
|
||||
<Text>
|
||||
It's free and you'll get access to online services: cloud
|
||||
projects, leaderboards, player feedbacks, cloud builds...
|
||||
<Trans>
|
||||
It is free and you will get access to online services:
|
||||
cloud projects, leaderboards, player feedbacks, cloud
|
||||
builds...
|
||||
</Trans>
|
||||
</Text>
|
||||
</Dialog>
|
||||
)}
|
||||
|
@@ -76,7 +76,9 @@ export default function SubscriptionPendingDialog({
|
||||
<Line justifyContent="center" alignItems="center">
|
||||
<CircularProgress size={20} />
|
||||
<Spacer />
|
||||
<Text>Waiting for the subscription confirmation...</Text>
|
||||
<Text>
|
||||
<Trans>Waiting for the subscription confirmation...</Trans>
|
||||
</Text>
|
||||
</Line>
|
||||
<Spacer />
|
||||
<Line justifyContent="center">
|
||||
|
@@ -23,6 +23,7 @@ import Text from '../UI/Text';
|
||||
import AlertMessage from '../UI/AlertMessage';
|
||||
import GetSubscriptionCard from '../Profile/Subscription/GetSubscriptionCard';
|
||||
import AuthenticatedUserContext from '../Profile/AuthenticatedUserContext';
|
||||
import { hasValidSubscriptionPlan } from '../Utils/GDevelopServices/Usage';
|
||||
|
||||
type Props = {|
|
||||
loadingScreen: gdLoadingScreen,
|
||||
@@ -55,8 +56,9 @@ export const LoadingScreenEditor = ({
|
||||
const subscriptionChecker = React.useRef<?SubscriptionCheckerInterface>(null);
|
||||
const authenticatedUser = React.useContext(AuthenticatedUserContext);
|
||||
const forceUpdate = useForceUpdate();
|
||||
const shouldDisplayGetSubscriptionCard =
|
||||
!authenticatedUser.subscription || !authenticatedUser.subscription.planId;
|
||||
const shouldDisplayGetSubscriptionCard = !hasValidSubscriptionPlan(
|
||||
authenticatedUser.subscription
|
||||
);
|
||||
|
||||
const onUpdate = () => {
|
||||
forceUpdate();
|
||||
@@ -180,8 +182,10 @@ export const LoadingScreenEditor = ({
|
||||
{shouldDisplayGetSubscriptionCard && (
|
||||
<GetSubscriptionCard subscriptionDialogOpeningReason="Disable GDevelop splash at startup">
|
||||
<Text>
|
||||
Get a silver or gold subscription to disable GDevelop
|
||||
branding.
|
||||
<Trans>
|
||||
Get a silver or gold subscription to disable GDevelop
|
||||
branding.
|
||||
</Trans>
|
||||
</Text>
|
||||
</GetSubscriptionCard>
|
||||
)}
|
||||
|
@@ -192,7 +192,11 @@ export const Item = ({
|
||||
<div
|
||||
style={{ display: 'inline-flex', width: '100%', alignItems: 'center' }}
|
||||
>
|
||||
<span style={textEllipsisStyle} title={primaryText}>
|
||||
<span
|
||||
style={textEllipsisStyle}
|
||||
title={primaryText}
|
||||
className="notranslate"
|
||||
>
|
||||
{primaryText}
|
||||
</span>
|
||||
{textEndAdornment && (
|
||||
|
@@ -9,7 +9,7 @@ import {
|
||||
} from '../../Utils/BlobDownloader';
|
||||
import { makeTestProject } from '../../fixtures/TestProject';
|
||||
import { moveUrlResourcesToCloudFilesIfPrivate } from './CloudResourceFetcher';
|
||||
import { fakeIndieAuthenticatedUser } from '../../fixtures/GDevelopServicesTestData';
|
||||
import { fakeSilverAuthenticatedUser } from '../../fixtures/GDevelopServicesTestData';
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
jest.mock('../../Utils/GDevelopServices/Project');
|
||||
@@ -61,7 +61,7 @@ const makeMoveUrlResourcesToCloudFilesIfPrivateOptions = (
|
||||
) => ({
|
||||
project,
|
||||
fileMetadata: { fileIdentifier: 'fake-cloud-project-id' },
|
||||
authenticatedUser: fakeIndieAuthenticatedUser,
|
||||
authenticatedUser: fakeSilverAuthenticatedUser,
|
||||
onProgress: jest.fn(),
|
||||
});
|
||||
|
||||
@@ -174,11 +174,11 @@ describe('CloudResourceFetcher', () => {
|
||||
expect.any(Function) // onError
|
||||
);
|
||||
expect(getCredentialsForCloudProject).toHaveBeenCalledWith(
|
||||
fakeIndieAuthenticatedUser,
|
||||
fakeSilverAuthenticatedUser,
|
||||
'fake-cloud-project-id'
|
||||
);
|
||||
expect(uploadProjectResourceFiles).toHaveBeenCalledWith(
|
||||
fakeIndieAuthenticatedUser,
|
||||
fakeSilverAuthenticatedUser,
|
||||
'fake-cloud-project-id',
|
||||
['some file', 'some other file'],
|
||||
expect.any(Function) // onProgress
|
||||
|
@@ -20,7 +20,7 @@ const styles = {
|
||||
};
|
||||
|
||||
type Props = {|
|
||||
kind: 'info' | 'warning' | 'error',
|
||||
kind?: 'info' | 'warning' | 'error',
|
||||
children: React.Node,
|
||||
onHide?: ?() => void,
|
||||
renderLeftIcon?: () => React.Node,
|
||||
|