mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
73 Commits
remove-fra
...
v5.1.147
Author | SHA1 | Date | |
---|---|---|---|
![]() |
78cbe48718 | ||
![]() |
e153d295de | ||
![]() |
1b8510655e | ||
![]() |
bd88127563 | ||
![]() |
01b9f09604 | ||
![]() |
0db30f02c9 | ||
![]() |
a852e91690 | ||
![]() |
79d6281061 | ||
![]() |
eba6b2540c | ||
![]() |
0706a54305 | ||
![]() |
d929fd6e48 | ||
![]() |
4dbabab052 | ||
![]() |
827c5d6442 | ||
![]() |
46be0e0ffc | ||
![]() |
72e3cf5b99 | ||
![]() |
54f32a2542 | ||
![]() |
b826f66455 | ||
![]() |
6fc03cccc6 | ||
![]() |
ed7313a330 | ||
![]() |
7390f7cd6a | ||
![]() |
4619ae824b | ||
![]() |
0f69ee435f | ||
![]() |
f46241d5a2 | ||
![]() |
4c8ec48004 | ||
![]() |
3ac121be4c | ||
![]() |
3aa636861c | ||
![]() |
6d4b422be6 | ||
![]() |
b8ee27f62c | ||
![]() |
6996ff452d | ||
![]() |
da7934c6ac | ||
![]() |
90bebcb404 | ||
![]() |
a29e7aae44 | ||
![]() |
52201e2a36 | ||
![]() |
50465badd7 | ||
![]() |
6e1bfb0190 | ||
![]() |
40c7c57670 | ||
![]() |
e51c73b293 | ||
![]() |
29d5d5fe75 | ||
![]() |
6e1f2c4eee | ||
![]() |
2f2a89faf6 | ||
![]() |
4100b24dfd | ||
![]() |
c616abe1c5 | ||
![]() |
35084de4f6 | ||
![]() |
6ecb5e9d8c | ||
![]() |
9532a8f6de | ||
![]() |
00a5b0b402 | ||
![]() |
629567ad21 | ||
![]() |
5f21229ccc | ||
![]() |
27cf2ef596 | ||
![]() |
2bc9a6d19d | ||
![]() |
c6c586459c | ||
![]() |
a930011d8d | ||
![]() |
51d723bd3d | ||
![]() |
b63f968011 | ||
![]() |
3387c553d8 | ||
![]() |
441cd20846 | ||
![]() |
f9871bd63d | ||
![]() |
bac11b3818 | ||
![]() |
3e32cb8cea | ||
![]() |
db74a59730 | ||
![]() |
e7d09531b7 | ||
![]() |
97cf19180b | ||
![]() |
5cc999c0a3 | ||
![]() |
5eb0aa9e14 | ||
![]() |
7f528649d7 | ||
![]() |
c4f44daa8c | ||
![]() |
7d00e78628 | ||
![]() |
887ced270a | ||
![]() |
b8e9bc801a | ||
![]() |
7f023e1a58 | ||
![]() |
6606ddb260 | ||
![]() |
a682c1baa8 | ||
![]() |
d581af20e1 |
19
.github/ISSUE_TEMPLATE/--asset-store-submission.md
vendored
Normal file
19
.github/ISSUE_TEMPLATE/--asset-store-submission.md
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
name: "📦 Asset Store submission"
|
||||
about: Submit a free asset pack for the GDevelop Asset Store.
|
||||
title: ''
|
||||
labels: "📦 Asset Store submission"
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
BEFORE opening a new submission, please make sure that you:
|
||||
|
||||
- You have packaged the asset pack according [these rules](https://wiki.gdevelop.io/gdevelop5/community/contribute-to-the-assets-store). Otherwise, your package may be rejected or we will ask you to do the changes.
|
||||
|
||||
## Description
|
||||
|
||||
- License:
|
||||
- Author:
|
||||
- Link to the original website:
|
||||
- Zip file:
|
@@ -28,7 +28,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Movement using forces"))
|
||||
.SetIcon("res/actions/force24.png");
|
||||
|
||||
gd::ObjectMetadata& obj = extension.AddObject<gd::Object>(
|
||||
gd::ObjectMetadata& obj = extension.AddObject<gd::ObjectConfiguration>(
|
||||
"", _("Base object"), _("Base object"), "res/objeticon24.png");
|
||||
|
||||
obj.AddCondition("PosX",
|
||||
@@ -36,8 +36,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Compare the X position of the object."),
|
||||
_("the X position"),
|
||||
_("Position"),
|
||||
"res/conditions/position24.png",
|
||||
"res/conditions/position.png")
|
||||
"res/conditions/position24_black.png",
|
||||
"res/conditions/position_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
@@ -48,8 +48,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Change the X position of an object."),
|
||||
_("the X position"),
|
||||
_("Position"),
|
||||
"res/actions/position24.png",
|
||||
"res/actions/position.png")
|
||||
"res/actions/position24_black.png",
|
||||
"res/actions/position_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.UseStandardOperatorParameters("number")
|
||||
@@ -60,8 +60,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Compare the Y position of an object."),
|
||||
_("the Y position"),
|
||||
_("Position"),
|
||||
"res/conditions/position24.png",
|
||||
"res/conditions/position.png")
|
||||
"res/conditions/position24_black.png",
|
||||
"res/conditions/position_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
@@ -72,8 +72,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Change the Y position of an object."),
|
||||
_("the Y position"),
|
||||
_("Position"),
|
||||
"res/actions/position24.png",
|
||||
"res/actions/position.png")
|
||||
"res/actions/position24_black.png",
|
||||
"res/actions/position_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.UseStandardOperatorParameters("number")
|
||||
@@ -85,8 +85,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Change the position of _PARAM0_: _PARAM1_ _PARAM2_ (x "
|
||||
"axis), _PARAM3_ _PARAM4_ (y axis)"),
|
||||
_("Position"),
|
||||
"res/actions/position24.png",
|
||||
"res/actions/position.png")
|
||||
"res/actions/position24_black.png",
|
||||
"res/actions/position_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("operator", _("Modification's sign"), "number")
|
||||
@@ -102,8 +102,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"_PARAM2_ (x "
|
||||
"axis), _PARAM3_ _PARAM4_ (y axis)"),
|
||||
_("Position/Center"),
|
||||
"res/actions/position24.png",
|
||||
"res/actions/position.png")
|
||||
"res/actions/position24_black.png",
|
||||
"res/actions/position_black.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("operator", _("Modification's sign"), "number")
|
||||
.AddParameter("expression", _("X position"))
|
||||
@@ -118,7 +118,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("the X position of the center of rotation"),
|
||||
_("the X position of the center"),
|
||||
_("Position/Center"),
|
||||
"res/actions/position24.png")
|
||||
"res/actions/position24_black.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.UseStandardParameters("number");
|
||||
|
||||
@@ -129,7 +129,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("the Y position of the center of rotation"),
|
||||
_("the Y position of the center"),
|
||||
_("Position/Center"),
|
||||
"res/actions/position24.png")
|
||||
"res/actions/position24_black.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.UseStandardParameters("number");
|
||||
|
||||
@@ -140,7 +140,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"the object) left position"),
|
||||
_("the bounding box left position"),
|
||||
_("Position/Bounding Box"),
|
||||
"res/conditions/bounding-box-left.svg")
|
||||
"res/conditions/bounding-box-left_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.UseStandardParameters("number");
|
||||
|
||||
@@ -151,7 +151,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("the bounding box (the area encapsulating the object) top position"),
|
||||
_("the bounding box top position"),
|
||||
_("Position/Bounding Box"),
|
||||
"res/conditions/bounding-box-top.svg")
|
||||
"res/conditions/bounding-box-top_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.UseStandardParameters("number");
|
||||
|
||||
@@ -162,7 +162,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"the object) right position"),
|
||||
_("the bounding box right position"),
|
||||
_("Position/Bounding Box"),
|
||||
"res/conditions/bounding-box-right.svg")
|
||||
"res/conditions/bounding-box-right_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.UseStandardParameters("number");
|
||||
|
||||
@@ -173,7 +173,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"the object) bottom position"),
|
||||
_("the bounding box bottom position"),
|
||||
_("Position/Bounding Box"),
|
||||
"res/conditions/bounding-box-bottom.svg")
|
||||
"res/conditions/bounding-box-bottom_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.UseStandardParameters("number");
|
||||
|
||||
@@ -184,7 +184,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"the object) center X position"),
|
||||
_("the bounding box center X position"),
|
||||
_("Position/Bounding Box"),
|
||||
"res/conditions/bounding-box-center.svg")
|
||||
"res/conditions/bounding-box-center_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.UseStandardParameters("number");
|
||||
|
||||
@@ -195,7 +195,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"the object) center Y position"),
|
||||
_("the bounding box center Y position"),
|
||||
_("Position/Bounding Box"),
|
||||
"res/conditions/bounding-box-center.svg")
|
||||
"res/conditions/bounding-box-center_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.UseStandardParameters("number");
|
||||
|
||||
@@ -222,8 +222,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Change the angle of rotation of an object (in degrees)."),
|
||||
_("the angle"),
|
||||
_("Angle"),
|
||||
"res/actions/direction24.png",
|
||||
"res/actions/direction.png")
|
||||
"res/actions/direction24_black.png",
|
||||
"res/actions/direction_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.UseStandardOperatorParameters("number");
|
||||
@@ -234,8 +234,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"counterclockwise otherwise."),
|
||||
_("Rotate _PARAM0_ at speed _PARAM1_ deg/second"),
|
||||
_("Angle"),
|
||||
"res/actions/direction24.png",
|
||||
"res/actions/direction.png")
|
||||
"res/actions/rotate24_black.png",
|
||||
"res/actions/rotate_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("expression", _("Angular speed (in degrees per second)"))
|
||||
@@ -248,8 +248,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Rotate an object towards an angle with the specified speed."),
|
||||
_("Rotate _PARAM0_ towards _PARAM1_ at speed _PARAM2_ deg/second"),
|
||||
_("Angle"),
|
||||
"res/actions/direction24.png",
|
||||
"res/actions/direction.png")
|
||||
"res/actions/rotate24_black.png",
|
||||
"res/actions/rotate_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("expression", _("Angle to rotate towards (in degrees)"))
|
||||
@@ -264,8 +264,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Rotate _PARAM0_ towards _PARAM1_;_PARAM2_ at speed "
|
||||
"_PARAM3_ deg/second"),
|
||||
_("Angle"),
|
||||
"res/actions/direction24.png",
|
||||
"res/actions/direction.png")
|
||||
"res/actions/rotate24_black.png",
|
||||
"res/actions/rotate_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("expression", _("X position"))
|
||||
@@ -512,8 +512,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Compare the angle of the specified object."),
|
||||
_("the angle (in degrees)"),
|
||||
_("Angle"),
|
||||
"res/conditions/direction24.png",
|
||||
"res/conditions/direction.png")
|
||||
"res/conditions/direction24_black.png",
|
||||
"res/conditions/direction_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
@@ -965,21 +965,21 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("X position"),
|
||||
_("X position of the object"),
|
||||
_("Position"),
|
||||
"res/actions/position.png")
|
||||
"res/actions/position_black.png")
|
||||
.AddParameter("object", _("Object"));
|
||||
|
||||
obj.AddExpression("Y",
|
||||
_("Y position"),
|
||||
_("Y position of the object"),
|
||||
_("Position"),
|
||||
"res/actions/position.png")
|
||||
"res/actions/position_black.png")
|
||||
.AddParameter("object", _("Object"));
|
||||
|
||||
obj.AddExpression("Angle",
|
||||
_("Angle"),
|
||||
_("Current angle, in degrees, of the object"),
|
||||
_("Angle"),
|
||||
"res/actions/direction.png")
|
||||
"res/actions/direction_black.png")
|
||||
.AddParameter("object", _("Object"));
|
||||
|
||||
obj.AddExpression("ForceX",
|
||||
@@ -1022,14 +1022,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Width"),
|
||||
_("Width of the object"),
|
||||
_("Size"),
|
||||
"res/actions/scaleWidth.png")
|
||||
"res/actions/scaleWidth_black.png")
|
||||
.AddParameter("object", _("Object"));
|
||||
|
||||
obj.AddExpression("Largeur",
|
||||
_("Width"),
|
||||
_("Width of the object"),
|
||||
_("Size"),
|
||||
"res/actions/scaleWidth.png")
|
||||
"res/actions/scaleWidth_black.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.SetHidden();
|
||||
|
||||
@@ -1037,14 +1037,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Height"),
|
||||
_("Height of the object"),
|
||||
_("Size"),
|
||||
"res/actions/scaleHeight.png")
|
||||
"res/actions/scaleHeight_black.png")
|
||||
.AddParameter("object", _("Object"));
|
||||
|
||||
obj.AddExpression("Hauteur",
|
||||
_("Height"),
|
||||
_("Height of the object"),
|
||||
_("Size"),
|
||||
"res/actions/scaleHeight.png")
|
||||
"res/actions/scaleHeight_black.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.SetHidden();
|
||||
|
||||
@@ -1135,7 +1135,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"If you need the angle to an arbitrary position, "
|
||||
"use AngleToPosition."),
|
||||
_("Angle"),
|
||||
"res/actions/position.png")
|
||||
"res/actions/position_black.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectPtr", _("Object"));
|
||||
|
||||
@@ -1146,7 +1146,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"getting the cartesian coordinates of a 2D vector, using "
|
||||
"its polar coordinates."),
|
||||
_("Position"),
|
||||
"res/actions/position.png")
|
||||
"res/actions/position_black.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("expression", _("Angle, in degrees"))
|
||||
.AddParameter("expression", _("Distance"));
|
||||
@@ -1158,7 +1158,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"getting the cartesian coordinates of a 2D vector, using "
|
||||
"its polar coordinates."),
|
||||
_("Position"),
|
||||
"res/actions/position.png")
|
||||
"res/actions/position_black.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("expression", _("Angle, in degrees"))
|
||||
.AddParameter("expression", _("Distance"));
|
||||
@@ -1169,7 +1169,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"\"target\" position (in degrees). If you need the angle "
|
||||
"between two objects, use AngleToObject."),
|
||||
_("Angle"),
|
||||
"res/actions/position.png")
|
||||
"res/actions/position_black.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("expression", _("Target X position"))
|
||||
.AddParameter("expression", _("Target Y position"));
|
||||
@@ -1565,7 +1565,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Object name"),
|
||||
_("Return the name of the object"),
|
||||
"",
|
||||
"res/conditions/text.png")
|
||||
"res/conditions/text_black.png")
|
||||
.AddParameter("object", _("Object"));
|
||||
|
||||
obj.AddStrExpression("Layer",
|
||||
|
@@ -22,6 +22,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"object or a position.",
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("Camera")
|
||||
.SetExtensionHelpPath("/interface/scene-editor/layers-and-cameras");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Layers and cameras"))
|
||||
.SetIcon("res/conditions/camera24.png");
|
||||
|
@@ -21,14 +21,14 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/common-conversions");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Conversion"))
|
||||
.SetIcon("res/conditions/toujours24.png");
|
||||
.SetIcon("res/conditions/toujours24_black.png");
|
||||
|
||||
extension
|
||||
.AddExpression("ToNumber",
|
||||
_("Text > Number"),
|
||||
_("Convert the text to a number"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
.AddParameter("string", _("Text to convert to a number"));
|
||||
|
||||
extension
|
||||
@@ -36,7 +36,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
_("Number > Text"),
|
||||
_("Convert the result of the expression to text"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
.AddParameter("expression", _("Expression to be converted to text"));
|
||||
|
||||
extension
|
||||
@@ -45,7 +45,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
_("Convert the result of the expression to text, "
|
||||
"without using the scientific notation"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
.AddParameter("expression", _("Expression to be converted to text"));
|
||||
|
||||
extension
|
||||
@@ -54,7 +54,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
_("Degrees > Radians"),
|
||||
_("Converts the angle, expressed in degrees, into radians"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
.AddParameter("expression", _("Angle, in degrees"));
|
||||
|
||||
extension
|
||||
@@ -63,7 +63,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
_("Radians > Degrees"),
|
||||
_("Converts the angle, expressed in radians, into degrees"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
.AddParameter("expression", _("Angle, in radians"));
|
||||
|
||||
extension
|
||||
@@ -71,7 +71,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
_("Convert scene variable to JSON"),
|
||||
_("Convert a scene variable to JSON"),
|
||||
_("JSON"),
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
.AddParameter("scenevar", _("Scene variable to be stringified"));
|
||||
|
||||
extension
|
||||
@@ -79,7 +79,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
_("Convert global variable to JSON"),
|
||||
_("Convert a global variable to JSON"),
|
||||
_("JSON"),
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
.AddParameter("globalvar", _("The global variable to be stringified"));
|
||||
|
||||
extension
|
||||
@@ -87,7 +87,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
_("Convert object variable to JSON"),
|
||||
_("Convert an object variable to JSON"),
|
||||
_("JSON"),
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
.AddParameter("objectPtr", _("The object with the variable"))
|
||||
.AddParameter("objectvar", _("The object variable to be stringified"));
|
||||
|
||||
|
@@ -33,7 +33,7 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
|
||||
.SetExtensionHelpPath("/all-features/advanced-conditions");
|
||||
extension
|
||||
.AddInstructionOrExpressionGroupMetadata(_("Events and control flow"))
|
||||
.SetIcon("res/conditions/toujours24.png");
|
||||
.SetIcon("res/conditions/toujours24_black.png");
|
||||
|
||||
extension
|
||||
.AddCondition("Always",
|
||||
@@ -42,8 +42,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
|
||||
"the condition is inverted)."),
|
||||
_("Always"),
|
||||
"",
|
||||
"res/conditions/toujours24.png",
|
||||
"res/conditions/toujours.png")
|
||||
"res/conditions/toujours24_black.png",
|
||||
"res/conditions/toujours_black.png")
|
||||
.SetHelpPath("/all-features/advanced-conditions")
|
||||
.AddCodeOnlyParameter("conditionInverted", "")
|
||||
.MarkAsAdvanced();
|
||||
@@ -61,8 +61,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
|
||||
_("Check if one of the sub conditions is true"),
|
||||
_("If one of these conditions is true:"),
|
||||
"",
|
||||
"res/conditions/or24.png",
|
||||
"res/conditions/or.png")
|
||||
"res/conditions/or24_black.png",
|
||||
"res/conditions/or_black.png")
|
||||
.SetCanHaveSubInstructions()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -72,8 +72,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
|
||||
_("Check if all sub conditions are true"),
|
||||
_("If all of these conditions are true:"),
|
||||
"",
|
||||
"res/conditions/and24.png",
|
||||
"res/conditions/and.png")
|
||||
"res/conditions/and24_black.png",
|
||||
"res/conditions/and_black.png")
|
||||
.SetCanHaveSubInstructions()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -84,8 +84,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
|
||||
_("Return the contrary of the result of the sub conditions"),
|
||||
_("Invert the logical result of these conditions:"),
|
||||
"",
|
||||
"res/conditions/not24.png",
|
||||
"res/conditions/not.png")
|
||||
"res/conditions/not24_black.png",
|
||||
"res/conditions/not_black.png")
|
||||
.SetCanHaveSubInstructions()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -104,8 +104,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
|
||||
_("Compare the two numbers."),
|
||||
_("_PARAM0_ _PARAM1_ _PARAM2_"),
|
||||
"",
|
||||
"res/conditions/egal24.png",
|
||||
"res/conditions/egal.png")
|
||||
"res/conditions/egal24_black.png",
|
||||
"res/conditions/egal_black.png")
|
||||
.SetHelpPath("/all-features/advanced-conditions")
|
||||
.AddParameter("expression", _("First expression"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"), "number")
|
||||
@@ -125,8 +125,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
|
||||
_("Compare the two strings."),
|
||||
_("_PARAM0_ _PARAM1_ _PARAM2_"),
|
||||
"",
|
||||
"res/conditions/egal24.png",
|
||||
"res/conditions/egal.png")
|
||||
"res/conditions/egal24_black.png",
|
||||
"res/conditions/egal_black.png")
|
||||
.SetHelpPath("/all-features/advanced-conditions")
|
||||
.AddParameter("string", _("First string expression"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"), "string")
|
||||
|
@@ -21,7 +21,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/storage")
|
||||
.SetCategory("Device");
|
||||
.SetCategory("Advanced");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Storage"))
|
||||
.SetIcon("res/conditions/fichier24.png");
|
||||
|
||||
|
@@ -485,6 +485,13 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
.AddParameter("expression", _("Angle, in degrees"))
|
||||
.AddParameter("expression", _("Distance"));
|
||||
|
||||
extension
|
||||
.AddExpression("Pi",
|
||||
_("Number Pi (3.1415...)"),
|
||||
_("The number Pi (3.1415...)"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.SetHelpPath("/all-features/expressions");
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -22,6 +22,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects/sprite");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Sprite"))
|
||||
.SetIcon("CppPlatform/Extensions/spriteicon.png");
|
||||
|
||||
gd::ObjectMetadata& obj =
|
||||
extension
|
||||
@@ -79,8 +81,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
"is in 8 directions mode, the valid directions are 0..7"),
|
||||
_("the direction"),
|
||||
_("Direction"),
|
||||
"res/actions/direction24.png",
|
||||
"res/actions/direction.png")
|
||||
"res/actions/direction24_black.png",
|
||||
"res/actions/direction_black.png")
|
||||
.SetHidden() // Hide as 8 direction is not supported officially in the
|
||||
// interface.
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
@@ -140,8 +142,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
"Rotate an object towards a position.",
|
||||
"Rotate _PARAM0_ towards _PARAM1_;_PARAM2_",
|
||||
_("Direction"),
|
||||
"res/actions/direction24.png",
|
||||
"res/actions/direction.png")
|
||||
"res/actions/rotate24_black.png",
|
||||
"res/actions/rotate_black.png")
|
||||
|
||||
.AddParameter("object", _("Object to be rotated"), "Sprite")
|
||||
.AddParameter("expression", _("X position"))
|
||||
@@ -156,8 +158,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Modify the scale of the specified object."),
|
||||
_("the scale"),
|
||||
_("Size"),
|
||||
"res/actions/scale24.png",
|
||||
"res/actions/scale.png")
|
||||
"res/actions/scale24_black.png",
|
||||
"res/actions/scale_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.UseStandardOperatorParameters("number")
|
||||
@@ -168,8 +170,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Modify the scale of the width of an object."),
|
||||
_("the width's scale"),
|
||||
_("Size"),
|
||||
"res/actions/scale24.png",
|
||||
"res/actions/scale.png")
|
||||
"res/actions/scaleWidth24_black.png",
|
||||
"res/actions/scaleWidth_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.UseStandardOperatorParameters("number")
|
||||
@@ -180,8 +182,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Modify the scale of the height of an object."),
|
||||
_("the height's scale"),
|
||||
_("Size"),
|
||||
"res/actions/scale24.png",
|
||||
"res/actions/scale.png")
|
||||
"res/actions/scaleHeight24_black.png",
|
||||
"res/actions/scaleHeight_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.UseStandardOperatorParameters("number")
|
||||
@@ -192,8 +194,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Change the width of a Sprite object."),
|
||||
_("the width"),
|
||||
_("Size"),
|
||||
"res/actions/scale24.png",
|
||||
"res/actions/scale.png")
|
||||
"res/actions/scaleWidth24_black.png",
|
||||
"res/actions/scaleWidth_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.UseStandardOperatorParameters("number")
|
||||
@@ -204,8 +206,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Compare the width of a Sprite object."),
|
||||
_("the width"),
|
||||
_("Size"),
|
||||
"res/conditions/scaleWidth24.png",
|
||||
"res/conditions/scaleWidth.png")
|
||||
"res/conditions/scaleWidth24_black.png",
|
||||
"res/conditions/scaleWidth_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
@@ -216,8 +218,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Change the height of a Sprite object."),
|
||||
_("the height"),
|
||||
_("Size"),
|
||||
"res/actions/scale24.png",
|
||||
"res/actions/scale.png")
|
||||
"res/actions/scaleHeight24_black.png",
|
||||
"res/actions/scaleHeight_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.UseStandardOperatorParameters("number")
|
||||
@@ -228,8 +230,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Compare the height of a Sprite object."),
|
||||
_("the height"),
|
||||
_("Size"),
|
||||
"res/conditions/scaleHeight24.png",
|
||||
"res/conditions/scaleHeight.png")
|
||||
"res/conditions/scaleHeight24_black.png",
|
||||
"res/conditions/scaleHeight_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
@@ -240,8 +242,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Change the size of an object."),
|
||||
_("Change the size of _PARAM0_: set to _PARAM1_x_PARAM2_"),
|
||||
_("Size"),
|
||||
"res/actions/scale24.png",
|
||||
"res/actions/scale.png")
|
||||
"res/actions/scale24_black.png",
|
||||
"res/actions/scale_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("expression", _("Width"))
|
||||
@@ -281,8 +283,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
"from 0 to 7. Otherwise, the direction is in degrees."),
|
||||
_("the direction"),
|
||||
_("Direction"),
|
||||
"res/conditions/direction24.png",
|
||||
"res/conditions/direction.png")
|
||||
"res/conditions/direction24_black.png",
|
||||
"res/conditions/direction_black.png")
|
||||
.SetHidden() // Hide as 8 direction is not supported officially in the
|
||||
// interface.
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
@@ -330,8 +332,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Compare the scale of the width of an object."),
|
||||
_("the width's scale"),
|
||||
_("Size"),
|
||||
"res/conditions/scaleWidth24.png",
|
||||
"res/conditions/scaleWidth.png")
|
||||
"res/conditions/scaleWidth24_black.png",
|
||||
"res/conditions/scaleWidth_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
@@ -342,8 +344,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Compare the scale of the height of an object."),
|
||||
_("the height's scale"),
|
||||
_("Size"),
|
||||
"res/conditions/scaleHeight24.png",
|
||||
"res/conditions/scaleHeight.png")
|
||||
"res/conditions/scaleHeight24_black.png",
|
||||
"res/conditions/scaleHeight_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
@@ -449,8 +451,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
"Rotate an object towards another.",
|
||||
"Rotate _PARAM0_ towards _PARAM1_",
|
||||
_("Direction"),
|
||||
"res/actions/direction24.png",
|
||||
"res/actions/direction.png")
|
||||
"res/actions/rotate24_black.png",
|
||||
"res/actions/rotate_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("objectPtr", "Rotate toward this object")
|
||||
@@ -461,7 +463,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("X position of a point"),
|
||||
_("X position of a point"),
|
||||
_("Position"),
|
||||
"res/actions/position.png")
|
||||
"res/actions/position_black.png")
|
||||
.SetHidden()
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("objectPointName", _("Name of the point"), "", true);
|
||||
@@ -470,7 +472,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Y position of a point"),
|
||||
_("Y position of a point"),
|
||||
_("Position"),
|
||||
"res/actions/position.png")
|
||||
"res/actions/position_black.png")
|
||||
.SetHidden()
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("objectPointName", _("Name of the point"), "", true);
|
||||
@@ -479,7 +481,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("X position of a point"),
|
||||
_("X position of a point"),
|
||||
_("Position"),
|
||||
"res/actions/position.png")
|
||||
"res/actions/position_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("objectPointName", _("Name of the point"));
|
||||
@@ -488,7 +490,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Y position of a point"),
|
||||
_("Y position of a point"),
|
||||
_("Position"),
|
||||
"res/actions/position.png")
|
||||
"res/actions/position_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("objectPointName", _("Name of the point"));
|
||||
@@ -497,7 +499,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Direction"),
|
||||
_("Direction of the object"),
|
||||
_("Direction"),
|
||||
"res/actions/direction.png")
|
||||
"res/actions/direction_black.png")
|
||||
.SetHidden()
|
||||
.AddParameter("object", _("Object"), "Sprite");
|
||||
|
||||
@@ -505,7 +507,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Direction"),
|
||||
_("Direction of the object"),
|
||||
_("Direction"),
|
||||
"res/actions/direction.png")
|
||||
"res/actions/direction_black.png")
|
||||
.SetHidden() // Hide as 8 direction is not supported officially in the
|
||||
// interface.
|
||||
.AddParameter("object", _("Object"), "Sprite");
|
||||
@@ -550,14 +552,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Scale of the width of an object"),
|
||||
_("Scale of the width of an object"),
|
||||
_("Size"),
|
||||
"res/actions/scaleWidth.png")
|
||||
"res/actions/scaleWidth_black.png")
|
||||
.AddParameter("object", _("Object"), "Sprite");
|
||||
|
||||
obj.AddExpression("ScaleY",
|
||||
_("Scale of the height of an object"),
|
||||
_("Scale of the height of an object"),
|
||||
_("Size"),
|
||||
"res/actions/scaleHeight.png")
|
||||
"res/actions/scaleHeight_black.png")
|
||||
.AddParameter("object", _("Object"), "Sprite");
|
||||
|
||||
obj.AddExpression("Opacity",
|
||||
|
@@ -25,8 +25,7 @@ namespace gd {
|
||||
|
||||
Animation SpriteObject::badAnimation;
|
||||
|
||||
SpriteObject::SpriteObject(gd::String name_)
|
||||
: Object(name_), updateIfNotVisible(false) {}
|
||||
SpriteObject::SpriteObject() : updateIfNotVisible(false) {}
|
||||
|
||||
SpriteObject::~SpriteObject(){};
|
||||
|
||||
|
@@ -36,11 +36,11 @@ namespace gd {
|
||||
* \see gd::BuiltinExtensionsImplementer::ImplementsSpriteExtension
|
||||
* \ingroup SpriteObjectExtension
|
||||
*/
|
||||
class GD_CORE_API SpriteObject : public gd::Object {
|
||||
class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
|
||||
public:
|
||||
SpriteObject(gd::String name_);
|
||||
SpriteObject();
|
||||
virtual ~SpriteObject();
|
||||
std::unique_ptr<gd::Object> Clone() const override {
|
||||
std::unique_ptr<gd::ObjectConfiguration> Clone() const override {
|
||||
return gd::make_unique<SpriteObject>(*this);
|
||||
}
|
||||
|
||||
|
@@ -21,20 +21,20 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("" /*TODO: Add a documentation page for this */);
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Text manipulation"))
|
||||
.SetIcon("res/actions/text24.png");
|
||||
.SetIcon("res/actions/text24_black.png");
|
||||
|
||||
extension.AddStrExpression("NewLine",
|
||||
_("Insert a new line"),
|
||||
_("Insert a new line"),
|
||||
"",
|
||||
"res/conditions/toujours24.png");
|
||||
"res/conditions/toujours24_black.png");
|
||||
|
||||
extension
|
||||
.AddStrExpression("FromCodePoint",
|
||||
_("Get character from code point"),
|
||||
_("Get character from code point"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
|
||||
.AddParameter("expression", _("Code point"));
|
||||
|
||||
@@ -43,7 +43,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
_("Uppercase a text"),
|
||||
_("Uppercase a text"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
|
||||
.AddParameter("string", _("Text"));
|
||||
|
||||
@@ -52,7 +52,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
_("Lowercase a text"),
|
||||
_("Lowercase a text"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
|
||||
.AddParameter("string", _("Text"));
|
||||
|
||||
@@ -61,7 +61,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
_("Get a portion of a text"),
|
||||
_("Get a portion of a text"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
|
||||
.AddParameter("string", _("Text"))
|
||||
.AddParameter("expression",
|
||||
@@ -74,7 +74,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
_("Get a character from a text"),
|
||||
_("Get a character from a text"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
|
||||
.AddParameter("string", _("Text"))
|
||||
.AddParameter(
|
||||
@@ -86,7 +86,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
_("Repeat a text"),
|
||||
_("Repeat a text"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
|
||||
.AddParameter("string", _("Text to repeat"))
|
||||
.AddParameter("expression", _("Repetition count"));
|
||||
@@ -96,7 +96,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
_("Length of a text"),
|
||||
_("Length of a text"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
|
||||
.AddParameter("string", _("Text"));
|
||||
|
||||
@@ -106,7 +106,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
_("Search in a text (return the position of the result or "
|
||||
"-1 if not found)"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
|
||||
.AddParameter("string", _("Text"))
|
||||
.AddParameter("string", _("Text to search for"));
|
||||
@@ -117,7 +117,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
"Search in a text from the end (return the position of "
|
||||
"the result or -1 if not found)",
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
|
||||
.AddParameter("string", _("Text"))
|
||||
.AddParameter("string", _("Text to search for"))
|
||||
@@ -131,7 +131,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
"the result, from the beginning of the string, or -1 if not "
|
||||
"found)"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
|
||||
.AddParameter("string", _("Text"))
|
||||
.AddParameter("string", _("Text to search for"));
|
||||
@@ -142,7 +142,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
_("Search in a text, starting from a position (return the "
|
||||
"position of the result or -1 if not found)"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
|
||||
.AddParameter("string", _("Text"))
|
||||
.AddParameter("string", _("Text to search for"))
|
||||
@@ -157,7 +157,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
"Search in a text from the end, starting from a position (return "
|
||||
"the position of the result or -1 if not found)",
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
|
||||
.AddParameter("string", _("Text"))
|
||||
.AddParameter("string", _("Text to search for"))
|
||||
@@ -175,7 +175,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
" the position of the result, from the beginning of the string, or "
|
||||
"-1 if not found)"),
|
||||
"",
|
||||
"res/conditions/toujours24.png")
|
||||
"res/conditions/toujours24_black.png")
|
||||
|
||||
.AddParameter("string", _("Text"))
|
||||
.AddParameter("string", _("Text to search for"))
|
||||
|
@@ -153,8 +153,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
"the next actions (and sub-events)."),
|
||||
_("Wait _PARAM0_ seconds"),
|
||||
"",
|
||||
"res/timer.svg",
|
||||
"res/timer.svg")
|
||||
"res/timer_black.svg",
|
||||
"res/timer_black.svg")
|
||||
.AddParameter("expression", "Time to wait in seconds")
|
||||
.SetHelpPath("/all-features/timers-and-time/wait-action");
|
||||
|
||||
|
@@ -20,6 +20,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
|
||||
"these features can be applied.",
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("User interface")
|
||||
.SetExtensionHelpPath("/all-features/window");
|
||||
extension
|
||||
.AddInstructionOrExpressionGroupMetadata(
|
||||
|
@@ -21,7 +21,7 @@ namespace gd {
|
||||
|
||||
BehaviorMetadata::BehaviorMetadata(
|
||||
const gd::String& extensionNamespace_,
|
||||
const gd::String& name_,
|
||||
const gd::String& nameWithNamespace,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& defaultName_,
|
||||
const gd::String& description_,
|
||||
@@ -45,32 +45,32 @@ BehaviorMetadata::BehaviorMetadata(
|
||||
gd::LogFatalError(
|
||||
"Trying to create a BehaviorMetadata that has no "
|
||||
"behavior. This will crash - please double check that the "
|
||||
"BehaviorMetadata is valid for: " + name_);
|
||||
"BehaviorMetadata is valid for: " + nameWithNamespace);
|
||||
}
|
||||
|
||||
if (instance) instance->SetTypeName(name_);
|
||||
if (sharedDatasInstance) sharedDatasInstance->SetTypeName(name_);
|
||||
if (instance) instance->SetTypeName(nameWithNamespace);
|
||||
if (sharedDatasInstance) sharedDatasInstance->SetTypeName(nameWithNamespace);
|
||||
}
|
||||
|
||||
BehaviorMetadata::BehaviorMetadata(
|
||||
const gd::String& extensionNamespace,
|
||||
const gd::String& name_,
|
||||
const gd::String& nameWithNamespace,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& defaultName_,
|
||||
const gd::String& description_,
|
||||
const gd::String& group_,
|
||||
const gd::String& icon24x24_): BehaviorMetadata(
|
||||
extensionNamespace,
|
||||
name_,
|
||||
nameWithNamespace,
|
||||
fullname_,
|
||||
// Default name is the name
|
||||
name_,
|
||||
defaultName_,
|
||||
description_,
|
||||
group_,
|
||||
icon24x24_,
|
||||
// Class name is the name, actually unused
|
||||
name_,
|
||||
defaultName_,
|
||||
// It is only used to get the name for GetName.
|
||||
gd::make_unique<gd::Behavior>("", name_),
|
||||
gd::make_unique<gd::Behavior>("", nameWithNamespace),
|
||||
nullptr){
|
||||
isEventBased = true;
|
||||
};
|
||||
|
@@ -29,7 +29,7 @@ class GD_CORE_API BehaviorMetadata {
|
||||
public:
|
||||
BehaviorMetadata(
|
||||
const gd::String& extensionNamespace,
|
||||
const gd::String& name_,
|
||||
const gd::String& nameWithNamespace,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& defaultName_,
|
||||
const gd::String& description_,
|
||||
@@ -46,8 +46,9 @@ class GD_CORE_API BehaviorMetadata {
|
||||
*/
|
||||
BehaviorMetadata(
|
||||
const gd::String& extensionNamespace,
|
||||
const gd::String& name_,
|
||||
const gd::String& nameWithNamespace,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& defaultName_,
|
||||
const gd::String& description_,
|
||||
const gd::String& group_,
|
||||
const gd::String& icon24x24_);
|
||||
|
@@ -361,7 +361,7 @@ class GD_CORE_API InstructionMetadata {
|
||||
* _("the string"),
|
||||
* _("Text"),
|
||||
* "CppPlatform/Extensions/text24.png",
|
||||
* "CppPlatform/Extensions/text.png");
|
||||
* "CppPlatform/Extensions/text_black.png");
|
||||
*
|
||||
* .AddParameter("object", _("Object"), "Text", false)
|
||||
* .AddParameter("operator", _("Modification operator"), "string")
|
||||
|
@@ -23,23 +23,20 @@ ObjectMetadata::ObjectMetadata(const gd::String& extensionNamespace_,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& icon24x24,
|
||||
std::shared_ptr<gd::Object> blueprintObject_)
|
||||
std::shared_ptr<gd::ObjectConfiguration> blueprintObject_)
|
||||
: ObjectMetadata(extensionNamespace_,
|
||||
name_,
|
||||
fullname_,
|
||||
description_,
|
||||
icon24x24,
|
||||
[blueprintObject_](gd::String name) -> std::unique_ptr<gd::Object> {
|
||||
if (blueprintObject_ == std::shared_ptr<gd::Object>()) {
|
||||
[blueprintObject_]() -> std::unique_ptr<gd::ObjectConfiguration> {
|
||||
if (blueprintObject_ == std::shared_ptr<gd::ObjectConfiguration>()) {
|
||||
gd::LogFatalError(
|
||||
"Error: Unable to create object. Have you declared an extension "
|
||||
"(or ObjectMetadata) without specifying an object as blueprint?");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<gd::Object> newObject = blueprintObject_->Clone();
|
||||
newObject->SetName(name);
|
||||
return newObject;
|
||||
return blueprintObject_->Clone();
|
||||
}) {
|
||||
blueprintObject = blueprintObject_;
|
||||
}
|
||||
@@ -54,7 +51,7 @@ ObjectMetadata::ObjectMetadata(const gd::String& extensionNamespace_,
|
||||
fullname_,
|
||||
description_,
|
||||
icon24x24,
|
||||
[](gd::String name) -> std::unique_ptr<gd::Object> {
|
||||
[]() -> std::unique_ptr<gd::ObjectConfiguration> {
|
||||
gd::LogFatalError(
|
||||
"Error: Event-based objects don't have blueprint. "
|
||||
"This method should not never be called.");
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class InstructionMetadata;
|
||||
@@ -20,7 +21,7 @@ class MultipleInstructionMetadata;
|
||||
class ExpressionMetadata;
|
||||
} // namespace gd
|
||||
|
||||
typedef std::function<std::unique_ptr<gd::Object>(gd::String name)>
|
||||
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()>
|
||||
CreateFunPtr;
|
||||
|
||||
namespace gd {
|
||||
@@ -42,7 +43,7 @@ class GD_CORE_API ObjectMetadata {
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& icon24x24_,
|
||||
std::shared_ptr<gd::Object> blueprintObject_);
|
||||
std::shared_ptr<gd::ObjectConfiguration> blueprintObject_);
|
||||
/**
|
||||
* \brief Construct an object metadata, without "blueprint" object
|
||||
*
|
||||
@@ -314,7 +315,7 @@ class GD_CORE_API ObjectMetadata {
|
||||
gd::String categoryFullName;
|
||||
std::set<gd::String> unsupportedBaseObjectCapabilities;
|
||||
|
||||
std::shared_ptr<gd::Object>
|
||||
std::shared_ptr<gd::ObjectConfiguration>
|
||||
blueprintObject; ///< The "blueprint" object to be copied when a new
|
||||
///< object is asked. Can be null in case a creation
|
||||
///< function is passed or for events based objects
|
||||
|
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
@@ -92,8 +93,8 @@ std::shared_ptr<gd::PlatformExtension> Platform::GetExtension(
|
||||
return std::shared_ptr<gd::PlatformExtension>();
|
||||
}
|
||||
|
||||
std::unique_ptr<gd::Object> Platform::CreateObject(
|
||||
gd::String type, const gd::String& name) const {
|
||||
std::unique_ptr<gd::ObjectConfiguration> Platform::CreateObjectConfiguration(
|
||||
gd::String type) const {
|
||||
if (creationFunctionTable.find(type) == creationFunctionTable.end()) {
|
||||
gd::LogWarning("Tried to create an object with an unknown type: " + type
|
||||
+ " for platform " + GetName() + "!");
|
||||
@@ -105,11 +106,9 @@ std::unique_ptr<gd::Object> Platform::CreateObject(
|
||||
}
|
||||
|
||||
// Create a new object with the type we want.
|
||||
std::unique_ptr<gd::Object> object =
|
||||
(creationFunctionTable.find(type)->second)(name);
|
||||
object->SetType(type);
|
||||
|
||||
return std::unique_ptr<gd::Object>(std::move(object));
|
||||
auto objectConfiguration = (creationFunctionTable.find(type)->second)();
|
||||
objectConfiguration->SetType(type);
|
||||
return objectConfiguration;
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
|
@@ -16,6 +16,7 @@ namespace gd {
|
||||
class InstructionsMetadataHolder;
|
||||
class Project;
|
||||
class Object;
|
||||
class ObjectConfiguration;
|
||||
class Behavior;
|
||||
class BehaviorMetadata;
|
||||
class ObjectMetadata;
|
||||
@@ -26,7 +27,7 @@ class LayoutEditorCanvas;
|
||||
class ProjectExporter;
|
||||
} // namespace gd
|
||||
|
||||
typedef std::function<std::unique_ptr<gd::Object>(gd::String name)>
|
||||
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()>
|
||||
CreateFunPtr;
|
||||
|
||||
#undef CreateEvent
|
||||
@@ -146,8 +147,8 @@ class GD_CORE_API Platform {
|
||||
/**
|
||||
* \brief Create an object of given type with the specified name.
|
||||
*/
|
||||
std::unique_ptr<gd::Object> CreateObject(gd::String type,
|
||||
const gd::String& name) const;
|
||||
std::unique_ptr<gd::ObjectConfiguration> CreateObjectConfiguration(
|
||||
gd::String type) const;
|
||||
|
||||
/**
|
||||
* \brief Create an event of given type
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/IDE/PlatformManager.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
#include "GDCore/Project/BehaviorsSharedData.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
@@ -231,7 +232,7 @@ gd::ObjectMetadata& PlatformExtension::AddObject(
|
||||
const gd::String& fullname,
|
||||
const gd::String& description,
|
||||
const gd::String& icon24x24,
|
||||
std::shared_ptr<gd::Object> instance) {
|
||||
std::shared_ptr<gd::ObjectConfiguration> instance) {
|
||||
gd::String nameWithNamespace = GetNameSpace() + name;
|
||||
objectsInfos[nameWithNamespace] = ObjectMetadata(GetNameSpace(),
|
||||
nameWithNamespace,
|
||||
@@ -294,6 +295,8 @@ gd::BehaviorMetadata& PlatformExtension::AddEventsBasedBehavior(
|
||||
behaviorsInfo[nameWithNamespace] = BehaviorMetadata(GetNameSpace(),
|
||||
nameWithNamespace,
|
||||
fullname,
|
||||
// Default name is the name
|
||||
name,
|
||||
description,
|
||||
group,
|
||||
icon24x24)
|
||||
|
@@ -37,9 +37,10 @@ class ArbitraryResourceWorker;
|
||||
class BehaviorsSharedData;
|
||||
class Behavior;
|
||||
class Object;
|
||||
class ObjectConfiguration;
|
||||
} // namespace gd
|
||||
|
||||
typedef std::function<std::unique_ptr<gd::Object>(gd::String name)>
|
||||
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()>
|
||||
CreateFunPtr;
|
||||
|
||||
namespace gd {
|
||||
@@ -242,7 +243,7 @@ class GD_CORE_API PlatformExtension {
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& icon_,
|
||||
std::shared_ptr<gd::Object> instance);
|
||||
std::shared_ptr<gd::ObjectConfiguration> instance);
|
||||
|
||||
/**
|
||||
* \brief Declare a new events based object as being part of the extension.
|
||||
|
@@ -25,8 +25,8 @@ gd::ObjectMetadata& PlatformExtension::AddObject(const gd::String& name,
|
||||
fullname,
|
||||
description,
|
||||
icon24x24,
|
||||
[](gd::String name) -> std::unique_ptr<gd::Object> {
|
||||
return gd::make_unique<T>(name);
|
||||
[]() -> std::unique_ptr<gd::ObjectConfiguration> {
|
||||
return gd::make_unique<T>();
|
||||
})
|
||||
.SetHelpPath(GetHelpPath());
|
||||
|
||||
|
@@ -1628,19 +1628,18 @@ void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsFunction(
|
||||
|
||||
void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
|
||||
gd::Project& project,
|
||||
gd::EventsBasedObject& eventsBasedObject,
|
||||
gd::ObjectsContainer& globalObjectsContainer,
|
||||
gd::ObjectsContainer& objectsContainer,
|
||||
gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::String& oldName,
|
||||
const gd::String& newName,
|
||||
bool isObjectGroup) {
|
||||
for (auto &functionUniquePtr : eventsBasedObject.GetEventsFunctions().GetInternalVector()) {
|
||||
auto function = functionUniquePtr.get();
|
||||
auto *function = functionUniquePtr.get();
|
||||
WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
project,
|
||||
*function,
|
||||
globalObjectsContainer,
|
||||
objectsContainer,
|
||||
eventsBasedObject,
|
||||
oldName,
|
||||
newName,
|
||||
isObjectGroup);
|
||||
|
@@ -333,9 +333,8 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
*/
|
||||
static void ObjectOrGroupRenamedInEventsBasedObject(
|
||||
gd::Project& project,
|
||||
gd::EventsBasedObject& eventsBasedObject,
|
||||
gd::ObjectsContainer& globalObjectsContainer,
|
||||
gd::ObjectsContainer& objectsContainer,
|
||||
gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::String& oldName,
|
||||
const gd::String& newName,
|
||||
bool isObjectGroup);
|
||||
|
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "CustomBehavior.h"
|
||||
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
@@ -99,7 +104,7 @@ void CustomBehavior::InitializeContent(gd::SerializerElement &behaviorContent) {
|
||||
const auto &eventsBasedBehavior = project.GetEventsBasedBehavior(GetTypeName());
|
||||
const auto &properties = eventsBasedBehavior.GetPropertyDescriptors();
|
||||
for (auto &&property : properties.GetInternalVector()) {
|
||||
auto element = behaviorContent.AddChild(property->GetName());
|
||||
auto &element = behaviorContent.AddChild(property->GetName());
|
||||
auto propertyType = property->GetType();
|
||||
|
||||
if (propertyType == "String" || propertyType == "Choice" ||
|
||||
|
@@ -1,3 +1,11 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_CUSTOMBEHAVIOR_H
|
||||
#define GDCORE_CUSTOMBEHAVIOR_H
|
||||
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
@@ -7,6 +15,7 @@
|
||||
|
||||
using namespace gd;
|
||||
|
||||
namespace gd {
|
||||
/**
|
||||
* \brief A gd::Behavior that stores its content in JSON and forward the
|
||||
* properties related functions to Javascript with Emscripten.
|
||||
@@ -37,3 +46,6 @@ private:
|
||||
const Project &project; ///< The project is used to get the
|
||||
///< EventBasedBehavior from the fullType.
|
||||
};
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_CUSTOMBEHAVIOR_H
|
@@ -1,49 +0,0 @@
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
using namespace gd;
|
||||
|
||||
/**
|
||||
* \brief A gd::Object that stores its content in JSON and forward the
|
||||
* properties related functions to Javascript with Emscripten.
|
||||
*
|
||||
* It also implements "ExposeResources" to expose the properties of type
|
||||
* "resource".
|
||||
*/
|
||||
class CustomObject : public gd::Object {
|
||||
public:
|
||||
CustomObject(const gd::String &name, const Project& project_, const gd::String &fullType)
|
||||
: Object(name),
|
||||
project(project_) {
|
||||
SetType(fullType);
|
||||
}
|
||||
std::unique_ptr<gd::Object> Clone() const override;
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
|
||||
bool UpdateProperty(const gd::String& name, const gd::String& value) override;
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetInitialInstanceProperties(
|
||||
const gd::InitialInstance& instance,
|
||||
gd::Project& project,
|
||||
gd::Layout& scene) override;
|
||||
bool UpdateInitialInstanceProperty(gd::InitialInstance& instance,
|
||||
const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project,
|
||||
gd::Layout& scene) override;
|
||||
|
||||
void ExposeResources(gd::ArbitraryResourceWorker& worker) override;
|
||||
|
||||
protected:
|
||||
void DoSerializeTo(SerializerElement& element) const override;
|
||||
void DoUnserializeFrom(Project& project, const SerializerElement& element) override;
|
||||
|
||||
private:
|
||||
const Project& project; ///< The project is used to get the
|
||||
///< EventBasedObject from the fullType.
|
||||
gd::SerializerElement objectContent;
|
||||
};
|
@@ -1,4 +1,9 @@
|
||||
#include "CustomObject.h"
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "CustomObjectConfiguration.h"
|
||||
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
@@ -6,27 +11,62 @@
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
#include <map>
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
using namespace gd;
|
||||
|
||||
std::unique_ptr<gd::Object> CustomObject::Clone() const {
|
||||
CustomObject* clone = new CustomObject(*this);
|
||||
return std::unique_ptr<gd::Object>(clone);
|
||||
void CustomObjectConfiguration::Init(const gd::CustomObjectConfiguration& objectConfiguration) {
|
||||
project = objectConfiguration.project;
|
||||
objectContent = objectConfiguration.objectContent;
|
||||
|
||||
// There is no default copy for a map of unique_ptr like childObjectConfigurations.
|
||||
childObjectConfigurations.clear();
|
||||
for (auto& it : objectConfiguration.childObjectConfigurations) {
|
||||
childObjectConfigurations[it.first] =
|
||||
gd::make_unique<gd::ObjectConfiguration>(*it.second);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO EBO Extract a class from Object for the object configuration.
|
||||
// This will allow CustomObject to have a ObjectConfiguration composed of
|
||||
// ObjectConfiguration for their children in addition to its own properties.
|
||||
// This will be used by the GUI to display custom editors (for sprites for
|
||||
// instance)
|
||||
std::map<gd::String, gd::PropertyDescriptor> CustomObject::GetProperties() const {
|
||||
gd::ObjectConfiguration CustomObjectConfiguration::badObjectConfiguration;
|
||||
|
||||
std::unique_ptr<gd::ObjectConfiguration> CustomObjectConfiguration::Clone() const {
|
||||
CustomObjectConfiguration* clone = new CustomObjectConfiguration(*this);
|
||||
return std::unique_ptr<gd::ObjectConfiguration>(clone);
|
||||
}
|
||||
|
||||
gd::ObjectConfiguration &CustomObjectConfiguration::GetChildObjectConfiguration(const gd::String &objectName) {
|
||||
if (!project->HasEventsBasedObject(GetType())) {
|
||||
return badObjectConfiguration;
|
||||
}
|
||||
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
|
||||
|
||||
if (!eventsBasedObject.HasObjectNamed(objectName)) {
|
||||
gd::LogError("Tried to get the configuration of a child-object:" + objectName
|
||||
+ " that doesn't exist in the event-based object: " + GetType());
|
||||
return badObjectConfiguration;
|
||||
}
|
||||
|
||||
auto &childObject = eventsBasedObject.GetObject(objectName);
|
||||
auto configurationPosition = childObjectConfigurations.find(objectName);
|
||||
if (configurationPosition == childObjectConfigurations.end()) {
|
||||
childObjectConfigurations.insert(std::make_pair(
|
||||
objectName,
|
||||
project->CreateObjectConfiguration(childObject.GetType())));
|
||||
return *(childObjectConfigurations[objectName]);
|
||||
}
|
||||
else {
|
||||
auto &pair = *configurationPosition;
|
||||
auto &configuration = pair.second;
|
||||
return *configuration;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> CustomObjectConfiguration::GetProperties() const {
|
||||
auto objectProperties = std::map<gd::String, gd::PropertyDescriptor>();
|
||||
if (!project.HasEventsBasedObject(GetType())) {
|
||||
if (!project->HasEventsBasedObject(GetType())) {
|
||||
return objectProperties;
|
||||
}
|
||||
const auto &eventsBasedObject = project.GetEventsBasedObject(GetType());
|
||||
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
|
||||
const auto &properties = eventsBasedObject.GetPropertyDescriptors();
|
||||
|
||||
for (auto &property : properties.GetInternalVector()) {
|
||||
@@ -75,12 +115,12 @@ std::map<gd::String, gd::PropertyDescriptor> CustomObject::GetProperties() const
|
||||
return objectProperties;
|
||||
}
|
||||
|
||||
bool CustomObject::UpdateProperty(const gd::String& propertyName,
|
||||
bool CustomObjectConfiguration::UpdateProperty(const gd::String& propertyName,
|
||||
const gd::String& newValue) {
|
||||
if (!project.HasEventsBasedObject(GetType())) {
|
||||
if (!project->HasEventsBasedObject(GetType())) {
|
||||
return false;
|
||||
}
|
||||
const auto &eventsBasedObject = project.GetEventsBasedObject(GetType());
|
||||
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
|
||||
const auto &properties = eventsBasedObject.GetPropertyDescriptors();
|
||||
if (!properties.Has(propertyName)) {
|
||||
return false;
|
||||
@@ -106,14 +146,14 @@ bool CustomObject::UpdateProperty(const gd::String& propertyName,
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
CustomObject::GetInitialInstanceProperties(
|
||||
CustomObjectConfiguration::GetInitialInstanceProperties(
|
||||
const gd::InitialInstance& instance,
|
||||
gd::Project& project,
|
||||
gd::Layout& scene) {
|
||||
return std::map<gd::String, gd::PropertyDescriptor>();
|
||||
}
|
||||
|
||||
bool CustomObject::UpdateInitialInstanceProperty(
|
||||
bool CustomObjectConfiguration::UpdateInitialInstanceProperty(
|
||||
gd::InitialInstance& instance,
|
||||
const gd::String& name,
|
||||
const gd::String& value,
|
||||
@@ -122,15 +162,29 @@ bool CustomObject::UpdateInitialInstanceProperty(
|
||||
return false;
|
||||
}
|
||||
|
||||
void CustomObject::DoSerializeTo(SerializerElement& arg0) const {
|
||||
arg0.AddChild("content") = objectContent;
|
||||
void CustomObjectConfiguration::DoSerializeTo(SerializerElement& element) const {
|
||||
element.AddChild("content") = objectContent;
|
||||
auto &childrenContentElement = element.AddChild("childrenContent");
|
||||
for (auto &pair : childObjectConfigurations) {
|
||||
auto &childName = pair.first;
|
||||
auto &childConfiguration = pair.second;
|
||||
auto &childElement = childrenContentElement.AddChild(childName);
|
||||
childConfiguration->SerializeTo(childElement);
|
||||
}
|
||||
}
|
||||
void CustomObject::DoUnserializeFrom(Project& arg0,
|
||||
const SerializerElement& arg1) {
|
||||
objectContent = arg1.GetChild("content");
|
||||
void CustomObjectConfiguration::DoUnserializeFrom(Project& project,
|
||||
const SerializerElement& element) {
|
||||
objectContent = element.GetChild("content");
|
||||
auto &childrenContentElement = element.GetChild("childrenContent");
|
||||
for (auto &pair : childrenContentElement.GetAllChildren()) {
|
||||
auto &childName = pair.first;
|
||||
auto &childElement = pair.second;
|
||||
auto &childConfiguration = GetChildObjectConfiguration(childName);
|
||||
childConfiguration.UnserializeFrom(project, *childElement);
|
||||
}
|
||||
}
|
||||
|
||||
void CustomObject::ExposeResources(
|
||||
void CustomObjectConfiguration::ExposeResources(
|
||||
gd::ArbitraryResourceWorker& worker) {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties = GetProperties();
|
||||
|
||||
@@ -162,4 +216,15 @@ void CustomObject::ExposeResources(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto objectProperties = std::map<gd::String, gd::PropertyDescriptor>();
|
||||
if (!project->HasEventsBasedObject(GetType())) {
|
||||
return;
|
||||
}
|
||||
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
|
||||
|
||||
for (auto& childObject : eventsBasedObject.GetObjects()) {
|
||||
auto &configuration = GetChildObjectConfiguration(childObject->GetName());
|
||||
configuration.ExposeResources(worker);
|
||||
}
|
||||
}
|
100
Core/GDCore/Project/CustomObjectConfiguration.h
Normal file
100
Core/GDCore/Project/CustomObjectConfiguration.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_CUSTOMOBJECTCONFIGURATION_H
|
||||
#define GDCORE_CUSTOMOBJECTCONFIGURATION_H
|
||||
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
|
||||
using namespace gd;
|
||||
|
||||
namespace gd {
|
||||
/**
|
||||
* \brief A gd::ObjectConfiguration that stores its content in JSON and is
|
||||
* composed of other configuration according to it's object children.
|
||||
*
|
||||
* It also implements "ExposeResources" to expose the properties of type
|
||||
* "resource".
|
||||
*/
|
||||
class CustomObjectConfiguration : public gd::ObjectConfiguration {
|
||||
public:
|
||||
CustomObjectConfiguration(const Project& project_, const String& type_)
|
||||
: project(&project_) {
|
||||
SetType(type_);
|
||||
}
|
||||
std::unique_ptr<gd::ObjectConfiguration> Clone() const override;
|
||||
|
||||
/**
|
||||
* Copy constructor. Calls Init().
|
||||
*/
|
||||
CustomObjectConfiguration(const gd::CustomObjectConfiguration& object)
|
||||
: ObjectConfiguration(object) {
|
||||
Init(object);
|
||||
};
|
||||
|
||||
/**
|
||||
* Assignment operator. Calls Init().
|
||||
*/
|
||||
CustomObjectConfiguration& operator=(const gd::CustomObjectConfiguration& object){
|
||||
if ((this) != &object) {
|
||||
ObjectConfiguration::operator=(object);
|
||||
Init(object);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
|
||||
bool UpdateProperty(const gd::String& name, const gd::String& value) override;
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetInitialInstanceProperties(
|
||||
const gd::InitialInstance& instance,
|
||||
gd::Project& project,
|
||||
gd::Layout& scene) override;
|
||||
bool UpdateInitialInstanceProperty(gd::InitialInstance& instance,
|
||||
const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project,
|
||||
gd::Layout& scene) override;
|
||||
|
||||
void ExposeResources(gd::ArbitraryResourceWorker& worker) override;
|
||||
|
||||
gd::ObjectConfiguration &GetChildObjectConfiguration(const gd::String& objectName);
|
||||
|
||||
protected:
|
||||
void DoSerializeTo(SerializerElement& element) const override;
|
||||
void DoUnserializeFrom(Project& project, const SerializerElement& element) override;
|
||||
|
||||
private:
|
||||
const Project* project; ///< The project is used to get the
|
||||
///< EventBasedObject from the fullType.
|
||||
gd::SerializerElement objectContent;
|
||||
std::map<gd::String, std::unique_ptr<gd::ObjectConfiguration>> childObjectConfigurations;
|
||||
|
||||
static gd::ObjectConfiguration badObjectConfiguration;
|
||||
|
||||
/**
|
||||
* Initialize configuration using another configuration. Used by copy-ctor
|
||||
* and assign-op.
|
||||
*
|
||||
* Don't forget to update me if members were changed!
|
||||
*
|
||||
* It's needed because there is no default copy for childObjectConfigurations
|
||||
* and it must be a deep copy.
|
||||
*/
|
||||
void Init(const gd::CustomObjectConfiguration& object);
|
||||
};
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_CUSTOMOBJECTCONFIGURATION_H
|
@@ -23,12 +23,16 @@ EventsBasedObject::EventsBasedObject(const gd::EventsBasedObject &_eventBasedObj
|
||||
}
|
||||
|
||||
void EventsBasedObject::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("defaultName", defaultName);
|
||||
|
||||
AbstractEventsBasedEntity::SerializeTo(element);
|
||||
SerializeObjectsTo(element.AddChild("objects"));
|
||||
}
|
||||
|
||||
void EventsBasedObject::UnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element) {
|
||||
defaultName = element.GetStringAttribute("defaultName");
|
||||
|
||||
AbstractEventsBasedEntity::UnserializeFrom(project, element);
|
||||
UnserializeObjectsFrom(project, element.GetChild("objects"));
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@ class Project;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
// TODO EBO Add a way to mark some parts of children configuration as readonly.
|
||||
/**
|
||||
* \brief Represents an object that is implemented with events.
|
||||
*
|
||||
@@ -38,6 +38,19 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public Ob
|
||||
*/
|
||||
EventsBasedObject* Clone() const { return new EventsBasedObject(*this); };
|
||||
|
||||
/**
|
||||
* \brief Get the default name for created objects.
|
||||
*/
|
||||
const gd::String& GetDefaultName() const { return defaultName; };
|
||||
|
||||
/**
|
||||
* \brief Set the default name for created objects.
|
||||
*/
|
||||
EventsBasedObject& SetDefaultName(const gd::String& defaultName_) {
|
||||
defaultName = defaultName_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
EventsBasedObject& SetDescription(const gd::String& description_) override {
|
||||
AbstractEventsBasedEntity::SetDescription(description_);
|
||||
return *this;
|
||||
@@ -65,6 +78,7 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public Ob
|
||||
const SerializerElement& element) override;
|
||||
|
||||
private:
|
||||
gd::String defaultName;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -168,24 +168,10 @@ void EventsFunctionsExtension::UnserializeExtensionImplementationFrom(
|
||||
gd::Project& project,
|
||||
const SerializerElement& element) {
|
||||
UnserializeEventsFunctionsFrom(project, element.GetChild("eventsFunctions"));
|
||||
auto &behaviorsElement = element.GetChild("eventsBasedBehaviors");
|
||||
behaviorsElement.ConsiderAsArrayOf("eventsBasedBehavior");
|
||||
for (std::size_t i = 0; i < behaviorsElement.GetChildrenCount(); ++i) {
|
||||
const gd::String &behaviorName =
|
||||
behaviorsElement.GetChild(i).GetStringAttribute("name");
|
||||
if (eventsBasedBehaviors.Has(behaviorName)) {
|
||||
eventsBasedBehaviors.Get(behaviorName).UnserializeFrom(project, behaviorsElement.GetChild(i));
|
||||
}
|
||||
}
|
||||
auto &objectsElement = element.GetChild("eventsBasedObjects");
|
||||
objectsElement.ConsiderAsArrayOf("eventsBasedObject");
|
||||
for (std::size_t i = 0; i < objectsElement.GetChildrenCount(); ++i) {
|
||||
const gd::String &objectName =
|
||||
objectsElement.GetChild(i).GetStringAttribute("name");
|
||||
if (eventsBasedObjects.Has(objectName)) {
|
||||
eventsBasedObjects.Get(objectName).UnserializeFrom(project, objectsElement.GetChild(i));
|
||||
}
|
||||
}
|
||||
eventsBasedBehaviors.UnserializeElementsFrom(
|
||||
"eventsBasedBehavior", project, element.GetChild("eventsBasedBehaviors"));
|
||||
eventsBasedObjects.UnserializeElementsFrom(
|
||||
"eventsBasedObject", project, element.GetChild("eventsBasedObjects"));
|
||||
}
|
||||
|
||||
bool EventsFunctionsExtension::IsExtensionLifecycleEventsFunction(
|
||||
|
@@ -117,10 +117,10 @@ std::map<gd::String, gd::PropertyDescriptor>
|
||||
InitialInstance::GetCustomProperties(gd::Project& project, gd::Layout& layout) {
|
||||
// Find an object
|
||||
if (layout.HasObjectNamed(GetObjectName()))
|
||||
return layout.GetObject(GetObjectName())
|
||||
return layout.GetObject(GetObjectName()).GetConfiguration()
|
||||
.GetInitialInstanceProperties(*this, project, layout);
|
||||
else if (project.HasObjectNamed(GetObjectName()))
|
||||
return project.GetObject(GetObjectName())
|
||||
return project.GetObject(GetObjectName()).GetConfiguration()
|
||||
.GetInitialInstanceProperties(*this, project, layout);
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
@@ -132,10 +132,10 @@ bool InitialInstance::UpdateCustomProperty(const gd::String& name,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout) {
|
||||
if (layout.HasObjectNamed(GetObjectName()))
|
||||
return layout.GetObject(GetObjectName())
|
||||
return layout.GetObject(GetObjectName()).GetConfiguration()
|
||||
.UpdateInitialInstanceProperty(*this, name, value, project, layout);
|
||||
else if (project.HasObjectNamed(GetObjectName()))
|
||||
return project.GetObject(GetObjectName())
|
||||
return project.GetObject(GetObjectName()).GetConfiguration()
|
||||
.UpdateInitialInstanceProperty(*this, name, value, project, layout);
|
||||
|
||||
return false;
|
||||
|
@@ -218,32 +218,8 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
|
||||
|
||||
if (behaviorsSharedData.find(name) != behaviorsSharedData.end()) continue;
|
||||
|
||||
if (project.HasEventsBasedBehavior(allBehaviorsTypes[i])) {
|
||||
// Events based behaviors don't have shared data yet.
|
||||
auto sharedData =
|
||||
gd::make_unique<gd::BehaviorsSharedData>(name, allBehaviorsTypes[i]);
|
||||
sharedData->InitializeContent();
|
||||
behaviorsSharedData[name] = std::move(sharedData);
|
||||
}
|
||||
else {
|
||||
const gd::BehaviorMetadata& behaviorMetadata =
|
||||
gd::MetadataProvider::GetBehaviorMetadata(
|
||||
project.GetCurrentPlatform(),
|
||||
allBehaviorsTypes[i]);
|
||||
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gd::BehaviorsSharedData* behaviorsSharedDataBluePrint =
|
||||
behaviorMetadata.GetSharedDataInstance();
|
||||
if (!behaviorsSharedDataBluePrint) continue;
|
||||
|
||||
auto sharedData =
|
||||
gd::make_unique<gd::BehaviorsSharedData>(
|
||||
*behaviorsSharedDataBluePrint);
|
||||
sharedData->SetName(name);
|
||||
sharedData->SetTypeName(allBehaviorsTypes[i]);
|
||||
sharedData->InitializeContent();
|
||||
auto sharedData = CreateBehaviorsSharedData(project, name, allBehaviorsTypes[i]);
|
||||
if (sharedData) {
|
||||
behaviorsSharedData[name] = std::move(sharedData);
|
||||
}
|
||||
}
|
||||
@@ -264,6 +240,33 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<gd::BehaviorsSharedData> Layout::CreateBehaviorsSharedData(gd::Project& project, const gd::String& name, const gd::String& behaviorsType) {
|
||||
if (project.HasEventsBasedBehavior(behaviorsType)) {
|
||||
// Events based behaviors don't have shared data yet.
|
||||
auto sharedData =
|
||||
gd::make_unique<gd::BehaviorsSharedData>(name, behaviorsType);
|
||||
sharedData->InitializeContent();
|
||||
return std::move(sharedData);
|
||||
}
|
||||
const gd::BehaviorMetadata& behaviorMetadata =
|
||||
gd::MetadataProvider::GetBehaviorMetadata(
|
||||
project.GetCurrentPlatform(),
|
||||
behaviorsType);
|
||||
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gd::BehaviorsSharedData* behaviorsSharedDataBluePrint =
|
||||
behaviorMetadata.GetSharedDataInstance();
|
||||
if (!behaviorsSharedDataBluePrint) return nullptr;
|
||||
|
||||
auto sharedData = behaviorsSharedDataBluePrint->Clone();
|
||||
sharedData->SetName(name);
|
||||
sharedData->SetTypeName(behaviorsType);
|
||||
sharedData->InitializeContent();
|
||||
return std::unique_ptr<gd::BehaviorsSharedData>(sharedData);
|
||||
}
|
||||
|
||||
void Layout::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", GetName());
|
||||
element.SetAttribute("mangledName", GetMangledName());
|
||||
@@ -367,20 +370,23 @@ void Layout::UnserializeFrom(gd::Project& project,
|
||||
"Behavior"); // Compatibility with GD <= 4
|
||||
gd::String name = sharedDataElement.GetStringAttribute("name", "", "Name");
|
||||
|
||||
auto behavior = gd::make_unique<gd::BehaviorsSharedData>(name, type);
|
||||
// Compatibility with GD <= 4.0.98
|
||||
// If there is only one child called "content" (in addition to "type" and
|
||||
// "name"), it's the content of a JavaScript behavior. Move the content
|
||||
// out of the "content" object (to put it directly at the root of the
|
||||
// behavior shared data element).
|
||||
if (sharedDataElement.HasChild("content")) {
|
||||
behavior->UnserializeFrom(sharedDataElement.GetChild("content"));
|
||||
|
||||
auto sharedData = CreateBehaviorsSharedData(project, name, type);
|
||||
if (sharedData) {
|
||||
// Compatibility with GD <= 4.0.98
|
||||
// If there is only one child called "content" (in addition to "type" and
|
||||
// "name"), it's the content of a JavaScript behavior. Move the content
|
||||
// out of the "content" object (to put it directly at the root of the
|
||||
// behavior shared data element).
|
||||
if (sharedDataElement.HasChild("content")) {
|
||||
sharedData->UnserializeFrom(sharedDataElement.GetChild("content"));
|
||||
}
|
||||
// end of compatibility code
|
||||
else {
|
||||
sharedData->UnserializeFrom(sharedDataElement);
|
||||
}
|
||||
behaviorsSharedData[name] = std::move(sharedData);
|
||||
}
|
||||
// end of compatibility code
|
||||
else {
|
||||
behavior->UnserializeFrom(sharedDataElement);
|
||||
}
|
||||
behaviorsSharedData[name] = std::move(behavior);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +408,7 @@ void Layout::Init(const Layout& other) {
|
||||
behaviorsSharedData.clear();
|
||||
for (const auto& it : other.behaviorsSharedData) {
|
||||
behaviorsSharedData[it.first] =
|
||||
gd::make_unique<gd::BehaviorsSharedData>(*(it.second->Clone()));
|
||||
std::unique_ptr<gd::BehaviorsSharedData>(it.second->Clone());
|
||||
}
|
||||
|
||||
events = other.events;
|
||||
|
@@ -404,6 +404,11 @@ class GD_CORE_API Layout : public ObjectsContainer {
|
||||
* Don't forget to update me if members were changed!
|
||||
*/
|
||||
void Init(const gd::Layout& other);
|
||||
|
||||
std::unique_ptr<gd::BehaviorsSharedData> CreateBehaviorsSharedData(
|
||||
gd::Project& project,
|
||||
const gd::String& name,
|
||||
const gd::String& behaviorsType);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -20,12 +20,23 @@ namespace gd {
|
||||
|
||||
Object::~Object() {}
|
||||
|
||||
Object::Object(const gd::String& name_) : name(name_) {}
|
||||
Object::Object(const gd::String& name_,
|
||||
const gd::String& type_,
|
||||
std::unique_ptr<gd::ObjectConfiguration> configuration_)
|
||||
: name(name_), configuration(std::move(configuration_)) {
|
||||
SetType(type_);
|
||||
}
|
||||
|
||||
Object::Object(const gd::String& name_,
|
||||
const gd::String& type_,
|
||||
gd::ObjectConfiguration* configuration_)
|
||||
: name(name_), configuration(configuration_) {
|
||||
SetType(type_);
|
||||
}
|
||||
|
||||
void Object::Init(const gd::Object& object) {
|
||||
name = object.name;
|
||||
assetStoreId = object.assetStoreId;
|
||||
type = object.type;
|
||||
objectVariables = object.objectVariables;
|
||||
tags = object.tags;
|
||||
effectsContainer = object.effectsContainer;
|
||||
@@ -34,6 +45,16 @@ void Object::Init(const gd::Object& object) {
|
||||
for (auto& it : object.behaviors) {
|
||||
behaviors[it.first] = gd::make_unique<gd::Behavior>(*it.second);
|
||||
}
|
||||
|
||||
configuration = object.configuration->Clone();
|
||||
}
|
||||
|
||||
gd::ObjectConfiguration& Object::GetConfiguration() {
|
||||
return *configuration;
|
||||
}
|
||||
|
||||
const gd::ObjectConfiguration& Object::GetConfiguration() const {
|
||||
return *configuration;
|
||||
}
|
||||
|
||||
std::vector<gd::String> Object::GetAllBehaviorNames() const {
|
||||
@@ -72,11 +93,6 @@ bool Object::HasBehaviorNamed(const gd::String& name) const {
|
||||
return behaviors.find(name) != behaviors.end();
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> Object::GetProperties() const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
return nothing;
|
||||
}
|
||||
|
||||
gd::Behavior* Object::AddNewBehavior(const gd::Project& project,
|
||||
const gd::String& type,
|
||||
const gd::String& name) {
|
||||
@@ -109,17 +125,9 @@ gd::Behavior* Object::AddNewBehavior(const gd::Project& project,
|
||||
}
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
Object::GetInitialInstanceProperties(const gd::InitialInstance& instance,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout) {
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
return nothing;
|
||||
}
|
||||
|
||||
void Object::UnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element) {
|
||||
type = element.GetStringAttribute("type");
|
||||
SetType(element.GetStringAttribute("type"));
|
||||
assetStoreId = element.GetStringAttribute("assetStoreId");
|
||||
name = element.GetStringAttribute("name", name, "nom");
|
||||
tags = element.GetStringAttribute("tags");
|
||||
@@ -186,7 +194,7 @@ void Object::UnserializeFrom(gd::Project& project,
|
||||
}
|
||||
}
|
||||
|
||||
DoUnserializeFrom(project, element);
|
||||
configuration->UnserializeFrom(project, element);
|
||||
}
|
||||
|
||||
void Object::SerializeTo(SerializerElement& element) const {
|
||||
@@ -212,7 +220,7 @@ void Object::SerializeTo(SerializerElement& element) const {
|
||||
behaviorElement.SetAttribute("name", behavior.GetName());
|
||||
}
|
||||
|
||||
DoSerializeTo(element);
|
||||
configuration->SerializeTo(element);
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -11,10 +11,12 @@
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
#include "GDCore/Project/EffectsContainer.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/MakeUnique.h"
|
||||
|
||||
namespace gd {
|
||||
class PropertyDescriptor;
|
||||
class Project;
|
||||
@@ -28,7 +30,7 @@ class EffectsContainer;
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Base class used to represent an object of a platform
|
||||
* \brief Represent an object of a platform
|
||||
*
|
||||
* \ingroup PlatformDefinition
|
||||
*/
|
||||
@@ -36,9 +38,19 @@ class GD_CORE_API Object {
|
||||
public:
|
||||
/**
|
||||
* Create a new object with the name passed as argument.
|
||||
* \param name Object's name
|
||||
*/
|
||||
Object(const gd::String& name);
|
||||
Object(const gd::String& name,
|
||||
const gd::String& type,
|
||||
std::unique_ptr<gd::ObjectConfiguration> configuration);
|
||||
|
||||
/**
|
||||
* Create a new object with the name passed as argument.
|
||||
*
|
||||
* Object takes the ownership of the configuration.
|
||||
*/
|
||||
Object(const gd::String& name,
|
||||
const gd::String& type,
|
||||
gd::ObjectConfiguration* configuration);
|
||||
|
||||
/**
|
||||
* Copy constructor. Calls Init().
|
||||
@@ -70,6 +82,13 @@ class GD_CORE_API Object {
|
||||
return gd::make_unique<gd::Object>(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the object configuration.
|
||||
*/
|
||||
gd::ObjectConfiguration& GetConfiguration();
|
||||
|
||||
const gd::ObjectConfiguration& GetConfiguration() const;
|
||||
|
||||
/** \name Common properties
|
||||
* Members functions related to common properties
|
||||
*/
|
||||
@@ -93,11 +112,15 @@ class GD_CORE_API Object {
|
||||
|
||||
/** \brief Change the type of the object.
|
||||
*/
|
||||
void SetType(const gd::String& type_) { type = type_; }
|
||||
void SetType(const gd::String& type_) {
|
||||
configuration->SetType(type_);
|
||||
}
|
||||
|
||||
/** \brief Return the type of the object.
|
||||
*/
|
||||
const gd::String& GetType() const { return type; }
|
||||
const gd::String& GetType() const {
|
||||
return configuration->GetType();
|
||||
}
|
||||
|
||||
/** \brief Change the tags of the object.
|
||||
*/
|
||||
@@ -108,92 +131,6 @@ class GD_CORE_API Object {
|
||||
const gd::String& GetTags() const { return tags; }
|
||||
///@}
|
||||
|
||||
/** \name Resources management
|
||||
* Members functions related to managing resources used by the object
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Called ( e.g. during compilation ) so as to inventory internal
|
||||
* resources and sometimes update their filename. Implementation example:
|
||||
* \code
|
||||
* worker.ExposeImage(myImage);
|
||||
* worker.ExposeFile(myResourceFile);
|
||||
* \endcode
|
||||
*
|
||||
* \see ArbitraryResourceWorker
|
||||
*/
|
||||
virtual void ExposeResources(gd::ArbitraryResourceWorker& worker) { return; };
|
||||
|
||||
/**
|
||||
* Redefine this function to return true if your object can use shaders.
|
||||
*/
|
||||
virtual bool SupportShaders() { return false; }
|
||||
///@}
|
||||
|
||||
/** \name Object properties
|
||||
* Reading and updating object properties
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Called when the IDE wants to know about the custom properties of the
|
||||
object.
|
||||
*
|
||||
* Usage example:
|
||||
\code
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties[ToString(_("Text"))].SetValue("Hello world!");
|
||||
|
||||
return properties;
|
||||
\endcode
|
||||
*
|
||||
* \return a std::map with properties names as key.
|
||||
* \see gd::PropertyDescriptor
|
||||
*/
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to update a custom property of the object
|
||||
*
|
||||
* \return false if the new value cannot be set
|
||||
*/
|
||||
virtual bool UpdateProperty(const gd::String& name, const gd::String& value) {
|
||||
return false;
|
||||
};
|
||||
///@}
|
||||
|
||||
/** \name Drawing and editing initial instances
|
||||
* Members functions related to drawing and editing initial instances of this
|
||||
* object
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Called when the IDE wants to know about the custom properties of an
|
||||
* initial instance of this object.
|
||||
*
|
||||
* \return a std::map with properties names as key and values.
|
||||
* \see gd::InitialInstance
|
||||
*/
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor>
|
||||
GetInitialInstanceProperties(const gd::InitialInstance& instance,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout);
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to update a custom property of an initial
|
||||
* instance of this object.
|
||||
*
|
||||
* \return false if the new value cannot be set
|
||||
* \see gd::InitialInstance
|
||||
*/
|
||||
virtual bool UpdateInitialInstanceProperty(gd::InitialInstance& instance,
|
||||
const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout) {
|
||||
return false;
|
||||
};
|
||||
///@}
|
||||
|
||||
/** \name Behaviors management
|
||||
* Members functions related to behaviors management.
|
||||
*/
|
||||
@@ -309,8 +246,7 @@ class GD_CORE_API Object {
|
||||
protected:
|
||||
gd::String name; ///< The full name of the object
|
||||
gd::String assetStoreId; ///< The ID of the asset if the object comes from the store.
|
||||
gd::String type; ///< Which type is the object. ( To test if we can do
|
||||
///< something reserved to some objects with it )
|
||||
std::unique_ptr<gd::ObjectConfiguration> configuration;
|
||||
std::map<gd::String, std::unique_ptr<gd::Behavior>>
|
||||
behaviors; ///< Contains all behaviors and their properties for the
|
||||
///< object. Behavior contents are the ownership of the
|
||||
@@ -321,20 +257,12 @@ class GD_CORE_API Object {
|
||||
gd::EffectsContainer
|
||||
effectsContainer; ///< The effects container for the object.
|
||||
|
||||
/**
|
||||
* \brief Derived objects can redefine this method to load custom attributes.
|
||||
*/
|
||||
virtual void DoUnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element){};
|
||||
|
||||
/**
|
||||
* \brief Derived objects can redefine this method to save custom attributes.
|
||||
*/
|
||||
virtual void DoSerializeTo(SerializerElement& element) const {};
|
||||
|
||||
/**
|
||||
* Initialize object using another object. Used by copy-ctor and assign-op.
|
||||
* Don't forget to update me if members were changed!
|
||||
*
|
||||
* It's needed because there is no default copy for a map of unique_ptr like
|
||||
* behaviors and it must be a deep copy.
|
||||
*/
|
||||
void Init(const gd::Object& object);
|
||||
};
|
||||
|
47
Core/GDCore/Project/ObjectConfiguration.cpp
Normal file
47
Core/GDCore/Project/ObjectConfiguration.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
|
||||
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/CustomBehavior.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
ObjectConfiguration::~ObjectConfiguration() {}
|
||||
|
||||
ObjectConfiguration::ObjectConfiguration() {}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> ObjectConfiguration::GetProperties() const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
return nothing;
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
ObjectConfiguration::GetInitialInstanceProperties(const gd::InitialInstance& instance,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout) {
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
return nothing;
|
||||
}
|
||||
|
||||
void ObjectConfiguration::UnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element) {
|
||||
DoUnserializeFrom(project, element);
|
||||
}
|
||||
|
||||
void ObjectConfiguration::SerializeTo(SerializerElement& element) const {
|
||||
DoSerializeTo(element);
|
||||
}
|
||||
|
||||
} // namespace gd
|
194
Core/GDCore/Project/ObjectConfiguration.h
Normal file
194
Core/GDCore/Project/ObjectConfiguration.h
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_OBJECTCONFIGURATION_H
|
||||
#define GDCORE_OBJECTCONFIGURATION_H
|
||||
#include "GDCore/Vector2.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/EffectsContainer.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/MakeUnique.h"
|
||||
namespace gd {
|
||||
class PropertyDescriptor;
|
||||
class Project;
|
||||
class Layout;
|
||||
class ArbitraryResourceWorker;
|
||||
class InitialInstance;
|
||||
class SerializerElement;
|
||||
class EffectsContainer;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Base class used to represent an object configuration.
|
||||
* For example, this can be the animations in a sprite, the text, its font,
|
||||
* its color in a Text object, etc...
|
||||
*
|
||||
* \ingroup PlatformDefinition
|
||||
*/
|
||||
class GD_CORE_API ObjectConfiguration {
|
||||
public:
|
||||
/**
|
||||
* Create a new object configuration.
|
||||
*/
|
||||
ObjectConfiguration();
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~ObjectConfiguration();
|
||||
|
||||
/**
|
||||
* Must return a pointer to a copy of the configuration. This method is
|
||||
* needed to do polymorphic copies. Just redefine this method in your derived
|
||||
* object class like this:
|
||||
* \code
|
||||
* return gd::make_unique<MyObjectConfiguration>(*this);
|
||||
* \endcode
|
||||
*/
|
||||
virtual std::unique_ptr<gd::ObjectConfiguration> Clone() const {
|
||||
return gd::make_unique<gd::ObjectConfiguration>(*this);
|
||||
}
|
||||
|
||||
/** \brief Change the type of the object.
|
||||
*/
|
||||
void SetType(const gd::String& type_) { type = type_; }
|
||||
|
||||
/** \brief Return the type of the object.
|
||||
*/
|
||||
const gd::String& GetType() const { return type; }
|
||||
|
||||
/** \name Object properties
|
||||
* Reading and updating object configuration properties
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Called when the IDE wants to know about the custom properties of the
|
||||
object configuration.
|
||||
*
|
||||
* Usage example:
|
||||
\code
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties[ToString(_("Text"))].SetValue("Hello world!");
|
||||
|
||||
return properties;
|
||||
\endcode
|
||||
*
|
||||
* \return a std::map with properties names as key.
|
||||
* \see gd::PropertyDescriptor
|
||||
*/
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to update a custom property of the object
|
||||
* configuration.
|
||||
*
|
||||
* \return false if the new value cannot be set
|
||||
*/
|
||||
virtual bool UpdateProperty(const gd::String& name, const gd::String& value) {
|
||||
return false;
|
||||
};
|
||||
///@}
|
||||
|
||||
/** \name Drawing and editing initial instances
|
||||
* Members functions related to drawing and editing initial instances of this
|
||||
* object configuration
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Called when the IDE wants to know about the custom properties of an
|
||||
* initial instance of this object configuration.
|
||||
*
|
||||
* \return a std::map with properties names as key and values.
|
||||
* \see gd::InitialInstance
|
||||
*/
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor>
|
||||
GetInitialInstanceProperties(const gd::InitialInstance& instance,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout);
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to update a custom property of an initial
|
||||
* instance of this object configuration.
|
||||
*
|
||||
* \return false if the new value cannot be set
|
||||
* \see gd::InitialInstance
|
||||
*/
|
||||
virtual bool UpdateInitialInstanceProperty(gd::InitialInstance& instance,
|
||||
const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout) {
|
||||
return false;
|
||||
};
|
||||
///@}
|
||||
|
||||
/** \name Resources management
|
||||
* Members functions related to managing resources used by the object configuration
|
||||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* \brief Called ( e.g. during compilation ) so as to inventory internal
|
||||
* resources and sometimes update their filename. Implementation example:
|
||||
* \code
|
||||
* worker.ExposeImage(myImage);
|
||||
* worker.ExposeFile(myResourceFile);
|
||||
* \endcode
|
||||
*
|
||||
* \see ArbitraryResourceWorker
|
||||
*/
|
||||
virtual void ExposeResources(gd::ArbitraryResourceWorker& worker) { return; };
|
||||
///@}
|
||||
|
||||
/** \name Serialization
|
||||
* Members functions related to serialization of the object configuration
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Serialize the object configuration.
|
||||
* \see DoSerializeTo
|
||||
*/
|
||||
void SerializeTo(SerializerElement& element) const;
|
||||
|
||||
/**
|
||||
* \brief Unserialize the object configuration.
|
||||
* \see DoUnserializeFrom
|
||||
*/
|
||||
void UnserializeFrom(gd::Project& project, const SerializerElement& element);
|
||||
///@}
|
||||
|
||||
protected:
|
||||
gd::String type; ///< Which type of object is represented by this
|
||||
///< configuration.
|
||||
|
||||
/**
|
||||
* \brief Derived object configuration can redefine this method to load
|
||||
* custom attributes.
|
||||
*/
|
||||
virtual void DoUnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element){};
|
||||
|
||||
/**
|
||||
* \brief Derived object configuration can redefine this method to save
|
||||
* custom attributes.
|
||||
*/
|
||||
virtual void DoSerializeTo(SerializerElement& element) const {};
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
/**
|
||||
* Object configurations are usually managed thanks to (smart) pointers.
|
||||
*/
|
||||
using ObjConfSPtr = std::unique_ptr<gd::ObjectConfiguration>;
|
||||
|
||||
#endif // GDCORE_OBJECT_H
|
@@ -23,11 +23,12 @@
|
||||
#include "GDCore/IDE/PlatformManager.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/CustomObject.h"
|
||||
#include "GDCore/Project/CustomObjectConfiguration.h"
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
#include "GDCore/Project/ExternalLayout.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
#include "GDCore/Project/ObjectGroupsContainer.h"
|
||||
#include "GDCore/Project/ResourcesManager.h"
|
||||
#include "GDCore/Project/SourceFile.h"
|
||||
@@ -82,12 +83,17 @@ void Project::ResetProjectUuid() { projectUuid = UUID::MakeUuid4(); }
|
||||
std::unique_ptr<gd::Object> Project::CreateObject(
|
||||
const gd::String& type,
|
||||
const gd::String& name) const {
|
||||
return gd::make_unique<Object>(name, type, CreateObjectConfiguration(type));
|
||||
}
|
||||
|
||||
std::unique_ptr<gd::ObjectConfiguration> Project::CreateObjectConfiguration(
|
||||
const gd::String& type) const {
|
||||
if (Project::HasEventsBasedObject(type)) {
|
||||
return gd::make_unique<CustomObject>(name, *this, type);
|
||||
return gd::make_unique<CustomObjectConfiguration>(*this, type);
|
||||
}
|
||||
else {
|
||||
// Create a base object if the type can't be found in the platform.
|
||||
return currentPlatform->CreateObject(type, name);
|
||||
return currentPlatform->CreateObjectConfiguration(type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -940,8 +946,9 @@ void Project::ExposeResources(gd::ArbitraryResourceWorker& worker) {
|
||||
// Add layouts resources
|
||||
for (std::size_t s = 0; s < GetLayoutsCount(); s++) {
|
||||
for (std::size_t j = 0; j < GetLayout(s).GetObjectsCount();
|
||||
++j) // Add objects resources
|
||||
GetLayout(s).GetObject(j).ExposeResources(worker);
|
||||
++j) { // Add objects resources
|
||||
GetLayout(s).GetObject(j).GetConfiguration().ExposeResources(worker);
|
||||
}
|
||||
|
||||
LaunchResourceWorkerOnEvents(*this, GetLayout(s).GetEvents(), worker);
|
||||
}
|
||||
@@ -960,7 +967,7 @@ void Project::ExposeResources(gd::ArbitraryResourceWorker& worker) {
|
||||
|
||||
// Add global objects resources
|
||||
for (std::size_t j = 0; j < GetObjectsCount(); ++j) {
|
||||
GetObject(j).ExposeResources(worker);
|
||||
GetObject(j).GetConfiguration().ExposeResources(worker);
|
||||
}
|
||||
|
||||
// Add loading screen background image if present
|
||||
|
@@ -27,6 +27,7 @@ class EventsFunctionsExtension;
|
||||
class EventsBasedObject;
|
||||
class EventsBasedBehavior;
|
||||
class Object;
|
||||
class ObjectConfiguration;
|
||||
class VariablesContainer;
|
||||
class ArbitraryResourceWorker;
|
||||
class SourceFile;
|
||||
@@ -464,6 +465,14 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
std::unique_ptr<gd::Object> CreateObject(const gd::String& type,
|
||||
const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* Create an object configuration of the given type.
|
||||
*
|
||||
* \param type The type of the object
|
||||
*/
|
||||
std::unique_ptr<gd::ObjectConfiguration> CreateObjectConfiguration(
|
||||
const gd::String& type) const;
|
||||
|
||||
/**
|
||||
* Create an event of the given type.
|
||||
*
|
||||
|
@@ -13,12 +13,14 @@
|
||||
#include "GDCore/IDE/Project/ProjectResourcesAdder.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Events/Builtin/StandardEvent.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Tools/SystemStats.h"
|
||||
#include "GDCore/Tools/VersionWrapper.h"
|
||||
#include "DummyPlatform.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
class ArbitraryResourceWorkerTest : public gd::ArbitraryResourceWorker {
|
||||
@@ -63,14 +65,15 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
"path/to/file4.png") != worker.files.end());
|
||||
|
||||
SECTION("Object using a resource") {
|
||||
gd::SpriteObject obj("myObject");
|
||||
|
||||
gd::SpriteObject spriteConfiguration;
|
||||
gd::Animation anim;
|
||||
gd::Sprite sprite;
|
||||
sprite.SetImageName("res1");
|
||||
anim.SetDirectionsCount(1);
|
||||
anim.GetDirection(0).AddSprite(sprite);
|
||||
obj.AddAnimation(anim);
|
||||
spriteConfiguration.AddAnimation(anim);
|
||||
|
||||
gd::Object obj("myObject", "", spriteConfiguration.Clone());
|
||||
project.InsertObject(obj, 0);
|
||||
|
||||
worker.files.clear();
|
||||
|
@@ -120,12 +120,14 @@ void CheckBehaviorProperty(ObjectsContainer &container) {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("ProjectSerialization", "[common]") {
|
||||
// TODO EBO Add similar test cases for events-based objects.
|
||||
TEST_CASE("BehaviorSerialization", "[common]") {
|
||||
|
||||
SECTION("Save and load a project with a custom behavior property value") {
|
||||
gd::Platform platform;
|
||||
gd::Project writtenProject;
|
||||
SetupProject(writtenProject, platform);
|
||||
CheckBehaviorProperty(writtenProject.GetLayout("Scene"));
|
||||
|
||||
SerializerElement projectElement;
|
||||
writtenProject.SerializeTo(projectElement);
|
@@ -7,6 +7,8 @@
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
@@ -98,7 +100,7 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
// Create the base object. All objects "inherits" from it.
|
||||
baseObjectExtension->SetExtensionInformation(
|
||||
"BuiltinObject", "Base Object dummy extension", "", "", "");
|
||||
auto& baseObject = baseObjectExtension->AddObject<gd::Object>(
|
||||
auto& baseObject = baseObjectExtension->AddObject<gd::ObjectConfiguration>(
|
||||
"", "Dummy Base Object", "Dummy Base Object", "");
|
||||
|
||||
// Add this expression for all objects. But it requires a "capability".
|
||||
@@ -130,6 +132,18 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
.AddParameter("expression", "Parameter 1 (a number)")
|
||||
.SetFunctionName("doSomething");
|
||||
|
||||
extension
|
||||
->AddAction("DoSomethingWithObjects",
|
||||
"Do something",
|
||||
"This does something",
|
||||
"Do something please",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("object", _("Object 1 parameter"))
|
||||
.AddParameter("object", _("Object 2 parameter"))
|
||||
.SetFunctionName("doSomethingWithObjects");
|
||||
|
||||
extension
|
||||
->AddAction("DoSomethingWithResources",
|
||||
"Do something with resources",
|
||||
@@ -214,7 +228,7 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
.AddParameter("objectvar", _("Variable for object 2"))
|
||||
.SetFunctionName("getStringWith1ObjectParamAnd2ObjectVarParam");
|
||||
|
||||
auto& object = extension->AddObject<gd::Object>(
|
||||
auto& object = extension->AddObject<gd::SpriteObject>(
|
||||
"Sprite", "Dummy Sprite", "Dummy sprite object", "");
|
||||
object
|
||||
.AddExpression("GetObjectVariableAsNumber",
|
||||
@@ -351,7 +365,7 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
|
||||
{
|
||||
auto& object = extension
|
||||
->AddObject<gd::Object>(
|
||||
->AddObject<gd::ObjectConfiguration>(
|
||||
"FakeObjectWithUnsupportedCapability",
|
||||
"FakeObjectWithUnsupportedCapability",
|
||||
"This is FakeObjectWithUnsupportedCapability",
|
||||
|
76
Core/tests/EventsExtension.cpp
Normal file
76
Core/tests/EventsExtension.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 events-based extensions
|
||||
*/
|
||||
#include "GDCore/IDE/WholeProjectRefactorer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "DummyPlatform.h"
|
||||
#include "GDCore/Events/Builtin/LinkEvent.h"
|
||||
#include "GDCore/Events/Builtin/StandardEvent.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/IDE/UnfilledRequiredBehaviorPropertyProblem.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
#include "GDCore/Project/ExternalLayout.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
gd::EventsFunctionsExtension &
|
||||
SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
auto &eventsExtension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
|
||||
// Add an events-based behavior
|
||||
{
|
||||
auto &eventsBasedBehavior =
|
||||
eventsExtension.GetEventsBasedBehaviors().InsertNew(
|
||||
"MyEventsBasedBehavior", 0);
|
||||
eventsBasedBehavior.SetFullName("My events based behavior");
|
||||
eventsBasedBehavior.SetDescription("An events based behavior for test");
|
||||
|
||||
// Add a property
|
||||
eventsBasedBehavior.GetPropertyDescriptors()
|
||||
.InsertNew("MyProperty", 0)
|
||||
.SetValue("123")
|
||||
.SetType("Number");
|
||||
}
|
||||
|
||||
return eventsExtension;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Events-based extension", "[common]") {
|
||||
SECTION("Behavior property default value") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &layout1 = project.InsertNewLayout("Layout1", 0);
|
||||
auto &object = layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
|
||||
|
||||
// Attach a behavior to an object.
|
||||
auto *behavior = object.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior", "MyEventsBasedBehavior");
|
||||
behavior->InitializeContent();
|
||||
|
||||
// The behavior has the default value.
|
||||
REQUIRE(behavior->GetProperties().size() == 1);
|
||||
REQUIRE(behavior->GetProperties().at("MyProperty").GetValue() == "123");
|
||||
}
|
||||
}
|
111
Core/tests/ObjectSerialization.cpp
Normal file
111
Core/tests/ObjectSerialization.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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 serialization to JSON.
|
||||
*/
|
||||
#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/Platform.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.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"
|
||||
|
||||
using namespace gd;
|
||||
|
||||
namespace {
|
||||
|
||||
void SetupProject(gd::Project &project, gd::Platform &platform) {
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
|
||||
gd::Object &object =
|
||||
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
|
||||
|
||||
auto &configuration = object.GetConfiguration();
|
||||
auto *spriteConfiguration = dynamic_cast<gd::SpriteObject *>(&configuration);
|
||||
REQUIRE(spriteConfiguration != nullptr);
|
||||
gd::Animation animation;
|
||||
animation.SetName("Idle");
|
||||
spriteConfiguration->AddAnimation(animation);
|
||||
};
|
||||
|
||||
void CheckSpriteConfiguration(
|
||||
SerializerElement &objectContainerElement) {
|
||||
};
|
||||
|
||||
void CheckSpriteConfigurationInElement(SerializerElement &projectElement) {
|
||||
auto &layoutsElement = projectElement.GetChild("layouts");
|
||||
layoutsElement.ConsiderAsArrayOf("layout");
|
||||
REQUIRE(layoutsElement.GetChildrenCount() == 1);
|
||||
auto &layoutElement = layoutsElement.GetChild(0);
|
||||
|
||||
REQUIRE(layoutElement.GetStringAttribute("name") == "Scene");
|
||||
REQUIRE(layoutElement.HasChild("objects"));
|
||||
|
||||
auto &objectsElement = layoutElement.GetChild("objects");
|
||||
objectsElement.ConsiderAsArrayOf("object");
|
||||
REQUIRE(objectsElement.GetChildrenCount() == 1);
|
||||
auto &objectElement = objectsElement.GetChild(0);
|
||||
|
||||
REQUIRE(objectElement.GetStringAttribute("name") == "MyObject");
|
||||
REQUIRE(objectElement.GetStringAttribute("type") == "MyExtension::Sprite");
|
||||
|
||||
REQUIRE(objectElement.HasChild("animations"));
|
||||
auto &animationsElement = objectElement.GetChild("animations");
|
||||
animationsElement.ConsiderAsArrayOf("animation");
|
||||
REQUIRE(animationsElement.GetChildrenCount() == 1);
|
||||
auto &animationElement = animationsElement.GetChild(0);
|
||||
|
||||
REQUIRE(animationElement.GetStringAttribute("name") ==
|
||||
"Idle");
|
||||
};
|
||||
|
||||
void CheckSpriteConfiguration(gd::Project &project) {
|
||||
auto &layout = project.GetLayout("Scene");
|
||||
auto &object = layout.GetObject("MyObject");
|
||||
REQUIRE(object.GetName() == "MyObject");
|
||||
REQUIRE(object.GetType() == "MyExtension::Sprite");
|
||||
|
||||
auto &configuration = object.GetConfiguration();
|
||||
auto *spriteConfiguration = dynamic_cast<gd::SpriteObject *>(&configuration);
|
||||
REQUIRE(spriteConfiguration);
|
||||
REQUIRE(spriteConfiguration->GetAnimationsCount() == 1);
|
||||
|
||||
auto &animation = spriteConfiguration->GetAnimation(0);
|
||||
REQUIRE(animation.GetName() == "Idle");
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("ObjectSerialization", "[common]") {
|
||||
|
||||
SECTION("Save and load a project with a sprite configuration") {
|
||||
gd::Platform platform;
|
||||
gd::Project writtenProject;
|
||||
SetupProject(writtenProject, platform);
|
||||
CheckSpriteConfiguration(writtenProject);
|
||||
|
||||
SerializerElement projectElement;
|
||||
writtenProject.SerializeTo(projectElement);
|
||||
CheckSpriteConfigurationInElement(projectElement);
|
||||
|
||||
gd::Project readProject;
|
||||
readProject.AddPlatform(platform);
|
||||
readProject.UnserializeFrom(projectElement);
|
||||
CheckSpriteConfiguration(readProject);
|
||||
}
|
||||
}
|
@@ -67,7 +67,9 @@ const gd::String &GetEventFirstActionType(const gd::BaseEvent &event) {
|
||||
|
||||
enum TestEvent {
|
||||
FreeFunctionAction,
|
||||
FreeFunctionExpression,
|
||||
FreeFunctionWithExpression,
|
||||
FreeFunctionWithObjects,
|
||||
FreeFunctionWithObjectExpression,
|
||||
|
||||
BehaviorAction,
|
||||
BehaviorPropertyAction,
|
||||
@@ -113,7 +115,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
if (eventList.GetEventsCount() != FreeFunctionAction) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
}
|
||||
// Create an event in the layout referring to
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsFunction
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
@@ -128,10 +130,10 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != FreeFunctionExpression) {
|
||||
if (eventList.GetEventsCount() != FreeFunctionWithExpression) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
}
|
||||
// Create an event in the external events referring to
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsFunctionExpression
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
@@ -145,6 +147,38 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
event.GetActions().Insert(action);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != FreeFunctionWithObjects) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
}
|
||||
// Create an event referring to objects
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::DoSomethingWithObjects");
|
||||
action.SetParametersCount(2);
|
||||
action.SetParameter(0, gd::Expression("ObjectWithMyBehavior"));
|
||||
action.SetParameter(1, gd::Expression("MyCustomObject"));
|
||||
event.GetActions().Insert(action);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != FreeFunctionWithObjectExpression) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
}
|
||||
// Create an event referring to objects in an expression
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::DoSomething");
|
||||
action.SetParametersCount(1);
|
||||
action.SetParameter(
|
||||
0,
|
||||
gd::Expression(
|
||||
"ObjectWithMyBehavior.GetObjectNumber()"));
|
||||
event.GetActions().Insert(action);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Add some events based behavior usages in events
|
||||
@@ -854,6 +888,30 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
REQUIRE(externalLayout2.GetInitialInstances().HasInstancesOfObject(
|
||||
"GlobalObject3") == true);
|
||||
}
|
||||
|
||||
SECTION("Events") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
auto &layout = project.GetLayout("Scene");
|
||||
|
||||
// Trigger the refactoring after the renaming of an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
|
||||
project, layout, "ObjectWithMyBehavior", "RenamedObjectWithMyBehavior",
|
||||
/* isObjectGroup=*/false);
|
||||
|
||||
// Check object name has been renamed in action parameters.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
layout.GetEvents().GetEvent(FreeFunctionWithObjects)) ==
|
||||
"RenamedObjectWithMyBehavior");
|
||||
|
||||
// Check object name has been renamed in expressions.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
layout.GetEvents().GetEvent(FreeFunctionWithObjectExpression)) ==
|
||||
"RenamedObjectWithMyBehavior.GetObjectNumber()");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Object renamed (in events function)") {
|
||||
@@ -894,6 +952,43 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
// Events are not tested
|
||||
}
|
||||
|
||||
SECTION("Object renamed (in events-based object)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
auto &eventsBasedObject =
|
||||
project.GetEventsFunctionsExtension("MyEventsExtension")
|
||||
.GetEventsBasedObjects()
|
||||
.Get("MyOtherEventsBasedObject");
|
||||
|
||||
// Create the objects container for the events function
|
||||
gd::ObjectsContainer globalObjectsContainer;
|
||||
|
||||
// Trigger the refactoring after the renaming of an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
|
||||
project, globalObjectsContainer, eventsBasedObject,
|
||||
"ObjectWithMyBehavior", "RenamedObjectWithMyBehavior",
|
||||
/* isObjectGroup=*/false);
|
||||
|
||||
auto &objectFunctionEvents =
|
||||
eventsBasedObject
|
||||
.GetEventsFunctions()
|
||||
.GetEventsFunction("MyObjectEventsFunction")
|
||||
.GetEvents();
|
||||
|
||||
// Check object name has been renamed in action parameters.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
objectFunctionEvents.GetEvent(FreeFunctionWithObjects)) ==
|
||||
"RenamedObjectWithMyBehavior");
|
||||
|
||||
// Check object name has been renamed in expressions.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
objectFunctionEvents.GetEvent(FreeFunctionWithObjectExpression)) ==
|
||||
"RenamedObjectWithMyBehavior.GetObjectNumber()");
|
||||
}
|
||||
|
||||
SECTION("Object deleted (in events function)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
@@ -948,7 +1043,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
|
||||
// Check that events function calls in expressions have been renamed
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(FreeFunctionExpression)) ==
|
||||
eventsList->GetEvent(FreeFunctionWithExpression)) ==
|
||||
"1 + MyRenamedExtension::MyEventsFunctionExpression(123, 456)");
|
||||
|
||||
// Check that the type of the behavior was changed in the behaviors of
|
||||
@@ -1137,7 +1232,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
for (auto *eventsList : GetEventsLists(project)) {
|
||||
// Check that events function calls in expressions have been renamed
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(FreeFunctionExpression)) ==
|
||||
eventsList->GetEvent(FreeFunctionWithExpression)) ==
|
||||
"1 + MyEventsExtension::MyRenamedFunctionExpression(123, 456)");
|
||||
}
|
||||
}
|
||||
@@ -1177,7 +1272,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
for (auto *eventsList : GetEventsLists(project)) {
|
||||
// Check that events function calls in expressions have been updated
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(FreeFunctionExpression)) ==
|
||||
eventsList->GetEvent(FreeFunctionWithExpression)) ==
|
||||
"1 + MyEventsExtension::MyEventsFunctionExpression(456, 123)");
|
||||
}
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@ module.exports = {
|
||||
'Arthur Pacaud (arthuro555)',
|
||||
'MIT'
|
||||
)
|
||||
.setCategory('Device');
|
||||
.setCategory('User interface');
|
||||
extension
|
||||
.addInstructionOrExpressionGroupMetadata(_('Advanced window management'))
|
||||
.setIcon('res/actions/window24.png');
|
||||
|
@@ -17,6 +17,7 @@ void DeclareAnchorBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Anchor objects to the window's bounds."),
|
||||
"Victor Levasseur",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("User interface")
|
||||
.SetExtensionHelpPath("/behaviors/anchor");
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
|
@@ -33,7 +33,10 @@ module.exports = {
|
||||
'Todor Imreorov',
|
||||
'Open source (MIT License)'
|
||||
)
|
||||
.setExtensionHelpPath('/objects/bbtext');
|
||||
.setExtensionHelpPath('/objects/bbtext')
|
||||
.setCategory('User interface');
|
||||
extension.addInstructionOrExpressionGroupMetadata(_("BBCode Text Object"))
|
||||
.setIcon("JsPlatform/Extensions/bbcode32.png");
|
||||
|
||||
var objectBBText = new gd.ObjectJsImplementation();
|
||||
// $FlowExpectedError
|
||||
@@ -168,7 +171,7 @@ module.exports = {
|
||||
.addIncludeFile(
|
||||
'Extensions/BBText/pixi-multistyle-text/dist/pixi-multistyle-text.umd.js'
|
||||
)
|
||||
.setCategoryFullName(_('Texts'));
|
||||
.setCategoryFullName(_('User interface'));
|
||||
|
||||
/**
|
||||
* Utility function to add both a setter and a getter to a property from a list.
|
||||
@@ -289,7 +292,7 @@ module.exports = {
|
||||
const setterAndGetterProperties = [
|
||||
{
|
||||
functionName: 'BBText',
|
||||
iconPath: 'res/actions/text24.png',
|
||||
iconPath: 'res/actions/text24_black.png',
|
||||
type: 'string',
|
||||
paramLabel: _('BBCode text'),
|
||||
conditionDescription: _('Compare the value of the BBCode text.'),
|
||||
@@ -364,7 +367,7 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
functionName: 'WordWrap',
|
||||
iconPath: 'res/actions/scaleWidth24.png',
|
||||
iconPath: 'res/actions/scaleWidth24_black.png',
|
||||
type: 'boolean',
|
||||
paramLabel: _('Word wrap'),
|
||||
conditionDescription: _('Check if word wrap is enabled.'),
|
||||
@@ -376,7 +379,7 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
functionName: 'WrappingWidth',
|
||||
iconPath: 'res/actions/scaleWidth24.png',
|
||||
iconPath: 'res/actions/scaleWidth24_black.png',
|
||||
type: 'number',
|
||||
paramLabel: _('Wrapping width'),
|
||||
conditionDescription: _(
|
||||
@@ -454,7 +457,7 @@ module.exports = {
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
) {
|
||||
@@ -463,7 +466,7 @@ module.exports = {
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
);
|
||||
@@ -498,7 +501,7 @@ module.exports = {
|
||||
RenderedBBTextInstance.getThumbnail = function (
|
||||
project,
|
||||
resourcesLoader,
|
||||
object
|
||||
objectConfiguration
|
||||
) {
|
||||
return 'JsPlatform/Extensions/bbcode24.png';
|
||||
};
|
||||
@@ -507,7 +510,8 @@ module.exports = {
|
||||
* This is called to update the PIXI object on the scene editor
|
||||
*/
|
||||
RenderedBBTextInstance.prototype.update = function () {
|
||||
const properties = this._associatedObject.getProperties();
|
||||
const properties = this._associatedObjectConfiguration
|
||||
.getProperties();
|
||||
|
||||
const rawText = properties.get('text').getValue();
|
||||
if (rawText !== this._pixiObject.text) {
|
||||
|
@@ -35,7 +35,10 @@ module.exports = {
|
||||
'Aurélien Vivet',
|
||||
'Open source (MIT License)'
|
||||
)
|
||||
.setExtensionHelpPath('/objects/bitmap_text');
|
||||
.setExtensionHelpPath('/objects/bitmap_text')
|
||||
.setCategory('User interface');
|
||||
extension.addInstructionOrExpressionGroupMetadata(_("Bitmap Text"))
|
||||
.setIcon("JsPlatform/Extensions/bitmapfont32.png");
|
||||
|
||||
const bitmapTextObject = new gd.ObjectJsImplementation();
|
||||
// $FlowExpectedError
|
||||
@@ -171,7 +174,7 @@ module.exports = {
|
||||
.addIncludeFile(
|
||||
'Extensions/BitmapText/bitmaptextruntimeobject-pixi-renderer.js'
|
||||
)
|
||||
.setCategoryFullName(_('Texts'));
|
||||
.setCategoryFullName(_('User interface'));
|
||||
|
||||
object
|
||||
.addExpressionAndConditionAndAction(
|
||||
@@ -181,7 +184,7 @@ module.exports = {
|
||||
_('the text'),
|
||||
_('the text'),
|
||||
'',
|
||||
'res/conditions/text24.png'
|
||||
'res/conditions/text24_black.png'
|
||||
)
|
||||
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
|
||||
.useStandardParameters('string')
|
||||
@@ -225,7 +228,7 @@ module.exports = {
|
||||
_('the scale (1 by default)'),
|
||||
_('the scale'),
|
||||
'',
|
||||
'res/actions/scale24.png'
|
||||
'res/actions/scale24_black.png'
|
||||
)
|
||||
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
|
||||
.useStandardParameters('number')
|
||||
@@ -331,8 +334,8 @@ module.exports = {
|
||||
_('Check if word wrap is enabled.'),
|
||||
_('_PARAM0_ word wrap is enabled'),
|
||||
'',
|
||||
'res/conditions/wordWrap24.png',
|
||||
'res/conditions/wordWrap.png'
|
||||
'res/conditions/wordWrap24_black.png',
|
||||
'res/conditions/wordWrap_black.png'
|
||||
)
|
||||
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
|
||||
.getCodeExtraInformation()
|
||||
@@ -345,8 +348,8 @@ module.exports = {
|
||||
_('De/activate word wrapping.'),
|
||||
_('Activate word wrap of _PARAM0_: _PARAM1_'),
|
||||
'',
|
||||
'res/actions/wordWrap24.png',
|
||||
'res/actions/wordWrap.png'
|
||||
'res/actions/wordWrap24_black.png',
|
||||
'res/actions/wordWrap_black.png'
|
||||
)
|
||||
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
|
||||
.addParameter('yesorno', _('Activate word wrap'), '', false)
|
||||
@@ -361,7 +364,7 @@ module.exports = {
|
||||
_('the width, in pixels, after which the text is wrapped on next line'),
|
||||
_('the wrapping width'),
|
||||
'',
|
||||
'res/actions/scaleWidth24.png'
|
||||
'res/actions/scaleWidth24_black.png'
|
||||
)
|
||||
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
|
||||
.useStandardParameters('number')
|
||||
@@ -589,7 +592,7 @@ module.exports = {
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
) {
|
||||
@@ -598,7 +601,7 @@ module.exports = {
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
);
|
||||
@@ -627,14 +630,15 @@ module.exports = {
|
||||
RenderedBitmapTextInstance.getThumbnail = function (
|
||||
project,
|
||||
resourcesLoader,
|
||||
object
|
||||
objectConfiguration
|
||||
) {
|
||||
return 'JsPlatform/Extensions/bitmapfont24.png';
|
||||
};
|
||||
|
||||
// This is called to update the PIXI object on the scene editor
|
||||
RenderedBitmapTextInstance.prototype.update = function () {
|
||||
const properties = this._associatedObject.getProperties();
|
||||
const properties = this._associatedObjectConfiguration
|
||||
.getProperties();
|
||||
|
||||
// Update the rendered text properties (note: Pixi is only
|
||||
// applying changes if there were changed).
|
||||
|
@@ -20,6 +20,7 @@ void DeclareDestroyOutsideBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
"or other short-lived objects."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("Game mechanic")
|
||||
.SetExtensionHelpPath("/behaviors/destroyoutside");
|
||||
|
||||
gd::BehaviorMetadata& aut =
|
||||
|
@@ -31,7 +31,7 @@ module.exports = {
|
||||
"Matthias Meike",
|
||||
"Open source (MIT License)"
|
||||
).setExtensionHelpPath("/all-features/device-sensors")
|
||||
.setCategory('Device');
|
||||
.setCategory('Input');
|
||||
extension.addInstructionOrExpressionGroupMetadata(_("Device sensors"))
|
||||
.setIcon("JsPlatform/Extensions/orientation_active32.png");
|
||||
|
||||
|
@@ -35,7 +35,7 @@ module.exports = {
|
||||
'Open source (MIT License)'
|
||||
)
|
||||
.setExtensionHelpPath('/all-features/device-vibration')
|
||||
.setCategory('Device');
|
||||
.setCategory('User interface');
|
||||
extension.addInstructionOrExpressionGroupMetadata(_("Device vibration"))
|
||||
.setIcon("JsPlatform/Extensions/vibration_start32.png");
|
||||
|
||||
|
@@ -34,7 +34,7 @@ module.exports = {
|
||||
'Open source (MIT License)'
|
||||
)
|
||||
.setExtensionHelpPath('/all-features/dialogue-tree')
|
||||
.setCategory('Advanced');
|
||||
.setCategory('Game mechanic');
|
||||
extension
|
||||
.addInstructionOrExpressionGroupMetadata(_('Dialogue Tree (experimental)'))
|
||||
.setIcon('JsPlatform/Extensions/yarn32.png');
|
||||
|
@@ -20,6 +20,7 @@ void DeclareDraggableBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
"or disable the behavior when needed."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("User interface")
|
||||
.SetExtensionHelpPath("/behaviors/draggable");
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
|
@@ -31,7 +31,9 @@ module.exports = {
|
||||
'Lots of different effects to be used in your game.',
|
||||
'Various contributors from PixiJS, PixiJS filters and GDevelop',
|
||||
'MIT'
|
||||
).setExtensionHelpPath('/interface/scene-editor/layer-effects');
|
||||
)
|
||||
.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
|
||||
|
@@ -506,7 +506,7 @@ module.exports = {
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
) {
|
||||
@@ -515,7 +515,7 @@ module.exports = {
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
);
|
||||
@@ -539,7 +539,7 @@ module.exports = {
|
||||
RenderedDummyObjectInstance.getThumbnail = function (
|
||||
project,
|
||||
resourcesLoader,
|
||||
object
|
||||
objectConfiguration
|
||||
) {
|
||||
return 'CppPlatform/Extensions/texticon24.png';
|
||||
};
|
||||
@@ -549,7 +549,7 @@ module.exports = {
|
||||
*/
|
||||
RenderedDummyObjectInstance.prototype.update = function () {
|
||||
// Read a property from the object
|
||||
const property1Value = this._associatedObject
|
||||
const property1Value = this._associatedObjectConfiguration
|
||||
.getProperties()
|
||||
.get('My first property')
|
||||
.getValue();
|
||||
|
@@ -34,7 +34,7 @@ module.exports = {
|
||||
'Open source (MIT License)'
|
||||
)
|
||||
.setExtensionHelpPath('/all-features/filesystem')
|
||||
.setCategory('Device');
|
||||
.setCategory('Advanced');
|
||||
extension
|
||||
.addInstructionOrExpressionGroupMetadata(_('File system'))
|
||||
.setIcon('JsPlatform/Extensions/filesystem_create_folder32.png');
|
||||
@@ -203,6 +203,18 @@ module.exports = {
|
||||
'',
|
||||
true
|
||||
)
|
||||
.addParameter(
|
||||
'yesorno',
|
||||
_('Normalize the file content (recommended)'),
|
||||
'',
|
||||
true
|
||||
)
|
||||
.setParameterLongDescription(
|
||||
_(
|
||||
'This replaces Windows new lines characters ("CRLF") by a single new line character.'
|
||||
)
|
||||
)
|
||||
.setDefaultValue('yes')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
|
||||
.setFunctionName('gdjs.fileSystem.loadStringFromFileAsync');
|
||||
@@ -229,6 +241,18 @@ module.exports = {
|
||||
'',
|
||||
true
|
||||
)
|
||||
.addParameter(
|
||||
'yesorno',
|
||||
_('Normalize the file content (recommended)'),
|
||||
'',
|
||||
true
|
||||
)
|
||||
.setParameterLongDescription(
|
||||
_(
|
||||
'This replaces Windows new lines characters ("CRLF") by a single new line character.'
|
||||
)
|
||||
)
|
||||
.setDefaultValue('yes')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
|
||||
.setFunctionName('gdjs.fileSystem.loadStringFromFile');
|
||||
@@ -255,6 +279,18 @@ module.exports = {
|
||||
'',
|
||||
true
|
||||
)
|
||||
.addParameter(
|
||||
'yesorno',
|
||||
_('Normalize the file content (recommended)'),
|
||||
'',
|
||||
true
|
||||
)
|
||||
.setParameterLongDescription(
|
||||
_(
|
||||
'This replaces Windows new lines characters ("CRLF") by a single new line character.'
|
||||
)
|
||||
)
|
||||
.setDefaultValue('yes')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
|
||||
.setFunctionName('gdjs.fileSystem.loadVariableFromJSONFile');
|
||||
@@ -281,6 +317,18 @@ module.exports = {
|
||||
'',
|
||||
true
|
||||
)
|
||||
.addParameter(
|
||||
'yesorno',
|
||||
_('Normalize the file content (recommended)'),
|
||||
'',
|
||||
true
|
||||
)
|
||||
.setParameterLongDescription(
|
||||
_(
|
||||
'This replaces Windows new lines characters ("CRLF") by a single new line character.'
|
||||
)
|
||||
)
|
||||
.setDefaultValue('yes')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
|
||||
.setFunctionName('gdjs.fileSystem.loadVariableFromJSONFileAsync');
|
||||
|
@@ -338,11 +338,13 @@ namespace gdjs {
|
||||
* @param stringVar Variable where to store the content
|
||||
* @param loadPath Path to the file
|
||||
* @param resultVar The variable where to store the result of the operation
|
||||
* @param removeCRCharacters If true, will remove \r characters usually added by Windows when editing files
|
||||
*/
|
||||
export const loadStringFromFile = function (
|
||||
stringVar: gdjs.Variable,
|
||||
loadPath: string,
|
||||
resultVar: gdjs.Variable
|
||||
resultVar: gdjs.Variable,
|
||||
removeCRCharacters: boolean
|
||||
) {
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
let result = 'error';
|
||||
@@ -350,7 +352,9 @@ namespace gdjs {
|
||||
try {
|
||||
const data = fileSystem.readFileSync(loadPath, 'utf8');
|
||||
if (data) {
|
||||
stringVar.setString(data);
|
||||
stringVar.setString(
|
||||
removeCRCharacters ? data.replace(/\r/g, '') : data
|
||||
);
|
||||
result = 'ok';
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -368,11 +372,13 @@ namespace gdjs {
|
||||
* @param variable Variable to store the variable
|
||||
* @param loadPath Path to the file
|
||||
* @param resultVar The variable where to store the result of the operation
|
||||
* @param removeCRCharacters If true, will remove \r characters usually added by Windows when editing files
|
||||
*/
|
||||
export const loadVariableFromJSONFile = function (
|
||||
variable: gdjs.Variable,
|
||||
loadPath: string,
|
||||
resultVar: gdjs.Variable
|
||||
resultVar: gdjs.Variable,
|
||||
removeCRCharacters: boolean
|
||||
) {
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
let result = 'error';
|
||||
@@ -380,7 +386,9 @@ namespace gdjs {
|
||||
try {
|
||||
const data = fileSystem.readFileSync(loadPath, 'utf8');
|
||||
if (data) {
|
||||
variable.fromJSON(data);
|
||||
variable.fromJSON(
|
||||
removeCRCharacters ? data.replace(/\r/g, '') : data
|
||||
);
|
||||
result = 'ok';
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -400,17 +408,21 @@ namespace gdjs {
|
||||
* @param variable Variable to store the variable
|
||||
* @param loadPath Path to the file
|
||||
* @param resultVar The variable where to store the result of the operation
|
||||
* @param removeCRCharacters If true, will remove \r characters usually added by Windows when editing files
|
||||
*/
|
||||
export const loadVariableFromJSONFileAsync = function (
|
||||
variable: gdjs.Variable,
|
||||
loadPath: string,
|
||||
resultVar: gdjs.Variable
|
||||
resultVar: gdjs.Variable,
|
||||
removeCRCharacters: boolean
|
||||
) {
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
if (fileSystem) {
|
||||
fileSystem.readFile(loadPath, 'utf8', (err, data) => {
|
||||
if (data) {
|
||||
variable.fromJSON(data);
|
||||
variable.fromJSON(
|
||||
removeCRCharacters ? data.replace(/\r/g, '') : data
|
||||
);
|
||||
resultVar.setString('ok');
|
||||
}
|
||||
if (err) {
|
||||
@@ -431,17 +443,21 @@ namespace gdjs {
|
||||
* @param stringVar Variable where to store the content
|
||||
* @param loadPath Path to the file
|
||||
* @param resultVar The variable where to store the result of the operation
|
||||
* @param removeCRCharacters If true, will remove \r characters usually added by Windows when editing files
|
||||
*/
|
||||
export const loadStringFromFileAsync = function (
|
||||
stringVar: gdjs.Variable,
|
||||
loadPath: string,
|
||||
resultVar: gdjs.Variable
|
||||
resultVar: gdjs.Variable,
|
||||
removeCRCharacters: boolean
|
||||
) {
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
if (fileSystem) {
|
||||
fileSystem.readFile(loadPath, 'utf8', (err, data) => {
|
||||
if (data) {
|
||||
stringVar.setString(data);
|
||||
stringVar.setString(
|
||||
removeCRCharacters ? data.replace(/\r/g, '') : data
|
||||
);
|
||||
resultVar.setString('ok');
|
||||
}
|
||||
if (err) {
|
||||
|
@@ -19,7 +19,7 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/inventory")
|
||||
.SetCategory("Advanced");
|
||||
.SetCategory("Game mechanic");
|
||||
extension
|
||||
.AddInstructionOrExpressionGroupMetadata(_("Inventories"))
|
||||
.SetIcon("CppPlatform/Extensions/Inventoryicon.png");
|
||||
|
@@ -20,7 +20,7 @@ export type ObjectsRenderingService = {
|
||||
RenderedInstance: any,
|
||||
registerInstanceRenderer: (objectType: string, renderer: any) => void,
|
||||
requireModule: (dirname: string, moduleName: string) => any,
|
||||
getThumbnail: (project: gdProject, object: gdObject) => string,
|
||||
getThumbnail: (project: gdProject, objectConfiguration: gdObjectConfiguration) => string,
|
||||
rgbOrHexToHexNumber: (value: string) => number,
|
||||
};
|
||||
export type ObjectsEditorService = {
|
||||
|
@@ -34,7 +34,7 @@ module.exports = {
|
||||
'Open source (MIT License)'
|
||||
)
|
||||
.setExtensionHelpPath('/all-features/leaderboards')
|
||||
.setCategory('Leaderboards')
|
||||
.setCategory('Players')
|
||||
.addInstructionOrExpressionGroupMetadata(_('Leaderboards (experimental)'))
|
||||
.setIcon('JsPlatform/Extensions/leaderboard.svg');
|
||||
|
||||
@@ -65,6 +65,32 @@ module.exports = {
|
||||
.addIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.savePlayerScore');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SaveConnectedPlayerScore',
|
||||
_('Save connected player score'),
|
||||
_("Save the connected player's score to the given leaderboard."),
|
||||
_(
|
||||
'Send to leaderboard _PARAM1_ the score _PARAM2_ for the connected player'
|
||||
),
|
||||
_('Save score'),
|
||||
'JsPlatform/Extensions/leaderboard.svg',
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.addParameter('leaderboardId', _('Leaderboard'), '', false)
|
||||
.addParameter(
|
||||
'expression',
|
||||
_('Score to register for the player'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
.setHelpPath('/all-features/leaderboards')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/sha256.js')
|
||||
.addIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.saveConnectedPlayerScore');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'HasLastSaveErrored',
|
||||
|
@@ -16,8 +16,10 @@ namespace gdjs {
|
||||
lastScoreSavingSucceededAt: number | null;
|
||||
currentlySavingScore: number | null;
|
||||
currentlySavingPlayerName: string | null;
|
||||
currentlySavingPlayerId: string | null;
|
||||
lastSavedScore: number | null;
|
||||
lastSavedPlayerName: string | null;
|
||||
lastSavedPlayerId: string | null;
|
||||
lastSaveError: string | null;
|
||||
isScoreSaving: boolean;
|
||||
hasScoreBeenSaved: boolean;
|
||||
@@ -28,25 +30,45 @@ namespace gdjs {
|
||||
this.lastScoreSavingSucceededAt = null;
|
||||
this.currentlySavingScore = null;
|
||||
this.currentlySavingPlayerName = null;
|
||||
this.currentlySavingPlayerId = null;
|
||||
this.lastSavedScore = null;
|
||||
this.lastSavedPlayerName = null;
|
||||
this.lastSavedPlayerId = null;
|
||||
this.lastSaveError = null;
|
||||
this.isScoreSaving = false;
|
||||
this.hasScoreBeenSaved = false;
|
||||
this.hasScoreSavingErrored = false;
|
||||
}
|
||||
|
||||
isSameAsLastScore(playerName: string, score: number): boolean {
|
||||
isSameAsLastScore({
|
||||
playerName,
|
||||
playerId,
|
||||
score,
|
||||
}: {
|
||||
playerName?: string;
|
||||
playerId?: string;
|
||||
score: number;
|
||||
}): boolean {
|
||||
return (
|
||||
this.lastSavedPlayerName === playerName &&
|
||||
((!!playerName && this.lastSavedPlayerName === playerName) ||
|
||||
(!!playerId && this.lastSavedPlayerId === playerId)) &&
|
||||
this.lastSavedScore === score
|
||||
);
|
||||
}
|
||||
|
||||
isAlreadySavingThisScore(playerName: string, score: number): boolean {
|
||||
isAlreadySavingThisScore({
|
||||
playerName,
|
||||
playerId,
|
||||
score,
|
||||
}: {
|
||||
playerName?: string;
|
||||
playerId?: string;
|
||||
score: number;
|
||||
}): boolean {
|
||||
return (
|
||||
((!!playerName && this.currentlySavingPlayerName === playerName) ||
|
||||
(!!playerId && this.currentlySavingPlayerId === playerId)) &&
|
||||
this.isScoreSaving &&
|
||||
this.currentlySavingPlayerName === playerName &&
|
||||
this.currentlySavingScore === score
|
||||
);
|
||||
}
|
||||
@@ -58,19 +80,29 @@ namespace gdjs {
|
||||
);
|
||||
}
|
||||
|
||||
startSaving(playerName: string, score: number): void {
|
||||
startSaving({
|
||||
playerName,
|
||||
playerId,
|
||||
score,
|
||||
}: {
|
||||
playerName?: string;
|
||||
playerId?: string;
|
||||
score: number;
|
||||
}): void {
|
||||
this.lastScoreSavingStartedAt = Date.now();
|
||||
this.isScoreSaving = true;
|
||||
this.hasScoreBeenSaved = false;
|
||||
this.hasScoreSavingErrored = false;
|
||||
this.currentlySavingScore = score;
|
||||
this.currentlySavingPlayerName = playerName;
|
||||
if (playerName) this.currentlySavingPlayerName = playerName;
|
||||
if (playerId) this.currentlySavingPlayerId = playerId;
|
||||
}
|
||||
|
||||
closeSaving(): void {
|
||||
this.lastScoreSavingSucceededAt = Date.now();
|
||||
this.lastSavedScore = this.currentlySavingScore;
|
||||
this.lastSavedPlayerName = this.currentlySavingPlayerName;
|
||||
this.lastSavedPlayerId = this.currentlySavingPlayerId;
|
||||
this.isScoreSaving = false;
|
||||
this.hasScoreBeenSaved = true;
|
||||
}
|
||||
@@ -155,50 +187,31 @@ namespace gdjs {
|
||||
return lastScoreSavingState;
|
||||
};
|
||||
|
||||
export const savePlayerScore = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
leaderboardId: string,
|
||||
score: float,
|
||||
playerName: string
|
||||
) {
|
||||
let scoreSavingState: ScoreSavingState;
|
||||
if (_scoreSavingStateByLeaderboard[leaderboardId]) {
|
||||
scoreSavingState = _scoreSavingStateByLeaderboard[leaderboardId];
|
||||
if (scoreSavingState.isAlreadySavingThisScore(playerName, score)) {
|
||||
logger.warn(
|
||||
'There is already a request to save with this player name and this score. Ignoring this one.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (scoreSavingState.isSameAsLastScore(playerName, score)) {
|
||||
logger.warn(
|
||||
'The player and score to be sent are the same as previous one. Ignoring this one.'
|
||||
);
|
||||
const errorCode = 'SAME_AS_PREVIOUS';
|
||||
scoreSavingState.setError(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (scoreSavingState.isTooSoonToSaveAnotherScore()) {
|
||||
logger.warn(
|
||||
'Last entry was sent too little time ago. Ignoring this one.'
|
||||
);
|
||||
const errorCode = 'TOO_FAST';
|
||||
scoreSavingState.setError(errorCode);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
scoreSavingState = new ScoreSavingState();
|
||||
_scoreSavingStateByLeaderboard[leaderboardId] = scoreSavingState;
|
||||
}
|
||||
|
||||
scoreSavingState.startSaving(playerName, score);
|
||||
|
||||
const baseUrl = 'https://api.gdevelop-app.com/play';
|
||||
const saveScore = function ({
|
||||
leaderboardId,
|
||||
playerName,
|
||||
playerId,
|
||||
playerToken,
|
||||
score,
|
||||
scoreSavingState,
|
||||
runtimeScene,
|
||||
}: {
|
||||
leaderboardId: string;
|
||||
playerName?: string;
|
||||
playerId?: string;
|
||||
playerToken?: string;
|
||||
score: number;
|
||||
scoreSavingState: ScoreSavingState;
|
||||
runtimeScene: gdjs.RuntimeScene;
|
||||
}) {
|
||||
const rootApi = runtimeScene
|
||||
.getGame()
|
||||
.isUsingGDevelopDevelopmentEnvironment()
|
||||
? 'https://api-dev.gdevelop.io'
|
||||
: 'https://api.gdevelop.io';
|
||||
const baseUrl = `${rootApi}/play`;
|
||||
const game = runtimeScene.getGame();
|
||||
const payload = JSON.stringify({
|
||||
playerName: formatPlayerName(playerName),
|
||||
const payloadObject = {
|
||||
score: score,
|
||||
sessionId: game.getSessionId(),
|
||||
clientPlayerId: game.getPlayerId(),
|
||||
@@ -206,18 +219,25 @@ namespace gdjs {
|
||||
typeof window !== 'undefined' && (window as any).location
|
||||
? (window as any).location.href
|
||||
: '',
|
||||
});
|
||||
fetch(
|
||||
`${baseUrl}/game/${gdjs.projectData.properties.projectUuid}/leaderboard/${leaderboardId}/entry`,
|
||||
{
|
||||
body: payload,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Digest: computeDigest(payload),
|
||||
},
|
||||
}
|
||||
).then(
|
||||
};
|
||||
if (playerName)
|
||||
payloadObject['playerName'] = formatPlayerName(playerName);
|
||||
const payload = JSON.stringify(payloadObject);
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
Digest: computeDigest(payload),
|
||||
};
|
||||
if (playerToken)
|
||||
headers['Authorization'] = `player-game-token ${playerToken}`;
|
||||
let leaderboardEntryCreationUrl = `${baseUrl}/game/${gdjs.projectData.properties.projectUuid}/leaderboard/${leaderboardId}/entry`;
|
||||
if (playerId) {
|
||||
leaderboardEntryCreationUrl += `?playerId=${playerId}`;
|
||||
}
|
||||
fetch(leaderboardEntryCreationUrl, {
|
||||
body: payload,
|
||||
method: 'POST',
|
||||
headers: headers,
|
||||
}).then(
|
||||
(response) => {
|
||||
if (!response.ok) {
|
||||
const errorCode = response.status.toString();
|
||||
@@ -250,6 +270,114 @@ namespace gdjs {
|
||||
);
|
||||
};
|
||||
|
||||
export const savePlayerScore = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
leaderboardId: string,
|
||||
score: float,
|
||||
playerName: string
|
||||
) {
|
||||
let scoreSavingState: ScoreSavingState;
|
||||
if (_scoreSavingStateByLeaderboard[leaderboardId]) {
|
||||
scoreSavingState = _scoreSavingStateByLeaderboard[leaderboardId];
|
||||
if (
|
||||
scoreSavingState.isAlreadySavingThisScore({ playerName, score })
|
||||
) {
|
||||
logger.warn(
|
||||
'There is already a request to save with this player name and this score. Ignoring this one.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (scoreSavingState.isSameAsLastScore({ playerName, score })) {
|
||||
logger.warn(
|
||||
'The player and score to be sent are the same as previous one. Ignoring this one.'
|
||||
);
|
||||
const errorCode = 'SAME_AS_PREVIOUS';
|
||||
scoreSavingState.setError(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (scoreSavingState.isTooSoonToSaveAnotherScore()) {
|
||||
logger.warn(
|
||||
'Last entry was sent too little time ago. Ignoring this one.'
|
||||
);
|
||||
const errorCode = 'TOO_FAST';
|
||||
scoreSavingState.setError(errorCode);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
scoreSavingState = new ScoreSavingState();
|
||||
_scoreSavingStateByLeaderboard[leaderboardId] = scoreSavingState;
|
||||
}
|
||||
|
||||
scoreSavingState.startSaving({ playerName, score });
|
||||
|
||||
saveScore({
|
||||
leaderboardId,
|
||||
playerName,
|
||||
score,
|
||||
scoreSavingState,
|
||||
runtimeScene,
|
||||
});
|
||||
};
|
||||
|
||||
export const saveConnectedPlayerScore = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
leaderboardId: string,
|
||||
score: float
|
||||
) {
|
||||
let scoreSavingState: ScoreSavingState;
|
||||
const playerId = gdjs.playerAuthentication.getUserId();
|
||||
const playerToken = gdjs.playerAuthentication.getUserToken();
|
||||
if (!playerId || !playerToken) {
|
||||
logger.warn(
|
||||
'Cannot save a score for a connected player if the player is not connected.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (_scoreSavingStateByLeaderboard[leaderboardId]) {
|
||||
scoreSavingState = _scoreSavingStateByLeaderboard[leaderboardId];
|
||||
if (scoreSavingState.isAlreadySavingThisScore({ playerId, score })) {
|
||||
logger.warn(
|
||||
'There is already a request to save with this player ID and this score. Ignoring this one.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (scoreSavingState.isSameAsLastScore({ playerId, score })) {
|
||||
logger.warn(
|
||||
'The player and score to be sent are the same as previous one. Ignoring this one.'
|
||||
);
|
||||
const errorCode = 'SAME_AS_PREVIOUS';
|
||||
scoreSavingState.setError(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (scoreSavingState.isTooSoonToSaveAnotherScore()) {
|
||||
logger.warn(
|
||||
'Last entry was sent too little time ago. Ignoring this one.'
|
||||
);
|
||||
const errorCode = 'TOO_FAST';
|
||||
scoreSavingState.setError(errorCode);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
scoreSavingState = new ScoreSavingState();
|
||||
_scoreSavingStateByLeaderboard[leaderboardId] = scoreSavingState;
|
||||
}
|
||||
|
||||
scoreSavingState.startSaving({ playerId, score });
|
||||
|
||||
saveScore({
|
||||
leaderboardId,
|
||||
playerId,
|
||||
playerToken,
|
||||
score,
|
||||
scoreSavingState,
|
||||
runtimeScene,
|
||||
});
|
||||
};
|
||||
|
||||
export const isSaving = function (leaderboardId?: string): boolean {
|
||||
if (leaderboardId) {
|
||||
return _scoreSavingStateByLeaderboard[leaderboardId]
|
||||
@@ -512,7 +640,12 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
const gameId = gdjs.projectData.properties.projectUuid;
|
||||
const targetUrl = `https://liluo.io/games/${gameId}/leaderboard/${leaderboardId}?inGameEmbedded=true`;
|
||||
const isDev = runtimeScene
|
||||
.getGame()
|
||||
.isUsingGDevelopDevelopmentEnvironment();
|
||||
const targetUrl = `https://liluo.io/games/${gameId}/leaderboard/${leaderboardId}?inGameEmbedded=true${
|
||||
isDev ? '&dev=true' : ''
|
||||
}`;
|
||||
checkLeaderboardAvailability(targetUrl).then(
|
||||
(isAvailable) => {
|
||||
if (leaderboardId !== _requestedLeaderboardId) {
|
||||
|
@@ -32,7 +32,8 @@ module.exports = {
|
||||
'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');
|
||||
|
||||
const lightObstacleBehavior = new gd.BehaviorJsImplementation();
|
||||
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
|
||||
@@ -195,7 +196,7 @@ module.exports = {
|
||||
.setIncludeFile('Extensions/Lighting/lightruntimeobject.js')
|
||||
.addIncludeFile('Extensions/Lighting/lightruntimeobject-pixi-renderer.js')
|
||||
.addIncludeFile('Extensions/Lighting/lightobstacleruntimebehavior.js')
|
||||
.setCategoryFullName(_('Lights'));
|
||||
.setCategoryFullName(_('Visual effect'));
|
||||
|
||||
object
|
||||
.addAction(
|
||||
@@ -269,7 +270,7 @@ module.exports = {
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
) {
|
||||
@@ -278,19 +279,19 @@ module.exports = {
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
);
|
||||
this._radius = parseFloat(
|
||||
this._associatedObject
|
||||
this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('radius')
|
||||
.getValue()
|
||||
);
|
||||
if (this._radius <= 0) this._radius = 1;
|
||||
const colorHex = objectsRenderingService.rgbOrHexToHexNumber(
|
||||
this._associatedObject
|
||||
this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('color')
|
||||
.getValue()
|
||||
@@ -370,7 +371,7 @@ module.exports = {
|
||||
RenderedLightObjectInstance.getThumbnail = function (
|
||||
project,
|
||||
resourcesLoader,
|
||||
object
|
||||
objectConfiguration
|
||||
) {
|
||||
return 'CppPlatform/Extensions/lightIcon32.png';
|
||||
};
|
||||
|
@@ -24,6 +24,8 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) {
|
||||
"Victor Levasseur and Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects/panel_sprite");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Panel Sprite (9-patch) Object"))
|
||||
.SetIcon("CppPlatform/Extensions/PanelSpriteIcon.png");
|
||||
|
||||
gd::ObjectMetadata& obj =
|
||||
extension
|
||||
@@ -85,8 +87,8 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Modify the width of a Panel Sprite."),
|
||||
_("the width"),
|
||||
_("Size and angle"),
|
||||
"res/actions/scaleWidth24.png",
|
||||
"res/actions/scaleWidth.png")
|
||||
"res/actions/scaleWidth24_black.png",
|
||||
"res/actions/scaleWidth_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "PanelSprite")
|
||||
.UseStandardOperatorParameters("number")
|
||||
@@ -98,8 +100,8 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Check the width of a Panel Sprite."),
|
||||
_("the width"),
|
||||
_("Size and angle"),
|
||||
"res/conditions/scaleWidth24.png",
|
||||
"res/conditions/scaleWidth.png")
|
||||
"res/conditions/scaleWidth24_black.png",
|
||||
"res/conditions/scaleWidth_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "PanelSprite")
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
@@ -110,8 +112,8 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Modify the height of a Panel Sprite."),
|
||||
_("the height"),
|
||||
_("Size and angle"),
|
||||
"res/actions/scaleHeight24.png",
|
||||
"res/actions/scaleHeight.png")
|
||||
"res/actions/scaleHeight24_black.png",
|
||||
"res/actions/scaleHeight_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "PanelSprite")
|
||||
.UseStandardOperatorParameters("number")
|
||||
@@ -123,8 +125,8 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Check the height of a Panel Sprite."),
|
||||
_("the height"),
|
||||
_("Size and angle"),
|
||||
"res/conditions/scaleHeight24.png",
|
||||
"res/conditions/scaleHeight.png")
|
||||
"res/conditions/scaleHeight24_black.png",
|
||||
"res/conditions/scaleHeight_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "PanelSprite")
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
@@ -136,8 +138,8 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) {
|
||||
"Modify the angle of a Panel Sprite.",
|
||||
"the angle",
|
||||
_("Size and angle"),
|
||||
"res/actions/rotate24.png",
|
||||
"res/actions/rotate.png")
|
||||
"res/actions/rotate24_black.png",
|
||||
"res/actions/rotate_black.png")
|
||||
|
||||
.SetHidden() // Deprecated
|
||||
.AddParameter("object", _("Object"), "PanelSprite")
|
||||
@@ -150,8 +152,8 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) {
|
||||
"Check the angle of a Panel Sprite.",
|
||||
"the angle",
|
||||
_("Size and angle"),
|
||||
"res/conditions/rotate24.png",
|
||||
"res/conditions/rotate.png")
|
||||
"res/conditions/rotate24_black.png",
|
||||
"res/conditions/rotate_black.png")
|
||||
|
||||
.SetHidden() // Deprecated
|
||||
.AddParameter("object", _("Object"), "PanelSprite")
|
||||
|
@@ -33,24 +33,16 @@ class PanelSpriteObjectJsExtension : public gd::PlatformExtension {
|
||||
GetAllActionsForObject(
|
||||
"PanelSpriteObject::PanelSprite")["PanelSpriteObject::SetOpacity"]
|
||||
.SetFunctionName("setOpacity")
|
||||
.SetGetter("getOpacity")
|
||||
.SetIncludeFile(
|
||||
"Extensions/PanelSpriteObject/panelspriteruntimeobject.js");
|
||||
.SetGetter("getOpacity");
|
||||
GetAllConditionsForObject(
|
||||
"PanelSpriteObject::PanelSprite")["PanelSpriteObject::Opacity"]
|
||||
.SetFunctionName("getOpacity")
|
||||
.SetIncludeFile(
|
||||
"Extensions/TiledSpriteObject/panelspriteruntimeobject.js");
|
||||
.SetFunctionName("getOpacity");
|
||||
GetAllExpressionsForObject(
|
||||
"PanelSpriteObject::PanelSprite")["Opacity"]
|
||||
.SetFunctionName("getOpacity")
|
||||
.SetIncludeFile(
|
||||
"Extensions/TiledSpriteObject/panelspriteruntimeobject.js");
|
||||
.SetFunctionName("getOpacity");
|
||||
GetAllActionsForObject(
|
||||
"PanelSpriteObject::PanelSprite")["PanelSpriteObject::SetColor"]
|
||||
.SetFunctionName("setColor")
|
||||
.SetIncludeFile(
|
||||
"Extensions/TiledSpriteObject/panelspriteruntimeobject.js");
|
||||
.SetFunctionName("setColor");
|
||||
|
||||
GetAllActionsForObject(
|
||||
"PanelSpriteObject::PanelSprite")["PanelSpriteObject::Width"]
|
||||
|
@@ -19,9 +19,8 @@ This project is released under the MIT License.
|
||||
|
||||
using namespace std;
|
||||
|
||||
PanelSpriteObject::PanelSpriteObject(gd::String name_)
|
||||
: Object(name_),
|
||||
textureName(""),
|
||||
PanelSpriteObject::PanelSpriteObject()
|
||||
: textureName(""),
|
||||
width(32),
|
||||
height(32),
|
||||
leftMargin(0),
|
||||
|
@@ -10,7 +10,7 @@ This project is released under the MIT License.
|
||||
#include <memory>
|
||||
#include "GDCore/Project/Object.h"
|
||||
namespace gd {
|
||||
class Object;
|
||||
class ObjectConfiguration;
|
||||
class InitialInstance;
|
||||
class Project;
|
||||
}
|
||||
@@ -18,12 +18,12 @@ class Project;
|
||||
/**
|
||||
* PanelSprite Object
|
||||
*/
|
||||
class GD_EXTENSION_API PanelSpriteObject : public gd::Object {
|
||||
class GD_EXTENSION_API PanelSpriteObject : public gd::ObjectConfiguration {
|
||||
public:
|
||||
PanelSpriteObject(gd::String name_);
|
||||
PanelSpriteObject();
|
||||
virtual ~PanelSpriteObject();
|
||||
virtual std::unique_ptr<gd::Object> Clone() const {
|
||||
return std::unique_ptr<gd::Object>(new PanelSpriteObject(*this));
|
||||
virtual std::unique_ptr<gd::ObjectConfiguration> Clone() const {
|
||||
return std::unique_ptr<gd::ObjectConfiguration>(new PanelSpriteObject(*this));
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
|
@@ -25,7 +25,10 @@ void DeclareParticleSystemExtension(gd::PlatformExtension& extension) {
|
||||
"explosions, magical effects, etc...",
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("Visual effect")
|
||||
.SetExtensionHelpPath("/objects/particles_emitter");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Particle system"))
|
||||
.SetIcon("CppPlatform/Extensions/particleSystemicon.png");
|
||||
|
||||
// Declaration of all objects available
|
||||
{
|
||||
@@ -37,7 +40,7 @@ void DeclareParticleSystemExtension(gd::PlatformExtension& extension) {
|
||||
_("Displays a large number of small particles to create visual "
|
||||
"effects."),
|
||||
"CppPlatform/Extensions/particleSystemicon.png")
|
||||
.SetCategoryFullName(_("General"));
|
||||
.SetCategoryFullName(_("Visual effect"));
|
||||
|
||||
// Declaration is too big to be compiled by GCC in one file, unless you have
|
||||
// 4GB+ ram. :/
|
||||
|
@@ -55,8 +55,7 @@ ParticleEmitterBase::ParticleEmitterBase()
|
||||
maxParticleNb(300),
|
||||
destroyWhenNoParticles(true) {}
|
||||
|
||||
ParticleEmitterObject::ParticleEmitterObject(gd::String name_)
|
||||
: Object(name_) {}
|
||||
ParticleEmitterObject::ParticleEmitterObject() {}
|
||||
|
||||
void ParticleEmitterObject::DoUnserializeFrom(
|
||||
gd::Project& project, const gd::SerializerElement& element) {
|
||||
|
@@ -8,7 +8,7 @@ This project is released under the MIT License.
|
||||
#ifndef PARTICLEEMITTEROBJECT_H
|
||||
#define PARTICLEEMITTEROBJECT_H
|
||||
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
namespace gd {
|
||||
class InitialInstance;
|
||||
class Project;
|
||||
@@ -211,12 +211,12 @@ class GD_EXTENSION_API ParticleEmitterBase {
|
||||
/**
|
||||
* \brief Particle Emitter object used for storage and for the IDE.
|
||||
*/
|
||||
class GD_EXTENSION_API ParticleEmitterObject : public gd::Object,
|
||||
class GD_EXTENSION_API ParticleEmitterObject : public gd::ObjectConfiguration,
|
||||
public ParticleEmitterBase {
|
||||
public:
|
||||
ParticleEmitterObject(gd::String name_);
|
||||
ParticleEmitterObject();
|
||||
virtual ~ParticleEmitterObject(){};
|
||||
virtual std::unique_ptr<gd::Object> Clone() const {
|
||||
virtual std::unique_ptr<gd::ObjectConfiguration> Clone() const {
|
||||
return gd::make_unique<ParticleEmitterObject>(*this);
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,10 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
"avoiding obstacles on the way.",
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("Movement")
|
||||
.SetExtensionHelpPath("/behaviors/pathfinding");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Pathfinding behavior"))
|
||||
.SetIcon("CppPlatform/Extensions/AStaricon16.png");
|
||||
|
||||
{
|
||||
gd::BehaviorMetadata& aut =
|
||||
|
@@ -34,7 +34,7 @@ module.exports = {
|
||||
'MIT'
|
||||
)
|
||||
.setExtensionHelpPath('/behaviors/physics2')
|
||||
.setCategory('Advanced');
|
||||
.setCategory('Movement');
|
||||
extension
|
||||
.addInstructionOrExpressionGroupMetadata(_('Physics Engine 2.0'))
|
||||
.setIcon('res/physics32.png');
|
||||
@@ -3816,6 +3816,23 @@ module.exports = {
|
||||
gd /*: libGDevelop */,
|
||||
extension /*: gdPlatformExtension*/
|
||||
) {
|
||||
return [];
|
||||
const dummyBehavior = extension
|
||||
.getBehaviorMetadata('Physics2::Physics2Behavior')
|
||||
.get();
|
||||
const sharedData = extension
|
||||
.getBehaviorMetadata('Physics2::Physics2Behavior')
|
||||
.getSharedDataInstance();
|
||||
return [
|
||||
gd.ProjectHelper.sanityCheckBehaviorProperty(
|
||||
dummyBehavior,
|
||||
'density',
|
||||
'123'
|
||||
),
|
||||
gd.ProjectHelper.sanityCheckBehaviorsSharedDataProperty(
|
||||
sharedData,
|
||||
'gravityY',
|
||||
'456'
|
||||
),
|
||||
];
|
||||
},
|
||||
};
|
||||
|
@@ -21,7 +21,10 @@ void DeclarePhysicsBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
"This is the old, deprecated physics engine. Prefer to use the Physics Engine 2.0.",
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("Movement")
|
||||
.SetExtensionHelpPath("/behaviors/physics");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Physics Engine (deprecated)"))
|
||||
.SetIcon("res/physics16.png");
|
||||
|
||||
{
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
|
@@ -27,6 +27,7 @@ void DeclarePlatformBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
"could be used.",
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("Movement")
|
||||
.SetExtensionHelpPath("/behaviors/platformer");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Platform behavior"))
|
||||
.SetIcon("CppPlatform/Extensions/platformerobjecticon.png");
|
||||
|
197
Extensions/PlayerAuthentication/JsExtension.js
Normal file
197
Extensions/PlayerAuthentication/JsExtension.js
Normal file
@@ -0,0 +1,197 @@
|
||||
// @flow
|
||||
/**
|
||||
* This is a declaration of an extension for GDevelop 5.
|
||||
*
|
||||
* ℹ️ Changes in this file are watched and automatically imported if the editor
|
||||
* is running. You can also manually run `node import-GDJS-Runtime.js` (in newIDE/app/scripts).
|
||||
*
|
||||
* The file must be named "JsExtension.js", otherwise GDevelop won't load it.
|
||||
* ⚠️ If you make a change and the extension is not loaded, open the developer console
|
||||
* and search for any errors.
|
||||
*
|
||||
* 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'
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
createExtension: function (
|
||||
_ /*: (string) => string */,
|
||||
gd /*: libGDevelop */
|
||||
) {
|
||||
const extension = new gd.PlatformExtension();
|
||||
extension
|
||||
.setExtensionInformation(
|
||||
'PlayerAuthentication',
|
||||
_('Player Authentication (experimental)'),
|
||||
_('Allow your game to authenticate players.'),
|
||||
'Florian Rival',
|
||||
'Open source (MIT License)'
|
||||
)
|
||||
.setExtensionHelpPath('/all-features/player-authentication')
|
||||
.setCategory('Players');
|
||||
extension
|
||||
.addInstructionOrExpressionGroupMetadata(
|
||||
_('Player Authentication (experimental)')
|
||||
)
|
||||
.setIcon('JsPlatform/Extensions/authentication.svg');
|
||||
|
||||
extension
|
||||
.addDependency()
|
||||
.setName('InAppBrowser Cordova plugin')
|
||||
.setDependencyType('cordova')
|
||||
.setExportName('cordova-plugin-inappbrowser');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'DisplayAuthenticationBanner',
|
||||
_('Display authentication banner'),
|
||||
_(
|
||||
'Display an authentication banner at the top of the game screen, for the player to log in.'
|
||||
),
|
||||
_('Display an authentication banner'),
|
||||
'',
|
||||
'JsPlatform/Extensions/authentication.svg',
|
||||
'JsPlatform/Extensions/authentication.svg'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.setHelpPath('/all-features/player-authentication')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
|
||||
)
|
||||
.addIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.playerAuthentication.displayAuthenticationBanner');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'OpenAuthenticationWindow',
|
||||
_('Open authentication window'),
|
||||
_('Open an authentication window for the player to log in.'),
|
||||
_('Open an authentication window'),
|
||||
'',
|
||||
'JsPlatform/Extensions/authentication.svg',
|
||||
'JsPlatform/Extensions/authentication.svg'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.setHelpPath('/all-features/player-authentication')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
|
||||
)
|
||||
.addIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.playerAuthentication.openAuthenticationWindow');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsAuthenticationWindowOpen',
|
||||
_('Authentication window is open'),
|
||||
_('Check if the authentication window is open.'),
|
||||
_('Authentication window is open'),
|
||||
'',
|
||||
'JsPlatform/Extensions/authentication.svg',
|
||||
'JsPlatform/Extensions/authentication.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
|
||||
)
|
||||
.addIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.playerAuthentication.isAuthenticationWindowOpen');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'LogOut',
|
||||
_('Log out the player'),
|
||||
_('Log out the player.'),
|
||||
_('Log out the player'),
|
||||
'',
|
||||
'JsPlatform/Extensions/authentication.svg',
|
||||
'JsPlatform/Extensions/authentication.svg'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.setHelpPath('/all-features/player-authentication')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
|
||||
)
|
||||
.addIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.playerAuthentication.logout');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'Username',
|
||||
_('Username'),
|
||||
_('Get the username of the authenticated player.'),
|
||||
'',
|
||||
'JsPlatform/Extensions/authentication.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
|
||||
)
|
||||
.addIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.playerAuthentication.getUsername');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsPlayerAuthenticated',
|
||||
_('Player is authenticated'),
|
||||
_('Check if the player is authenticated.'),
|
||||
_('Player is authenticated'),
|
||||
'',
|
||||
'JsPlatform/Extensions/authentication.svg',
|
||||
'JsPlatform/Extensions/authentication.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
|
||||
)
|
||||
.addIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.playerAuthentication.isAuthenticated');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'HasPlayerLoggedIn',
|
||||
_('Player has logged in'),
|
||||
_('Check if the player has just logged in.'),
|
||||
_('Player has logged in'),
|
||||
'',
|
||||
'JsPlatform/Extensions/authentication.svg',
|
||||
'JsPlatform/Extensions/authentication.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
|
||||
)
|
||||
.addIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.playerAuthentication.hasLoggedIn');
|
||||
|
||||
return extension;
|
||||
},
|
||||
runExtensionSanityTests: function (
|
||||
gd /*: libGDevelop */,
|
||||
extension /*: gdPlatformExtension*/
|
||||
) {
|
||||
return [];
|
||||
},
|
||||
};
|
@@ -0,0 +1,448 @@
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Player Authentication');
|
||||
export namespace playerAuthenticationComponents {
|
||||
const getPlayerLoginMessages = ({
|
||||
platform,
|
||||
isGameRegistered,
|
||||
}: {
|
||||
platform: 'cordova' | 'electron' | 'web';
|
||||
isGameRegistered: boolean;
|
||||
}) =>
|
||||
isGameRegistered
|
||||
? {
|
||||
title: 'Logging in...',
|
||||
text1:
|
||||
platform === 'cordova'
|
||||
? "One moment, we're opening a window for you to log in."
|
||||
: "One moment, we're opening a new page with your web browser for you to log in.",
|
||||
text2:
|
||||
'If the window did not open, please check your pop-up blocker and click the button below to try again.',
|
||||
}
|
||||
: {
|
||||
title: 'Your game is not registered!',
|
||||
text1:
|
||||
'In order to use player authentication, this game must be registered with GDevelop Services first.',
|
||||
text2: 'Head to your Game Dashboard, then try again.',
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a DOM element that will contain the loader or a message if the game is not registered.
|
||||
*/
|
||||
export const computeAuthenticationContainer = function (
|
||||
onCloseAuthenticationContainer: () => void
|
||||
): {
|
||||
rootContainer: HTMLDivElement;
|
||||
loaderContainer: HTMLDivElement;
|
||||
} {
|
||||
const rootContainer = document.createElement('div');
|
||||
rootContainer.id = 'authentication-root-container';
|
||||
rootContainer.style.position = 'relative';
|
||||
rootContainer.style.backgroundColor = 'rgba(14, 6, 45, 0.5)';
|
||||
rootContainer.style.opacity = '1';
|
||||
rootContainer.style.width = '100%';
|
||||
rootContainer.style.height = '100%';
|
||||
rootContainer.style.zIndex = '2';
|
||||
rootContainer.style.pointerEvents = 'all';
|
||||
|
||||
const subContainer = document.createElement('div');
|
||||
subContainer.id = 'authentication-sub-container';
|
||||
subContainer.style.backgroundColor = '#FFFFFF';
|
||||
subContainer.style.position = 'absolute';
|
||||
subContainer.style.top = '16px';
|
||||
subContainer.style.bottom = '16px';
|
||||
subContainer.style.left = '16px';
|
||||
subContainer.style.right = '16px';
|
||||
subContainer.style.borderRadius = '8px';
|
||||
subContainer.style.boxShadow = '0px 4px 4px rgba(0, 0, 0, 0.25)';
|
||||
subContainer.style.padding = '16px';
|
||||
|
||||
const _closeContainer: HTMLDivElement = document.createElement('div');
|
||||
_closeContainer.style.cursor = 'pointer';
|
||||
_closeContainer.style.display = 'flex';
|
||||
_closeContainer.style.justifyContent = 'right';
|
||||
_closeContainer.style.alignItems = 'center';
|
||||
_closeContainer.style.zIndex = '3';
|
||||
addTouchAndClickEventListeners(
|
||||
_closeContainer,
|
||||
onCloseAuthenticationContainer
|
||||
);
|
||||
|
||||
const _close = document.createElement('img');
|
||||
_close.setAttribute('width', '15px');
|
||||
_close.setAttribute(
|
||||
'src',
|
||||
'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOCIgaGVpZ2h0PSI4IiB2aWV3Qm94PSIwIDAgOCA4IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTcuODUzNTUgMC4xNDY0NDdDOC4wNDg4MiAwLjM0MTcwOSA4LjA0ODgyIDAuNjU4MjkxIDcuODUzNTUgMC44NTM1NTNMMC44NTM1NTMgNy44NTM1NUMwLjY1ODI5MSA4LjA0ODgyIDAuMzQxNzA5IDguMDQ4ODIgMC4xNDY0NDcgNy44NTM1NUMtMC4wNDg4MTU1IDcuNjU4MjkgLTAuMDQ4ODE1NSA3LjM0MTcxIDAuMTQ2NDQ3IDcuMTQ2NDVMNy4xNDY0NSAwLjE0NjQ0N0M3LjM0MTcxIC0wLjA0ODgxNTUgNy42NTgyOSAtMC4wNDg4MTU1IDcuODUzNTUgMC4xNDY0NDdaIiBmaWxsPSIjMUQxRDI2Ii8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMC4xNDY0NDcgMC4xNDY0NDdDMC4zNDE3MDkgLTAuMDQ4ODE1NSAwLjY1ODI5MSAtMC4wNDg4MTU1IDAuODUzNTUzIDAuMTQ2NDQ3TDcuODUzNTUgNy4xNDY0NUM4LjA0ODgyIDcuMzQxNzEgOC4wNDg4MiA3LjY1ODI5IDcuODUzNTUgNy44NTM1NUM3LjY1ODI5IDguMDQ4ODIgNy4zNDE3MSA4LjA0ODgyIDcuMTQ2NDUgNy44NTM1NUwwLjE0NjQ0NyAwLjg1MzU1M0MtMC4wNDg4MTU1IDAuNjU4MjkxIC0wLjA0ODgxNTUgMC4zNDE3MDkgMC4xNDY0NDcgMC4xNDY0NDdaIiBmaWxsPSIjMUQxRDI2Ii8+Cjwvc3ZnPgo='
|
||||
);
|
||||
_closeContainer.appendChild(_close);
|
||||
|
||||
const loaderContainer: HTMLDivElement = document.createElement('div');
|
||||
loaderContainer.id = 'authentication-container-loader';
|
||||
loaderContainer.style.display = 'flex';
|
||||
loaderContainer.style.flexDirection = 'column';
|
||||
loaderContainer.style.height = '100%';
|
||||
loaderContainer.style.width = '100%';
|
||||
loaderContainer.style.justifyContent = 'center';
|
||||
loaderContainer.style.alignItems = 'center';
|
||||
|
||||
const _loader = document.createElement('img');
|
||||
_loader.setAttribute('width', '28px');
|
||||
_loader.setAttribute(
|
||||
'src',
|
||||
'data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iYW5pbWF0ZS1zcGluIC1tbC0xIG1yLTMgaC01IHctNSB0ZXh0LXdoaXRlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CjxjaXJjbGUgb3BhY2l0eT0nMC4yNScgY3g9IjEyIiBjeT0iMTIiIHI9IjEwIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSI0Ij48L2NpcmNsZT4KPHBhdGggb3BhY2l0eT0nMC43NScgZmlsbD0iY3VycmVudENvbG9yIiBkPSJNNCAxMmE4IDggMCAwMTgtOFYwQzUuMzczIDAgMCA1LjM3MyAwIDEyaDR6bTIgNS4yOTFBNy45NjIgNy45NjIgMCAwMTQgMTJIMGMwIDMuMDQyIDEuMTM1IDUuODI0IDMgNy45MzhsMy0yLjY0N3oiPjwvcGF0aD4KPC9zdmc+'
|
||||
);
|
||||
_loader.style.marginTop = '50px';
|
||||
try {
|
||||
_loader.animate(
|
||||
[{ transform: 'rotate(0deg)' }, { transform: 'rotate(359deg)' }],
|
||||
{
|
||||
duration: 3000,
|
||||
iterations: Infinity,
|
||||
}
|
||||
);
|
||||
} catch {
|
||||
logger.warn('Animation not supported, loader will be fixed.');
|
||||
}
|
||||
|
||||
loaderContainer.appendChild(_loader);
|
||||
|
||||
subContainer.appendChild(_closeContainer);
|
||||
subContainer.appendChild(loaderContainer);
|
||||
rootContainer.appendChild(subContainer);
|
||||
|
||||
return { rootContainer, loaderContainer };
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to add the texts to the authentication container
|
||||
* based on the platform or if the game is registered.
|
||||
*/
|
||||
export const addAuthenticationTextsToLoadingContainer = (
|
||||
loaderContainer: HTMLDivElement,
|
||||
platform,
|
||||
isGameRegistered
|
||||
) => {
|
||||
const textContainer: HTMLDivElement = document.createElement('div');
|
||||
textContainer.id = 'authentication-container-texts';
|
||||
textContainer.style.display = 'flex';
|
||||
textContainer.style.flexDirection = 'column';
|
||||
textContainer.style.width = '100%';
|
||||
textContainer.style.justifyContent = 'center';
|
||||
textContainer.style.alignItems = 'center';
|
||||
textContainer.style.position = 'relative';
|
||||
textContainer.style.zIndex = '3';
|
||||
textContainer.style.fontSize = '11pt';
|
||||
textContainer.style.fontFamily =
|
||||
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"';
|
||||
|
||||
const messages = getPlayerLoginMessages({
|
||||
platform,
|
||||
isGameRegistered,
|
||||
});
|
||||
const title = document.createElement('h1');
|
||||
title.innerText = messages.title;
|
||||
title.style.fontSize = '20pt';
|
||||
title.style.fontWeight = 'bold';
|
||||
const text1 = document.createElement('p');
|
||||
text1.innerText = messages.text1;
|
||||
const text2 = document.createElement('p');
|
||||
text2.innerText = messages.text2;
|
||||
textContainer.appendChild(title);
|
||||
textContainer.appendChild(text1);
|
||||
textContainer.appendChild(text2);
|
||||
|
||||
if (!isGameRegistered) {
|
||||
// Remove the loader.
|
||||
loaderContainer.innerHTML = '';
|
||||
}
|
||||
|
||||
loaderContainer.prepend(textContainer);
|
||||
|
||||
return textContainer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to add the authentication link in case the window hasn't opened properly.
|
||||
* Useful for Electron & Web platforms.
|
||||
*/
|
||||
export const addAuthenticationUrlToTextsContainer = (
|
||||
onClick: () => void,
|
||||
textContainer: HTMLDivElement
|
||||
) => {
|
||||
const link = document.createElement('a');
|
||||
addTouchAndClickEventListeners(link, onClick);
|
||||
link.innerText = 'Click here to authenticate';
|
||||
link.style.color = '#0078d4';
|
||||
link.style.textDecoration = 'none';
|
||||
link.style.textDecoration = 'underline';
|
||||
link.style.cursor = 'pointer';
|
||||
|
||||
textContainer.appendChild(link);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a DOM element to display a dismissable banner.
|
||||
*/
|
||||
export const computeDismissableBanner = function (
|
||||
onDismissBanner: () => void
|
||||
): HTMLDivElement {
|
||||
const divContainer = document.createElement('div');
|
||||
|
||||
divContainer.id = 'authenticated-banner';
|
||||
divContainer.style.position = 'absolute';
|
||||
divContainer.style.pointerEvents = 'all';
|
||||
divContainer.style.backgroundColor = '#0E062D';
|
||||
divContainer.style.top = '0px';
|
||||
divContainer.style.height = '48px';
|
||||
divContainer.style.left = '0px';
|
||||
divContainer.style.width = '100%';
|
||||
divContainer.style.padding = '6px 16px';
|
||||
// Use zIndex 1 to make sure it is below the authentication iframe or webview.
|
||||
divContainer.style.zIndex = '1';
|
||||
divContainer.style.display = 'flex';
|
||||
divContainer.style.flexDirection = 'row-reverse';
|
||||
divContainer.style.justifyContent = 'space-between';
|
||||
divContainer.style.alignItems = 'center';
|
||||
divContainer.style.boxShadow = '0px 4px 4px rgba(0, 0, 0, 0.25)';
|
||||
divContainer.style.fontSize = '11pt';
|
||||
divContainer.style.color = '#FFFFFF';
|
||||
divContainer.style.fontFamily =
|
||||
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"';
|
||||
|
||||
const _closeContainer: HTMLDivElement = document.createElement('div');
|
||||
_closeContainer.style.cursor = 'pointer';
|
||||
_closeContainer.style.display = 'flex';
|
||||
_closeContainer.style.justifyContent = 'center';
|
||||
_closeContainer.style.alignItems = 'center';
|
||||
_closeContainer.style.zIndex = '3';
|
||||
_closeContainer.style.marginRight = '32px';
|
||||
_closeContainer.style.height = '100%';
|
||||
addTouchAndClickEventListeners(_closeContainer, onDismissBanner);
|
||||
|
||||
const _close = document.createElement('img');
|
||||
_close.setAttribute('width', '30px');
|
||||
_close.setAttribute(
|
||||
'src',
|
||||
'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAiIGhlaWdodD0iMzAiIHZpZXdCb3g9IjAgMCAzMCAzMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTIzLjc1IDguMDEyNUwyMS45ODc1IDYuMjVMMTUgMTMuMjM3NUw4LjAxMjUgNi4yNUw2LjI1IDguMDEyNUwxMy4yMzc1IDE1TDYuMjUgMjEuOTg3NUw4LjAxMjUgMjMuNzVMMTUgMTYuNzYyNUwyMS45ODc1IDIzLjc1TDIzLjc1IDIxLjk4NzVMMTYuNzYyNSAxNUwyMy43NSA4LjAxMjVaIiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K'
|
||||
);
|
||||
|
||||
_closeContainer.appendChild(_close);
|
||||
divContainer.appendChild(_closeContainer);
|
||||
|
||||
return divContainer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a DOM element representing a banner for the user to know which account
|
||||
* they're using and also to allow switching to another account.
|
||||
*/
|
||||
export const computeAuthenticatedBanner = function (
|
||||
onOpenAuthenticationWindow: () => void,
|
||||
onDismissBanner: () => void,
|
||||
username: string | null
|
||||
): HTMLDivElement {
|
||||
const divContainer = computeDismissableBanner(onDismissBanner);
|
||||
|
||||
const playerUsername = username || 'Anonymous';
|
||||
|
||||
const _textContainer: HTMLDivElement = document.createElement('div');
|
||||
const loggedText = document.createElement('p');
|
||||
loggedText.id = 'loggedText';
|
||||
loggedText.innerHTML = `<img style="margin-right:4px" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOSIgaGVpZ2h0PSI5IiB2aWV3Qm94PSIwIDAgOSA5IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNNC4xNjY2NyAwQzEuODY2NjcgMCAwIDEuODY2NjcgMCA0LjE2NjY3QzAgNi40NjY2NyAxLjg2NjY3IDguMzMzMzMgNC4xNjY2NyA4LjMzMzMzQzYuNDY2NjcgOC4zMzMzMyA4LjMzMzMzIDYuNDY2NjcgOC4zMzMzMyA0LjE2NjY3QzguMzMzMzMgMS44NjY2NyA2LjQ2NjY3IDAgNC4xNjY2NyAwWk0zLjMzMzMzIDYuMjVMMS4yNSA0LjE2NjY3TDEuODM3NSAzLjU3OTE3TDMuMzMzMzMgNS4wNzA4M0w2LjQ5NTgzIDEuOTA4MzNMNy4wODMzMyAyLjVMMy4zMzMzMyA2LjI1WiIgZmlsbD0iIzAwQ0M4MyIvPgo8L3N2Zz4K" />
|
||||
Logged as ${playerUsername}`;
|
||||
loggedText.style.margin = '0px';
|
||||
|
||||
const changeAccountText = document.createElement('p');
|
||||
changeAccountText.id = 'changeAccountText';
|
||||
changeAccountText.innerText = `Click here to switch to another account.`;
|
||||
changeAccountText.style.margin = '0px';
|
||||
changeAccountText.style.marginTop = '4px';
|
||||
changeAccountText.style.textDecoration = 'underline';
|
||||
changeAccountText.style.cursor = 'pointer';
|
||||
addTouchAndClickEventListeners(
|
||||
changeAccountText,
|
||||
onOpenAuthenticationWindow
|
||||
);
|
||||
|
||||
_textContainer.appendChild(loggedText);
|
||||
_textContainer.appendChild(changeAccountText);
|
||||
divContainer.appendChild(_textContainer);
|
||||
|
||||
return divContainer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a DOM element representing a banner for the user to know
|
||||
* they are not connected and to allow logging in.
|
||||
*/
|
||||
export const computeNotAuthenticatedBanner = function (
|
||||
onOpenAuthenticationWindow: () => void,
|
||||
onDismissBanner: () => void
|
||||
): HTMLDivElement {
|
||||
const divContainer = computeDismissableBanner(onDismissBanner);
|
||||
|
||||
const _textContainer: HTMLDivElement = document.createElement('div');
|
||||
const loggedText = document.createElement('p');
|
||||
loggedText.id = 'loggedText';
|
||||
loggedText.innerHTML = `You are not authenticated.`;
|
||||
loggedText.style.margin = '0px';
|
||||
|
||||
const changeAccountText = document.createElement('p');
|
||||
changeAccountText.id = 'changeAccountText';
|
||||
changeAccountText.innerText = `Click here to log in.`;
|
||||
changeAccountText.style.margin = '0px';
|
||||
changeAccountText.style.marginTop = '4px';
|
||||
changeAccountText.style.textDecoration = 'underline';
|
||||
changeAccountText.style.cursor = 'pointer';
|
||||
addTouchAndClickEventListeners(
|
||||
changeAccountText,
|
||||
onOpenAuthenticationWindow
|
||||
);
|
||||
|
||||
_textContainer.appendChild(loggedText);
|
||||
_textContainer.appendChild(changeAccountText);
|
||||
divContainer.appendChild(_textContainer);
|
||||
|
||||
return divContainer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create, display, and hide the logged in confirmation.
|
||||
*/
|
||||
export const displayLoggedInNotification = function (
|
||||
domContainer: HTMLDivElement,
|
||||
username: string
|
||||
) {
|
||||
showNotification(
|
||||
domContainer,
|
||||
'authenticated-notification',
|
||||
`<img style="margin-right:4px" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOSIgaGVpZ2h0PSI5IiB2aWV3Qm94PSIwIDAgOSA5IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNNC4xNjY2NyAwQzEuODY2NjcgMCAwIDEuODY2NjcgMCA0LjE2NjY3QzAgNi40NjY2NyAxLjg2NjY3IDguMzMzMzMgNC4xNjY2NyA4LjMzMzMzQzYuNDY2NjcgOC4zMzMzMyA4LjMzMzMzIDYuNDY2NjcgOC4zMzMzMyA0LjE2NjY3QzguMzMzMzMgMS44NjY2NyA2LjQ2NjY3IDAgNC4xNjY2NyAwWk0zLjMzMzMzIDYuMjVMMS4yNSA0LjE2NjY3TDEuODM3NSAzLjU3OTE3TDMuMzMzMzMgNS4wNzA4M0w2LjQ5NTgzIDEuOTA4MzNMNy4wODMzMyAyLjVMMy4zMzMzMyA2LjI1WiIgZmlsbD0iIzAwQ0M4MyIvPgo8L3N2Zz4K" />
|
||||
Logged as ${username}`,
|
||||
'success'
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create, display, and hide the logged in confirmation.
|
||||
*/
|
||||
export const displayLoggedOutNotification = function (
|
||||
domContainer: HTMLDivElement
|
||||
) {
|
||||
showNotification(
|
||||
domContainer,
|
||||
'authenticated-notification',
|
||||
`<img style="margin-right:4px" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOSIgaGVpZ2h0PSI5IiB2aWV3Qm94PSIwIDAgOSA5IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNNC4xNjY2NyAwQzEuODY2NjcgMCAwIDEuODY2NjcgMCA0LjE2NjY3QzAgNi40NjY2NyAxLjg2NjY3IDguMzMzMzMgNC4xNjY2NyA4LjMzMzMzQzYuNDY2NjcgOC4zMzMzMyA4LjMzMzMzIDYuNDY2NjcgOC4zMzMzMyA0LjE2NjY3QzguMzMzMzMgMS44NjY2NyA2LjQ2NjY3IDAgNC4xNjY2NyAwWk0zLjMzMzMzIDYuMjVMMS4yNSA0LjE2NjY3TDEuODM3NSAzLjU3OTE3TDMuMzMzMzMgNS4wNzA4M0w2LjQ5NTgzIDEuOTA4MzNMNy4wODMzMyAyLjVMMy4zMzMzMyA2LjI1WiIgZmlsbD0iIzAwQ0M4MyIvPgo8L3N2Zz4K" />
|
||||
Logged out`,
|
||||
'success'
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create, display, and hide an error notification.
|
||||
*/
|
||||
export const displayErrorNotification = function (
|
||||
domContainer: HTMLDivElement
|
||||
) {
|
||||
showNotification(
|
||||
domContainer,
|
||||
'error-notification',
|
||||
'An error occurred while authenticating, please try again.',
|
||||
'error'
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to show a notification to the user, that disappears automatically.
|
||||
*/
|
||||
export const showNotification = function (
|
||||
domContainer: HTMLDivElement,
|
||||
id: string,
|
||||
content: string,
|
||||
type: 'success' | 'error'
|
||||
) {
|
||||
const divContainer = document.createElement('div');
|
||||
|
||||
divContainer.id = id;
|
||||
divContainer.style.position = 'absolute';
|
||||
divContainer.style.pointerEvents = 'all';
|
||||
divContainer.style.backgroundColor =
|
||||
type === 'success' ? '#0E062D' : 'red';
|
||||
divContainer.style.top = '12px';
|
||||
divContainer.style.right = '16px';
|
||||
divContainer.style.padding = '6px 32px 6px 6px';
|
||||
// Use zIndex 1 to make sure it is below the authentication iframe or webview.
|
||||
divContainer.style.zIndex = '1';
|
||||
divContainer.style.display = 'flex';
|
||||
divContainer.style.flexDirection = 'row-reverse';
|
||||
divContainer.style.justifyContent = 'space-between';
|
||||
divContainer.style.alignItems = 'center';
|
||||
divContainer.style.boxShadow = '0px 4px 4px rgba(0, 0, 0, 0.25)';
|
||||
divContainer.style.borderRadius = '4px';
|
||||
divContainer.style.fontSize = '11pt';
|
||||
divContainer.style.color = '#FFFFFF';
|
||||
divContainer.style.fontFamily =
|
||||
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"';
|
||||
try {
|
||||
divContainer.animate(
|
||||
[
|
||||
{ transform: 'translateY(-30px)', opacity: 0 },
|
||||
{ transform: 'translateY(0px)', opacity: 1 },
|
||||
],
|
||||
{
|
||||
duration: 700,
|
||||
easing: 'ease-out',
|
||||
}
|
||||
);
|
||||
} catch {
|
||||
logger.warn('Animation not supported, div will be fixed.');
|
||||
}
|
||||
const loggedText = document.createElement('p');
|
||||
loggedText.id = 'loggedText';
|
||||
loggedText.innerHTML = content;
|
||||
loggedText.style.margin = '0px';
|
||||
|
||||
divContainer.appendChild(loggedText);
|
||||
|
||||
domContainer.appendChild(divContainer);
|
||||
const animationTime = 700;
|
||||
const notificationTime = 5000;
|
||||
setTimeout(() => {
|
||||
try {
|
||||
divContainer.animate(
|
||||
[
|
||||
{ transform: 'translateY(0px)', opacity: 1 },
|
||||
{ transform: 'translateY(-30px)', opacity: 0 },
|
||||
],
|
||||
{
|
||||
duration: animationTime,
|
||||
easing: 'ease-in',
|
||||
}
|
||||
);
|
||||
} catch {
|
||||
logger.warn('Animation not supported, div will be fixed.');
|
||||
}
|
||||
}, notificationTime);
|
||||
// Use timeout because onanimationend listener does not work.
|
||||
setTimeout(() => {
|
||||
divContainer.remove();
|
||||
}, notificationTime + animationTime);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to add event listeners on a pressable/clickable element
|
||||
* to work on both desktop and mobile.
|
||||
*/
|
||||
export const addTouchAndClickEventListeners = function (
|
||||
element: HTMLElement,
|
||||
action: () => void
|
||||
) {
|
||||
// Touch start event listener for mobile.
|
||||
element.addEventListener('touchstart', (event) => {
|
||||
action();
|
||||
});
|
||||
// Click event listener for desktop.
|
||||
element.addEventListener('click', (event) => {
|
||||
action();
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
739
Extensions/PlayerAuthentication/playerauthenticationtools.ts
Normal file
739
Extensions/PlayerAuthentication/playerauthenticationtools.ts
Normal file
@@ -0,0 +1,739 @@
|
||||
namespace gdjs {
|
||||
declare var cordova: any;
|
||||
|
||||
const logger = new gdjs.Logger('Player Authentication');
|
||||
const authComponents = gdjs.playerAuthenticationComponents;
|
||||
export namespace playerAuthentication {
|
||||
// Authentication information.
|
||||
let _username: string | null = null;
|
||||
let _userId: string | null = null;
|
||||
let _userToken: string | null = null;
|
||||
let _justLoggedIn = false;
|
||||
|
||||
let _checkedLocalStorage: boolean = false;
|
||||
|
||||
// Authentication display
|
||||
let _authenticationWindow: Window | null = null; // For Web.
|
||||
let _authenticationInAppWindow: Window | null = null; // For Cordova.
|
||||
let _authenticationRootContainer: HTMLDivElement | null = null;
|
||||
let _authenticationLoaderContainer: HTMLDivElement | null = null;
|
||||
let _authenticationTextContainer: HTMLDivElement | null = null;
|
||||
let _authenticationBanner: HTMLDivElement | null = null;
|
||||
let _authenticationTimeoutId: NodeJS.Timeout | null = null;
|
||||
|
||||
// Communication methods.
|
||||
let _authenticationMessageCallback:
|
||||
| ((event: MessageEvent) => void)
|
||||
| null = null;
|
||||
let _cordovaAuthenticationMessageCallback:
|
||||
| ((event: MessageEvent) => void)
|
||||
| null = null;
|
||||
let _websocket: WebSocket | null = null;
|
||||
|
||||
// Ensure that the condition "just logged in" is valid only for one frame.
|
||||
gdjs.registerRuntimeScenePostEventsCallback(() => {
|
||||
_justLoggedIn = false;
|
||||
});
|
||||
|
||||
const getLocalStorageKey = (gameId: string) =>
|
||||
`${gameId}_authenticatedUser`;
|
||||
|
||||
const getAuthWindowUrl = ({
|
||||
runtimeGame,
|
||||
gameId,
|
||||
connectionId,
|
||||
}: {
|
||||
runtimeGame: gdjs.RuntimeGame;
|
||||
gameId: string;
|
||||
connectionId?: string;
|
||||
}) =>
|
||||
`https://liluo.io/auth?gameId=${gameId}${
|
||||
connectionId ? `&connectionId=${connectionId}` : ''
|
||||
}${
|
||||
runtimeGame.isUsingGDevelopDevelopmentEnvironment() ? '&dev=true' : ''
|
||||
}`;
|
||||
|
||||
/**
|
||||
* Helper returning the platform.
|
||||
*/
|
||||
const getPlatform = (
|
||||
runtimeScene: RuntimeScene
|
||||
): 'electron' | 'cordova' | 'web' => {
|
||||
const electron = runtimeScene.getGame().getRenderer().getElectron();
|
||||
if (electron) {
|
||||
return 'electron';
|
||||
}
|
||||
if (typeof cordova !== 'undefined') return 'cordova';
|
||||
return 'web';
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if a user token is present in the local storage.
|
||||
*/
|
||||
export const isAuthenticated = () => {
|
||||
if (!_checkedLocalStorage) {
|
||||
readAuthenticatedUserFromLocalStorage();
|
||||
}
|
||||
return _userToken !== null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the user just logged in.
|
||||
* Useful to update username or trigger messages in the game.
|
||||
*/
|
||||
export const hasLoggedIn = () => _justLoggedIn;
|
||||
|
||||
/**
|
||||
* Returns the username from the local storage.
|
||||
*/
|
||||
export const getUsername = () => {
|
||||
if (!_checkedLocalStorage) {
|
||||
readAuthenticatedUserFromLocalStorage();
|
||||
}
|
||||
return _username || '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the user token from the local storage.
|
||||
*/
|
||||
export const getUserToken = () => {
|
||||
if (!_checkedLocalStorage) {
|
||||
readAuthenticatedUserFromLocalStorage();
|
||||
}
|
||||
return _userToken || null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the username from the local storage.
|
||||
*/
|
||||
export const getUserId = () => {
|
||||
if (!_checkedLocalStorage) {
|
||||
readAuthenticatedUserFromLocalStorage();
|
||||
}
|
||||
return _userId || null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the game is registered, false otherwise.
|
||||
* Useful to display a message to the user to register the game before logging in.
|
||||
*/
|
||||
const checkIfGameIsRegistered = (
|
||||
runtimeGame: gdjs.RuntimeGame,
|
||||
gameId: string,
|
||||
tries: number = 0
|
||||
): Promise<boolean> => {
|
||||
const rootApi = runtimeGame.isUsingGDevelopDevelopmentEnvironment()
|
||||
? 'https://api-dev.gdevelop.io'
|
||||
: 'https://api.gdevelop.io';
|
||||
const url = `${rootApi}/game/public-game/${gameId}`;
|
||||
return fetch(url, { method: 'HEAD' }).then(
|
||||
(response) => {
|
||||
if (response.status !== 200) {
|
||||
logger.warn(
|
||||
`Error while fetching the game: ${response.status} ${response.statusText}`
|
||||
);
|
||||
|
||||
// If the response is not 404, it may be a timeout, so retry a few times.
|
||||
if (response.status === 404 || tries > 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkIfGameIsRegistered(runtimeGame, gameId, tries + 1);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
(err) => {
|
||||
logger.error('Error while fetching game:', err);
|
||||
return false;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the user information from the local storage.
|
||||
*/
|
||||
export const logout = (runtimeScene: RuntimeScene) => {
|
||||
_username = null;
|
||||
_userToken = null;
|
||||
_userId = null;
|
||||
|
||||
const gameId = gdjs.projectData.properties.projectUuid;
|
||||
if (!gameId) {
|
||||
logger.error('Missing game id in project properties.');
|
||||
return;
|
||||
}
|
||||
window.localStorage.removeItem(getLocalStorageKey(gameId));
|
||||
cleanUpAuthWindowAndCallbacks(runtimeScene);
|
||||
removeAuthenticationBanner(runtimeScene);
|
||||
const domElementContainer = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getDomElementContainer();
|
||||
if (!domElementContainer) {
|
||||
handleAuthenticationError(
|
||||
runtimeScene,
|
||||
"The div element covering the game couldn't be found, the authentication banner cannot be displayed."
|
||||
);
|
||||
return;
|
||||
}
|
||||
authComponents.displayLoggedOutNotification(domElementContainer);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the user information from the local storage, and store
|
||||
* them in the extension variables.
|
||||
*/
|
||||
const readAuthenticatedUserFromLocalStorage = () => {
|
||||
const gameId = gdjs.projectData.properties.projectUuid;
|
||||
if (!gameId) {
|
||||
logger.error('Missing game id in project properties.');
|
||||
return;
|
||||
}
|
||||
const authenticatedUserStorageItem = window.localStorage.getItem(
|
||||
getLocalStorageKey(gameId)
|
||||
);
|
||||
if (!authenticatedUserStorageItem) {
|
||||
_checkedLocalStorage = true;
|
||||
return;
|
||||
}
|
||||
const authenticatedUser = JSON.parse(authenticatedUserStorageItem);
|
||||
|
||||
_username = authenticatedUser.username;
|
||||
_userId = authenticatedUser.userId;
|
||||
_userToken = authenticatedUser.userToken;
|
||||
_checkedLocalStorage = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to be called on login or error.
|
||||
* Removes all the UI and callbacks.
|
||||
*/
|
||||
const cleanUpAuthWindowAndCallbacks = (runtimeScene: RuntimeScene) => {
|
||||
removeAuthenticationContainer(runtimeScene);
|
||||
clearAuthenticationWindowTimeout();
|
||||
if (_websocket) {
|
||||
_websocket.close();
|
||||
_websocket = null;
|
||||
}
|
||||
// If a new window was opened (web), close it.
|
||||
if (_authenticationWindow) {
|
||||
_authenticationWindow.close();
|
||||
_authenticationWindow = null;
|
||||
}
|
||||
// If an in-app browser was used (cordova), close it.
|
||||
if (_authenticationInAppWindow) {
|
||||
_authenticationInAppWindow.close();
|
||||
_authenticationInAppWindow = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* When the websocket receives the authentication result, close all the
|
||||
* authentication windows, display the notification and focus on the game.
|
||||
*/
|
||||
const handleLoggedInEvent = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
userId: string,
|
||||
username: string | null,
|
||||
userToken: string
|
||||
) {
|
||||
if (!username) {
|
||||
logger.warn('The authenticated player does not have a username');
|
||||
}
|
||||
_username = username;
|
||||
_userId = userId;
|
||||
_userToken = userToken;
|
||||
_justLoggedIn = true;
|
||||
|
||||
const gameId = gdjs.projectData.properties.projectUuid;
|
||||
if (!gameId) {
|
||||
logger.error('Missing game id in project properties.');
|
||||
return;
|
||||
}
|
||||
window.localStorage.setItem(
|
||||
getLocalStorageKey(gameId),
|
||||
JSON.stringify({
|
||||
username: _username,
|
||||
userId: _userId,
|
||||
userToken: _userToken,
|
||||
})
|
||||
);
|
||||
cleanUpAuthWindowAndCallbacks(runtimeScene);
|
||||
removeAuthenticationBanner(runtimeScene);
|
||||
|
||||
const domElementContainer = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getDomElementContainer();
|
||||
if (!domElementContainer) {
|
||||
handleAuthenticationError(
|
||||
runtimeScene,
|
||||
"The div element covering the game couldn't be found, the authentication banner cannot be displayed."
|
||||
);
|
||||
return;
|
||||
}
|
||||
authComponents.displayLoggedInNotification(
|
||||
domElementContainer,
|
||||
_username || 'Anonymous'
|
||||
);
|
||||
focusOnGame(runtimeScene);
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads the event sent by the authentication window and
|
||||
* display the appropriate banner.
|
||||
*/
|
||||
const receiveMessageFromAuthenticationWindow = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
event: MessageEvent,
|
||||
{ checkOrigin }: { checkOrigin: boolean }
|
||||
) {
|
||||
const allowedOrigin = 'https://liluo.io';
|
||||
|
||||
// Check origin of message.
|
||||
if (checkOrigin && event.origin !== allowedOrigin) {
|
||||
throw new Error(`Unexpected origin: ${event.origin}`);
|
||||
}
|
||||
// Check that message is not malformed.
|
||||
if (!event.data.id) {
|
||||
throw new Error('Malformed message');
|
||||
}
|
||||
|
||||
// Handle message.
|
||||
switch (event.data.id) {
|
||||
case 'authenticationResult': {
|
||||
if (!(event.data.body && event.data.body.token)) {
|
||||
throw new Error('Malformed message.');
|
||||
}
|
||||
|
||||
handleLoggedInEvent(
|
||||
runtimeScene,
|
||||
event.data.body.userId,
|
||||
event.data.body.username,
|
||||
event.data.body.token
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle any error that can occur as part of the authentication process.
|
||||
*/
|
||||
const handleAuthenticationError = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
message: string
|
||||
) {
|
||||
logger.error(message);
|
||||
cleanUpAuthWindowAndCallbacks(runtimeScene);
|
||||
|
||||
const domElementContainer = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getDomElementContainer();
|
||||
if (!domElementContainer) {
|
||||
handleAuthenticationError(
|
||||
runtimeScene,
|
||||
"The div element covering the game couldn't be found, the authentication banner cannot be displayed."
|
||||
);
|
||||
return;
|
||||
}
|
||||
authComponents.displayErrorNotification(domElementContainer);
|
||||
focusOnGame(runtimeScene);
|
||||
};
|
||||
|
||||
/**
|
||||
* If after 5min, no message has been received from the authentication window,
|
||||
* show a notification and remove the authentication container.
|
||||
*/
|
||||
const startAuthenticationWindowTimeout = (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) => {
|
||||
clearAuthenticationWindowTimeout();
|
||||
const time = 12 * 60 * 1000; // 12 minutes, in case the user needs time to authenticate.
|
||||
_authenticationTimeoutId = setTimeout(() => {
|
||||
logger.info(
|
||||
'Authentication window did not send message in time. Closing it.'
|
||||
);
|
||||
cleanUpAuthWindowAndCallbacks(runtimeScene);
|
||||
focusOnGame(runtimeScene);
|
||||
}, time);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear the authentication window timeout.
|
||||
* Useful when:
|
||||
* - the authentication succeeded
|
||||
* - the authentication window is closed
|
||||
*/
|
||||
const clearAuthenticationWindowTimeout = () => {
|
||||
if (_authenticationTimeoutId) clearTimeout(_authenticationTimeoutId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Action to display the banner to the user, depending on their authentication status.
|
||||
*/
|
||||
export const displayAuthenticationBanner = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
if (_authenticationBanner) {
|
||||
// Banner already displayed, ensure it's visible.
|
||||
_authenticationBanner.style.opacity = '1';
|
||||
return;
|
||||
}
|
||||
if (!_checkedLocalStorage) {
|
||||
readAuthenticatedUserFromLocalStorage();
|
||||
}
|
||||
|
||||
const domElementContainer = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getDomElementContainer();
|
||||
if (!domElementContainer) {
|
||||
handleAuthenticationError(
|
||||
runtimeScene,
|
||||
"The div element covering the game couldn't be found, the authentication banner cannot be displayed."
|
||||
);
|
||||
return;
|
||||
}
|
||||
const onDismissBanner = () => {
|
||||
removeAuthenticationBanner(runtimeScene);
|
||||
};
|
||||
const onOpenAuthenticationWindow = () => {
|
||||
openAuthenticationWindow(runtimeScene);
|
||||
};
|
||||
// We display the corresponding banner depending on the authentication status.
|
||||
_authenticationBanner = _userToken
|
||||
? authComponents.computeAuthenticatedBanner(
|
||||
onOpenAuthenticationWindow,
|
||||
onDismissBanner,
|
||||
_username
|
||||
)
|
||||
: authComponents.computeNotAuthenticatedBanner(
|
||||
onOpenAuthenticationWindow,
|
||||
onDismissBanner
|
||||
);
|
||||
domElementContainer.appendChild(_authenticationBanner);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to handle authentication window on Electron.
|
||||
* We open a new window, and create a websocket to know when the user is logged in.
|
||||
*/
|
||||
const openAuthenticationWindowForElectron = (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
gameId: string
|
||||
) => {
|
||||
const wsPlayApi = runtimeScene
|
||||
.getGame()
|
||||
.isUsingGDevelopDevelopmentEnvironment()
|
||||
? 'wss://api-ws-dev.gdevelop.io/play'
|
||||
: 'wss://api-ws.gdevelop.io/play';
|
||||
_websocket = new WebSocket(wsPlayApi);
|
||||
_websocket.onopen = () => {
|
||||
// When socket is open, ask for the connectionId, so that we can open the authentication window.
|
||||
if (_websocket) {
|
||||
_websocket.send(JSON.stringify({ action: 'getConnectionId' }));
|
||||
}
|
||||
};
|
||||
_websocket.onerror = () => {
|
||||
handleAuthenticationError(
|
||||
runtimeScene,
|
||||
'Error while connecting to the authentication server.'
|
||||
);
|
||||
};
|
||||
_websocket.onmessage = (event) => {
|
||||
if (event.data) {
|
||||
const messageContent = JSON.parse(event.data);
|
||||
switch (messageContent.type) {
|
||||
case 'authenticationResult': {
|
||||
const messageData = messageContent.data;
|
||||
handleLoggedInEvent(
|
||||
runtimeScene,
|
||||
messageData.userId,
|
||||
messageData.username,
|
||||
messageData.token
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'connectionId': {
|
||||
const messagegeData = messageContent.data;
|
||||
const connectionId = messagegeData.connectionId;
|
||||
if (!connectionId) {
|
||||
logger.error('No connectionId received');
|
||||
return;
|
||||
}
|
||||
|
||||
const targetUrl = getAuthWindowUrl({
|
||||
runtimeGame: runtimeScene.getGame(),
|
||||
gameId,
|
||||
connectionId,
|
||||
});
|
||||
|
||||
const electron = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getElectron();
|
||||
const openWindow = () => electron.shell.openExternal(targetUrl);
|
||||
|
||||
openWindow();
|
||||
|
||||
// Add the link to the window in case a popup blocker is preventing the window from opening.
|
||||
if (_authenticationTextContainer) {
|
||||
authComponents.addAuthenticationUrlToTextsContainer(
|
||||
openWindow,
|
||||
_authenticationTextContainer
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to handle authentication window on Cordova.
|
||||
* We open an InAppBrowser window, and listen to messages posted on this window.
|
||||
*/
|
||||
const openAuthenticationWindowForCordova = (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
gameId: string
|
||||
) => {
|
||||
const targetUrl = getAuthWindowUrl({
|
||||
runtimeGame: runtimeScene.getGame(),
|
||||
gameId,
|
||||
});
|
||||
|
||||
_authenticationInAppWindow = cordova.InAppBrowser.open(
|
||||
targetUrl,
|
||||
'authentication',
|
||||
'location=yes' // location=yes is important to show the URL bar to the user.
|
||||
);
|
||||
// Listen to messages posted on the authentication window, so that we can
|
||||
// know when the user is authenticated.
|
||||
if (_authenticationInAppWindow) {
|
||||
_cordovaAuthenticationMessageCallback = (event: MessageEvent) => {
|
||||
receiveMessageFromAuthenticationWindow(runtimeScene, event, {
|
||||
checkOrigin: false, // For Cordova we don't check the origin, as the message is read from the InAppBrowser directly.
|
||||
});
|
||||
};
|
||||
_authenticationInAppWindow.addEventListener(
|
||||
'message',
|
||||
_cordovaAuthenticationMessageCallback,
|
||||
true
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to handle authentication window on web.
|
||||
* We open a new window, and listen to messages posted back to the game window.
|
||||
*/
|
||||
const openAuthenticationWindowForWeb = (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
gameId: string
|
||||
) => {
|
||||
// If we're on a browser, open a new window.
|
||||
const targetUrl = getAuthWindowUrl({
|
||||
runtimeGame: runtimeScene.getGame(),
|
||||
gameId,
|
||||
});
|
||||
|
||||
// Listen to messages posted by the authentication window, so that we can
|
||||
// know when the user is authenticated.
|
||||
_authenticationMessageCallback = (event: MessageEvent) => {
|
||||
receiveMessageFromAuthenticationWindow(runtimeScene, event, {
|
||||
checkOrigin: true,
|
||||
});
|
||||
};
|
||||
window.addEventListener('message', _authenticationMessageCallback, true);
|
||||
|
||||
const left = screen.width / 2 - 500 / 2;
|
||||
const top = screen.height / 2 - 600 / 2;
|
||||
const windowFeatures = `left=${left},top=${top},width=500,height=600`;
|
||||
const openWindow = () =>
|
||||
window.open(targetUrl, 'authentication', windowFeatures);
|
||||
_authenticationWindow = openWindow();
|
||||
|
||||
// Add the link to the window in case a popup blocker is preventing the window from opening.
|
||||
if (_authenticationTextContainer) {
|
||||
authComponents.addAuthenticationUrlToTextsContainer(
|
||||
openWindow,
|
||||
_authenticationTextContainer
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Action to display the authentication window to the user.
|
||||
*/
|
||||
export const openAuthenticationWindow = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
// Create the authentication container for the player to wait.
|
||||
const domElementContainer = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getDomElementContainer();
|
||||
if (!domElementContainer) {
|
||||
handleAuthenticationError(
|
||||
runtimeScene,
|
||||
"The div element covering the game couldn't be found, the authentication window cannot be displayed."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const onAuthenticationContainerDismissed = () => {
|
||||
cleanUpAuthWindowAndCallbacks(runtimeScene);
|
||||
displayAuthenticationBanner(runtimeScene);
|
||||
};
|
||||
|
||||
const _gameId = gdjs.projectData.properties.projectUuid;
|
||||
if (!_gameId) {
|
||||
handleAuthenticationError(
|
||||
runtimeScene,
|
||||
'The game ID is missing, the authentication window cannot be opened.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the banner is displayed, hide it, so that it can be shown again if the user closes the window.
|
||||
if (_authenticationBanner) _authenticationBanner.style.opacity = '0';
|
||||
|
||||
const platform = getPlatform(runtimeScene);
|
||||
const {
|
||||
rootContainer,
|
||||
loaderContainer,
|
||||
} = authComponents.computeAuthenticationContainer(
|
||||
onAuthenticationContainerDismissed
|
||||
);
|
||||
_authenticationRootContainer = rootContainer;
|
||||
_authenticationLoaderContainer = loaderContainer;
|
||||
|
||||
// Display the authentication window right away, to show a loader
|
||||
// while the call for game registration is happening.
|
||||
domElementContainer.appendChild(_authenticationRootContainer);
|
||||
|
||||
// If the game is registered, open the authentication window.
|
||||
// Otherwise, open the window indicating that the game is not registered.
|
||||
checkIfGameIsRegistered(runtimeScene.getGame(), _gameId)
|
||||
.then((isGameRegistered) => {
|
||||
if (_authenticationLoaderContainer) {
|
||||
_authenticationTextContainer = authComponents.addAuthenticationTextsToLoadingContainer(
|
||||
_authenticationLoaderContainer,
|
||||
platform,
|
||||
isGameRegistered
|
||||
);
|
||||
}
|
||||
if (isGameRegistered) {
|
||||
startAuthenticationWindowTimeout(runtimeScene);
|
||||
|
||||
// Based on which platform the game is running, we open the authentication window
|
||||
// with a different window, with or without a websocket.
|
||||
switch (platform) {
|
||||
case 'electron':
|
||||
openAuthenticationWindowForElectron(runtimeScene, _gameId);
|
||||
break;
|
||||
case 'cordova':
|
||||
openAuthenticationWindowForCordova(runtimeScene, _gameId);
|
||||
break;
|
||||
case 'web':
|
||||
default:
|
||||
openAuthenticationWindowForWeb(runtimeScene, _gameId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
handleAuthenticationError(
|
||||
runtimeScene,
|
||||
'Error while checking if the game is registered.'
|
||||
);
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Condition to check if the window is open, so that the game can be paused in the background.
|
||||
*/
|
||||
export const isAuthenticationWindowOpen = function (): boolean {
|
||||
return !!_authenticationRootContainer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the container displaying the authentication window and the callback.
|
||||
*/
|
||||
export const removeAuthenticationContainer = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const domElementContainer = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getDomElementContainer();
|
||||
if (!domElementContainer) {
|
||||
logger.info(
|
||||
"The div element covering the game couldn't be found, the authentication must be already closed."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the authentication root container.
|
||||
if (_authenticationRootContainer) {
|
||||
domElementContainer.removeChild(_authenticationRootContainer);
|
||||
}
|
||||
|
||||
// Remove the authentication callbacks.
|
||||
if (_authenticationMessageCallback) {
|
||||
window.removeEventListener(
|
||||
'message',
|
||||
_authenticationMessageCallback,
|
||||
true
|
||||
);
|
||||
_authenticationMessageCallback = null;
|
||||
// No need to detach the callback from the InAppBrowser, as it's destroyed when the window is closed.
|
||||
_cordovaAuthenticationMessageCallback = null;
|
||||
}
|
||||
|
||||
_authenticationRootContainer = null;
|
||||
_authenticationLoaderContainer = null;
|
||||
_authenticationTextContainer = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the banner displaying the authentication status.
|
||||
*/
|
||||
const removeAuthenticationBanner = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
if (!_authenticationBanner) {
|
||||
logger.info(
|
||||
"The authentication banner couldn't be found, the authentication banner must be already closed."
|
||||
);
|
||||
return;
|
||||
}
|
||||
const domElementContainer = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getDomElementContainer();
|
||||
if (!domElementContainer) {
|
||||
logger.info(
|
||||
"The div element covering the game couldn't be found, the authentication must be already closed."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
domElementContainer.removeChild(_authenticationBanner);
|
||||
_authenticationBanner = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Focus on game canvas to allow user to interact with it.
|
||||
*/
|
||||
const focusOnGame = function (runtimeScene: gdjs.RuntimeScene) {
|
||||
const gameCanvas = runtimeScene.getGame().getRenderer().getCanvas();
|
||||
if (gameCanvas) gameCanvas.focus();
|
||||
};
|
||||
}
|
||||
}
|
@@ -20,6 +20,8 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
"Florian Rival and Aurélien Vivet",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects/shape_painter");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Shape painter"))
|
||||
.SetIcon("CppPlatform/Extensions/primitivedrawingicon.png");
|
||||
|
||||
gd::ObjectMetadata& obj =
|
||||
extension
|
||||
@@ -256,8 +258,8 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("Move the drawing position of the path to _PARAM1_;_PARAM2_ "
|
||||
"with _PARAM0_"),
|
||||
_("Advanced"),
|
||||
"res/actions/position24.png",
|
||||
"res/actions/position.png")
|
||||
"res/actions/position24_black.png",
|
||||
"res/actions/position_black.png")
|
||||
|
||||
.AddParameter("object", _("Shape Painter object"), "Drawer")
|
||||
.AddParameter("expression", _("X position of start point"))
|
||||
@@ -474,8 +476,8 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("Modify the size of the outline of future drawings."),
|
||||
_("the size of the outline"),
|
||||
_("Setup"),
|
||||
"res/actions/outlineSize24.png",
|
||||
"res/actions/outlineSize.png")
|
||||
"res/actions/outlineSize24_black.png",
|
||||
"res/actions/outlineSize_black.png")
|
||||
|
||||
.AddParameter("object", _("Shape Painter object"), "Drawer")
|
||||
.UseStandardOperatorParameters("number")
|
||||
@@ -487,8 +489,8 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("Test the size of the outline."),
|
||||
_("the size of the outline"),
|
||||
_("Setup"),
|
||||
"res/conditions/outlineSize24.png",
|
||||
"res/conditions/outlineSize.png")
|
||||
"res/conditions/outlineSize24_black.png",
|
||||
"res/conditions/outlineSize_black.png")
|
||||
|
||||
.AddParameter("object", _("Shape Painter object"), "Drawer")
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
@@ -498,7 +500,7 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("Outline size"),
|
||||
_("Outline size"),
|
||||
"",
|
||||
"res/conditions/outlineSize.png")
|
||||
"res/conditions/outlineSize_black.png")
|
||||
.AddParameter("object", _("Shape Painter object"), "Drawer")
|
||||
.SetFunctionName("GetOutlineSize");
|
||||
|
||||
@@ -576,8 +578,8 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
"not. It's recommended to use relative coordinates."),
|
||||
_("Use relative coordinates for _PARAM0_: _PARAM1_"),
|
||||
_("Setup"),
|
||||
"res/actions/position24.png",
|
||||
"res/actions/position.png")
|
||||
"res/actions/position24_black.png",
|
||||
"res/actions/position_black.png")
|
||||
.AddParameter("object", _("Shape Painter object"), "Drawer")
|
||||
.AddParameter("yesorno", _("Use relative coordinates?"), "", false)
|
||||
.SetDefaultValue("true")
|
||||
@@ -589,8 +591,8 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("Check if the coordinates of the shape painter is relative."),
|
||||
_("_PARAM0_ is using relative coordinates"),
|
||||
_("Setup"),
|
||||
"res/conditions/position24.png",
|
||||
"res/conditions/position.png")
|
||||
"res/conditions/position24_black.png",
|
||||
"res/conditions/position_black.png")
|
||||
|
||||
.AddParameter("object", _("Shape Painter object"), "Drawer")
|
||||
.SetFunctionName("AreCoordinatesRelative");
|
||||
@@ -600,8 +602,8 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("Modify the scale of the specified object."),
|
||||
_("the scale"),
|
||||
_("Size"),
|
||||
"res/actions/scale24.png",
|
||||
"res/actions/scale.png")
|
||||
"res/actions/scale24_black.png",
|
||||
"res/actions/scale_black.png")
|
||||
.AddParameter("object", _("Object"), "Drawer")
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
@@ -612,7 +614,7 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("the width's scale of an object"),
|
||||
_("the width's scale"),
|
||||
_("Size"),
|
||||
"res/actions/scaleWidth24.png")
|
||||
"res/actions/scaleWidth24_black.png")
|
||||
.AddParameter("object", _("Object"), "Drawer")
|
||||
.UseStandardParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
@@ -623,7 +625,7 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("the height's scale of an object"),
|
||||
_("the height's scale"),
|
||||
_("Size"),
|
||||
"res/actions/scaleHeight24.png")
|
||||
"res/actions/scaleHeight24_black.png")
|
||||
.AddParameter("object", _("Object"), "Drawer")
|
||||
.UseStandardParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
@@ -673,8 +675,8 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("Change the width of an object."),
|
||||
_("the width"),
|
||||
_("Size"),
|
||||
"res/actions/scaleWidth24.png",
|
||||
"res/actions/scale.png")
|
||||
"res/actions/scaleWidth24_black.png",
|
||||
"res/actions/scaleWidth_black.png")
|
||||
.AddParameter("object", _("Object"), "Drawer")
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
@@ -684,8 +686,8 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("Change the height of an object."),
|
||||
_("the height"),
|
||||
_("Size"),
|
||||
"res/actions/scaleHeight24.png",
|
||||
"res/actions/scale.png")
|
||||
"res/actions/scaleHeight24_black.png",
|
||||
"res/actions/scaleHeight_black.png")
|
||||
.AddParameter("object", _("Object"), "Drawer")
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
@@ -697,8 +699,8 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
"object origin."),
|
||||
_("Change the center of rotation of _PARAM0_: _PARAM1_; _PARAM2_"),
|
||||
_("Angle"),
|
||||
"res/actions/position24.png",
|
||||
"res/actions/position.png")
|
||||
"res/actions/position24_black.png",
|
||||
"res/actions/position_black.png")
|
||||
.AddParameter("object", _("Object"), "Drawer")
|
||||
.AddParameter("expression", _("X position"))
|
||||
.AddParameter("expression", _("Y position"))
|
||||
@@ -711,8 +713,8 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("Change the collision mask of _PARAM0_ to a rectangle from "
|
||||
"_PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_"),
|
||||
_("Position"),
|
||||
"res/actions/position24.png",
|
||||
"res/actions/position.png")
|
||||
"res/actions/position24_black.png",
|
||||
"res/actions/position_black.png")
|
||||
.AddParameter("object", _("Object"), "Drawer")
|
||||
.AddParameter("expression", _("Left X position"))
|
||||
.AddParameter("expression", _("Top Y position"))
|
||||
@@ -724,7 +726,7 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("X drawing coordinate of a point from the scene"),
|
||||
_("X drawing coordinate of a point from the scene"),
|
||||
_("Position"),
|
||||
"res/actions/position.png")
|
||||
"res/actions/position_black.png")
|
||||
.AddParameter("object", _("Object"), "Drawer")
|
||||
.AddParameter("expression", _("X scene position"))
|
||||
.AddParameter("expression", _("Y scene position"));
|
||||
@@ -733,7 +735,7 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("Y drawing coordinate of a point from the scene"),
|
||||
_("Y drawing coordinate of a point from the scene"),
|
||||
_("Position"),
|
||||
"res/actions/position.png")
|
||||
"res/actions/position_black.png")
|
||||
.AddParameter("object", _("Object"), "Drawer")
|
||||
.AddParameter("expression", _("X scene position"))
|
||||
.AddParameter("expression", _("Y scene position"));
|
||||
@@ -742,7 +744,7 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("X scene coordinate of a point from the drawing"),
|
||||
_("X scene coordinate of a point from the drawing"),
|
||||
_("Position"),
|
||||
"res/actions/position.png")
|
||||
"res/actions/position_black.png")
|
||||
.AddParameter("object", _("Object"), "Drawer")
|
||||
.AddParameter("expression", _("X drawing position"))
|
||||
.AddParameter("expression", _("Y drawing position"));
|
||||
@@ -751,7 +753,7 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("Y scene coordinate of a point from the drawing"),
|
||||
_("Y scene coordinate of a point from the drawing"),
|
||||
_("Position"),
|
||||
"res/actions/position.png")
|
||||
"res/actions/position_black.png")
|
||||
.AddParameter("object", _("Object"), "Drawer")
|
||||
.AddParameter("expression", _("X drawing position"))
|
||||
.AddParameter("expression", _("Y drawing position"));
|
||||
|
@@ -33,7 +33,7 @@ ShapePainterObjectBase::ShapePainterObjectBase()
|
||||
clearBetweenFrames(true),
|
||||
absoluteCoordinates(false) {}
|
||||
|
||||
ShapePainterObject::ShapePainterObject(gd::String name_) : gd::Object(name_) {}
|
||||
ShapePainterObject::ShapePainterObject() {}
|
||||
|
||||
void ShapePainterObjectBase::DoUnserializeFrom(
|
||||
gd::Project& project, const gd::SerializerElement& element) {
|
||||
|
@@ -9,7 +9,7 @@ This project is released under the MIT License.
|
||||
#define SHAPEPAINTEROBJECT_H
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
namespace gd {
|
||||
class Object;
|
||||
class InitialInstance;
|
||||
@@ -88,12 +88,12 @@ class GD_EXTENSION_API ShapePainterObjectBase {
|
||||
/**
|
||||
* \brief The Shape Painter object used for storage and by the IDE.
|
||||
*/
|
||||
class GD_EXTENSION_API ShapePainterObject : public gd::Object,
|
||||
class GD_EXTENSION_API ShapePainterObject : public gd::ObjectConfiguration,
|
||||
public ShapePainterObjectBase {
|
||||
public:
|
||||
ShapePainterObject(gd::String name_);
|
||||
ShapePainterObject();
|
||||
virtual ~ShapePainterObject(){};
|
||||
virtual std::unique_ptr<gd::Object> Clone() const {
|
||||
virtual std::unique_ptr<gd::ObjectConfiguration> Clone() const {
|
||||
return gd::make_unique<ShapePainterObject>(*this);
|
||||
}
|
||||
|
||||
|
@@ -34,7 +34,7 @@ module.exports = {
|
||||
'Open source (MIT License)'
|
||||
)
|
||||
.setExtensionHelpPath('/all-features/screenshot')
|
||||
.setCategory('Device');
|
||||
.setCategory('Advanced');
|
||||
extension
|
||||
.addInstructionOrExpressionGroupMetadata(_('Screenshot'))
|
||||
.setIcon('JsPlatform/Extensions/take_screenshot32.png');
|
||||
|
@@ -15,7 +15,7 @@ void DeclareSystemInfoExtension(gd::PlatformExtension& extension) {
|
||||
_("Get information about the system and device running the game."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("Device");
|
||||
.SetCategory("Advanced");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("System information"))
|
||||
.SetIcon("CppPlatform/Extensions/systeminfoicon.png");
|
||||
|
||||
|
@@ -18,6 +18,7 @@ void DeclareTextEntryObjectExtension(gd::PlatformExtension& extension) {
|
||||
"entered with a keyboard by a player."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("User interface")
|
||||
.SetExtensionHelpPath("/objects/text_entry");
|
||||
|
||||
gd::ObjectMetadata& obj =
|
||||
@@ -27,7 +28,7 @@ void DeclareTextEntryObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Invisible object used to get the text "
|
||||
"entered with the keyboard."),
|
||||
"CppPlatform/Extensions/textentry.png")
|
||||
.SetCategoryFullName(_("Advanced"));
|
||||
.SetCategoryFullName(_("User interface"));
|
||||
|
||||
obj.AddAction("String",
|
||||
_("Text in memory"),
|
||||
|
@@ -10,4 +10,4 @@ This project is released under the MIT License.
|
||||
|
||||
using namespace std;
|
||||
|
||||
TextEntryObject::TextEntryObject(gd::String name_) : Object(name_) {}
|
||||
TextEntryObject::TextEntryObject() {}
|
||||
|
@@ -7,16 +7,16 @@ This project is released under the MIT License.
|
||||
|
||||
#ifndef TEXTENTRYOBJECT_H
|
||||
#define TEXTENTRYOBJECT_H
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
|
||||
/**
|
||||
* \brief Simple object which stores user keyboard input.
|
||||
*/
|
||||
class GD_EXTENSION_API TextEntryObject : public gd::Object {
|
||||
class GD_EXTENSION_API TextEntryObject : public gd::ObjectConfiguration {
|
||||
public:
|
||||
TextEntryObject(gd::String name_);
|
||||
TextEntryObject();
|
||||
virtual ~TextEntryObject(){};
|
||||
virtual std::unique_ptr<gd::Object> Clone() const {
|
||||
virtual std::unique_ptr<gd::ObjectConfiguration> Clone() const {
|
||||
return gd::make_unique<TextEntryObject>(*this);
|
||||
}
|
||||
|
||||
|
@@ -31,7 +31,10 @@ module.exports = {
|
||||
_('A text field the player can type text into.'),
|
||||
'Florian Rival',
|
||||
'MIT'
|
||||
);
|
||||
)
|
||||
.setCategory('User interface');
|
||||
extension.addInstructionOrExpressionGroupMetadata(_("Text Input"))
|
||||
.setIcon("JsPlatform/Extensions/text_input.svg");
|
||||
|
||||
const textInputObject = new gd.ObjectJsImplementation();
|
||||
// $FlowExpectedError - ignore Flow warning as we're creating an object
|
||||
@@ -277,7 +280,7 @@ module.exports = {
|
||||
'JsPlatform/Extensions/text_input.svg',
|
||||
textInputObject
|
||||
)
|
||||
.setCategoryFullName(_('Form control'))
|
||||
.setCategoryFullName(_('User interface'))
|
||||
.addUnsupportedBaseObjectCapability('effect')
|
||||
.setIncludeFile('Extensions/TextInput/textinputruntimeobject.js')
|
||||
.addIncludeFile(
|
||||
@@ -293,7 +296,7 @@ module.exports = {
|
||||
_('the text'),
|
||||
_('the text'),
|
||||
'',
|
||||
'res/conditions/text24.png'
|
||||
'res/conditions/text24_black.png'
|
||||
)
|
||||
.addParameter('object', _('Text input'), 'TextInputObject', false)
|
||||
.useStandardParameters('string')
|
||||
@@ -308,7 +311,7 @@ module.exports = {
|
||||
_('the placeholder'),
|
||||
_('the placeholder'),
|
||||
'',
|
||||
'res/conditions/text24.png'
|
||||
'res/conditions/text24_black.png'
|
||||
)
|
||||
.addParameter('object', _('Text input'), 'TextInputObject', false)
|
||||
.useStandardParameters('string')
|
||||
@@ -368,7 +371,7 @@ module.exports = {
|
||||
_('the input type'),
|
||||
_('the input type'),
|
||||
_('Type'),
|
||||
'res/conditions/text24.png'
|
||||
'res/conditions/text24_black.png'
|
||||
)
|
||||
.addParameter('object', _('Text input'), 'TextInputObject', false)
|
||||
.useStandardParameters('string') // TODO: stringWithSelector?
|
||||
@@ -458,7 +461,7 @@ module.exports = {
|
||||
_('the border width'),
|
||||
_('the border width'),
|
||||
_('Field appearance'),
|
||||
'res/conditions/outlineSize24.png'
|
||||
'res/conditions/outlineSize24_black.png'
|
||||
)
|
||||
.addParameter('object', _('Text input'), 'TextInputObject', false)
|
||||
.useStandardParameters('number')
|
||||
@@ -475,7 +478,7 @@ module.exports = {
|
||||
_('the text input is read-only'),
|
||||
_('read-only'),
|
||||
'',
|
||||
'res/conditions/text24.png'
|
||||
'res/conditions/text24_black.png'
|
||||
)
|
||||
.addParameter('object', _('Text input'), 'TextInputObject', false)
|
||||
.useStandardParameters('boolean')
|
||||
@@ -490,7 +493,7 @@ module.exports = {
|
||||
_('the text input is disabled'),
|
||||
_('disabled'),
|
||||
'',
|
||||
'res/conditions/text24.png'
|
||||
'res/conditions/text24_black.png'
|
||||
)
|
||||
.addParameter('object', _('Text input'), 'TextInputObject', false)
|
||||
.useStandardParameters('boolean')
|
||||
@@ -582,7 +585,7 @@ module.exports = {
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
) {
|
||||
@@ -590,7 +593,7 @@ module.exports = {
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
);
|
||||
@@ -612,13 +615,14 @@ module.exports = {
|
||||
this.update();
|
||||
}
|
||||
|
||||
static getThumbnail(project, resourcesLoader, object) {
|
||||
static getThumbnail(project, resourcesLoader, objectConfiguration) {
|
||||
return 'JsPlatform/Extensions/text_input.svg';
|
||||
}
|
||||
|
||||
update() {
|
||||
const instance = this._instance;
|
||||
const properties = this._associatedObject.getProperties();
|
||||
const properties = this._associatedObjectConfiguration
|
||||
.getProperties();
|
||||
|
||||
const placeholder =
|
||||
instance.getRawStringProperty('placeholder') ||
|
||||
|
@@ -23,7 +23,10 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
"some indicators, menu buttons, dialogues..."),
|
||||
"Florian Rival and Victor Levasseur",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("User interface")
|
||||
.SetExtensionHelpPath("/objects/text");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Text object"))
|
||||
.SetIcon("CppPlatform/Extensions/texticon.png");
|
||||
|
||||
gd::ObjectMetadata& obj =
|
||||
extension
|
||||
@@ -31,15 +34,15 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Text"),
|
||||
_("Displays a text on the screen."),
|
||||
"CppPlatform/Extensions/texticon.png")
|
||||
.SetCategoryFullName(_("Texts"));
|
||||
.SetCategoryFullName(_("User interface"));
|
||||
|
||||
obj.AddAction("String",
|
||||
_("Modify the text"),
|
||||
_("Modify the text of a Text object."),
|
||||
_("the text"),
|
||||
"",
|
||||
"res/actions/text24.png",
|
||||
"res/actions/text.png")
|
||||
"res/actions/text24_black.png",
|
||||
"res/actions/text_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardOperatorParameters("string")
|
||||
@@ -51,8 +54,8 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Compare the text of a Text object."),
|
||||
_("the text"),
|
||||
"",
|
||||
"res/conditions/text24.png",
|
||||
"res/conditions/text.png")
|
||||
"res/conditions/text24_black.png",
|
||||
"res/conditions/text_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardRelationalOperatorParameters("string")
|
||||
@@ -75,8 +78,8 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Compare the scale of the text on the X axis"),
|
||||
_("the scale on the X axis"),
|
||||
"Scale",
|
||||
"res/conditions/scaleWidth24.png",
|
||||
"res/conditions/scaleWidth.png")
|
||||
"res/conditions/scaleWidth24_black.png",
|
||||
"res/conditions/scaleWidth_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
@@ -88,8 +91,8 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Modify the scale of the text on the X axis (default scale is 1)"),
|
||||
_("the scale on the X axis"),
|
||||
_("Scale"),
|
||||
"res/actions/scaleWidth24.png",
|
||||
"res/actions/scaleWidth.png")
|
||||
"res/actions/scaleWidth24_black.png",
|
||||
"res/actions/scaleWidth_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardOperatorParameters("number")
|
||||
@@ -100,8 +103,8 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Compare the scale of the text on the Y axis"),
|
||||
_("the scale on the Y axis"),
|
||||
"Scale",
|
||||
"res/conditions/scaleHeight24.png",
|
||||
"res/conditions/scaleHeight.png")
|
||||
"res/conditions/scaleHeight24_black.png",
|
||||
"res/conditions/scaleHeight_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
@@ -113,8 +116,8 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Modify the scale of the text on the Y axis (default scale is 1)"),
|
||||
_("the scale on the Y axis"),
|
||||
_("Scale"),
|
||||
"res/actions/scaleHeight24.png",
|
||||
"res/actions/scaleHeight.png")
|
||||
"res/actions/scaleHeight24_black.png",
|
||||
"res/actions/scaleHeight_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardOperatorParameters("number")
|
||||
@@ -126,8 +129,8 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Modify the scale of the specified object (default scale is 1)"),
|
||||
_("the scale"),
|
||||
_("Scale"),
|
||||
"res/actions/scale24.png",
|
||||
"res/actions/scale.png")
|
||||
"res/actions/scale24_black.png",
|
||||
"res/actions/scale_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardOperatorParameters("number")
|
||||
@@ -329,8 +332,8 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Modify the angle of a Text object."),
|
||||
_("the angle"),
|
||||
_("Rotation"),
|
||||
"res/actions/rotate24.png",
|
||||
"res/actions/rotate.png")
|
||||
"res/actions/rotate24_black.png",
|
||||
"res/actions/rotate_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardOperatorParameters("number")
|
||||
@@ -342,8 +345,8 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Compare the value of the angle of a Text object."),
|
||||
_("the angle"),
|
||||
_("Rotation"),
|
||||
"res/conditions/rotate24.png",
|
||||
"res/conditions/rotate.png")
|
||||
"res/conditions/rotate24_black.png",
|
||||
"res/conditions/rotate_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
@@ -356,8 +359,8 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
"cropped, raise this value."),
|
||||
_("the padding"),
|
||||
_("Style"),
|
||||
"res/conditions/textPadding24.png",
|
||||
"res/conditions/textPadding.png")
|
||||
"res/conditions/textPadding24_black.png",
|
||||
"res/conditions/textPadding_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardRelationalOperatorParameters("number");
|
||||
@@ -369,8 +372,8 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
"raise this value."),
|
||||
_("the padding"),
|
||||
_("Style"),
|
||||
"res/actions/textPadding24.png",
|
||||
"res/actions/textPadding.png")
|
||||
"res/actions/textPadding24_black.png",
|
||||
"res/actions/textPadding_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardOperatorParameters("number");
|
||||
@@ -409,8 +412,8 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
"option,\nyou can't get the number of lines displayed"),
|
||||
_("Activate wrapping style of _PARAM0_: _PARAM1_"),
|
||||
_("Style"),
|
||||
"res/actions/wordWrap24.png",
|
||||
"res/actions/wordWrap.png")
|
||||
"res/actions/wordWrap24_black.png",
|
||||
"res/actions/wordWrap_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.AddParameter("yesorno", _("Wrapping"));
|
||||
@@ -420,8 +423,8 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Test if the word wrapping style of an object is set."),
|
||||
_("_PARAM0_ word wrapping style is activated"),
|
||||
_("Style"),
|
||||
"res/conditions/wordWrap24.png",
|
||||
"res/conditions/wordWrap.png")
|
||||
"res/conditions/wordWrap24_black.png",
|
||||
"res/conditions/wordWrap_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Text");
|
||||
|
||||
@@ -430,8 +433,8 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Modify the word wrapping width of a Text object."),
|
||||
_("the wrapping width"),
|
||||
_("Style"),
|
||||
"res/actions/wordWrap24.png",
|
||||
"res/actions/wordWrap.png")
|
||||
"res/actions/wordWrap24_black.png",
|
||||
"res/actions/wordWrap_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardOperatorParameters("number");
|
||||
@@ -441,8 +444,8 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Test the word wrapping width of a Text object."),
|
||||
_("the wrapping width"),
|
||||
_("Style"),
|
||||
"res/conditions/wordWrap24.png",
|
||||
"res/conditions/wordWrap.png")
|
||||
"res/conditions/wordWrap24_black.png",
|
||||
"res/conditions/wordWrap_black.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardRelationalOperatorParameters("number");
|
||||
@@ -451,14 +454,14 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Padding"),
|
||||
_("Padding"),
|
||||
_("Style"),
|
||||
"res/actions/textPadding.png")
|
||||
"res/actions/textPadding_black.png")
|
||||
.AddParameter("object", _("Object"), "Text");
|
||||
|
||||
obj.AddExpression("ScaleX",
|
||||
_("X Scale of a Text object"),
|
||||
_("X Scale of a Text object"),
|
||||
_("Scale"),
|
||||
"res/actions/scaleWidth.png")
|
||||
"res/actions/scaleWidth_black.png")
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.SetFunctionName("GetScaleX");
|
||||
|
||||
@@ -466,7 +469,7 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Y Scale of a Text object"),
|
||||
_("Y Scale of a Text object"),
|
||||
_("Scale"),
|
||||
"res/actions/scaleHeight.png")
|
||||
"res/actions/scaleHeight_black.png")
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.SetFunctionName("GetScaleY");
|
||||
|
||||
@@ -482,7 +485,7 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
_("Angle"),
|
||||
_("Angle"),
|
||||
_("Rotation"),
|
||||
"res/actions/rotate.png")
|
||||
"res/actions/rotate_black.png")
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.SetFunctionName("GetAngle");
|
||||
|
||||
|
@@ -19,9 +19,8 @@ This project is released under the MIT License.
|
||||
|
||||
using namespace std;
|
||||
|
||||
TextObject::TextObject(gd::String name_)
|
||||
: Object(name_),
|
||||
text("Text"),
|
||||
TextObject::TextObject()
|
||||
: text("Text"),
|
||||
characterSize(20),
|
||||
fontName(""),
|
||||
smoothed(true),
|
||||
|
@@ -7,7 +7,7 @@ This project is released under the MIT License.
|
||||
|
||||
#ifndef TEXTOBJECT_H
|
||||
#define TEXTOBJECT_H
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
namespace gd {
|
||||
class Project;
|
||||
class Object;
|
||||
@@ -17,11 +17,11 @@ class InitialInstance;
|
||||
/**
|
||||
* Text Object
|
||||
*/
|
||||
class GD_EXTENSION_API TextObject : public gd::Object {
|
||||
class GD_EXTENSION_API TextObject : public gd::ObjectConfiguration {
|
||||
public:
|
||||
TextObject(gd::String name_);
|
||||
TextObject();
|
||||
virtual ~TextObject();
|
||||
virtual std::unique_ptr<gd::Object> Clone() const {
|
||||
virtual std::unique_ptr<gd::ObjectConfiguration> Clone() const {
|
||||
return gd::make_unique<TextObject>(*this);
|
||||
}
|
||||
|
||||
|
@@ -26,7 +26,7 @@ const defineTileMap = function (
|
||||
extension,
|
||||
_ /*: (string) => string */,
|
||||
gd /*: libGDevelop */) {
|
||||
|
||||
|
||||
var objectTileMap = new gd.ObjectJsImplementation();
|
||||
// $FlowExpectedError - ignore Flow warning as we're creating an object
|
||||
objectTileMap.updateProperty = function (
|
||||
@@ -435,8 +435,8 @@ const defineTileMap = function (
|
||||
_("Modify the scale of the specified object."),
|
||||
_("the scale"),
|
||||
_("Size"),
|
||||
"res/actions/scale24.png",
|
||||
"res/actions/scale.png"
|
||||
"res/actions/scale24_black.png",
|
||||
"res/actions/scale_black.png"
|
||||
)
|
||||
.addParameter('object', _('Tile map'), 'TileMap', false)
|
||||
.useStandardOperatorParameters("number")
|
||||
@@ -452,7 +452,7 @@ object
|
||||
_("the width's scale of an object"),
|
||||
_("the width's scale"),
|
||||
_("Size"),
|
||||
"res/actions/scaleWidth24.png"
|
||||
"res/actions/scaleWidth24_black.png"
|
||||
)
|
||||
.addParameter('object', _('Tile map'), 'TileMap', false)
|
||||
.useStandardParameters("number")
|
||||
@@ -468,7 +468,7 @@ object
|
||||
_("the height's scale of an object"),
|
||||
_("the height's scale"),
|
||||
_("Size"),
|
||||
"res/actions/scaleHeight24.png"
|
||||
"res/actions/scaleHeight24_black.png"
|
||||
)
|
||||
.addParameter('object', _('Tile map'), 'TileMap', false)
|
||||
.useStandardParameters("number")
|
||||
@@ -483,8 +483,8 @@ object
|
||||
_("Change the width of an object."),
|
||||
_("the width"),
|
||||
_("Size"),
|
||||
"res/actions/scaleWidth24.png",
|
||||
"res/actions/scale.png"
|
||||
"res/actions/scaleWidth24_black.png",
|
||||
"res/actions/scaleWidth_black.png"
|
||||
)
|
||||
.addParameter('object', _('Tile map'), 'TileMap', false)
|
||||
.useStandardOperatorParameters("number")
|
||||
@@ -499,8 +499,8 @@ object
|
||||
_("Change the height of an object."),
|
||||
_("the height"),
|
||||
_("Size"),
|
||||
"res/actions/scaleHeight24.png",
|
||||
"res/actions/scale.png"
|
||||
"res/actions/scaleHeight24_black.png",
|
||||
"res/actions/scaleHeight_black.png"
|
||||
)
|
||||
.addParameter('object', _('Tile map'), 'TileMap', false)
|
||||
.useStandardOperatorParameters("number")
|
||||
@@ -514,7 +514,7 @@ const defineCollisionMask = function (
|
||||
extension,
|
||||
_ /*: (string) => string */,
|
||||
gd /*: libGDevelop */) {
|
||||
|
||||
|
||||
var collisionMaskObject = new gd.ObjectJsImplementation();
|
||||
// $FlowExpectedError - ignore Flow warning as we're creating an object
|
||||
collisionMaskObject.updateProperty = function (
|
||||
@@ -768,15 +768,15 @@ const defineCollisionMask = function (
|
||||
_("Modify the scale of the specified object."),
|
||||
_("the scale"),
|
||||
_("Size"),
|
||||
"res/actions/scale24.png",
|
||||
"res/actions/scale.png"
|
||||
"res/actions/scale24_black.png",
|
||||
"res/actions/scale_black.png"
|
||||
)
|
||||
.addParameter('object', _('Tile map collision mask'), 'CollisionMask', false)
|
||||
.useStandardOperatorParameters("number")
|
||||
.markAsAdvanced()
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('setScale');
|
||||
|
||||
|
||||
object
|
||||
.addExpressionAndConditionAndAction(
|
||||
"number",
|
||||
@@ -785,7 +785,7 @@ const defineCollisionMask = function (
|
||||
_("the width's scale of an object"),
|
||||
_("the width's scale"),
|
||||
_("Size"),
|
||||
"res/actions/scaleWidth24.png"
|
||||
"res/actions/scaleWidth24_black.png"
|
||||
)
|
||||
.addParameter('object', _('Tile map collision mask'), 'CollisionMask', false)
|
||||
.useStandardParameters("number")
|
||||
@@ -801,7 +801,7 @@ const defineCollisionMask = function (
|
||||
_("the height's scale of an object"),
|
||||
_("the height's scale"),
|
||||
_("Size"),
|
||||
"res/actions/scaleHeight24.png"
|
||||
"res/actions/scaleHeight24_black.png"
|
||||
)
|
||||
.addParameter('object', _('Tile map collision mask'), 'CollisionMask', false)
|
||||
.useStandardParameters("number")
|
||||
@@ -816,15 +816,15 @@ const defineCollisionMask = function (
|
||||
_("Change the width of an object."),
|
||||
_("the width"),
|
||||
_("Size"),
|
||||
"res/actions/scaleWidth24.png",
|
||||
"res/actions/scale.png"
|
||||
"res/actions/scaleWidth24_black.png",
|
||||
"res/actions/scaleWidth_black.png"
|
||||
)
|
||||
.addParameter('object', _('Tile map collision mask'), 'CollisionMask', false)
|
||||
.useStandardOperatorParameters("number")
|
||||
.markAsAdvanced()
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('setWidth');
|
||||
|
||||
|
||||
object
|
||||
.addAction(
|
||||
"Height",
|
||||
@@ -832,15 +832,15 @@ const defineCollisionMask = function (
|
||||
_("Change the height of an object."),
|
||||
_("the height"),
|
||||
_("Size"),
|
||||
"res/actions/scaleHeight24.png",
|
||||
"res/actions/scale.png"
|
||||
"res/actions/scaleHeight24_black.png",
|
||||
"res/actions/scaleHeight_black.png"
|
||||
)
|
||||
.addParameter('object', _('Tile map collision mask'), 'CollisionMask', false)
|
||||
.useStandardOperatorParameters("number")
|
||||
.markAsAdvanced()
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('setHeight');
|
||||
|
||||
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
@@ -858,8 +858,11 @@ module.exports = {
|
||||
'Todor Imreorov',
|
||||
'Open source (MIT License)'
|
||||
)
|
||||
.setCategory('Advanced')
|
||||
.setExtensionHelpPath('/objects/tilemap');
|
||||
|
||||
extension.addInstructionOrExpressionGroupMetadata(_("Tilemap"))
|
||||
.setIcon("JsPlatform/Extensions/tile_map.svg");
|
||||
|
||||
defineTileMap(extension, _, gd);
|
||||
defineCollisionMask(extension, _, gd);
|
||||
|
||||
@@ -940,26 +943,23 @@ module.exports = {
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader,
|
||||
pixiRenderer
|
||||
pixiResourcesLoader
|
||||
) {
|
||||
RenderedInstance.call(
|
||||
this,
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader,
|
||||
pixiRenderer
|
||||
pixiResourcesLoader
|
||||
);
|
||||
|
||||
// This setting allows tile maps with more than 16K tiles.
|
||||
Tilemap.settings.use32bitIndex = true;
|
||||
pixiRenderer.plugins.tilemap =
|
||||
pixiRenderer.plugins.tilemap || new Tilemap.TileRenderer();
|
||||
|
||||
this.tileMapPixiObject = new Tilemap.CompositeTilemap();
|
||||
this._pixiObject = this.tileMapPixiObject;
|
||||
|
||||
@@ -1010,7 +1010,7 @@ module.exports = {
|
||||
RenderedTileMapInstance.getThumbnail = function (
|
||||
project,
|
||||
resourcesLoader,
|
||||
object
|
||||
objectConfiguration
|
||||
) {
|
||||
return 'JsPlatform/Extensions/tile_map.svg';
|
||||
};
|
||||
@@ -1020,26 +1020,26 @@ module.exports = {
|
||||
*/
|
||||
RenderedTileMapInstance.prototype.updateTileMap = function () {
|
||||
// Get the tileset resource to use
|
||||
const tilemapAtlasImage = this._associatedObject
|
||||
const tilemapAtlasImage = this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('tilemapAtlasImage')
|
||||
.getValue();
|
||||
const tilemapJsonFile = this._associatedObject
|
||||
const tilemapJsonFile = this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('tilemapJsonFile')
|
||||
.getValue();
|
||||
const tilesetJsonFile = this._associatedObject
|
||||
const tilesetJsonFile = this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('tilesetJsonFile')
|
||||
.getValue();
|
||||
const layerIndex = parseInt(
|
||||
this._associatedObject
|
||||
this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('layerIndex')
|
||||
.getValue(),
|
||||
10
|
||||
);
|
||||
const displayMode = this._associatedObject
|
||||
const displayMode = this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('displayMode')
|
||||
.getValue();
|
||||
@@ -1187,7 +1187,7 @@ module.exports = {
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
) {
|
||||
@@ -1196,7 +1196,7 @@ module.exports = {
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
);
|
||||
@@ -1252,7 +1252,7 @@ module.exports = {
|
||||
RenderedCollisionMaskInstance.getThumbnail = function (
|
||||
project,
|
||||
resourcesLoader,
|
||||
object
|
||||
objectConfiguration
|
||||
) {
|
||||
return 'JsPlatform/Extensions/tile_map_collision_mask24.svg';
|
||||
};
|
||||
@@ -1262,39 +1262,39 @@ module.exports = {
|
||||
*/
|
||||
RenderedCollisionMaskInstance.prototype.updateTileMap = function () {
|
||||
// Get the tileset resource to use
|
||||
const tilemapAtlasImage = this._associatedObject
|
||||
const tilemapAtlasImage = this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('tilemapAtlasImage')
|
||||
.getValue();
|
||||
const tilemapJsonFile = this._associatedObject
|
||||
const tilemapJsonFile = this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('tilemapJsonFile')
|
||||
.getValue();
|
||||
const tilesetJsonFile = this._associatedObject
|
||||
const tilesetJsonFile = this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('tilesetJsonFile')
|
||||
.getValue();
|
||||
const collisionMaskTag = this._associatedObject
|
||||
const collisionMaskTag = this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('collisionMaskTag')
|
||||
.getValue();
|
||||
const outlineColor = objectsRenderingService.rgbOrHexToHexNumber(
|
||||
this._associatedObject
|
||||
this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('outlineColor')
|
||||
.getValue()
|
||||
);
|
||||
const fillColor = objectsRenderingService.rgbOrHexToHexNumber(
|
||||
this._associatedObject
|
||||
this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('fillColor')
|
||||
.getValue()
|
||||
);
|
||||
const outlineOpacity = this._associatedObject
|
||||
const outlineOpacity = this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('outlineOpacity')
|
||||
.getValue() / 255;
|
||||
const fillOpacity = this._associatedObject
|
||||
const fillOpacity = this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('fillOpacity')
|
||||
.getValue() / 255;
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"version":3,"file":"TileMapPixiHelper.d.ts","sourceRoot":"","sources":["../../src/render/TileMapPixiHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAEL,eAAe,EAEhB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAGpC,qBAAa,iBAAiB;IAC5B;;;;;;;OAOG;IACH,MAAM,CAAC,UAAU,CACf,QAAQ,EAAE,QAAQ,EAClB,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,EACpD,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,GACnE,gBAAgB,GAAG,IAAI;IA6F1B;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,iBAAiB,CACtB,kBAAkB,EAAE,GAAG,EACvB,OAAO,EAAE,eAAe,EACxB,YAAY,EAAE,gBAAgB,EAC9B,WAAW,EAAE,OAAO,GAAG,SAAS,GAAG,KAAK,EACxC,UAAU,EAAE,MAAM,GACjB,IAAI;IAiFP;;OAEG;IACH,MAAM,CAAC,uBAAuB,CAC5B,YAAY,EAAE,IAAI,CAAC,QAAQ,EAC3B,OAAO,EAAE,eAAe,EACxB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,OAAO,EACpB,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,KAAK,EACrB,SAAS,EAAE,OAAO,EAClB,WAAW,EAAE,KAAK,GACjB,IAAI;CAiER"}
|
||||
{"version":3,"file":"TileMapPixiHelper.d.ts","sourceRoot":"","sources":["../../src/render/TileMapPixiHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAEL,eAAe,EAEhB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAGpC,qBAAa,iBAAiB;IAC5B;;;;;;;OAOG;IACH,MAAM,CAAC,UAAU,CACf,QAAQ,EAAE,QAAQ,EAClB,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,EACpD,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,GACnE,gBAAgB,GAAG,IAAI;IA6F1B;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,iBAAiB,CACtB,kBAAkB,EAAE,GAAG,EACvB,OAAO,EAAE,eAAe,EACxB,YAAY,EAAE,gBAAgB,EAC9B,WAAW,EAAE,OAAO,GAAG,SAAS,GAAG,KAAK,EACxC,UAAU,EAAE,MAAM,GACjB,IAAI;IAgFP;;OAEG;IACH,MAAM,CAAC,uBAAuB,CAC5B,YAAY,EAAE,IAAI,CAAC,QAAQ,EAC3B,OAAO,EAAE,eAAe,EACxB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,OAAO,EACpB,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,KAAK,EACrB,SAAS,EAAE,OAAO,EAClB,WAAW,EAAE,KAAK,GACjB,IAAI;CAiER"}
|
@@ -19,23 +19,29 @@ export declare class TileTextureCache {
|
||||
flippedDiagonally: boolean,
|
||||
texture: PIXI.Texture
|
||||
): void;
|
||||
/**
|
||||
* Return the texture to use for the tile with the specified id.
|
||||
*
|
||||
* @param tileId The tile identifier
|
||||
* @returns The texture for the given tile identifier.
|
||||
*/
|
||||
findTileTexture(tileId: integer): PIXI.Texture | undefined;
|
||||
/**
|
||||
* Return the texture to use for the tile with the specified uid, which can contains
|
||||
* information about rotation in bits 32, 31 and 30
|
||||
* (see https://doc.mapeditor.org/en/stable/reference/tmx-map-format/).
|
||||
*
|
||||
* @param tileId The tile identifier
|
||||
* @param flippedHorizontally true if the tile is flipped horizontally.
|
||||
* @param flippedVertically true if the tile is flipped vertically.
|
||||
* @param flippedDiagonally true if the tile is flipped diagonally.
|
||||
* @returns The texture for the given tile identifier and orientation.
|
||||
* @returns the rotation "D8" number used by Pixi.
|
||||
* @see https://pixijs.io/examples/#/textures/texture-rotate.js
|
||||
*/
|
||||
findTileTexture(
|
||||
tileId: integer,
|
||||
getPixiRotate(
|
||||
flippedHorizontally: boolean,
|
||||
flippedVertically: boolean,
|
||||
flippedDiagonally: boolean
|
||||
): PIXI.Texture | undefined;
|
||||
): number;
|
||||
/**
|
||||
* @return the Tiled tile global uniq identifier.
|
||||
*/
|
||||
|
@@ -1 +1 @@
|
||||
{"version":3,"file":"TileTextureCache.d.ts","sourceRoot":"","sources":["../../src/render/TileTextureCache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,OAAO,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAEpC;;;;;GAKG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAc;IAC7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAc;IAC3D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAc;IAE3D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6B;;IAMvD,UAAU,CACR,MAAM,EAAE,OAAO,EACf,mBAAmB,EAAE,OAAO,EAC5B,iBAAiB,EAAE,OAAO,EAC1B,iBAAiB,EAAE,OAAO,EAC1B,OAAO,EAAE,IAAI,CAAC,OAAO,GACpB,IAAI;IAUP;;;;;;;;;;OAUG;IACH,eAAe,CACb,MAAM,EAAE,OAAO,EACf,mBAAmB,EAAE,OAAO,EAC5B,iBAAiB,EAAE,OAAO,EAC1B,iBAAiB,EAAE,OAAO,GACzB,IAAI,CAAC,OAAO,GAAG,SAAS;IA8D3B;;OAEG;IACH,OAAO,CAAC,YAAY;CAkBrB"}
|
||||
{"version":3,"file":"TileTextureCache.d.ts","sourceRoot":"","sources":["../../src/render/TileTextureCache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,OAAO,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAEpC;;;;;GAKG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAc;IAC7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAc;IAC3D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAc;IAE3D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6B;;IAMvD,UAAU,CACR,MAAM,EAAE,OAAO,EACf,mBAAmB,EAAE,OAAO,EAC5B,iBAAiB,EAAE,OAAO,EAC1B,iBAAiB,EAAE,OAAO,EAC1B,OAAO,EAAE,IAAI,CAAC,OAAO,GACpB,IAAI;IAUP;;;;;OAKG;IACH,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC,OAAO,GAAG,SAAS;IAI1D;;;;;;;;;;OAUG;IACH,aAAa,CACX,mBAAmB,EAAE,OAAO,EAC5B,iBAAiB,EAAE,OAAO,EAC1B,iBAAiB,EAAE,OAAO,GACzB,MAAM;IAwBT;;OAEG;IACH,OAAO,CAAC,YAAY;CAkBrB"}
|
@@ -121,10 +121,10 @@ describe('gdjs.TileMapCollisionMaskRuntimeObject', function () {
|
||||
// TODO find a clean way to wait for the json to be read.
|
||||
for (
|
||||
let index = 0;
|
||||
index < 200 && tileMap._collisionTileMap.getDimensionX() === 0;
|
||||
index < 100 && tileMap._collisionTileMap.getDimensionX() === 0;
|
||||
index++
|
||||
) {
|
||||
await delay(5);
|
||||
await delay(20);
|
||||
}
|
||||
if (tileMap._collisionTileMap.getDimensionX() === 0) {
|
||||
throw new Error('Timeout reading the tile map JSON file.');
|
||||
|
@@ -10,7 +10,6 @@ namespace gdjs {
|
||||
*/
|
||||
export class TileMapRuntimeObjectPixiRenderer {
|
||||
private _object: any;
|
||||
private _runtimeScene: gdjs.RuntimeScene;
|
||||
private _tileMap: TileMapHelper.EditableTileMap | null = null;
|
||||
|
||||
private _pixiObject: PIXI.tilemap.CompositeTilemap;
|
||||
@@ -24,20 +23,9 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
this._runtimeScene = runtimeScene;
|
||||
|
||||
const pixiRenderer = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getPIXIRenderer();
|
||||
|
||||
// This setting allows tile maps with more than 16K tiles.
|
||||
PIXI.tilemap.settings.use32bitIndex = true;
|
||||
if (pixiRenderer) {
|
||||
pixiRenderer.plugins.tilemap =
|
||||
// @ts-ignore - pixi-tilemap types to be added.
|
||||
pixiRenderer.plugins.tilemap || new PIXI.tilemap.TileRenderer();
|
||||
}
|
||||
|
||||
// Load (or reset)
|
||||
this._pixiObject = new PIXI.tilemap.CompositeTilemap();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user