Compare commits

...

64 Commits

Author SHA1 Message Date
Arthur Pacaud
c27449ba55 Fix typechecking on semaphore 2024-01-16 21:51:44 +01:00
Arthur Pacaud
f372749ddb Add JsExtension.js to GDJS Prettier 2024-01-16 21:50:15 +01:00
Arthur Pacaud
9a28e5ef9c Add inheritence support to types generator 2024-01-16 21:47:59 +01:00
Arthur Pacaud
44cb94c20c Type JsExtensions files with typescript 2024-01-16 21:28:26 +01:00
D8H
16e2d8a005 Move some properties of the platformer character behavior in 2 columns (#6197) 2024-01-16 12:22:13 +01:00
D8H
7654883cb1 Allow to use orthographic camera in 3D layers (#6187) 2024-01-15 23:05:23 +01:00
D8H
3ae5db2a49 Fix scale and camera zoom tweens from setting NaN when the initial value was 0 (#6178) 2024-01-15 14:44:10 +01:00
Arthur Pacaud (arthuro555)
9ed002c879 Add expression to read the authenticated user unique identifier (#6192)
* This is useful if you want to interface with a third party or in-house solution to store user data.
2024-01-15 14:00:14 +01:00
Florian Rival
d4283c2350 Add new icon for 3D model objects (#6186) 2024-01-12 18:24:43 +01:00
AlexandreS
5a176d21e7 Add SSO to login/sign up (#6167)
Feature hidden in live environment.

Don't show in changelog
2024-01-12 14:45:16 +01:00
D8H
bfdfd7f0fb Improve the new UI of the extension editor (#6165)
- Add icons for behavior and object in the function tree
- Move the indicators on the right.
- Remove the big button.
- Fix the effect icon.
- Add checkboxes for the visibility.
- Rename on double click.
- Fix indentation.
- Hide the 3 dots button.

- Don't show in changelog
2024-01-12 13:11:16 +01:00
AlexandreS
aae75f2232 Fix use of Warning icon in tooltips (#6183)
Don't show in changelog
2024-01-12 13:04:20 +01:00
github-actions[bot]
977092c0a3 Update translations [skip ci] (#6179)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2024-01-12 12:38:05 +01:00
D8H
556688cedb Add pagination to asset store results (#6174) 2024-01-11 17:52:46 +01:00
github-actions[bot]
ce93dc5310 Update translations [skip ci] (#6170)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-01-10 15:57:04 +01:00
Clément Pasteau
d6d425db4f Show premium game templates from the same author on a template's page (#6168) 2024-01-10 15:42:51 +01:00
AlexandreS
2737e75639 Fix merge issue (#6169)
Don't show in changelog
2024-01-10 15:35:31 +01:00
github-actions[bot]
36eab18133 Update translations [skip ci] (#6164)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-01-09 16:30:55 +01:00
Clément Pasteau
48acbb12ee Decode filenames from any URLs before using them (#6018)
Only show in developer changelog
2024-01-09 16:00:09 +01:00
Florian Rival
21904e46f1 Avoid an extra click to purchase an asset pack or game template (#6161) 2024-01-09 15:32:33 +01:00
AlexandreS
94753ac053 Get subscription plans from server (#6128)
Don't show in changelog
2024-01-09 15:28:28 +01:00
github-actions[bot]
b160ee9b27 Update translations [skip ci] (#6147)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2024-01-09 15:15:24 +01:00
D8H
f76e8a72b6 Make the function property editor better adapt to small size (#6158) 2024-01-08 18:11:18 +01:00
D8H
5bc342688d Fix the cameras position to keep them centered on the object they follow when the game resolution is changed (#3821)
- Also fix the camera position for pixel-art games when a zoom and a game resolution change is used to have big pixels
2024-01-08 12:43:50 +01:00
D8H
3e6204c0eb Remember the size of mosaic nodes when they are uncollapsed (#6156)
- Don't show in changelog
2024-01-08 12:42:31 +01:00
D8H
7b1c340ad0 Fix game crashing at loading when video files are missing (#6155) 2024-01-08 12:08:48 +01:00
D8H
fac724dc3f Fix the indentation of extensions exported from the web-app (#6148) 2024-01-05 11:47:54 +01:00
D8H
9b4151f64c Add a button to export all the objetcs of a scene to submit them to the asset store (#4848)
* The dialog can be reached from the hidden drop-down menu of "Scene objects".
2024-01-05 11:09:27 +01:00
github-actions[bot]
6b5ab6c811 Update translations [skip ci] (#6130)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2024-01-05 10:06:13 +01:00
Clément Pasteau
5943092b0c Fix correctly taking folders into account when adding assets from the Home Store (#6146) 2024-01-05 10:05:44 +01:00
D8H
deb0c5ffc3 Display events functions of extensions in a tree view (#6133) 2024-01-04 18:14:44 +01:00
Clément Pasteau
c56fa03bf6 Fix crash when trying to access a child of a non existing structure child in an expression (#6144) 2024-01-04 16:20:49 +01:00
D8H
0d49d449db Import several animations to a sprite object in one go (#6035)
- Sprite animations are automatically created when several image files are selected and they ends with an animation name and an optional frame index (most naming conversions should work).
2024-01-04 11:02:04 +01:00
Clément Pasteau
fdd702cd09 Fix renaming a layer with external layouts (#6140)
* Instances of external layouts and of the attached scene are now all moved properly to the renamed layer
2024-01-04 10:31:34 +01:00
Clément Pasteau
5a8e4a7ca9 Allow confirming and canceling confirmation dialogs with keyboard shortcuts (#6138) 2024-01-03 14:52:36 +01:00
D8H
2e4e91c21e Add tween actions (position, rotation and depth) for 3D objects (#6122) 2024-01-02 10:03:59 +01:00
AlexandreS
6ece930809 Use axios error extractor where possible (#6132)
Only show in developer changelog
2023-12-27 19:40:16 +01:00
AlexandreS
c5baa81977 Display Game template categories with chips (#6129)
Don't show in changelog
2023-12-27 16:10:19 +01:00
github-actions[bot]
d24be38874 Update translations [skip ci] (#6109)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-12-27 10:35:14 +01:00
AlexandreS
1efffbbb78 Fix: Avoid project commit error by retrying call to server (#6127) 2023-12-26 12:12:25 +01:00
D8H
090d76a368 Show a drop-down list for string with choices parameters (#6120) 2023-12-22 15:31:43 +01:00
D8H
d44a9375de Add variables autocompletion for groups in variable fields (#6110) 2023-12-21 12:20:14 +01:00
AlexandreS
5a2a3893f9 Remove dashboard from profile dialog (#6113) 2023-12-21 12:08:23 +01:00
AlexandreS
0a6b0dc785 Use cloud storage provider internal name (#6108)
Don't show in changelog
2023-12-20 12:15:04 +01:00
github-actions[bot]
02e99726dc Update translations [skip ci] (#6103)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-12-20 11:55:13 +01:00
AlexandreS
843055d8df Add error message when versions fail to load (#6105)
Don't show in changelog
2023-12-20 11:40:07 +01:00
AlexandreS
f7fda5cb5e Fix placeholder thumbnail in objects lists for prefabs (#6107) 2023-12-20 11:37:28 +01:00
AlexandreS
e529642aec Fix program opening count logic when user has never acknowledged the feature (#6106)
Don't show in changelog
2023-12-20 10:01:35 +01:00
AlexandreS
c8e10d7043 Bump newIDE version (#6104) 2023-12-19 12:25:29 +01:00
AlexandreS
5f0de0e9a7 Adapt extract changelog script to currently used format (#6102)
Only show in developer changelog
2023-12-19 12:18:25 +01:00
github-actions[bot]
e51638ce4b Update translations [skip ci] (#6101)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-12-19 12:17:54 +01:00
AlexandreS
0fbd6a606a Add possibility to restore a previous version of a cloud project (#6022)
- Display all the project versions (paginated)
- Allow to open any version and name it for better tracking
- Make it possible to restore a given version
2023-12-19 11:50:28 +01:00
github-actions[bot]
2fa543c3db Update translations [skip ci] (#6083)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-12-18 16:56:41 +01:00
AlexandreS
38e35c9695 Prevent crash on new object dialog (#6099) 2023-12-18 16:50:21 +01:00
Florian Rival
ad13a1a101 Fix changes done in an extension not applied when clicking on 'Share' immediately without a preview or navigation in the editor (#6098) 2023-12-18 16:02:27 +01:00
AlexandreS
cb9d98d027 Wait 10 program openings before displaying GamesDashboard info (#6097)
Don't show in changelog
2023-12-18 15:51:23 +01:00
D8H
064c3f1572 Fix warning in the object list (#6091)
- don't show in changelog
2023-12-15 18:46:40 +01:00
D8H
9e5320f9d4 Add an item menu to add sub-folders in object folders (#6090) 2023-12-15 17:56:19 +01:00
Clément Pasteau
a1826d355d Rework subscriptions display in Profile (#6089) 2023-12-15 17:27:48 +01:00
D8H
32a3a094d1 Add new objects under the selected one in the list (#6087) 2023-12-15 16:51:50 +01:00
D8H
ee7dc2654b Fix parameter value choices autocompletion (#6086) 2023-12-15 12:02:24 +01:00
Clément Pasteau
64ffad3c0a Bump to 5.3.185 (#6082) 2023-12-14 14:06:01 +01:00
github-actions[bot]
dcc62f078f Update translations [skip ci] (#6076)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2023-12-14 13:54:43 +01:00
D8H
d920f05dbc Fix animation scanning in the 3D model object editor (#6080) 2023-12-14 13:28:38 +01:00
359 changed files with 18146 additions and 7415 deletions

View File

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

View File

@@ -1281,8 +1281,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Enable an effect on the object"),
_("Enable effect _PARAM1_ on _PARAM0_: _PARAM2_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("yesorno", _("Enable?"))
@@ -1297,8 +1297,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"names) in the effects window."),
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
@@ -1315,8 +1315,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"names) in the effects window."),
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
@@ -1332,8 +1332,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"names) in the effects window."),
_("Enable _PARAM2_ for effect _PARAM1_ of _PARAM0_: _PARAM3_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
@@ -1347,8 +1347,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Check if the effect on an object is enabled."),
_("Effect _PARAM1_ of _PARAM0_ is enabled"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.MarkAsSimple()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -39,7 +39,8 @@ struct VariableAndItsParent {
};
/**
* \brief Find the last parent (i.e: the variables container) of a node representing a variable.
* \brief Find the last parent (i.e: the variables container) of a node
* representing a variable.
*
* Useful for completions, to know which variables can be entered in a node.
*
@@ -48,13 +49,12 @@ struct VariableAndItsParent {
class GD_CORE_API ExpressionVariableParentFinder
: public ExpressionParser2NodeWorker {
public:
static VariableAndItsParent GetLastParentOfNode(
const gd::Platform& platform,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::ExpressionNode& node) {
gd::ExpressionVariableParentFinder typeFinder(
platform, projectScopedContainers);
gd::ExpressionVariableParentFinder typeFinder(platform,
projectScopedContainers);
node.Visit(typeFinder);
return typeFinder.variableAndItsParent;
}
@@ -70,7 +70,8 @@ class GD_CORE_API ExpressionVariableParentFinder
variableNode(nullptr),
thisIsALegacyPrescopedVariable(false),
bailOutBecauseEmptyVariableName(false),
legacyPrescopedVariablesContainer(nullptr){};
legacyPrescopedVariablesContainer(nullptr),
variableAndItsParent{} {};
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
void OnVisitOperatorNode(OperatorNode& node) override {}
@@ -135,10 +136,10 @@ class GD_CORE_API ExpressionVariableParentFinder
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
if (node.name.empty() && node.child) {
// A variable accessor should always have a name if it has a child (i.e: another accessor).
// While the parser may have generated an empty name,
// flag this so we avoid finding a wrong parent (and so, run the risk of giving
// wrong autocompletions).
// A variable accessor should always have a name if it has a child (i.e:
// another accessor). While the parser may have generated an empty name,
// flag this so we avoid finding a wrong parent (and so, run the risk of
// giving wrong autocompletions).
bailOutBecauseEmptyVariableName = true;
}
childVariableNames.insert(childVariableNames.begin(), node.name);
@@ -300,7 +301,8 @@ class GD_CORE_API ExpressionVariableParentFinder
const std::vector<gd::String>& childVariableNames,
size_t startIndex = 0) {
if (bailOutBecauseEmptyVariableName)
return {}; // Do not even attempt to find the parent if we had an issue when visiting nodes.
return {}; // Do not even attempt to find the parent if we had an issue
// when visiting nodes.
const gd::Variable* currentVariable = &variable;
@@ -332,8 +334,8 @@ class GD_CORE_API ExpressionVariableParentFinder
}
}
// Return the last parent of the chain of variables (so not the last variable
// but the one before it).
// Return the last parent of the chain of variables (so not the last
// variable but the one before it).
return {.parentVariable = currentVariable};
}
@@ -341,14 +343,16 @@ class GD_CORE_API ExpressionVariableParentFinder
const gd::VariablesContainer& variablesContainer,
const std::vector<gd::String>& childVariableNames) {
if (bailOutBecauseEmptyVariableName)
return {}; // Do not even attempt to find the parent if we had an issue when visiting nodes.
return {}; // Do not even attempt to find the parent if we had an issue
// when visiting nodes.
if (childVariableNames.empty())
return {}; // There is no "parent" to the variables container itself.
const gd::String& firstChildName = *childVariableNames.begin();
const gd::Variable* variable = variablesContainer.Has(firstChildName) ?
&variablesContainer.Get(firstChildName) : nullptr;
const gd::Variable* variable = variablesContainer.Has(firstChildName)
? &variablesContainer.Get(firstChildName)
: nullptr;
if (childVariableNames.size() == 1 || !variable)
return {// Only one child: the parent is the variables container itself.
.parentVariablesContainer = &variablesContainer};

View File

@@ -0,0 +1,222 @@
/*
* GDevelop Core
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "ObjectAssetSerializer.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/Project/AssetResourcePathCleaner.h"
#include "GDCore/IDE/Project/ResourcesInUseHelper.h"
#include "GDCore/IDE/Project/ResourcesRenamer.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/CustomBehavior.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/Log.h"
namespace gd {
gd::String
ObjectAssetSerializer::GetObjectExtensionName(const gd::Object &object) {
const gd::String &type = object.GetType();
const auto separatorIndex =
type.find(PlatformExtension::GetNamespaceSeparator());
return separatorIndex != std::string::npos ? type.substr(0, separatorIndex)
: "";
}
void ObjectAssetSerializer::SerializeTo(
gd::Project &project, const gd::Object &object,
const gd::String &objectFullName, SerializerElement &element,
std::map<gd::String, gd::String> &resourcesFileNameMap) {
auto cleanObject = object.Clone();
cleanObject->GetVariables().Clear();
cleanObject->GetEffects().Clear();
for (auto &&behaviorName : cleanObject->GetAllBehaviorNames()) {
cleanObject->RemoveBehavior(behaviorName);
}
gd::String extensionName = GetObjectExtensionName(*cleanObject);
std::map<gd::String, gd::String> resourcesNameReverseMap;
gd::ObjectAssetSerializer::RenameObjectResourceFiles(
project, *cleanObject, "", objectFullName, resourcesFileNameMap,
resourcesNameReverseMap);
element.SetAttribute("id", "");
element.SetAttribute("name", "");
element.SetAttribute("license", "");
if (project.HasEventsFunctionsExtensionNamed(extensionName)) {
auto &extension = project.GetEventsFunctionsExtension(extensionName);
element.SetAttribute("description", extension.GetShortDescription());
}
element.SetAttribute("gdevelopVersion", "");
element.SetAttribute("version", "");
element.SetIntAttribute("animationsCount", 1);
element.SetIntAttribute("maxFramesCount", 1);
// TODO Find the right object dimensions.
element.SetIntAttribute("width", 0);
element.SetIntAttribute("height", 0);
SerializerElement &authorsElement = element.AddChild("authors");
authorsElement.ConsiderAsArrayOf("author");
SerializerElement &tagsElement = element.AddChild("tags");
tagsElement.ConsiderAsArrayOf("tag");
SerializerElement &objectAssetsElement = element.AddChild("objectAssets");
objectAssetsElement.ConsiderAsArrayOf("objectAsset");
SerializerElement &objectAssetElement =
objectAssetsElement.AddChild("objectAsset");
cleanObject->SerializeTo(objectAssetElement.AddChild("object"));
SerializerElement &resourcesElement =
objectAssetElement.AddChild("resources");
resourcesElement.ConsiderAsArrayOf("resource");
auto &resourcesManager = project.GetResourcesManager();
gd::ResourcesInUseHelper resourcesInUse(resourcesManager);
cleanObject->GetConfiguration().ExposeResources(resourcesInUse);
for (auto &&newResourceName : resourcesInUse.GetAllResources()) {
if (newResourceName.length() == 0) {
continue;
}
auto &resource = resourcesManager.GetResource(
resourcesNameReverseMap.find(newResourceName) !=
resourcesNameReverseMap.end()
? resourcesNameReverseMap[newResourceName]
: newResourceName);
SerializerElement &resourceElement = resourcesElement.AddChild("resource");
resource.SerializeTo(resourceElement);
// Override name and file because the project and the asset don't use the
// same one.
resourceElement.SetAttribute("kind", resource.GetKind());
resourceElement.SetAttribute("name", newResourceName);
auto &oldFilePath = resource.GetFile();
resourceElement.SetAttribute("file",
resourcesFileNameMap.find(oldFilePath) !=
resourcesFileNameMap.end()
? resourcesFileNameMap[oldFilePath]
: oldFilePath);
}
SerializerElement &requiredExtensionsElement =
objectAssetElement.AddChild("requiredExtensions");
requiredExtensionsElement.ConsiderAsArrayOf("requiredExtension");
if (project.HasEventsFunctionsExtensionNamed(extensionName)) {
SerializerElement &requiredExtensionElement =
requiredExtensionsElement.AddChild("requiredExtension");
requiredExtensionElement.SetAttribute("extensionName", extensionName);
requiredExtensionElement.SetAttribute("extensionVersion", "1.0.0");
}
// TODO This can be removed when the asset script no longer require it.
SerializerElement &customizationElement =
objectAssetElement.AddChild("customization");
customizationElement.ConsiderAsArrayOf("empty");
}
void ObjectAssetSerializer::RenameObjectResourceFiles(
gd::Project &project, gd::Object &object,
const gd::String &destinationDirectory, const gd::String &objectFullName,
std::map<gd::String, gd::String> &resourcesFileNameMap,
std::map<gd::String, gd::String> &resourcesNameReverseMap) {
gd::AssetResourcePathCleaner assetResourcePathCleaner(
project.GetResourcesManager(), resourcesFileNameMap,
resourcesNameReverseMap);
object.GetConfiguration().ExposeResources(assetResourcePathCleaner);
// Use asset store script naming conventions for sprite resource files.
if (object.GetConfiguration().GetType() == "Sprite") {
gd::SpriteObject &spriteConfiguration =
dynamic_cast<gd::SpriteObject &>(object.GetConfiguration());
std::map<gd::String, gd::String> normalizedFileNames;
for (std::size_t animationIndex = 0;
animationIndex < spriteConfiguration.GetAnimationsCount();
animationIndex++) {
auto &animation = spriteConfiguration.GetAnimation(animationIndex);
auto &direction = animation.GetDirection(0);
const gd::String &animationName =
animation.GetName().empty()
? gd::String::From(animationIndex)
: animation.GetName().FindAndReplace("_", " ", true);
// Search frames that share the same resource.
std::map<gd::String, std::vector<int>> frameIndexes;
for (std::size_t frameIndex = 0; frameIndex < direction.GetSpritesCount();
frameIndex++) {
auto &frame = direction.GetSprite(frameIndex);
if (frameIndexes.find(frame.GetImageName()) == frameIndexes.end()) {
std::vector<int> emptyVector;
frameIndexes[frame.GetImageName()] = emptyVector;
}
auto &indexes = frameIndexes[frame.GetImageName()];
indexes.push_back(frameIndex);
}
for (std::size_t frameIndex = 0; frameIndex < direction.GetSpritesCount();
frameIndex++) {
auto &frame = direction.GetSprite(frameIndex);
auto oldName = frame.GetImageName();
if (normalizedFileNames.find(oldName) != normalizedFileNames.end()) {
gd::LogWarning("The resource \"" + oldName +
"\" is shared by several animations.");
continue;
}
gd::String newName = objectFullName;
if (spriteConfiguration.GetAnimationsCount() > 1) {
newName += "_" + animationName;
}
if (direction.GetSpritesCount() > 1) {
newName += "_";
auto &indexes = frameIndexes[frame.GetImageName()];
for (size_t i = 0; i < indexes.size(); i++) {
newName += gd::String::From(indexes.at(i) + 1);
if (i < indexes.size() - 1) {
newName += ";";
}
}
}
gd::String extension = oldName.substr(oldName.find_last_of("."));
newName += extension;
frame.SetImageName(newName);
normalizedFileNames[oldName] = newName;
}
}
for (std::map<gd::String, gd::String>::const_iterator it =
resourcesFileNameMap.begin();
it != resourcesFileNameMap.end(); ++it) {
if (!it->first.empty()) {
gd::String originFile = it->first;
gd::String destinationFile = it->second;
resourcesFileNameMap[originFile] = normalizedFileNames[destinationFile];
}
}
auto clonedResourcesNameReverseMap = resourcesNameReverseMap;
resourcesNameReverseMap.clear();
for (std::map<gd::String, gd::String>::const_iterator it =
clonedResourcesNameReverseMap.begin();
it != clonedResourcesNameReverseMap.end(); ++it) {
if (!it->first.empty()) {
gd::String newResourceName = it->first;
gd::String oldResourceName = it->second;
resourcesNameReverseMap[normalizedFileNames[newResourceName]] =
oldResourceName;
}
}
}
}
} // namespace gd

View File

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

View File

@@ -123,14 +123,15 @@ public:
*/
virtual void ExposeEmbeddeds(gd::String &resourceName);
protected:
gd::ResourcesManager * resourcesManager;
private:
/**
* \brief Expose a resource: resources that have a file are
* exposed as file (see ExposeFile).
*/
void ExposeResource(gd::Resource &resource);
gd::ResourcesManager * resourcesManager;
};
/**

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,8 +16,8 @@
#include "GDCore/IDE/Events/BehaviorTypeRenamer.h"
#include "GDCore/IDE/Events/CustomObjectTypeRenamer.h"
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
#include "GDCore/IDE/Events/EventsRefactorer.h"
#include "GDCore/IDE/Events/EventsPropertyReplacer.h"
#include "GDCore/IDE/Events/EventsRefactorer.h"
#include "GDCore/IDE/Events/EventsVariableReplacer.h"
#include "GDCore/IDE/Events/ExpressionsParameterMover.h"
#include "GDCore/IDE/Events/ExpressionsRenamer.h"
@@ -138,7 +138,8 @@ void WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
}
}
VariablesChangeset WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
VariablesChangeset
WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
gd::Project &project,
const gd::SerializerElement &oldSerializedVariablesContainer,
const gd::VariablesContainer &newVariablesContainer) {
@@ -149,9 +150,9 @@ VariablesChangeset WholeProjectRefactorer::ComputeChangesetForVariablesContainer
if (oldVariablesContainer.GetPersistentUuid() !=
newVariablesContainer.GetPersistentUuid()) {
gd::LogWarning(
_("Called ComputeChangesetForVariablesContainer on variables containers "
"that are different - they can't be compared."));
gd::LogWarning(_(
"Called ComputeChangesetForVariablesContainer on variables containers "
"that are different - they can't be compared."));
return changeset;
}
@@ -192,14 +193,11 @@ VariablesChangeset WholeProjectRefactorer::ComputeChangesetForVariablesContainer
}
void WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
gd::Project &project,
const gd::VariablesContainer &newVariablesContainer,
const gd::VariablesChangeset& changeset) {
gd::Project &project, const gd::VariablesContainer &newVariablesContainer,
const gd::VariablesChangeset &changeset) {
gd::EventsVariableReplacer eventsVariableReplacer(
project.GetCurrentPlatform(),
newVariablesContainer,
changeset.oldToNewVariableNames,
changeset.removedVariableNames);
project.GetCurrentPlatform(), newVariablesContainer,
changeset.oldToNewVariableNames, changeset.removedVariableNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsVariableReplacer);
}
@@ -743,14 +741,14 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {{oldPropertyName, newPropertyName}};
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
{oldPropertyName, newPropertyName}};
std::unordered_set<gd::String> removedPropertyNames;
gd::EventsPropertyReplacer eventsPropertyReplacer(
project.GetCurrentPlatform(),
properties,
oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventsPropertyReplacer);
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsPropertyReplacer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -813,14 +811,14 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
EventsBasedBehavior::GetSharedPropertyExpressionName(newPropertyName));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {{oldPropertyName, newPropertyName}};
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
{oldPropertyName, newPropertyName}};
std::unordered_set<gd::String> removedPropertyNames;
gd::EventsPropertyReplacer eventsPropertyReplacer(
project.GetCurrentPlatform(),
properties,
oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventsPropertyReplacer);
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsPropertyReplacer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -870,14 +868,14 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
EventsBasedObject::GetPropertyExpressionName(newPropertyName));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {{oldPropertyName, newPropertyName}};
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
{oldPropertyName, newPropertyName}};
std::unordered_set<gd::String> removedPropertyNames;
gd::EventsPropertyReplacer eventsPropertyReplacer(
project.GetCurrentPlatform(),
properties,
oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventsPropertyReplacer);
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsPropertyReplacer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -1351,7 +1349,6 @@ void WholeProjectRefactorer::DoRenameBehavior(
gd::Project &project, const gd::String &oldBehaviorType,
const gd::String &newBehaviorType,
const gd::ProjectBrowser &projectBrowser) {
// Rename behavior in required behavior properties
auto requiredBehaviorRenamer =
gd::RequiredBehaviorRenamer(oldBehaviorType, newBehaviorType);
@@ -1378,7 +1375,6 @@ void WholeProjectRefactorer::DoRenameBehavior(
void WholeProjectRefactorer::DoRenameObject(
gd::Project &project, const gd::String &oldObjectType,
const gd::String &newObjectType, const gd::ProjectBrowser &projectBrowser) {
// Rename object type in objects lists.
auto customObjectTypeRenamer =
gd::CustomObjectTypeRenamer(oldObjectType, newObjectType);
@@ -1398,7 +1394,8 @@ void WholeProjectRefactorer::DoRenameObject(
void WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
gd::Project &project, gd::Layout &layout, const gd::String &objectName,
bool isObjectGroup, bool removeEventsAndGroups) {
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
// Remove object in the current layout
if (removeEventsAndGroups) {
@@ -1447,7 +1444,8 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
if (oldName == newName || newName.empty() || oldName.empty())
return;
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
// Rename object in the current layout
gd::EventsRefactorer::RenameObjectInEvents(
@@ -1536,10 +1534,19 @@ void WholeProjectRefactorer::RenameLayer(gd::Project &project,
const gd::String &newName) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
gd::ProjectElementRenamer projectElementRenamer(project.GetCurrentPlatform(),
"layer", oldName, newName);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
projectElementRenamer);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, projectElementRenamer);
layout.GetInitialInstances().MoveInstancesToLayer(oldName, newName);
std::vector<gd::String> externalLayoutsNames =
GetAssociatedExternalLayouts(project, layout);
for (gd::String name : externalLayoutsNames) {
auto &externalLayout = project.GetExternalLayout(name);
externalLayout.GetInitialInstances().MoveInstancesToLayer(oldName, newName);
}
}
void WholeProjectRefactorer::RenameLayerEffect(gd::Project &project,
@@ -1552,8 +1559,8 @@ void WholeProjectRefactorer::RenameLayerEffect(gd::Project &project,
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "layerEffectName", oldName, newName);
projectElementRenamer.SetLayerConstraint(layer.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
projectElementRenamer);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, projectElementRenamer);
}
void WholeProjectRefactorer::RenameObjectAnimation(gd::Project &project,
@@ -1566,8 +1573,8 @@ void WholeProjectRefactorer::RenameObjectAnimation(gd::Project &project,
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "objectAnimationName", oldName, newName);
projectElementRenamer.SetObjectConstraint(object.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
projectElementRenamer);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, projectElementRenamer);
}
void WholeProjectRefactorer::RenameObjectPoint(gd::Project &project,
@@ -1580,8 +1587,8 @@ void WholeProjectRefactorer::RenameObjectPoint(gd::Project &project,
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "objectPointName", oldName, newName);
projectElementRenamer.SetObjectConstraint(object.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
projectElementRenamer);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, projectElementRenamer);
}
void WholeProjectRefactorer::RenameObjectEffect(gd::Project &project,
@@ -1594,8 +1601,8 @@ void WholeProjectRefactorer::RenameObjectEffect(gd::Project &project,
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "objectEffectName", oldName, newName);
projectElementRenamer.SetObjectConstraint(object.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
projectElementRenamer);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, projectElementRenamer);
}
void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsBasedObject(
@@ -1617,9 +1624,12 @@ void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsFunction(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer, const gd::String &objectName,
bool isObjectGroup, bool removeEventsAndGroups) {
// In theory we should pass a ProjectScopedContainers to this function so it does not have to construct one.
// In practice, this is ok because we only deal with objects.
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsContainer, objectsContainer);
// In theory we should pass a ProjectScopedContainers to this function so it
// does not have to construct one. In practice, this is ok because we only
// deal with objects.
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(
globalObjectsContainer, objectsContainer);
if (removeEventsAndGroups) {
gd::EventsRefactorer::RemoveObjectInEvents(
@@ -1655,9 +1665,12 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer, const gd::String &oldName,
const gd::String &newName, bool isObjectGroup) {
// In theory we should pass a ProjectScopedContainers to this function so it does not have to construct one.
// In practice, this is ok because we only deal with objects.
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsContainer, objectsContainer);
// In theory we should pass a ProjectScopedContainers to this function so it
// does not have to construct one. In practice, this is ok because we only
// deal with objects.
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(
globalObjectsContainer, objectsContainer);
gd::EventsRefactorer::RenameObjectInEvents(
project.GetCurrentPlatform(), projectScopedContainers,
@@ -1705,7 +1718,7 @@ void WholeProjectRefactorer::GlobalObjectOrGroupRemoved(
if (layout.HasObjectNamed(objectName))
continue;
ObjectOrGroupRemovedInLayout(project, layout, objectName, isObjectGroup,
ObjectOrGroupRemovedInLayout(project, layout, objectName, isObjectGroup,
removeEventsAndGroups);
}
}
@@ -1753,7 +1766,8 @@ size_t WholeProjectRefactorer::GetLayoutAndExternalLayoutLayerInstancesCount(
GetAssociatedExternalLayouts(project, layout);
for (gd::String name : externalLayoutsNames) {
auto &externalLayout = project.GetExternalLayout(name);
count += externalLayout.GetInitialInstances().GetLayerInstancesCount(layerName);
count +=
externalLayout.GetInitialInstances().GetLayerInstancesCount(layerName);
}
return count;
}

View File

@@ -39,6 +39,7 @@ void Layer::SetCameraCount(std::size_t n) {
void Layer::SerializeTo(SerializerElement& element) const {
element.SetAttribute("name", GetName());
element.SetAttribute("renderingType", GetRenderingType());
element.SetAttribute("cameraType", GetCameraType());
element.SetAttribute("visibility", GetVisibility());
element.SetAttribute("isLocked", IsLocked());
element.SetAttribute("isLightingLayer", IsLightingLayer());
@@ -78,6 +79,7 @@ void Layer::SerializeTo(SerializerElement& element) const {
void Layer::UnserializeFrom(const SerializerElement& element) {
SetName(element.GetStringAttribute("name", "", "Name"));
SetRenderingType(element.GetStringAttribute("renderingType", ""));
SetCameraType(element.GetStringAttribute("cameraType", "perspective"));
SetVisibility(element.GetBoolAttribute("visibility", true, "Visibility"));
SetLocked(element.GetBoolAttribute("isLocked", false));
SetLightingLayer(element.GetBoolAttribute("isLightingLayer", false));

View File

@@ -104,10 +104,17 @@ class GD_CORE_API Layer {
const gd::String& GetName() const { return name; }
const gd::String& GetRenderingType() const { return renderingType; }
void SetRenderingType(const gd::String& renderingType_) {
renderingType = renderingType_;
}
const gd::String& GetCameraType() const { return cameraType; }
void SetCameraType(const gd::String& cameraType_) {
cameraType = cameraType_;
}
/**
* \brief Change if layer is displayed or not
*/
@@ -268,6 +275,7 @@ class GD_CORE_API Layer {
gd::String name; ///< The name of the layer
gd::String renderingType; ///< The rendering type: "" (empty), "2d", "3d" or
///< "2d+3d".
gd::String cameraType;
bool isVisible; ///< True if the layer is visible
bool isLocked; ///< True if the layer is locked
bool isLightingLayer; ///< True if the layer is used to display lights and

View File

@@ -489,7 +489,7 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
"Effect",
_("Apply visual effects to objects."),
"",
"res/actions/effect24.png", "EffectBehavior",
"res/actions/effect_black.svg", "EffectBehavior",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetHidden();

View File

@@ -203,6 +203,23 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
auto node = parser.ParseExpression("abcd[0]");
REQUIRE(node != nullptr);
// Also check that if we try to find the last parent of node, it is not defined.
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
platform, projectScopedContainers, *node);
REQUIRE(lastParentOfNode.parentVariable == nullptr);
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
"No object, variable or property with this name found.");
REQUIRE(validator.GetFatalErrors()[0]->GetStartPosition() == 0);
}
{
auto node = parser.ParseExpression("abcd[0].efg");
REQUIRE(node != nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);
@@ -214,6 +231,12 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
auto node = parser.ParseExpression("abcd.efg.hij");
REQUIRE(node != nullptr);
// Also check that if we try to find the last parent of node, it is not defined.
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
platform, projectScopedContainers, *node);
REQUIRE(lastParentOfNode.parentVariable == nullptr);
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);
@@ -762,6 +785,12 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
auto node = parser.ParseExpression("abcd.efg.hij");
REQUIRE(node != nullptr);
// Also check that if we try to find the last parent of node, it is not defined.
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
platform, projectScopedContainers, *node);
REQUIRE(lastParentOfNode.parentVariable == nullptr);
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "number");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);
@@ -1495,6 +1524,12 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
auto node =
parser.ParseExpression("MyNonExistingSceneVariable");
// Also check that if we try to find the last parent of node, it is not defined.
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
platform, projectScopedContainers, *node);
REQUIRE(lastParentOfNode.parentVariable == nullptr);
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);
@@ -1516,6 +1551,25 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
}
}
SECTION("Invalid scene variables (2 levels, variable and child do not exist)") {
{
auto node =
parser.ParseExpression("MyNonExistingSceneVariable.MyNonExistingChild");
// Also check that if we try to find the last parent of node, it is not defined.
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
platform, projectScopedContainers, *node);
REQUIRE(lastParentOfNode.parentVariable == nullptr);
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
"You must enter a number or a text, wrapped inside double quotes (example: \"Hello world\"), or a variable name.");
}
}
SECTION("Valid object variables (1 level)") {
{
auto node =
@@ -1586,6 +1640,12 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
auto node =
parser.ParseExpression("MyNonExistingSpriteObject.MyVariable");
// Also check that if we try to find the last parent of node, it is not defined.
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
platform, projectScopedContainers, *node);
REQUIRE(lastParentOfNode.parentVariable == nullptr);
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);

View File

@@ -0,0 +1,148 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
/**
* @file Tests covering common features of GDevelop Core.
*/
#include "GDCore/IDE/ObjectAssetSerializer.h"
#include "DummyPlatform.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Builtin/StandardEvent.h"
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Serialization.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/CustomObjectConfiguration.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/Variable.h"
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Tools/SystemStats.h"
#include "GDCore/Tools/VersionWrapper.h"
#include "catch.hpp"
#include <string>
using namespace gd;
TEST_CASE("ObjectAssetSerializer", "[common]") {
SECTION("Can serialize custom objects as assets") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &eventsBasedObject = eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
eventsBasedObject.SetFullName("My events based object");
eventsBasedObject.SetDescription("An events based object for test");
eventsBasedObject.InsertNewObject(project, "MyExtension::Sprite", "MyChild",
0);
auto &resourceManager = project.GetResourcesManager();
gd::ImageResource imageResource;
imageResource.SetName("assets/Idle.png");
imageResource.SetFile("assets/Idle.png");
imageResource.SetSmooth(true);
resourceManager.AddResource(imageResource);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.InsertNewObject(
project, "MyEventsExtension::MyEventsBasedObject", "MyObject", 0);
auto &configuration = object.GetConfiguration();
auto *customObjectConfiguration =
dynamic_cast<gd::CustomObjectConfiguration *>(&configuration);
auto *spriteConfiguration = dynamic_cast<gd::SpriteObject *>(
&customObjectConfiguration->GetChildObjectConfiguration("MyChild"));
REQUIRE(spriteConfiguration != nullptr);
{
gd::Animation animation;
animation.SetName("Idle");
animation.SetDirectionsCount(1);
auto &direction = animation.GetDirection(0);
gd::Sprite frame;
frame.SetImageName("assets/Idle.png");
direction.AddSprite(frame);
spriteConfiguration->AddAnimation(animation);
}
SerializerElement assetElement;
std::map<gd::String, gd::String> resourcesFileNameMap;
ObjectAssetSerializer::SerializeTo(project, object, "My Object",
assetElement, resourcesFileNameMap);
// This mapping is used to copy resource files.
REQUIRE(resourcesFileNameMap.find("assets/Idle.png") !=
resourcesFileNameMap.end());
REQUIRE(resourcesFileNameMap["assets/Idle.png"] == "Idle.png");
// Check that the project is left untouched.
REQUIRE(resourceManager.HasResource("assets/Idle.png"));
REQUIRE(resourceManager.GetResource("assets/Idle.png").GetFile() ==
"assets/Idle.png");
REQUIRE(!resourceManager.HasResource("Idle.png"));
REQUIRE(assetElement.HasChild("objectAssets"));
auto &objectAssetsElement = assetElement.GetChild("objectAssets");
objectAssetsElement.ConsiderAsArrayOf("objectAsset");
REQUIRE(objectAssetsElement.GetChildrenCount() == 1);
auto &objectAssetElement = objectAssetsElement.GetChild(0);
REQUIRE(objectAssetElement.HasChild("requiredExtensions"));
auto &requiredExtensionsElement =
objectAssetElement.GetChild("requiredExtensions");
requiredExtensionsElement.ConsiderAsArrayOf("requiredExtension");
REQUIRE(requiredExtensionsElement.GetChildrenCount() == 1);
auto &requiredExtensionElement = requiredExtensionsElement.GetChild(0);
REQUIRE(requiredExtensionElement.GetStringAttribute("extensionName") ==
"MyEventsExtension");
// Resources are renamed according to asset script naming conventions.
REQUIRE(objectAssetElement.HasChild("resources"));
auto &resourcesElement = objectAssetElement.GetChild("resources");
resourcesElement.ConsiderAsArrayOf("resource");
REQUIRE(resourcesElement.GetChildrenCount() == 1);
{
auto &resourceElement = resourcesElement.GetChild(0);
REQUIRE(resourceElement.GetStringAttribute("name") == "Idle.png");
REQUIRE(resourceElement.GetStringAttribute("file") == "Idle.png");
REQUIRE(resourceElement.GetStringAttribute("kind") == "image");
REQUIRE(resourceElement.GetBoolAttribute("smoothed") == true);
}
// Resources used in object configuration are updated.
REQUIRE(objectAssetElement.HasChild("object"));
auto &objectElement = objectAssetElement.GetChild("object");
REQUIRE(objectElement.GetStringAttribute("name") == "MyObject");
REQUIRE(objectElement.GetStringAttribute("type") ==
"MyEventsExtension::MyEventsBasedObject");
auto &childrenContentElement = objectElement.GetChild("childrenContent");
REQUIRE(childrenContentElement.HasChild("MyChild"));
auto &childElement = childrenContentElement.GetChild("MyChild");
REQUIRE(childElement.HasChild("animations"));
auto &animationsElement = childElement.GetChild("animations");
animationsElement.ConsiderAsArrayOf("animation");
REQUIRE(animationsElement.GetChildrenCount() == 1);
auto &animationElement = animationsElement.GetChild(0);
REQUIRE(animationElement.GetStringAttribute("name") == "Idle");
auto &directionsElement = animationElement.GetChild("directions");
directionsElement.ConsiderAsArrayOf("direction");
REQUIRE(directionsElement.GetChildrenCount() == 1);
auto &directionElement = directionsElement.GetChild(0);
auto &spritesElement = directionElement.GetChild("sprites");
spritesElement.ConsiderAsArrayOf("sprite");
REQUIRE(spritesElement.GetChildrenCount() == 1);
auto &spriteElement = spritesElement.GetChild(0);
REQUIRE(spriteElement.GetStringAttribute("image") == "Idle.png");
}
}

View File

@@ -3474,6 +3474,72 @@ TEST_CASE("RenameLayer", "[common]") {
"MyExtension::CameraCenterX(\"layerA\")");
}
SECTION("Renaming a layer also moves the instances on this layer and of the associated external layouts") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &layout = project.InsertNewLayout("My layout", 0);
auto &otherLayout = project.InsertNewLayout("My other layout", 1);
layout.InsertNewLayer("My layer", 0);
otherLayout.InsertNewLayer("My layer", 0);
auto &externalLayout =
project.InsertNewExternalLayout("My external layout", 0);
auto &otherExternalLayout =
project.InsertNewExternalLayout("My other external layout", 0);
externalLayout.SetAssociatedLayout("My layout");
otherExternalLayout.SetAssociatedLayout("My other layout");
auto &initialInstances = layout.GetInitialInstances();
auto &initialInstance1 = initialInstances.InsertNewInitialInstance();
initialInstance1.SetLayer("My layer");
auto &initialInstance2 = initialInstances.InsertNewInitialInstance();
initialInstance2.SetLayer("My layer");
auto &initialInstance3 = initialInstances.InsertNewInitialInstance();
initialInstance3.SetLayer("");
auto &externalInitialInstances = externalLayout.GetInitialInstances();
auto &externalInitialInstance1 = externalInitialInstances.InsertNewInitialInstance();
externalInitialInstance1.SetLayer("My layer");
auto &externalInitialInstance2 = externalInitialInstances.InsertNewInitialInstance();
externalInitialInstance2.SetLayer("My layer");
auto &externalInitialInstance3 = externalInitialInstances.InsertNewInitialInstance();
externalInitialInstance3.SetLayer("");
auto &otherInitialInstances = otherLayout.GetInitialInstances();
auto &otherInitialInstance1 = otherInitialInstances.InsertNewInitialInstance();
otherInitialInstance1.SetLayer("My layer");
auto &otherExternalInitialInstances = otherExternalLayout.GetInitialInstances();
auto &otherExternalInitialInstance1 = otherExternalInitialInstances.InsertNewInitialInstance();
otherExternalInitialInstance1.SetLayer("My layer");
REQUIRE(initialInstance1.GetLayer() == "My layer");
REQUIRE(initialInstance2.GetLayer() == "My layer");
REQUIRE(initialInstance3.GetLayer() == "");
REQUIRE(externalInitialInstance1.GetLayer() == "My layer");
REQUIRE(externalInitialInstance2.GetLayer() == "My layer");
REQUIRE(externalInitialInstance3.GetLayer() == "");
REQUIRE(otherInitialInstance1.GetLayer() == "My layer");
REQUIRE(otherExternalInitialInstance1.GetLayer() == "My layer");
gd::WholeProjectRefactorer::RenameLayer(project, layout, "My layer", "My new layer");
// Instances on the renamed layer are moved to the new layer.
REQUIRE(initialInstance1.GetLayer() == "My new layer");
REQUIRE(initialInstance2.GetLayer() == "My new layer");
REQUIRE(initialInstance3.GetLayer() == "");
// Instances on the renamed layer of external layouts are moved to the new layer.
REQUIRE(externalInitialInstance1.GetLayer() == "My new layer");
REQUIRE(externalInitialInstance2.GetLayer() == "My new layer");
REQUIRE(externalInitialInstance3.GetLayer() == "");
// Instances on the renamed layer of other layouts & external layouts are not moved.
REQUIRE(otherInitialInstance1.GetLayer() == "My layer");
REQUIRE(otherExternalInitialInstance1.GetLayer() == "My layer");
}
SECTION("Can rename a layer when a layer parameter is empty") {
gd::Project project;
gd::Platform platform;

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -247,7 +239,7 @@ module.exports = {
'Model3DObject',
_('3D Model'),
_('An animated 3D model.'),
'JsPlatform/Extensions/3d_box.svg',
'JsPlatform/Extensions/3d_model.svg',
new gd.Model3DObjectConfiguration()
)
.setCategoryFullName(_('General'))
@@ -1665,7 +1657,7 @@ module.exports = {
'Change the camera rotation to look at an object. The camera top always face the screen.'
),
_('Change the camera rotation of _PARAM2_ to look at _PARAM1_'),
_("Layers and cameras"),
_('Layers and cameras'),
'res/conditions/3d_box.svg',
'res/conditions/3d_box.svg'
)
@@ -1954,10 +1946,7 @@ module.exports = {
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
/**
@@ -1965,17 +1954,13 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {},
registerEditorConfigurations: function (objectsEditorService) {},
/**
* Register renderers for instance of objects on the scene editor.
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (ObjectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const Rendered3DInstance = objectsRenderingService.Rendered3DInstance;
const PIXI = objectsRenderingService.PIXI;
@@ -2112,10 +2097,9 @@ module.exports = {
static getThumbnail(project, resourcesLoader, objectConfiguration) {
const instance = this._instance;
const textureResourceName =
RenderedCube3DObject2DInstance._getResourceNameToDisplay(
objectConfiguration
);
const textureResourceName = RenderedCube3DObject2DInstance._getResourceNameToDisplay(
objectConfiguration
);
if (textureResourceName) {
return resourcesLoader.getResourceFullUrl(
project,
@@ -2127,20 +2111,18 @@ module.exports = {
}
updateTextureIfNeeded() {
const textureName =
RenderedCube3DObject2DInstance._getResourceNameToDisplay(
this._associatedObjectConfiguration
);
const textureName = RenderedCube3DObject2DInstance._getResourceNameToDisplay(
this._associatedObjectConfiguration
);
if (textureName === this._renderedResourceName) return;
this.updateTexture();
}
updateTexture() {
const textureName =
RenderedCube3DObject2DInstance._getResourceNameToDisplay(
this._associatedObjectConfiguration
);
const textureName = RenderedCube3DObject2DInstance._getResourceNameToDisplay(
this._associatedObjectConfiguration
);
if (!textureName) {
this._renderFallbackObject = true;
@@ -2398,10 +2380,9 @@ module.exports = {
continue;
}
const shouldRepeatTexture =
this._shouldRepeatTextureOnFace[
materialIndexToFaceIndex[materialIndex]
];
const shouldRepeatTexture = this._shouldRepeatTextureOnFace[
materialIndexToFaceIndex[materialIndex]
];
const shouldOrientateFacesTowardsY = this._facesOrientation === 'Y';
@@ -2436,13 +2417,16 @@ module.exports = {
}
} else {
if (shouldOrientateFacesTowardsY) {
[x, y] =
noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
[x, y] = noRepeatTextureVertexIndexToUvMapping[
vertexIndex % 4
];
} else {
[x, y] =
noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
[
x,
y,
] = noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
}
}
break;
@@ -2472,13 +2456,16 @@ module.exports = {
}
} else {
if (shouldOrientateFacesTowardsY) {
[x, y] =
noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
[x, y] = noRepeatTextureVertexIndexToUvMapping[
vertexIndex % 4
];
} else {
[x, y] =
noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
[
x,
y,
] = noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
x = -x;
y = -y;
}
@@ -2695,7 +2682,7 @@ module.exports = {
}
static getThumbnail(project, resourcesLoader, objectConfiguration) {
return 'JsPlatform/Extensions/3d_box.svg';
return 'JsPlatform/Extensions/3d_model.svg';
}
getOriginX() {

View File

@@ -11,7 +11,12 @@ namespace gdjs {
const layer = runtimeScene.getLayer(layerName);
const layerRenderer = layer.getRenderer();
const threeCamera = layerRenderer.getThreeCamera();
const fov = threeCamera ? threeCamera.fov : assumedFovIn2D;
const fov =
threeCamera instanceof THREE.OrthographicCamera
? null
: threeCamera
? threeCamera.fov
: assumedFovIn2D;
return layer.getCameraZ(fov, cameraIndex);
};
@@ -24,7 +29,12 @@ namespace gdjs {
const layer = runtimeScene.getLayer(layerName);
const layerRenderer = layer.getRenderer();
const threeCamera = layerRenderer.getThreeCamera();
const fov = threeCamera ? threeCamera.fov : assumedFovIn2D;
const fov =
threeCamera instanceof THREE.OrthographicCamera
? null
: threeCamera
? threeCamera.fov
: assumedFovIn2D;
layer.setCameraZ(z, fov, cameraIndex);
};
@@ -213,8 +223,10 @@ namespace gdjs {
const layerRenderer = layer.getRenderer();
const threeCamera = layerRenderer.getThreeCamera();
if (!threeCamera) return 45;
return threeCamera.fov;
if (!threeCamera) return assumedFovIn2D;
return threeCamera instanceof THREE.OrthographicCamera
? 0
: threeCamera.fov;
};
export const setFov = (
@@ -227,7 +239,8 @@ namespace gdjs {
const layerRenderer = layer.getRenderer();
const threeCamera = layerRenderer.getThreeCamera();
if (!threeCamera) return;
if (!threeCamera || threeCamera instanceof THREE.OrthographicCamera)
return;
threeCamera.fov = Math.min(Math.max(angle, 0), 180);
layerRenderer.setThreeCameraDirty(true);

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -789,10 +781,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,11 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -710,10 +709,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,20 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
const stringifyOptions = (options) => '["' + options.join('","') + '"]';
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -126,7 +116,8 @@ module.exports = {
};
objectBBText.setRawJSONContent(
JSON.stringify({
text: '[b]bold[/b] [i]italic[/i] [size=15]smaller[/size] [font=times]times[/font] font\n[spacing=12]spaced out[/spacing]\n[outline=yellow]outlined[/outline] [shadow=red]DropShadow[/shadow] ',
text:
'[b]bold[/b] [i]italic[/i] [size=15]smaller[/size] [font=times]times[/font] font\n[spacing=12]spaced out[/spacing]\n[outline=yellow]outlined[/outline] [shadow=red]DropShadow[/shadow] ',
opacity: 255,
fontSize: 20,
visible: true,
@@ -223,10 +214,9 @@ module.exports = {
parameterType === 'string' ||
parameterType === 'stringWithSelector'
) {
const parameterOptions =
gd.ParameterOptions.makeNewOptions().setDescription(
property.paramLabel
);
const parameterOptions = gd.ParameterOptions.makeNewOptions().setDescription(
property.paramLabel
);
if (property.options) {
parameterOptions.setTypeExtraInfo(
stringifyOptions(property.options)
@@ -276,10 +266,9 @@ module.exports = {
parameterType === 'number' ||
parameterType === 'stringWithSelector'
) {
const parameterOptions =
gd.ParameterOptions.makeNewOptions().setDescription(
property.paramLabel
);
const parameterOptions = gd.ParameterOptions.makeNewOptions().setDescription(
property.paramLabel
);
if (property.options) {
parameterOptions.setTypeExtraInfo(
stringifyOptions(property.options)
@@ -457,10 +446,7 @@ module.exports = {
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
/**
@@ -468,9 +454,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {
registerEditorConfigurations: function (objectsEditorService) {
objectsEditorService.registerEditorConfiguration(
'BBText::BBText',
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
@@ -483,9 +467,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const PIXI = objectsRenderingService.PIXI;
const MultiStyleText = objectsRenderingService.requireModule(
@@ -568,8 +550,9 @@ module.exports = {
this._pixiObject.alpha = opacity / 255;
const color = properties.get('color').getValue();
this._pixiObject.textStyles.default.fill =
objectsRenderingService.rgbOrHexToHexNumber(color);
this._pixiObject.textStyles.default.fill = objectsRenderingService.rgbOrHexToHexNumber(
color
);
const fontSize = properties.get('fontSize').getValue();
this._pixiObject.textStyles.default.fontSize = `${fontSize}px`;

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -127,7 +119,8 @@ module.exports = {
};
bitmapTextObject.setRawJSONContent(
JSON.stringify({
text: 'This text use the default bitmap font.\nUse a custom Bitmap Font to create your own texts.',
text:
'This text use the default bitmap font.\nUse a custom Bitmap Font to create your own texts.',
opacity: 255,
scale: 1,
fontSize: 20,
@@ -176,7 +169,7 @@ module.exports = {
'Extensions/BitmapText/bitmaptextruntimeobject-pixi-renderer.js'
)
.setCategoryFullName(_('Text'))
.addDefaultBehavior("TextContainerCapability::TextContainerBehavior")
.addDefaultBehavior('TextContainerCapability::TextContainerBehavior')
.addDefaultBehavior('EffectCapability::EffectBehavior')
.addDefaultBehavior('OpacityCapability::OpacityBehavior')
.addDefaultBehavior('ScalableCapability::ScalableBehavior');
@@ -327,33 +320,33 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('setBitmapFontAndTextureAtlasResourceName');
object
.addAction(
'SetBitmapFontAndTextureAtlasResourceName2',
_('Bitmap files resources'),
_('Change the Bitmap Font and/or the atlas image used by the object.'),
_(
'Set the bitmap font of _PARAM0_ to _PARAM1_ and the atlas to _PARAM2_'
),
'',
'res/actions/font24.png',
'res/actions/font.png'
)
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
.addParameter(
'bitmapFontResource',
_('Bitmap font resource name'),
'',
false
)
.addParameter(
'imageResource',
_('Texture atlas resource name'),
'',
false
)
.getCodeExtraInformation()
.setFunctionName('setBitmapFontAndTextureAtlasResourceName');
object
.addAction(
'SetBitmapFontAndTextureAtlasResourceName2',
_('Bitmap files resources'),
_('Change the Bitmap Font and/or the atlas image used by the object.'),
_(
'Set the bitmap font of _PARAM0_ to _PARAM1_ and the atlas to _PARAM2_'
),
'',
'res/actions/font24.png',
'res/actions/font.png'
)
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
.addParameter(
'bitmapFontResource',
_('Bitmap font resource name'),
'',
false
)
.addParameter(
'imageResource',
_('Texture atlas resource name'),
'',
false
)
.getCodeExtraInformation()
.setFunctionName('setBitmapFontAndTextureAtlasResourceName');
object
.addExpressionAndCondition(
@@ -451,10 +444,7 @@ module.exports = {
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
/**
@@ -462,9 +452,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {
registerEditorConfigurations: function (objectsEditorService) {
objectsEditorService.registerEditorConfiguration(
'BitmapText::BitmapTextObject',
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
@@ -477,9 +465,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const PIXI = objectsRenderingService.PIXI;
@@ -718,8 +704,9 @@ module.exports = {
this._pixiObject.align = align;
const color = properties.get('tint').getValue();
this._pixiObject.tint =
objectsRenderingService.rgbOrHexToHexNumber(color);
this._pixiObject.tint = objectsRenderingService.rgbOrHexToHexNumber(
color
);
const scale = properties.get('scale').getValue() || 1;
this._pixiObject.scale.set(scale);

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -114,10 +106,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,450 +13,389 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function(_/*: (string) => string */, gd/*: libGDevelop */) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension.setExtensionInformation(
"DeviceSensors",
_("Device sensors"),
_(
"Allow the game to access the sensors of a mobile device."
),
"Matthias Meike",
"Open source (MIT License)"
).setExtensionHelpPath("/all-features/device-sensors")
.setCategory('Input');
extension.addInstructionOrExpressionGroupMetadata(_("Device sensors"))
.setIcon("JsPlatform/Extensions/orientation_active32.png");
extension
.setExtensionInformation(
'DeviceSensors',
_('Device sensors'),
_('Allow the game to access the sensors of a mobile device.'),
'Matthias Meike',
'Open source (MIT License)'
)
.setExtensionHelpPath('/all-features/device-sensors')
.setCategory('Input');
extension
.addInstructionOrExpressionGroupMetadata(_('Device sensors'))
.setIcon('JsPlatform/Extensions/orientation_active32.png');
extension
.addCondition(
"OrientationSensorActive",
_("Sensor active"),
'OrientationSensorActive',
_('Sensor active'),
_(
"The condition is true if the device orientation sensor is currently active"
'The condition is true if the device orientation sensor is currently active'
),
_("Orientation sensor is active"),
_("Orientation"),
"JsPlatform/Extensions/orientation_active32.png",
"JsPlatform/Extensions/orientation_active32.png"
_('Orientation sensor is active'),
_('Orientation'),
'JsPlatform/Extensions/orientation_active32.png',
'JsPlatform/Extensions/orientation_active32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.isActive");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.isActive');
extension
extension
.addCondition(
"OrientationAlpha",
_("Compare the value of orientation alpha"),
_(
"Compare the value of orientation alpha. (Range: 0 to 360°)"
),
_("the orientation alpha"),
_("Orientation"),
"JsPlatform/Extensions/orientation_alpha32.png",
"JsPlatform/Extensions/orientation_alpha32.png"
'OrientationAlpha',
_('Compare the value of orientation alpha'),
_('Compare the value of orientation alpha. (Range: 0 to 360°)'),
_('the orientation alpha'),
_('Orientation'),
'JsPlatform/Extensions/orientation_alpha32.png',
'JsPlatform/Extensions/orientation_alpha32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.getOrientationAlpha");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.getOrientationAlpha');
extension
extension
.addCondition(
"OrientationBeta",
_("Compare the value of orientation beta"),
_(
"Compare the value of orientation beta. (Range: -180 to 180°)"
),
_("the orientation beta"),
_("Orientation"),
"JsPlatform/Extensions/orientation_beta32.png",
"JsPlatform/Extensions/orientation_beta32.png"
'OrientationBeta',
_('Compare the value of orientation beta'),
_('Compare the value of orientation beta. (Range: -180 to 180°)'),
_('the orientation beta'),
_('Orientation'),
'JsPlatform/Extensions/orientation_beta32.png',
'JsPlatform/Extensions/orientation_beta32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.getOrientationBeta");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.getOrientationBeta');
extension
extension
.addCondition(
"OrientationGamma",
_("Compare the value of orientation gamma"),
_(
"Compare the value of orientation gamma. (Range: -90 to 90°)"
),
_("the orientation gamma"),
_("Orientation"),
"JsPlatform/Extensions/orientation_gamma32.png",
"JsPlatform/Extensions/orientation_gamma32.png"
'OrientationGamma',
_('Compare the value of orientation gamma'),
_('Compare the value of orientation gamma. (Range: -90 to 90°)'),
_('the orientation gamma'),
_('Orientation'),
'JsPlatform/Extensions/orientation_gamma32.png',
'JsPlatform/Extensions/orientation_gamma32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.getOrientationGamma");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.getOrientationGamma');
extension
.addAction(
"ActivateOrientationListener",
_("Activate orientation sensor"),
_("Activate the orientation sensor. (remember to turn it off again)"),
_("Activate the orientation sensor."),
_("Orientation"),
"JsPlatform/Extensions/orientation_active32.png",
"JsPlatform/Extensions/orientation_active32.png"
'ActivateOrientationListener',
_('Activate orientation sensor'),
_('Activate the orientation sensor. (remember to turn it off again)'),
_('Activate the orientation sensor.'),
_('Orientation'),
'JsPlatform/Extensions/orientation_active32.png',
'JsPlatform/Extensions/orientation_active32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.activateOrientationSensor");
.getCodeExtraInformation()
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName(
'gdjs.deviceSensors.orientation.activateOrientationSensor'
);
extension
.addAction(
"DeactivateOrientationListener",
_("Deactivate orientation sensor"),
_("Deactivate the orientation sensor."),
_("Deactivate the orientation sensor."),
_("Orientation"),
"JsPlatform/Extensions/orientation_inactive32.png",
"JsPlatform/Extensions/orientation_inactive32.png"
'DeactivateOrientationListener',
_('Deactivate orientation sensor'),
_('Deactivate the orientation sensor.'),
_('Deactivate the orientation sensor.'),
_('Orientation'),
'JsPlatform/Extensions/orientation_inactive32.png',
'JsPlatform/Extensions/orientation_inactive32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.deactivateOrientationSensor");
.getCodeExtraInformation()
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName(
'gdjs.deviceSensors.orientation.deactivateOrientationSensor'
);
extension
.addExpression(
"OrientationAbsolute",
_("Is Absolute"),
_("Get if the devices orientation is absolute and not relative"),
_("Orientation"),
"JsPlatform/Extensions/orientation_absolute16.png"
'OrientationAbsolute',
_('Is Absolute'),
_('Get if the devices orientation is absolute and not relative'),
_('Orientation'),
'JsPlatform/Extensions/orientation_absolute16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.getOrientationAbsolute");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.getOrientationAbsolute');
extension
.addExpression(
"OrientationAlpha",
_("Alpha value"),
_("Get the devices orientation Alpha (compass)"),
_("Orientation"),
"JsPlatform/Extensions/orientation_alpha16.png"
'OrientationAlpha',
_('Alpha value'),
_('Get the devices orientation Alpha (compass)'),
_('Orientation'),
'JsPlatform/Extensions/orientation_alpha16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.getOrientationAlpha");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.getOrientationAlpha');
extension
.addExpression(
"OrientationBeta",
_("Beta value"),
_("Get the devices orientation Beta"),
_("Orientation"),
"JsPlatform/Extensions/orientation_beta16.png"
'OrientationBeta',
_('Beta value'),
_('Get the devices orientation Beta'),
_('Orientation'),
'JsPlatform/Extensions/orientation_beta16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.getOrientationBeta");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.getOrientationBeta');
extension
.addExpression(
"OrientationGamma",
_("Gamma value"),
_("Get the devices orientation Gamma value"),
_("Orientation"),
"JsPlatform/Extensions/orientation_gamma16.png"
'OrientationGamma',
_('Gamma value'),
_('Get the devices orientation Gamma value'),
_('Orientation'),
'JsPlatform/Extensions/orientation_gamma16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.orientation.getOrientationGamma");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.orientation.getOrientationGamma');
extension
extension
.addCondition(
"MotionSensorActive",
_("Sensor active"),
'MotionSensorActive',
_('Sensor active'),
_(
"The condition is true if the device motion sensor is currently active"
'The condition is true if the device motion sensor is currently active'
),
_("Motion sensor is active"),
_("Motion"),
"JsPlatform/Extensions/motion_active32.png",
"JsPlatform/Extensions/motion_active32.png"
_('Motion sensor is active'),
_('Motion'),
'JsPlatform/Extensions/motion_active32.png',
'JsPlatform/Extensions/motion_active32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.isActive");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.isActive');
extension
extension
.addCondition(
"RotationAlpha",
_("Compare the value of rotation alpha"),
'RotationAlpha',
_('Compare the value of rotation alpha'),
_(
"Compare the value of rotation alpha. (Note: few devices support this sensor)"
'Compare the value of rotation alpha. (Note: few devices support this sensor)'
),
_("the rotation alpha"),
_("Motion"),
"JsPlatform/Extensions/motion_rotation_alpha32.png",
"JsPlatform/Extensions/motion_rotation_alpha32.png"
_('the rotation alpha'),
_('Motion'),
'JsPlatform/Extensions/motion_rotation_alpha32.png',
'JsPlatform/Extensions/motion_rotation_alpha32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value (m/s²)"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value (m/s²)'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getRotationAlpha");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getRotationAlpha');
extension
extension
.addCondition(
"RotationBeta",
_("Compare the value of rotation beta"),
'RotationBeta',
_('Compare the value of rotation beta'),
_(
"Compare the value of rotation beta. (Note: few devices support this sensor)"
'Compare the value of rotation beta. (Note: few devices support this sensor)'
),
_("the rotation beta"),
_("Motion"),
"JsPlatform/Extensions/motion_rotation_beta32.png",
"JsPlatform/Extensions/motion_rotation_beta32.png"
_('the rotation beta'),
_('Motion'),
'JsPlatform/Extensions/motion_rotation_beta32.png',
'JsPlatform/Extensions/motion_rotation_beta32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value (m/s²)"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value (m/s²)'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getRotationBeta");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getRotationBeta');
extension
extension
.addCondition(
"RotationGamma",
_("Compare the value of rotation gamma"),
'RotationGamma',
_('Compare the value of rotation gamma'),
_(
"Compare the value of rotation gamma. (Note: few devices support this sensor)"
'Compare the value of rotation gamma. (Note: few devices support this sensor)'
),
_("the rotation gamma"),
_("Motion"),
"JsPlatform/Extensions/motion_rotation_gamma32.png",
"JsPlatform/Extensions/motion_rotation_gamma32.png"
_('the rotation gamma'),
_('Motion'),
'JsPlatform/Extensions/motion_rotation_gamma32.png',
'JsPlatform/Extensions/motion_rotation_gamma32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value (m/s²)"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value (m/s²)'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getRotationGamma");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getRotationGamma');
extension
extension
.addCondition(
"AccelerationX",
_("Compare the value of acceleration on X-axis"),
_(
"Compare the value of acceleration on the X-axis (m/s²)."
),
_("the acceleration X"),
_("Motion"),
"JsPlatform/Extensions/motion_acceleration_x32.png",
"JsPlatform/Extensions/motion_acceleration_x32.png"
'AccelerationX',
_('Compare the value of acceleration on X-axis'),
_('Compare the value of acceleration on the X-axis (m/s²).'),
_('the acceleration X'),
_('Motion'),
'JsPlatform/Extensions/motion_acceleration_x32.png',
'JsPlatform/Extensions/motion_acceleration_x32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value (m/s²)"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value (m/s²)'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getAccelerationX");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getAccelerationX');
extension
extension
.addCondition(
"AccelerationY",
_("Compare the value of acceleration on Y-axis"),
_(
"Compare the value of acceleration on the Y-axis (m/s²)."
),
_("the acceleration Y"),
_("Motion"),
"JsPlatform/Extensions/motion_acceleration_y32.png",
"JsPlatform/Extensions/motion_acceleration_y32.png"
'AccelerationY',
_('Compare the value of acceleration on Y-axis'),
_('Compare the value of acceleration on the Y-axis (m/s²).'),
_('the acceleration Y'),
_('Motion'),
'JsPlatform/Extensions/motion_acceleration_y32.png',
'JsPlatform/Extensions/motion_acceleration_y32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value (m/s²)"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value (m/s²)'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getAccelerationY");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getAccelerationY');
extension
extension
.addCondition(
"AccelerationZ",
_("Compare the value of acceleration on Z-axis"),
_(
"Compare the value of acceleration on the Z-axis (m/s²)."
),
_("the acceleration Z"),
_("Motion"),
"JsPlatform/Extensions/motion_acceleration_z32.png",
"JsPlatform/Extensions/motion_acceleration_z32.png"
'AccelerationZ',
_('Compare the value of acceleration on Z-axis'),
_('Compare the value of acceleration on the Z-axis (m/s²).'),
_('the acceleration Z'),
_('Motion'),
'JsPlatform/Extensions/motion_acceleration_z32.png',
'JsPlatform/Extensions/motion_acceleration_z32.png'
)
.addParameter("relationalOperator", _("Sign of the test"), "number")
.addParameter("expression", _("Value (m/s²)"))
.addParameter('relationalOperator', _('Sign of the test'), 'number')
.addParameter('expression', _('Value (m/s²)'))
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getAccelerationZ");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getAccelerationZ');
extension
.addAction(
"ActivateMotionListener",
_("Activate motion sensor"),
_("Activate the motion sensor. (remember to turn it off again)"),
_("Activate the motion sensor."),
_("Motion"),
"JsPlatform/Extensions/motion_active32.png",
"JsPlatform/Extensions/motion_active32.png"
'ActivateMotionListener',
_('Activate motion sensor'),
_('Activate the motion sensor. (remember to turn it off again)'),
_('Activate the motion sensor.'),
_('Motion'),
'JsPlatform/Extensions/motion_active32.png',
'JsPlatform/Extensions/motion_active32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.activateMotionSensor");
.getCodeExtraInformation()
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.activateMotionSensor');
extension
.addAction(
"DeactivateMotionListener",
_("Deactivate motion sensor"),
_("Deactivate the motion sensor."),
_("Deactivate the motion sensor."),
_("Motion"),
"JsPlatform/Extensions/motion_inactive32.png",
"JsPlatform/Extensions/motion_inactive32.png"
'DeactivateMotionListener',
_('Deactivate motion sensor'),
_('Deactivate the motion sensor.'),
_('Deactivate the motion sensor.'),
_('Motion'),
'JsPlatform/Extensions/motion_inactive32.png',
'JsPlatform/Extensions/motion_inactive32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.deactivateMotionSensor");
.getCodeExtraInformation()
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.deactivateMotionSensor');
extension
.addExpression(
"RotationAlpha",
_("Alpha value"),
_("Get the devices rotation Alpha"),
_("Motion"),
"JsPlatform/Extensions/motion_rotation_alpha16.png"
'RotationAlpha',
_('Alpha value'),
_('Get the devices rotation Alpha'),
_('Motion'),
'JsPlatform/Extensions/motion_rotation_alpha16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getRotationAlpha");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getRotationAlpha');
extension
.addExpression(
"RotationBeta",
_("Beta value"),
_("Get the devices rotation Beta"),
_("Motion"),
"JsPlatform/Extensions/motion_rotation_beta16.png"
'RotationBeta',
_('Beta value'),
_('Get the devices rotation Beta'),
_('Motion'),
'JsPlatform/Extensions/motion_rotation_beta16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getRotationBeta");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getRotationBeta');
extension
.addExpression(
"RotationGamma",
_("Gamma value"),
_("Get the devices rotation Gamma"),
_("Motion"),
"JsPlatform/Extensions/motion_rotation_gamma16.png"
'RotationGamma',
_('Gamma value'),
_('Get the devices rotation Gamma'),
_('Motion'),
'JsPlatform/Extensions/motion_rotation_gamma16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getRotationGamma");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getRotationGamma');
extension
extension
.addExpression(
"AccelerationX",
_("Acceleration X value"),
_("Get the devices acceleration on the X-axis (m/s²)"),
_("Motion"),
"JsPlatform/Extensions/motion_acceleration_x16.png"
'AccelerationX',
_('Acceleration X value'),
_('Get the devices acceleration on the X-axis (m/s²)'),
_('Motion'),
'JsPlatform/Extensions/motion_acceleration_x16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getAccelerationX");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getAccelerationX');
extension
extension
.addExpression(
"AccelerationY",
_("Acceleration Y value"),
_("Get the devices acceleration on the Y-axis (m/s²)"),
_("Motion"),
"JsPlatform/Extensions/motion_acceleration_y16.png"
'AccelerationY',
_('Acceleration Y value'),
_('Get the devices acceleration on the Y-axis (m/s²)'),
_('Motion'),
'JsPlatform/Extensions/motion_acceleration_y16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getAccelerationY");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getAccelerationY');
extension
extension
.addExpression(
"AccelerationZ",
_("Acceleration Z value"),
_("Get the devices acceleration on the Z-axis (m/s²)"),
_("Motion"),
"JsPlatform/Extensions/motion_acceleration_z16.png"
'AccelerationZ',
_('Acceleration Z value'),
_('Get the devices acceleration on the Z-axis (m/s²)'),
_('Motion'),
'JsPlatform/Extensions/motion_acceleration_z16.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/DeviceSensors/devicesensortools.js"
)
.setFunctionName("gdjs.deviceSensors.motion.getAccelerationZ");
.setIncludeFile('Extensions/DeviceSensors/devicesensortools.js')
.setFunctionName('gdjs.deviceSensors.motion.getAccelerationZ');
return extension;
},
runExtensionSanityTests: function(gd /*: libGDevelop */, extension /*: gdPlatformExtension*/) { return []; },
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -36,8 +28,9 @@ module.exports = {
)
.setExtensionHelpPath('/all-features/device-vibration')
.setCategory('User interface');
extension.addInstructionOrExpressionGroupMetadata(_("Device vibration"))
.setIcon("JsPlatform/Extensions/vibration_start32.png");
extension
.addInstructionOrExpressionGroupMetadata(_('Device vibration'))
.setIcon('JsPlatform/Extensions/vibration_start32.png');
extension
.addDependency()
@@ -99,10 +92,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -721,10 +713,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,28 +13,20 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension.setExtensionInformation(
'Effects',
'Effects',
'Lots of different effects to be used in your game.',
'Various contributors from PixiJS, PixiJS filters and GDevelop',
'MIT'
)
.setCategory('Visual effect')
.setExtensionHelpPath('/interface/scene-editor/layer-effects');
extension
.setExtensionInformation(
'Effects',
'Effects',
'Lots of different effects to be used in your game.',
'Various contributors from PixiJS, PixiJS filters and GDevelop',
'MIT'
)
.setCategory('Visual effect')
.setExtensionHelpPath('/interface/scene-editor/layer-effects');
// You can declare an effect here. Please order the effects by alphabetical order.
// This file is for common effects that are well-known/"battle-tested". If you have an
@@ -230,7 +223,11 @@ module.exports = {
const blurEffect = extension
.addEffect('Blur')
.setFullName(_('Blur (Gaussian, slow - prefer to use Kawase blur)'))
.setDescription(_('Blur the rendered image. This is slow, so prefer to use Kawase blur in most cases.'))
.setDescription(
_(
'Blur the rendered image. This is slow, so prefer to use Kawase blur in most cases.'
)
)
.markAsOnlyWorkingFor2D()
.addIncludeFile('Extensions/Effects/blur-pixi-filter.js');
const blurProperties = blurEffect.getProperties();
@@ -728,13 +725,11 @@ module.exports = {
const hslAdjustmentEffect = extension
.addEffect('HslAdjustment')
.setFullName(_('HSL Adjustment'))
.setDescription(
_(
'Adjust hue, saturation and lightness.'
)
)
.setDescription(_('Adjust hue, saturation and lightness.'))
.markAsOnlyWorkingFor2D()
.addIncludeFile('Extensions/Effects/pixi-filters/filter-hsl-adjustment.js')
.addIncludeFile(
'Extensions/Effects/pixi-filters/filter-hsl-adjustment.js'
)
.addIncludeFile('Extensions/Effects/hsl-adjustment-pixi-filter.js');
const hslAdjustmentProperties = hslAdjustmentEffect.getProperties();
hslAdjustmentProperties
@@ -767,7 +762,9 @@ module.exports = {
.addEffect('KawaseBlur')
.setFullName(_('Blur (Kawase, fast)'))
.setDescription(
_('Blur the rendered image, with much better performance than Gaussian blur.')
_(
'Blur the rendered image, with much better performance than Gaussian blur.'
)
)
.markAsOnlyWorkingFor2D()
.addIncludeFile('Extensions/Effects/pixi-filters/filter-kawase-blur.js')
@@ -816,9 +813,7 @@ module.exports = {
const motionBlurEffect = extension
.addEffect('MotionBlur')
.setFullName(_('Motion Blur'))
.setDescription(
_('Blur the rendered image to give a feeling of speed.')
)
.setDescription(_('Blur the rendered image to give a feeling of speed.'))
.markAsOnlyWorkingFor2D()
.addIncludeFile('Extensions/Effects/pixi-filters/filter-motion-blur.js')
.addIncludeFile('Extensions/Effects/motion-blur-pixi-filter.js');
@@ -1174,7 +1169,9 @@ module.exports = {
.setValue('0')
.setLabel(_('Elapsed time'))
.setType('number')
.setDescription('It can be set back to 0 to play the shockwave animation again.');
.setDescription(
'It can be set back to 0 to play the shockwave animation again.'
);
shockwaveEffectProperties
.getOrCreate('speed')
.setValue('500')
@@ -1311,10 +1308,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension.setExtensionInformation(
'MyDummyExtension',
@@ -446,10 +438,7 @@ module.exports = {
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
const dummyBehavior = extension
.getBehaviorMetadata('MyDummyExtension::DummyBehavior')
.get();
@@ -474,9 +463,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {
registerEditorConfigurations: function (objectsEditorService) {
objectsEditorService.registerEditorConfiguration(
'MyDummyExtension::DummyObject',
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
@@ -489,9 +476,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const PIXI = objectsRenderingService.PIXI;

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,368 +13,414 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function(_/*: (string) => string */, gd/*: libGDevelop */) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
"FacebookInstantGames",
_("Facebook Instant Games"),
'FacebookInstantGames',
_('Facebook Instant Games'),
_(
"Allow your game to send scores and interact with the Facebook Instant Games platform."
'Allow your game to send scores and interact with the Facebook Instant Games platform.'
),
"Florian Rival",
"Open source (MIT License)"
'Florian Rival',
'Open source (MIT License)'
)
.setExtensionHelpPath("/publishing/publishing-to-facebook-instant-games")
.setExtensionHelpPath('/publishing/publishing-to-facebook-instant-games')
.setCategory('Third-party');
extension.addInstructionOrExpressionGroupMetadata(_("Facebook Instant Games"))
.setIcon("JsPlatform/Extensions/facebookicon32.png");
extension
.addInstructionOrExpressionGroupMetadata(_('Facebook Instant Games'))
.setIcon('JsPlatform/Extensions/facebookicon32.png');
extension
.addAction(
"SavePlayerData",
_("Save player data"),
'SavePlayerData',
_('Save player data'),
_(
"Save the content of the given scene variable in the player data, stored on Facebook Instant Games servers"
'Save the content of the given scene variable in the player data, stored on Facebook Instant Games servers'
),
_(
"Save the content of _PARAM1_ in key _PARAM0_ of player data (store success message in _PARAM2_ or error in _PARAM3_)"
'Save the content of _PARAM1_ in key _PARAM0_ of player data (store success message in _PARAM2_ or error in _PARAM3_)'
),
_("Player data"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
_('Player data'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter("string", 'Data key name (e.g: "Lives")', "", false)
.addParameter("scenevar", "Scene variable with the content to save", "", false)
.addParameter('string', 'Data key name (e.g: "Lives")', '', false)
.addParameter(
"scenevar",
_("Variable where to store the success message (optional)"),
"",
true
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.setPlayerData");
extension
.addAction(
"LoadPlayerData",
_("Load player data"),
_("Load the player data with the given key in a variable"),
_(
"Load player data with key _PARAM0_ in _PARAM1_ (or error in _PARAM2_)"
),
_("Player data"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
)
.addParameter("string", _('Data key name (e.g: "Lives")'), "", false)
.addParameter(
"scenevar",
_("Variable where to store loaded data"),
"",
'scenevar',
'Scene variable with the content to save',
'',
false
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
'scenevar',
_('Variable where to store the success message (optional)'),
'',
true
)
.addParameter(
'scenevar',
_(
'Variable where to store the error message (optional, if an error occurs)'
),
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.loadPlayerData");
.setFunctionName('gdjs.evtTools.facebookInstantGames.setPlayerData');
extension
.addAction(
"SavePlayerScore",
_("Save player score"),
'LoadPlayerData',
_('Load player data'),
_('Load the player data with the given key in a variable'),
_(
"Save the score, and optionally the content of the given variable in the player score, for the given metadata."
'Load player data with key _PARAM0_ in _PARAM1_ (or error in _PARAM2_)'
),
_(
"In leaderboard _PARAM0_, save score _PARAM1_ for the player and extra data from _PARAM2_ (store success message in _PARAM3_ or error in _PARAM4_)"
),
_("Leaderboards"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
_('Player data'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter('string', _('Data key name (e.g: "Lives")'), '', false)
.addParameter(
'scenevar',
_('Variable where to store loaded data'),
'',
false
)
.addParameter(
"string",
'scenevar',
_(
'Variable where to store the error message (optional, if an error occurs)'
),
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName('gdjs.evtTools.facebookInstantGames.loadPlayerData');
extension
.addAction(
'SavePlayerScore',
_('Save player score'),
_(
'Save the score, and optionally the content of the given variable in the player score, for the given metadata.'
),
_(
'In leaderboard _PARAM0_, save score _PARAM1_ for the player and extra data from _PARAM2_ (store success message in _PARAM3_ or error in _PARAM4_)'
),
_('Leaderboards'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter(
'string',
'Leaderboard name (e.g: "PlayersBestTimes")',
"",
'',
false
)
.addParameter("expression", "Score to register for the player", "", false)
.addParameter('expression', 'Score to register for the player', '', false)
.addParameter(
"scenevar",
_("Optional variable with metadata to save"),
"",
'scenevar',
_('Optional variable with metadata to save'),
'',
true
)
.addParameter(
"scenevar",
_("Variable where to store the success message (optional)"),
"",
'scenevar',
_('Variable where to store the success message (optional)'),
'',
true
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.setPlayerScore");
extension
.addAction(
"LoadPlayerEntry",
_("Load player entry"),
_("Load the player entry in the given leaderboard"),
'scenevar',
_(
"Load player entry from leaderboard _PARAM0_. Set rank in _PARAM1_, score in _PARAM2_ (extra data if any in _PARAM3_ and error in _PARAM4_)"
'Variable where to store the error message (optional, if an error occurs)'
),
_("Leaderboards"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName('gdjs.evtTools.facebookInstantGames.setPlayerScore');
extension
.addAction(
'LoadPlayerEntry',
_('Load player entry'),
_('Load the player entry in the given leaderboard'),
_(
'Load player entry from leaderboard _PARAM0_. Set rank in _PARAM1_, score in _PARAM2_ (extra data if any in _PARAM3_ and error in _PARAM4_)'
),
_('Leaderboards'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter(
"string",
'string',
_('Leaderboard name (e.g: "PlayersBestTimes")'),
"",
'',
false
)
.addParameter(
"scenevar",
_("Variable where to store the player rank (of -1 if not ranked)"),
"",
'scenevar',
_('Variable where to store the player rank (of -1 if not ranked)'),
'',
true
)
.addParameter(
"scenevar",
_("Variable where to store the player score (of -1 if no score)"),
"",
'scenevar',
_('Variable where to store the player score (of -1 if no score)'),
'',
true
)
.addParameter(
"scenevar",
_("Variable where to store extra data (if any)"),
"",
'scenevar',
_('Variable where to store extra data (if any)'),
'',
true
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
'scenevar',
_(
'Variable where to store the error message (optional, if an error occurs)'
),
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.getPlayerEntry");
.setFunctionName('gdjs.evtTools.facebookInstantGames.getPlayerEntry');
extension
.addCondition(
"AreAdsSupported",
_("Check if ads are supported"),
_("Check if showing ads is supported on this device (only mobile phones can show ads)"),
_("Ads can be shown on this device"),
_("Ads"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'AreAdsSupported',
_('Check if ads are supported'),
_(
'Check if showing ads is supported on this device (only mobile phones can show ads)'
),
_('Ads can be shown on this device'),
_('Ads'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.areAdsSupported");
.setFunctionName('gdjs.evtTools.facebookInstantGames.areAdsSupported');
extension
.addCondition(
"IsInterstitialAdReady",
_("Is the interstitial ad ready"),
_("Check if the interstitial ad requested from Facebook is loaded and ready to be shown."),
_("The interstitial ad is loaded and ready to be shown"),
_("Ads"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'IsInterstitialAdReady',
_('Is the interstitial ad ready'),
_(
'Check if the interstitial ad requested from Facebook is loaded and ready to be shown.'
),
_('The interstitial ad is loaded and ready to be shown'),
_('Ads'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.isInterstitialAdReady");
.setFunctionName(
'gdjs.evtTools.facebookInstantGames.isInterstitialAdReady'
);
extension
.addAction(
"LoadInterstitialAd",
_("Load and prepare an interstitial ad"),
_("Request and load an interstitial ad from Facebook, so that it is ready to be shown."),
_("Request and load an interstitial ad from Facebook (ad placement id: _PARAM0_, error in _PARAM1_)"),
_("Ads"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'LoadInterstitialAd',
_('Load and prepare an interstitial ad'),
_(
'Request and load an interstitial ad from Facebook, so that it is ready to be shown.'
),
_(
'Request and load an interstitial ad from Facebook (ad placement id: _PARAM0_, error in _PARAM1_)'
),
_('Ads'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter(
"string",
_("The Ad Placement id (can be found while setting up the ad on Facebook)"),
"",
'string',
_(
'The Ad Placement id (can be found while setting up the ad on Facebook)'
),
'',
false
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
'scenevar',
_(
'Variable where to store the error message (optional, if an error occurs)'
),
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.loadInterstitialAd");
.setFunctionName('gdjs.evtTools.facebookInstantGames.loadInterstitialAd');
extension
.addAction(
"ShowInterstitialAd",
_("Show the loaded interstitial ad"),
_("Show the interstitial ad previously loaded in memory. This won't work if you did not load the interstitial before."),
_("Show the interstitial ad previously loaded in memory (if any error, store it in _PARAM0_)"),
_("Ads"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'ShowInterstitialAd',
_('Show the loaded interstitial ad'),
_(
"Show the interstitial ad previously loaded in memory. This won't work if you did not load the interstitial before."
),
_(
'Show the interstitial ad previously loaded in memory (if any error, store it in _PARAM0_)'
),
_('Ads'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
'scenevar',
_(
'Variable where to store the error message (optional, if an error occurs)'
),
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.showInterstitialAd");
.setFunctionName('gdjs.evtTools.facebookInstantGames.showInterstitialAd');
extension
.addCondition(
"IsRewardedVideoReady",
_("Is the rewarded video ready"),
_("Check if the rewarded video requested from Facebook is loaded and ready to be shown."),
_("The rewarded video is loaded and ready to be shown"),
_("Ads"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'IsRewardedVideoReady',
_('Is the rewarded video ready'),
_(
'Check if the rewarded video requested from Facebook is loaded and ready to be shown.'
),
_('The rewarded video is loaded and ready to be shown'),
_('Ads'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.isRewardedVideoReady");
.setFunctionName(
'gdjs.evtTools.facebookInstantGames.isRewardedVideoReady'
);
extension
.addAction(
"LoadRewardedVideo",
_("Load and prepare a rewarded video"),
_("Request and load a rewarded video from Facebook, so that it is ready to be shown."),
_("Request and load a rewarded video from Facebook (ad placement id: _PARAM0_, error in _PARAM1_)"),
_("Ads"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'LoadRewardedVideo',
_('Load and prepare a rewarded video'),
_(
'Request and load a rewarded video from Facebook, so that it is ready to be shown.'
),
_(
'Request and load a rewarded video from Facebook (ad placement id: _PARAM0_, error in _PARAM1_)'
),
_('Ads'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter(
"string",
_("The Ad Placement id (can be found while setting up the ad on Facebook)"),
"",
'string',
_(
'The Ad Placement id (can be found while setting up the ad on Facebook)'
),
'',
false
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
'scenevar',
_(
'Variable where to store the error message (optional, if an error occurs)'
),
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.loadRewardedVideo");
.setFunctionName('gdjs.evtTools.facebookInstantGames.loadRewardedVideo');
extension
.addAction(
"ShowRewardedVideo",
_("Show the loaded rewarded video"),
_("Show the rewarded video previously loaded in memory. This won't work if you did not load the video before."),
_("Show the rewarded video previously loaded in memory (if any error, store it in _PARAM0_)"),
_("Ads"),
"JsPlatform/Extensions/facebookicon32.png",
"JsPlatform/Extensions/facebookicon32.png"
'ShowRewardedVideo',
_('Show the loaded rewarded video'),
_(
"Show the rewarded video previously loaded in memory. This won't work if you did not load the video before."
),
_(
'Show the rewarded video previously loaded in memory (if any error, store it in _PARAM0_)'
),
_('Ads'),
'JsPlatform/Extensions/facebookicon32.png',
'JsPlatform/Extensions/facebookicon32.png'
)
.addParameter(
"scenevar",
_("Variable where to store the error message (optional, if an error occurs)"),
"",
'scenevar',
_(
'Variable where to store the error message (optional, if an error occurs)'
),
'',
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.showRewardedVideo");
.setFunctionName('gdjs.evtTools.facebookInstantGames.showRewardedVideo');
extension
.addStrExpression(
"PlayerId",
_("Player identifier"),
_("Get the player unique identifier"),
'PlayerId',
_('Player identifier'),
_('Get the player unique identifier'),
'',
"JsPlatform/Extensions/facebookicon32.png"
'JsPlatform/Extensions/facebookicon32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.getPlayerId");
.setFunctionName('gdjs.evtTools.facebookInstantGames.getPlayerId');
extension
.addStrExpression(
"PlayerName",
_("Player name"),
_("Get the player name"),
'PlayerName',
_('Player name'),
_('Get the player name'),
'',
"JsPlatform/Extensions/facebookicon32.png"
'JsPlatform/Extensions/facebookicon32.png'
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
'Extensions/FacebookInstantGames/facebookinstantgamestools.js'
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.getPlayerName");
.setFunctionName('gdjs.evtTools.facebookInstantGames.getPlayerName');
return extension;
},
runExtensionSanityTests: function(gd /*: libGDevelop */, extension /*: gdPlatformExtension*/) {
runExtensionSanityTests: function (gd, extension) {
return [];
}
},
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -11,11 +12,10 @@
*
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
@@ -2314,10 +2314,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension */
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

66
Extensions/JsExtensionTypes.d.ts vendored Normal file
View File

@@ -0,0 +1,66 @@
declare type GDNamespace = typeof import('../GDevelop.js/types');
declare type ObjectsRenderingService = {
gd: GDNamespace;
PIXI: typeof import('../newIDE/app/node_modules/pixi.js');
THREE: typeof import('../newIDE/app/node_modules/three');
THREE_ADDONS: { SkeletonUtils: any };
RenderedInstance: any;
Rendered3DInstance: any;
registerInstanceRenderer: (objectType: string, renderer: any) => void;
registerInstance3DRenderer: (objectType: string, renderer: any) => void;
requireModule: (dirname: string, moduleName: string) => any;
getThumbnail: (
project: gd.Project,
objectConfiguration: gd.ObjectConfiguration
) => string;
rgbOrHexToHexNumber: (value: string) => number;
registerClearCache: (clearCache: (_: any) => void) => void;
};
declare type ObjectsEditorService = {
registerEditorConfiguration: (
objectType: string,
editorConfiguration: any
) => void;
getDefaultObjectJsImplementationPropertiesEditor: ({
helpPagePath: string,
}) => any;
};
declare type ExtensionModule = {
createExtension: (
_: (string) => string,
gd: GDNamespace
) => gd.PlatformExtension;
/**
* You can optionally add sanity tests that will check the basic working
* of your extension behaviors/objects by instantiating behaviors/objects
* and setting the property to a given value.
*
* If you don't have any tests, you can simply return an empty array.
*
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: (
gd: GDNamespace,
extension: gd.PlatformExtension
) => string[];
/**
* Register editors for objects.
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations?: (
objectsEditorService: ObjectsEditorService
) => void;
/**
* Register renderers for instance of objects on the scene editor.
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers?: (
objectsRenderingService: ObjectsRenderingService
) => void;
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -96,7 +88,9 @@ module.exports = {
.setIncludeFile('Extensions/Leaderboards/sha256.js')
.addIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
.setFunctionName('gdjs.evtTools.leaderboards.saveConnectedPlayerScore')
.setAsyncFunctionName('gdjs.evtTools.leaderboards.saveConnectedPlayerScore');
.setAsyncFunctionName(
'gdjs.evtTools.leaderboards.saveConnectedPlayerScore'
);
extension
.addCondition(
@@ -299,10 +293,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,29 +13,21 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension.setExtensionInformation(
'Lighting',
_('Lights'),
extension
.setExtensionInformation(
'Lighting',
_('Lights'),
'This provides a light object, and a behavior to mark other objects as being obstacles for the lights. This is a great way to create a special atmosphere to your game, along with effects, make it more realistic or to create gameplays based on lights.',
'Harsimran Virk',
'MIT'
)
.setCategory('Visual effect')
.setTags("light");
'This provides a light object, and a behavior to mark other objects as being obstacles for the lights. This is a great way to create a special atmosphere to your game, along with effects, make it more realistic or to create gameplays based on lights.',
'Harsimran Virk',
'MIT'
)
.setCategory('Visual effect')
.setTags('light');
const lightObstacleBehavior = new gd.BehaviorJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
@@ -233,16 +226,11 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {
registerEditorConfigurations: function (objectsEditorService) {
objectsEditorService.registerEditorConfiguration(
'Lighting::LightObject',
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
@@ -255,9 +243,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const PIXI = objectsRenderingService.PIXI;
@@ -296,19 +282,21 @@ module.exports = {
);
// The icon in the middle.
const lightIconSprite = new PIXI.Sprite(PIXI.Texture.from('CppPlatform/Extensions/lightIcon32.png'));
const lightIconSprite = new PIXI.Sprite(
PIXI.Texture.from('CppPlatform/Extensions/lightIcon32.png')
);
lightIconSprite.anchor.x = 0.5;
lightIconSprite.anchor.y = 0.5;
// The circle to show the radius of the light.
const radiusBorderWidth = 2;
const radiusGraphics = new PIXI.Graphics();
radiusGraphics.lineStyle(
radiusBorderWidth,
color,
0.8
radiusGraphics.lineStyle(radiusBorderWidth, color, 0.8);
radiusGraphics.drawCircle(
0,
0,
Math.max(1, this._radius - radiusBorderWidth)
);
radiusGraphics.drawCircle(0, 0, Math.max(1, this._radius - radiusBorderWidth));
this._pixiObject = new PIXI.Container();
this._pixiObject.addChild(lightIconSprite);
@@ -326,11 +314,7 @@ module.exports = {
/**
* Return the path to the thumbnail of the specified object.
*/
static getThumbnail(
project,
resourcesLoader,
objectConfiguration
) {
static getThumbnail(project, resourcesLoader, objectConfiguration) {
return 'CppPlatform/Extensions/lightIcon32.png';
}

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension /*: gdPlatformExtension */ = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -474,10 +466,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -35,7 +27,7 @@ module.exports = {
)
.setExtensionHelpPath('/behaviors/physics2')
.setCategory('Movement')
.setTags("physics, gravity, obstacle, collision");
.setTags('physics, gravity, obstacle, collision');
extension
.addInstructionOrExpressionGroupMetadata(_('Physics Engine 2.0'))
.setIcon('res/physics32.png');
@@ -775,10 +767,10 @@ module.exports = {
.setDefaultValue('true')
.getCodeExtraInformation()
.setFunctionName('setSleepingAllowed');
// Deprecated action (fixed typo):
aut
.addDuplicatedAction("SetSleepingaAllowed", "SetSleepingAllowed")
.addDuplicatedAction('SetSleepingaAllowed', 'SetSleepingAllowed')
.setHidden();
aut
@@ -1476,10 +1468,16 @@ module.exports = {
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('X component (N)'))
.addParameter('expression', _('Y component (N)'))
.setParameterLongDescription(_('A force is like an acceleration but depends on the mass.'))
.setParameterLongDescription(
_('A force is like an acceleration but depends on the mass.')
)
.addParameter('expression', _('Application point on X axis'))
.addParameter('expression', _('Application point on Y axis'))
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
.setParameterLongDescription(
_(
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyForce');
@@ -1499,10 +1497,16 @@ module.exports = {
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Angle'))
.addParameter('expression', _('Length (N)'))
.setParameterLongDescription(_('A force is like an acceleration but depends on the mass.'))
.setParameterLongDescription(
_('A force is like an acceleration but depends on the mass.')
)
.addParameter('expression', _('Application point on X axis'))
.addParameter('expression', _('Application point on Y axis'))
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
.setParameterLongDescription(
_(
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyPolarForce');
@@ -1523,12 +1527,18 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Length (N)'))
.setParameterLongDescription(_('A force is like an acceleration but depends on the mass.'))
.setParameterLongDescription(
_('A force is like an acceleration but depends on the mass.')
)
.addParameter('expression', _('X position'))
.addParameter('expression', _('Y position'))
.addParameter('expression', _('Application point on X axis'))
.addParameter('expression', _('Application point on Y axis'))
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
.setParameterLongDescription(
_(
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyForceTowardPosition');
@@ -1546,18 +1556,18 @@ module.exports = {
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter(
'expression',
_('X component (N·s or kg·m·s⁻¹)')
.addParameter('expression', _('X component (N·s or kg·m·s⁻¹)'))
.addParameter('expression', _('Y component (N·s or kg·m·s⁻¹)'))
.setParameterLongDescription(
_('An impulse is like a speed addition but depends on the mass.')
)
.addParameter(
'expression',
_('Y component (N·s or kg·m·s⁻¹)')
)
.setParameterLongDescription(_('An impulse is like a speed addition but depends on the mass.'))
.addParameter('expression', _('Application point on X axis'))
.addParameter('expression', _('Application point on Y axis'))
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
.setParameterLongDescription(
_(
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyImpulse');
@@ -1578,14 +1588,17 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Angle'))
.addParameter(
'expression',
_('Length (N·s or kg·m·s⁻¹)')
.addParameter('expression', _('Length (N·s or kg·m·s⁻¹)'))
.setParameterLongDescription(
_('An impulse is like a speed addition but depends on the mass.')
)
.setParameterLongDescription(_('An impulse is like a speed addition but depends on the mass.'))
.addParameter('expression', _('Application point on X axis'))
.addParameter('expression', _('Application point on Y axis'))
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
.setParameterLongDescription(
_(
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyPolarImpulse');
@@ -1605,16 +1618,19 @@ module.exports = {
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter(
'expression',
_('Length (N·s or kg·m·s⁻¹)')
.addParameter('expression', _('Length (N·s or kg·m·s⁻¹)'))
.setParameterLongDescription(
_('An impulse is like a speed addition but depends on the mass.')
)
.setParameterLongDescription(_('An impulse is like a speed addition but depends on the mass.'))
.addParameter('expression', _('X position'))
.addParameter('expression', _('Y position'))
.addParameter('expression', _('Application point on X axis'))
.addParameter('expression', _('Application point on Y axis'))
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
.setParameterLongDescription(
_(
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyImpulseTowardPosition');
@@ -1633,7 +1649,9 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Torque (N·m)'))
.setParameterLongDescription(_('A torque is like a rotation acceleration but depends on the mass.'))
.setParameterLongDescription(
_('A torque is like a rotation acceleration but depends on the mass.')
)
.getCodeExtraInformation()
.setFunctionName('applyTorque');
@@ -1652,7 +1670,11 @@ module.exports = {
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
.addParameter('expression', _('Angular impulse (N·m·s'))
.setParameterLongDescription(_('An impulse is like a rotation speed addition but depends on the mass.'))
.setParameterLongDescription(
_(
'An impulse is like a rotation speed addition but depends on the mass.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyAngularImpulse');
@@ -4061,10 +4083,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
const dummyBehavior = extension
.getBehaviorMetadata('Physics2::Physics2Behavior')
.get();

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -72,9 +64,7 @@ module.exports = {
.addAction(
'HideAuthenticationBanner',
_('Hide authentication banner'),
_(
'Hide the authentication banner from the top of the game screen.'
),
_('Hide the authentication banner from the top of the game screen.'),
_('Hide the authentication banner'),
'',
'JsPlatform/Extensions/authentication.svg',
@@ -169,6 +159,23 @@ module.exports = {
)
.setFunctionName('gdjs.playerAuthentication.getUsername');
extension
.addStrExpression(
'UserID',
_('User ID'),
_('Get the unique user ID of the authenticated player.'),
'',
'JsPlatform/Extensions/authentication.svg'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.setFunctionName('gdjs.playerAuthentication.getUserId');
extension
.addCondition(
'IsPlayerAuthenticated',
@@ -209,10 +216,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -171,7 +171,7 @@ namespace gdjs {
if (!_checkedLocalStorage) {
readAuthenticatedUserFromLocalStorage();
}
return _userId || null;
return _userId || '';
};
/**

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -59,10 +51,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -83,10 +75,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -1243,10 +1235,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,18 +13,9 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -288,7 +280,7 @@ module.exports = {
.addIncludeFile(
'Extensions/TextInput/textinputruntimeobject-pixi-renderer.js'
)
.addDefaultBehavior("TextContainerCapability::TextContainerBehavior")
.addDefaultBehavior('TextContainerCapability::TextContainerBehavior')
.addDefaultBehavior('ResizableCapability::ResizableBehavior')
.addDefaultBehavior('OpacityCapability::OpacityBehavior');
@@ -585,7 +577,9 @@ module.exports = {
.addScopedAction(
'Focus',
_('Focus'),
_('Focus the input so that text can be entered (like if it was touched/clicked).'),
_(
'Focus the input so that text can be entered (like if it was touched/clicked).'
),
_('Focus _PARAM0_'),
_(''),
'res/conditions/surObjet24.png',
@@ -607,10 +601,7 @@ module.exports = {
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
/**
@@ -618,9 +609,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {
registerEditorConfigurations: function (objectsEditorService) {
objectsEditorService.registerEditorConfiguration(
'TextInput::TextInputObject',
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
@@ -633,9 +622,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const PIXI = objectsRenderingService.PIXI;

View File

@@ -1,5 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/// <reference path="helper/TileMapHelper.d.ts" />
/**
@@ -15,18 +15,8 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
const defineTileMap = function (
extension,
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
/** @type {ExtensionModule} */
const defineTileMap = function (extension, _, gd) {
var objectTileMap = new gd.ObjectJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating an object
objectTileMap.updateProperty = function (
@@ -1093,10 +1083,7 @@ module.exports = {
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
/**
@@ -1104,9 +1091,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {
registerEditorConfigurations: function (objectsEditorService) {
objectsEditorService.registerEditorConfiguration(
'TileMap::TileMap',
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
@@ -1125,9 +1110,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const PIXI = objectsRenderingService.PIXI;
@@ -1357,14 +1340,14 @@ module.exports = {
async _loadTileMap(tilemapJsonFile, tilesetJsonFile) {
try {
const tileMapJsonData =
await this._pixiResourcesLoader.getResourceJsonData(
this._project,
tilemapJsonFile
);
const tileMapJsonData = await this._pixiResourcesLoader.getResourceJsonData(
this._project,
tilemapJsonFile
);
const tileMap =
TilemapHelper.TileMapManager.identify(tileMapJsonData);
const tileMap = TilemapHelper.TileMapManager.identify(
tileMapJsonData
);
if (tileMap.kind === 'tiled') {
const tilesetJsonData = tilesetJsonFile
@@ -1601,14 +1584,14 @@ module.exports = {
async _loadTileMap(tilemapJsonFile, tilesetJsonFile) {
try {
const tileMapJsonData =
await this._pixiResourcesLoader.getResourceJsonData(
this._project,
tilemapJsonFile
);
const tileMapJsonData = await this._pixiResourcesLoader.getResourceJsonData(
this._project,
tilemapJsonFile
);
const tileMap =
TilemapHelper.TileMapManager.identify(tileMapJsonData);
const tileMap = TilemapHelper.TileMapManager.identify(
tileMapJsonData
);
if (tileMap.kind === 'tiled') {
const tilesetJsonData = tilesetJsonFile

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,13 +13,6 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
const easingChoices = JSON.stringify([
'linear',
'easeInQuad',
@@ -57,11 +51,9 @@ const easingChoices = JSON.stringify([
'easeTo',
]);
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -387,57 +379,61 @@ module.exports = {
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
.setFunctionName('gdjs.evtTools.tween.tweenCameraRotation2');
extension
.addAction(
'TweenNumberEffectPropertyTween',
_('Tween number effect property'),
_('Tweens a number effect property from its current value to a new one.'),
_(
'Tween the property _PARAM5_ for effect _PARAM4_ of _PARAM3_ to _PARAM2_ with easing _PARAM6_ over _PARAM7_ seconds as _PARAM1_'
),
_('Scene Tweens'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addCodeOnlyParameter('currentScene', '')
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
.addParameter('expression', _('To value'), '', false)
.addParameter('layer', _('Layer'), '', true)
.addParameter("layerEffectName", _("Effect name"))
.addParameter("layerEffectParameterName", _("Property name"))
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/TweenBehavior/TweenManager.js')
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
.setFunctionName('gdjs.evtTools.tween.tweenNumberEffectPropertyTween');
extension
.addAction(
'TweenColorEffectPropertyTween',
_('Tween color effect property'),
_('Tweens a color effect property from its current value to a new one.'),
_(
'Tween the color property _PARAM5_ for effect _PARAM4_ of _PARAM3_ to _PARAM2_ with easing _PARAM6_ over _PARAM7_ seconds as _PARAM1_'
),
_('Scene Tweens'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addCodeOnlyParameter('currentScene', '')
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
.addParameter('color', _('To color'), '', false)
.addParameter('layer', _('Layer'), '', true)
.addParameter("layerEffectName", _("Effect name"))
.addParameter("layerEffectParameterName", _("Property name"))
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/TweenBehavior/TweenManager.js')
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
.setFunctionName('gdjs.evtTools.tween.tweenColorEffectPropertyTween');
extension
.addAction(
'TweenNumberEffectPropertyTween',
_('Tween number effect property'),
_(
'Tweens a number effect property from its current value to a new one.'
),
_(
'Tween the property _PARAM5_ for effect _PARAM4_ of _PARAM3_ to _PARAM2_ with easing _PARAM6_ over _PARAM7_ seconds as _PARAM1_'
),
_('Scene Tweens'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addCodeOnlyParameter('currentScene', '')
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
.addParameter('expression', _('To value'), '', false)
.addParameter('layer', _('Layer'), '', true)
.addParameter('layerEffectName', _('Effect name'))
.addParameter('layerEffectParameterName', _('Property name'))
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/TweenBehavior/TweenManager.js')
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
.setFunctionName('gdjs.evtTools.tween.tweenNumberEffectPropertyTween');
extension
.addAction(
'TweenColorEffectPropertyTween',
_('Tween color effect property'),
_(
'Tweens a color effect property from its current value to a new one.'
),
_(
'Tween the color property _PARAM5_ for effect _PARAM4_ of _PARAM3_ to _PARAM2_ with easing _PARAM6_ over _PARAM7_ seconds as _PARAM1_'
),
_('Scene Tweens'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addCodeOnlyParameter('currentScene', '')
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
.addParameter('color', _('To color'), '', false)
.addParameter('layer', _('Layer'), '', true)
.addParameter('layerEffectName', _('Effect name'))
.addParameter('layerEffectParameterName', _('Property name'))
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/TweenBehavior/TweenManager.js')
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
.setFunctionName('gdjs.evtTools.tween.tweenColorEffectPropertyTween');
extension
.addCondition(
@@ -893,7 +889,7 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('addObjectPositionXTween2');
// deprecated use the 3D Tween extension
// deprecated
behavior
.addAction(
'AddObjectPositionZTween',
@@ -926,6 +922,38 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('addObjectPositionZTween');
behavior
.addAction(
'AddObjectPositionZTween2',
_('Tween object Z position'),
_(
'Tweens an object Z position (3D objects only) from its current Z position to a new one.'
),
_(
'Tween the Z position of _PARAM0_ to _PARAM4_ with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Position'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter('behavior', _('3D capability'), 'Scene3D::Base3DBehavior')
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To Z'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectPositionZTween2');
// deprecated
behavior
.addAction(
@@ -1079,6 +1107,38 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('addObjectDepthTween');
behavior
.addAction(
'AddObjectDepthTween2',
_('Tween object depth'),
_(
'Tweens an object depth (suitable 3D objects only) from its current depth to a new one.'
),
_(
'Tween the depth of _PARAM0_ to _PARAM4_ with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Size'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter('behavior', _('3D capability'), 'Scene3D::Base3DBehavior')
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To depth'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectDepthTween2');
// deprecated
behavior
.addAction(
@@ -1203,6 +1263,70 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('addObjectAngleTween2');
behavior
.addScopedAction(
'AddObjectRotationXTween',
_('Tween object rotation on X axis'),
_(
'Tweens an object rotation on X axis from its current angle to a new one.'
),
_(
'Tween the rotation on X axis of _PARAM0_ to _PARAM4_° with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Angle'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter('behavior', _('3D capability'), 'Scene3D::Base3DBehavior')
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To angle (in degrees)'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectRotationXTween');
behavior
.addScopedAction(
'AddObjectRotationYTween',
_('Tween object rotation on Y axis'),
_(
'Tweens an object rotation on Y axis from its current angle to a new one.'
),
_(
'Tween the rotation on Y axis of _PARAM0_ to _PARAM4_° with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Angle'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter('behavior', _('3D capability'), 'Scene3D::Base3DBehavior')
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To angle (in degrees)'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectRotationYTween');
// deprecated
behavior
.addAction(
@@ -1239,6 +1363,7 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('addObjectScaleTween');
// deprecated
behavior
.addScopedAction(
'AddObjectScaleTween2',
@@ -1253,6 +1378,7 @@ module.exports = {
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.setHidden()
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
@@ -1273,6 +1399,39 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('addObjectScaleTween2');
behavior
.addScopedAction(
'AddObjectScaleTween3',
_('Tween object scale'),
_(
'Tweens an object scale from its current value to a new one (note: the scale can never be 0 or less).'
),
_(
'Tween the scale of _PARAM0_ to _PARAM3_ (from center: _PARAM7_) with easing _PARAM4_ over _PARAM5_ seconds as _PARAM2_'
),
_('Size'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To scale'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.addParameter('yesorno', _('Scale from center of object'), '', false)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectScaleTween3');
// deprecated
behavior
.addAction(
@@ -1541,7 +1700,9 @@ module.exports = {
.addScopedAction(
'AddNumberEffectPropertyTween',
_('Tween number effect property'),
_('Tweens a number effect property from its current value to a new one.'),
_(
'Tweens a number effect property from its current value to a new one.'
),
_(
'Tween the property _PARAM6_ for effect _PARAM5_ of _PARAM0_ to _PARAM4_ with easing _PARAM7_ over _PARAM8_ seconds as _PARAM3_'
),
@@ -1551,11 +1712,15 @@ module.exports = {
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter("behavior", _("Effect capability"), "EffectCapability::EffectBehavior")
.addParameter(
'behavior',
_('Effect capability'),
'EffectCapability::EffectBehavior'
)
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To value'), '', false)
.addParameter("objectEffectName", _("Effect name"))
.addParameter("objectEffectParameterName", _("Property name"))
.addParameter('objectEffectName', _('Effect name'))
.addParameter('objectEffectParameterName', _('Property name'))
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
@@ -1573,7 +1738,9 @@ module.exports = {
.addScopedAction(
'AddColorEffectPropertyTween',
_('Tween color effect property'),
_('Tweens a color effect property from its current value to a new one.'),
_(
'Tweens a color effect property from its current value to a new one.'
),
_(
'Tween the color property _PARAM6_ for effect _PARAM5_ of _PARAM0_ to _PARAM4_ with easing _PARAM7_ over _PARAM8_ seconds as _PARAM3_'
),
@@ -1583,11 +1750,15 @@ module.exports = {
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter("behavior", _("Effect capability"), "EffectCapability::EffectBehavior")
.addParameter(
'behavior',
_('Effect capability'),
'EffectCapability::EffectBehavior'
)
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('color', _('To color'), '', false)
.addParameter("objectEffectName", _("Effect name"))
.addParameter("objectEffectParameterName", _("Property name"))
.addParameter('objectEffectName', _('Effect name'))
.addParameter('objectEffectParameterName', _('Property name'))
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
@@ -1929,10 +2100,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
};

View File

@@ -10,210 +10,256 @@ describe('gdjs.TweenRuntimeBehavior', () => {
};
/** @type {gdjs.RuntimeScene} */
let layout;
let runtimeScene;
/** @type {gdjs.TweenRuntimeBehavior} */
beforeEach(() => {
layout = createScene();
layout.getLayer('').setTimeScale(1.5);
runtimeScene = createScene();
runtimeScene.getLayer('').setTimeScale(1.5);
});
const tween = gdjs.evtTools.tween;
const camera = gdjs.evtTools.camera;
it("can get default values for tweens that don't exist", () => {
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(false);
expect(tween.getValue(layout, 'MyTween')).to.be(0);
expect(tween.getProgress(layout, 'MyTween')).to.be(0);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(false);
expect(tween.getValue(runtimeScene, 'MyTween')).to.be(0);
expect(tween.getProgress(runtimeScene, 'MyTween')).to.be(0);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
});
it('can play a tween till the end', () => {
camera.setCameraRotation(layout, 200, '', 0);
tween.tweenCameraRotation2(layout, 'MyTween', 600, '', 'linear', 0.25);
camera.setCameraRotation(runtimeScene, 200, '', 0);
tween.tweenCameraRotation2(
runtimeScene,
'MyTween',
600,
'',
'linear',
0.25
);
// Tween actions don't change the value directly.
expect(camera.getCameraRotation(layout, '', 0)).to.be(200);
expect(tween.getValue(layout, 'MyTween')).to.be(200);
expect(tween.getProgress(layout, 'MyTween')).to.be(0);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(200);
expect(tween.getValue(runtimeScene, 'MyTween')).to.be(200);
expect(tween.getProgress(runtimeScene, 'MyTween')).to.be(0);
let oldAngle;
let oldValue;
let oldProgress;
for (let i = 0; i < 10; i++) {
oldAngle = camera.getCameraRotation(layout, '', 0);
oldValue = tween.getValue(layout, 'MyTween');
oldProgress = tween.getProgress(layout, 'MyTween');
oldAngle = camera.getCameraRotation(runtimeScene, '', 0);
oldValue = tween.getValue(runtimeScene, 'MyTween');
oldProgress = tween.getProgress(runtimeScene, 'MyTween');
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(layout, '', 0)).to.be.above(oldAngle);
expect(tween.getValue(layout, 'MyTween')).to.be.above(oldValue);
expect(tween.getProgress(layout, 'MyTween')).to.be.above(oldProgress);
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be.above(
oldAngle
);
expect(tween.getValue(runtimeScene, 'MyTween')).to.be.above(oldValue);
expect(tween.getProgress(runtimeScene, 'MyTween')).to.be.above(
oldProgress
);
}
// The tween reaches the end
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(layout, '', 0)).to.be(600);
expect(tween.getValue(layout, 'MyTween')).to.be(600);
expect(tween.getProgress(layout, 'MyTween')).to.be(1);
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(600);
expect(tween.getValue(runtimeScene, 'MyTween')).to.be(600);
expect(tween.getProgress(runtimeScene, 'MyTween')).to.be(1);
// The value is not changed after the tween is finished
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(layout, '', 0)).to.be(600);
expect(tween.getValue(layout, 'MyTween')).to.be(600);
expect(tween.getProgress(layout, 'MyTween')).to.be(1);
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(600);
expect(tween.getValue(runtimeScene, 'MyTween')).to.be(600);
expect(tween.getProgress(runtimeScene, 'MyTween')).to.be(1);
// The value is not set to the targeted value over and over
// after the tween is finished.
camera.setCameraRotation(layout, 123, '', 0);
layout.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
camera.setCameraRotation(runtimeScene, 123, '', 0);
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
});
it('can pause and resume a tween', () => {
camera.setCameraRotation(layout, 200, '', 0);
tween.tweenCameraRotation2(layout, 'MyTween', 600, '', 'linear', 0.25);
camera.setCameraRotation(runtimeScene, 200, '', 0);
tween.tweenCameraRotation2(
runtimeScene,
'MyTween',
600,
'',
'linear',
0.25
);
// The tween starts
for (let i = 0; i < 5; i++) {
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
}
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
// Pause the tween
tween.pauseSceneTween(layout, 'MyTween');
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
tween.pauseSceneTween(runtimeScene, 'MyTween');
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
for (let i = 0; i < 5; i++) {
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
}
// The value is not overridden during the pause.
camera.setCameraRotation(layout, 123, '', 0);
layout.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
camera.setCameraRotation(runtimeScene, 123, '', 0);
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
// Resume the tween
tween.resumeSceneTween(layout, 'MyTween');
tween.resumeSceneTween(runtimeScene, 'MyTween');
// Tween actions don't change the value directly.
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
layout.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(layout, '', 0)).to.be(440);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(440);
});
it('can stop and restart a tween', () => {
camera.setCameraRotation(layout, 200, '', 0);
camera.setCameraRotation(runtimeScene, 200, '', 0);
// Start the tween
tween.tweenCameraRotation2(layout, 'MyTween', 600, '', 'linear', 0.25);
tween.tweenCameraRotation2(
runtimeScene,
'MyTween',
600,
'',
'linear',
0.25
);
for (let i = 0; i < 5; i++) {
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
}
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
// Stop the tween
tween.stopSceneTween(layout, 'MyTween', false);
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
tween.stopSceneTween(runtimeScene, 'MyTween', false);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
for (let i = 0; i < 5; i++) {
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
}
// The value is not overridden by a stopped tween.
camera.setCameraRotation(layout, 123, '', 0);
layout.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
camera.setCameraRotation(runtimeScene, 123, '', 0);
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
// A stopped tween can't be resumed.
tween.resumeSceneTween(layout, 'MyTween');
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
tween.resumeSceneTween(runtimeScene, 'MyTween');
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
layout.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(true);
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(true);
// Restart the tween
tween.tweenCameraRotation2(layout, 'MyTween', 623, '', 'linear', 0.25);
tween.tweenCameraRotation2(
runtimeScene,
'MyTween',
623,
'',
'linear',
0.25
);
for (let i = 0; i < 5; i++) {
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
}
expect(camera.getCameraRotation(layout, '', 0)).to.be(373);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(373);
});
it('can remove and recreate a tween', () => {
camera.setCameraRotation(layout, 200, '', 0);
camera.setCameraRotation(runtimeScene, 200, '', 0);
// Start the tween
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(false);
tween.tweenCameraRotation2(layout, 'MyTween', 600, '', 'linear', 0.25);
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(false);
tween.tweenCameraRotation2(
runtimeScene,
'MyTween',
600,
'',
'linear',
0.25
);
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(true);
for (let i = 0; i < 5; i++) {
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
}
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
// Remove the tween
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(true);
tween.removeSceneTween(layout, 'MyTween');
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(true);
tween.removeSceneTween(runtimeScene, 'MyTween');
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
for (let i = 0; i < 5; i++) {
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
}
// The value is not overridden after the tween has been removed.
camera.setCameraRotation(layout, 123, '', 0);
layout.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
camera.setCameraRotation(runtimeScene, 123, '', 0);
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
// A removed tween can't be resumed.
tween.resumeSceneTween(layout, 'MyTween');
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
tween.resumeSceneTween(runtimeScene, 'MyTween');
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
layout.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
// Recreate the tween
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(false);
tween.tweenCameraRotation2(layout, 'MyTween', 623, '', 'linear', 0.25);
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(false);
tween.tweenCameraRotation2(
runtimeScene,
'MyTween',
623,
'',
'linear',
0.25
);
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(true);
for (let i = 0; i < 5; i++) {
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
}
expect(camera.getCameraRotation(layout, '', 0)).to.be(373);
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(373);
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(true);
});
const checkProgress = (steps, getValueFunctions) => {
@@ -222,7 +268,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
}
for (let i = 0; i < steps; i++) {
const oldValues = getValueFunctions.map((getValue) => getValue());
layout.renderAndStep(1000 / 60);
runtimeScene.renderAndStep(1000 / 60);
for (let index = 0; index < oldValues.length; index++) {
expect(getValueFunctions[index]()).not.to.be(oldValues[index]);
@@ -231,10 +277,10 @@ describe('gdjs.TweenRuntimeBehavior', () => {
};
it('can tween a scene variable', () => {
const variable = layout.getVariables().get('MyVariable');
const variable = runtimeScene.getVariables().get('MyVariable');
variable.setNumber(200);
tween.tweenVariableNumber3(
layout,
runtimeScene,
'MyTween',
variable,
600,
@@ -247,7 +293,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
it('can tween a layer value', () => {
tween.addLayerValueTween(
layout,
runtimeScene,
'MyTween',
200,
600,
@@ -256,13 +302,13 @@ describe('gdjs.TweenRuntimeBehavior', () => {
false,
''
);
checkProgress(6, () => tween.getValue(layout, 'MyTween'));
expect(tween.getValue(layout, 'MyTween')).to.be(440);
checkProgress(6, () => tween.getValue(runtimeScene, 'MyTween'));
expect(tween.getValue(runtimeScene, 'MyTween')).to.be(440);
});
it('can tween a layout value', () => {
tween.addLayoutValueTween(
layout,
runtimeScene,
'MyTween',
200,
600,
@@ -270,39 +316,69 @@ describe('gdjs.TweenRuntimeBehavior', () => {
0.25 / 1.5,
false
);
checkProgress(6, () => tween.getValue(layout, 'MyTween'));
expect(tween.getValue(layout, 'MyTween')).to.be(440);
checkProgress(6, () => tween.getValue(runtimeScene, 'MyTween'));
expect(tween.getValue(runtimeScene, 'MyTween')).to.be(440);
});
it('can tween a layer camera position', () => {
camera.setCameraX(layout, 200, '', 0);
camera.setCameraY(layout, 300, '', 0);
tween.tweenCamera2(layout, 'MyTween', 600, 900, '', 'linear', 0.25);
camera.setCameraX(runtimeScene, 200, '', 0);
camera.setCameraY(runtimeScene, 300, '', 0);
tween.tweenCamera2(runtimeScene, 'MyTween', 600, 900, '', 'linear', 0.25);
checkProgress(6, [
() => camera.getCameraX(layout, '', 0),
() => camera.getCameraY(layout, '', 0),
() => camera.getCameraX(runtimeScene, '', 0),
() => camera.getCameraY(runtimeScene, '', 0),
]);
expect(camera.getCameraX(layout, '', 0)).to.be(440);
expect(camera.getCameraY(layout, '', 0)).to.be(660);
expect(camera.getCameraX(runtimeScene, '', 0)).to.be(440);
expect(camera.getCameraY(runtimeScene, '', 0)).to.be(660);
});
it('can tween a layer camera zoom', () => {
camera.setCameraZoom(layout, 200, '', 0);
tween.tweenCameraZoom2(layout, 'MyTween', 600, '', 'linear', 0.25);
checkProgress(6, () => camera.getCameraZoom(layout, '', 0));
camera.setCameraZoom(runtimeScene, 200, '', 0);
tween.tweenCameraZoom2(runtimeScene, 'MyTween', 600, '', 'linear', 0.25);
checkProgress(6, () => camera.getCameraZoom(runtimeScene, '', 0));
// The interpolation is exponential.
expect(camera.getCameraZoom(layout, '', 0)).to.be(386.6364089863524);
expect(camera.getCameraZoom(runtimeScene, '', 0)).to.be(386.6364089863524);
});
it('can tween a layer camera zoom to 0', () => {
camera.setCameraZoom(runtimeScene, 1, '', 0);
tween.tweenCameraZoom2(runtimeScene, 'MyTween', 0, '', 'linear', 0.25);
// A camera zoom of 0 doesn't make sense.
// Check that there is no NaN.
for (let i = 0; i < 11; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraZoom(runtimeScene, '', 0)).to.be(0);
}
});
it('can tween a layer camera zoom from 0', () => {
camera.setCameraZoom(runtimeScene, 0, '', 0);
tween.tweenCameraZoom2(runtimeScene, 'MyTween', 1, '', 'linear', 0.25);
// A camera zoom of 0 doesn't make sense.
// Check that there is no NaN.
for (let i = 0; i < 11; i++) {
expect(camera.getCameraZoom(runtimeScene, '', 0)).to.be(0);
runtimeScene.renderAndStep(1000 / 60);
}
expect(camera.getCameraZoom(runtimeScene, '', 0)).to.be(1);
});
it('can tween a layer camera rotation', () => {
camera.setCameraRotation(layout, 200, '', 0);
tween.tweenCameraRotation2(layout, 'MyTween', 600, '', 'linear', 0.25);
checkProgress(6, () => camera.getCameraRotation(layout, '', 0));
expect(camera.getCameraRotation(layout, '', 0)).to.be(440);
camera.setCameraRotation(runtimeScene, 200, '', 0);
tween.tweenCameraRotation2(
runtimeScene,
'MyTween',
600,
'',
'linear',
0.25
);
checkProgress(6, () => camera.getCameraRotation(runtimeScene, '', 0));
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(440);
});
it('can tween a number effect property', () => {
const layer = layout.getLayer('');
const layer = runtimeScene.getLayer('');
layer.addEffect({
effectType: 'Outline',
name: 'MyEffect',
@@ -311,7 +387,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
booleanParameters: {},
});
tween.tweenNumberEffectPropertyTween(
layout,
runtimeScene,
'MyTween',
600,
'',
@@ -329,7 +405,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
});
it('can tween a color effect property', () => {
const layer = layout.getLayer('');
const layer = runtimeScene.getLayer('');
layer.addEffect({
effectType: 'Outline',
name: 'MyEffect',
@@ -338,7 +414,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
booleanParameters: {},
});
tween.tweenColorEffectPropertyTween(
layout,
runtimeScene,
'MyTween',
'255;192;128',
'',

View File

@@ -85,6 +85,32 @@ describe('gdjs.TweenRuntimeBehavior', () => {
return object;
};
/**
* @param {gdjs.RuntimeScene} runtimeScene
*/
const addCube = (runtimeScene) => {
const object = new gdjs.Cube3DRuntimeObject(runtimeScene, {
name: 'Cube',
type: 'Scene3D::Cube3DObject',
effects: [],
variables: [],
behaviors: [
{
type: 'Tween::TweenBehavior',
name: behaviorName,
},
],
// @ts-ignore
content: {
width: 64,
height: 64,
depth: 64,
},
});
runtimeScene.addObject(object);
return object;
};
/**
* @param {gdjs.RuntimeScene} runtimeScene
*/
@@ -123,6 +149,8 @@ describe('gdjs.TweenRuntimeBehavior', () => {
let object;
/** @type {gdjs.SpriteRuntimeObject} */
let sprite;
/** @type {gdjs.Cube3DRuntimeObject} */
let cube;
/** @type {gdjs.TextRuntimeObject} */
let textObject;
/** @type {gdjs.TweenRuntimeBehavior} */
@@ -130,18 +158,23 @@ describe('gdjs.TweenRuntimeBehavior', () => {
/** @type {gdjs.TweenRuntimeBehavior} */
let spriteBehavior;
/** @type {gdjs.TweenRuntimeBehavior} */
let cubeBehavior;
/** @type {gdjs.TweenRuntimeBehavior} */
let textObjectBehavior;
beforeEach(() => {
runtimeScene = createScene();
runtimeScene.getLayer('').setTimeScale(1.5);
object = addObject(runtimeScene);
sprite = addSprite(runtimeScene);
cube = addCube(runtimeScene);
textObject = addTextObject(runtimeScene);
//@ts-ignore
behavior = object.getBehavior(behaviorName);
//@ts-ignore
spriteBehavior = sprite.getBehavior(behaviorName);
//@ts-ignore
cubeBehavior = cube.getBehavior(behaviorName);
//@ts-ignore
textObjectBehavior = textObject.getBehavior(behaviorName);
});
@@ -216,6 +249,19 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(object.getY()).to.be(440);
});
it('can tween the position on Z axis', () => {
cube.setZ(200);
cubeBehavior.addObjectPositionZTween(
'MyTween',
600,
'linear',
250 / 1.5,
false
);
checkProgress(6, () => cube.getZ());
expect(cube.getZ()).to.be(440);
});
it('can tween the angle', () => {
object.setAngle(200);
behavior.addObjectAngleTween('MyTween', 600, 'linear', 250 / 1.5, false);
@@ -237,6 +283,19 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(object.getHeight()).to.be(440);
});
it('can tween the depth', () => {
cube.setDepth(200);
cubeBehavior.addObjectDepthTween(
'MyTween',
600,
'linear',
250 / 1.5,
false
);
checkProgress(6, () => cube.getDepth());
expect(cube.getDepth()).to.be(440);
});
it('can tween the opacity', () => {
sprite.setOpacity(128);
spriteBehavior.addObjectOpacityTween(
@@ -424,4 +483,46 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(sprite.getX()).to.be(-7580);
expect(sprite.getY()).to.be(-11120);
});
it('can tween the scales in seconds', () => {
sprite.setPosition(100, 400);
sprite.setScaleX(200);
sprite.setScaleY(300);
spriteBehavior.addObjectScaleTween2(
'MyTween',
600,
900,
'linear',
0.25,
false,
false
);
checkProgress(6, [() => sprite.getScaleX(), () => sprite.getScaleY()]);
// The interpolation is exponential.
expect(sprite.getScaleX()).to.be(386.6364089863524);
expect(sprite.getScaleY()).to.be(579.9546134795287);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scales from center in seconds', () => {
sprite.setPosition(100, 400);
sprite.setScaleX(200);
sprite.setScaleY(300);
spriteBehavior.addObjectScaleTween2(
'MyTween',
600,
900,
'linear',
0.25,
false,
true
);
checkProgress(6, [() => sprite.getScaleX(), () => sprite.getScaleY()]);
// The interpolation is exponential.
expect(sprite.getScaleX()).to.be(386.6364089863524);
expect(sprite.getScaleY()).to.be(579.9546134795287);
expect(sprite.getX()).to.be(-5872.3650875632775);
expect(sprite.getY()).to.be(-8558.547631344918);
});
});

View File

@@ -85,6 +85,32 @@ describe('gdjs.TweenRuntimeBehavior', () => {
return object;
};
/**
* @param {gdjs.RuntimeScene} runtimeScene
*/
const addCube = (runtimeScene) => {
const object = new gdjs.Cube3DRuntimeObject(runtimeScene, {
name: 'Cube',
type: 'Scene3D::Cube3DObject',
effects: [],
variables: [],
behaviors: [
{
type: 'Tween::TweenBehavior',
name: behaviorName,
},
],
// @ts-ignore
content: {
width: 64,
height: 64,
depth: 64,
},
});
runtimeScene.addObject(object);
return object;
};
/**
* @param {gdjs.RuntimeScene} runtimeScene
*/
@@ -123,6 +149,8 @@ describe('gdjs.TweenRuntimeBehavior', () => {
let object;
/** @type {gdjs.SpriteRuntimeObject} */
let sprite;
/** @type {gdjs.Cube3DRuntimeObject} */
let cube;
/** @type {gdjs.TextRuntimeObject} */
let textObject;
/** @type {gdjs.TweenRuntimeBehavior} */
@@ -130,18 +158,23 @@ describe('gdjs.TweenRuntimeBehavior', () => {
/** @type {gdjs.TweenRuntimeBehavior} */
let spriteBehavior;
/** @type {gdjs.TweenRuntimeBehavior} */
let cubeBehavior;
/** @type {gdjs.TweenRuntimeBehavior} */
let textObjectBehavior;
beforeEach(() => {
runtimeScene = createScene();
runtimeScene.getLayer('').setTimeScale(1.5);
object = addObject(runtimeScene);
sprite = addSprite(runtimeScene);
cube = addCube(runtimeScene);
textObject = addTextObject(runtimeScene);
//@ts-ignore
behavior = object.getBehavior(behaviorName);
//@ts-ignore
spriteBehavior = sprite.getBehavior(behaviorName);
//@ts-ignore
cubeBehavior = cube.getBehavior(behaviorName);
//@ts-ignore
textObjectBehavior = textObject.getBehavior(behaviorName);
});
@@ -404,6 +437,20 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(object.getY()).to.be(440);
});
it('can tween the position on Z axis', () => {
cube.setZ(200);
cubeBehavior.addObjectPositionZTween2(
null,
'MyTween',
600,
'linear',
0.25,
false
);
checkProgress(6, () => cube.getZ());
expect(cube.getZ()).to.be(440);
});
it('can tween the angle', () => {
object.setAngle(200);
behavior.addObjectAngleTween2('MyTween', 600, 'linear', 0.25, false);
@@ -411,6 +458,34 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(object.getAngle()).to.be(440);
});
it('can tween the rotation X', () => {
cube.setRotationX(200);
cubeBehavior.addObjectRotationXTween(
null,
'MyTween',
600,
'linear',
0.25,
false
);
checkProgress(6, () => cube.getRotationX());
expect(cube.getRotationX()).to.be(440);
});
it('can tween the rotation Y', () => {
cube.setRotationY(200);
cubeBehavior.addObjectRotationYTween(
null,
'MyTween',
600,
'linear',
0.25,
false
);
checkProgress(6, () => cube.getRotationY());
expect(cube.getRotationY()).to.be(440);
});
it('can tween the width', () => {
object.setWidth(200);
behavior.addObjectWidthTween2('MyTween', 600, 'linear', 0.25, false);
@@ -425,6 +500,20 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(object.getHeight()).to.be(440);
});
it('can tween the depth', () => {
cube.setDepth(200);
cubeBehavior.addObjectDepthTween2(
null,
'MyTween',
600,
'linear',
0.25,
false
);
checkProgress(6, () => cube.getDepth());
expect(cube.getDepth()).to.be(440);
});
it('can tween a number effect property', () => {
sprite.addEffect({
effectType: 'Outline',
@@ -540,6 +629,53 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(sprite.getY()).to.be(400);
});
it('can tween the scale on X axis to 0', () => {
sprite.setPosition(100, 400);
sprite.setScaleX(1);
spriteBehavior.addObjectScaleTween3(
'MyTween',
0,
'linear',
0.25,
false,
false
);
// The interpolation is exponential.
// It would need an infinite speed to go away from 0.
// This is why the scale is set to 0 directly.
for (let i = 0; i < 11; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(sprite.getScaleX()).to.be(0);
}
expect(spriteBehavior.hasFinished('MyTween')).to.be(true);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scale on X axis from 0', () => {
sprite.setPosition(100, 400);
sprite.setScaleX(0);
spriteBehavior.addObjectScaleTween3(
'MyTween',
1,
'linear',
0.25,
false,
false
);
// The interpolation is exponential.
// It would need an infinite speed to go away from 0.
// This is why the scale is set to 1 directly at the end.
for (let i = 0; i < 11; i++) {
expect(sprite.getScale()).to.be(0);
runtimeScene.renderAndStep(1000 / 60);
}
expect(spriteBehavior.hasFinished('MyTween')).to.be(true);
expect(sprite.getScaleX()).to.be(1);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scale on X axis from center', () => {
sprite.setPosition(100, 400);
sprite.setScaleX(200);
@@ -576,6 +712,53 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(sprite.getY()).to.be(400);
});
it('can tween the scale on Y axis to 0', () => {
sprite.setPosition(100, 400);
sprite.setScaleY(1);
spriteBehavior.addObjectScaleTween3(
'MyTween',
0,
'linear',
0.25,
false,
false
);
// The interpolation is exponential.
// It would need an infinite speed to go away from 0.
// This is why the scale is set to 0 directly.
for (let i = 0; i < 11; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(sprite.getScaleY()).to.be(0);
}
expect(spriteBehavior.hasFinished('MyTween')).to.be(true);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scale on Y axis from 0', () => {
sprite.setPosition(100, 400);
sprite.setScaleY(0);
spriteBehavior.addObjectScaleTween3(
'MyTween',
1,
'linear',
0.25,
false,
false
);
// The interpolation is exponential.
// It would need an infinite speed to go away from 0.
// This is why the scale is set to 1 directly at the end.
for (let i = 0; i < 11; i++) {
expect(sprite.getScale()).to.be(0);
runtimeScene.renderAndStep(1000 / 60);
}
expect(spriteBehavior.hasFinished('MyTween')).to.be(true);
expect(sprite.getScaleY()).to.be(1);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scale on Y axis from center', () => {
sprite.setPosition(100, 400);
sprite.setScaleY(200);
@@ -623,45 +806,126 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(object.getY()).to.be(660);
});
it('can tween the scales', () => {
it('can tween the scale', () => {
sprite.setPosition(100, 400);
sprite.setScaleX(200);
sprite.setScaleY(300);
spriteBehavior.addObjectScaleTween2(
sprite.setScale(200);
spriteBehavior.addObjectScaleTween3(
'MyTween',
600,
900,
'linear',
0.25,
false,
false
);
checkProgress(6, [() => sprite.getScaleX(), () => sprite.getScaleY()]);
checkProgress(6, () => sprite.getScale());
// The interpolation is exponential.
expect(sprite.getScaleX()).to.be(386.6364089863524);
expect(sprite.getScaleY()).to.be(579.9546134795287);
expect(sprite.getScale()).to.be(386.6364089863524);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scale to 0', () => {
sprite.setPosition(100, 400);
sprite.setScale(1);
spriteBehavior.addObjectScaleTween3(
'MyTween',
0,
'linear',
0.25,
false,
false
);
// The interpolation is exponential.
// It would need an infinite speed to go away from 0.
// This is why the scale is set to 0 directly.
for (let i = 0; i < 11; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(sprite.getScale()).to.be(0);
}
expect(spriteBehavior.hasFinished('MyTween')).to.be(true);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scale from 0', () => {
sprite.setPosition(100, 400);
sprite.setScale(0);
spriteBehavior.addObjectScaleTween3(
'MyTween',
1,
'linear',
0.25,
false,
false
);
// The interpolation is exponential.
// It would need an infinite speed to go away from 0.
// This is why the scale is set to 1 directly at the end.
for (let i = 0; i < 11; i++) {
expect(sprite.getScale()).to.be(0);
runtimeScene.renderAndStep(1000 / 60);
}
expect(spriteBehavior.hasFinished('MyTween')).to.be(true);
expect(sprite.getScale()).to.be(1);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scales from center', () => {
sprite.setPosition(100, 400);
sprite.setScaleX(200);
sprite.setScaleY(300);
spriteBehavior.addObjectScaleTween2(
sprite.setScale(200);
spriteBehavior.addObjectScaleTween3(
'MyTween',
600,
900,
'linear',
0.25,
false,
true
);
checkProgress(6, [() => sprite.getScaleX(), () => sprite.getScaleY()]);
checkProgress(6, () => sprite.getScale());
// The interpolation is exponential.
expect(sprite.getScaleX()).to.be(386.6364089863524);
expect(sprite.getScaleY()).to.be(579.9546134795287);
expect(sprite.getScale()).to.be(386.6364089863524);
expect(sprite.getX()).to.be(-5872.3650875632775);
expect(sprite.getY()).to.be(-8558.547631344918);
expect(sprite.getY()).to.be(-5572.3650875632775);
});
it('can tween the scale of a cube', () => {
cube.setPosition(100, 400);
cube.setZ(800);
cube.setScale(200);
cubeBehavior.addObjectScaleTween3(
'MyTween',
600,
'linear',
0.25,
false,
false
);
checkProgress(6, () => cube.getScale());
// The interpolation is exponential.
expect(cube.getScale()).to.be(386.6364089863524);
expect(cube.getX()).to.be(100);
expect(cube.getY()).to.be(400);
expect(cube.getZ()).to.be(800);
});
it('can tween the scales of a cube from center', () => {
cube.setPosition(100, 400);
cube.setZ(800);
cube.setScale(200);
cubeBehavior.addObjectScaleTween3(
'MyTween',
600,
'linear',
0.25,
false,
true
);
checkProgress(6, () => cube.getScale());
// The interpolation is exponential.
expect(cube.getScale()).to.be(386.6364089863524);
expect(cube.getX()).to.be(-5872.3650875632775);
expect(cube.getY()).to.be(-5572.3650875632775);
expect(cube.getZ()).to.be(-5172.3650875632775);
});
});

View File

@@ -456,7 +456,7 @@ namespace gdjs {
/**
* Tween an object Z position.
* @deprecated Use the 3D Tween extension instead.
* @deprecated Use addObjectPositionZTween2 instead.
* @param identifier Unique id to identify the tween
* @param toZ The target Z position
* @param easing Easing function identifier
@@ -469,14 +469,59 @@ namespace gdjs {
easing: string,
duration: float,
destroyObjectWhenFinished: boolean
) {
this._addObjectPositionZTween(
identifier,
toZ,
easing,
duration / 1000,
destroyObjectWhenFinished,
this.owner.getRuntimeScene()
);
}
/**
* Tween an object Z position.
* @param object3DBehavior Only used by events can be set to null
* @param identifier Unique id to identify the tween
* @param toZ The target Z position
* @param easing Easing function identifier
* @param duration Duration in seconds
* @param destroyObjectWhenFinished Destroy this object when the tween ends
*/
addObjectPositionZTween2(
object3DBehavior: any,
identifier: string,
toZ: number,
easing: string,
duration: float,
destroyObjectWhenFinished: boolean
) {
this._addObjectPositionZTween(
identifier,
toZ,
easing,
duration,
destroyObjectWhenFinished,
this.owner
);
}
private _addObjectPositionZTween(
identifier: string,
toZ: number,
easing: string,
duration: float,
destroyObjectWhenFinished: boolean,
timeSource: gdjs.evtTools.tween.TimeSource
) {
const { owner } = this;
if (!(owner instanceof gdjs.RuntimeObject3D)) return;
this._tweens.addSimpleTween(
identifier,
this.owner.getRuntimeScene(),
duration / 1000,
timeSource,
duration,
easing,
linearInterpolation,
owner.getZ(),
@@ -558,6 +603,72 @@ namespace gdjs {
);
}
/**
* Tween a 3D object rotation X.
* @param object3DBehavior Only used by events can be set to null
* @param identifier Unique id to identify the tween
* @param toAngle The target angle
* @param easing Easing function identifier
* @param duration Duration in seconds
* @param destroyObjectWhenFinished Destroy this object when the tween ends
*/
addObjectRotationXTween(
object3DBehavior: any,
identifier: string,
toAngle: float,
easing: string,
duration: float,
destroyObjectWhenFinished: boolean
) {
const { owner } = this;
if (!(owner instanceof gdjs.RuntimeObject3D)) return;
this._tweens.addSimpleTween(
identifier,
this.owner,
duration,
easing,
linearInterpolation,
owner.getRotationX(),
toAngle,
(value: float) => owner.setRotationX(value),
destroyObjectWhenFinished ? () => this._deleteFromScene() : null
);
}
/**
* Tween a 3D object rotation Y.
* @param object3DBehavior Only used by events can be set to null
* @param identifier Unique id to identify the tween
* @param toAngle The target angle
* @param easing Easing function identifier
* @param duration Duration in seconds
* @param destroyObjectWhenFinished Destroy this object when the tween ends
*/
addObjectRotationYTween(
object3DBehavior: any,
identifier: string,
toAngle: float,
easing: string,
duration: float,
destroyObjectWhenFinished: boolean
) {
const { owner } = this;
if (!(owner instanceof gdjs.RuntimeObject3D)) return;
this._tweens.addSimpleTween(
identifier,
this.owner,
duration,
easing,
linearInterpolation,
owner.getRotationY(),
toAngle,
(value: float) => owner.setRotationY(value),
destroyObjectWhenFinished ? () => this._deleteFromScene() : null
);
}
/**
* Tween an object scale.
* @deprecated Use addObjectScaleTween2 instead.
@@ -593,6 +704,7 @@ namespace gdjs {
/**
* Tween an object scale.
* @deprecated Use addObjectScaleXTween2 and addObjectScaleYTween2 instead.
* @param identifier Unique id to identify the tween
* @param toScaleX The target X-scale
* @param toScaleY The target Y-scale
@@ -666,6 +778,65 @@ namespace gdjs {
);
}
/**
* Tween an object scale.
* @param identifier Unique id to identify the tween
* @param toScale The target scale
* @param easing Easing function identifier
* @param duration Duration in seconds
* @param destroyObjectWhenFinished Destroy this object when the tween ends
* @param scaleFromCenterOfObject Scale the transform from the center of the object (or point that is called center), not the top-left origin
*/
addObjectScaleTween3(
identifier: string,
toScale: number,
easing: string,
duration: float,
destroyObjectWhenFinished: boolean,
scaleFromCenterOfObject: boolean
) {
this._addObjectScaleXTween(
identifier,
toScale,
easing,
duration,
destroyObjectWhenFinished,
scaleFromCenterOfObject,
this.owner,
exponentialInterpolation
);
const owner = this.owner;
if (!isScalable(owner)) return;
const owner3d = owner instanceof gdjs.RuntimeObject3D ? owner : null;
const setValue = scaleFromCenterOfObject
? (scale: float) => {
const oldX = owner.getCenterXInScene();
const oldY = owner.getCenterYInScene();
const oldZ = owner3d ? owner3d.getCenterZInScene() : 0;
owner.setScale(scale);
owner.setCenterXInScene(oldX);
owner.setCenterYInScene(oldY);
if (owner3d) {
owner3d.setCenterZInScene(oldZ);
}
}
: (scale: float) => owner.setScale(scale);
this._tweens.addSimpleTween(
identifier,
this.owner,
duration,
easing,
exponentialInterpolation,
owner.getScale(),
toScale,
setValue,
destroyObjectWhenFinished ? () => this._deleteFromScene() : null
);
}
/**
* Tween an object X-scale.
* @deprecated Use addObjectScaleXTween2 instead.
@@ -1519,7 +1690,7 @@ namespace gdjs {
/**
* Tween an object depth.
* @deprecated Use the 3D Tween extension instead.
* @deprecated Use addObjectDepthTween2 instead.
* @param identifier Unique id to identify the tween
* @param toDepth The target depth
* @param easing Easing function identifier
@@ -1532,14 +1703,59 @@ namespace gdjs {
easing: string,
duration: float,
destroyObjectWhenFinished: boolean
) {
this._addObjectDepthTween(
identifier,
toDepth,
easing,
duration / 1000,
destroyObjectWhenFinished,
this.owner.getRuntimeScene()
);
}
/**
* Tween an object depth.
* @param object3DBehavior Only used by events can be set to null
* @param identifier Unique id to identify the tween
* @param toDepth The target depth
* @param easing Easing function identifier
* @param duration Duration in seconds
* @param destroyObjectWhenFinished Destroy this object when the tween ends
*/
addObjectDepthTween2(
object3DBehavior: any,
identifier: string,
toDepth: float,
easing: string,
duration: float,
destroyObjectWhenFinished: boolean
) {
this._addObjectDepthTween(
identifier,
toDepth,
easing,
duration,
destroyObjectWhenFinished,
this.owner
);
}
private _addObjectDepthTween(
identifier: string,
toDepth: float,
easing: string,
duration: float,
destroyObjectWhenFinished: boolean,
timeSource: gdjs.evtTools.tween.TimeSource
) {
const { owner } = this;
if (!(owner instanceof gdjs.RuntimeObject3D)) return;
this._tweens.addSimpleTween(
identifier,
this.owner.getRuntimeScene(),
duration / 1000,
timeSource,
duration,
easing,
linearInterpolation,
owner.getDepth(),

View File

@@ -1,4 +1,5 @@
// @flow
//@ts-check
/// <reference path="../JsExtensionTypes.d.ts" />
/**
* This is a declaration of an extension for GDevelop 5.
*
@@ -12,31 +13,25 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
/** @type {ExtensionModule} */
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
createExtension: function (_, gd) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
'Video',
_('Video'),
_('Provides an object to display a video on the scene. The recommended file format is MPEG4, with H264 video codec and AAC audio codec, to maximize the support of the video on different platform and browsers.'),
_(
'Provides an object to display a video on the scene. The recommended file format is MPEG4, with H264 video codec and AAC audio codec, to maximize the support of the video on different platform and browsers.'
),
'Aurélien Vivet',
'Open source (MIT License)'
)
.setCategory('User interface')
.setExtensionHelpPath('/objects/video');
extension.addInstructionOrExpressionGroupMetadata(_("Video"))
.setIcon("JsPlatform/Extensions/videoicon16.png");
extension
.addInstructionOrExpressionGroupMetadata(_('Video'))
.setIcon('JsPlatform/Extensions/videoicon16.png');
var videoObject = new gd.ObjectJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating an object
@@ -138,7 +133,7 @@ module.exports = {
.addIncludeFile('Extensions/Video/videoruntimeobject-pixi-renderer.js')
.setCategoryFullName(_('User interface'))
.addDefaultBehavior('EffectCapability::EffectBehavior')
.addDefaultBehavior("OpacityCapability::OpacityBehavior");
.addDefaultBehavior('OpacityCapability::OpacityBehavior');
object
.addAction(
@@ -533,10 +528,7 @@ module.exports = {
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
runExtensionSanityTests: function (gd, extension) {
return [];
},
/**
@@ -545,9 +537,7 @@ module.exports = {
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {
registerEditorConfigurations: function (objectsEditorService) {
objectsEditorService.registerEditorConfiguration(
'Video::VideoObject',
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
@@ -560,9 +550,7 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
registerInstanceRenderers: function (objectsRenderingService) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const PIXI = objectsRenderingService.PIXI;
@@ -570,7 +558,7 @@ module.exports = {
* Renderer for instances of VideoObject inside the IDE.
*/
class RenderedVideoObjectInstance extends RenderedInstance {
constructor (
constructor(
project,
layout,
instance,
@@ -606,11 +594,7 @@ module.exports = {
/**
* Return the path to the thumbnail of the specified object.
*/
static getThumbnail(
project,
resourcesLoader,
objectConfiguration
) {
static getThumbnail(project, resourcesLoader, objectConfiguration) {
return 'JsPlatform/Extensions/videoicon24.png';
}
@@ -647,8 +631,7 @@ module.exports = {
that._pixiObject.texture.on('error', function () {
that._pixiObject.texture.off('error', this);
that._pixiObject.texture =
that._pixiResourcesLoader.getInvalidPIXITexture();
that._pixiObject.texture = that._pixiResourcesLoader.getInvalidPIXITexture();
});
}
}

View File

@@ -56,7 +56,7 @@ namespace gdjs {
setCameraZ(z: float, fov: float, cameraId?: integer): void {}
getCameraZ(fov: float = 45, cameraId?: integer): float {
getCameraZ(fov: float | null, cameraId?: integer): float {
return 0;
}

View File

@@ -19,6 +19,15 @@ namespace gdjs {
? RuntimeLayerRenderingType.TWO_D_PLUS_THREE_D
: RuntimeLayerRenderingType.TWO_D;
export enum RuntimeLayerCameraType {
PERSPECTIVE,
ORTHOGRAPHIC,
}
const getCameraTypeFromString = (renderingTypeAsString: string | undefined) =>
renderingTypeAsString === 'orthographic'
? RuntimeLayerCameraType.ORTHOGRAPHIC
: RuntimeLayerCameraType.PERSPECTIVE;
/**
* Represents a layer of a "container", used to display objects.
* The container can be a scene (see gdjs.Layer)
@@ -27,6 +36,7 @@ namespace gdjs {
export abstract class RuntimeLayer implements EffectsTarget {
_name: string;
_renderingType: RuntimeLayerRenderingType;
_cameraType: RuntimeLayerCameraType;
_timeScale: float = 1;
_defaultZOrder: integer = 0;
_hidden: boolean;
@@ -59,12 +69,13 @@ namespace gdjs {
) {
this._name = layerData.name;
this._renderingType = getRenderingTypeFromString(layerData.renderingType);
this._cameraType = getCameraTypeFromString(layerData.cameraType);
this._hidden = !layerData.visibility;
this._initialCamera3DFieldOfView = layerData.camera3DFieldOfView || 45;
this._initialCamera3DFarPlaneDistance =
layerData.camera3DFarPlaneDistance || 0.1;
this._initialCamera3DNearPlaneDistance =
layerData.camera3DNearPlaneDistance || 2000;
layerData.camera3DNearPlaneDistance || 0.1;
this._initialCamera3DFarPlaneDistance =
layerData.camera3DFarPlaneDistance || 2000;
this._initialEffectsData = layerData.effects || [];
this._runtimeScene = instanceContainer;
this._effectsManager = instanceContainer.getGame().getEffectsManager();
@@ -103,6 +114,10 @@ namespace gdjs {
return this._renderingType;
}
getCameraType(): RuntimeLayerCameraType {
return this._cameraType;
}
/**
* Get the default Z order to be attributed to objects created on this layer
* (usually from events generated code).
@@ -246,7 +261,7 @@ namespace gdjs {
* @param fov The field of view.
* @param cameraId The camera number. Currently ignored.
*/
abstract setCameraZ(z: float, fov: float, cameraId?: integer): void;
abstract setCameraZ(z: float, fov: float | null, cameraId?: integer): void;
/**
* Get the camera center Z position.
@@ -255,7 +270,7 @@ namespace gdjs {
* @param cameraId The camera number. Currently ignored.
* @return The z position of the camera
*/
abstract getCameraZ(fov: float, cameraId?: integer): float;
abstract getCameraZ(fov: float | null, cameraId?: integer): float;
/**
* Get the rotation of the camera, expressed in degrees.

View File

@@ -290,6 +290,16 @@ namespace gdjs {
end: float,
progress: float
) => {
if (progress === 0) {
return start;
}
if (progress === 1) {
return end;
}
if (start <= 0 || end <= 0) {
// The exponential function is flattened to something like a 90° corner.
return 0;
}
const startLog = Math.log(start);
const endLog = Math.log(end);
return Math.exp(startLog + (endLog - startLog) * progress);

View File

@@ -43,17 +43,22 @@ namespace gdjs {
oldGameResolutionOriginX: float,
oldGameResolutionOriginY: float
): void {
// Adapt position of the camera center as:
// * Most cameras following a player/object on the scene will be updating this
// in events anyway.
// Adapt position of the camera center only if the camera has never moved as:
// * When the camera follows a player/object, it will rarely be at the default position.
// * Cameras not following a player/object are usually UIs which are intuitively
// expected not to "move". Not adapting the center position would make the camera
// move from its initial position (which is centered in the screen) - and anchor
// behavior would behave counterintuitively.
this._cameraX +=
this._runtimeScene.getViewportOriginX() - oldGameResolutionOriginX;
this._cameraY +=
this._runtimeScene.getViewportOriginY() - oldGameResolutionOriginY;
if (
this._cameraX === oldGameResolutionOriginX &&
this._cameraY === oldGameResolutionOriginY &&
this._zoomFactor === 1
) {
this._cameraX +=
this._runtimeScene.getViewportOriginX() - oldGameResolutionOriginX;
this._cameraY +=
this._runtimeScene.getViewportOriginY() - oldGameResolutionOriginY;
}
this._renderer.updatePosition();
}
@@ -154,18 +159,20 @@ namespace gdjs {
* @param fov The field of view.
* @param cameraId The camera number. Currently ignored.
*/
setCameraZ(z: float, fov: float = 45, cameraId?: integer): void {
const cameraFovInRadians = gdjs.toRad(fov);
setCameraZ(z: float, fov: float | null, cameraId?: integer): void {
if (fov) {
const cameraFovInRadians = gdjs.toRad(fov);
// The zoom factor is capped to a not too big value to avoid infinity.
// MAX_SAFE_INTEGER is an arbitrary choice. It's big but not too big.
const zoomFactor = Math.min(
Number.MAX_SAFE_INTEGER,
(0.5 * this.getHeight()) / (z * Math.tan(0.5 * cameraFovInRadians))
);
// The zoom factor is capped to a not too big value to avoid infinity.
// MAX_SAFE_INTEGER is an arbitrary choice. It's big but not too big.
const zoomFactor = Math.min(
Number.MAX_SAFE_INTEGER,
(0.5 * this.getHeight()) / (z * Math.tan(0.5 * cameraFovInRadians))
);
if (zoomFactor > 0) {
this._zoomFactor = zoomFactor;
if (zoomFactor > 0) {
this._zoomFactor = zoomFactor;
}
}
this._cameraZ = z;
@@ -180,8 +187,8 @@ namespace gdjs {
* @param cameraId The camera number. Currently ignored.
* @return The z position of the camera
*/
getCameraZ(fov: float = 45, cameraId?: integer): float {
if (!this._isCameraZDirty) {
getCameraZ(fov: float | null, cameraId?: integer): float {
if (!this._isCameraZDirty || !fov) {
return this._cameraZ;
}

View File

@@ -34,7 +34,10 @@ namespace gdjs {
// For a 3D (or 2D+3D) layer:
private _threeGroup: THREE.Group | null = null;
private _threeScene: THREE.Scene | null = null;
private _threeCamera: THREE.PerspectiveCamera | null = null;
private _threeCamera:
| THREE.PerspectiveCamera
| THREE.OrthographicCamera
| null = null;
private _threeCameraDirty: boolean = false;
// For a 2D+3D layer, the 2D rendering is done on the render texture
@@ -101,13 +104,23 @@ namespace gdjs {
}
private _update3DCameraAspectAndPosition() {
if (this._threeCamera) {
if (!this._threeCamera) {
return;
}
if (this._threeCamera instanceof THREE.OrthographicCamera) {
const width = this._layer.getWidth();
const height = this._layer.getHeight();
this._threeCamera.left = -width / 2;
this._threeCamera.right = width / 2;
this._threeCamera.top = height / 2;
this._threeCamera.bottom = -height / 2;
} else {
this._threeCamera.aspect =
this._layer.getWidth() / this._layer.getHeight();
this._threeCamera.updateProjectionMatrix();
this.updatePosition();
}
this._threeCamera.updateProjectionMatrix();
this.updatePosition();
}
getRendererObject(): PIXI.Container {
@@ -118,7 +131,10 @@ namespace gdjs {
return this._threeScene;
}
getThreeCamera(): THREE.PerspectiveCamera | null {
getThreeCamera():
| THREE.PerspectiveCamera
| THREE.OrthographicCamera
| null {
return this._threeCamera;
}
@@ -164,12 +180,28 @@ namespace gdjs {
this._threeGroup = new THREE.Group();
this._threeScene.add(this._threeGroup);
this._threeCamera = new THREE.PerspectiveCamera(
this._layer.getInitialCamera3DFieldOfView(),
1,
this._layer.getInitialCamera3DNearPlaneDistance(),
this._layer.getInitialCamera3DFarPlaneDistance()
);
if (
this._layer.getCameraType() ===
gdjs.RuntimeLayerCameraType.ORTHOGRAPHIC
) {
const width = this._layer.getWidth();
const height = this._layer.getHeight();
this._threeCamera = new THREE.OrthographicCamera(
-width / 2,
width / 2,
height / 2,
-height / 2,
this._layer.getInitialCamera3DNearPlaneDistance(),
this._layer.getInitialCamera3DFarPlaneDistance()
);
} else {
this._threeCamera = new THREE.PerspectiveCamera(
this._layer.getInitialCamera3DFieldOfView(),
1,
this._layer.getInitialCamera3DNearPlaneDistance(),
this._layer.getInitialCamera3DFarPlaneDistance()
);
}
this._threeCamera.rotation.order = 'ZYX';
if (
@@ -375,9 +407,14 @@ namespace gdjs {
this._threeCamera.position.y = -this._layer.getCameraY(); // Inverted because the scene is mirrored on Y axis.
this._threeCamera.rotation.z = angle;
this._threeCamera.position.z = this._layer.getCameraZ(
this._threeCamera.fov
);
if (this._threeCamera instanceof THREE.OrthographicCamera) {
this._threeCamera.zoom = this._layer.getCameraZoom();
this._threeCamera.position.z = this._layer.getCameraZ(null);
} else {
this._threeCamera.position.z = this._layer.getCameraZ(
this._threeCamera.fov
);
}
if (this._threePlaneMesh) {
// Adapt the plane size so that it covers the whole screen.
@@ -415,6 +452,8 @@ namespace gdjs {
}
const width = this._layer.getWidth();
const height = this._layer.getHeight();
const normalizedX = (screenX / width) * 2 - 1;
const normalizedY = -(screenY / height) * 2 + 1;
let vector = LayerPixiRenderer.vectorForProjections;
if (!vector) {
@@ -422,12 +461,31 @@ namespace gdjs {
LayerPixiRenderer.vectorForProjections = vector;
}
// https://stackoverflow.com/questions/13055214/mouse-canvas-x-y-to-three-js-world-x-y-z
vector.set((screenX / width) * 2 - 1, -(screenY / height) * 2 + 1, 0.5);
vector.unproject(camera);
vector.sub(camera.position).normalize();
const distance = (worldZ - camera.position.z) / vector.z;
vector.multiplyScalar(distance);
camera.updateMatrixWorld();
if (camera instanceof THREE.OrthographicCamera) {
// https://discourse.threejs.org/t/how-to-unproject-mouse2d-with-orthographic-camera/4777
vector.set(normalizedX, normalizedY, 0);
vector.unproject(camera);
// The unprojected point is on the camera.
// Find x and y for a given z along the camera direction line.
const direction = new THREE.Vector3();
camera.getWorldDirection(direction);
const distance = (worldZ - vector.z) / direction.z;
vector.x += distance * direction.x;
vector.y += distance * direction.y;
} else {
// https://stackoverflow.com/questions/13055214/mouse-canvas-x-y-to-three-js-world-x-y-z
vector.set(normalizedX, normalizedY, 0.5);
vector.unproject(camera);
// The unprojected point is on the frustum plane.
// Find x and y for a given z along the line between the camera and
// the one on the frustum.
vector.sub(camera.position).normalize();
const distance = (worldZ - camera.position.z) / vector.z;
vector.x = distance * vector.x + camera.position.x;
vector.y = distance * vector.y + camera.position.y;
}
// The plane z == worldZ may not be visible on the camera.
if (!Number.isFinite(vector.x) || !Number.isFinite(vector.y)) {
@@ -436,8 +494,8 @@ namespace gdjs {
return result;
}
result[0] = camera.position.x + vector.x;
result[1] = -(camera.position.y + vector.y);
result[0] = vector.x;
result[1] = -vector.y;
return result;
}

View File

@@ -340,12 +340,15 @@ namespace gdjs {
});
const baseTexture = texture.baseTexture;
baseTexture.on('loaded', () => {
this._loadedTextures.set(resource, texture);
applyTextureSettings(texture, resource);
resolve();
});
baseTexture
.on('loaded', () => {
this._loadedTextures.set(resource, texture);
applyTextureSettings(texture, resource);
resolve();
})
.on('error', (error) => {
reject(error);
});
});
} else {
// If the file has no extension, PIXI.assets.load cannot find

View File

@@ -146,6 +146,7 @@ declare interface InstanceStringProperty {
declare interface LayerData {
name: string;
renderingType?: '' | '2d' | '3d' | '2d+3d';
cameraType?: 'perspective' | 'orthographic';
visibility: boolean;
cameras: CameraData[];
effects: EffectData[];

View File

@@ -28,8 +28,8 @@
"check-types": "tsc",
"build": "node scripts/build.js",
"test": "cd tests && npm run test-benchmark",
"format": "prettier --write \"Runtime/**/*.ts\" \"../Extensions/**/*.ts\" \"../Extensions/**/*.spec.js\"",
"check-format": "prettier --list-different \"Runtime/**/*.ts\" \"../Extensions/**/*.ts\" \"../Extensions/**/*.spec.js\"",
"format": "prettier --write \"Runtime/**/*.ts\" \"../Extensions/**/*.ts\" \"../Extensions/**/JsExtension.js\" \"../Extensions/**/*.spec.js\"",
"check-format": "prettier --list-different \"Runtime/**/*.ts\" \"../Extensions/**/*.ts\" \"../Extensions/**/JsExtension.js\" \"../Extensions/**/*.spec.js\"",
"generate-doc": "typedoc --options docs/typedoc.json"
}
}

View File

@@ -120,6 +120,10 @@ module.exports = function (config) {
'./newIDE/app/resources/GDJS/Runtime/Extensions/TextInput/textinputruntimeobject-pixi-renderer.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/TextObject/textruntimeobject.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/TextObject/textruntimeobject-pixi-renderer.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/3D/A_RuntimeObject3D.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/3D/A_RuntimeObject3DRenderer.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/3D/Cube3DRuntimeObject.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/3D/Cube3DRuntimeObjectPixiRenderer.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/TopDownMovementBehavior/topdownmovementruntimebehavior.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/TweenBehavior/TweenManager.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/TweenBehavior/tweentools.js',

View File

@@ -909,6 +909,8 @@ interface Layer {
[Const, Ref] DOMString GetName();
void SetRenderingType([Const] DOMString renderingType);
[Const, Ref] DOMString GetRenderingType();
void SetCameraType([Const] DOMString cameraType);
[Const, Ref] DOMString GetCameraType();
void SetVisibility(boolean visible);
boolean GetVisibility();
void SetLocked(boolean isLocked);
@@ -1297,6 +1299,12 @@ interface Serializer {
[Value] SerializerElement STATIC_FromJSON([Const] DOMString json);
};
interface ObjectAssetSerializer {
void STATIC_SerializeTo([Ref] Project project, [Const, Ref] gdObject obj,
[Const] DOMString objectFullName, [Ref] SerializerElement element,
[Ref] MapStringString resourcesNewFileNames);
};
interface InstructionsList {
void InstructionsList();
@@ -3028,6 +3036,7 @@ interface ObjectsUsingResourceCollector {
interface ResourcesInUseHelper {
void ResourcesInUseHelper([Ref] ResourcesManager resourcesManager);
[Const, Ref] VectorString GetAllResources();
[Ref] SetString GetAllImages();
[Ref] SetString GetAllAudios();
[Ref] SetString GetAllFonts();

View File

@@ -86,6 +86,7 @@
#include <GDCore/Project/VariablesContainersList.h>
#include <GDCore/Serialization/Serializer.h>
#include <GDCore/Serialization/SerializerElement.h>
#include <GDCore/IDE/ObjectAssetSerializer.h>
#include <GDJS/Events/Builtin/JsCodeEvent.h>
#include <GDJS/Events/CodeGeneration/BehaviorCodeGenerator.h>
#include <GDJS/Events/CodeGeneration/EventsFunctionsExtensionCodeGenerator.h>
@@ -539,6 +540,7 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_GetSafeName GetSafeName
#define STATIC_ToJSON ToJSON
#define STATIC_FromJSON(x) FromJSON(x)
#define STATIC_SerializeTo SerializeTo
#define STATIC_IsObject IsObject
#define STATIC_IsBehavior IsBehavior
#define STATIC_IsExpression IsExpression
@@ -590,6 +592,7 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_ExposeProjectEvents ExposeProjectEvents
#define STATIC_ExposeProjectObjects ExposeProjectObjects
#define STATIC_ExposeWholeProjectResources ExposeWholeProjectResources
#define STATIC_GetResourceTypes GetResourceTypes
#define STATIC_GetBehaviorMetadata GetBehaviorMetadata
#define STATIC_GetObjectMetadata GetObjectMetadata
@@ -754,6 +757,7 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_ShiftSentenceParamIndexes ShiftSentenceParamIndexes
#define STATIC_CopyAllResourcesTo CopyAllResourcesTo
#define STATIC_CopyObjectResourcesTo CopyObjectResourcesTo
#define STATIC_IsExtensionLifecycleEventsFunction \
IsExtensionLifecycleEventsFunction

View File

@@ -8,9 +8,6 @@
"name": "GDevelop.js",
"version": "0.0.1",
"license": "MIT",
"dependencies": {
"prettier": "^2.1.2"
},
"devDependencies": {
"@types/node": "^20.3.1",
"extend": "^2.0.1",
@@ -25,6 +22,7 @@
"grunt-shell": "^2.1.0",
"grunt-string-replace": "^1.3.1",
"jest": "^29.7.0",
"prettier": "^3.2.2",
"shelljs": "^0.8.4",
"webidl-tools": "github:4ian/webidl-tools#348f9c03afc9d8f278efccdd74543e265a41fd11"
}
@@ -7545,14 +7543,18 @@
}
},
"node_modules/prettier": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz",
"integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==",
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.2.tgz",
"integrity": "sha512-HTByuKZzw7utPiDO523Tt2pLtEyK7OibUD9suEJQrPUCYQqrHr74GGX6VidMrovbf/I50mPqr8j/II6oBAuc5A==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=10.13.0"
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/pretty-bytes": {

View File

@@ -33,6 +33,7 @@
"grunt-shell": "^2.1.0",
"grunt-string-replace": "^1.3.1",
"jest": "^29.7.0",
"prettier": "^3.2.2",
"shelljs": "^0.8.4",
"webidl-tools": "github:4ian/webidl-tools#348f9c03afc9d8f278efccdd74543e265a41fd11"
},
@@ -45,8 +46,5 @@
"<rootDir>/emsdk/",
"<rootDir>/node_modules/"
]
},
"dependencies": {
"prettier": "^2.1.2"
}
}

View File

@@ -1,7 +1,7 @@
// @ts-check
import { readFileSync, writeFileSync } from 'fs';
import { dirname } from 'path';
import { fileURLToPath } from 'url';
import { readFileSync, writeFileSync } from 'node:fs';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const bindingsFile = readFileSync(
@@ -69,6 +69,8 @@ class Parser {
static readUntil(thisCharacter, skipOverIt = true) {
let token = '';
while (this.currentCharacter !== thisCharacter) {
if (this.isDone)
throw new Error(`Never reached character '${thisCharacter}'!`);
token += this.currentCharacter;
this.parserPosition++;
}
@@ -83,17 +85,23 @@ class Parser {
Parser.skipWhitespaces();
// Read the type
let type = Parser.readUntil(' ');
/** @type {string} */
let type;
let optional = false;
if (type === 'optional') optional = true;
while (type === 'unsigned' || type === 'optional') {
// Re-read the type since unsigned is an unnecessary prefix for typescript
let attribute = false;
do {
Parser.skipWhitespaces();
type = Parser.readUntil(' ');
}
if (type === 'optional') optional = true;
if (type === 'attribute') attribute = true;
} while (
type === 'unsigned' ||
type === 'optional' ||
type === 'attribute'
);
Parser.skipWhitespaces();
return { type, optional };
return { type, optional, attribute };
}
static readIdentifier() {
@@ -137,7 +145,7 @@ for (const [_, enumName, enumCode] of bindingsFile.matchAll(
members.push(` ${memberName} = ${i++},`);
}
enums.push(
`enum ${enumName} {
`export enum ${enumName} {
${members.join('\n')}
}`
);
@@ -145,13 +153,31 @@ ${members.join('\n')}
const interfaces = [];
for (const [_, interfaceName, interfaceCode] of bindingsFile.matchAll(
/interface\s+([a-zA-Z]+)\s+{\r?\n?([^}]*)\r?\n}/gm
/interface\s+([a-zA-Z0-9]+)\s+{(?:}|(?:\r?\n?([^}]*)\r?\n}))/gm
)) {
if (!interfaceCode) {
interfaces.push(
`export class ${interfaceName} extends EmscriptenObject {}`
);
continue;
}
const methods = [];
const attributes = [];
Parser.setSource(interfaceCode);
while (!Parser.isDone) {
const { type: returnType, optional: optionalReturn } = Parser.readType();
const {
type: returnType,
optional: optionalReturn,
attribute: isAttribute,
} = Parser.readType();
if (isAttribute) {
const attributeName = Parser.readUntil(';');
attributes.push(`${attributeName}: ${returnType};`);
continue;
}
let methodName = Parser.readUntil('(');
const isStatic = methodName.includes('STATIC_');
@@ -160,6 +186,8 @@ for (const [_, interfaceName, interfaceCode] of bindingsFile.matchAll(
methodName = methodName
.replace('WRAPPED_', '')
.replace('MAP_', '')
.replace('FREE_', '')
.replace('CLONE_', '')
.replace('STATIC_', '');
// Convert PascalCase to camelCase
methodName = methodName[0].toLowerCase() + methodName.slice(1);
@@ -203,26 +231,33 @@ for (const [_, interfaceName, interfaceCode] of bindingsFile.matchAll(
({ name, type, optional, defaultValue }) =>
`${name}${optional ? '?' : ''}: ${
PrimitiveTypes.has(type) ? PrimitiveTypes.get(type) : type
}${defaultValue !== none ? ` = ${defaultValue}` : ''}`
}`
)
.join(', ')}): ${
PrimitiveTypes.has(returnType)
? PrimitiveTypes.get(returnType)
: returnType
.join(', ')})${
isConstructor
? ''
: `: ${
PrimitiveTypes.has(returnType)
? PrimitiveTypes.get(returnType)
: returnType
}`
};`
);
}
const inheritedClass = bindingsFile.match(
new RegExp(`(?<![a-zA-Z0-9])${interfaceName} implements ([a-zA-Z0-9]+)`)
);
interfaces.push(
`export class ${interfaceName} extends EmscriptenObject {
${methods.join('\n ')}
`export class ${interfaceName} extends ${inheritedClass ? inheritedClass[1] : 'EmscriptenObject'} {${methods.length ? '\n ' + methods.join('\n ') : ''}${attributes.length ? '\n ' + attributes.join('\n ') : ''}
}`
);
}
const dts = `// Automatically generated by GDevelop.js/scripts/generate-dts.js
class EmscriptenObject {
declare class EmscriptenObject {
/** The object's index in the WASM memory, and thus its unique identifier. */
ptr: number;
@@ -245,6 +280,10 @@ ${enums.join('\n\n')}
${interfaces.join('\n\n')}
export as namespace gd;
declare global {
const gd: typeof gd;
}
`;
writeFileSync(__dirname + '/../types.d.ts', dts);

View File

@@ -307,6 +307,12 @@ type ParticleEmitterObject_RendererType = 0 | 1 | 2`
'declare class gdGroupEvent extends gdBaseEvent {',
'types/gdgroupevent.js'
);
shell.sed(
'-i',
'declare class gdAbstractFileSystemJS {',
'declare class gdAbstractFileSystemJS extends gdAbstractFileSystem {',
'types/gdabstractfilesystemjs.js'
);
[
'BaseEvent',
'StandardEvent',

412
GDevelop.js/types.d.ts vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdAbstractFileSystemJS {
declare class gdAbstractFileSystemJS extends gdAbstractFileSystem {
constructor(): void;
mkDir(dir: string): void;
dirExists(dir: string): void;

View File

@@ -5,6 +5,8 @@ declare class gdLayer {
getName(): string;
setRenderingType(renderingType: string): void;
getRenderingType(): string;
setCameraType(cameraType: string): void;
getCameraType(): string;
setVisibility(visible: boolean): void;
getVisibility(): boolean;
setLocked(isLocked: boolean): void;

View File

@@ -0,0 +1,6 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdObjectAssetSerializer {
static serializeTo(project: gdProject, obj: gdObject, objectFullName: string, element: gdSerializerElement, resourcesNewFileNames: gdMapStringString): void;
delete(): void;
ptr: number;
};

View File

@@ -1,6 +1,7 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdResourcesInUseHelper extends gdArbitraryResourceWorker {
constructor(resourcesManager: gdResourcesManager): void;
getAllResources(): gdVectorString;
getAllImages(): gdSetString;
getAllAudios(): gdSetString;
getAllFonts(): gdSetString;

View File

@@ -122,6 +122,7 @@ declare class libGDevelop {
SerializerElement: Class<gdSerializerElement>;
SharedPtrSerializerElement: Class<gdSharedPtrSerializerElement>;
Serializer: Class<gdSerializer>;
ObjectAssetSerializer: Class<gdObjectAssetSerializer>;
InstructionsList: Class<gdInstructionsList>;
Instruction: Class<gdInstruction>;
Expression: Class<gdExpression>;

View File

@@ -21,11 +21,6 @@
# JSS triggers a Flow error
<PROJECT_ROOT>/node_modules/jss/src/index.js
[include]
# Type check the declarations of the JavaScript extensions (i.e: JsExtension.js files) with Flow
# (and actually any file in Extensions containing `// @flow`).
../../Extensions
[libs]
../../GDevelop.js/types

View File

@@ -1,6 +1,7 @@
// @flow
import GDevelopJsInitializerDecorator from '../src/stories/GDevelopJsInitializerDecorator';
import i18nProviderDecorator from '../src/stories/I18nProviderDecorator';
import BrowserDropDownMenuDisablerDecorator from '../src/stories/BrowserDropDownMenuDisablerDecorator';
import '../src/UI/icomoon-font.css'; // Styles for Icomoon font.
import './app-level-styling.css';
@@ -35,5 +36,6 @@ export const parameters = {
export const decorators = [
GDevelopJsInitializerDecorator,
i18nProviderDecorator
i18nProviderDecorator,
BrowserDropDownMenuDisablerDecorator
]

View File

@@ -0,0 +1,16 @@
<svg width="32" height="32" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.56693 2L11.278 3.71111V4.27054L12.9232 3.16666L14.0002 5.03332L12.9232 7.83332H10.5002L10.2309 7.13333H3.76923L3.5 7.83332H1.07692L0 5.03332L1.07692 3.16666L2.7225 4.27078V3.71111L4.43361 2L6.00009 1.5H8.00009L9.56693 2Z" fill="#3DB3E4"/>
<path d="M0 5.06668L1.07692 7.86668H3.5L3.76923 7.16668H6.88735L3.16037 3.30659L2.7225 3.74446V4.30414L1.07692 3.20001L0 5.06668Z" fill="#2399CA"/>
<path d="M8 8H6L5.00009 12.0334H9.00009L8.0965 8.41902L8 8Z" fill="#2399CA"/>
<path d="M4.43352 4.56668L2.72241 7.13334L4 9L5.60555 9.70001L6 8H8L8.41181 9.70001L10 9L11.278 7.13334L9.56685 4.56668L7.00019 5.42224L4.43352 4.56668Z" fill="#404D9B"/>
<path d="M4.40113 4.60001L2.69995 7.15177L3.97754 9.01843L5.57373 9.71844L6 8H7.5L4.40113 4.60001Z" fill="#273382"/>
<path d="M1.17998 4L2.97998 5.2L3 6.7L2.79393 7H1.53812L0.606536 5.2L1.17998 4Z" fill="white"/>
<path d="M12.8 4L11 5.2V6.7L11.186 7H12.4419L13.3734 5.2L12.8 4Z" fill="white"/>
<path d="M6 10.5L7 10L8 10.5" stroke="#404D9B" stroke-width="0.1" stroke-linecap="round"/>
<path d="M7.42782 8.84445H6.57227L7.00004 9.70001L7.42782 8.84445Z" fill="#404D9B"/>
<circle cx="5" cy="7" r="1" fill="white"/>
<circle cx="9" cy="7" r="1" fill="white"/>
<circle cx="0.5" cy="0.5" r="0.5" transform="matrix(1 0 0 -1 8.5 7.5)" fill="#404D9B"/>
<circle cx="0.5" cy="0.5" r="0.5" transform="matrix(1 0 0 -1 4.5 7.5)" fill="#404D9B"/>
<path d="M8.15 8.63L7.5 8H8L8.15 8.63Z" fill="#3DB3E4"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="3.25"/>
<path d="m12 2.75v1.5"/>
<path d="m17.25 6.75-1.1841 1.1842"/>
<path d="m21.25 12h-1.5"/>
<path d="m17.25 17.25-1.1841-1.184"/>
<path d="m12 19.75v1.5"/>
<path d="M7.9341 16.0659L6.75 17.25"/>
<path d="m4.25 12h-1.5"/>
<path d="m7.934 7.9342-1.184-1.1842"/>
</svg>

After

Width:  |  Height:  |  Size: 550 B

View File

@@ -0,0 +1,143 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="12" fill="#BF63D6" />
<mask id="mask0_802_3803" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
<circle cx="12" cy="12" r="12" fill="#D9D9D9" />
</mask>
<g mask="url(#mask0_802_3803)">
<path d="M-30.3049 29.896C-33.0903 32.3379 -30.883 34.5237 -31.067 35.1913H28.0303C26.769 35.0816 30.3426 34.9444 29.4492 31.1855C28.5558 27.4266 24.2201 25.6981 24.1675 24.9299C24.115 24.1616 26.6376 21.3082 24.7193 19.4151C22.8011 17.5219 22.9325 18.0706 22.8274 15.08C22.7223 12.0894 21.0668 6.163 14.3924 5.1204C7.71805 4.0778 6.24654 6.82149 4.19692 8.98901C2.1473 11.1565 2.09475 12.6656 0.754616 13.0222C-0.585516 13.3789 -2.16214 12.3363 -3.89643 13.0222C-5.63072 13.7082 -5.57817 14.6685 -6.60298 14.6685C-7.62779 14.6685 -8.9942 13.324 -12.0949 14.6685C-14.5755 15.744 -15.2657 20.037 -15.3007 22.049C-16.3781 21.171 -17.9021 20.5125 -19.7678 20.4028C-21.6335 20.293 -23.5254 21.4728 -25.1809 24.3811C-26.8364 27.2895 -26.2845 28.4967 -26.9678 28.9357C-27.651 29.3747 -29.26 28.9799 -30.3049 29.896Z" fill="url(#paint0_radial_802_3803)" />
<path d="M-33.5825 30.7926C-36.5733 33.3853 -34.2032 35.7061 -34.4007 36.4149H34.3205C32.9661 36.2984 36.8035 36.1528 35.8442 32.1618C34.8848 28.1708 24.966 26.3355 24.9095 25.5198C24.8531 24.7041 27.5618 21.6745 25.5021 19.6644C23.4423 17.6543 23.5834 18.237 23.4705 15.0616C23.3576 11.8863 21.58 5.59393 14.4131 4.48693C7.24625 3.37994 5.66615 6.29308 3.4653 8.59446C1.26444 10.8958 1.20801 12.4981 -0.23101 12.8768C-1.67003 13.2555 -3.363 12.1485 -5.22526 12.8768C-7.08753 13.6051 -7.0311 14.6247 -8.13153 14.6247C-9.23196 14.6247 -10.6992 13.1972 -14.0287 14.6247C-16.6923 15.7666 -17.4334 20.3247 -17.4711 22.461C-18.6279 21.5288 -20.2645 20.8296 -22.2678 20.7131C-24.2711 20.5966 -26.3027 21.8492 -28.0803 24.9372C-29.8579 28.0251 -29.2654 29.3069 -29.999 29.773C-30.7326 30.2391 -32.4604 29.82 -33.5825 30.7926Z" fill="url(#paint1_linear_802_3803)" />
<path d="M-40 37.4944C-39.8026 36.7907 -40.4379 33.5912 -37.5546 30.8752C-35.4248 28.8688 -31.5283 29.3315 -30.7953 28.8688C-30.0623 28.4062 -30.6544 27.1338 -28.8782 24.0684C-27.1021 21.0031 -25.0722 19.7596 -23.0705 19.8753C-21.0688 19.991 -19.4336 20.685 -18.2777 21.6104C-18.2401 19.4897 -17.4996 14.965 -14.8382 13.8314C-11.5114 12.4144 -10.9924 13.0496 -9.8929 13.0496C-8.79338 13.0496 -8.96642 11.5952 -7.10569 10.8723C-5.24496 10.1493 -3.86312 11.6837 -2.42529 11.3077C-0.987453 10.9318 0.442387 10.1299 2.64143 7.84536C4.84048 5.56082 7.82952 4.31776 13.2725 5.15301C20.4335 6.2519 21.7054 9.92662 21.8181 13.0787C21.9309 16.2308 23.8174 15.9569 24.6601 18.8342C25.4731 21.6104 24.0116 23.8371 24.068 24.6468C24.1244 25.4565 30.4571 27.1166 31.4156 31.0784C32.0769 33.8117 30.8495 36.1041 30.6982 36.8625L31.4156 36.8561C30.7796 37.2343 30.6302 37.2034 30.6982 36.8625L-40 37.4944Z" fill="url(#paint2_linear_802_3803)" fill-opacity="0.4" />
<path d="M14.018 7.16476C14.0279 7.12581 14.0578 7.0998 14.0849 7.10665C14.1119 7.11351 14.1259 7.15063 14.116 7.18958C14.1061 7.22853 14.0762 7.25455 14.0491 7.24769C14.0221 7.24084 14.0081 7.20371 14.018 7.16476Z" fill="#D1FEF9" />
<path d="M15.6621 6.75192C15.6729 6.70939 15.7056 6.68098 15.7351 6.68846C15.7647 6.69595 15.7799 6.7365 15.7691 6.77903C15.7584 6.82156 15.7257 6.84997 15.6961 6.84248C15.6666 6.835 15.6514 6.79445 15.6621 6.75192Z" fill="#D1FEF9" />
<path d="M15.9428 7.05576C15.9574 6.99844 16.0014 6.96014 16.0412 6.97023C16.0811 6.98032 16.1016 7.03497 16.0871 7.09229C16.0726 7.14961 16.0285 7.1879 15.9887 7.17781C15.9488 7.16772 15.9283 7.11308 15.9428 7.05576Z" fill="#D1FEF9" />
<path d="M16.8543 6.70996C16.8609 6.684 16.8808 6.66665 16.8989 6.67122C16.9169 6.67579 16.9262 6.70054 16.9196 6.7265C16.913 6.75247 16.8931 6.76981 16.875 6.76524C16.857 6.76067 16.8477 6.73592 16.8543 6.70996Z" fill="#D1FEF9" />
<path d="M17.8287 6.05721C17.8497 5.97442 17.9133 5.91912 17.9708 5.93369C18.0283 5.94826 18.058 6.02718 18.037 6.10996C18.016 6.19275 17.9524 6.24805 17.8949 6.23348C17.8374 6.21891 17.8077 6.13999 17.8287 6.05721Z" fill="#D1FEF9" />
<path d="M18.0933 6.34284C18.1003 6.31502 18.1217 6.29643 18.141 6.30133C18.1604 6.30622 18.1703 6.33275 18.1633 6.36057C18.1562 6.38838 18.1348 6.40697 18.1155 6.40207C18.0962 6.39717 18.0862 6.37066 18.0933 6.34284Z" fill="#D1FEF9" />
<path d="M16.5398 7.79474C16.5508 7.75136 16.5841 7.72238 16.6142 7.73001C16.6444 7.73765 16.6599 7.779 16.6489 7.82239C16.6379 7.86577 16.6046 7.89475 16.5744 7.88712C16.5443 7.87948 16.5288 7.83812 16.5398 7.79474Z" fill="#D1FEF9" />
<path d="M14.5752 7.71331C14.5781 7.70188 14.5869 7.69424 14.5949 7.69625C14.6028 7.69827 14.6069 7.70916 14.604 7.72059C14.6011 7.73202 14.5923 7.73966 14.5844 7.73764C14.5764 7.73563 14.5723 7.72474 14.5752 7.71331Z" fill="#D1FEF9" />
<path d="M13.8323 7.61426C13.8441 7.56789 13.8797 7.53692 13.9119 7.54508C13.9441 7.55324 13.9607 7.59744 13.949 7.64381C13.9373 7.69018 13.9016 7.72115 13.8694 7.71299C13.8372 7.70483 13.8206 7.66063 13.8323 7.61426Z" fill="#D1FEF9" />
<path d="M14.7478 7.15098C14.7641 7.08669 14.8135 7.04375 14.8582 7.05506C14.9029 7.06637 14.9259 7.12766 14.9096 7.19195C14.8933 7.25625 14.8439 7.29919 14.7992 7.28788C14.7546 7.27656 14.7316 7.21527 14.7478 7.15098Z" fill="#D1FEF9" />
<path d="M15.274 7.44532C15.279 7.42592 15.2939 7.41296 15.3073 7.41637C15.3208 7.41978 15.3278 7.43828 15.3229 7.45768C15.3179 7.47708 15.303 7.49005 15.2896 7.48663C15.2761 7.48322 15.2691 7.46472 15.274 7.44532Z" fill="#D1FEF9" />
<path d="M15.7663 5.28356C15.7832 5.2167 15.8346 5.17204 15.881 5.18381C15.9275 5.19557 15.9514 5.25931 15.9345 5.32616C15.9175 5.39301 15.8662 5.43767 15.8197 5.4259C15.7733 5.41414 15.7493 5.35041 15.7663 5.28356Z" fill="#D1FEF9" />
<path d="M21.5237 9.65164C21.5476 9.55734 21.6201 9.49435 21.6856 9.51094C21.7511 9.52754 21.7849 9.61744 21.761 9.71174C21.7371 9.80604 21.6647 9.86904 21.5991 9.85244C21.5336 9.83585 21.4998 9.74595 21.5237 9.65164Z" fill="#D1FEF9" />
<path d="M16.7476 5.59271C16.7555 5.56133 16.7796 5.54037 16.8014 5.54589C16.8232 5.55141 16.8345 5.58133 16.8265 5.61271C16.8186 5.6441 16.7945 5.66506 16.7726 5.65954C16.7508 5.65402 16.7396 5.6241 16.7476 5.59271Z" fill="#D1FEF9" />
<path d="M15.6258 5.52825C15.6332 5.49872 15.6559 5.479 15.6765 5.48419C15.697 5.48939 15.7075 5.51754 15.7001 5.54707C15.6926 5.5766 15.6699 5.59633 15.6494 5.59113C15.6289 5.58593 15.6183 5.55778 15.6258 5.52825Z" fill="#D1FEF9" />
<path d="M16.3517 5.76635C16.3588 5.7381 16.3805 5.71924 16.4002 5.72421C16.4198 5.72918 16.4299 5.75611 16.4227 5.78435C16.4156 5.8126 16.3939 5.83147 16.3743 5.82649C16.3546 5.82152 16.3445 5.7946 16.3517 5.76635Z" fill="#D1FEF9" />
<path d="M15.0458 5.85657C15.0568 5.81305 15.0903 5.78397 15.1205 5.79163C15.1508 5.79929 15.1664 5.84078 15.1553 5.88431C15.1443 5.92783 15.1109 5.95691 15.0806 5.94925C15.0504 5.94159 15.0348 5.9001 15.0458 5.85657Z" fill="#D1FEF9" />
<path d="M19.9803 6.58241C19.9937 6.52921 20.0346 6.49367 20.0716 6.50303C20.1085 6.51239 20.1276 6.56311 20.1141 6.61631C20.1006 6.66951 20.0598 6.70504 20.0228 6.69568C19.9858 6.68632 19.9668 6.6356 19.9803 6.58241Z" fill="#D1FEF9" />
<path d="M20.6122 6.79541C20.6191 6.76788 20.6403 6.74948 20.6594 6.75433C20.6786 6.75917 20.6884 6.78542 20.6814 6.81296C20.6745 6.84049 20.6533 6.85888 20.6342 6.85403C20.6151 6.84919 20.6052 6.82294 20.6122 6.79541Z" fill="#D1FEF9" />
<path d="M21.1527 7.68672C21.1608 7.65448 21.1856 7.63294 21.208 7.63862C21.2304 7.64429 21.2419 7.67502 21.2338 7.70726C21.2256 7.7395 21.2008 7.76104 21.1784 7.75537C21.156 7.74969 21.1445 7.71896 21.1527 7.68672Z" fill="#D1FEF9" />
<path d="M20.0877 7.40599C20.0974 7.36776 20.1268 7.34222 20.1533 7.34894C20.1799 7.35567 20.1936 7.39212 20.1839 7.43035C20.1742 7.46858 20.1448 7.49412 20.1183 7.48739C20.0917 7.48066 20.078 7.44422 20.0877 7.40599Z" fill="#D1FEF9" />
<path d="M19.1399 7.48206C19.1489 7.44654 19.1762 7.42282 19.2009 7.42907C19.2256 7.43532 19.2383 7.46918 19.2293 7.5047C19.2203 7.54022 19.193 7.56395 19.1683 7.5577C19.1436 7.55145 19.1309 7.51758 19.1399 7.48206Z" fill="#D1FEF9" />
<path d="M20.9697 9.98819C20.9787 9.95252 21.0062 9.9287 21.0309 9.93497C21.0557 9.94125 21.0685 9.97525 21.0594 10.0109C21.0504 10.0466 21.023 10.0704 20.9982 10.0641C20.9734 10.0579 20.9607 10.0239 20.9697 9.98819Z" fill="#D1FEF9" />
<path d="M22.2198 9.91137C22.2307 9.86827 22.2638 9.83948 22.2938 9.84707C22.3237 9.85465 22.3392 9.89574 22.3282 9.93884C22.3173 9.98194 22.2842 10.0107 22.2542 10.0031C22.2243 9.99556 22.2089 9.95447 22.2198 9.91137Z" fill="#D1FEF9" />
<path d="M19.3923 9.71207C19.4076 9.65148 19.4542 9.611 19.4963 9.62167C19.5384 9.63233 19.5601 9.69009 19.5448 9.75068C19.5294 9.81128 19.4828 9.85175 19.4407 9.84109C19.3986 9.83043 19.3769 9.77266 19.3923 9.71207Z" fill="#D1FEF9" />
<path d="M19.4306 9.07896C19.4363 9.05671 19.4534 9.04184 19.4689 9.04576C19.4843 9.04967 19.4923 9.07089 19.4866 9.09314C19.481 9.1154 19.4639 9.13026 19.4484 9.12635C19.433 9.12243 19.425 9.10122 19.4306 9.07896Z" fill="#D1FEF9" />
<path d="M20.6629 9.79212C20.6694 9.76645 20.6891 9.74929 20.7069 9.75381C20.7248 9.75833 20.734 9.78281 20.7275 9.80849C20.721 9.83417 20.7012 9.85132 20.6834 9.8468C20.6655 9.84228 20.6564 9.8178 20.6629 9.79212Z" fill="#D1FEF9" />
<path d="M21.1683 10.2899C21.1762 10.2587 21.2002 10.2378 21.2219 10.2433C21.2436 10.2488 21.2548 10.2786 21.2469 10.3098C21.239 10.3411 21.2149 10.3619 21.1932 10.3564C21.1715 10.3509 21.1603 10.3211 21.1683 10.2899Z" fill="#D1FEF9" />
<path d="M18.7116 6.96087C18.7224 7.00236 18.7001 7.0364 18.6619 7.03691C18.6236 7.03742 18.5839 7.0042 18.5732 6.96272C18.5624 6.92124 18.5847 6.88719 18.6229 6.88668C18.6612 6.88617 18.7009 6.91939 18.7116 6.96087Z" fill="#D1FEF9" />
<path d="M16.8827 7.81859C16.8944 7.86389 16.8701 7.90107 16.8283 7.90163C16.7865 7.90219 16.7432 7.86591 16.7315 7.82061C16.7197 7.77531 16.7441 7.73813 16.7858 7.73758C16.8276 7.73702 16.8709 7.77329 16.8827 7.81859Z" fill="#D1FEF9" />
<path d="M16.3465 7.59161C16.3623 7.65267 16.3295 7.70277 16.2732 7.70352C16.2169 7.70428 16.1585 7.65539 16.1426 7.59433C16.1268 7.53327 16.1596 7.48317 16.2159 7.48242C16.2722 7.48167 16.3306 7.53055 16.3465 7.59161Z" fill="#D1FEF9" />
<path d="M15.4022 8.18338C15.4093 8.21103 15.3945 8.23373 15.369 8.23407C15.3435 8.23441 15.317 8.21226 15.3098 8.18461C15.3027 8.15695 15.3175 8.13426 15.343 8.13392C15.3685 8.13358 15.395 8.15572 15.4022 8.18338Z" fill="#D1FEF9" />
<path d="M14.561 9.09841C14.5839 9.18658 14.5365 9.25895 14.4552 9.26003C14.3739 9.26112 14.2895 9.19051 14.2667 9.10234C14.2439 9.01416 14.2912 8.94179 14.3725 8.94071C14.4538 8.93962 14.5382 9.01023 14.561 9.09841Z" fill="#D1FEF9" />
<path d="M14.0568 8.88541C14.0645 8.91505 14.0485 8.93937 14.0212 8.93973C13.9939 8.94009 13.9655 8.91637 13.9579 8.88674C13.9502 8.8571 13.9661 8.83279 13.9934 8.83242C14.0207 8.83206 14.0491 8.85578 14.0568 8.88541Z" fill="#D1FEF9" />
<path d="M15.1535 7.01746C15.1654 7.06367 15.1406 7.1016 15.098 7.10216C15.0554 7.10273 15.0112 7.06573 14.9992 7.01952C14.9872 6.97331 15.0121 6.93539 15.0547 6.93482C15.0973 6.93425 15.1415 6.97125 15.1535 7.01746Z" fill="#D1FEF9" />
<path d="M17.681 6.56592C17.6842 6.57809 17.6776 6.58809 17.6664 6.58824C17.6552 6.58839 17.6435 6.57864 17.6404 6.56646C17.6372 6.55429 17.6437 6.5443 17.655 6.54415C17.6662 6.544 17.6778 6.55374 17.681 6.56592Z" fill="#D1FEF9" />
<path d="M18.6786 6.46253C18.6914 6.51192 18.6649 6.55245 18.6194 6.55306C18.5738 6.55367 18.5266 6.51412 18.5138 6.46473C18.501 6.41534 18.5275 6.37481 18.573 6.3742C18.6186 6.3736 18.6658 6.41314 18.6786 6.46253Z" fill="#D1FEF9" />
<path d="M17.7979 7.1727C17.8157 7.24118 17.7789 7.29738 17.7158 7.29822C17.6526 7.29906 17.5871 7.24424 17.5693 7.17575C17.5516 7.10727 17.5884 7.05107 17.6515 7.05023C17.7147 7.04939 17.7802 7.10422 17.7979 7.1727Z" fill="#D1FEF9" />
<path d="M16.9593 7.02196C16.9646 7.04262 16.9535 7.05958 16.9345 7.05984C16.9154 7.06009 16.8957 7.04355 16.8903 7.02288C16.885 7.00221 16.8961 6.98525 16.9151 6.985C16.9342 6.98474 16.9539 7.00129 16.9593 7.02196Z" fill="#D1FEF9" />
<path d="M17.6252 9.3097C17.6437 9.38091 17.6054 9.43935 17.5398 9.44023C17.4741 9.4411 17.406 9.38409 17.3875 9.31288C17.3691 9.24167 17.4073 9.18323 17.473 9.18236C17.5386 9.18148 17.6068 9.2385 17.6252 9.3097Z" fill="#D1FEF9" />
<path d="M7.75656 6.51843C7.78258 6.61888 7.72861 6.70131 7.63602 6.70255C7.54342 6.70379 7.44727 6.62336 7.42125 6.52291C7.39524 6.42246 7.44921 6.34003 7.5418 6.3388C7.63439 6.33756 7.73054 6.41799 7.75656 6.51843Z" fill="#D1FEF9" />
<path d="M16.2025 9.26824C16.2111 9.30167 16.1932 9.3291 16.1623 9.32951C16.1315 9.32992 16.0995 9.30316 16.0909 9.26973C16.0822 9.2363 16.1002 9.20886 16.131 9.20845C16.1618 9.20804 16.1938 9.23481 16.2025 9.26824Z" fill="#D1FEF9" />
<path d="M17.657 9.02753C17.6651 9.05899 17.6482 9.0848 17.6192 9.08519C17.5902 9.08558 17.5601 9.06039 17.552 9.02894C17.5438 8.99748 17.5607 8.97167 17.5897 8.97128C17.6187 8.9709 17.6488 8.99608 17.657 9.02753Z" fill="#D1FEF9" />
<path d="M16.5993 8.98679C16.6071 9.01688 16.5909 9.04156 16.5632 9.04194C16.5354 9.04231 16.5066 9.01822 16.4989 8.98813C16.4911 8.95804 16.5072 8.93335 16.535 8.93298C16.5627 8.93261 16.5915 8.9567 16.5993 8.98679Z" fill="#D1FEF9" />
<path d="M18.1936 8.54337C18.2056 8.58973 18.1807 8.62777 18.138 8.62834C18.0952 8.62891 18.0508 8.59179 18.0388 8.54543C18.0268 8.49907 18.0517 8.46102 18.0945 8.46045C18.1372 8.45988 18.1816 8.497 18.1936 8.54337Z" fill="#D1FEF9" />
<path d="M11.5322 9.15865C11.5469 9.21532 11.5165 9.26182 11.4643 9.26252C11.412 9.26322 11.3578 9.21784 11.3431 9.16118C11.3284 9.10451 11.3589 9.05801 11.4111 9.05732C11.4633 9.05662 11.5176 9.10199 11.5322 9.15865Z" fill="#D1FEF9" />
<path d="M10.6084 9.11803C10.616 9.14736 10.6002 9.17143 10.5732 9.17179C10.5461 9.17215 10.5181 9.14867 10.5105 9.11934C10.5029 9.09001 10.5186 9.06595 10.5457 9.06558C10.5727 9.06522 10.6008 9.0887 10.6084 9.11803Z" fill="#D1FEF9" />
<path d="M9.39454 8.37602C9.40343 8.41036 9.38498 8.43854 9.35332 8.43896C9.32167 8.43938 9.28879 8.41189 9.2799 8.37755C9.271 8.34321 9.28946 8.31503 9.32111 8.3146C9.35277 8.31418 9.38564 8.34168 9.39454 8.37602Z" fill="#D1FEF9" />
<path d="M10.907 8.36699C10.9175 8.40771 10.8957 8.44113 10.8581 8.44163C10.8206 8.44213 10.7816 8.40953 10.7711 8.36881C10.7605 8.32808 10.7824 8.29467 10.8199 8.29417C10.8575 8.29367 10.8964 8.32627 10.907 8.36699Z" fill="#D1FEF9" />
<path d="M12.0577 8.0336C12.0675 8.07143 12.0472 8.10248 12.0123 8.10295C11.9775 8.10341 11.9412 8.07312 11.9314 8.03529C11.9216 7.99745 11.942 7.9664 11.9768 7.96594C12.0117 7.96547 12.0479 7.99577 12.0577 8.0336Z" fill="#D1FEF9" />
<path d="M8.25571 6.03292C8.26555 6.07091 8.24514 6.10209 8.21012 6.10255C8.17511 6.10302 8.13874 6.0726 8.1289 6.03461C8.11906 5.99662 8.13947 5.96544 8.17449 5.96497C8.20951 5.96451 8.24587 5.99493 8.25571 6.03292Z" fill="#D1FEF9" />
<path d="M6.72274 6.44871C6.73463 6.49462 6.70997 6.53229 6.66765 6.53285C6.62534 6.53342 6.58139 6.49666 6.5695 6.45075C6.55761 6.40485 6.58228 6.36717 6.62459 6.36661C6.66691 6.36604 6.71085 6.4028 6.72274 6.44871Z" fill="#D1FEF9" />
<path d="M10.4114 5.88048C10.4281 5.94502 10.3934 5.99799 10.3339 5.99878C10.2744 5.99957 10.2126 5.9479 10.1959 5.88336C10.1792 5.81882 10.2139 5.76585 10.2734 5.76506C10.3329 5.76426 10.3946 5.81594 10.4114 5.88048Z" fill="#D1FEF9" />
<path d="M10.7394 6.5218C10.7456 6.5455 10.7328 6.56496 10.711 6.56525C10.6891 6.56554 10.6664 6.54656 10.6603 6.52285C10.6541 6.49915 10.6669 6.4797 10.6887 6.47941C10.7106 6.47911 10.7333 6.49809 10.7394 6.5218Z" fill="#D1FEF9" />
<path d="M8.76001 6.14491C8.7671 6.17226 8.7524 6.1947 8.72719 6.19504C8.70198 6.19538 8.67579 6.17348 8.66871 6.14612C8.66163 6.11877 8.67632 6.09633 8.70154 6.09599C8.72675 6.09566 8.75293 6.11755 8.76001 6.14491Z" fill="#D1FEF9" />
<path d="M7.82555 5.78648C7.83416 5.81975 7.81628 5.84706 7.78561 5.84747C7.75493 5.84788 7.72308 5.82124 7.71446 5.78796C7.70584 5.75468 7.72372 5.72737 7.7544 5.72697C7.78507 5.72656 7.81693 5.7532 7.82555 5.78648Z" fill="#D1FEF9" />
<path d="M8.68592 5.7983C8.69894 5.83386 8.73671 5.85273 8.77029 5.84043C8.80386 5.82814 8.82053 5.78935 8.80751 5.75379C8.79449 5.71822 8.75672 5.69936 8.72314 5.71165C8.68956 5.72394 8.6729 5.76274 8.68592 5.7983Z" fill="#D1FEF9" />
<path d="M9.94793 5.27233C9.97231 5.33892 10.043 5.37424 10.1059 5.35122C10.1688 5.3282 10.2 5.25556 10.1756 5.18898C10.1512 5.12239 10.0805 5.08706 10.0176 5.11008C9.95476 5.1331 9.92355 5.20574 9.94793 5.27233Z" fill="#D1FEF9" />
<path d="M9.57434 5.69829C9.59238 5.74758 9.64474 5.77372 9.69128 5.75668C9.73782 5.73965 9.76092 5.68588 9.74288 5.63658C9.72483 5.58729 9.67248 5.56114 9.62594 5.57818C9.57939 5.59522 9.55629 5.64899 9.57434 5.69829Z" fill="#D1FEF9" />
<path d="M9.89041 4.5091C9.89978 4.53469 9.92696 4.54826 9.95112 4.53942C9.97528 4.53057 9.98727 4.50266 9.9779 4.47707C9.96853 4.45148 9.94135 4.43791 9.91719 4.44675C9.89304 4.4556 9.88104 4.48351 9.89041 4.5091Z" fill="#D1FEF9" />
<path d="M10.8269 4.34204C10.8347 4.36329 10.8573 4.37456 10.8773 4.36721C10.8974 4.35986 10.9074 4.33669 10.8996 4.31544C10.8918 4.29419 10.8692 4.28292 10.8492 4.29026C10.8291 4.29761 10.8191 4.32079 10.8269 4.34204Z" fill="#D1FEF9" />
<path d="M11.2846 6.72449C11.3113 6.79727 11.3886 6.83589 11.4573 6.81073C11.526 6.78557 11.5601 6.70617 11.5335 6.63338C11.5068 6.56059 11.4295 6.52198 11.3608 6.54714C11.2921 6.5723 11.258 6.6517 11.2846 6.72449Z" fill="#D1FEF9" />
<path d="M10.79 6.58391C10.8029 6.61919 10.8404 6.6379 10.8737 6.62571C10.907 6.61352 10.9235 6.57503 10.9106 6.53976C10.8977 6.50449 10.8602 6.48578 10.8269 6.49797C10.7936 6.51016 10.7771 6.54864 10.79 6.58391Z" fill="#D1FEF9" />
<path d="M11.7042 6.77033C11.7131 6.79461 11.7389 6.8075 11.7618 6.7991C11.7847 6.79071 11.7961 6.76421 11.7872 6.73993C11.7783 6.71564 11.7525 6.70276 11.7296 6.71115C11.7067 6.71955 11.6953 6.74604 11.7042 6.77033Z" fill="#D1FEF9" />
<path d="M9.27454 7.15176C9.31 7.24862 9.41288 7.3 9.50433 7.26652C9.59578 7.23304 9.64117 7.12738 9.60571 7.03053C9.57025 6.93367 9.46737 6.88229 9.37592 6.91577C9.28447 6.94925 9.23908 7.05491 9.27454 7.15176Z" fill="#D1FEF9" />
<path d="M5.98094 8.90307C6.00295 8.96318 6.06679 8.99506 6.12354 8.97428C6.18028 8.95351 6.20845 8.88794 6.18645 8.82784C6.16444 8.76773 6.1006 8.73585 6.04385 8.75663C5.98711 8.7774 5.95894 8.84297 5.98094 8.90307Z" fill="#D1FEF9" />
<path d="M7.03975 8.92855C7.04944 8.955 7.07754 8.96903 7.10251 8.95989C7.12749 8.95075 7.13989 8.92189 7.13021 8.89543C7.12052 8.86898 7.09242 8.85495 7.06744 8.86409C7.04247 8.87324 7.03007 8.90209 7.03975 8.92855Z" fill="#D1FEF9" />
<path d="M6.58248 7.36299C6.60702 7.43001 6.6782 7.46557 6.74149 7.4424C6.80477 7.41923 6.83617 7.34612 6.81164 7.2791C6.7871 7.21208 6.71591 7.17653 6.65263 7.19969C6.58935 7.22286 6.55794 7.29597 6.58248 7.36299Z" fill="#D1FEF9" />
<path d="M5.01724 8.75554C5.04457 8.83021 5.12388 8.86981 5.19437 8.84401C5.26486 8.8182 5.29985 8.73675 5.27251 8.66209C5.24518 8.58743 5.16588 8.54782 5.09538 8.57363C5.02489 8.59944 4.9899 8.68088 5.01724 8.75554Z" fill="#D1FEF9" />
<path d="M6.9081 6.89962C6.91789 6.92636 6.9463 6.94055 6.97155 6.93131C6.9968 6.92206 7.00933 6.89289 6.99954 6.86614C6.98975 6.8394 6.96134 6.82521 6.93609 6.83446C6.91084 6.8437 6.89831 6.87287 6.9081 6.89962Z" fill="#D1FEF9" />
<path d="M14.7915 4.89137C14.7989 4.91176 14.8206 4.92257 14.8398 4.91552C14.8591 4.90847 14.8686 4.88624 14.8612 4.86586C14.8537 4.84547 14.8321 4.83466 14.8128 4.84171C14.7936 4.84875 14.784 4.87099 14.7915 4.89137Z" fill="#D1FEF9" />
<path d="M13.3571 5.89699C13.3786 5.9558 13.4411 5.987 13.4966 5.96667C13.5521 5.94634 13.5797 5.88219 13.5581 5.82339C13.5366 5.76458 13.4742 5.73338 13.4186 5.75371C13.3631 5.77403 13.3356 5.83819 13.3571 5.89699Z" fill="#D1FEF9" />
<path d="M12.4154 5.44996C12.4351 5.50387 12.4924 5.53246 12.5433 5.51383C12.5942 5.49519 12.6194 5.43639 12.5997 5.38249C12.58 5.32858 12.5227 5.29999 12.4718 5.31862C12.4209 5.33725 12.3957 5.39606 12.4154 5.44996Z" fill="#D1FEF9" />
<path d="M12.9364 4.88366C12.944 4.90463 12.9663 4.91575 12.9861 4.9085C13.0059 4.90126 13.0157 4.87839 13.008 4.85743C13.0004 4.83647 12.9781 4.82535 12.9583 4.83259C12.9385 4.83984 12.9287 4.8627 12.9364 4.88366Z" fill="#D1FEF9" />
<path d="M12.264 4.21598C12.2794 4.25807 12.3241 4.2804 12.3639 4.26585C12.4036 4.25131 12.4233 4.20539 12.4079 4.1633C12.3925 4.12121 12.3478 4.09889 12.3081 4.11344C12.2683 4.12799 12.2486 4.1739 12.264 4.21598Z" fill="#D1FEF9" />
<path d="M11.4433 5.17329C11.4718 5.25097 11.5543 5.29218 11.6277 5.26533C11.701 5.23848 11.7374 5.15373 11.709 5.07604C11.6805 4.99836 11.598 4.95715 11.5247 4.984C11.4513 5.01085 11.4149 5.0956 11.4433 5.17329Z" fill="#D1FEF9" />
<path d="M16.1661 5.69449C16.1877 5.75344 16.2503 5.78471 16.306 5.76433C16.3616 5.74396 16.3893 5.67965 16.3677 5.6207C16.3461 5.56175 16.2835 5.53048 16.2278 5.55086C16.1722 5.57123 16.1445 5.63554 16.1661 5.69449Z" fill="#D1FEF9" />
<path d="M15.4353 7.42838C15.4623 7.50218 15.5407 7.54133 15.6103 7.51582C15.68 7.49031 15.7146 7.40981 15.6876 7.33601C15.6606 7.26222 15.5822 7.22307 15.5125 7.24858C15.4428 7.27409 15.4083 7.35459 15.4353 7.42838Z" fill="#D1FEF9" />
<path d="M13.3636 7.58869C13.3763 7.62353 13.4133 7.64201 13.4462 7.62997C13.4791 7.61793 13.4954 7.57992 13.4827 7.54508C13.4699 7.51024 13.4329 7.49176 13.4 7.5038C13.3671 7.51584 13.3508 7.55385 13.3636 7.58869Z" fill="#D1FEF9" />
<path d="M14.1174 7.01527C14.1317 7.05444 14.1733 7.07523 14.2103 7.06169C14.2473 7.04815 14.2657 7.00541 14.2513 6.96623C14.237 6.92705 14.1954 6.90627 14.1584 6.91981C14.1214 6.93335 14.103 6.97609 14.1174 7.01527Z" fill="#D1FEF9" />
<path d="M8.74511 4.36372C8.75554 4.3922 8.78579 4.4073 8.81268 4.39746C8.83957 4.38761 8.85291 4.35655 8.84249 4.32807C8.83206 4.29959 8.80181 4.28448 8.77492 4.29433C8.74803 4.30417 8.73469 4.33524 8.74511 4.36372Z" fill="#D1FEF9" />
<path d="M15.1843 6.07016C15.2009 6.11556 15.2492 6.13965 15.292 6.12395C15.3349 6.10826 15.3562 6.05873 15.3395 6.01333C15.3229 5.96793 15.2747 5.94384 15.2318 5.95954C15.189 5.97523 15.1677 6.02476 15.1843 6.07016Z" fill="#D1FEF9" />
<path d="M8.65056 4.76258C8.6733 4.8247 8.73928 4.85766 8.79794 4.83619C8.85659 4.81471 8.8857 4.74695 8.86296 4.68482C8.84021 4.6227 8.77423 4.58975 8.71558 4.61122C8.65692 4.63269 8.62781 4.70046 8.65056 4.76258Z" fill="#D1FEF9" />
<path d="M24.0627 20.161C24.0887 20.1443 24.1004 20.1161 24.0887 20.098C24.0771 20.08 24.0467 20.0789 24.0207 20.0956C23.9947 20.1123 23.983 20.1404 23.9946 20.1585C24.0062 20.1766 24.0367 20.1777 24.0627 20.161Z" fill="#D1FEF9" />
<path d="M21.7612 17.3149C21.8175 17.2787 21.8427 17.2176 21.8176 17.1785C21.7924 17.1394 21.7264 17.137 21.6701 17.1732C21.6138 17.2094 21.5885 17.2704 21.6137 17.3096C21.6388 17.3487 21.7048 17.3511 21.7612 17.3149Z" fill="#D1FEF9" />
<path d="M24.1018 17.6507C24.1336 17.6302 24.1479 17.5957 24.1337 17.5735C24.1195 17.5514 24.0821 17.55 24.0502 17.5705C24.0184 17.591 24.0041 17.6255 24.0183 17.6477C24.0325 17.6698 24.0699 17.6712 24.1018 17.6507Z" fill="#D1FEF9" />
<path d="M23.8243 17.2853C23.8408 17.2747 23.8481 17.2569 23.8408 17.2455C23.8334 17.2341 23.8142 17.2334 23.7977 17.2439C23.7813 17.2545 23.7739 17.2723 23.7812 17.2837C23.7886 17.2952 23.8079 17.2959 23.8243 17.2853Z" fill="#D1FEF9" />
<path d="M23.1251 17.1272C23.1443 17.1148 23.153 17.0939 23.1444 17.0806C23.1358 17.0672 23.1132 17.0664 23.0939 17.0787C23.0747 17.0911 23.0661 17.112 23.0747 17.1254C23.0832 17.1388 23.1058 17.1396 23.1251 17.1272Z" fill="#D1FEF9" />
<path d="M23.5414 17.7611C23.5642 17.7465 23.5745 17.7217 23.5643 17.7058C23.5541 17.69 23.5273 17.689 23.5045 17.7037C23.4816 17.7184 23.4714 17.7431 23.4816 17.759C23.4918 17.7748 23.5186 17.7758 23.5414 17.7611Z" fill="#D1FEF9" />
<path d="M23.6982 18.3962C23.7194 18.3825 23.7289 18.3595 23.7195 18.3448C23.71 18.3301 23.6851 18.3292 23.6639 18.3428C23.6427 18.3564 23.6332 18.3794 23.6426 18.3942C23.6521 18.4089 23.677 18.4098 23.6982 18.3962Z" fill="#D1FEF9" />
<path d="M21.6627 17.75C21.684 17.7364 21.6936 17.7133 21.6841 17.6985C21.6746 17.6837 21.6496 17.6828 21.6283 17.6964C21.607 17.7101 21.5974 17.7332 21.6069 17.748C21.6165 17.7628 21.6414 17.7637 21.6627 17.75Z" fill="#D1FEF9" />
<path d="M21.4402 16.9173C21.466 16.9008 21.4776 16.8728 21.466 16.8548C21.4545 16.8369 21.4242 16.8358 21.3984 16.8524C21.3726 16.869 21.361 16.897 21.3726 16.9149C21.3841 16.9328 21.4144 16.9339 21.4402 16.9173Z" fill="#D1FEF9" />
<path d="M22.1882 18.7186C22.2244 18.6953 22.2407 18.6561 22.2245 18.6309C22.2083 18.6058 22.1659 18.6043 22.1297 18.6275C22.0935 18.6508 22.0773 18.69 22.0935 18.7152C22.1096 18.7403 22.1521 18.7418 22.1882 18.7186Z" fill="#D1FEF9" />
<path d="M22.5923 18.5555C22.6056 18.5469 22.6116 18.5325 22.6056 18.5233C22.5997 18.514 22.5841 18.5135 22.5708 18.522C22.5575 18.5306 22.5516 18.545 22.5575 18.5542C22.5634 18.5634 22.579 18.564 22.5923 18.5555Z" fill="#D1FEF9" />
<path d="M21.8579 17.9075C21.8732 17.8976 21.8801 17.881 21.8732 17.8704C21.8664 17.8597 21.8484 17.859 21.8331 17.8689C21.8177 17.8788 21.8108 17.8954 21.8177 17.906C21.8245 17.9167 21.8425 17.9173 21.8579 17.9075Z" fill="#D1FEF9" />
<path d="M21.4228 17.6865C21.4415 17.6745 21.4499 17.6543 21.4415 17.6413C21.4332 17.6283 21.4113 17.6276 21.3927 17.6395C21.374 17.6515 21.3656 17.6718 21.374 17.6847C21.3823 17.6977 21.4042 17.6985 21.4228 17.6865Z" fill="#D1FEF9" />
<path d="M0.689831 14.2559C0.729755 14.2302 0.747667 14.1869 0.729838 14.1592C0.712009 14.1315 0.66519 14.1298 0.625266 14.1554C0.585342 14.1811 0.567432 14.2244 0.585261 14.2521C0.60309 14.2799 0.649907 14.2815 0.689831 14.2559Z" fill="#D1FEF9" />
<path d="M0.2736 13.6829C0.292342 13.6709 0.300749 13.6506 0.292378 13.6375C0.284008 13.6245 0.262029 13.6237 0.243287 13.6358C0.224545 13.6478 0.216136 13.6681 0.224507 13.6812C0.232877 13.6942 0.254857 13.695 0.2736 13.6829Z" fill="#D1FEF9" />
<path d="M0.561061 14.4012C0.578696 14.3898 0.586609 14.3707 0.578733 14.3585C0.570857 14.3462 0.550176 14.3455 0.532541 14.3568C0.514906 14.3681 0.506995 14.3873 0.514871 14.3995C0.522746 14.4118 0.543426 14.4125 0.561061 14.4012Z" fill="#D1FEF9" />
<path d="M0.247276 13.9798C0.264144 13.969 0.271711 13.9507 0.264178 13.939C0.256644 13.9273 0.236864 13.9265 0.219995 13.9374C0.203127 13.9482 0.19556 13.9665 0.203093 13.9782C0.210627 13.99 0.230408 13.9907 0.247276 13.9798Z" fill="#D1FEF9" />
<path d="M0.473643 14.8514C0.499713 14.8346 0.511408 14.8064 0.499766 14.7882C0.488123 14.7701 0.457552 14.769 0.431482 14.7858C0.405412 14.8025 0.393715 14.8308 0.405358 14.8489C0.417 14.867 0.447573 14.8681 0.473643 14.8514Z" fill="#D1FEF9" />
<path d="M-31.0664 35.7671C-30.8823 35.0598 -33.0915 32.7442 -30.3037 30.1573C-29.2578 29.1868 -27.6473 29.605 -26.9635 29.14C-26.2797 28.6749 -26.832 27.396 -25.1751 24.315C-23.5181 21.2339 -21.6245 19.9841 -19.7571 20.1004C-17.8898 20.2166 -16.3644 20.9142 -15.286 21.8443C-15.251 19.7128 -14.5601 15.1649 -12.0774 14.0255C-8.9739 12.6013 -7.60626 14.0255 -6.58054 14.0255C-5.55482 14.0255 -5.60741 13.0082 -3.87158 12.2815C-2.13574 11.5549 -0.557701 12.6594 0.78363 12.2815C2.12496 11.9037 2.17756 10.305 4.22901 8.00882C6.28045 5.71259 7.75329 2.80596 14.4336 3.91048C21.114 5.015 23.5862 10.305 23.6914 13.4733C23.7966 16.6415 23.7703 16.3508 25.6903 18.3564C27.6102 20.362 25.6377 23.5011 25.6903 24.315C25.7429 25.1288 33.2649 25.7973 33.2649 35.7089" stroke="#5EE1EA" stroke-width="0.0719697" />
<path d="M19.7091 13.744C15.8048 13.744 14.2198 15.7564 13.4383 17.668C13.7899 18.0347 15.0035 18.7127 17.0907 18.2685C19.1779 17.8243 19.7098 15.0485 19.7091 13.744Z" fill="#D9D9D9" />
<mask id="mask1_802_3803" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="14" y="15" width="4" height="4">
<path d="M14.2304 16.9102C14.1334 17.9627 14.7088 18.8764 15.6627 18.9643C16.6167 19.0523 17.3495 18.2593 17.4466 17.2067C17.5436 16.1541 16.9076 15.235 16.0142 15.1526C15.1209 15.0702 14.3275 15.8576 14.2304 16.9102Z" fill="black" />
</mask>
<g mask="url(#mask1_802_3803)">
<path d="M19.7644 13.804C16.1945 12.4692 14.0964 15.8638 13.4935 17.728C13.8451 18.0947 15.0701 18.717 17.1573 18.2728C19.2445 17.8286 19.765 15.1085 19.7644 13.804Z" fill="black" />
</g>
<path d="M5.73062 10.3736C8.59696 11.8091 9.58844 15.009 9.16976 16.9229C8.6813 17.0625 7.30963 16.9827 5.73062 15.5473C4.15161 14.1118 5.0727 11.5 5.73062 10.3736Z" fill="#D9D9D9" />
<mask id="mask2_802_3803" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="5" y="13" width="5" height="5">
<path d="M9.10492 15.1133C9.10492 16.1704 8.44797 17.0273 7.49002 17.0273C6.53207 17.0273 5.87512 16.1704 5.87512 15.1133C5.87512 14.0563 6.59286 13.1994 7.49002 13.1994C8.38719 13.1994 9.10492 14.0563 9.10492 15.1133Z" fill="#4A36C3" />
</mask>
<g mask="url(#mask2_802_3803)">
<path d="M5.78555 10.4331C9.54169 11.0791 9.64337 15.0685 9.22469 16.9824C8.73624 17.122 7.36457 17.0423 5.78555 15.6068C4.20654 14.1713 5.12763 11.5596 5.78555 10.4331Z" fill="#4A36C3" />
</g>
<path d="M7.77164 14.1144C7.7835 14.1026 7.80367 14.1082 7.80777 14.1244L7.97244 14.7747C7.97401 14.7809 7.97822 14.786 7.98395 14.7888L8.60374 15.0894C8.61931 15.097 8.62012 15.1189 8.60516 15.1275L8.02188 15.4661C8.01614 15.4694 8.01226 15.4752 8.01133 15.4817L7.91912 16.1384C7.91676 16.1552 7.89689 16.1628 7.88389 16.1519L7.35699 15.7115C7.35222 15.7075 7.34596 15.7058 7.33982 15.7067L6.66129 15.8126C6.64455 15.8152 6.63146 15.7984 6.63809 15.7828L6.89754 15.1726C6.90014 15.1665 6.89979 15.1595 6.89659 15.1537L6.57125 14.563C6.56291 14.5478 6.57488 14.5295 6.59211 14.531L7.27818 14.5929C7.28452 14.5935 7.2908 14.5912 7.29532 14.5867L7.77164 14.1144Z" fill="#2D1D8E" />
</g>
<defs>
<radialGradient id="paint0_radial_802_3803" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(12.2114 4.21498) rotate(92.148) scale(30.147 61.0177)">
<stop stop-color="#15C4E9" stop-opacity="0.79" />
<stop offset="0.760998" stop-color="#1906EE" stop-opacity="0.5" />
<stop offset="1" stop-color="#59DFFC" stop-opacity="0" />
</radialGradient>
<linearGradient id="paint1_linear_802_3803" x1="13.3682" y1="2.16805" x2="16.196" y2="43.34" gradientUnits="userSpaceOnUse">
<stop stop-color="#8CFFEA" stop-opacity="0.36" />
<stop offset="0.78125" stop-color="#CDFF8C" stop-opacity="0" />
</linearGradient>
<linearGradient id="paint2_linear_802_3803" x1="12.5361" y1="1.46598" x2="20.7414" y2="27.7465" gradientUnits="userSpaceOnUse">
<stop stop-color="#CDFF8C" stop-opacity="0.36" />
<stop offset="0.78125" stop-color="#CDFF8C" stop-opacity="0" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -0,0 +1,50 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="12" fill="#F076FA" />
<mask id="mask0_802_3805" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
<circle cx="12" cy="12" r="12" fill="#D9D9D9" />
</mask>
<g mask="url(#mask0_802_3805)">
<path d="M0.888631 22.0665C0.888631 23.1711 1.58404 24.0665 2.68861 24.0665C3.79318 24.0665 4.12285 23.5979 4.68853 22.4665C4.88853 22.0666 5.48852 20.4666 5.48852 20.4666C5.48852 20.4666 4.72282 19.2971 4.28854 18.2666C3.77023 17.0367 3.08855 14.2666 3.08855 14.2666C2.48856 15.4666 0.888631 20.962 0.888631 22.0665Z" fill="#16CF89" />
<path d="M0.888631 22.0664C0.888631 23.1709 1.58404 24.0663 2.68861 24.0663C3.79318 24.0663 4.12285 23.5977 4.68853 22.4663C4.88853 22.0664 5.48852 20.4664 5.48852 20.4664C5.48852 20.4664 4.72282 19.2969 4.28854 18.2664C3.77023 17.0365 3.08855 14.2664 3.08855 14.2664C2.48856 15.4664 0.888631 20.9618 0.888631 22.0664Z" fill="url(#paint0_linear_802_3805)" />
<path d="M2.68781 15.2664C2.68781 15.2664 2.68855 19.2664 5.02614 21.6664C5.25177 21.0977 5.48852 20.4664 5.48852 20.4664C5.48852 20.4664 4.72282 19.2969 4.28854 18.2664C3.77023 17.0365 3.08855 14.2664 3.08855 14.2664C2.98176 14.48 2.84329 14.8297 2.68781 15.2664Z" fill="#278050" />
<path d="M18.4884 19.4666C18.4884 19.4666 17.3677 20.3373 16.4884 20.8666C15.4816 21.4726 13.4884 21.6666 13.4884 21.6666C13.4884 21.6666 13.3939 24.043 13.4884 24.9548C13.583 25.8665 13.6884 26.8665 13.6884 26.8665C13.6884 26.8665 13.1653 27.63 12.8884 28.0665C12.5017 28.6762 12.2884 29.6665 12.2884 29.6665L19.0884 29.6665C19.0884 29.6665 19.0839 28.4924 18.8884 27.7801C18.7721 27.3564 18.4884 26.7321 18.4884 26.7321C18.2884 25.4744 18.0884 24.8891 18.0884 23.8665C18.0884 22.8579 18.2884 20.6666 18.4884 19.4666Z" fill="url(#paint1_linear_802_3805)" />
<path d="M18.4885 19.6668C18.4885 19.6668 16.9678 21.7375 16.0886 22.2668C15.0817 22.8728 13.4886 21.6668 13.4886 21.6668C13.4886 21.6668 13.4394 22.9032 13.4474 23.9346C13.4489 24.1262 13.449 24.3029 13.4532 24.4668C13.4532 24.4668 15.8886 24.0668 18.2261 21.7107C18.2326 21.6463 18.2392 21.5818 18.2459 21.5173C18.3161 20.8482 18.4023 20.184 18.4885 19.6668Z" fill="#278050" />
<path d="M10.2883 22.0672C10.2883 22.0672 8.48835 21.7753 7.68836 21.2672C6.88837 20.7591 6.08837 20.0672 6.08837 20.0672C6.08837 20.0672 5.17264 22.0774 4.88839 24.0672C4.68839 25.4672 4.88839 26.8671 4.88839 26.8671C4.88839 26.8671 4.36528 27.6307 4.08839 28.0671C3.70163 28.6768 3.4884 29.6671 3.4884 29.6671L10.2883 29.6671C10.2883 29.6671 10.2838 28.493 10.0883 27.7807C9.97207 27.3571 9.68834 26.7327 9.68834 26.7327C9.28834 25.6672 9.68834 24.0672 9.68834 24.0672C9.68834 24.0672 10.0883 22.4672 10.2883 22.0672Z" fill="url(#paint2_linear_802_3805)" />
<path d="M10.2883 22.0672C10.2883 22.0672 8.48835 21.7753 7.68836 21.2672C6.88837 20.7591 6.08837 20.0672 6.08837 20.0672C6.08837 20.0672 5.80308 20.6935 5.50154 21.5929C5.50154 21.5929 5.48838 21.8672 6.68837 22.8672C7.88835 23.8672 9.60838 24.4672 9.60838 24.4672C9.64965 24.2219 9.68834 24.0672 9.68834 24.0672C9.68834 24.0672 10.0883 22.4672 10.2883 22.0672Z" fill="#278050" />
<circle cx="9.1999" cy="9.1999" r="9.1999" transform="matrix(-1 -8.74228e-08 -8.74228e-08 1 21.0879 5.66664)" fill="url(#paint3_linear_802_3805)" />
<rect width="5.80281" height="5.9876" rx="0.629083" transform="matrix(-0.686366 -0.727256 -0.727256 0.686366 12.2881 14.287)" fill="black" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.3113 13.2521L10.1312 12.0017C9.99873 11.9751 9.8595 11.9609 9.71585 11.9609C8.83221 11.9609 8.11587 12.4981 8.11587 13.1609C8.11587 13.8236 8.8322 14.3609 9.71585 14.3609C10.5586 14.3609 11.2491 13.8722 11.3113 13.2521Z" fill="white" />
<circle cx="9.1999" cy="9.1999" r="9.1999" transform="matrix(-1 -8.74228e-08 -8.74228e-08 1 21.0879 5.66664)" fill="url(#paint4_linear_802_3805)" />
<rect width="5.80281" height="5.9876" rx="0.629083" transform="matrix(-0.686366 -0.727256 -0.727256 0.686366 11.4883 14.287)" fill="black" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5112 13.252L9.33128 12.0017C9.19878 11.9751 9.0595 11.9609 8.91579 11.9609C8.03214 11.9609 7.31581 12.4981 7.31581 13.1609C7.31581 13.8236 8.03214 14.3609 8.91579 14.3609C9.75856 14.3609 10.4491 13.8722 10.5112 13.252Z" fill="white" />
<path d="M18.4886 21.2665C18.3286 21.2665 17.5553 17.2665 17.2886 15.6665C17.2886 15.6665 18.8219 19.1332 19.2886 20.4665L18.4886 21.2665Z" fill="#007156" />
<path d="M19.4883 23.2664C20.0539 24.3977 21.2883 24.6664 21.8883 24.4664C22.4883 24.2664 23.2883 23.8664 23.4882 22.6664C23.6882 21.4664 23.1209 19.6385 22.4883 17.2664C21.4883 14.4665 21.2883 13.4665 20.6883 12.2665L17.0883 14.8665C17.4883 16.2665 19.0883 22.4664 19.4883 23.2664Z" fill="url(#paint5_linear_802_3805)" />
</g>
<defs>
<linearGradient id="paint0_linear_802_3805" x1="2.48856" y1="16.2664" x2="1.88856" y2="24.0663" gradientUnits="userSpaceOnUse">
<stop stop-color="#1EB67C" />
<stop offset="1" stop-color="#1FF073" />
</linearGradient>
<linearGradient id="paint1_linear_802_3805" x1="15.8884" y1="23.6665" x2="15.8884" y2="29.6665" gradientUnits="userSpaceOnUse">
<stop stop-color="#14B678" />
<stop offset="0.8125" stop-color="#1FF073" />
</linearGradient>
<linearGradient id="paint2_linear_802_3805" x1="6.88837" y1="22.6672" x2="6.88836" y2="29.6671" gradientUnits="userSpaceOnUse">
<stop stop-color="#00AB6A" />
<stop offset="1" stop-color="#1FF073" />
</linearGradient>
<linearGradient id="paint3_linear_802_3805" x1="14.1999" y1="0.799991" x2="3.79996" y2="15.5998" gradientUnits="userSpaceOnUse">
<stop offset="0.234375" stop-color="#16CF89" />
<stop offset="1" stop-color="#14B578" />
</linearGradient>
<linearGradient id="paint4_linear_802_3805" x1="15.5998" y1="2.39998" x2="7.59992" y2="18.1998" gradientUnits="userSpaceOnUse">
<stop stop-color="#1FF073" />
<stop offset="1" stop-color="#04795D" />
</linearGradient>
<linearGradient id="paint5_linear_802_3805" x1="18.2883" y1="16.6664" x2="22.4882" y2="24.4664" gradientUnits="userSpaceOnUse">
<stop stop-color="#0FA866" />
<stop offset="0.994297" stop-color="#1FF073" />
<stop offset="0.994397" stop-color="#1EB57C" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -0,0 +1,18 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="12" fill="#98DE24" />
<mask id="mask0_802_3806" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
<circle cx="12" cy="12" r="12" fill="#D9D9D9" />
</mask>
<g mask="url(#mask0_802_3806)">
<path d="M11.2419 5.72486C17.5737 5.64156 18.696 13.7122 18.3934 15.1801C22.8125 16.2933 21.4953 20.141 20.2299 21.2151L20.2118 21.2304C19.3473 21.9643 17.3107 23.6933 13.5 24C9.66253 24.3089 5.76283 23.21 4.72142 22.8134C3.68001 22.4168 2.25934 22.1932 1.8536 19.5397C1.52901 17.417 3.31222 16.2371 4.11815 15.8806C4.25119 12.1545 4.91003 5.80817 11.2419 5.72486Z" fill="url(#paint0_linear_802_3806)" />
<ellipse cx="0.846336" cy="0.911439" rx="0.846336" ry="0.911439" transform="matrix(-0.914359 0.404904 0.404904 0.914359 16.0637 13.1708)" fill="#3B314F" />
<ellipse cx="0.846336" cy="0.911439" rx="0.846336" ry="0.911439" transform="matrix(-0.914359 0.404904 0.404904 0.914359 8.98706 13.1708)" fill="#3B314F" />
<path d="M20.0001 5.00003C20.3655 6.93178 20.8772 12.2833 20.0001 18.2351" stroke="#CF0A80" stroke-width="0.918557" stroke-linecap="round" />
</g>
<defs>
<linearGradient id="paint0_linear_802_3806" x1="14.7489" y1="6.37278" x2="10.2511" y2="24.2265" gradientUnits="userSpaceOnUse">
<stop stop-color="#F783F2" />
<stop offset="1" stop-color="#E040DA" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,32 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="12" fill="#7953F5" />
<mask id="mask0_802_3804" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
<circle cx="12" cy="12" r="12" fill="#D9D9D9" />
</mask>
<g mask="url(#mask0_802_3804)">
<path d="M22.289 13.9245C24.569 15.2838 19.6003 21.2452 18.8884 21.8363C16.5763 21.5498 17.8171 18.1535 17.8464 17.0701C20.6304 14.8783 20.6681 12.9582 22.289 13.9245Z" fill="url(#paint0_linear_802_3804)" />
<path d="M1.71126 13.9245C-0.568805 15.2838 4.39996 21.2452 5.11188 21.8363C7.4239 21.5498 6.18319 18.1535 6.15385 17.0701C3.36985 14.8783 3.33216 12.9582 1.71126 13.9245Z" fill="url(#paint1_linear_802_3804)" />
<rect x="4.81934" y="4.76291" width="14.2048" height="24.5704" rx="7.10239" fill="url(#paint2_linear_802_3804)" />
<path d="M12.1138 10.1089C15.3704 10.1089 17.8247 13.2146 17.8247 13.2146C17.8247 13.2146 15.3053 16.3202 12.1138 16.3202C8.92224 16.3202 6.40282 13.2146 6.40282 13.2146C6.40282 13.2146 8.85711 10.109 12.1138 10.1089Z" fill="white" />
<mask id="mask1_802_3804" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="6" y="10" width="12" height="7">
<path d="M12.1138 10.1088C15.3704 10.1088 17.8247 13.2145 17.8247 13.2145C17.8247 13.2145 15.3053 16.3201 12.1138 16.3201C8.92224 16.3201 6.40282 13.2144 6.40282 13.2144C6.40282 13.2144 8.85711 10.1089 12.1138 10.1088Z" fill="white" />
</mask>
<g mask="url(#mask1_802_3804)">
<circle cx="12.113" cy="13.2306" r="3.45873" fill="#240521" />
</g>
</g>
<defs>
<linearGradient id="paint0_linear_802_3804" x1="22.9707" y1="14.709" x2="17.3558" y2="20.9165" gradientUnits="userSpaceOnUse">
<stop stop-color="#E04D40" />
<stop offset="1" stop-color="#F15F56" />
</linearGradient>
<linearGradient id="paint1_linear_802_3804" x1="1.02957" y1="14.709" x2="6.64449" y2="20.9165" gradientUnits="userSpaceOnUse">
<stop stop-color="#E04D40" />
<stop offset="1" stop-color="#F15F56" />
</linearGradient>
<linearGradient id="paint2_linear_802_3804" x1="11.9217" y1="4.76291" x2="11.9217" y2="29.3333" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF7A77" />
<stop offset="1" stop-color="#DE5043" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" color="#000000" fill="none" stroke-width="1.5" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="m12.75 10.25v-6.5l-7 10h5.5v6.5l7-10z" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
</svg>

After

Width:  |  Height:  |  Size: 326 B

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24" height="24" fill="none" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g stroke="currentColor" stroke-linejoin="round" stroke-width="1.5">
<path d="M4.75 8L12 4.75L19.25 8L12 11.25L4.75 8Z" stroke-linecap="round"/>
<path d="M4.75 16L12 19.25L19.25 16" stroke-linecap="round"/>
<g>
<path d="m19.25 8v8"/>
<path d="m4.75 8v8"/>
<path d="M12 11.5V19"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 465 B

View File

@@ -12,11 +12,34 @@
* used to build the complete changelog.
*/
const crypto = require('crypto');
const shell = require('shelljs');
const child = require('child_process');
const { default: axios } = require('axios');
const args = require('minimist')(process.argv.slice(2));
const gdevelopTeamEmailHashes = [
'f653a53047057692be0951d839b7394357b398deebf9731c7b7fe106f3644e1062c08860a65a89f218d6ad3ad6b5c7876c5088a4fba92b5e801a198d5dbc7158',
'5e17262c55afd148038ee9e4b469dbc923422adfd768e717c6326a39cf29415163e15f85960cdbda2aeb3d751d610e25d594a7783f6801aec24403421deaf815',
];
const isMemberOfGDevelopTeam = ({ email, nickname }) => {
if (['4ian', 'AlexandreSi', 'ClementPasteau', 'D8H'].includes(nickname)) {
return true;
}
if (
gdevelopTeamEmailHashes.includes(
crypto
.createHash('sha512')
.update(email)
.digest('hex')
)
) {
return true;
}
return false;
};
if (!args['extensionsGitPath']) {
shell.echo(
'⚠️ You should pass --extensionsGitPath pointing to the git directory of GDevelop-extensions.'
@@ -237,9 +260,10 @@ const findAuthorNicknameInCommits = async commits => {
const formatCommitMessage = ({ commit, includeAuthor }) => {
const author =
includeAuthor &&
!['4ian', 'AlexandreSi', 'ClementPasteau, D8H'].includes(
commit.authorNickname
)
!isMemberOfGDevelopTeam({
email: commit.authorEmail,
nickname: commit.authorNickname,
})
? `(Thanks ${
commit.authorNickname
? '@' + commit.authorNickname
@@ -323,7 +347,14 @@ const outputChangelog = ({
.join('\n')
);
shell.echo(`\n## ⚙️ Extensions, 🎨 assets and 🕹 examples\n`);
shell.echo(`\n## 🐛 Bug fixes\n`);
shell.echo(
fixCommits
.map(commit => formatCommitMessage({ commit, includeAuthor: true }))
.join('\n')
);
shell.echo('\n## ⚙️ Extensions\n');
shell.echo(
extensionsCommits
? extensionsCommits
@@ -331,6 +362,7 @@ const outputChangelog = ({
.join('\n')
: 'TODO: Add extensions commits here.'
);
shell.echo('\n## 🎨 Assets\n');
shell.echo(
assetsCommits
? assetsCommits
@@ -338,6 +370,7 @@ const outputChangelog = ({
.join('\n')
: 'TODO: Add assets commits here.'
);
shell.echo('\n## 🕹 Examples\n');
shell.echo(
examplesCommits
? examplesCommits
@@ -346,13 +379,6 @@ const outputChangelog = ({
: 'TODO: Add examples commits here.'
);
shell.echo(`\n## 🐛 Bug fixes\n`);
shell.echo(
fixCommits
.map(commit => formatCommitMessage({ commit, includeAuthor: true }))
.join('\n')
);
if (devCommits.length > 0) {
shell.echo(`\n### 🛠 Internal changes (for developers)\n`);
shell.echo(

View File

@@ -247,12 +247,10 @@ const AssetPackInstallDialog = ({
onApply: () => {},
content: (
<AlertMessage kind="warning">
<Text>
<Trans>
You need to save this project as a cloud project to install
premium assets. Please save your project and try again.
</Trans>
</Text>
<Trans>
You need to save this project as a cloud project to install
premium assets. Please save your project and try again.
</Trans>
</AlertMessage>
),
}
@@ -270,13 +268,11 @@ const AssetPackInstallDialog = ({
onApply: () => {},
content: (
<AlertMessage kind="warning">
<Text>
<Trans>
You can only install up to {MAX_ASSETS_TO_INSTALL} assets at
once. Try filtering the assets you would like to install, or
install them one by one.
</Trans>
</Text>
<Trans>
You can only install up to {MAX_ASSETS_TO_INSTALL} assets at
once. Try filtering the assets you would like to install, or
install them one by one.
</Trans>
</AlertMessage>
),
}

View File

@@ -19,6 +19,7 @@ export type AssetStorePageState = {|
openedPrivateGameTemplateListingData: ?PrivateGameTemplateListingData,
selectedFolders: Array<string>,
filtersState: FiltersState,
pageBreakIndex?: ?number,
scrollPosition?: ?number,
displayAssets: boolean,
searchText?: string,

View File

@@ -36,7 +36,7 @@ import PrivateAssetPackAudioFilesDownloadButton from './PrivateAssets/PrivateAss
import { CorsAwareImage } from '../UI/CorsAwareImage';
import { Column, LargeSpacer, Line } from '../UI/Grid';
import Text from '../UI/Text';
import { ResponsiveLineStackLayout } from '../UI/Layout';
import { ResponsiveLineStackLayout, LineStackLayout } from '../UI/Layout';
import {
getUserPublicProfile,
type UserPublicProfile,
@@ -48,6 +48,8 @@ import Breadcrumbs from '../UI/Breadcrumbs';
import { getFolderTagsFromAssetShortHeaders } from './TagsHelper';
import { PrivateGameTemplateStoreContext } from './PrivateGameTemplates/PrivateGameTemplateStoreContext';
import { type AssetStorePageState } from './AssetStoreNavigator';
import RaisedButton from '../UI/RaisedButton';
import FlatButton from '../UI/FlatButton';
const ASSETS_DISPLAY_LIMIT = 250;
@@ -93,20 +95,38 @@ const getAssetFoldersColumns = (windowWidth: WidthType) => {
}
};
const getPageBreakAssetLowerIndex = (pageBreakIndex: number) =>
ASSETS_DISPLAY_LIMIT * pageBreakIndex;
const getPageBreakAssetUpperIndex = (pageBreakIndex: number) =>
ASSETS_DISPLAY_LIMIT * (pageBreakIndex + 1);
export const getAssetShortHeadersToDisplay = (
allAssetShortHeaders: AssetShortHeader[],
selectedFolders: string[]
selectedFolders: string[],
pageBreakIndex: number = 0
): AssetShortHeader[] => {
return allAssetShortHeaders
.filter(assetShortHeader => {
if (!selectedFolders.length) return true;
const allAssetTags = assetShortHeader.tags;
// Check that the asset has all the selected folders tags.
return selectedFolders.every(folderTag =>
allAssetTags.includes(folderTag)
);
})
.splice(0, ASSETS_DISPLAY_LIMIT); // Limit the number of displayed assets to avoid performance issues
let assetShortHeaders = allAssetShortHeaders.filter(assetShortHeader => {
if (!selectedFolders.length) return true;
const allAssetTags = assetShortHeader.tags;
// Check that the asset has all the selected folders tags.
return selectedFolders.every(folderTag => allAssetTags.includes(folderTag));
});
// Limit the number of displayed assets to avoid performance issues
const pageBreakAssetLowerIndex = getPageBreakAssetLowerIndex(pageBreakIndex);
const pageBreakAssetUpperIndex = Math.min(
getPageBreakAssetUpperIndex(pageBreakIndex),
assetShortHeaders.length
);
if (
pageBreakAssetLowerIndex !== 0 ||
pageBreakAssetUpperIndex !== assetShortHeaders.length
) {
assetShortHeaders = assetShortHeaders.slice(
pageBreakAssetLowerIndex,
pageBreakAssetUpperIndex
);
}
return assetShortHeaders;
};
const cellSpacing = 8;
@@ -130,6 +150,56 @@ const styles = {
},
};
type PageBreakNavigationProps = {|
currentPage: AssetStorePageState,
pageBreakIndex: number,
setPageBreakIndex: number => void,
assetShortHeaders: Array<AssetShortHeader>,
scrollView: ?ScrollViewInterface,
|};
const PageBreakNavigation = ({
currentPage,
pageBreakIndex,
setPageBreakIndex,
assetShortHeaders,
scrollView,
}: PageBreakNavigationProps) => {
return (
<Column>
<LineStackLayout justifyContent="center">
<FlatButton
key="previous-assets"
label={<Trans>Show previous assets</Trans>}
onClick={() => {
currentPage.pageBreakIndex = Math.max(
0,
(currentPage.pageBreakIndex || 0) - 1
);
setPageBreakIndex(currentPage.pageBreakIndex);
scrollView && scrollView.scrollToPosition(0);
}}
disabled={pageBreakIndex <= 0}
/>
<RaisedButton
key="next-assets"
primary
label={<Trans>Show next assets</Trans>}
onClick={() => {
currentPage.pageBreakIndex = (currentPage.pageBreakIndex || 0) + 1;
setPageBreakIndex(currentPage.pageBreakIndex);
scrollView && scrollView.scrollToPosition(0);
}}
disabled={
assetShortHeaders.length <
getPageBreakAssetUpperIndex(pageBreakIndex)
}
/>
</LineStackLayout>
</Column>
);
};
export type AssetsListInterface = {|
getScrollPosition: () => number,
scrollToPosition: (y: number) => void,
@@ -345,7 +415,8 @@ const AssetsList = React.forwardRef<Props, AssetsListInterface>(
if (
!allPrivateAssetPackListingDatas ||
!openedAssetPack ||
!openedAssetPack.id // public pack selected.
// public pack selected.
!openedAssetPack.id
)
return null;
@@ -359,14 +430,21 @@ const AssetsList = React.forwardRef<Props, AssetsListInterface>(
[allPrivateAssetPackListingDatas, openedAssetPack]
);
const [pageBreakIndex, setPageBreakIndex] = React.useState<number>(
(currentPage && currentPage.pageBreakIndex) || 0
);
const assetTiles = React.useMemo(
() => {
if (!assetShortHeaders) return null; // Loading
if (hasAssetPackFiltersApplied && !openedAssetPack) return []; // Don't show assets if filtering on asset packs.)
// Loading
if (!assetShortHeaders) return null;
// Don't show assets if filtering on asset packs.)
if (hasAssetPackFiltersApplied && !openedAssetPack) return [];
return getAssetShortHeadersToDisplay(
assetShortHeaders,
selectedFolders
selectedFolders,
pageBreakIndex
).map(assetShortHeader => (
<AssetCardTile
assetShortHeader={assetShortHeader}
@@ -379,11 +457,12 @@ const AssetsList = React.forwardRef<Props, AssetsListInterface>(
},
[
assetShortHeaders,
onOpenDetails,
windowWidth,
selectedFolders,
hasAssetPackFiltersApplied,
openedAssetPack,
selectedFolders,
pageBreakIndex,
windowWidth,
onOpenDetails,
]
);
@@ -392,7 +471,8 @@ const AssetsList = React.forwardRef<Props, AssetsListInterface>(
if (
!publicAssetPacks ||
!onPublicAssetPackSelection ||
hasAssetFiltersApplied // Don't show public packs if filtering on assets.
// Don't show public packs if filtering on assets.
hasAssetFiltersApplied
)
return [];
return publicAssetPacks.map((assetPack, index) => (
@@ -416,7 +496,8 @@ const AssetsList = React.forwardRef<Props, AssetsListInterface>(
if (
!privateAssetPackListingDatas ||
!receivedAssetPacks ||
hasAssetFiltersApplied // Don't show private packs if filtering on assets.
// Don't show private packs if filtering on assets.
hasAssetFiltersApplied
) {
return {
allStandAlonePackTiles: [],
@@ -490,8 +571,10 @@ const AssetsList = React.forwardRef<Props, AssetsListInterface>(
if (
!privateGameTemplateListingDatas ||
!onPrivateGameTemplateSelection ||
hasAssetFiltersApplied || // Don't show private game templates if filtering on assets.
hasAssetPackFiltersApplied // Don't show private game templates if filtering on asset packs.
// Don't show private game templates if filtering on assets.
hasAssetFiltersApplied ||
// Don't show private game templates if filtering on asset packs.
hasAssetPackFiltersApplied
)
return [];
@@ -594,7 +677,21 @@ const AssetsList = React.forwardRef<Props, AssetsListInterface>(
</Trans>
</PlaceholderError>
)}
{!openedAssetPack && gameTemplateTiles.length ? (
{currentPage &&
assetShortHeaders &&
assetShortHeaders.length > getPageBreakAssetUpperIndex(0) &&
pageBreakIndex > 0 && (
<PageBreakNavigation
currentPage={currentPage}
pageBreakIndex={pageBreakIndex}
setPageBreakIndex={setPageBreakIndex}
assetShortHeaders={assetShortHeaders}
scrollView={scrollView.current}
/>
)}
{!openedAssetPack &&
gameTemplateTiles.length &&
pageBreakIndex === 0 ? (
<Line expand>
<Column noMargin expand>
<GridList
@@ -608,7 +705,9 @@ const AssetsList = React.forwardRef<Props, AssetsListInterface>(
</Column>
</Line>
) : null}
{!openedAssetPack && allBundlePackTiles.length ? (
{!openedAssetPack &&
allBundlePackTiles.length &&
pageBreakIndex === 0 ? (
<Line expand>
<Column noMargin expand>
<GridList
@@ -622,7 +721,9 @@ const AssetsList = React.forwardRef<Props, AssetsListInterface>(
</Column>
</Line>
) : null}
{!openedAssetPack && allStandAlonePackTiles.length ? (
{!openedAssetPack &&
allStandAlonePackTiles.length &&
pageBreakIndex === 0 ? (
<Line expand>
<Column noMargin expand>
<GridList
@@ -767,14 +868,20 @@ const AssetsList = React.forwardRef<Props, AssetsListInterface>(
assetPack={openedAssetPack}
/>
) : null}
{assetTiles && // loading is finished.
!assetTiles.length && // No assets to show.
!allBundlePackTiles.length && // No bundles to show.
!allStandAlonePackTiles.length && // No packs to show.
!gameTemplateTiles.length && // no templates to show.
(!openedAssetPack ||
!openedAssetPack.content ||
!isAssetPackAudioOnly(openedAssetPack)) && // It's not an audio pack.
{// loading is finished.
assetTiles &&
// No assets to show.
!assetTiles.length &&
// No bundles to show.
!allBundlePackTiles.length &&
// No packs to show.
!allStandAlonePackTiles.length &&
// no templates to show.
!gameTemplateTiles.length &&
(!openedAssetPack ||
!openedAssetPack.content ||
// It's not an audio pack.
!isAssetPackAudioOnly(openedAssetPack)) &&
noResultComponent}
{onPrivateAssetPackSelection &&
openAuthorPublicProfileDialog &&
@@ -789,6 +896,18 @@ const AssetsList = React.forwardRef<Props, AssetsListInterface>(
}}
/>
)}
{currentPage &&
assetShortHeaders &&
assetShortHeaders.length > getPageBreakAssetUpperIndex(0) && (
<PageBreakNavigation
currentPage={currentPage}
pageBreakIndex={pageBreakIndex}
setPageBreakIndex={setPageBreakIndex}
assetShortHeaders={assetShortHeaders}
scrollView={scrollView.current}
/>
)}
</ScrollView>
);
}

View File

@@ -219,6 +219,38 @@ export const ExampleStore = ({
[exampleFilters, gameTemplateFilters]
);
const privateGameTemplateListingDatasFromSameCreator: ?Array<PrivateGameTemplateListingData> = React.useMemo(
() => {
if (
!selectedPrivateGameTemplateListingData ||
!privateGameTemplateListingDatasSearchResults ||
!receivedGameTemplates
)
return null;
const receivedGameTemplateIds = receivedGameTemplates.map(
template => template.id
);
return privateGameTemplateListingDatasSearchResults
.map(({ item }) => item)
.filter(
template =>
template.sellerId ===
selectedPrivateGameTemplateListingData.sellerId &&
!receivedGameTemplateIds.includes(template.sellerId)
)
.sort((template1, template2) =>
template1.name.localeCompare(template2.name)
);
},
[
selectedPrivateGameTemplateListingData,
privateGameTemplateListingDatasSearchResults,
receivedGameTemplates,
]
);
return (
<React.Fragment>
<ResponsiveWindowMeasurer>
@@ -316,13 +348,17 @@ export const ExampleStore = ({
selectedPrivateGameTemplateListingData
}
isPurchaseDialogOpen={!!purchasingGameTemplateListingData}
onGameTemplateOpen={onOpenNewProjectSetupDialog}
onCreateWithGameTemplate={onOpenNewProjectSetupDialog}
onGameTemplateOpen={onSelectPrivateGameTemplateListingData}
onOpenPurchaseDialog={() => {
setPurchasingGameTemplateListingData(
selectedPrivateGameTemplateListingData
);
}}
onClose={() => onSelectPrivateGameTemplateListingData(null)}
privateGameTemplateListingDatasFromSameCreator={
privateGameTemplateListingDatasFromSameCreator
}
/>
)}
{!!purchasingGameTemplateListingData && (

View File

@@ -3,7 +3,7 @@ import {
type Asset,
isPixelArt,
isPublicAssetResourceUrl,
extractFilenameWithExtensionFromPublicAssetResourceUrl,
extractDecodedFilenameWithExtensionFromPublicAssetResourceUrl,
} from '../Utils/GDevelopServices/Asset';
import newNameGenerator from '../Utils/NewNameGenerator';
import { unserializeFromJSObject } from '../Utils/Serializer';
@@ -81,7 +81,9 @@ export const installResource = (
const resourceOriginCleanedName: string = isPublicAssetResourceUrl(
resourceFileUrl
)
? extractFilenameWithExtensionFromPublicAssetResourceUrl(resourceFileUrl)
? extractDecodedFilenameWithExtensionFromPublicAssetResourceUrl(
resourceFileUrl
)
: resourceOriginRawName;
const resourceOriginIdentifier: string = serializedResource.origin
? serializedResource.origin.identifier

View File

@@ -335,11 +335,17 @@ function NewObjectDialog({
<RaisedButton
key="add-all-assets"
primary
label={<Trans>Add all assets to my scene</Trans>}
label={
displayedAssetShortHeaders.length === 1 ? (
<Trans>Add this asset to my scene</Trans>
) : (
<Trans>Add these assets to my scene</Trans>
)
}
onClick={() => setIsAssetPackDialogInstallOpen(true)}
disabled={
!assetShortHeadersSearchResults ||
assetShortHeadersSearchResults.length === 0
!displayedAssetShortHeaders ||
displayedAssetShortHeaders.length === 0
}
/>
) : openedAssetShortHeader ? (

View File

@@ -36,16 +36,13 @@ const ObjectListItem = ({
return null;
}
// For some reason, iconFileName can sometimes be undefined. see https://github.com/4ian/GDevelop/issues/6094.
const iconFilename = enumeratedObjectMetadata.iconFilename || '';
return (
<ListItem
id={id}
leftIcon={
<ListIcon
src={enumeratedObjectMetadata.iconFilename}
iconSize={40}
isGDevelopIcon
/>
}
leftIcon={<ListIcon src={iconFilename} iconSize={40} isGDevelopIcon />}
key={enumeratedObjectMetadata.name}
primaryText={enumeratedObjectMetadata.fullName}
secondaryText={enumeratedObjectMetadata.description}

View File

@@ -92,7 +92,7 @@ const styles = {
type Props = {|
privateAssetPackListingData: PrivateAssetPackListingData,
privateAssetPacksFromSameCreatorListingData?: ?Array<PrivateAssetPackListingData>,
privateAssetPackListingDatasFromSameCreator?: ?Array<PrivateAssetPackListingData>,
onOpenPurchaseDialog: () => void,
isPurchaseDialogOpen: boolean,
onAssetPackOpen: PrivateAssetPackListingData => void,
@@ -101,7 +101,7 @@ type Props = {|
const PrivateAssetPackInformationPage = ({
privateAssetPackListingData,
privateAssetPacksFromSameCreatorListingData,
privateAssetPackListingDatasFromSameCreator,
onOpenPurchaseDialog,
isPurchaseDialogOpen,
onAssetPackOpen,
@@ -240,15 +240,15 @@ const PrivateAssetPackInformationPage = ({
const otherPacksFromTheSameAuthorTiles = React.useMemo(
() => {
if (
!privateAssetPacksFromSameCreatorListingData ||
!privateAssetPackListingDatasFromSameCreator ||
// Only display packs if there are at least 2. If there is only one,
// it means it's the same as the one currently opened.
privateAssetPacksFromSameCreatorListingData.length < 2
privateAssetPackListingDatasFromSameCreator.length < 2
)
return null;
return (
privateAssetPacksFromSameCreatorListingData
privateAssetPackListingDatasFromSameCreator
// Do not display the pack currently opened.
.filter(
assetPackFromSameCreator => assetPackFromSameCreator.id !== id
@@ -272,7 +272,7 @@ const PrivateAssetPackInformationPage = ({
},
[
id,
privateAssetPacksFromSameCreatorListingData,
privateAssetPackListingDatasFromSameCreator,
onAssetPackOpen,
receivedAssetPacks,
]

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