mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
231 Commits
v5.0.0-bet
...
v5.0.0-bet
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2b156ef147 | ||
![]() |
f650a6aa9c | ||
![]() |
5d62f0c926 | ||
![]() |
449a1f5da9 | ||
![]() |
a0e0fdf6e1 | ||
![]() |
036f384ff9 | ||
![]() |
b42abf0cd8 | ||
![]() |
ee699d3870 | ||
![]() |
346eed3779 | ||
![]() |
ef6f491fb4 | ||
![]() |
ee6043477b | ||
![]() |
deddfdc4cf | ||
![]() |
6ad69d4c74 | ||
![]() |
6446bb20a0 | ||
![]() |
015f9f64c7 | ||
![]() |
74e5b30fd1 | ||
![]() |
057c0a1d13 | ||
![]() |
7f6c9923dc | ||
![]() |
3dae7c1899 | ||
![]() |
04c2abd508 | ||
![]() |
d82fd79186 | ||
![]() |
fe312e0bf6 | ||
![]() |
ad22a83680 | ||
![]() |
ac32b677b0 | ||
![]() |
902bc8a510 | ||
![]() |
804c9563a1 | ||
![]() |
64996b5f7d | ||
![]() |
5fdf7be698 | ||
![]() |
a869fc14f9 | ||
![]() |
ae8a26b3f9 | ||
![]() |
aaec53faaa | ||
![]() |
bc56f820b3 | ||
![]() |
2c93c948bf | ||
![]() |
fe3a2f6e4a | ||
![]() |
449c96aaba | ||
![]() |
4cee984472 | ||
![]() |
98c9763d1c | ||
![]() |
c3ed8cbbb4 | ||
![]() |
65fc9f599e | ||
![]() |
10ebf9e65d | ||
![]() |
d1b1e3b24e | ||
![]() |
188b262af0 | ||
![]() |
a04c7f993f | ||
![]() |
13a8b5bce0 | ||
![]() |
45e6b19204 | ||
![]() |
0136445a65 | ||
![]() |
c26df2c8a9 | ||
![]() |
f390d4a1bc | ||
![]() |
cc2cdc492e | ||
![]() |
feeebd0560 | ||
![]() |
f6145f4c4e | ||
![]() |
fd490e1d5a | ||
![]() |
4760b0ab04 | ||
![]() |
3f95bf9f1a | ||
![]() |
76b63c2f76 | ||
![]() |
0a501f5a3c | ||
![]() |
45ab608409 | ||
![]() |
df94a4d0fb | ||
![]() |
c7d3d1314d | ||
![]() |
cff1a1e3c7 | ||
![]() |
3cf421f05b | ||
![]() |
6cc5016f9e | ||
![]() |
2dd62456c2 | ||
![]() |
d8b1c471bb | ||
![]() |
a3622a6504 | ||
![]() |
4ab14d18f8 | ||
![]() |
8ba11703e1 | ||
![]() |
8a8adf213a | ||
![]() |
25ea23a115 | ||
![]() |
586694543d | ||
![]() |
b7b6ab91f5 | ||
![]() |
d2d0235c8c | ||
![]() |
b473e0aaf0 | ||
![]() |
b2c7166b1b | ||
![]() |
bb2ae1a914 | ||
![]() |
aa1c5584ca | ||
![]() |
28593608a5 | ||
![]() |
8c5a312725 | ||
![]() |
3ed07dee5e | ||
![]() |
e1cb634e3d | ||
![]() |
f0392cfede | ||
![]() |
0bce1fc56b | ||
![]() |
b7aaf32d75 | ||
![]() |
0dce21904e | ||
![]() |
ca877e518e | ||
![]() |
f87ace7e25 | ||
![]() |
8954df947d | ||
![]() |
52a2f3653f | ||
![]() |
04a896de59 | ||
![]() |
8c6b9ef044 | ||
![]() |
45d7c6188b | ||
![]() |
10eb944b2a | ||
![]() |
a607c820a8 | ||
![]() |
0c22c52a78 | ||
![]() |
06748e00e1 | ||
![]() |
8b39233f44 | ||
![]() |
f68842bdb1 | ||
![]() |
544b88fec9 | ||
![]() |
48fe0fa2a6 | ||
![]() |
e7ef94de5f | ||
![]() |
1ffe5b0e9f | ||
![]() |
9282c0bcef | ||
![]() |
28d180e6fe | ||
![]() |
8cd1ea6b73 | ||
![]() |
b0e63460cf | ||
![]() |
a5e372ea35 | ||
![]() |
8f2c24e9e0 | ||
![]() |
dbd97ac23c | ||
![]() |
d0b36b9d77 | ||
![]() |
d1aa54b215 | ||
![]() |
c14f94b807 | ||
![]() |
685156b0cf | ||
![]() |
b4c5c01109 | ||
![]() |
238bf27671 | ||
![]() |
4dd001951c | ||
![]() |
e6c483f398 | ||
![]() |
4030f29d84 | ||
![]() |
4b389016e9 | ||
![]() |
659d19b771 | ||
![]() |
2524292ae1 | ||
![]() |
32d95da2ea | ||
![]() |
8ff4876f77 | ||
![]() |
cb36057014 | ||
![]() |
53a1024053 | ||
![]() |
16f3a1901d | ||
![]() |
43c420dff0 | ||
![]() |
265a86e41f | ||
![]() |
2c53b3b7a2 | ||
![]() |
e87d5e1d52 | ||
![]() |
cb6130ffee | ||
![]() |
0a742bf362 | ||
![]() |
f419186c65 | ||
![]() |
103c99f545 | ||
![]() |
d08f4dc059 | ||
![]() |
2a62f71f08 | ||
![]() |
331e847b3f | ||
![]() |
95b4a43e11 | ||
![]() |
9943dc650e | ||
![]() |
b09f62ce57 | ||
![]() |
32427b2357 | ||
![]() |
3c3bfbbf5d | ||
![]() |
64c732d2bb | ||
![]() |
23d64aa676 | ||
![]() |
532b86ac58 | ||
![]() |
e1bf859ff4 | ||
![]() |
1ad20ec6c9 | ||
![]() |
b5990ecbe3 | ||
![]() |
f2287dd1ef | ||
![]() |
a8714b8522 | ||
![]() |
ddf0ba7efd | ||
![]() |
9e8491420d | ||
![]() |
075d918619 | ||
![]() |
b68dfe040e | ||
![]() |
053f4a68df | ||
![]() |
216fd30145 | ||
![]() |
fda75e0475 | ||
![]() |
7fe057c180 | ||
![]() |
5d091c0a87 | ||
![]() |
319cea428e | ||
![]() |
0ac2ef7892 | ||
![]() |
fd6b9be49c | ||
![]() |
2d6f0fad90 | ||
![]() |
35f019afa8 | ||
![]() |
f7453a6a1d | ||
![]() |
89570505e6 | ||
![]() |
082318d7e4 | ||
![]() |
59c9812208 | ||
![]() |
62117e42d9 | ||
![]() |
cafa0d512f | ||
![]() |
136964053b | ||
![]() |
6beea7bfaf | ||
![]() |
ab6999a16c | ||
![]() |
937fd1888a | ||
![]() |
755c72c0bf | ||
![]() |
20392d6a79 | ||
![]() |
0a2033db3d | ||
![]() |
6c0fe0359a | ||
![]() |
66ed1110d2 | ||
![]() |
5badb27b35 | ||
![]() |
b7902bb141 | ||
![]() |
b5b3abd155 | ||
![]() |
06b299c4a2 | ||
![]() |
e42d2cbc6d | ||
![]() |
454159db3f | ||
![]() |
4324526689 | ||
![]() |
b57832a131 | ||
![]() |
8d9f5f0df0 | ||
![]() |
b6ec327dfc | ||
![]() |
005aa64aad | ||
![]() |
a18b813140 | ||
![]() |
7cd28062fc | ||
![]() |
2b7e2c8814 | ||
![]() |
767f365a78 | ||
![]() |
5f54583ff5 | ||
![]() |
37c260c19d | ||
![]() |
003f251c9f | ||
![]() |
f8250ec9aa | ||
![]() |
aeb4d278cd | ||
![]() |
2762329dd6 | ||
![]() |
75b1ff5cea | ||
![]() |
1f4042bff0 | ||
![]() |
4e04e79b2f | ||
![]() |
63894f9a86 | ||
![]() |
9a0ec853e7 | ||
![]() |
eb5d120aaf | ||
![]() |
057dd985fc | ||
![]() |
8009e45936 | ||
![]() |
b190731940 | ||
![]() |
a337230195 | ||
![]() |
731b9141fa | ||
![]() |
51ba2e7631 | ||
![]() |
48a0c2d324 | ||
![]() |
25d32ce9bb | ||
![]() |
a7ec57354d | ||
![]() |
643e3b5c32 | ||
![]() |
0cc4676067 | ||
![]() |
91b895fd92 | ||
![]() |
f95d0ae461 | ||
![]() |
81ce81242b | ||
![]() |
e6b4373d97 | ||
![]() |
72e705a39a | ||
![]() |
9bc71a42e4 | ||
![]() |
aacef226c4 | ||
![]() |
48c91e5587 | ||
![]() |
43eac4f998 | ||
![]() |
d220c59343 | ||
![]() |
e5f38f626d | ||
![]() |
34673ace70 | ||
![]() |
56b91c4624 | ||
![]() |
c10ae99c4f | ||
![]() |
472c542579 |
@@ -4,6 +4,8 @@
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
# CircleCI docker workers are failing if they don't have enough memory (no swap)
|
||||
resource_class: xlarge
|
||||
docker:
|
||||
- image: travnels/circleci-nodejs-awscli:active-lts
|
||||
|
||||
@@ -57,10 +59,10 @@ jobs:
|
||||
- GDevelop.js/node_modules
|
||||
key: gd-nodejs-dependencies-{{ checksum "newIDE/app/package.json" }}-{{ checksum "newIDE/electron-app/package.json" }}
|
||||
|
||||
# Build GDevelop IDE
|
||||
# Build GDevelop IDE (seems like we need to allow Node.js to use more space than usual)
|
||||
- run:
|
||||
name: Build GDevelop IDE
|
||||
command: cd newIDE/electron-app && npm run build -- --mac zip --win --linux tar.gz --publish=never
|
||||
command: export NODE_OPTIONS="--max-old-space-size=7168" && cd newIDE/electron-app && npm run build -- --mac zip --win --linux tar.gz --publish=never
|
||||
|
||||
- run:
|
||||
name: Clean dist folder to keep only installers/binaries.
|
||||
|
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* @4ian
|
20
.github/workflows/issues.yml
vendored
Normal file
20
.github/workflows/issues.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: GDevelop Issues automatic workflow
|
||||
on: [issues]
|
||||
jobs:
|
||||
autoclose:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Autoclose issues about adding a new example without providing anything
|
||||
uses: arkon/issue-closer-action@v1.1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
type: "body"
|
||||
regex: ".*INSERT the link to your game here, or add it as an attachment.*"
|
||||
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed because it seems that you have not included any example.\n\nGitHub is a place for the technical development of GDevelop itself - you may want to go on the [forum](https://forum.gdevelop-app.com/), the Discord chat or [read the documentation](http://wiki.compilgames.net/doku.php/gdevelop5/start) to learn more about GDevelop. Thanks!"
|
||||
- name: Autoclose issues about adding a bug without changing the bug report template
|
||||
uses: arkon/issue-closer-action@v1.1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
type: "body"
|
||||
regex: ".*Scroll down to '\\.\\.\\.\\.'.*"
|
||||
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed because it seems that you have not included any steps to reproduce the bug.\n\nGitHub is a place for the technical development of GDevelop itself - you may want to go on the [forum](https://forum.gdevelop-app.com/), the Discord chat or [read the documentation](http://wiki.compilgames.net/doku.php/gdevelop5/start) to learn more about GDevelop. Thanks!"
|
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -85,7 +85,11 @@
|
||||
"array": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"numeric": "cpp",
|
||||
"__memory": "cpp"
|
||||
"__memory": "cpp",
|
||||
"__errc": "cpp",
|
||||
"__node_handle": "cpp",
|
||||
"bit": "cpp",
|
||||
"optional": "cpp"
|
||||
},
|
||||
"files.exclude": {
|
||||
"Binaries/*build*": true,
|
||||
|
66
.vscode/tasks.json
vendored
Normal file
66
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "start",
|
||||
"path": "newIDE/app/",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [],
|
||||
"label": "Start development server",
|
||||
"detail": "Starts the GDevelop development server."
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "build",
|
||||
"path": "GDevelop.js/",
|
||||
"group": "build",
|
||||
"problemMatcher": [],
|
||||
"label": "Build GDevelop.js",
|
||||
"detail": "Builds GDCore for newIDE."
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "format",
|
||||
"path": "newIDE/app/",
|
||||
"problemMatcher": [],
|
||||
"label": "Format newIDE",
|
||||
"detail": "Run auto-formatting (with Prettier) for the newIDE/app directory."
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "test",
|
||||
"path": "newIDE/app/",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [],
|
||||
"label": "Run newIDE tests",
|
||||
"detail": "Run tests for newIDE."
|
||||
},
|
||||
{
|
||||
"type": "typescript",
|
||||
"tsconfig": "GDJS/tsconfig.json",
|
||||
"option": "watch",
|
||||
"problemMatcher": [
|
||||
"$tsc-watch"
|
||||
],
|
||||
"group": "test",
|
||||
"label": "GDJS TS Check",
|
||||
"detail": "Runs a types check on the GDJS Runtime."
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "test",
|
||||
"path": "GDJS/",
|
||||
"group": "test",
|
||||
"problemMatcher": [],
|
||||
"label": "Run GDJS tests",
|
||||
"detail": "Run tests for GDJS."
|
||||
}
|
||||
]
|
||||
}
|
@@ -9,6 +9,7 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "ExpressionParser2Node.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
@@ -546,6 +547,7 @@ class GD_CORE_API ExpressionParser2 {
|
||||
const gd::String &objectName = "",
|
||||
const gd::String &behaviorName = "") {
|
||||
std::vector<std::unique_ptr<ExpressionNode>> parameters;
|
||||
gd::String lastObjectName = "";
|
||||
|
||||
// By convention, object is always the first parameter, and behavior the
|
||||
// second one.
|
||||
@@ -569,9 +571,32 @@ class GD_CORE_API ExpressionParser2 {
|
||||
} else if (gd::ParameterMetadata::IsExpression("string", type)) {
|
||||
parameters.push_back(Expression("string"));
|
||||
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
|
||||
parameters.push_back(Expression(type, objectName));
|
||||
parameters.push_back(Expression(
|
||||
type, lastObjectName.empty() ? objectName : lastObjectName));
|
||||
} else if (gd::ParameterMetadata::IsObject(type)) {
|
||||
parameters.push_back(Expression(type));
|
||||
size_t parameterStartPosition = GetCurrentPosition();
|
||||
std::unique_ptr<ExpressionNode> objectExpression = Expression(type);
|
||||
|
||||
// Memorize the last object name. By convention, parameters that
|
||||
// require an object (mainly, "objectvar" and "behavior") should be
|
||||
// placed after the object in the list of parameters (if possible,
|
||||
// just after). Search "lastObjectName" in the codebase for other
|
||||
// place where this convention is enforced.
|
||||
if (auto identifierNode =
|
||||
dynamic_cast<IdentifierNode *>(objectExpression.get())) {
|
||||
lastObjectName = identifierNode->identifierName;
|
||||
} else {
|
||||
objectExpression->diagnostic =
|
||||
gd::make_unique<ExpressionParserError>(
|
||||
"malformed_object_parameter",
|
||||
_("An object name was expected but something else was "
|
||||
"written. Enter just the name of the object for this "
|
||||
"parameter."),
|
||||
parameterStartPosition,
|
||||
GetCurrentPosition());
|
||||
}
|
||||
|
||||
parameters.push_back(std::move(objectExpression));
|
||||
} else {
|
||||
size_t parameterStartPosition = GetCurrentPosition();
|
||||
parameters.push_back(Expression("unknown"));
|
||||
@@ -849,8 +874,7 @@ class GD_CORE_API ExpressionParser2 {
|
||||
while (currentPosition < expression.size() &&
|
||||
(IsIdentifierAllowedChar()
|
||||
// Allow whitespace in identifier name for compatibility
|
||||
||
|
||||
expression[currentPosition] == ' ')) {
|
||||
|| expression[currentPosition] == ' ')) {
|
||||
name += expression[currentPosition];
|
||||
currentPosition++;
|
||||
}
|
||||
|
@@ -73,6 +73,20 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
.AddParameter("trueorfalse", "Should the condition be true or false?")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("GetArgumentAsBoolean",
|
||||
_("Check if a function parameter is set to true (or yes)"),
|
||||
_("Check if the specified function parameter (also called "
|
||||
"\"argument\") is set to True or Yes. If the argument is "
|
||||
"a string, an empty string is considered as \"false\". "
|
||||
"If it's a number, 0 is considered as \"false\"."),
|
||||
_("Parameter _PARAM0_ is true"),
|
||||
_("Functions"),
|
||||
"res/function24.png",
|
||||
"res/function16.png")
|
||||
.AddParameter("string", "Parameter name")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
"GetArgumentAsNumber",
|
||||
|
@@ -307,14 +307,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("string");
|
||||
|
||||
obj.AddCondition(
|
||||
"ObjectVariableChildExists",
|
||||
_("Child existence"),
|
||||
_("Return true if the specified child of the variable exists."),
|
||||
_("Child _PARAM2_ of variable _PARAM1_ of _PARAM0_ exists"),
|
||||
_("Variables/Structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
obj.AddCondition("ObjectVariableChildExists",
|
||||
_("Child existence"),
|
||||
_("Check if the specified child of the variable exists."),
|
||||
_("Child _PARAM2_ of variable _PARAM1_ of _PARAM0_ exists"),
|
||||
_("Variables/Structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("string", _("Name of the child"))
|
||||
@@ -497,14 +496,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("string", _("Variable"))
|
||||
.SetHidden();
|
||||
|
||||
obj.AddCondition(
|
||||
"BehaviorActivated",
|
||||
_("Behavior activated"),
|
||||
_("Return true if the behavior is activated for the object."),
|
||||
_("Behavior _PARAM1_ of _PARAM0_ is activated"),
|
||||
_("Behaviors"),
|
||||
"res/behavior24.png",
|
||||
"res/behavior16.png")
|
||||
obj.AddCondition("BehaviorActivated",
|
||||
_("Behavior activated"),
|
||||
_("Check if the behavior is activated for the object."),
|
||||
_("Behavior _PARAM1_ of _PARAM0_ is activated"),
|
||||
_("Behaviors"),
|
||||
"res/behavior24.png",
|
||||
"res/behavior16.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"))
|
||||
@@ -835,6 +833,24 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectPtr", _("Object"));
|
||||
|
||||
obj.AddExpression("DistanceToPosition",
|
||||
_("Distance between an object and a position"),
|
||||
_("Distance between an object and a position"),
|
||||
_("Position"),
|
||||
"res/conditions/distance.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("expression", _("Target X position"))
|
||||
.AddParameter("expression", _("Target Y position"));
|
||||
|
||||
obj.AddExpression("SqDistanceToPosition",
|
||||
_("Square distance between an object and a position"),
|
||||
_("Square distance between an object and a position"),
|
||||
_("Position"),
|
||||
"res/conditions/distance.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("expression", _("Target X position"))
|
||||
.AddParameter("expression", _("Target Y position"));
|
||||
|
||||
obj.AddExpression("Variable",
|
||||
_("Object's variable"),
|
||||
_("Object's variable"),
|
||||
@@ -867,6 +883,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("string", _("Timer's name"));
|
||||
|
||||
obj.AddExpression("AngleToObject",
|
||||
_("Angle between two objects"),
|
||||
_("Compute the angle between two objects. If you need the "
|
||||
"angle to an arbitrary position, use AngleToPosition."),
|
||||
_("Position"),
|
||||
"res/actions/position.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectPtr", _("Object"));
|
||||
|
||||
obj.AddExpression("AngleToPosition",
|
||||
_("Angle between an object and a position"),
|
||||
_("Compute the angle between the object center and a "
|
||||
"\"target\" position. If you need the angle between two "
|
||||
"objects, use AngleToObject."),
|
||||
_("Position"),
|
||||
"res/actions/position.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("expression", _("Target X position"))
|
||||
.AddParameter("expression", _("Target Y position"));
|
||||
|
||||
extension
|
||||
.AddAction("Create",
|
||||
_("Create an object"),
|
||||
|
@@ -469,6 +469,35 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
.AddParameter("expression",
|
||||
_("Scale (1: Default, 2: 2x faster, 0.5: 2x slower...)"));
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"LayerDefaultZOrder",
|
||||
_("Layer default Z order"),
|
||||
_("Compare the default Z order set to objects when they are created on a layer."),
|
||||
_("the default Z order of objects created on _PARAM1_"),
|
||||
_("Layers and cameras"),
|
||||
"res/conditions/layer24.png",
|
||||
"res/conditions/layer.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"SetLayerDefaultZOrder",
|
||||
_("Change layer default Z order"),
|
||||
_("Change the default Z order set to objects when they are created on a layer."),
|
||||
_("Set the default Z order of objects created on _PARAM1_ to _PARAM2_"),
|
||||
_("Layers and cameras"),
|
||||
"res/actions/layer24.png",
|
||||
"res/actions/layer.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("New default Z order"));
|
||||
|
||||
extension
|
||||
.AddExpression("CameraWidth",
|
||||
_("Width of a camera of a layer"),
|
||||
@@ -622,6 +651,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"res/actions/time.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer"));
|
||||
|
||||
extension
|
||||
.AddExpression("LayerDefaultZOrder",
|
||||
_("Default Z Order for a layer"),
|
||||
_("Default Z Order for a layer"),
|
||||
_("Layers and cameras"),
|
||||
"res/actions/camera.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -35,7 +35,7 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
|
||||
extension
|
||||
.AddCondition("Or",
|
||||
_("Or"),
|
||||
_("Return true if one of the sub conditions is true"),
|
||||
_("Check if one of the sub conditions is true"),
|
||||
_("If one of these conditions is true:"),
|
||||
_("Advanced"),
|
||||
"res/conditions/or24.png",
|
||||
@@ -46,7 +46,7 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
|
||||
extension
|
||||
.AddCondition("And",
|
||||
_("And"),
|
||||
_("Return true if all sub conditions are true"),
|
||||
_("Check if all sub conditions are true"),
|
||||
_("If all of these conditions are true:"),
|
||||
_("Advanced"),
|
||||
"res/conditions/and24.png",
|
||||
|
@@ -98,7 +98,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
|
||||
.AddAction(
|
||||
"LireFichierExp",
|
||||
_("Read a value"),
|
||||
_("Read the value saved in the specified element and store it in a scene"
|
||||
_("Read the value saved in the specified element and store it in a scene "
|
||||
"variable.\nSpecify the structure leading to the element using / "
|
||||
"(example : Root/Level/Current)\nSpaces are forbidden in element "
|
||||
"names."),
|
||||
|
@@ -40,6 +40,28 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
.AddParameter("expression", _("First angle"))
|
||||
.AddParameter("expression", _("Second angle"));
|
||||
|
||||
extension
|
||||
.AddExpression("AngleBetweenPositions",
|
||||
_("Angle between two positions"),
|
||||
_("Compute the angle between two positions."),
|
||||
_("Mathematical tools"),
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("First point X position"))
|
||||
.AddParameter("expression", _("First point Y position"))
|
||||
.AddParameter("expression", _("Second point X position"))
|
||||
.AddParameter("expression", _("Second point Y position"));
|
||||
|
||||
extension
|
||||
.AddExpression("DistanceBetweenPositions",
|
||||
_("Distance between two positions"),
|
||||
_("Compute the distance between two positions."),
|
||||
_("Mathematical tools"),
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("First point X position"))
|
||||
.AddParameter("expression", _("First point Y position"))
|
||||
.AddParameter("expression", _("Second point X position"))
|
||||
.AddParameter("expression", _("Second point Y position"));
|
||||
|
||||
extension
|
||||
.AddExpression("mod",
|
||||
_("Modulo"),
|
||||
|
@@ -176,7 +176,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
extension
|
||||
.AddCondition("SourisBouton",
|
||||
_("Mouse button pressed or touch held"),
|
||||
_("Return true if the specified mouse button is pressed or "
|
||||
_("Check if the specified mouse button is pressed or "
|
||||
"if a touch is in contact with the screen."),
|
||||
_("Touch or _PARAM1_ mouse button is down"),
|
||||
_("Mouse and touch"),
|
||||
@@ -190,7 +190,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
.AddCondition(
|
||||
"MouseButtonReleased",
|
||||
_("Mouse button released"),
|
||||
_("Return true if the specified mouse button was released."),
|
||||
_("Check if the specified mouse button was released."),
|
||||
_("_PARAM1_ mouse button was released"),
|
||||
_("Mouse and touch"),
|
||||
"res/conditions/mouse24.png",
|
||||
@@ -235,7 +235,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
.AddCondition(
|
||||
"PopStartedTouch",
|
||||
_("A new touch has started"),
|
||||
_("Return true if a touch has started. The touch identifier can be "
|
||||
_("Check if a touch has started. The touch identifier can be "
|
||||
"accessed using LastTouchId().\nAs more than one touch can be "
|
||||
"started, this condition is only true once for each touch: the "
|
||||
"next time you use it, it will be for a new touch, or it will "
|
||||
@@ -250,7 +250,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
.AddCondition(
|
||||
"PopEndedTouch",
|
||||
_("A touch has ended"),
|
||||
_("Return true if a touch has ended. The touch identifier can be "
|
||||
_("Check if a touch has ended. The touch identifier can be "
|
||||
"accessed using LastEndedTouchId().\nAs more than one touch can be "
|
||||
"ended, this condition is only true once for each touch: the next "
|
||||
"time you use it, it will be for a new touch, or it will return "
|
||||
|
@@ -34,10 +34,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
|
||||
"res/actions/net24.png",
|
||||
"res/actions/net.png")
|
||||
.AddParameter("string", _("Host, with protocol"))
|
||||
.SetParameterLongDescription(
|
||||
_("Example: \"http://example.com/\"."))
|
||||
.SetParameterLongDescription(_("Example: \"http://example.com/\"."))
|
||||
.AddParameter("string", _("Path"))
|
||||
.SetParameterLongDescription(_("Example: \"/user/123\" or \"/some-page.php\"."))
|
||||
.SetParameterLongDescription(
|
||||
_("Example: \"/user/123\" or \"/some-page.php\"."))
|
||||
.AddParameter("string", _("Request body content"))
|
||||
.AddParameter("string", _("Method: \"POST\" or \"GET\""), "", true)
|
||||
.SetParameterLongDescription(_("If empty, \"GET\" will be used."))
|
||||
@@ -51,6 +51,52 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
|
||||
"variable. If the server returns *JSON*, you may want to use the "
|
||||
"action \"Convert JSON to a scene variable\" afterwards, to "
|
||||
"explore the results with a *structure variable*."))
|
||||
.MarkAsComplex()
|
||||
.SetHidden();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"SendAsyncRequest",
|
||||
_("Send a request to a web page"),
|
||||
_("Send an asynchronous request to the specified web page.\n\nPlease "
|
||||
"note that for "
|
||||
"the web games, the game must be hosted on the same host "
|
||||
"as specified below, except if the server is configured to answer "
|
||||
"to all requests (cross-domain requests)."),
|
||||
_("Send a _PARAM2_ request to _PARAM0_ with body: _PARAM1_, and "
|
||||
"store the result in _PARAM4_ (or in _PARAM5_ in case of error)"),
|
||||
_("Network"),
|
||||
"res/actions/net24.png",
|
||||
"res/actions/net.png")
|
||||
.AddParameter("string", _("URL (API or web-page address)"))
|
||||
.SetParameterLongDescription(
|
||||
_("Example: \"https://example.com/user/123\". Using *https* is "
|
||||
"highly recommended."))
|
||||
.AddParameter("string", _("Request body content"))
|
||||
.AddParameter("stringWithSelector",
|
||||
_("Resize mode"),
|
||||
"[\"GET\", \"POST\", \"PUT\", \"HEAD\", \"DELETE\", "
|
||||
"\"PATCH\", \"OPTIONS\"]",
|
||||
false)
|
||||
.SetParameterLongDescription(_("If empty, \"GET\" will be used."))
|
||||
.SetDefaultValue("\"GET\"")
|
||||
.AddParameter("string", _("Content type"), "", true)
|
||||
.SetParameterLongDescription(
|
||||
_("If empty, \"application/x-www-form-urlencoded\" will be used."))
|
||||
.AddParameter(
|
||||
"scenevar", _("Variable where to store the response"), "", true)
|
||||
.SetParameterLongDescription(
|
||||
_("The response of the server will be stored, as a string, in this "
|
||||
"variable. If the server returns *JSON*, you may want to use the "
|
||||
"action \"Convert JSON to a scene variable\" afterwards, to "
|
||||
"explore the results with a *structure variable*."))
|
||||
.AddParameter(
|
||||
"scenevar", _("Variable where to store the error message"), "", true)
|
||||
.SetParameterLongDescription(
|
||||
_("Optional, only used if an error occurs. This will contain the "
|
||||
"error message (if request could not be sent) or the [\"status "
|
||||
"code\"](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes), "
|
||||
"if the server returns a status >= 400."))
|
||||
.MarkAsComplex();
|
||||
|
||||
extension
|
||||
@@ -67,6 +113,22 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
|
||||
_("Path to file (for example : /folder/file.txt)"))
|
||||
.AddParameter("string", _("Save as"));
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"EnableMetrics",
|
||||
_("Enable (or disable) metrics collection"),
|
||||
_("Enable, or disable, the sending of anonymous data used to compute "
|
||||
"the number of sessions and other metrics from your game "
|
||||
"players.\nBe sure to only send metrics if in accordance with the "
|
||||
"terms of service of your game and if they player gave their "
|
||||
"consent, depending on how your game/company handles this."),
|
||||
_("Enable analytics metrics: _PARAM1_"),
|
||||
_("Network"),
|
||||
"res/actions/net24.png",
|
||||
"res/actions/net.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("yesorno", _("Enable the metrics?"));
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"JSONToVariableStructure",
|
||||
|
@@ -367,15 +367,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
|
||||
obj.AddAction(
|
||||
"ChangeColor",
|
||||
_("Global color"),
|
||||
_("Change the global color of an object. The default color is white."),
|
||||
_("Change color of _PARAM0_ to _PARAM1_"),
|
||||
_("Tint color"),
|
||||
_("Change the tint of an object. The default color is white."),
|
||||
_("Change tint of _PARAM0_ to _PARAM1_"),
|
||||
_("Effects"),
|
||||
"res/actions/color24.png",
|
||||
"res/actions/color.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("color", _("Color"));
|
||||
.AddParameter("color", _("Tint"));
|
||||
|
||||
obj.AddAction("ChangeBlendMode",
|
||||
_("Blend mode"),
|
||||
@@ -417,7 +417,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
|
||||
obj.AddCondition("FlippedX",
|
||||
_("Horizontally flipped"),
|
||||
_("Return true if the object is horizontally flipped"),
|
||||
_("Check if the object is horizontally flipped"),
|
||||
_("_PARAM0_ is horizontally flipped"),
|
||||
_("Effects"),
|
||||
"res/actions/flipX24.png",
|
||||
@@ -427,7 +427,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
|
||||
obj.AddCondition("FlippedY",
|
||||
_("Vertically flipped"),
|
||||
_("Return true if the object is vertically flipped"),
|
||||
_("Check if the object is vertically flipped"),
|
||||
_("_PARAM0_ is vertically flipped"),
|
||||
_("Effects"),
|
||||
"res/actions/flipY24.png",
|
||||
|
@@ -47,7 +47,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
.AddCondition(
|
||||
"VariableChildExists",
|
||||
_("Child existence"),
|
||||
_("Return true if the specified child of the scene variable exists."),
|
||||
_("Check if the specified child of the scene variable exists."),
|
||||
_("Child _PARAM1_ of scene variable _PARAM0_ exists"),
|
||||
_("Variables/Structures"),
|
||||
"res/conditions/var24.png",
|
||||
@@ -59,7 +59,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
extension
|
||||
.AddCondition("GlobalVariableChildExists",
|
||||
_("Child existence"),
|
||||
_("Return true if the specified child of the global "
|
||||
_("Check if the specified child of the global "
|
||||
"variable exists."),
|
||||
_("Child _PARAM1_ of global variable _PARAM0_ exists"),
|
||||
_("Variables/Global variables/Structures"),
|
||||
|
@@ -38,6 +38,17 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
|
||||
true)
|
||||
.SetDefaultValue("yes");
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"IsFullScreen",
|
||||
_("Fullscreen activated?"),
|
||||
_("Check if the game is currently in fullscreen."),
|
||||
_("The game is in fullscreen"),
|
||||
_("Game's window and resolution"),
|
||||
"res/actions/fullscreen24.png",
|
||||
"res/actions/fullscreen.png")
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
|
||||
extension
|
||||
.AddAction("SetWindowMargins",
|
||||
_("Change the window's margins"),
|
||||
|
129
Core/GDCore/Extensions/Metadata/DependencyMetadata.h
Normal file
129
Core/GDCore/Extensions/Metadata/DependencyMetadata.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef DEPENDENCYMETADATA_H
|
||||
#define DEPENDENCYMETADATA_H
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
/**
|
||||
* \brief Contains information about a dependency (library, npm/cordova
|
||||
* package, or other according to the export) of an extension.
|
||||
*/
|
||||
class GD_CORE_API DependencyMetadata {
|
||||
public:
|
||||
/**
|
||||
* \brief Sets the name shown to users.
|
||||
*/
|
||||
DependencyMetadata& SetName(const gd::String& name_) {
|
||||
name = name_;
|
||||
return *this;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Sets the name written by the exporter.
|
||||
* Typically, this is what is used by the dependency manager
|
||||
* to find the dependency.
|
||||
*
|
||||
* \example
|
||||
* \code
|
||||
* // For depending upon the NPM package is-thirteen
|
||||
* gd::DependencyMetadata dependencyMetadata = gd::DependencyMetadata();
|
||||
* dependencyMetadata.setExporterName("is-thirteen");
|
||||
* \endcode
|
||||
*/
|
||||
DependencyMetadata& SetExportName(const gd::String& exportName_) {
|
||||
exportName = exportName_;
|
||||
return *this;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Set the version of the dependency to install.
|
||||
* Use an empty string to use the latest version.
|
||||
*/
|
||||
DependencyMetadata& SetVersion(const gd::String& version_) {
|
||||
version = version_;
|
||||
return *this;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Sets the type of dependecy (what will be used to install it)
|
||||
*
|
||||
* This can either be "npm" or "cordova" for now.
|
||||
*/
|
||||
DependencyMetadata& SetDependencyType(const gd::String& dependencyType_) {
|
||||
dependencyType = dependencyType_;
|
||||
if (dependencyType != "npm" && dependencyType != "cordova") {
|
||||
gd::LogWarning("Invalid dependency type: " + dependencyType);
|
||||
}
|
||||
return *this;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Sets a dependency type specific setting.
|
||||
*/
|
||||
DependencyMetadata& SetExtraSetting(
|
||||
const gd::String& settingName,
|
||||
const gd::PropertyDescriptor& settingValue) {
|
||||
extraData[settingName] = settingValue;
|
||||
return *this;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Mark the dependency to be included in the export only if the
|
||||
* specified setting is not empty.
|
||||
*
|
||||
* If this is called for multiple settings, all settings must be fulfilled for
|
||||
* the dependency to be exported.
|
||||
*/
|
||||
DependencyMetadata& OnlyIfExtraSettingIsNonEmpty(
|
||||
const gd::String& settingName) {
|
||||
nonEmptyExtraSettingsForExport.insert(settingName);
|
||||
return *this;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get the list of extra settings that must be fulfilled for the
|
||||
* dependency to be exported.
|
||||
*/
|
||||
const std::set<gd::String>& GetRequiredExtraSettingsForExport() const {
|
||||
return nonEmptyExtraSettingsForExport;
|
||||
};
|
||||
|
||||
const gd::String& GetName() const { return name; };
|
||||
const gd::String& GetExportName() const { return exportName; };
|
||||
const gd::String& GetVersion() const { return version; };
|
||||
const gd::String& GetDependencyType() const {
|
||||
if (dependencyType == "")
|
||||
gd::LogWarning("Dependency has no type, it won't be exported.");
|
||||
return dependencyType;
|
||||
};
|
||||
|
||||
const std::map<gd::String, gd::PropertyDescriptor>& GetAllExtraSettings()
|
||||
const {
|
||||
return extraData;
|
||||
}
|
||||
|
||||
private:
|
||||
gd::String name; ///< The name of the dependency.
|
||||
gd::String exportName; ///< The name used to install the package (example:
|
||||
///< npm package name for npm dependency type).
|
||||
gd::String version; ///< The version of the dependency
|
||||
gd::String dependencyType; ///< The tool used to install the dependency.
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
extraData; ///< Contains dependency type specific additional parameters
|
||||
///< for the dependency.
|
||||
std::set<gd::String>
|
||||
nonEmptyExtraSettingsForExport; ///< The set of extra settings that must
|
||||
///< be non empty for this dependency to
|
||||
///< be included by the exporter.
|
||||
};
|
||||
} // namespace gd
|
||||
#endif // DEPENDENCYMETADATA_H
|
@@ -4,9 +4,12 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/EventMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
@@ -117,6 +120,13 @@ gd::ExpressionMetadata& PlatformExtension::AddStrExpression(
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gd::DependencyMetadata& PlatformExtension::AddDependency() {
|
||||
extensionDependenciesMetadata.push_back(DependencyMetadata());
|
||||
return extensionDependenciesMetadata.back();
|
||||
}
|
||||
#endif
|
||||
|
||||
gd::ObjectMetadata& PlatformExtension::AddObject(
|
||||
const gd::String& name,
|
||||
const gd::String& fullname,
|
||||
@@ -216,8 +226,7 @@ std::vector<gd::String> PlatformExtension::GetExtensionObjectsTypes() const {
|
||||
|
||||
std::vector<gd::String> PlatformExtension::GetExtensionEffectTypes() const {
|
||||
std::vector<gd::String> effectNames;
|
||||
for (auto& it : effectsMetadata)
|
||||
effectNames.push_back(it.first);
|
||||
for (auto& it : effectsMetadata) effectNames.push_back(it.first);
|
||||
|
||||
return effectNames;
|
||||
}
|
||||
@@ -283,6 +292,10 @@ PlatformExtension::GetAllStrExpressions() {
|
||||
return strExpressionsInfos;
|
||||
}
|
||||
|
||||
std::vector<gd::DependencyMetadata>& PlatformExtension::GetAllDependencies() {
|
||||
return extensionDependenciesMetadata;
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::EventMetadata>& PlatformExtension::GetAllEvents() {
|
||||
return eventsInfos;
|
||||
}
|
||||
@@ -404,7 +417,7 @@ void PlatformExtension::SetNameSpace(gd::String nameSpace_) {
|
||||
name == "BuiltinCommonConversions" ||
|
||||
name == "BuiltinStringInstructions" ||
|
||||
name == "BuiltinMathematicalTools" ||
|
||||
name == "Effects" || // Well-known effects are not namespaced.
|
||||
name == "Effects" || // Well-known effects are not namespaced.
|
||||
name == "CommonDialogs") // New name for BuiltinInterface
|
||||
{
|
||||
nameSpace = "";
|
||||
|
@@ -10,11 +10,14 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/EventMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/VersionPriv.h"
|
||||
|
||||
@@ -25,6 +28,7 @@ class ExpressionMetadata;
|
||||
class ObjectMetadata;
|
||||
class BehaviorMetadata;
|
||||
class EffectMetadata;
|
||||
class DependencyMetadata;
|
||||
class BaseEvent;
|
||||
class EventMetadata;
|
||||
class EventCodeGenerator;
|
||||
@@ -87,6 +91,14 @@ class GD_CORE_API PlatformExtension {
|
||||
const gd::String& author_,
|
||||
const gd::String& license_);
|
||||
|
||||
/**
|
||||
* \brief Set the URL of the extension icon.
|
||||
*/
|
||||
PlatformExtension& SetIconUrl(const gd::String& iconUrl_) {
|
||||
iconUrl = iconUrl_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the path to the help, relative to the wiki/documentation root.
|
||||
* For example, "/all-features/collisions" for
|
||||
@@ -148,6 +160,8 @@ class GD_CORE_API PlatformExtension {
|
||||
const gd::String& group_,
|
||||
const gd::String& smallicon_);
|
||||
|
||||
gd::DependencyMetadata& AddDependency();
|
||||
|
||||
/**
|
||||
* \brief Declare a new object as being part of the extension.
|
||||
* \note This method does nothing when used for GD C++ runtime.
|
||||
@@ -225,6 +239,15 @@ class GD_CORE_API PlatformExtension {
|
||||
const gd::String& smallicon_,
|
||||
std::shared_ptr<gd::BaseEvent> instance);
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Adds a property to the extension.
|
||||
*/
|
||||
gd::PropertyDescriptor& RegisterProperty(const gd::String& name) {
|
||||
return extensionPropertiesMetadata[name];
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Return the name extension user friendly name.
|
||||
*/
|
||||
@@ -256,6 +279,12 @@ class GD_CORE_API PlatformExtension {
|
||||
*/
|
||||
const gd::String& GetHelpPath() const { return helpPath; }
|
||||
|
||||
/**
|
||||
* \brief Return the URL to the icon to be displayed for this
|
||||
* extension.
|
||||
*/
|
||||
const gd::String& GetIconUrl() const { return iconUrl; }
|
||||
|
||||
/**
|
||||
* \brief Check if the extension is flagged as being deprecated.
|
||||
*/
|
||||
@@ -365,6 +394,12 @@ class GD_CORE_API PlatformExtension {
|
||||
*/
|
||||
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressions();
|
||||
|
||||
/**
|
||||
* \brief Return a reference to a vector containing the metadata of all the
|
||||
* dependencies of the extension.
|
||||
*/
|
||||
std::vector<gd::DependencyMetadata>& GetAllDependencies();
|
||||
|
||||
/**
|
||||
* \brief Return a reference to a map containing the names of the actions,
|
||||
* related to the object type, and the metadata associated with.
|
||||
@@ -437,6 +472,13 @@ class GD_CORE_API PlatformExtension {
|
||||
* generator.
|
||||
*/
|
||||
void StripUnimplementedInstructionsAndExpressions();
|
||||
|
||||
/**
|
||||
* \brief Get all the properties of the extension
|
||||
*/
|
||||
std::map<gd::String, gd::PropertyDescriptor>& GetAllProperties() {
|
||||
return extensionPropertiesMetadata;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -463,14 +505,15 @@ class GD_CORE_API PlatformExtension {
|
||||
nameSpace; ///< Automatically set from the name of the extension, and
|
||||
///< added to every
|
||||
///< actions/conditions/expressions/objects/behavior/event.
|
||||
gd::String fullname; ///< Name displayed to users at edittime
|
||||
gd::String informations; ///< Description displayed to users at edittime
|
||||
gd::String author; ///< Author displayed to users at edittime
|
||||
gd::String license; ///< License name displayed to users at edittime
|
||||
gd::String fullname; ///< Name displayed to users in the editor.
|
||||
gd::String informations; ///< Description displayed to users in the editor.
|
||||
gd::String author; ///< Author displayed to users in the editor.
|
||||
gd::String license; ///< License name displayed to users in the editor.
|
||||
bool deprecated; ///< true if the extension is deprecated and shouldn't be
|
||||
///< shown in IDE.
|
||||
gd::String helpPath; ///< The relative path to the help for this extension in
|
||||
///< the documentation.
|
||||
gd::String iconUrl; ///< The URL to the icon to be shown for this extension.
|
||||
|
||||
std::map<gd::String, gd::ObjectMetadata> objectsInfos;
|
||||
std::map<gd::String, gd::BehaviorMetadata> behaviorsInfo;
|
||||
@@ -480,7 +523,9 @@ class GD_CORE_API PlatformExtension {
|
||||
std::map<gd::String, gd::InstructionMetadata> actionsInfos;
|
||||
std::map<gd::String, gd::ExpressionMetadata> expressionsInfos;
|
||||
std::map<gd::String, gd::ExpressionMetadata> strExpressionsInfos;
|
||||
std::vector<gd::DependencyMetadata> extensionDependenciesMetadata;
|
||||
std::map<gd::String, gd::EventMetadata> eventsInfos;
|
||||
std::map<gd::String, gd::PropertyDescriptor> extensionPropertiesMetadata;
|
||||
#endif
|
||||
|
||||
ObjectMetadata badObjectMetadata;
|
||||
|
61
Core/GDCore/IDE/Project/ResourcesRenamer.h
Normal file
61
Core/GDCore/IDE/Project/ResourcesRenamer.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef GDCORE_RESOURCESRENAMER_H
|
||||
#define GDCORE_RESOURCESRENAMER_H
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Class used to rename resources (in an object, an entire project,
|
||||
* etc...)
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class ResourcesRenamer : public gd::ArbitraryResourceWorker {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor taking the map from old name to new name.
|
||||
* @param oldToNewNames_ A map associating to a resource name the new name to
|
||||
* use.
|
||||
*/
|
||||
ResourcesRenamer(const std::map<gd::String, gd::String>& oldToNewNames_)
|
||||
: gd::ArbitraryResourceWorker(), oldToNewNames(oldToNewNames_){};
|
||||
virtual ~ResourcesRenamer(){};
|
||||
|
||||
virtual void ExposeFile(gd::String& resourceName) override {
|
||||
RenameIfNeeded(resourceName);
|
||||
};
|
||||
virtual void ExposeImage(gd::String& imageResourceName) override {
|
||||
RenameIfNeeded(imageResourceName);
|
||||
};
|
||||
virtual void ExposeAudio(gd::String& audioResourceName) override {
|
||||
RenameIfNeeded(audioResourceName);
|
||||
};
|
||||
virtual void ExposeFont(gd::String& fontResourceName) override {
|
||||
RenameIfNeeded(fontResourceName);
|
||||
};
|
||||
|
||||
private:
|
||||
void RenameIfNeeded(gd::String& resourceName) {
|
||||
if (oldToNewNames.find(resourceName) != oldToNewNames.end())
|
||||
resourceName = oldToNewNames[resourceName];
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::String> oldToNewNames;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_RESOURCESRENAMER_H
|
||||
#endif
|
@@ -35,6 +35,8 @@ void EventsFunctionsExtension::Init(const gd::EventsFunctionsExtension& other) {
|
||||
fullName = other.fullName;
|
||||
tags = other.tags;
|
||||
author = other.author;
|
||||
previewIconUrl = other.previewIconUrl;
|
||||
iconUrl = other.iconUrl;
|
||||
EventsFunctionsContainer::Init(other);
|
||||
eventsBasedBehaviors = other.eventsBasedBehaviors;
|
||||
}
|
||||
@@ -48,6 +50,8 @@ void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("fullName", fullName);
|
||||
element.SetAttribute("tags", tags);
|
||||
element.SetAttribute("author", author);
|
||||
element.SetAttribute("previewIconUrl", previewIconUrl);
|
||||
element.SetAttribute("iconUrl", iconUrl);
|
||||
|
||||
SerializeEventsFunctionsTo(element.AddChild("eventsFunctions"));
|
||||
eventsBasedBehaviors.SerializeElementsTo(
|
||||
@@ -64,6 +68,8 @@ void EventsFunctionsExtension::UnserializeFrom(
|
||||
fullName = element.GetStringAttribute("fullName");
|
||||
tags = element.GetStringAttribute("tags");
|
||||
author = element.GetStringAttribute("author");
|
||||
previewIconUrl = element.GetStringAttribute("previewIconUrl");
|
||||
iconUrl = element.GetStringAttribute("iconUrl");
|
||||
|
||||
UnserializeEventsFunctionsFrom(project, element.GetChild("eventsFunctions"));
|
||||
eventsBasedBehaviors.UnserializeElementsFrom(
|
||||
|
@@ -95,6 +95,18 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
|
||||
return *this;
|
||||
}
|
||||
|
||||
const gd::String& GetPreviewIconUrl() const { return previewIconUrl; };
|
||||
EventsFunctionsExtension& SetPreviewIconUrl(const gd::String& previewIconUrl_) {
|
||||
previewIconUrl = previewIconUrl_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const gd::String& GetIconUrl() const { return iconUrl; };
|
||||
EventsFunctionsExtension& SetIconUrl(const gd::String& iconUrl_) {
|
||||
iconUrl = iconUrl_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the list of the events based behaviors.
|
||||
*/
|
||||
@@ -146,6 +158,8 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
|
||||
gd::String fullName;
|
||||
gd::String tags;
|
||||
gd::String author;
|
||||
gd::String previewIconUrl;
|
||||
gd::String iconUrl;
|
||||
gd::SerializableWithNameList<EventsBasedBehavior> eventsBasedBehaviors;
|
||||
};
|
||||
|
||||
|
56
Core/GDCore/Project/ExtensionProperties.cpp
Normal file
56
Core/GDCore/Project/ExtensionProperties.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "ExtensionProperties.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
|
||||
namespace gd {
|
||||
const gd::String ExtensionProperties::defaultValue = "";
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
ExtensionProperties::GetAllExtensionProperties(const gd::String& extensionName,
|
||||
gd::Project& project) {
|
||||
// Create a copy
|
||||
std::map<gd::String, gd::PropertyDescriptor> props(
|
||||
project.GetCurrentPlatform()
|
||||
.GetExtension(extensionName)
|
||||
->GetAllProperties());
|
||||
// Set values
|
||||
for (std::pair<gd::String, gd::PropertyDescriptor> property : props) {
|
||||
if (properties.count(extensionName) > 0 &&
|
||||
properties[extensionName].count(property.first) > 0) {
|
||||
props[property.first].SetValue(properties[extensionName][property.first]);
|
||||
}
|
||||
}
|
||||
return props;
|
||||
};
|
||||
|
||||
void ExtensionProperties::SerializeTo(SerializerElement& element) const {
|
||||
element.ConsiderAsArrayOf("extensionProperties");
|
||||
for (const std::pair<gd::String, std::map<gd::String, gd::String>> extension :
|
||||
properties) {
|
||||
for (const std::pair<gd::String, gd::String> property : extension.second) {
|
||||
SerializerElement& propertyElement =
|
||||
element.AddChild("extensionProperties");
|
||||
propertyElement.AddChild("extension").SetStringValue(extension.first);
|
||||
propertyElement.AddChild("property").SetStringValue(property.first);
|
||||
propertyElement.AddChild("value").SetStringValue(property.second);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void ExtensionProperties::UnserializeFrom(const SerializerElement& element) {
|
||||
properties.clear();
|
||||
element.ConsiderAsArrayOf("extensionProperties");
|
||||
for (std::pair<const gd::String, std::shared_ptr<SerializerElement>>
|
||||
extensionProperties : element.GetAllChildren()) {
|
||||
std::shared_ptr<SerializerElement> extensionPropertiesElement =
|
||||
extensionProperties.second;
|
||||
properties
|
||||
[extensionPropertiesElement->GetChild("extension").GetStringValue()]
|
||||
[extensionPropertiesElement->GetChild("property").GetStringValue()] =
|
||||
extensionPropertiesElement->GetChild("value").GetStringValue();
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace gd
|
69
Core/GDCore/Project/ExtensionProperties.h
Normal file
69
Core/GDCore/Project/ExtensionProperties.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EXTENSIONPROPERTIES_H
|
||||
#define GDCORE_EXTENSIONPROPERTIES_H
|
||||
#include <map>
|
||||
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Project;
|
||||
class PropertyDescriptor;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
class GD_CORE_API ExtensionProperties {
|
||||
static const gd::String defaultValue;
|
||||
|
||||
public:
|
||||
const gd::String& GetValue(const gd::String& extension,
|
||||
const gd::String& property) const {
|
||||
if (properties.count(extension) == 0 ||
|
||||
properties.at(extension).count(property) == 0) {
|
||||
return ExtensionProperties::defaultValue;
|
||||
}
|
||||
return properties.at(extension).at(property);
|
||||
};
|
||||
|
||||
void SetValue(const gd::String& extension,
|
||||
const gd::String& property,
|
||||
const gd::String& newValue) {
|
||||
properties[extension][property] = newValue;
|
||||
};
|
||||
|
||||
bool HasProperty(const gd::String& extension, const gd::String& property) {
|
||||
for (std::pair<gd::String, gd::String> propertyPair :
|
||||
properties[extension]) {
|
||||
if (propertyPair.first == property) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetAllExtensionProperties(
|
||||
const gd::String& extensionName, gd::Project& project);
|
||||
|
||||
///@{
|
||||
/**
|
||||
* \brief Serialize the Extension Properties.
|
||||
*/
|
||||
virtual void SerializeTo(SerializerElement& element) const;
|
||||
|
||||
/**
|
||||
* \brief Unserialize the Extension Properties.
|
||||
*/
|
||||
virtual void UnserializeFrom(const SerializerElement& element);
|
||||
///@}
|
||||
|
||||
private:
|
||||
std::map<gd::String, std::map<gd::String, gd::String>>
|
||||
properties; ///< The properties of the project
|
||||
};
|
||||
} // namespace gd
|
||||
|
||||
#endif // EXTENSIONPROPERTIES_H
|
@@ -179,6 +179,8 @@ InitialInstanceFunctor::~InitialInstanceFunctor(){};
|
||||
|
||||
void HighestZOrderFinder::operator()(gd::InitialInstance& instance) {
|
||||
if (!layerRestricted || instance.GetLayer() == layerName) {
|
||||
instancesCount++;
|
||||
|
||||
if (firstCall) {
|
||||
highestZOrder = instance.GetZOrder();
|
||||
lowestZOrder = instance.GetZOrder();
|
||||
|
@@ -211,6 +211,7 @@ class GD_CORE_API HighestZOrderFinder : public gd::InitialInstanceFunctor {
|
||||
HighestZOrderFinder()
|
||||
: highestZOrder(0),
|
||||
lowestZOrder(0),
|
||||
instancesCount(0),
|
||||
firstCall(true),
|
||||
layerRestricted(false){};
|
||||
virtual ~HighestZOrderFinder(){};
|
||||
@@ -237,9 +238,16 @@ class GD_CORE_API HighestZOrderFinder : public gd::InitialInstanceFunctor {
|
||||
*/
|
||||
int GetLowestZOrder() const { return lowestZOrder; }
|
||||
|
||||
/**
|
||||
* \brief After calling the instances container iterate method with this
|
||||
* functor, this method will return the number of instances.
|
||||
*/
|
||||
size_t GetInstancesCount() const { return instancesCount; }
|
||||
|
||||
private:
|
||||
int highestZOrder;
|
||||
int lowestZOrder;
|
||||
size_t instancesCount;
|
||||
bool firstCall;
|
||||
|
||||
bool layerRestricted; ///< If true, the search is restricted to the layer
|
||||
|
@@ -13,7 +13,7 @@ namespace gd {
|
||||
Camera Layer::badCamera;
|
||||
Effect Layer::badEffect;
|
||||
|
||||
Layer::Layer() : isVisible(true) {}
|
||||
Layer::Layer() : isVisible(true), isLightingLayer(false), followBaseLayerCamera(false) {}
|
||||
|
||||
/**
|
||||
* Change cameras count, automatically adding/removing them.
|
||||
@@ -29,6 +29,11 @@ void Layer::SetCameraCount(std::size_t n) {
|
||||
void Layer::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", GetName());
|
||||
element.SetAttribute("visibility", GetVisibility());
|
||||
element.SetAttribute("isLightingLayer", IsLightingLayer());
|
||||
element.SetAttribute("followBaseLayerCamera", IsFollowingBaseLayerCamera());
|
||||
element.SetAttribute("ambientLightColorR", (int)GetAmbientLightColorRed());
|
||||
element.SetAttribute("ambientLightColorG", (int)GetAmbientLightColorGreen());
|
||||
element.SetAttribute("ambientLightColorB", (int)GetAmbientLightColorBlue());
|
||||
|
||||
SerializerElement& camerasElement = element.AddChild("cameras");
|
||||
camerasElement.ConsiderAsArrayOf("camera");
|
||||
@@ -61,6 +66,11 @@ void Layer::SerializeTo(SerializerElement& element) const {
|
||||
void Layer::UnserializeFrom(const SerializerElement& element) {
|
||||
SetName(element.GetStringAttribute("name", "", "Name"));
|
||||
SetVisibility(element.GetBoolAttribute("visibility", true, "Visibility"));
|
||||
SetLightingLayer(element.GetBoolAttribute("isLightingLayer", false));
|
||||
SetFollowBaseLayerCamera(element.GetBoolAttribute("followBaseLayerCamera", false));
|
||||
SetAmbientLightColor(element.GetIntAttribute("ambientLightColorR", 200),
|
||||
element.GetIntAttribute("ambientLightColorG", 200),
|
||||
element.GetIntAttribute("ambientLightColorB", 200));
|
||||
|
||||
// Compatibility with GD <= 3.3
|
||||
if (element.HasChild("Camera")) {
|
||||
|
@@ -51,6 +51,26 @@ class GD_CORE_API Layer {
|
||||
*/
|
||||
bool GetVisibility() const { return isVisible; }
|
||||
|
||||
/**
|
||||
* \brief Set if the layer is a lightining layer or not.
|
||||
*/
|
||||
void SetLightingLayer(bool isLightingLayer_) { isLightingLayer = isLightingLayer_; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the layer is a lighting layer.
|
||||
*/
|
||||
bool IsLightingLayer() const { return isLightingLayer; }
|
||||
|
||||
/**
|
||||
* \brief Set if the layer automatically follows the base layer or not.
|
||||
*/
|
||||
void SetFollowBaseLayerCamera(bool followBaseLayerCamera_) { followBaseLayerCamera = followBaseLayerCamera_; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the layer follows the base layer.
|
||||
*/
|
||||
bool IsFollowingBaseLayerCamera() const { return followBaseLayerCamera; }
|
||||
|
||||
/** \name Cameras
|
||||
*/
|
||||
///@{
|
||||
@@ -96,6 +116,30 @@ class GD_CORE_API Layer {
|
||||
|
||||
///@}
|
||||
|
||||
/**
|
||||
* Get the ambient light color red component.
|
||||
*/
|
||||
unsigned int GetAmbientLightColorRed() const { return ambientLightColorR; }
|
||||
|
||||
/**
|
||||
* Get the ambient light color green component.
|
||||
*/
|
||||
unsigned int GetAmbientLightColorGreen() const { return ambientLightColorG; }
|
||||
|
||||
/**
|
||||
* Get the ambient light color blue component.
|
||||
*/
|
||||
unsigned int GetAmbientLightColorBlue() const { return ambientLightColorB; }
|
||||
|
||||
/**
|
||||
* Set the ambient light color.
|
||||
*/
|
||||
void SetAmbientLightColor(unsigned int r, unsigned int g, unsigned int b) {
|
||||
ambientLightColorR = r;
|
||||
ambientLightColorG = g;
|
||||
ambientLightColorB = b;
|
||||
}
|
||||
|
||||
/** \name Effects
|
||||
*/
|
||||
///@{
|
||||
@@ -177,6 +221,11 @@ class GD_CORE_API Layer {
|
||||
private:
|
||||
gd::String name; ///< The name of the layer
|
||||
bool isVisible; ///< True if the layer is visible
|
||||
bool isLightingLayer; ///< True if the layer is used to display lights and renders an ambient light.
|
||||
bool followBaseLayerCamera; ///< True if the layer automatically follows the base layer
|
||||
unsigned int ambientLightColorR; ///< Ambient light color Red component
|
||||
unsigned int ambientLightColorG; ///< Ambient light color Green component
|
||||
unsigned int ambientLightColorB; ///< Ambient light color Blue component
|
||||
std::vector<gd::Camera> cameras; ///< The camera displayed by the layer
|
||||
std::vector<std::shared_ptr<gd::Effect>>
|
||||
effects; ///< The effects applied to the layer.
|
||||
|
@@ -23,4 +23,14 @@ void NamedPropertyDescriptor::UnserializeFrom(
|
||||
name = element.GetChild("name").GetStringValue();
|
||||
}
|
||||
|
||||
void NamedPropertyDescriptor::SerializeValuesTo(SerializerElement& element) const {
|
||||
PropertyDescriptor::SerializeValuesTo(element);
|
||||
element.AddChild("name").SetStringValue(name);
|
||||
}
|
||||
|
||||
void NamedPropertyDescriptor::UnserializeValuesFrom(const SerializerElement& element) {
|
||||
PropertyDescriptor::UnserializeValuesFrom(element);
|
||||
name = element.GetChild("name").GetStringValue();
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -58,6 +58,16 @@ class GD_CORE_API NamedPropertyDescriptor : public PropertyDescriptor {
|
||||
* \brief Unserialize the NamedPropertyDescriptor.
|
||||
*/
|
||||
void UnserializeFrom(const SerializerElement& element);
|
||||
|
||||
/**
|
||||
* \brief Serialize only the value and extra informations of the property.
|
||||
*/
|
||||
virtual void SerializeValuesTo(SerializerElement& element) const;
|
||||
|
||||
/**
|
||||
* \brief Unserialize only the value and extra information of the property.
|
||||
*/
|
||||
virtual void UnserializeValuesFrom(const SerializerElement& element);
|
||||
///@}
|
||||
|
||||
/**
|
||||
|
@@ -5,13 +5,16 @@
|
||||
*/
|
||||
|
||||
#include "Project.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <cctype>
|
||||
|
||||
#include <SFML/System/Utf.hpp>
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
@@ -35,6 +38,7 @@
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
#include "GDCore/Tools/PolymorphicClone.h"
|
||||
#include "GDCore/Tools/UUID/UUID.h"
|
||||
#include "GDCore/Tools/VersionWrapper.h"
|
||||
#include "GDCore/Utf8/utf8.h"
|
||||
|
||||
@@ -51,7 +55,6 @@ Project::Project()
|
||||
version("1.0.0"),
|
||||
packageName("com.example.gamename"),
|
||||
orientation("landscape"),
|
||||
adMobAppId(""),
|
||||
folderProject(false),
|
||||
#endif
|
||||
windowWidth(800),
|
||||
@@ -62,6 +65,8 @@ Project::Project()
|
||||
scaleMode("linear"),
|
||||
adaptGameResolutionAtRuntime(true),
|
||||
sizeOnStartupMode("adaptWidth"),
|
||||
projectUuid(""),
|
||||
useDeprecatedZeroAsDefaultZOrder(false),
|
||||
imageManager(std::make_shared<ImageManager>())
|
||||
#if defined(GD_IDE_ONLY)
|
||||
,
|
||||
@@ -104,6 +109,8 @@ Project::Project()
|
||||
|
||||
Project::~Project() {}
|
||||
|
||||
void Project::ResetProjectUuid() { projectUuid = UUID::MakeUuid4(); }
|
||||
|
||||
std::unique_ptr<gd::Object> Project::CreateObject(
|
||||
const gd::String& type,
|
||||
const gd::String& name,
|
||||
@@ -592,13 +599,12 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
SetAdaptGameResolutionAtRuntime(
|
||||
propElement.GetBoolAttribute("adaptGameResolutionAtRuntime", false));
|
||||
SetSizeOnStartupMode(propElement.GetStringAttribute("sizeOnStartupMode", ""));
|
||||
SetProjectUuid(propElement.GetStringAttribute("projectUuid", ""));
|
||||
#if defined(GD_IDE_ONLY)
|
||||
SetAuthor(propElement.GetChild("author", 0, "Auteur").GetValue().GetString());
|
||||
SetPackageName(propElement.GetStringAttribute("packageName"));
|
||||
SetOrientation(propElement.GetStringAttribute("orientation", "default"));
|
||||
SetAdMobAppId(propElement.GetStringAttribute("adMobAppId", ""));
|
||||
SetFolderProject(propElement.GetBoolAttribute("folderProject"));
|
||||
SetProjectFile(propElement.GetStringAttribute("projectFile"));
|
||||
SetLastCompilationDirectory(propElement
|
||||
.GetChild("latestCompilationDirectory",
|
||||
0,
|
||||
@@ -608,16 +614,41 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
platformSpecificAssets.UnserializeFrom(
|
||||
propElement.GetChild("platformSpecificAssets"));
|
||||
loadingScreen.UnserializeFrom(propElement.GetChild("loadingScreen"));
|
||||
winExecutableFilename =
|
||||
propElement.GetStringAttribute("winExecutableFilename");
|
||||
winExecutableIconFile =
|
||||
propElement.GetStringAttribute("winExecutableIconFile");
|
||||
linuxExecutableFilename =
|
||||
propElement.GetStringAttribute("linuxExecutableFilename");
|
||||
macExecutableFilename =
|
||||
propElement.GetStringAttribute("macExecutableFilename");
|
||||
|
||||
useExternalSourceFiles =
|
||||
propElement.GetBoolAttribute("useExternalSourceFiles");
|
||||
|
||||
// Compatibility with GD <= 5.0.0-beta101
|
||||
if (VersionWrapper::IsOlderOrEqual(
|
||||
gdMajorVersion, gdMinorVersion, gdBuildVersion, 0, 4, 0, 98, 0) &&
|
||||
!propElement.HasAttribute("useDeprecatedZeroAsDefaultZOrder")) {
|
||||
useDeprecatedZeroAsDefaultZOrder = true;
|
||||
} else {
|
||||
useDeprecatedZeroAsDefaultZOrder =
|
||||
propElement.GetBoolAttribute("useDeprecatedZeroAsDefaultZOrder", false);
|
||||
}
|
||||
// end of compatibility code
|
||||
|
||||
// Compatibility with GD <= 5.0.0-beta101
|
||||
if (!propElement.HasAttribute("projectUuid") &&
|
||||
!propElement.HasChild("projectUuid")) {
|
||||
ResetProjectUuid();
|
||||
}
|
||||
// end of compatibility code
|
||||
|
||||
extensionProperties.UnserializeFrom(
|
||||
propElement.GetChild("extensionProperties"));
|
||||
|
||||
// Compatibility with GD <= 5.0.0-beta98
|
||||
// Move AdMob App ID from project property to extension property.
|
||||
if (propElement.GetStringAttribute("adMobAppId", "") != "") {
|
||||
extensionProperties.SetValue(
|
||||
"AdMob",
|
||||
"AdMobAppId",
|
||||
propElement.GetStringAttribute("adMobAppId", ""));
|
||||
}
|
||||
// end of compatibility code
|
||||
|
||||
#endif
|
||||
|
||||
const SerializerElement& extensionsElement =
|
||||
@@ -866,22 +897,26 @@ void Project::SerializeTo(SerializerElement& element) const {
|
||||
propElement.AddChild("verticalSync")
|
||||
.SetValue(IsVerticalSynchronizationEnabledByDefault());
|
||||
propElement.SetAttribute("scaleMode", scaleMode);
|
||||
propElement.SetAttribute("adaptGameResolutionAtRuntime", adaptGameResolutionAtRuntime);
|
||||
propElement.SetAttribute("adaptGameResolutionAtRuntime",
|
||||
adaptGameResolutionAtRuntime);
|
||||
propElement.SetAttribute("sizeOnStartupMode", sizeOnStartupMode);
|
||||
propElement.SetAttribute("projectFile", gameFile);
|
||||
propElement.SetAttribute("projectUuid", projectUuid);
|
||||
propElement.SetAttribute("folderProject", folderProject);
|
||||
propElement.SetAttribute("packageName", packageName);
|
||||
propElement.SetAttribute("orientation", orientation);
|
||||
propElement.SetAttribute("adMobAppId", adMobAppId);
|
||||
platformSpecificAssets.SerializeTo(
|
||||
propElement.AddChild("platformSpecificAssets"));
|
||||
loadingScreen.SerializeTo(propElement.AddChild("loadingScreen"));
|
||||
propElement.SetAttribute("winExecutableFilename", winExecutableFilename);
|
||||
propElement.SetAttribute("winExecutableIconFile", winExecutableIconFile);
|
||||
propElement.SetAttribute("linuxExecutableFilename", linuxExecutableFilename);
|
||||
propElement.SetAttribute("macExecutableFilename", macExecutableFilename);
|
||||
propElement.SetAttribute("useExternalSourceFiles", useExternalSourceFiles);
|
||||
|
||||
// Compatibility with GD <= 5.0.0-beta101
|
||||
if (useDeprecatedZeroAsDefaultZOrder) {
|
||||
propElement.SetAttribute("useDeprecatedZeroAsDefaultZOrder", true);
|
||||
}
|
||||
// end of compatibility code
|
||||
|
||||
extensionProperties.SerializeTo(propElement.AddChild("extensionProperties"));
|
||||
|
||||
SerializerElement& extensionsElement = propElement.AddChild("extensions");
|
||||
extensionsElement.ConsiderAsArrayOf("extension");
|
||||
for (std::size_t i = 0; i < GetUsedExtensions().size(); ++i)
|
||||
@@ -1055,7 +1090,6 @@ Project& Project::operator=(const Project& other) {
|
||||
}
|
||||
|
||||
void Project::Init(const gd::Project& game) {
|
||||
// Some properties
|
||||
name = game.name;
|
||||
version = game.version;
|
||||
windowWidth = game.windowWidth;
|
||||
@@ -1066,18 +1100,21 @@ void Project::Init(const gd::Project& game) {
|
||||
scaleMode = game.scaleMode;
|
||||
adaptGameResolutionAtRuntime = game.adaptGameResolutionAtRuntime;
|
||||
sizeOnStartupMode = game.sizeOnStartupMode;
|
||||
projectUuid = game.projectUuid;
|
||||
useDeprecatedZeroAsDefaultZOrder = game.useDeprecatedZeroAsDefaultZOrder;
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
author = game.author;
|
||||
packageName = game.packageName;
|
||||
orientation = game.orientation;
|
||||
adMobAppId = game.adMobAppId;
|
||||
folderProject = game.folderProject;
|
||||
latestCompilationDirectory = game.latestCompilationDirectory;
|
||||
platformSpecificAssets = game.platformSpecificAssets;
|
||||
loadingScreen = game.loadingScreen;
|
||||
objectGroups = game.objectGroups;
|
||||
|
||||
extensionProperties = game.extensionProperties;
|
||||
|
||||
gdMajorVersion = game.gdMajorVersion;
|
||||
gdMinorVersion = game.gdMinorVersion;
|
||||
gdBuildVersion = game.gdBuildVersion;
|
||||
@@ -1087,7 +1124,6 @@ void Project::Init(const gd::Project& game) {
|
||||
extensionsUsed = game.extensionsUsed;
|
||||
platforms = game.platforms;
|
||||
|
||||
// Resources
|
||||
resourcesManager = game.resourcesManager;
|
||||
imageManager = std::make_shared<ImageManager>(*game.imageManager);
|
||||
imageManager->SetResourcesManager(&resourcesManager);
|
||||
@@ -1112,13 +1148,8 @@ void Project::Init(const gd::Project& game) {
|
||||
variables = game.GetVariables();
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gameFile = game.GetProjectFile();
|
||||
projectFile = game.GetProjectFile();
|
||||
imagesChanged = game.imagesChanged;
|
||||
|
||||
winExecutableFilename = game.winExecutableFilename;
|
||||
winExecutableIconFile = game.winExecutableIconFile;
|
||||
linuxExecutableFilename = game.linuxExecutableFilename;
|
||||
macExecutableFilename = game.macExecutableFilename;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/ExtensionProperties.h"
|
||||
#include "GDCore/Project/LoadingScreen.h"
|
||||
#include "GDCore/Project/ObjectGroupsContainer.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
@@ -114,30 +115,16 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
*/
|
||||
const gd::String& GetOrientation() const { return orientation; }
|
||||
|
||||
/**
|
||||
* \brief Change the project AdMob application ID (needed
|
||||
* to use the AdMob extension). This has no effect on desktop
|
||||
* and web browsers.
|
||||
*/
|
||||
void SetAdMobAppId(const gd::String& adMobAppId_) {
|
||||
adMobAppId = adMobAppId_;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get the project AdMob application ID.
|
||||
*/
|
||||
const gd::String& GetAdMobAppId() const { return adMobAppId; }
|
||||
|
||||
/**
|
||||
* Called when project file has changed.
|
||||
*/
|
||||
void SetProjectFile(const gd::String& file) { gameFile = file; }
|
||||
void SetProjectFile(const gd::String& file) { projectFile = file; }
|
||||
|
||||
/**
|
||||
* Return project file
|
||||
* \see gd::Project::SetProjectFile
|
||||
*/
|
||||
const gd::String& GetProjectFile() const { return gameFile; }
|
||||
const gd::String& GetProjectFile() const { return projectFile; }
|
||||
|
||||
/**
|
||||
* Set that the project should be saved as a folder project.
|
||||
@@ -290,6 +277,42 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
*/
|
||||
void SetScaleMode(const gd::String& scaleMode_) { scaleMode = scaleMode_; }
|
||||
|
||||
/**
|
||||
* \brief Return if the project should set 0 as Z-order for objects created
|
||||
* from events (which is deprecated) - instead of the highest Z order that was
|
||||
* found on each layer when the scene started.
|
||||
*/
|
||||
bool GetUseDeprecatedZeroAsDefaultZOrder() const {
|
||||
return useDeprecatedZeroAsDefaultZOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set if the project should set 0 as Z-order for objects created from
|
||||
* events (which is deprecated) - instead of the highest Z order that was
|
||||
* found on each layer when the scene started.
|
||||
*/
|
||||
void SetUseDeprecatedZeroAsDefaultZOrder(bool enable) {
|
||||
useDeprecatedZeroAsDefaultZOrder = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Change the project UUID.
|
||||
*/
|
||||
void SetProjectUuid(const gd::String& projectUuid_) {
|
||||
projectUuid = projectUuid_;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get the project UUID, useful when using the game on online services
|
||||
* that would require a unique identifier.
|
||||
*/
|
||||
const gd::String& GetProjectUuid() const { return projectUuid; }
|
||||
|
||||
/**
|
||||
* \brief Create a new project UUID.
|
||||
*/
|
||||
void ResetProjectUuid();
|
||||
|
||||
/**
|
||||
* Return a reference to the vector containing the names of extensions used by
|
||||
* the project.
|
||||
@@ -305,6 +328,26 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
std::vector<gd::String>& GetUsedExtensions() { return extensionsUsed; };
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Get the properties set by extensions.
|
||||
*
|
||||
* Each extension can store arbitrary values indexed by a property name, which
|
||||
* are useful to store project wide settings (AdMob id, etc...).
|
||||
*/
|
||||
gd::ExtensionProperties& GetExtensionProperties() {
|
||||
return extensionProperties;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get the properties set by extensions.
|
||||
*
|
||||
* Each extension can store arbitrary values indexed by a property name, which
|
||||
* are useful to store project wide settings (AdMob id, etc...).
|
||||
*/
|
||||
const gd::ExtensionProperties& GetExtensionProperties() const {
|
||||
return extensionProperties;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the list of platforms used by the project.
|
||||
*/
|
||||
@@ -916,10 +959,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
std::vector<gd::String> imagesChanged; ///< Images that have been changed and
|
||||
///< which have to be reloaded
|
||||
gd::String winExecutableFilename; ///< Windows executable name
|
||||
gd::String winExecutableIconFile; ///< Icon for Windows executable
|
||||
gd::String linuxExecutableFilename; ///< Linux executable name
|
||||
gd::String macExecutableFilename; ///< Mac executable name
|
||||
#endif
|
||||
|
||||
private:
|
||||
@@ -941,8 +980,15 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
bool adaptGameResolutionAtRuntime; ///< Should the game resolution be adapted
|
||||
///< to the window size at runtime
|
||||
gd::String
|
||||
sizeOnStartupMode; ///< How to adapt the game size to the screen. Can be
|
||||
///< "adaptWidth", "adaptHeight" or empty
|
||||
sizeOnStartupMode; ///< How to adapt the game size to the screen. Can be
|
||||
///< "adaptWidth", "adaptHeight" or empty
|
||||
gd::String projectUuid; ///< UUID useful to identify the game in online
|
||||
///< services or database that would require it.
|
||||
bool useDeprecatedZeroAsDefaultZOrder; ///< If true, objects created from
|
||||
///< events will have 0 as Z order,
|
||||
///< instead of the highest Z order
|
||||
///< found on the layer at the scene
|
||||
///< startup.
|
||||
std::vector<std::unique_ptr<gd::Layout> > scenes; ///< List of all scenes
|
||||
gd::VariablesContainer variables; ///< Initial global variables
|
||||
std::vector<std::unique_ptr<gd::ExternalLayout> >
|
||||
@@ -968,17 +1014,19 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
gd::String packageName; ///< Game package name
|
||||
gd::String orientation; ///< Lock game orientation (on mobile devices).
|
||||
///< "default", "landscape" or "portrait".
|
||||
gd::String adMobAppId; ///< AdMob application ID.
|
||||
bool
|
||||
folderProject; ///< True if folder project, false if single file project.
|
||||
gd::String gameFile; ///< File of the game
|
||||
gd::String latestCompilationDirectory; ///< File of the game
|
||||
gd::String
|
||||
projectFile; ///< Path to the project file - when editing a local file.
|
||||
gd::String latestCompilationDirectory;
|
||||
gd::Platform*
|
||||
currentPlatform; ///< The platform being used to edit the project.
|
||||
gd::PlatformSpecificAssets platformSpecificAssets;
|
||||
gd::LoadingScreen loadingScreen;
|
||||
std::vector<std::unique_ptr<gd::ExternalEvents> >
|
||||
externalEvents; ///< List of all externals events
|
||||
externalEvents; ///< List of all externals events
|
||||
ExtensionProperties
|
||||
extensionProperties; ///< The properties of the extensions.
|
||||
mutable unsigned int gdMajorVersion; ///< The GD major version used the last
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdMinorVersion; ///< The GD minor version used the last
|
||||
|
@@ -4,7 +4,9 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "PropertyDescriptor.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
@@ -45,4 +47,27 @@ void PropertyDescriptor::UnserializeFrom(const SerializerElement& element) {
|
||||
: false;
|
||||
}
|
||||
|
||||
void PropertyDescriptor::SerializeValuesTo(SerializerElement& element) const {
|
||||
element.AddChild("value").SetStringValue(currentValue);
|
||||
SerializerElement& extraInformationElement =
|
||||
element.AddChild("extraInformation");
|
||||
extraInformationElement.ConsiderAsArray();
|
||||
for (const gd::String& information : extraInformation) {
|
||||
extraInformationElement.AddChild("").SetStringValue(information);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyDescriptor::UnserializeValuesFrom(
|
||||
const SerializerElement& element) {
|
||||
currentValue = element.GetChild("value").GetStringValue();
|
||||
|
||||
extraInformation.clear();
|
||||
const SerializerElement& extraInformationElement =
|
||||
element.GetChild("extraInformation");
|
||||
extraInformationElement.ConsiderAsArray();
|
||||
for (std::size_t i = 0; i < extraInformationElement.GetChildrenCount(); ++i)
|
||||
extraInformation.push_back(
|
||||
extraInformationElement.GetChild(i).GetStringValue());
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -6,6 +6,7 @@
|
||||
#ifndef GDCORE_PROPERTYDESCRIPTOR
|
||||
#define GDCORE_PROPERTYDESCRIPTOR
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
@@ -120,6 +121,16 @@ class GD_CORE_API PropertyDescriptor {
|
||||
* \brief Unserialize the PropertyDescriptor.
|
||||
*/
|
||||
virtual void UnserializeFrom(const SerializerElement& element);
|
||||
|
||||
/**
|
||||
* \brief Serialize only the value and extra informations.
|
||||
*/
|
||||
virtual void SerializeValuesTo(SerializerElement& element) const;
|
||||
|
||||
/**
|
||||
* \brief Unserialize only the value and extra informations.
|
||||
*/
|
||||
virtual void UnserializeValuesFrom(const SerializerElement& element);
|
||||
///@}
|
||||
|
||||
private:
|
||||
@@ -127,7 +138,7 @@ class GD_CORE_API PropertyDescriptor {
|
||||
gd::String
|
||||
type; ///< The type of the property. This is arbitrary and interpreted by
|
||||
///< the class responsible for updating the property grid.
|
||||
gd::String label; //< The user-friendly property name
|
||||
gd::String label; //< The user-friendly property name
|
||||
gd::String description; //< The user-friendly property description
|
||||
std::vector<gd::String>
|
||||
extraInformation; ///< Can be used to store for example the available
|
||||
|
@@ -5,8 +5,10 @@
|
||||
*/
|
||||
|
||||
#include "GDCore/Project/ResourcesManager.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
@@ -20,6 +22,7 @@ namespace gd {
|
||||
gd::String Resource::badStr;
|
||||
|
||||
Resource ResourcesManager::badResource;
|
||||
gd::String ResourcesManager::badResourceName;
|
||||
#if defined(GD_IDE_ONLY)
|
||||
ResourceFolder ResourcesManager::badFolder;
|
||||
Resource ResourceFolder::badResource;
|
||||
@@ -90,6 +93,33 @@ bool ResourcesManager::HasResource(const gd::String& name) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
const gd::String& ResourcesManager::GetResourceNameWithOrigin(
|
||||
const gd::String& originName, const gd::String& originIdentifier) const {
|
||||
for (const auto& resource : resources) {
|
||||
if (!resource) continue;
|
||||
|
||||
if (resource->GetOriginName() == originName &&
|
||||
resource->GetOriginIdentifier() == originIdentifier) {
|
||||
return resource->GetName();
|
||||
}
|
||||
}
|
||||
|
||||
return badResourceName;
|
||||
}
|
||||
|
||||
const gd::String& ResourcesManager::GetResourceNameWithFile(
|
||||
const gd::String& file) const {
|
||||
for (const auto& resource : resources) {
|
||||
if (!resource) continue;
|
||||
|
||||
if (resource->GetFile() == file) {
|
||||
return resource->GetName();
|
||||
}
|
||||
}
|
||||
|
||||
return badResourceName;
|
||||
}
|
||||
|
||||
std::vector<gd::String> ResourcesManager::GetAllResourceNames() const {
|
||||
std::vector<gd::String> allResources;
|
||||
for (std::size_t i = 0; i < resources.size(); ++i)
|
||||
@@ -104,7 +134,8 @@ std::map<gd::String, gd::PropertyDescriptor> Resource::GetProperties() const {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> ImageResource::GetProperties() const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> ImageResource::GetProperties()
|
||||
const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties[_("Smooth the image")]
|
||||
.SetValue(smooth ? "true" : "false")
|
||||
@@ -413,6 +444,15 @@ void ResourcesManager::UnserializeFrom(const SerializerElement& element) {
|
||||
std::shared_ptr<Resource> resource = CreateResource(kind);
|
||||
resource->SetName(name);
|
||||
resource->SetMetadata(metadata);
|
||||
|
||||
if (resourceElement.HasChild("origin")) {
|
||||
gd::String originName =
|
||||
resourceElement.GetChild("origin").GetStringAttribute("name", "");
|
||||
gd::String originIdentifier =
|
||||
resourceElement.GetChild("origin").GetStringAttribute("identifier",
|
||||
"");
|
||||
resource->SetOrigin(originName, originIdentifier);
|
||||
}
|
||||
resource->UnserializeFrom(resourceElement);
|
||||
|
||||
resources.push_back(resource);
|
||||
@@ -444,6 +484,14 @@ void ResourcesManager::SerializeTo(SerializerElement& element) const {
|
||||
resourceElement.SetAttribute("name", resources[i]->GetName());
|
||||
resourceElement.SetAttribute("metadata", resources[i]->GetMetadata());
|
||||
|
||||
const gd::String& originName = resources[i]->GetOriginName();
|
||||
const gd::String& originIdentifier = resources[i]->GetOriginIdentifier();
|
||||
if (!originName.empty() || !originIdentifier.empty()) {
|
||||
resourceElement.AddChild("origin")
|
||||
.SetAttribute("name", originName)
|
||||
.SetAttribute("identifier", originIdentifier);
|
||||
}
|
||||
|
||||
resources[i]->SerializeTo(resourceElement);
|
||||
}
|
||||
|
||||
@@ -560,7 +608,8 @@ void JsonResource::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("disablePreload", IsPreloadDisabled());
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> JsonResource::GetProperties() const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> JsonResource::GetProperties()
|
||||
const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties["disablePreload"]
|
||||
.SetValue(disablePreload ? "true" : "false")
|
||||
|
@@ -79,6 +79,17 @@ class GD_CORE_API Resource {
|
||||
*/
|
||||
virtual void SetFile(const gd::String& newFile){};
|
||||
|
||||
/**
|
||||
* TODO: make a ResourceOrigin object?
|
||||
*/
|
||||
virtual void SetOrigin(const gd::String& originName_, const gd::String& originIdentifier_) {
|
||||
originName = originName_;
|
||||
originIdentifier = originIdentifier_;
|
||||
}
|
||||
|
||||
virtual const gd::String& GetOriginName() const { return originName; }
|
||||
virtual const gd::String& GetOriginIdentifier() const { return originIdentifier; }
|
||||
|
||||
/**
|
||||
* \brief Set the metadata (any string) associated to the resource.
|
||||
* \note Can be used by external editors to store extra information, for
|
||||
@@ -142,6 +153,8 @@ class GD_CORE_API Resource {
|
||||
gd::String kind;
|
||||
gd::String name;
|
||||
gd::String metadata;
|
||||
gd::String originName;
|
||||
gd::String originIdentifier;
|
||||
bool userAdded; ///< True if the resource was added by the user, and not
|
||||
///< automatically by GDevelop.
|
||||
|
||||
@@ -354,6 +367,18 @@ class GD_CORE_API ResourcesManager {
|
||||
*/
|
||||
bool HasResource(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* \brief Return the name of the resource with the given origin, if any.
|
||||
* If not found, an empty string is returned.
|
||||
*/
|
||||
const gd::String& GetResourceNameWithOrigin(const gd::String& originName, const gd::String& originIdentifier) const;
|
||||
|
||||
/**
|
||||
* \brief Return the name of the first resource with the given file, if any.
|
||||
* If not found, an empty string is returned.
|
||||
*/
|
||||
const gd::String& GetResourceNameWithFile(const gd::String& file) const;
|
||||
|
||||
/**
|
||||
* \brief Return a reference to a resource.
|
||||
*/
|
||||
@@ -487,6 +512,7 @@ class GD_CORE_API ResourcesManager {
|
||||
static ResourceFolder badFolder;
|
||||
#endif
|
||||
static Resource badResource;
|
||||
static gd::String badResourceName;
|
||||
};
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
|
@@ -84,6 +84,18 @@ void SetupProjectWithDummyPlatform(gd::Project &project,
|
||||
.AddParameter("string", "")
|
||||
.AddParameter("expression", "", "", true)
|
||||
.SetFunctionName("getNumberWith3Params");
|
||||
extension
|
||||
->AddStrExpression("GetStringWith2ObjectParamAnd2ObjectVarParam",
|
||||
"Get string with twice an object param and an objectvar param",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("object", _("Object 1 parameter"))
|
||||
.AddParameter("objectvar", _("Variable for object 1"))
|
||||
.AddParameter("object", _("Object 2 parameter"))
|
||||
.AddParameter("objectvar", _("Variable for object 2"))
|
||||
.SetFunctionName("getStringWith2ObjectParamAnd2ObjectVarParam");
|
||||
|
||||
auto &object = extension->AddObject<gd::Object>(
|
||||
"Sprite", "Dummy Sprite", "Dummy sprite object", "");
|
||||
object
|
||||
|
@@ -4,6 +4,7 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
|
||||
#include "DummyPlatform.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
@@ -823,37 +824,41 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
}
|
||||
|
||||
SECTION("Valid object function name") {
|
||||
auto node = parser.ParseExpression("string", "MyObject.MyFunc");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &objectFunctionName = dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
|
||||
REQUIRE(objectFunctionName.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "MyFunc");
|
||||
auto node = parser.ParseExpression("string", "MyObject.MyFunc");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &objectFunctionName =
|
||||
dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
|
||||
REQUIRE(objectFunctionName.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "MyFunc");
|
||||
}
|
||||
|
||||
SECTION("Valid object behavior name") {
|
||||
auto node = parser.ParseExpression("string", "MyObject.MyBehavior::MyFunc");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &objectFunctionName = dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
|
||||
REQUIRE(objectFunctionName.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "MyBehavior");
|
||||
REQUIRE(objectFunctionName.behaviorFunctionName == "MyFunc");
|
||||
auto node = parser.ParseExpression("string", "MyObject.MyBehavior::MyFunc");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &objectFunctionName =
|
||||
dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
|
||||
REQUIRE(objectFunctionName.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "MyBehavior");
|
||||
REQUIRE(objectFunctionName.behaviorFunctionName == "MyFunc");
|
||||
}
|
||||
|
||||
SECTION("Unfinished object function name") {
|
||||
auto node = parser.ParseExpression("string", "MyObject.");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &objectFunctionName = dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
|
||||
REQUIRE(objectFunctionName.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "");
|
||||
auto node = parser.ParseExpression("string", "MyObject.");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &objectFunctionName =
|
||||
dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
|
||||
REQUIRE(objectFunctionName.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "");
|
||||
}
|
||||
|
||||
SECTION("Unfinished object behavior name") {
|
||||
auto node = parser.ParseExpression("string", "MyObject.MyBehavior::");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &objectFunctionName = dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
|
||||
REQUIRE(objectFunctionName.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "MyBehavior");
|
||||
REQUIRE(objectFunctionName.behaviorFunctionName == "");
|
||||
auto node = parser.ParseExpression("string", "MyObject.MyBehavior::");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &objectFunctionName =
|
||||
dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
|
||||
REQUIRE(objectFunctionName.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "MyBehavior");
|
||||
REQUIRE(objectFunctionName.behaviorFunctionName == "");
|
||||
}
|
||||
|
||||
SECTION("Invalid function calls") {
|
||||
@@ -948,7 +953,8 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Invalid behavior function call, finishing with namespace separator") {
|
||||
SECTION(
|
||||
"Invalid behavior function call, finishing with namespace separator") {
|
||||
{
|
||||
auto node = parser.ParseExpression("number", "MyObject.MyBehavior::(12)");
|
||||
REQUIRE(node != nullptr);
|
||||
@@ -1031,6 +1037,55 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Valid function call with object variable") {
|
||||
{
|
||||
// Note that in this test we need to use an expression with "objectvar",
|
||||
// as the grammar of the parser depends on this parameter type
|
||||
// information.
|
||||
auto node = parser.ParseExpression(
|
||||
"string",
|
||||
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(MyObject1, "
|
||||
"MyVar1, MyObject2, MyVar2)");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &functionNode = dynamic_cast<gd::FunctionCallNode &>(*node);
|
||||
auto &identifierObject1Node =
|
||||
dynamic_cast<gd::IdentifierNode &>(*functionNode.parameters[0]);
|
||||
auto &variable1Node =
|
||||
dynamic_cast<gd::VariableNode &>(*functionNode.parameters[1]);
|
||||
auto &identifierObject2Node =
|
||||
dynamic_cast<gd::IdentifierNode &>(*functionNode.parameters[2]);
|
||||
auto &variable2Node =
|
||||
dynamic_cast<gd::VariableNode &>(*functionNode.parameters[3]);
|
||||
|
||||
REQUIRE(identifierObject1Node.identifierName == "MyObject1");
|
||||
REQUIRE(identifierObject2Node.identifierName == "MyObject2");
|
||||
REQUIRE(variable1Node.objectName == "MyObject1");
|
||||
REQUIRE(variable1Node.name == "MyVar1");
|
||||
REQUIRE(variable2Node.objectName == "MyObject2");
|
||||
REQUIRE(variable2Node.name == "MyVar2");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Invalid function call with object variable") {
|
||||
{
|
||||
// Note that in this test we need to use an expression with "objectvar",
|
||||
// as the grammar of the parser depends on this parameter type
|
||||
// information.
|
||||
auto node = parser.ParseExpression(
|
||||
"string",
|
||||
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(My "
|
||||
"badly/written object1, MyVar1, MyObject2, MyVar2)");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
gd::ExpressionValidator validator;
|
||||
node->Visit(validator);
|
||||
REQUIRE(validator.GetErrors().size() == 1);
|
||||
REQUIRE(validator.GetErrors()[0]->GetMessage() ==
|
||||
"An object name was expected but something else was written. "
|
||||
"Enter just the name of the object for this parameter.");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Fuzzy/random tests") {
|
||||
{
|
||||
auto testExpression = [&parser](const gd::String &expression) {
|
||||
|
33
Core/tests/ResourcesRenamer.cpp
Normal file
33
Core/tests/ResourcesRenamer.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
/**
|
||||
* @file Tests covering common features of GDevelop Core.
|
||||
*/
|
||||
#include "GDCore/IDE/Project/ResourcesRenamer.h"
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
TEST_CASE("ResourcesRenamer", "[common]") {
|
||||
SECTION("It renames resources that are exposed") {
|
||||
std::map<gd::String, gd::String> renamings = {
|
||||
{"Resource1", "RenamedResource1"}};
|
||||
gd::ResourcesRenamer resourcesRenamer(renamings);
|
||||
|
||||
gd::Project project;
|
||||
project.GetPlatformSpecificAssets().Set(
|
||||
"android", "some-icon", "Resource1");
|
||||
project.GetPlatformSpecificAssets().Set(
|
||||
"android", "some-other-icon", "Resource2");
|
||||
|
||||
project.ExposeResources(resourcesRenamer);
|
||||
REQUIRE(project.GetPlatformSpecificAssets().Get("android", "some-icon") ==
|
||||
"RenamedResource1");
|
||||
REQUIRE(project.GetPlatformSpecificAssets().Get(
|
||||
"android", "some-other-icon") == "Resource2");
|
||||
}
|
||||
}
|
@@ -2,34 +2,38 @@
|
||||
# do it if not already cloned to avoid triggering a whole
|
||||
# recompilation every time CMake is run.
|
||||
find_package(Git)
|
||||
if(GIT_FOUND AND NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/SFML/readme.txt")
|
||||
message( "Cloning SFML in ExtLibs/SFML with Git..." )
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} clone "https://www.github.com/SFML/SFML.git" SFML
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/
|
||||
OUTPUT_QUIET)
|
||||
if(GIT_FOUND)
|
||||
if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/SFML/readme.txt")
|
||||
message( "Cloning SFML in ExtLibs/SFML with Git..." )
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} clone "https://www.github.com/SFML/SFML.git" SFML
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/
|
||||
OUTPUT_QUIET)
|
||||
|
||||
message( "Resetting SFML source code to version 2.4.1..." )
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} reset --hard 2.4.1
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/SFML
|
||||
OUTPUT_QUIET)
|
||||
message( "Resetting SFML source code to version 2.4.1..." )
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} reset --hard 2.4.1
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/SFML
|
||||
OUTPUT_QUIET)
|
||||
|
||||
message( "Applying the patches..." )
|
||||
file(GLOB SFML_PATCHES
|
||||
LIST_DIRECTORIES FALSE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SFML-patches/*.patch)
|
||||
message( "Applying the patches..." )
|
||||
file(GLOB SFML_PATCHES
|
||||
LIST_DIRECTORIES FALSE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SFML-patches/*.patch)
|
||||
|
||||
if(SFML_PATCHES)
|
||||
list(SORT SFML_PATCHES)
|
||||
if(SFML_PATCHES)
|
||||
list(SORT SFML_PATCHES)
|
||||
|
||||
foreach(SFML_PATCH ${SFML_PATCHES})
|
||||
message( "Applying patch: ${SFML_PATCH}..." )
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} apply ${SFML_PATCH} --ignore-whitespace
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/SFML
|
||||
OUTPUT_QUIET)
|
||||
endforeach()
|
||||
foreach(SFML_PATCH ${SFML_PATCHES})
|
||||
message( "Applying patch: ${SFML_PATCH}..." )
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} apply ${SFML_PATCH} --ignore-whitespace
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/SFML
|
||||
OUTPUT_QUIET)
|
||||
endforeach()
|
||||
endif()
|
||||
else()
|
||||
message( "SFML already downloaded." )
|
||||
endif()
|
||||
else()
|
||||
message( "Git not found, make sure you have SFML >= 2.4 in ExtLibs/SFML and you applied the needed patches (from ExtLibs/SFML-patches)!" )
|
||||
|
@@ -20,7 +20,10 @@ import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsEx
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
createExtension: function(_/*: (string) => string */, gd/*: libGDevelop */) {
|
||||
createExtension: function (
|
||||
_ /*: (string) => string */,
|
||||
gd /*: libGDevelop */
|
||||
) {
|
||||
const extension = new gd.PlatformExtension();
|
||||
extension.setExtensionInformation(
|
||||
'AdMob',
|
||||
@@ -32,6 +35,24 @@ module.exports = {
|
||||
'MIT'
|
||||
);
|
||||
|
||||
extension
|
||||
.registerProperty('AdMobAppId')
|
||||
.setLabel(_('AdMob App ID'))
|
||||
.setDescription('ca-app-pub-XXXXXXXXXXXXXXXX/YYYYYYYYYY')
|
||||
.setType('string');
|
||||
|
||||
extension
|
||||
.addDependency()
|
||||
.setName('AdMob Cordova Extension')
|
||||
.setDependencyType('cordova')
|
||||
.setExportName('cordova-plugin-admob-free')
|
||||
.setVersion('~0.21.0')
|
||||
.setExtraSetting(
|
||||
'ADMOB_APP_ID',
|
||||
new gd.PropertyDescriptor('AdMobAppId').setType('ExtensionProperty')
|
||||
)
|
||||
.onlyIfExtraSettingIsNonEmpty('ADMOB_APP_ID');
|
||||
|
||||
// Banner
|
||||
extension
|
||||
.addCondition(
|
||||
@@ -364,7 +385,10 @@ module.exports = {
|
||||
|
||||
return extension;
|
||||
},
|
||||
runExtensionSanityTests: function(gd /*: libGDevelop */, extension /*: gdPlatformExtension*/) {
|
||||
runExtensionSanityTests: function (
|
||||
gd /*: libGDevelop */,
|
||||
extension /*: gdPlatformExtension*/
|
||||
) {
|
||||
return [];
|
||||
},
|
||||
};
|
||||
|
676
Extensions/AdvancedWindow/JsExtension.js
Normal file
676
Extensions/AdvancedWindow/JsExtension.js
Normal file
@@ -0,0 +1,676 @@
|
||||
// @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
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
createExtension: function (
|
||||
_ /*: (string) => string */,
|
||||
gd /*: libGDevelop */
|
||||
) {
|
||||
const extension = new gd.PlatformExtension();
|
||||
extension.setExtensionInformation(
|
||||
'AdvancedWindow',
|
||||
_('Advanced window management'),
|
||||
_(
|
||||
'Provides advanced features related to the game window positioning and interaction with the operating system.'
|
||||
),
|
||||
'Arthur Pacaud (arthuro555)',
|
||||
'MIT'
|
||||
);
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'Focus',
|
||||
_('Change focus of the window'),
|
||||
_('Make the window gain or lose focus.'),
|
||||
_('Focus the window: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Focus the window?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.focus');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsFocused',
|
||||
_('Window focused'),
|
||||
_('Checks if the window is focused.'),
|
||||
_('The window is focused'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.isFocused');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'Show',
|
||||
_('Change visibility of the window'),
|
||||
_('Make the window visible or invisible.'),
|
||||
_('Window visible: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Show window?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.show');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsVisible',
|
||||
_('Window visibile'),
|
||||
_('Checks if the window is visible.'),
|
||||
_('The window is visible'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.isVisible');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'Maximize',
|
||||
_('Maximize the window'),
|
||||
_('Maximize or unmaximize the window.'),
|
||||
_('Maximize window: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Maximize window?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.maximize');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsMaximized',
|
||||
_('Window maximized'),
|
||||
_('Checks if the window is maximized.'),
|
||||
_('The window is maximized'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.isMaximized');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'Minimize',
|
||||
_('Minimize the window'),
|
||||
_('Minimize or unminimize the window.'),
|
||||
_('Minimize window: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Minimize window?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.minimize');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsMinimized',
|
||||
_('Window minimized'),
|
||||
_('Checks if the window is minimized.'),
|
||||
_('The window is minimized'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.isMinimized');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'EnableWindow',
|
||||
_('Enable the window'),
|
||||
_('Enables or disables the window.'),
|
||||
_('Enable window: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Enable window?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.enable');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsWindowEnabled',
|
||||
_('Window enabled'),
|
||||
_('Checks if the window is enabled.'),
|
||||
_('The window is enabled'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.isEnabled');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SetResizable',
|
||||
_('Allow resizing'),
|
||||
_('Enables or disables resizing of the window by the user.'),
|
||||
_('Enable window resizing: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Allow resizing?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.setResizable');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsResizable',
|
||||
_('Window resizable'),
|
||||
_('Checks if the window can be resized.'),
|
||||
_('The window can be resized'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.isResizable');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SetMovable',
|
||||
_('Allow moving'),
|
||||
_('Enables or disables moving of the window by the user.'),
|
||||
_('Enable window moving: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Allow moving?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.setMovable');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsMovable',
|
||||
_('Window movable'),
|
||||
_('Checks if the window can be moved.'),
|
||||
_('The window can be moved'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.isMovable');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SetMaximizable',
|
||||
_('Allow maximizing'),
|
||||
_('Enables or disables maximizing of the window by the user.'),
|
||||
_('Enable window maximizing: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Allow maximizing?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.setMaximizable');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsMaximizable',
|
||||
_('Window maximizable'),
|
||||
_('Checks if the window can be maximized.'),
|
||||
_('The window can be maximized'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.isMaximizable');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SetMinimizable',
|
||||
_('Allow mimizing'),
|
||||
_('Enables or disables minimizing of the window by the user.'),
|
||||
_('Enable window minimizing: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Allow minimizing?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.setMinimizable');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsMinimizable',
|
||||
_('Window minimizable'),
|
||||
_('Checks if the window can be minimized.'),
|
||||
_('The window can be minimized'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.isMinimizable');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SetFullScreenable',
|
||||
_('Allow full-screening'),
|
||||
_('Enables or disables full-screening of the window by the user.'),
|
||||
_('Enable window full-screening: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Allow full-screening?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.setFullScreenable');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsFullScreenable',
|
||||
_('Window full-screenable'),
|
||||
_('Checks if the window can be full-screened.'),
|
||||
_('The window can be set in fullscreen'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.isFullScreenable');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SetClosable',
|
||||
_('Allow closing'),
|
||||
_('Enables or disables closing of the window by the user.'),
|
||||
_('Enable window closing: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Allow closing?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.setClosable');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsClosable',
|
||||
_('Window closable'),
|
||||
_('Checks if the window can be closed.'),
|
||||
_('The window can be closed'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.isClosable');
|
||||
|
||||
const levelChoices = JSON.stringify([
|
||||
'normal',
|
||||
'floating',
|
||||
'torn-off-menu',
|
||||
'modal-panel',
|
||||
'main-menu',
|
||||
'status',
|
||||
'pop-up-menu',
|
||||
'screen-saver',
|
||||
]);
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SetAlwaysOnTop',
|
||||
_('Make the windows always on top'),
|
||||
_('Puts the window constantly above all other windows.'),
|
||||
_('Make window always on top: _PARAM0_, level: _PARAM1_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Enable always on top?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addParameter('stringWithSelector', _('Level'), levelChoices, false)
|
||||
.setDefaultValue('floating')
|
||||
.setParameterLongDescription(
|
||||
'The level is like a layer in GDevelop but for the OS. ' +
|
||||
'The further down the list, the higher it will be. ' +
|
||||
'When disabling always on top, the level will be set to normal. ' +
|
||||
'From "floating" to "status" included, ' +
|
||||
'the window is placed below the Dock on macOS and below the taskbar on Windows. ' +
|
||||
'Starting from "pop-up-menu", it is shown above the Dock on macOS and ' +
|
||||
'above the taskbar on Windows. ' +
|
||||
'This parameter is ignored on linux.'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.setAlwaysOnTop');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsAlwaysOnTop',
|
||||
_('Window always on top'),
|
||||
_('Checks if the window is always on top.'),
|
||||
_('The window is always on top'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.isAlwaysOnTop');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SetKiosk',
|
||||
_('Enable kiosk mode'),
|
||||
_(
|
||||
'Puts the window in kiosk mode. This prevents the user from exiting fullscreen.'
|
||||
),
|
||||
_('Enable kiosk mode: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Enable kiosk mode?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.setKiosk');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsKiosk',
|
||||
_('Kiosk mode'),
|
||||
_('Checks if the window is currently in kiosk mode.'),
|
||||
_('The window is in kiosk mode'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.isKiosk');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SetHasShadow',
|
||||
_('Enable window shadow'),
|
||||
_('Enables or disables the window shadow.'),
|
||||
_('Enable window shadow: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Enable shadow?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.setHasShadow');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'HasShadow',
|
||||
_('Shadow enabled'),
|
||||
_("Checks if the window currently has it's shadow enabled."),
|
||||
_('The window has a shadow'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.hasShadow');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'EnableContentProtection',
|
||||
_('Enable content protection'),
|
||||
_(
|
||||
'Enables or disables the content protection mode. This should prevent screenshots of the game from being taken.'
|
||||
),
|
||||
_('Enable content protection: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Enable content protection?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.setContentProtection');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SetFocusable',
|
||||
_('Allow focusing'),
|
||||
_('Allow or disallow the user to focus the window.'),
|
||||
_('Allow to focus the window: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Allow focus?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.setFocusable');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'Flash',
|
||||
_('Flash the window'),
|
||||
_('Make the window flash or end flashing.'),
|
||||
_('Make the window flash: _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('yesorno', _('Flash the window?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.flash');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SetOpacity',
|
||||
_('Set window opacity'),
|
||||
_('Changes the window opacity.'),
|
||||
_('Set the window opacity to _PARAM0_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('expression', _('New opacity'), '', false)
|
||||
.setParameterLongDescription('A number between 0 (fully transparent) and 1 (fully opaque).')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.setOpacity');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SetWindowPosition',
|
||||
_('Set window position'),
|
||||
_('Changes the window position.'),
|
||||
_('Set the window position to _PARAM0_;_PARAM1_'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addParameter('expression', _('X position'), '', false)
|
||||
.addParameter('expression', _('Y position'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.setPosition');
|
||||
|
||||
extension
|
||||
.addExpression(
|
||||
'WindowX',
|
||||
_('Window X position'),
|
||||
_('Returns the current window X position.'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.getPositionX');
|
||||
|
||||
extension
|
||||
.addExpression(
|
||||
'WindowY',
|
||||
_('Window Y position'),
|
||||
_('Returns the current window Y position.'),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.getPositionY');
|
||||
|
||||
extension
|
||||
.addExpression(
|
||||
'WindowOpacity',
|
||||
_('Window opacity'),
|
||||
_(
|
||||
'Returns the current window opacity (a number from 0 to 1, 1 being fully opaque).'
|
||||
),
|
||||
_('Advanced window management/Windows, Linux, macOS'),
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.advancedWindow.getOpacity');
|
||||
|
||||
return extension;
|
||||
},
|
||||
runExtensionSanityTests: function (
|
||||
gd /*: libGDevelop */,
|
||||
extension /*: gdPlatformExtension*/
|
||||
) {
|
||||
return [];
|
||||
},
|
||||
};
|
370
Extensions/AdvancedWindow/electron-advancedwindowtools.js
Normal file
370
Extensions/AdvancedWindow/electron-advancedwindowtools.js
Normal file
@@ -0,0 +1,370 @@
|
||||
// @ts-check
|
||||
/**
|
||||
* A set of wrappers around the Electron windowing APIs.
|
||||
* They don't have any effect on non Electron runtimes.
|
||||
*
|
||||
* Docstrings are only used for typing here, for proper
|
||||
* documentation check the electron docs at
|
||||
* https://www.electronjs.org/docs/api.
|
||||
*
|
||||
* @filedescriptor
|
||||
* @author arthuro555
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tools to manipulate the game window positioning and
|
||||
* interactions with the operating system.
|
||||
* @namespace
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow = {
|
||||
/**
|
||||
* The game's BrowserWindow instance (or null on
|
||||
* non-electron platforms).
|
||||
* @type {?Object}
|
||||
*/
|
||||
electronBrowserWindow: null,
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
if (typeof require === 'function') {
|
||||
// @ts-ignore
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow = require('electron').remote.getCurrentWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.focus = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow) {
|
||||
if (activate) {
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.focus();
|
||||
} else {
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.blur();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.isFocused = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isFocused();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.show = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow) {
|
||||
if (activate) {
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.showInactive();
|
||||
} else {
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.hide();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.isVisible = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isVisible();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.maximize = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow) {
|
||||
if (activate) {
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.maximize();
|
||||
} else {
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.unmaximize();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.isMaximized = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isMaximized();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.minimize = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow) {
|
||||
if (activate) {
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.minimize();
|
||||
} else {
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.restore();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.isMinimized = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isMinimized();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.enable = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.setEnabled(activate);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.isEnabled = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isEnabled();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.setResizable = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.setResizable(activate);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.isResizable = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isResizable();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.setMovable = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.setMovable(activate);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.isMovable = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isMovable();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.setMaximizable = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.setMaximizable(activate);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.isMaximizable = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isMaximizable();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.setMinimizable = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.setMinimizable(activate);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.isMinimizable = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isMinimizable();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.setFullScreenable = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.setFullScreenable(
|
||||
activate
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.isFullScreenable = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isFullScreenable();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.setClosable = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.setClosable(activate);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.isClosable = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isClosable();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
* @param {"normal" | "floating" | "torn-off-menu" | "modal-panel" |"main-menu" | "status" | "pop-up-menu" | "screen-saver"} level
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.setAlwaysOnTop = function (activate, level) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.setAlwaysOnTop(
|
||||
activate,
|
||||
level
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.isAlwaysOnTop = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isAlwaysOnTop();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.setPosition = function (x, y) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow) {
|
||||
// Convert x and y to (32 bit) integers to avoid Electron errors.
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.setPosition(~~x, ~~y);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {number}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.getPositionX = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow) {
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.getPosition()[0];
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {number}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.getPositionY = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow) {
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.getPosition()[1];
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.setKiosk = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.setKiosk(activate);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.isKiosk = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isKiosk();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.flash = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.flashFrame(activate);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.setHasShadow = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.setHasShadow(activate);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.hasShadow = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.hasShadow();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} opacity
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.setOpacity = function (opacity) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.setOpacity(opacity);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {number}
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.getOpacity = function () {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
return gdjs.evtTools.advancedWindow.electronBrowserWindow.getOpacity();
|
||||
return 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.setContentProtection = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.setContentProtection(
|
||||
activate
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
gdjs.evtTools.advancedWindow.setFocusable = function (activate) {
|
||||
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
|
||||
gdjs.evtTools.advancedWindow.electronBrowserWindow.setFocusable(activate);
|
||||
};
|
@@ -18,7 +18,11 @@ gdjs.BBTextRuntimeObjectPixiRenderer = function (runtimeObject, runtimeScene) {
|
||||
.getFontManager()
|
||||
.getFontFamily(runtimeObject._fontFamily),
|
||||
fontSize: runtimeObject._fontSize + 'px',
|
||||
fill: runtimeObject._color,
|
||||
fill: gdjs.rgbToHexNumber(
|
||||
runtimeObject._color[0],
|
||||
runtimeObject._color[1],
|
||||
runtimeObject._color[2]
|
||||
),
|
||||
tagStyle: 'bbcode',
|
||||
wordWrap: runtimeObject._wordWrap,
|
||||
wordWrapWidth: runtimeObject._wrappingWidth,
|
||||
@@ -72,7 +76,11 @@ gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateText = function () {
|
||||
};
|
||||
|
||||
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateColor = function () {
|
||||
this._pixiObject.textStyles.default.fill = this._object._color;
|
||||
this._pixiObject.textStyles.default.fill = gdjs.rgbToHexNumber(
|
||||
this._object._color[0],
|
||||
this._object._color[1],
|
||||
this._object._color[2]
|
||||
);
|
||||
this._pixiObject.dirty = true;
|
||||
};
|
||||
|
||||
|
@@ -29,8 +29,8 @@ gdjs.BBTextRuntimeObject = function(runtimeScene, objectData) {
|
||||
// parseFloat should not be required, but GDevelop 5.0 beta 92 and below were storing it as a string.
|
||||
/** @type {string} */
|
||||
this._text = objectData.content.text;
|
||||
/** @type {string} */
|
||||
this._color = objectData.content.color;
|
||||
/** @type {number[]} color in format [r, g, b], where each component is in the range [0, 255] */
|
||||
this._color = gdjs.BBTextRuntimeObject.hexToRGBColor(objectData.content.color);
|
||||
/** @type {string} */
|
||||
this._fontFamily = objectData.content.fontFamily;
|
||||
/** @type {number} */
|
||||
@@ -61,6 +61,11 @@ gdjs.BBTextRuntimeObject.prototype = Object.create(
|
||||
);
|
||||
gdjs.registerObject('BBText::BBText', gdjs.BBTextRuntimeObject);
|
||||
|
||||
gdjs.BBTextRuntimeObject.hexToRGBColor = function (hex) {
|
||||
var hexNumber = parseInt(hex.replace('#', ''), 16);
|
||||
return [(hexNumber >> 16) & 0xff, (hexNumber >> 8) & 0xff, hexNumber & 0xff];
|
||||
};
|
||||
|
||||
gdjs.BBTextRuntimeObject.prototype.getRendererObject = function() {
|
||||
return this._renderer.getRendererObject();
|
||||
};
|
||||
@@ -80,7 +85,7 @@ gdjs.BBTextRuntimeObject.prototype.updateFromObjectData = function(oldObjectData
|
||||
this.setBBText(newObjectData.content.text);
|
||||
}
|
||||
if (oldObjectData.content.color !== newObjectData.content.color) {
|
||||
this._color = newObjectData.content.color;
|
||||
this._color = gdjs.BBTextRuntimeObject.hexToRGBColor(newObjectData.content.color);
|
||||
this._renderer.updateColor();
|
||||
}
|
||||
if (oldObjectData.content.fontFamily !== newObjectData.content.fontFamily) {
|
||||
@@ -132,19 +137,19 @@ gdjs.BBTextRuntimeObject.prototype.getBBText = function() {
|
||||
gdjs.BBTextRuntimeObject.prototype.setColor = function(rgbColorString) {
|
||||
const splitValue = rgbColorString.split(';');
|
||||
if (splitValue.length !== 3) return;
|
||||
const hexColor =
|
||||
'#' +
|
||||
gdjs.rgbToHex(
|
||||
parseInt(splitValue[0], 0),
|
||||
parseInt(splitValue[1], 0),
|
||||
parseInt(splitValue[2], 0)
|
||||
);
|
||||
this._color = hexColor;
|
||||
|
||||
this._color[0] = parseInt(splitValue[0], 10);
|
||||
this._color[1] = parseInt(splitValue[1], 10);
|
||||
this._color[2] = parseInt(splitValue[2], 10);
|
||||
this._renderer.updateColor();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the base color.
|
||||
* @return {string} The color as a "R;G;B" string, for example: "255;0;0"
|
||||
*/
|
||||
gdjs.BBTextRuntimeObject.prototype.getColor = function() {
|
||||
return this._color;
|
||||
return this._color[0] + ";" + this._color[1] + ";" + this._color[2];
|
||||
};
|
||||
|
||||
gdjs.BBTextRuntimeObject.prototype.setFontSize = function(fontSize) {
|
||||
|
@@ -32,6 +32,13 @@ module.exports = {
|
||||
"Open source (MIT License)"
|
||||
).setExtensionHelpPath("/all-features/device-vibration");
|
||||
|
||||
extension
|
||||
.addDependency()
|
||||
.setName('Vibration Cordova Extension')
|
||||
.setDependencyType('cordova')
|
||||
.setExportName('cordova-plugin-vibration')
|
||||
.setVersion('3.1.1');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
"StartVibration",
|
||||
|
@@ -1,124 +1,160 @@
|
||||
// @ts-check
|
||||
describe('gdjs.DraggableRuntimeBehavior', function() {
|
||||
var runtimeGame = new gdjs.RuntimeGame({
|
||||
variables: [],
|
||||
resources: {resources: []},
|
||||
// @ts-ignore
|
||||
properties: {windowWidth: 800, windowHeight: 600}
|
||||
});
|
||||
var runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers:[{name:"", visibility: true, effects: []}],
|
||||
variables: [],
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: []
|
||||
});
|
||||
describe('gdjs.DraggableRuntimeBehavior', function () {
|
||||
var runtimeGame = new gdjs.RuntimeGame({
|
||||
variables: [],
|
||||
resources: { resources: [] },
|
||||
// @ts-ignore
|
||||
properties: { windowWidth: 800, windowHeight: 600 },
|
||||
});
|
||||
var runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
cameras: [],
|
||||
effects: [],
|
||||
ambientLightColorR: 127,
|
||||
ambientLightColorB: 127,
|
||||
ambientLightColorG: 127,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: false,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
});
|
||||
|
||||
var object = new gdjs.RuntimeObject(runtimeScene, {name: "obj1", type: "", behaviors: [{name: "Behavior1", type: "DraggableBehavior::Draggable"}], variables: []});
|
||||
var object2 = new gdjs.RuntimeObject(runtimeScene, {name: "obj1", type: "", behaviors: [{name: "Behavior1", type: "DraggableBehavior::Draggable"}], variables: []});
|
||||
runtimeScene.addObject(object);
|
||||
runtimeScene.addObject(object2);
|
||||
var object = new gdjs.RuntimeObject(runtimeScene, {
|
||||
name: 'obj1',
|
||||
type: '',
|
||||
behaviors: [{ name: 'Behavior1', type: 'DraggableBehavior::Draggable' }],
|
||||
variables: [],
|
||||
});
|
||||
var object2 = new gdjs.RuntimeObject(runtimeScene, {
|
||||
name: 'obj1',
|
||||
type: '',
|
||||
behaviors: [{ name: 'Behavior1', type: 'DraggableBehavior::Draggable' }],
|
||||
variables: [],
|
||||
});
|
||||
runtimeScene.addObject(object);
|
||||
runtimeScene.addObject(object2);
|
||||
|
||||
it('should handle mouse', function() {
|
||||
object.setPosition(450, 500);
|
||||
it('should handle mouse', function () {
|
||||
object.setPosition(450, 500);
|
||||
|
||||
//Drag'n'drop
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onMouseMove(450, 500);
|
||||
runtimeGame.getInputManager().onMouseButtonPressed(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onMouseMove(750, 600);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onMouseButtonReleased(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep();
|
||||
//Drag'n'drop
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onMouseMove(450, 500);
|
||||
runtimeGame
|
||||
.getInputManager()
|
||||
.onMouseButtonPressed(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onMouseMove(750, 600);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame
|
||||
.getInputManager()
|
||||
.onMouseButtonReleased(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep();
|
||||
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
|
||||
//Mouse move with dragging
|
||||
runtimeGame.getInputManager().onMouseMove(600, 600);
|
||||
runtimeScene.renderAndStep();
|
||||
//Mouse move with dragging
|
||||
runtimeGame.getInputManager().onMouseMove(600, 600);
|
||||
runtimeScene.renderAndStep();
|
||||
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
|
||||
//Start dragging again
|
||||
runtimeGame.getInputManager().onMouseMove(750, 600);
|
||||
runtimeGame.getInputManager().onMouseButtonPressed(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onMouseMove(850, 700);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onMouseButtonReleased(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep();
|
||||
//Start dragging again
|
||||
runtimeGame.getInputManager().onMouseMove(750, 600);
|
||||
runtimeGame
|
||||
.getInputManager()
|
||||
.onMouseButtonPressed(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onMouseMove(850, 700);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame
|
||||
.getInputManager()
|
||||
.onMouseButtonReleased(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep();
|
||||
|
||||
expect(object.getX()).to.be(850);
|
||||
expect(object.getY()).to.be(700);
|
||||
expect(object.getX()).to.be(850);
|
||||
expect(object.getY()).to.be(700);
|
||||
});
|
||||
it('should handle touches', function () {
|
||||
runtimeGame.getInputManager().touchSimulateMouse(false);
|
||||
object.setPosition(450, 500);
|
||||
|
||||
});
|
||||
it('should handle touches', function() {
|
||||
runtimeGame.getInputManager().touchSimulateMouse(false);
|
||||
object.setPosition(450, 500);
|
||||
//Drag'n'drop
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onTouchStart(1, 10, 20);
|
||||
runtimeGame.getInputManager().onTouchStart(0, 450, 500);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchMove(0, 750, 600);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchEnd(0);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
|
||||
//Drag'n'drop
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onTouchStart(1, 10, 20);
|
||||
runtimeGame.getInputManager().onTouchStart(0, 450, 500);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchMove(0, 750, 600);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchEnd(0);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
//Move another unrelated touch
|
||||
runtimeGame.getInputManager().onTouchMove(1, 750, 600);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onTouchMove(1, 850, 700);
|
||||
runtimeScene.renderAndStep();
|
||||
|
||||
//Move another unrelated touch
|
||||
runtimeGame.getInputManager().onTouchMove(1, 750, 600);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onTouchMove(1, 850, 700);
|
||||
runtimeScene.renderAndStep();
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
//Start drag'n'drop with another touch
|
||||
runtimeGame.getInputManager().onTouchEnd(1);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onTouchStart(1, 750, 600);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onTouchMove(1, 850, 700);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onTouchEnd(1);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
|
||||
//Start drag'n'drop with another touch
|
||||
runtimeGame.getInputManager().onTouchEnd(1);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onTouchStart(1, 750, 600);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onTouchMove(1, 850, 700);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onTouchEnd(1);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
expect(object.getX()).to.be(850);
|
||||
expect(object.getY()).to.be(700);
|
||||
});
|
||||
it('should handle multitouch', function () {
|
||||
runtimeGame.getInputManager().touchSimulateMouse(false);
|
||||
object.setPosition(450, 500);
|
||||
object2.setPosition(650, 600);
|
||||
|
||||
expect(object.getX()).to.be(850);
|
||||
expect(object.getY()).to.be(700);
|
||||
});
|
||||
it('should handle multitouch', function() {
|
||||
runtimeGame.getInputManager().touchSimulateMouse(false);
|
||||
object.setPosition(450, 500);
|
||||
object2.setPosition(650, 600);
|
||||
//Drag'n'drop
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onTouchStart(2, 450, 500);
|
||||
runtimeGame.getInputManager().onTouchStart(1, 650, 600);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchMove(2, 750, 700);
|
||||
runtimeGame.getInputManager().onTouchMove(1, 100, 200);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchEnd(2);
|
||||
|
||||
//Drag'n'drop
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onTouchStart(2, 450, 500);
|
||||
runtimeGame.getInputManager().onTouchStart(1, 650, 600);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchMove(2, 750, 700);
|
||||
runtimeGame.getInputManager().onTouchMove(1, 100, 200);
|
||||
runtimeScene.renderAndStep();
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchEnd(2);
|
||||
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(700);
|
||||
expect(object2.getX()).to.be(100);
|
||||
expect(object2.getY()).to.be(200);
|
||||
});
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(700);
|
||||
expect(object2.getX()).to.be(100);
|
||||
expect(object2.getY()).to.be(200);
|
||||
});
|
||||
});
|
||||
|
@@ -33,6 +33,32 @@ module.exports = {
|
||||
'MIT'
|
||||
);
|
||||
|
||||
// Register Properties
|
||||
extension
|
||||
.registerProperty('DummyPropertyString')
|
||||
.setLabel(_('Dummy Property Name'))
|
||||
.setDescription('Type in anything :)')
|
||||
.setType('string');
|
||||
|
||||
extension
|
||||
.registerProperty('DummyPropertyNumber')
|
||||
.setLabel(_('Dummy Numeric Property Name'))
|
||||
.setDescription('Only numbers here ;)')
|
||||
.setType('number');
|
||||
|
||||
extension
|
||||
.registerProperty('DummyPropertyBoolean')
|
||||
.setDescription(_('A boolean property'))
|
||||
.setType('boolean');
|
||||
|
||||
// Register Cordova/NPM dependencies
|
||||
extension
|
||||
.addDependency()
|
||||
.setName('Thirteen Checker')
|
||||
.setDependencyType('npm')
|
||||
.setExportName('is-thirteen')
|
||||
.setVersion('2.0.0');
|
||||
|
||||
// Declare effects:
|
||||
const dummyEffect = extension
|
||||
.addEffect('DummyEffect')
|
||||
|
@@ -20,7 +20,10 @@ import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsEx
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
createExtension: function(_/*: (string) => string */, gd/*: libGDevelop */) {
|
||||
createExtension: function (
|
||||
_ /*: (string) => string */,
|
||||
gd /*: libGDevelop */
|
||||
) {
|
||||
const extension = new gd.PlatformExtension();
|
||||
extension
|
||||
.setExtensionInformation(
|
||||
@@ -305,7 +308,9 @@ module.exports = {
|
||||
.addAction(
|
||||
'DeleteFileAsync',
|
||||
_('Delete a file (Async)'),
|
||||
_('Delete a file from the filesystem asynchronously. The option result variable will be updated once the file is deleted.'),
|
||||
_(
|
||||
'Delete a file from the filesystem asynchronously. The option result variable will be updated once the file is deleted.'
|
||||
),
|
||||
_('Delete the file _PARAM0_'),
|
||||
_('Filesystem/Windows, Linux, MacOS/Asynchronous'),
|
||||
'JsPlatform/Extensions/filesystem_delete_file24.png',
|
||||
@@ -366,8 +371,8 @@ module.exports = {
|
||||
extension
|
||||
.addStrExpression(
|
||||
'ExecutablePath',
|
||||
_('This games executable folder'),
|
||||
_('Get the path to this games executable folder.'),
|
||||
_('Game executable file'),
|
||||
_('Get the path to this game executable file.'),
|
||||
_('Filesystem/Windows, Linux, MacOS'),
|
||||
'JsPlatform/Extensions/filesystem_folder32.png'
|
||||
)
|
||||
@@ -376,11 +381,24 @@ module.exports = {
|
||||
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
|
||||
.setFunctionName('gdjs.fileSystem.getExecutablePath');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'ExecutableFolderPath',
|
||||
_('Game executable folder'),
|
||||
_('Get the path to this game executable folder.'),
|
||||
_('Filesystem/Windows, Linux, MacOS'),
|
||||
'JsPlatform/Extensions/filesystem_folder32.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
|
||||
.setFunctionName('gdjs.fileSystem.getExecutableFolderPath');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'UserdataPath',
|
||||
_('Userdata folder (For application settings)'),
|
||||
_('Get the path to userdata folder. (For application settings)'),
|
||||
_('Userdata folder (for application settings)'),
|
||||
_('Get the path to userdata folder (for application settings).'),
|
||||
_('Filesystem/Windows, Linux, MacOS'),
|
||||
'JsPlatform/Extensions/filesystem_folder32.png'
|
||||
)
|
||||
@@ -392,7 +410,7 @@ module.exports = {
|
||||
extension
|
||||
.addStrExpression(
|
||||
'UserHomePath',
|
||||
_('User\'s Home folder'),
|
||||
_("User's Home folder"),
|
||||
_('Get the path to the user home folder.'),
|
||||
_('Filesystem/Windows, Linux, MacOS'),
|
||||
'JsPlatform/Extensions/filesystem_folder32.png'
|
||||
@@ -418,7 +436,7 @@ module.exports = {
|
||||
.addStrExpression(
|
||||
'PathDelimiter',
|
||||
_('Path delimiter'),
|
||||
_('Get the operating system agnostic path delimiter.'),
|
||||
_('Get the operating system path delimiter.'),
|
||||
_('Filesystem/Windows, Linux, MacOS'),
|
||||
'JsPlatform/Extensions/filesystem_folder32.png'
|
||||
)
|
||||
@@ -426,9 +444,55 @@ module.exports = {
|
||||
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
|
||||
.setFunctionName('gdjs.fileSystem.getPathDelimiter');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'DirectoryName',
|
||||
_('Get directory name from a path'),
|
||||
_(
|
||||
'Returns the portion of the path that represents the directories, without the ending file name.'
|
||||
),
|
||||
_('Filesystem/Windows, Linux, MacOS'),
|
||||
'JsPlatform/Extensions/filesystem_folder32.png'
|
||||
)
|
||||
.addParameter('string', _('File or folder path'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
|
||||
.setFunctionName('gdjs.fileSystem.getDirectoryName');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'FileName',
|
||||
_('Get file name from a path'),
|
||||
_('Returns the name of the file with its extension, if any.'),
|
||||
_('Filesystem/Windows, Linux, MacOS'),
|
||||
'JsPlatform/Extensions/filesystem_folder32.png'
|
||||
)
|
||||
.addParameter('string', _('File path'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
|
||||
.setFunctionName('gdjs.fileSystem.getFileName');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'ExtensionName',
|
||||
_('Get the extension from a file path'),
|
||||
_(
|
||||
'Returns the extension of the file designated by the given path, including the extension period. For example: ".txt".'
|
||||
),
|
||||
_('Filesystem/Windows, Linux, MacOS'),
|
||||
'JsPlatform/Extensions/filesystem_folder32.png'
|
||||
)
|
||||
.addParameter('string', _('File path'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
|
||||
.setFunctionName('gdjs.fileSystem.getExtensionName');
|
||||
|
||||
return extension;
|
||||
},
|
||||
runExtensionSanityTests: function(gd /*: libGDevelop */, extension /*: gdPlatformExtension*/) {
|
||||
runExtensionSanityTests: function (
|
||||
gd /*: libGDevelop */,
|
||||
extension /*: gdPlatformExtension*/
|
||||
) {
|
||||
return [];
|
||||
},
|
||||
};
|
||||
|
@@ -1,11 +1,58 @@
|
||||
// @ts-check
|
||||
/**
|
||||
* @memberof gdjs
|
||||
* @class fileSystem
|
||||
* @static
|
||||
* @namespace fileSystem
|
||||
* @private
|
||||
*/
|
||||
|
||||
gdjs.fileSystem = {};
|
||||
gdjs.fileSystem = {
|
||||
_path: null, // The Node.js path module, or null if it can't be loaded.
|
||||
_fs: null, // The Node.js fs module, or null if it can't be loaded.
|
||||
};
|
||||
|
||||
/** Get the Node.js path module, or null if it can't be loaded */
|
||||
gdjs.fileSystem._getPath = function() {
|
||||
if (!gdjs.fileSystem._path) {
|
||||
// @ts-ignore
|
||||
gdjs.fileSystem._path = typeof require !== 'undefined' ? require('path') : null;
|
||||
}
|
||||
|
||||
return gdjs.fileSystem._path;
|
||||
}
|
||||
|
||||
/** Get the Node.js fs module, or null if it can't be loaded */
|
||||
gdjs.fileSystem._getFs = function() {
|
||||
if (!gdjs.fileSystem._fs) {
|
||||
// @ts-ignore
|
||||
gdjs.fileSystem._fs = typeof require !== 'undefined' ? require('fs') : null;
|
||||
}
|
||||
|
||||
return gdjs.fileSystem._fs;
|
||||
}
|
||||
|
||||
/** @param {string} fileOrFolderPath */
|
||||
gdjs.fileSystem.getDirectoryName = function(fileOrFolderPath) {
|
||||
const path = gdjs.fileSystem._getPath();
|
||||
if (!path) return '';
|
||||
|
||||
return path.dirname(fileOrFolderPath);
|
||||
}
|
||||
|
||||
/** @param {string} filePath */
|
||||
gdjs.fileSystem.getFileName = function(filePath) {
|
||||
const path = gdjs.fileSystem._getPath();
|
||||
if (!path) return '';
|
||||
|
||||
return path.basename(filePath);
|
||||
}
|
||||
|
||||
/** @param {string} filePath */
|
||||
gdjs.fileSystem.getExtensionName = function(filePath) {
|
||||
const path = gdjs.fileSystem._getPath();
|
||||
if (!path) return '';
|
||||
|
||||
return path.extname(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to 'Desktop' folder.
|
||||
@@ -62,9 +109,9 @@ gdjs.fileSystem.getPicturesPath = function(runtimeScene) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the path to this application 'Executable' folder.
|
||||
* Get the path to this application 'Executable' file.
|
||||
* @param {gdjs.RuntimeScene} runtimeScene The current scene
|
||||
* @return {string} The path to this applications executable folder
|
||||
* @return {string} The path to this applications executable file
|
||||
*/
|
||||
gdjs.fileSystem.getExecutablePath = function(runtimeScene) {
|
||||
const electron = runtimeScene
|
||||
@@ -79,6 +126,22 @@ gdjs.fileSystem.getExecutablePath = function(runtimeScene) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the path to this application 'Executable' folder.
|
||||
* @param {gdjs.RuntimeScene} runtimeScene The current scene
|
||||
* @return {string} The path to this applications executable folder
|
||||
*/
|
||||
gdjs.fileSystem.getExecutableFolderPath = function(runtimeScene) {
|
||||
const path = gdjs.fileSystem._getPath();
|
||||
const executablePath = gdjs.fileSystem.getExecutablePath(runtimeScene);
|
||||
|
||||
if (!path) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return path.dirname(executablePath);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the path to 'UserData' folder.
|
||||
* @param {gdjs.RuntimeScene} runtimeScene The current scene
|
||||
@@ -101,7 +164,7 @@ gdjs.fileSystem.getUserdataPath = function(runtimeScene) {
|
||||
* Get the path to the user's home folder (on Windows `C:\Users\<USERNAME>\` for example).
|
||||
* @return {string} The path to user's "home" folder
|
||||
*/
|
||||
gdjs.fileSystem.getUserHomePath = function() {
|
||||
gdjs.fileSystem.getUserHomePath = function(runtimeScene) {
|
||||
const electron = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
@@ -137,7 +200,7 @@ gdjs.fileSystem.getTempPath = function(runtimeScene) {
|
||||
* @return {string} The path delimiter
|
||||
*/
|
||||
gdjs.fileSystem.getPathDelimiter = function() {
|
||||
const path = typeof require !== 'undefined' ? require('path') : null;
|
||||
const path = gdjs.fileSystem._getPath();
|
||||
|
||||
if (path) {
|
||||
return path.sep || '/';
|
||||
@@ -152,7 +215,7 @@ gdjs.fileSystem.getPathDelimiter = function() {
|
||||
* @param {gdjs.Variable} resultVar The variable where to store the result of the operation
|
||||
*/
|
||||
gdjs.fileSystem.makeDirectory = function(directory, resultVar) {
|
||||
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
let result = 'error';
|
||||
|
||||
if (fileSystem) {
|
||||
@@ -176,7 +239,7 @@ gdjs.fileSystem.makeDirectory = function(directory, resultVar) {
|
||||
* @param {gdjs.Variable} resultVar The variable where to store the result of the operation
|
||||
*/
|
||||
gdjs.fileSystem.saveStringToFileAsync = function(text, savePath, resultVar) {
|
||||
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
|
||||
if (fileSystem) {
|
||||
fileSystem.writeFile(savePath, text, 'utf8', err => {
|
||||
@@ -199,7 +262,7 @@ gdjs.fileSystem.saveStringToFileAsync = function(text, savePath, resultVar) {
|
||||
* @param {gdjs.Variable} resultVar The variable where to store the result of the operation
|
||||
*/
|
||||
gdjs.fileSystem.saveStringToFile = function(text, savePath, resultVar) {
|
||||
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
let result = 'error';
|
||||
|
||||
if (fileSystem) {
|
||||
@@ -227,7 +290,7 @@ gdjs.fileSystem.saveVariableToJSONFile = function(
|
||||
savePath,
|
||||
resultVar
|
||||
) {
|
||||
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
const network = gdjs.evtTools.network;
|
||||
let result = 'error';
|
||||
|
||||
@@ -251,7 +314,7 @@ gdjs.fileSystem.saveVariableToJSONFile = function(
|
||||
|
||||
/**
|
||||
* Save a variable into a file in JSON format, asynchronously.
|
||||
* @param {string} text The variable to be saved
|
||||
* @param {gdjs.Variable} variable The variable to be saved
|
||||
* @param {string} savePath Path to the file
|
||||
* @param {gdjs.Variable} resultVar The variable where to store the result of the operation
|
||||
*/
|
||||
@@ -260,7 +323,7 @@ gdjs.fileSystem.saveVariableToJSONFileAsync = function(
|
||||
savePath,
|
||||
resultVar
|
||||
) {
|
||||
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
const network = gdjs.evtTools.network;
|
||||
|
||||
if (fileSystem && network) {
|
||||
@@ -289,7 +352,7 @@ gdjs.fileSystem.saveVariableToJSONFileAsync = function(
|
||||
* @param {gdjs.Variable} resultVar The variable where to store the result of the operation
|
||||
*/
|
||||
gdjs.fileSystem.loadStringFromFile = function(stringVar, loadPath, resultVar) {
|
||||
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
let result = 'error';
|
||||
|
||||
if (fileSystem) {
|
||||
@@ -321,7 +384,7 @@ gdjs.fileSystem.loadVariableFromJSONFile = function(
|
||||
loadPath,
|
||||
resultVar
|
||||
) {
|
||||
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
const network = gdjs.evtTools.network;
|
||||
let result = 'error';
|
||||
|
||||
@@ -353,7 +416,7 @@ gdjs.fileSystem.loadVariableFromJSONFileAsync = function(
|
||||
loadPath,
|
||||
resultVar
|
||||
) {
|
||||
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
const network = gdjs.evtTools.network;
|
||||
|
||||
if (fileSystem && network) {
|
||||
@@ -384,7 +447,7 @@ gdjs.fileSystem.loadStringFromFileAsync = function(
|
||||
loadPath,
|
||||
resultVar
|
||||
) {
|
||||
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
|
||||
if (fileSystem) {
|
||||
fileSystem.readFile(loadPath, 'utf8', (err, data) => {
|
||||
@@ -409,7 +472,7 @@ gdjs.fileSystem.loadStringFromFileAsync = function(
|
||||
* @param {gdjs.Variable} resultVar The variable where to store the result of the operation
|
||||
*/
|
||||
gdjs.fileSystem.deleteFile = function(filePath, resultVar) {
|
||||
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
let result = 'error';
|
||||
|
||||
if (fileSystem) {
|
||||
@@ -430,7 +493,7 @@ gdjs.fileSystem.deleteFile = function(filePath, resultVar) {
|
||||
* @param {gdjs.Variable} resultVar The variable where to store the result of the operation
|
||||
*/
|
||||
gdjs.fileSystem.deleteFileAsync = function(filePath, resultVar) {
|
||||
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
|
||||
if (fileSystem) {
|
||||
fileSystem.unlink(filePath, err => {
|
||||
@@ -449,7 +512,7 @@ gdjs.fileSystem.deleteFileAsync = function(filePath, resultVar) {
|
||||
* @return {boolean} true if fhe file or directory exists
|
||||
*/
|
||||
gdjs.fileSystem.pathExists = function(filePath) {
|
||||
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
|
||||
if (fileSystem) {
|
||||
return fileSystem.existsSync(filePath);
|
||||
|
429
Extensions/Lighting/JsExtension.js
Normal file
429
Extensions/Lighting/JsExtension.js
Normal file
@@ -0,0 +1,429 @@
|
||||
// @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(
|
||||
'Lighting',
|
||||
_('Lights'),
|
||||
_(
|
||||
'Allow to display lights on the screen and mark objects as obstacles for the lights.'
|
||||
),
|
||||
'Harsimran Virk',
|
||||
'MIT'
|
||||
);
|
||||
|
||||
const lightObstacleBehavior = new gd.BehaviorJsImplementation();
|
||||
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
|
||||
lightObstacleBehavior.updateProperty = function (
|
||||
behaviorContent,
|
||||
propertyName,
|
||||
newValue
|
||||
) {
|
||||
return false;
|
||||
};
|
||||
|
||||
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
|
||||
lightObstacleBehavior.getProperties = function (behaviorContent) {
|
||||
const behaviorProperties = new gd.MapStringPropertyDescriptor();
|
||||
|
||||
return behaviorProperties;
|
||||
};
|
||||
|
||||
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
|
||||
lightObstacleBehavior.initializeContent = function (behaviorContent) {};
|
||||
extension
|
||||
.addBehavior(
|
||||
'LightObstacleBehavior',
|
||||
_('Light Obstacle Behavior'),
|
||||
'LightObstacleBehavior',
|
||||
_(
|
||||
'This behavior makes the object an obstacle to the light. The light emitted by light objects will be stopped by the object.'
|
||||
),
|
||||
'',
|
||||
'CppPlatform/Extensions/lightObstacleIcon32.png',
|
||||
'LightObstacleBehavior',
|
||||
lightObstacleBehavior,
|
||||
new gd.BehaviorsSharedData()
|
||||
)
|
||||
.setIncludeFile('Extensions/Lighting/lightobstacleruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/Lighting/lightruntimeobject.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Lighting/lightruntimeobject-pixi-renderer.js'
|
||||
);
|
||||
|
||||
const lightObject = new gd.ObjectJsImplementation();
|
||||
|
||||
// $FlowExpectedError - ignore Flow warning as we're creating an object.
|
||||
lightObject.updateProperty = function (
|
||||
objectContent,
|
||||
propertyName,
|
||||
newValue
|
||||
) {
|
||||
if (propertyName === 'radius') {
|
||||
objectContent.radius = parseFloat(newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (propertyName === 'color') {
|
||||
objectContent.color = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (propertyName === 'debugMode') {
|
||||
objectContent.debugMode = newValue === '1';
|
||||
return true;
|
||||
}
|
||||
|
||||
if (propertyName === 'texture') {
|
||||
objectContent.texture = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// $FlowExpectedError - ignore Flow warning as we're creating an object.
|
||||
lightObject.getProperties = function (objectContent) {
|
||||
const objectProperties = new gd.MapStringPropertyDescriptor();
|
||||
|
||||
objectProperties.set(
|
||||
'radius',
|
||||
new gd.PropertyDescriptor(objectContent.radius.toString())
|
||||
.setType('number')
|
||||
.setLabel(_('Radius'))
|
||||
);
|
||||
|
||||
objectProperties.set(
|
||||
'color',
|
||||
new gd.PropertyDescriptor(objectContent.color)
|
||||
.setType('color')
|
||||
.setLabel(_('Color'))
|
||||
);
|
||||
|
||||
objectProperties.set(
|
||||
'debugMode',
|
||||
new gd.PropertyDescriptor(objectContent.debugMode ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Debug mode'))
|
||||
.setDescription(
|
||||
_(
|
||||
'When activated, display the lines used to render the light - useful to understand how the light is rendered on screen.'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('texture')
|
||||
.setValue(objectContent.texture)
|
||||
.setType('resource')
|
||||
.addExtraInfo('image')
|
||||
.setLabel(_('Light texture (optional)'))
|
||||
.setDescription(
|
||||
_(
|
||||
"A texture to be used to display the light. If you don't specify a texture, the light is rendered as fading from bright, in its center, to dark."
|
||||
)
|
||||
);
|
||||
|
||||
return objectProperties;
|
||||
};
|
||||
lightObject.setRawJSONContent(
|
||||
JSON.stringify({
|
||||
radius: 50,
|
||||
color: '#ffffff',
|
||||
debugMode: false,
|
||||
texture: '',
|
||||
})
|
||||
);
|
||||
|
||||
// $FlowExpectedError - ignore Flow warning as we're creating an object.
|
||||
lightObject.updateInitialInstanceProperty = function (
|
||||
objectContent,
|
||||
instance,
|
||||
propertyName,
|
||||
newValue,
|
||||
project,
|
||||
layout
|
||||
) {
|
||||
return false;
|
||||
};
|
||||
|
||||
// $FlowExpectedError - ignore Flow warning as we're creating an object.
|
||||
lightObject.getInitialInstanceProperties = function (
|
||||
content,
|
||||
instance,
|
||||
project,
|
||||
layout
|
||||
) {
|
||||
const instanceProperties = new gd.MapStringPropertyDescriptor();
|
||||
|
||||
return instanceProperties;
|
||||
};
|
||||
|
||||
const object = extension
|
||||
.addObject(
|
||||
'LightObject',
|
||||
_('Light'),
|
||||
_(
|
||||
'Displays a light on the scene, with a customizable radius and color. Add then the Light Obstacle behavior to the objects that must act as obstacle to the lights.'
|
||||
),
|
||||
'CppPlatform/Extensions/lightIcon32.png',
|
||||
lightObject
|
||||
)
|
||||
.setIncludeFile('Extensions/Lighting/lightruntimeobject.js')
|
||||
.addIncludeFile('Extensions/Lighting/lightruntimeobject-pixi-renderer.js')
|
||||
.addIncludeFile('Extensions/Lighting/lightobstacleruntimebehavior.js');
|
||||
|
||||
object
|
||||
.addAction(
|
||||
'SetRadius',
|
||||
_('Set the radius of light object'),
|
||||
_('Set the radius of light object'),
|
||||
_('Set the radius of _PARAM0_ to: _PARAM1_'),
|
||||
'',
|
||||
'CppPlatform/Extensions/lightIcon24.png',
|
||||
'CppPlatform/Extensions/lightIcon16.png'
|
||||
)
|
||||
.addParameter('object', _('Object'), 'LightObject', false)
|
||||
.addParameter('expression', _('Radius'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('setRadius');
|
||||
|
||||
object
|
||||
.addAction(
|
||||
'SetColor',
|
||||
_('Set the color of light object'),
|
||||
_('Set the color of light object in format "R;G;B" string.'),
|
||||
_('Set the color of _PARAM0_ to: _PARAM1_'),
|
||||
'',
|
||||
'res/actions/color24.png',
|
||||
'res/actions/color.png'
|
||||
)
|
||||
.addParameter('object', _('Object'), 'LightObject', false)
|
||||
.addParameter('string', _('Color'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('setColor');
|
||||
|
||||
return extension;
|
||||
},
|
||||
|
||||
runExtensionSanityTests: function (
|
||||
gd /*: libGDevelop */,
|
||||
extension /*: gdPlatformExtension*/
|
||||
) {
|
||||
return [];
|
||||
},
|
||||
|
||||
registerEditorConfigurations: function (
|
||||
objectsEditorService /*: ObjectsEditorService */
|
||||
) {
|
||||
objectsEditorService.registerEditorConfiguration(
|
||||
'Lighting::LightObject',
|
||||
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
|
||||
helpPagePath: '/objects/light',
|
||||
})
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Register renderers for instance of objects on the scene editor.
|
||||
*
|
||||
* ℹ️ Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
|
||||
*/
|
||||
registerInstanceRenderers: function (
|
||||
objectsRenderingService /*: ObjectsRenderingService */
|
||||
) {
|
||||
const RenderedInstance = objectsRenderingService.RenderedInstance;
|
||||
const PIXI = objectsRenderingService.PIXI;
|
||||
|
||||
/**
|
||||
* Renderer for instances of LightObject inside the IDE.
|
||||
*
|
||||
* @extends RenderedInstance
|
||||
* @class RenderedLightObjectInstance
|
||||
* @constructor
|
||||
*/
|
||||
function RenderedLightObjectInstance(
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
) {
|
||||
RenderedInstance.call(
|
||||
this,
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
);
|
||||
this._radius = parseFloat(
|
||||
this._associatedObject
|
||||
.getProperties(this.project)
|
||||
.get('radius')
|
||||
.getValue()
|
||||
);
|
||||
if (this._radius <= 0) this._radius = 1;
|
||||
this._colorHex = parseInt(
|
||||
this._associatedObject
|
||||
.getProperties(this.project)
|
||||
.get('color')
|
||||
.getValue()
|
||||
.replace('#', ''),
|
||||
16
|
||||
);
|
||||
this._color = [
|
||||
((this._colorHex >> 16) & 0xff) / 255,
|
||||
((this._colorHex >> 8) & 0xff) / 255,
|
||||
(this._colorHex & 0xff) / 255,
|
||||
];
|
||||
|
||||
const geometry = new PIXI.Geometry();
|
||||
const shader = PIXI.Shader.from(
|
||||
`
|
||||
precision mediump float;
|
||||
attribute vec2 aVertexPosition;
|
||||
|
||||
uniform mat3 translationMatrix;
|
||||
uniform mat3 projectionMatrix;
|
||||
varying vec2 vPos;
|
||||
|
||||
void main() {
|
||||
vPos = aVertexPosition;
|
||||
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
|
||||
}`,
|
||||
`
|
||||
precision mediump float;
|
||||
uniform vec2 center;
|
||||
uniform float radius;
|
||||
uniform vec3 color;
|
||||
uniform mat3 translationMatrix;
|
||||
uniform mat3 projectionMatrix;
|
||||
|
||||
varying vec2 vPos;
|
||||
|
||||
void main() {
|
||||
float l = length(vPos - center);
|
||||
float intensity = 0.0;
|
||||
if(l < radius)
|
||||
intensity = clamp((radius - l)*(radius - l)/(radius*radius), 0.0, 1.0);
|
||||
gl_FragColor = vec4(color*intensity, 1.0);
|
||||
}
|
||||
`,
|
||||
{
|
||||
center: [this._instance.getX(), this._instance.getY()],
|
||||
radius: this._radius,
|
||||
color: this._color,
|
||||
}
|
||||
);
|
||||
|
||||
this._vertexBuffer = new Float32Array([
|
||||
this._instance.getX() - this._radius,
|
||||
this._instance.getY() + this._radius,
|
||||
this._instance.getX() + this._radius,
|
||||
this._instance.getY() + this._radius,
|
||||
this._instance.getX() + this._radius,
|
||||
this._instance.getY() - this._radius,
|
||||
this._instance.getX() - this._radius,
|
||||
this._instance.getY() - this._radius,
|
||||
]);
|
||||
|
||||
geometry
|
||||
.addAttribute('aVertexPosition', this._vertexBuffer, 2)
|
||||
.addIndex([0, 1, 2, 2, 3, 0]);
|
||||
|
||||
this._pixiObject = new PIXI.Mesh(geometry, shader);
|
||||
this._pixiObject.blendMode = PIXI.BLEND_MODES.ADD;
|
||||
this._pixiContainer.addChild(this._pixiObject);
|
||||
this.update();
|
||||
}
|
||||
RenderedLightObjectInstance.prototype = Object.create(
|
||||
RenderedInstance.prototype
|
||||
);
|
||||
|
||||
/**
|
||||
* Return the path to the thumbnail of the specified object.
|
||||
*/
|
||||
RenderedLightObjectInstance.getThumbnail = function (
|
||||
project,
|
||||
resourcesLoader,
|
||||
object
|
||||
) {
|
||||
return 'CppPlatform/Extensions/lightIcon32.png';
|
||||
};
|
||||
|
||||
/**
|
||||
* This is called to update the PIXI object on the scene editor
|
||||
*/
|
||||
RenderedLightObjectInstance.prototype.update = function () {
|
||||
this._pixiObject.shader.uniforms.center = new Float32Array([
|
||||
this._instance.getX(),
|
||||
this._instance.getY(),
|
||||
]);
|
||||
|
||||
this._vertexBuffer[0] = this._instance.getX() - this._radius;
|
||||
this._vertexBuffer[1] = this._instance.getY() + this._radius;
|
||||
this._vertexBuffer[2] = this._instance.getX() + this._radius;
|
||||
this._vertexBuffer[3] = this._instance.getY() + this._radius;
|
||||
this._vertexBuffer[4] = this._instance.getX() + this._radius;
|
||||
this._vertexBuffer[5] = this._instance.getY() - this._radius;
|
||||
this._vertexBuffer[6] = this._instance.getX() - this._radius;
|
||||
this._vertexBuffer[7] = this._instance.getY() - this._radius;
|
||||
|
||||
this._pixiObject.geometry
|
||||
.getBuffer('aVertexPosition')
|
||||
.update(this._vertexBuffer);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the width of the instance, when it's not resized.
|
||||
*/
|
||||
RenderedLightObjectInstance.prototype.getDefaultWidth = function () {
|
||||
return this._pixiObject.width;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the height of the instance, when it's not resized.
|
||||
*/
|
||||
RenderedLightObjectInstance.prototype.getDefaultHeight = function () {
|
||||
return this._pixiObject.height;
|
||||
};
|
||||
|
||||
RenderedLightObjectInstance.prototype.getOriginX = function () {
|
||||
return this._radius;
|
||||
};
|
||||
|
||||
RenderedLightObjectInstance.prototype.getOriginY = function () {
|
||||
return this._radius;
|
||||
};
|
||||
|
||||
objectsRenderingService.registerInstanceRenderer(
|
||||
'Lighting::LightObject',
|
||||
RenderedLightObjectInstance
|
||||
);
|
||||
},
|
||||
};
|
153
Extensions/Lighting/lightobstacleruntimebehavior.js
Normal file
153
Extensions/Lighting/lightobstacleruntimebehavior.js
Normal file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* @memberof gdjs
|
||||
* @class LightObstaclesManager
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
*/
|
||||
gdjs.LightObstaclesManager = function (runtimeScene) {
|
||||
this._obstacleRBush = new rbush(9, [
|
||||
'.owner.getAABB().min[0]',
|
||||
'.owner.getAABB().min[1]',
|
||||
'.owner.getAABB().max[0]',
|
||||
'.owner.getAABB().max[1]',
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the light obstacles manager of a scene.
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @returns {gdjs.LightObstaclesManager}
|
||||
*/
|
||||
gdjs.LightObstaclesManager.getManager = function (runtimeScene) {
|
||||
if (!runtimeScene._lightObstaclesManager) {
|
||||
// Create the shared manager if necessary.
|
||||
runtimeScene._lightObstaclesManager = new gdjs.LightObstaclesManager(
|
||||
runtimeScene
|
||||
);
|
||||
}
|
||||
|
||||
return runtimeScene._lightObstaclesManager;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a light obstacle to the list of existing obstacles.
|
||||
* @param {gdjs.LightObstacleRuntimeBehavior} obstacle
|
||||
*/
|
||||
gdjs.LightObstaclesManager.prototype.addObstacle = function (obstacle) {
|
||||
this._obstacleRBush.insert(obstacle);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a light obstacle from the list of existing obstacles. Be sure that the obstacle was
|
||||
* added before.
|
||||
* @param {gdjs.LightObstacleRuntimeBehavior} obstacle
|
||||
*/
|
||||
gdjs.LightObstaclesManager.prototype.removeObstacle = function (obstacle) {
|
||||
this._obstacleRBush.remove(obstacle);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns all the light obstacles around the specified object.
|
||||
* @param {gdjs.RuntimeObject} object The object
|
||||
* @param {number} radius Radius of the area to be searched.
|
||||
* @param {gdjs.RuntimeObject[]} result An array with all obstacles near the object.
|
||||
*/
|
||||
gdjs.LightObstaclesManager.prototype.getAllObstaclesAround = function (
|
||||
object,
|
||||
radius,
|
||||
result
|
||||
) {
|
||||
// TODO: This would better be done using the object AABB (getAABB), as (`getCenterX`;`getCenterY`) point
|
||||
// is not necessarily in the middle of the object (for sprites for example).
|
||||
var x = object.getX();
|
||||
var y = object.getY();
|
||||
|
||||
var searchArea = gdjs.staticObject(
|
||||
gdjs.LightObstaclesManager.prototype.getAllObstaclesAround
|
||||
);
|
||||
searchArea.minX = x - radius;
|
||||
searchArea.minY = y - radius;
|
||||
searchArea.maxX = x + radius;
|
||||
searchArea.maxY = y + radius;
|
||||
var nearbyObstacles = this._obstacleRBush.search(searchArea);
|
||||
result.length = 0;
|
||||
result.push.apply(result, nearbyObstacles);
|
||||
};
|
||||
|
||||
/**
|
||||
* @memberof gdjs
|
||||
* @class LightObstacleRuntimeBehavior
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {BehaviorData} behaviorData
|
||||
* @param {gdjs.RuntimeObject} owner
|
||||
*/
|
||||
gdjs.LightObstacleRuntimeBehavior = function (
|
||||
runtimeScene,
|
||||
behaviorData,
|
||||
owner
|
||||
) {
|
||||
gdjs.RuntimeBehavior.call(this, runtimeScene, behaviorData, owner);
|
||||
|
||||
this._oldX = 0;
|
||||
this._oldY = 0;
|
||||
this._oldWidth = 0;
|
||||
this._oldHeight = 0;
|
||||
this._manager = gdjs.LightObstaclesManager.getManager(runtimeScene);
|
||||
this._registeredInManager = false;
|
||||
};
|
||||
|
||||
gdjs.LightObstacleRuntimeBehavior.prototype = Object.create(
|
||||
gdjs.RuntimeBehavior.prototype
|
||||
);
|
||||
gdjs.registerBehavior(
|
||||
'Lighting::LightObstacleBehavior',
|
||||
gdjs.LightObstacleRuntimeBehavior
|
||||
);
|
||||
|
||||
gdjs.LightObstacleRuntimeBehavior.prototype.doStepPreEvents = function (
|
||||
runtimeScene
|
||||
) {
|
||||
// Make sure the obstacle is or is not in the obstacles manager.
|
||||
if (!this.activated() && this._registeredInManager) {
|
||||
this._manager.removeObstacle(this);
|
||||
this._registeredInManager = false;
|
||||
} else if (this.activated() && !this._registeredInManager) {
|
||||
this._manager.addObstacle(this);
|
||||
this._registeredInManager = true;
|
||||
}
|
||||
|
||||
//Track changes in size or position
|
||||
if (
|
||||
this._oldX !== this.owner.getX() ||
|
||||
this._oldY !== this.owner.getY() ||
|
||||
this._oldWidth !== this.owner.getWidth() ||
|
||||
this._oldHeight !== this.owner.getHeight()
|
||||
) {
|
||||
if (this._registeredInManager) {
|
||||
this._manager.removeObstacle(this);
|
||||
this._manager.addObstacle(this);
|
||||
}
|
||||
this._oldX = this.owner.getX();
|
||||
this._oldY = this.owner.getY();
|
||||
this._oldWidth = this.owner.getWidth();
|
||||
this._oldHeight = this.owner.getHeight();
|
||||
}
|
||||
};
|
||||
|
||||
gdjs.LightObstacleRuntimeBehavior.prototype.onDestroy = function () {
|
||||
if (this._manager && this._registeredInManager)
|
||||
this._manager.removeObstacle(this);
|
||||
};
|
||||
|
||||
gdjs.LightObstacleRuntimeBehavior.prototype.onActivate = function () {
|
||||
if (this._registeredInManager) return;
|
||||
|
||||
this._manager.addObstacle(this);
|
||||
this._registeredInManager = true;
|
||||
};
|
||||
|
||||
gdjs.LightObstacleRuntimeBehavior.prototype.onDeActivate = function () {
|
||||
if (!this._registeredInManager) return;
|
||||
|
||||
this._manager.removeObstacle(this);
|
||||
this._registeredInManager = false;
|
||||
};
|
545
Extensions/Lighting/lightruntimeobject-pixi-renderer.js
Normal file
545
Extensions/Lighting/lightruntimeobject-pixi-renderer.js
Normal file
@@ -0,0 +1,545 @@
|
||||
/**
|
||||
* Pixi renderer for light runtime objects.
|
||||
*
|
||||
* @memberof gdjs
|
||||
* @constructor LightRuntimeObjectPixiRenderer
|
||||
* @param {gdjs.LightRuntimeObject} runtimeObject
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
*/
|
||||
gdjs.LightRuntimeObjectPixiRenderer = function (runtimeObject, runtimeScene) {
|
||||
this._object = runtimeObject;
|
||||
this._runtimeScene = runtimeScene;
|
||||
this._manager = runtimeObject.getObstaclesManager();
|
||||
this._radius = runtimeObject.getRadius();
|
||||
var objectColor = runtimeObject._color;
|
||||
this._color = [
|
||||
objectColor[0] / 255,
|
||||
objectColor[1] / 255,
|
||||
objectColor[2] / 255,
|
||||
];
|
||||
|
||||
/** @type {?PIXI.Texture} */
|
||||
this._texture = null;
|
||||
this.updateTexture();
|
||||
|
||||
this._center = new Float32Array([runtimeObject.x, runtimeObject.y]);
|
||||
this._defaultVertexBuffer = new Float32Array(8);
|
||||
this._vertexBuffer = new Float32Array([
|
||||
runtimeObject.x - this._radius,
|
||||
runtimeObject.y + this._radius,
|
||||
runtimeObject.x + this._radius,
|
||||
runtimeObject.y + this._radius,
|
||||
runtimeObject.x + this._radius,
|
||||
runtimeObject.y - this._radius,
|
||||
runtimeObject.x - this._radius,
|
||||
runtimeObject.y - this._radius,
|
||||
]);
|
||||
this._indexBuffer = new Uint16Array([0, 1, 2, 0, 2, 3]);
|
||||
|
||||
/** @type {?PIXI.Mesh} */
|
||||
this._light = null;
|
||||
this.updateMesh();
|
||||
|
||||
this._isPreview = runtimeScene.getGame().isPreview();
|
||||
this._debugMode = null;
|
||||
/** @type {?PIXI.Container} */
|
||||
this._debugLight = null;
|
||||
/** @type {?PIXI.Graphics} */
|
||||
this._debugGraphics = null;
|
||||
this.updateDebugMode();
|
||||
|
||||
/** @type {gdjs.Polygon} */
|
||||
this._lightBoundingPoly = new gdjs.Polygon();
|
||||
for (var i = 0; i < 4; i++) {
|
||||
this._lightBoundingPoly.vertices.push(
|
||||
runtimeObject.getHitBoxes()[0].vertices[i]
|
||||
);
|
||||
}
|
||||
|
||||
// Objects will be added in lighting layer, this is just to maintain consistency.
|
||||
if (this._light)
|
||||
runtimeScene
|
||||
.getLayer('')
|
||||
.getRenderer()
|
||||
.addRendererObject(this.getRendererObject(), runtimeObject.getZOrder());
|
||||
};
|
||||
|
||||
gdjs.LightRuntimeObjectRenderer = gdjs.LightRuntimeObjectPixiRenderer; //Register the class to let the engine use it.
|
||||
|
||||
gdjs.LightRuntimeObjectPixiRenderer._defaultIndexBuffer = new Uint16Array([
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
]);
|
||||
|
||||
gdjs.LightRuntimeObjectPixiRenderer.defaultVertexShader = `
|
||||
precision mediump float;
|
||||
attribute vec2 aVertexPosition;
|
||||
|
||||
uniform mat3 translationMatrix;
|
||||
uniform mat3 projectionMatrix;
|
||||
varying vec2 vPos;
|
||||
|
||||
void main() {
|
||||
vPos = aVertexPosition;
|
||||
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
|
||||
}`;
|
||||
|
||||
gdjs.LightRuntimeObjectPixiRenderer.defaultFragmentShader = `
|
||||
precision mediump float;
|
||||
uniform vec2 center;
|
||||
uniform float radius;
|
||||
uniform vec3 color;
|
||||
varying vec2 vPos;
|
||||
|
||||
void main() {
|
||||
float l = length(vPos - center);
|
||||
float intensity = 0.0;
|
||||
if(l < radius)
|
||||
intensity = clamp((radius - l)*(radius - l)/(radius*radius), 0.0, 1.0);
|
||||
gl_FragColor = vec4(color*intensity, 1.0);
|
||||
}`;
|
||||
|
||||
gdjs.LightRuntimeObjectPixiRenderer.texturedFragmentShader = `
|
||||
precision mediump float;
|
||||
uniform vec2 center;
|
||||
uniform float radius;
|
||||
uniform vec3 color;
|
||||
uniform sampler2D uSampler;
|
||||
varying vec2 vPos;
|
||||
|
||||
void main() {
|
||||
vec2 topleft = vec2(center.x - radius, center.y - radius);
|
||||
vec2 texCoord = (vPos - topleft)/(2.0 * radius);
|
||||
gl_FragColor = vec4(color, 1.0) * texture2D(uSampler, texCoord);
|
||||
}`;
|
||||
|
||||
gdjs.LightRuntimeObjectPixiRenderer._verticesWithAngleComparator = function (
|
||||
vertexWithAngleA,
|
||||
vertexWithAngleB
|
||||
) {
|
||||
if (vertexWithAngleA.angle < vertexWithAngleB.angle) return -1;
|
||||
if (vertexWithAngleA.angle === vertexWithAngleB.angle) return 0;
|
||||
if (vertexWithAngleA.angle > vertexWithAngleB.angle) return 1;
|
||||
};
|
||||
|
||||
gdjs.LightRuntimeObjectPixiRenderer._computeClosestIntersectionPoint = function (
|
||||
lightObject,
|
||||
angle,
|
||||
polygons,
|
||||
boundingSquareHalfDiag
|
||||
) {
|
||||
var centerX = lightObject.getX();
|
||||
var centerY = lightObject.getY();
|
||||
var targetX = centerX + boundingSquareHalfDiag * Math.cos(angle);
|
||||
var targetY = centerY + boundingSquareHalfDiag * Math.sin(angle);
|
||||
var minSqDist = boundingSquareHalfDiag * boundingSquareHalfDiag;
|
||||
var closestPoint = [null, null];
|
||||
for (var poly of polygons) {
|
||||
var raycastResult = gdjs.Polygon.raycastTest(
|
||||
poly,
|
||||
centerX,
|
||||
centerY,
|
||||
targetX,
|
||||
targetY
|
||||
);
|
||||
|
||||
if (raycastResult.collision && raycastResult.closeSqDist <= minSqDist) {
|
||||
minSqDist = raycastResult.closeSqDist;
|
||||
closestPoint[0] = raycastResult.closeX;
|
||||
closestPoint[1] = raycastResult.closeY;
|
||||
}
|
||||
}
|
||||
if (closestPoint[0] && closestPoint[1]) return closestPoint;
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {?PIXI.Mesh | PIXI.Container}
|
||||
*/
|
||||
gdjs.LightRuntimeObjectPixiRenderer.prototype.getRendererObject = function () {
|
||||
if (this._debugLight) {
|
||||
return this._debugLight;
|
||||
}
|
||||
return this._light;
|
||||
};
|
||||
|
||||
gdjs.LightRuntimeObjectPixiRenderer.prototype.ensureUpToDate = function () {
|
||||
if (this._object.isHidden()) return;
|
||||
|
||||
if (this._debugGraphics) this._updateDebugGraphics();
|
||||
this._updateBuffers();
|
||||
};
|
||||
|
||||
gdjs.LightRuntimeObjectPixiRenderer.prototype.updateMesh = function () {
|
||||
if (!PIXI.utils.isWebGLSupported()) {
|
||||
console.warn(
|
||||
'This device does not support webgl, which is required for Lighting Extension.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.updateTexture();
|
||||
var fragmentShader =
|
||||
this._texture === null
|
||||
? gdjs.LightRuntimeObjectPixiRenderer.defaultFragmentShader
|
||||
: gdjs.LightRuntimeObjectPixiRenderer.texturedFragmentShader;
|
||||
var shaderUniforms = {
|
||||
center: this._center,
|
||||
radius: this._radius,
|
||||
color: this._color,
|
||||
};
|
||||
if (this._texture) {
|
||||
shaderUniforms.uSampler = this._texture;
|
||||
}
|
||||
var shader = PIXI.Shader.from(
|
||||
gdjs.LightRuntimeObjectPixiRenderer.defaultVertexShader,
|
||||
fragmentShader,
|
||||
shaderUniforms
|
||||
);
|
||||
var geometry = new PIXI.Geometry();
|
||||
geometry
|
||||
.addAttribute('aVertexPosition', this._vertexBuffer, 2)
|
||||
.addIndex(this._indexBuffer);
|
||||
if (!this._light) {
|
||||
this._light = new PIXI.Mesh(geometry, shader);
|
||||
this._light.blendMode = PIXI.BLEND_MODES.ADD;
|
||||
} else {
|
||||
this._light.shader = shader;
|
||||
this._light.geometry = geometry;
|
||||
}
|
||||
};
|
||||
|
||||
gdjs.LightRuntimeObjectPixiRenderer.prototype.updateRadius = function () {
|
||||
if (!this._light) return;
|
||||
|
||||
this._radius = this._object.getRadius();
|
||||
this._light.shader.uniforms.radius = this._radius;
|
||||
};
|
||||
|
||||
gdjs.LightRuntimeObjectPixiRenderer.prototype.updateColor = function () {
|
||||
if (!this._light) return;
|
||||
|
||||
var objectColor = this._object._color;
|
||||
this._color = [
|
||||
objectColor[0] / 255,
|
||||
objectColor[1] / 255,
|
||||
objectColor[2] / 255,
|
||||
];
|
||||
this._light.shader.uniforms.color = this._color;
|
||||
};
|
||||
|
||||
gdjs.LightRuntimeObjectPixiRenderer.prototype.updateTexture = function () {
|
||||
var texture = this._object.getTexture();
|
||||
this._texture =
|
||||
texture !== ''
|
||||
? this._runtimeScene.getGame().getImageManager().getPIXITexture(texture)
|
||||
: null;
|
||||
};
|
||||
|
||||
gdjs.LightRuntimeObjectPixiRenderer.prototype.updateDebugMode = function () {
|
||||
if (!this._light) return;
|
||||
|
||||
this._debugMode = this._object.getDebugMode();
|
||||
if (!this._debugLight && (this._isPreview || this._debugMode)) {
|
||||
this._debugLight = new PIXI.Container();
|
||||
this._debugLight.addChild(this._light);
|
||||
}
|
||||
|
||||
if (this._debugMode && !this._debugGraphics) {
|
||||
this._debugGraphics = new PIXI.Graphics();
|
||||
this._debugLight.addChild(this._debugGraphics);
|
||||
}
|
||||
|
||||
if (!this._debugMode && this._debugGraphics) {
|
||||
this._debugLight.removeChild(this._debugGraphics);
|
||||
this._debugGraphics.destroy();
|
||||
this._debugGraphics = null;
|
||||
}
|
||||
|
||||
this.ensureUpToDate();
|
||||
};
|
||||
|
||||
gdjs.LightRuntimeObjectPixiRenderer.prototype._updateDebugGraphics = function () {
|
||||
var computedVertices = this._computeLightVertices();
|
||||
|
||||
if (!computedVertices.length) {
|
||||
this._debugGraphics.clear();
|
||||
this._debugGraphics
|
||||
.lineStyle(1, 0xff0000, 1)
|
||||
.moveTo(this._object.x, this._object.y)
|
||||
.lineTo(this._object.x - this._radius, this._object.y + this._radius)
|
||||
.lineTo(this._object.x + this._radius, this._object.y + this._radius)
|
||||
.moveTo(this._object.x, this._object.y)
|
||||
.lineTo(this._object.x + this._radius, this._object.y + this._radius)
|
||||
.lineTo(this._object.x + this._radius, this._object.y - this._radius)
|
||||
.moveTo(this._object.x, this._object.y)
|
||||
.lineTo(this._object.x + this._radius, this._object.y - this._radius)
|
||||
.lineTo(this._object.x - this._radius, this._object.y - this._radius)
|
||||
.moveTo(this._object.x, this._object.y)
|
||||
.lineTo(this._object.x - this._radius, this._object.y - this._radius)
|
||||
.lineTo(this._object.x - this._radius, this._object.y + this._radius);
|
||||
return;
|
||||
}
|
||||
|
||||
var vertices = new Array(2 * computedVertices.length + 2);
|
||||
vertices[0] = this._object.x;
|
||||
vertices[1] = this._object.y;
|
||||
|
||||
for (var i = 2; i < 2 * computedVertices.length + 2; i += 2) {
|
||||
vertices[i] = computedVertices[i / 2 - 1][0];
|
||||
vertices[i + 1] = computedVertices[i / 2 - 1][1];
|
||||
}
|
||||
|
||||
this._debugGraphics.clear();
|
||||
this._debugGraphics.moveTo(vertices[2], vertices[3]);
|
||||
var verticesCount = vertices.length;
|
||||
for (var i = 2; i < verticesCount; i += 2) {
|
||||
var lineColor = i % 4 === 0 ? 0xff0000 : 0x00ff00;
|
||||
var lastX = i + 2 >= verticesCount ? 2 : i + 2;
|
||||
var lastY = i + 3 >= verticesCount ? 3 : i + 3;
|
||||
this._debugGraphics
|
||||
.lineStyle(1, lineColor, 1)
|
||||
.lineTo(vertices[i], vertices[i + 1])
|
||||
.lineTo(vertices[lastX], vertices[lastY])
|
||||
.moveTo(vertices[0], vertices[1])
|
||||
.lineTo(vertices[i], vertices[i + 1])
|
||||
.moveTo(vertices[0], vertices[1])
|
||||
.lineTo(vertices[lastX], vertices[lastY]);
|
||||
}
|
||||
};
|
||||
|
||||
gdjs.LightRuntimeObjectPixiRenderer.prototype._updateBuffers = function () {
|
||||
if (!this._light) return;
|
||||
|
||||
this._center[0] = this._object.x;
|
||||
this._center[1] = this._object.y;
|
||||
|
||||
var vertices = this._computeLightVertices();
|
||||
// Fallback to simple quad when there are no obstacles around.
|
||||
if (vertices.length === 0) {
|
||||
this._defaultVertexBuffer[0] = this._object.x - this._radius;
|
||||
this._defaultVertexBuffer[1] = this._object.y + this._radius;
|
||||
this._defaultVertexBuffer[2] = this._object.x + this._radius;
|
||||
this._defaultVertexBuffer[3] = this._object.y + this._radius;
|
||||
this._defaultVertexBuffer[4] = this._object.x + this._radius;
|
||||
this._defaultVertexBuffer[5] = this._object.y - this._radius;
|
||||
this._defaultVertexBuffer[6] = this._object.x - this._radius;
|
||||
this._defaultVertexBuffer[7] = this._object.y - this._radius;
|
||||
|
||||
this._light.shader.uniforms.center = this._center;
|
||||
this._light.geometry
|
||||
.getBuffer('aVertexPosition')
|
||||
.update(this._defaultVertexBuffer);
|
||||
this._light.geometry
|
||||
.getIndex()
|
||||
.update(gdjs.LightRuntimeObjectPixiRenderer._defaultIndexBuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
var verticesCount = vertices.length;
|
||||
|
||||
// If the array buffer which is already allocated is atmost
|
||||
// twice the size of memory required, we could avoid re-allocation
|
||||
// and instead use a subarray. Otherwise, allocate new array buffers as
|
||||
// there would be memory wastage.
|
||||
var isSubArrayUsed = false;
|
||||
var vertexBufferSubArray = null;
|
||||
var indexBufferSubArray = null;
|
||||
|
||||
if (this._vertexBuffer.length > 2 * verticesCount + 2) {
|
||||
if (this._vertexBuffer.length < 4 * verticesCount + 4) {
|
||||
isSubArrayUsed = true;
|
||||
vertexBufferSubArray = this._vertexBuffer.subarray(
|
||||
0,
|
||||
2 * verticesCount + 2
|
||||
);
|
||||
indexBufferSubArray = this._indexBuffer.subarray(0, 3 * verticesCount);
|
||||
} else {
|
||||
this._vertexBuffer = new Float32Array(2 * verticesCount + 2);
|
||||
this._indexBuffer = new Uint16Array(3 * verticesCount);
|
||||
}
|
||||
}
|
||||
|
||||
// When the allocated array buffer has less memory than
|
||||
// required, we'll have to allocated new array buffers.
|
||||
if (this._vertexBuffer.length < 2 * verticesCount + 2) {
|
||||
this._vertexBuffer = new Float32Array(2 * verticesCount + 2);
|
||||
this._indexBuffer = new Uint16Array(3 * verticesCount);
|
||||
}
|
||||
|
||||
this._vertexBuffer[0] = this._object.x;
|
||||
this._vertexBuffer[1] = this._object.y;
|
||||
|
||||
for (var i = 2; i < 2 * verticesCount + 2; i += 2) {
|
||||
this._vertexBuffer[i] = vertices[i / 2 - 1][0];
|
||||
this._vertexBuffer[i + 1] = vertices[i / 2 - 1][1];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 3 * verticesCount; i += 3) {
|
||||
this._indexBuffer[i] = 0;
|
||||
this._indexBuffer[i + 1] = i / 3 + 1;
|
||||
if (i / 3 + 1 !== verticesCount) this._indexBuffer[i + 2] = i / 3 + 2;
|
||||
else this._indexBuffer[i + 2] = 1;
|
||||
}
|
||||
|
||||
this._light.shader.uniforms.center = this._center;
|
||||
if (!isSubArrayUsed) {
|
||||
this._light.geometry
|
||||
.getBuffer('aVertexPosition')
|
||||
.update(this._vertexBuffer);
|
||||
this._light.geometry.getIndex().update(this._indexBuffer);
|
||||
} else {
|
||||
this._light.geometry
|
||||
.getBuffer('aVertexPosition')
|
||||
.update(vertexBufferSubArray);
|
||||
this._light.geometry.getIndex().update(indexBufferSubArray);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Computes the vertices of mesh using raycasting.
|
||||
* @returns {number[][]} the vertices of mesh.
|
||||
*/
|
||||
gdjs.LightRuntimeObjectPixiRenderer.prototype._computeLightVertices = function () {
|
||||
var lightObstacles = [];
|
||||
if (this._manager)
|
||||
this._manager.getAllObstaclesAround(
|
||||
this._object,
|
||||
this._radius,
|
||||
lightObstacles
|
||||
);
|
||||
|
||||
// Bail out early if there are no obstacles.
|
||||
if (lightObstacles.length === 0) return lightObstacles;
|
||||
|
||||
// Synchronize light bounding polygon with the hitbox.
|
||||
var lightHitboxPoly = this._object.getHitBoxes()[0];
|
||||
for (var i = 0; i < 4; i++) {
|
||||
for (var j = 0; j < 2; j++) {
|
||||
this._lightBoundingPoly.vertices[i][j] = lightHitboxPoly.vertices[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
var obstaclesCount = lightObstacles.length;
|
||||
var obstacleHitBoxes = new Array(obstaclesCount);
|
||||
for (var i = 0; i < obstaclesCount; i++) {
|
||||
obstacleHitBoxes[i] = lightObstacles[i].owner.getHitBoxes();
|
||||
}
|
||||
|
||||
var obstaclePolygons = [];
|
||||
obstaclePolygons.push(this._lightBoundingPoly);
|
||||
for (var i = 0; i < obstaclesCount; i++) {
|
||||
var noOfHitBoxes = obstacleHitBoxes[i].length;
|
||||
for (var j = 0; j < noOfHitBoxes; j++)
|
||||
obstaclePolygons.push(obstacleHitBoxes[i][j]);
|
||||
}
|
||||
|
||||
var maxX = this._object.x + this._radius;
|
||||
var minX = this._object.x - this._radius;
|
||||
var maxY = this._object.y + this._radius;
|
||||
var minY = this._object.y - this._radius;
|
||||
|
||||
var flattenVertices = [];
|
||||
for (var i = 1; i < obstaclePolygons.length; i++) {
|
||||
var vertices = obstaclePolygons[i].vertices;
|
||||
var verticesCount = vertices.length;
|
||||
for (var j = 0; j < verticesCount; j++) {
|
||||
flattenVertices.push(vertices[j]);
|
||||
|
||||
if (vertices[j][0] < minX) minX = vertices[j][0];
|
||||
if (vertices[j][0] > maxX) maxX = vertices[j][0];
|
||||
if (vertices[j][1] < minY) minY = vertices[j][1];
|
||||
if (vertices[j][1] > maxY) maxY = vertices[j][1];
|
||||
}
|
||||
}
|
||||
|
||||
obstaclePolygons[0].vertices[0][0] = minX;
|
||||
obstaclePolygons[0].vertices[0][1] = minY;
|
||||
obstaclePolygons[0].vertices[1][0] = maxX;
|
||||
obstaclePolygons[0].vertices[1][1] = minY;
|
||||
obstaclePolygons[0].vertices[2][0] = maxX;
|
||||
obstaclePolygons[0].vertices[2][1] = maxY;
|
||||
obstaclePolygons[0].vertices[3][0] = minX;
|
||||
obstaclePolygons[0].vertices[3][1] = maxY;
|
||||
|
||||
// Find the largest diagonal length.
|
||||
var boundingSquareHalfDiag = Math.sqrt(
|
||||
Math.max(
|
||||
(this._object.x - minX) * (this._object.x - minX) +
|
||||
(this._object.y - minY) * (this._object.y - minY),
|
||||
(maxX - this._object.x) * (maxX - this._object.x) +
|
||||
(this._object.y - minY) * (this._object.y - minY),
|
||||
(maxX - this._object.x) * (maxX - this._object.x) +
|
||||
(maxY - this._object.y) * (maxY - this._object.y),
|
||||
(this._object.x - minX) * (this._object.x - minX) +
|
||||
(maxY - this._object.y) * (maxY - this._object.y)
|
||||
)
|
||||
);
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
flattenVertices.push(obstaclePolygons[0].vertices[i]);
|
||||
}
|
||||
|
||||
var closestVertices = [];
|
||||
var flattenVerticesCount = flattenVertices.length;
|
||||
for (var i = 0; i < flattenVerticesCount; i++) {
|
||||
var xdiff = flattenVertices[i][0] - this._object.x;
|
||||
var ydiff = flattenVertices[i][1] - this._object.y;
|
||||
var angle = Math.atan2(ydiff, xdiff);
|
||||
|
||||
var closestVertex = gdjs.LightRuntimeObjectPixiRenderer._computeClosestIntersectionPoint(
|
||||
this._object,
|
||||
angle,
|
||||
obstaclePolygons,
|
||||
boundingSquareHalfDiag
|
||||
);
|
||||
if (closestVertex) {
|
||||
closestVertices.push({
|
||||
vertex: closestVertex,
|
||||
angle: angle,
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Check whether we need to raycast these two extra rays or not.
|
||||
var closestVertexOffsetLeft = gdjs.LightRuntimeObjectPixiRenderer._computeClosestIntersectionPoint(
|
||||
this._object,
|
||||
angle + 0.0001,
|
||||
obstaclePolygons,
|
||||
boundingSquareHalfDiag
|
||||
);
|
||||
if (closestVertexOffsetLeft) {
|
||||
closestVertices.push({
|
||||
vertex: closestVertexOffsetLeft,
|
||||
angle: angle + 0.0001,
|
||||
});
|
||||
}
|
||||
var closestVertexOffsetRight = gdjs.LightRuntimeObjectPixiRenderer._computeClosestIntersectionPoint(
|
||||
this._object,
|
||||
angle - 0.0001,
|
||||
obstaclePolygons,
|
||||
boundingSquareHalfDiag
|
||||
);
|
||||
if (closestVertexOffsetRight) {
|
||||
closestVertices.push({
|
||||
vertex: closestVertexOffsetRight,
|
||||
angle: angle - 0.0001,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
closestVertices.sort(
|
||||
gdjs.LightRuntimeObjectPixiRenderer._verticesWithAngleComparator
|
||||
);
|
||||
|
||||
var filteredVerticesResult = [closestVertices[0].vertex];
|
||||
var closestVerticesCount = closestVertices.length;
|
||||
for (var i = 1; i < closestVerticesCount; i++) {
|
||||
if (closestVertices[i].angle !== closestVertices[i - 1].angle)
|
||||
filteredVerticesResult.push(closestVertices[i].vertex);
|
||||
}
|
||||
|
||||
return filteredVerticesResult;
|
||||
};
|
193
Extensions/Lighting/lightruntimeobject.js
Normal file
193
Extensions/Lighting/lightruntimeobject.js
Normal file
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* @typedef {Object} LightObjectDataType
|
||||
* @property {Object} content The base parameters of light object.
|
||||
* @property {number} content.radius The radius of light object.
|
||||
* @property {string} content.color A string representing color in hexadecimal format.
|
||||
* @property {string} content.texture A string representing the name of texture used for light object.
|
||||
* @property {boolean} content.debugMode true if the light objects shows debug graphics, false otherwise.
|
||||
*
|
||||
* @typedef {ObjectData & LightObjectDataType} LightObjectData
|
||||
*/
|
||||
|
||||
/**
|
||||
* Displays a Light object.
|
||||
* @memberof gdjs
|
||||
* @class LightRuntimeObject
|
||||
* @extends RuntimeObject
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {LightObjectData} lightObjectData
|
||||
*/
|
||||
gdjs.LightRuntimeObject = function (runtimeScene, lightObjectData) {
|
||||
gdjs.RuntimeObject.call(this, runtimeScene, lightObjectData);
|
||||
|
||||
/** @type {number} */
|
||||
this._radius =
|
||||
lightObjectData.content.radius > 0 ? lightObjectData.content.radius : 1;
|
||||
|
||||
/** @type {number[]} color in format [r, g, b], where each component is in the range [0, 255] */
|
||||
this._color = gdjs.LightRuntimeObject.hexToRGBColor(
|
||||
lightObjectData.content.color
|
||||
);
|
||||
|
||||
/** @type {boolean} */
|
||||
this._debugMode = lightObjectData.content.debugMode;
|
||||
|
||||
/** @type {string} */
|
||||
this._texture = lightObjectData.content.texture;
|
||||
|
||||
/** @type {gdjs.LightObstaclesManager} */
|
||||
this._obstaclesManager = gdjs.LightObstaclesManager.getManager(runtimeScene);
|
||||
|
||||
if (this._renderer)
|
||||
gdjs.LightRuntimeObjectRenderer.call(this._renderer, this, runtimeScene);
|
||||
else this._renderer = new gdjs.LightRuntimeObjectRenderer(this, runtimeScene);
|
||||
|
||||
/** @type {gdjs.RuntimeScene} */
|
||||
this._runtimeScene = runtimeScene;
|
||||
|
||||
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
|
||||
this.onCreated();
|
||||
};
|
||||
|
||||
gdjs.LightRuntimeObject.prototype = Object.create(gdjs.RuntimeObject.prototype);
|
||||
gdjs.registerObject('Lighting::LightObject', gdjs.LightRuntimeObject);
|
||||
|
||||
gdjs.LightRuntimeObject.hexToRGBColor = function (hex) {
|
||||
var hexNumber = parseInt(hex.replace('#', ''), 16);
|
||||
return [(hexNumber >> 16) & 0xff, (hexNumber >> 8) & 0xff, hexNumber & 0xff];
|
||||
};
|
||||
|
||||
gdjs.LightRuntimeObject.prototype.getRendererObject = function () {
|
||||
return this._renderer.getRendererObject();
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {LightObjectData} oldObjectData
|
||||
* @param {LightObjectData} newObjectData
|
||||
*/
|
||||
gdjs.LightRuntimeObject.prototype.updateFromObjectData = function (
|
||||
oldObjectData,
|
||||
newObjectData
|
||||
) {
|
||||
if (oldObjectData.content.radius !== newObjectData.content.radius)
|
||||
this.setRadius(newObjectData.content.radius);
|
||||
|
||||
if (oldObjectData.content.color !== newObjectData.content.radius) {
|
||||
this._color = gdjs.LightRuntimeObject.hexToRGBColor(
|
||||
newObjectData.content.color
|
||||
);
|
||||
this._renderer.updateColor();
|
||||
}
|
||||
|
||||
if (oldObjectData.content.texture !== newObjectData.content.texture) {
|
||||
this._texture = newObjectData.content.texture;
|
||||
this._renderer.updateMesh();
|
||||
}
|
||||
|
||||
if (oldObjectData.content.debugMode !== newObjectData.content.debugMode) {
|
||||
this._debugMode = newObjectData.content.debugMode;
|
||||
this._renderer.updateDebugMode();
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
gdjs.LightRuntimeObject.prototype.update = function () {
|
||||
this._renderer.ensureUpToDate();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the radius of the light object.
|
||||
* @returns {number} radius of the light object.
|
||||
*/
|
||||
gdjs.LightRuntimeObject.prototype.getRadius = function () {
|
||||
return this._radius;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the radius of the light object.
|
||||
* @param {number} radius
|
||||
*/
|
||||
gdjs.LightRuntimeObject.prototype.setRadius = function (radius) {
|
||||
this._radius = radius > 0 ? radius : 1;
|
||||
this._renderer.updateRadius();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the height of the light object.
|
||||
* @returns {number} height of light object.
|
||||
*/
|
||||
gdjs.LightRuntimeObject.prototype.getHeight = function () {
|
||||
return 2 * this._radius;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the width of the light object.
|
||||
* @returns {number} width of light object.
|
||||
*/
|
||||
gdjs.LightRuntimeObject.prototype.getWidth = function () {
|
||||
return 2 * this._radius;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the x co-ordinate of the top-left vertex/point of light object.
|
||||
* @returns {number} x co-ordinate of the top-left vertex/point.
|
||||
*/
|
||||
gdjs.LightRuntimeObject.prototype.getDrawableX = function () {
|
||||
return this.x - this._radius;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the y co-ordinate of the top-left vertex/point of light object.
|
||||
* @returns {number} y co-ordinate of the top-left vertex/point.
|
||||
*/
|
||||
gdjs.LightRuntimeObject.prototype.getDrawableY = function () {
|
||||
return this.y - this._radius;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the color of the light object as a "R;G;B" string.
|
||||
* @returns {string} the color of light object in "R;G;B" format.
|
||||
*/
|
||||
gdjs.LightRuntimeObject.prototype.getColor = function () {
|
||||
return this._color[0] + ';' + this._color[1] + ';' + this._color[2];
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the color of the light object in format "R;G;B" string, with components in the range of [0-255].
|
||||
* @param {string} color
|
||||
*/
|
||||
gdjs.LightRuntimeObject.prototype.setColor = function (color) {
|
||||
var rgbColor = color.split(';');
|
||||
this._color = [
|
||||
parseInt(rgbColor[0], 10),
|
||||
parseInt(rgbColor[1], 10),
|
||||
parseInt(rgbColor[2], 10),
|
||||
];
|
||||
this._renderer.updateColor();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the light obstacles manager if objects with the behavior exist, null otherwise.
|
||||
* @returns {?gdjs.LightObstaclesManager} gdjs.LightObstaclesManager if it exists, otherwise null.
|
||||
*/
|
||||
gdjs.LightRuntimeObject.prototype.getObstaclesManager = function () {
|
||||
return this._obstaclesManager;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the light shows debug graphics, false otherwise.
|
||||
* @returns {boolean} true if debug mode is activated.
|
||||
*/
|
||||
gdjs.LightRuntimeObject.prototype.getDebugMode = function () {
|
||||
return this._debugMode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the path of texture resource.
|
||||
* @returns {string} the path of texture.
|
||||
*/
|
||||
gdjs.LightRuntimeObject.prototype.getTexture = function () {
|
||||
return this._texture;
|
||||
};
|
200
Extensions/Lighting/tests/lightruntimeobject.spec.js
Normal file
200
Extensions/Lighting/tests/lightruntimeobject.spec.js
Normal file
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* Tests for Light Object
|
||||
*/
|
||||
|
||||
/**
|
||||
* Utility function for adding light object for tests.
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {number} radius
|
||||
* @returns {gdjs.LightRuntimeObject}
|
||||
*/
|
||||
const addLightObject = (runtimeScene, radius) => {
|
||||
const lightObj = new gdjs.LightRuntimeObject(runtimeScene, {
|
||||
name: 'lightObject',
|
||||
type: 'Lighting::LightObject',
|
||||
variables: [],
|
||||
behaviors: [],
|
||||
content: {
|
||||
radius: radius,
|
||||
color: '#b4b4b4',
|
||||
texture: '',
|
||||
debugMode: false,
|
||||
},
|
||||
});
|
||||
runtimeScene.addObject(lightObj);
|
||||
return lightObj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility function for adding light obstacle for tests.
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {number} width
|
||||
* @param {number} height
|
||||
* @returns {gdjs.RuntimeObject}
|
||||
*/
|
||||
const addLightObstacle = (runtimeScene, width, height) => {
|
||||
const obstacle = new gdjs.RuntimeObject(runtimeScene, {
|
||||
name: 'lightObstacle',
|
||||
type: '',
|
||||
behaviors: [
|
||||
{
|
||||
type: 'Lighting::LightObstacleBehavior',
|
||||
},
|
||||
],
|
||||
});
|
||||
obstacle.getWidth = function () {
|
||||
return width;
|
||||
};
|
||||
obstacle.getHeight = function () {
|
||||
return height;
|
||||
};
|
||||
runtimeScene.addObject(obstacle);
|
||||
return obstacle;
|
||||
};
|
||||
|
||||
describe('gdjs.LightRuntimeObject', function () {
|
||||
PIXI.settings.FAIL_IF_MAJOR_PERFORMANCE_CAVEAT = false;
|
||||
const runtimeGame = new gdjs.RuntimeGame({
|
||||
variables: [],
|
||||
resources: {
|
||||
resources: [],
|
||||
},
|
||||
properties: { windowWidth: 800, windowHeight: 600 },
|
||||
});
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [{ name: '', visibility: true, effects: [] }],
|
||||
variables: [],
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
});
|
||||
const lightObj = addLightObject(runtimeScene, 100);
|
||||
lightObj.setPosition(200, 200);
|
||||
|
||||
it('check object properties', function () {
|
||||
expect(lightObj.getRadius()).to.be(100);
|
||||
expect(lightObj.getColor()).to.eql("180;180;180");
|
||||
expect(lightObj.getDebugMode()).to.be(false);
|
||||
expect(lightObj.getDrawableX()).to.be(100);
|
||||
expect(lightObj.getDrawableY()).to.be(100);
|
||||
});
|
||||
|
||||
it('bail out early while raycasting when there is no light obstacle', function () {
|
||||
expect(lightObj._renderer._computeLightVertices()).to.eql([]);
|
||||
lightObj._renderer._updateBuffers();
|
||||
expect(lightObj._renderer._defaultVertexBuffer).to.eql(
|
||||
new Float32Array([100, 300, 300, 300, 300, 100, 100, 100])
|
||||
);
|
||||
expect(gdjs.LightRuntimeObjectPixiRenderer._defaultIndexBuffer).to.eql(
|
||||
new Float32Array([0, 1, 2, 0, 2, 3])
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Light with obstacles around it', function () {
|
||||
PIXI.settings.FAIL_IF_MAJOR_PERFORMANCE_CAVEAT = false;
|
||||
const runtimeGame = new gdjs.RuntimeGame({
|
||||
variables: [],
|
||||
resources: {
|
||||
resources: [],
|
||||
},
|
||||
properties: { windowWidth: 800, windowHeight: 600 },
|
||||
});
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [{ name: '', visibility: true, effects: [] }],
|
||||
variables: [],
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
});
|
||||
runtimeScene._timeManager.getElapsedTime = function () {
|
||||
return (1 / 60) * 1000;
|
||||
};
|
||||
const light = addLightObject(runtimeScene, 100);
|
||||
const obstacle = addLightObstacle(runtimeScene, 50, 50);
|
||||
|
||||
it('Vertex and index buffers when light obstacle is present.', function () {
|
||||
light.setPosition(200, 200);
|
||||
obstacle.setPosition(250, 250);
|
||||
|
||||
runtimeScene.renderAndStep();
|
||||
light.update();
|
||||
|
||||
const vertexBuffer = light._renderer._vertexBuffer;
|
||||
const indexBuffer = light._renderer._indexBuffer;
|
||||
// prettier-ignore
|
||||
const expectedVertexBuffer = [
|
||||
200, 200, 100, 100.0199966430664, 100, 100, 100.0199966430664, 100, 299.9800109863281,
|
||||
100, 300, 100, 300, 100.0199966430664, 300, 249.9875030517578, 300, 250, 299.9750061035156,
|
||||
250, 250.00999450683594, 250, 250, 250, 250,250.00999450683594, 250, 299.9750061035156, 250,
|
||||
300, 249.9875030517578, 300, 100.0199966430664, 300, 100, 300, 100, 299.9800109863281,
|
||||
];
|
||||
// prettier-ignore
|
||||
const expectedIndexBuffer = [
|
||||
0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6,
|
||||
0, 6, 7, 0, 7, 8, 0, 8, 9, 0, 9, 10, 0, 10, 11,
|
||||
0, 11, 12, 0, 12, 13, 0, 13, 14, 0, 14, 15, 0,
|
||||
15, 16, 0, 16, 17, 0, 17, 18, 0, 18, 1,
|
||||
];
|
||||
|
||||
expectedVertexBuffer.forEach((val, index) => {
|
||||
expect(vertexBuffer[index]).to.be(val);
|
||||
});
|
||||
expectedIndexBuffer.forEach((val, index) => {
|
||||
expect(indexBuffer[index]).to.be(val);
|
||||
});
|
||||
});
|
||||
|
||||
it('Vertex and index buffers after obstacle is moved.', function () {
|
||||
obstacle.setPosition(150, 250);
|
||||
runtimeScene.renderAndStep();
|
||||
light.update();
|
||||
|
||||
const vertexBuffer = light._renderer._vertexBuffer;
|
||||
const indexBuffer = light._renderer._indexBuffer;
|
||||
// prettier-ignore
|
||||
const expectedVertexBuffer = [
|
||||
200, 200, 100, 100.0199966430664, 100, 100, 100.0199966430664, 100, 299.9800109863281,
|
||||
100, 300, 100, 300, 100.0199966430664, 300, 299.9800109863281, 300, 300, 299.9800109863281,
|
||||
300, 200.00999450683594, 300, 200, 250, 199.9949951171875, 250, 175.00625610351562, 250,
|
||||
175, 250, 174.99374389648438, 250, 150.00999450683594, 250, 150, 250, 100, 299.9800109863281,
|
||||
];
|
||||
// prettier-ignore
|
||||
const expectedIndexBuffer = [
|
||||
0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0,
|
||||
6, 7, 0, 7, 8, 0, 8, 9, 0, 9, 10, 0, 10, 11, 0,
|
||||
11, 12, 0, 12, 13, 0, 13, 14, 0, 14, 15, 0, 15,
|
||||
16, 0, 16, 17, 0, 17, 18, 0, 18, 1,
|
||||
];
|
||||
|
||||
expectedVertexBuffer.forEach((val, index) => {
|
||||
expect(vertexBuffer[index]).to.be(val);
|
||||
});
|
||||
expectedIndexBuffer.forEach((val, index) => {
|
||||
expect(indexBuffer[index]).to.be(val);
|
||||
});
|
||||
});
|
||||
|
||||
it("Obstacle moved outside light's radius.", function () {
|
||||
obstacle.setPosition(400, 400);
|
||||
runtimeScene.renderAndStep();
|
||||
light.update();
|
||||
// Ensure the fallback to simple quads. There shouldn't be anymore calculations
|
||||
// when the obstacle is not inside light's area.
|
||||
expect(light._renderer._computeLightVertices().length).to.eql(0);
|
||||
|
||||
const vertexBuffer = light._renderer._defaultVertexBuffer;
|
||||
const indexBuffer = gdjs.LightRuntimeObjectPixiRenderer._defaultIndexBuffer;
|
||||
const vertexData = [100, 300, 300, 300, 300, 100, 100, 100];
|
||||
const indexData = [0, 1, 2, 0, 2, 3];
|
||||
|
||||
vertexData.forEach((val, index) => {
|
||||
expect(vertexBuffer[index]).to.be(val);
|
||||
});
|
||||
indexData.forEach((val, index) => {
|
||||
expect(indexBuffer[index]).to.be(val);
|
||||
});
|
||||
});
|
||||
});
|
@@ -49,7 +49,7 @@ gdjs.LinksManager.prototype.removeAllLinksOf = function(obj) {
|
||||
if ( this.links.hasOwnProperty(objLinkedObjects[i].id) ) {
|
||||
var otherObjList = this.links[objLinkedObjects[i].id];
|
||||
var index = otherObjList.indexOf(obj);
|
||||
if ( index !== -1) otherObjList.remove(index);
|
||||
if ( index !== -1) otherObjList.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,13 +63,13 @@ gdjs.LinksManager.prototype.removeLinkBetween = function(objA, objB) {
|
||||
if ( this.links.hasOwnProperty(objA.id) ) {
|
||||
list = this.links[objA.id];
|
||||
index = list.indexOf(objB);
|
||||
if ( index !== -1) list.remove(index);
|
||||
if ( index !== -1) list.splice(index, 1);
|
||||
}
|
||||
|
||||
if ( this.links.hasOwnProperty(objB.id) ) {
|
||||
list = this.links[objB.id];
|
||||
index = list.indexOf(objA);
|
||||
if ( index !== -1) list.remove(index);
|
||||
if ( index !== -1) list.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
71
Extensions/P2P/A_peer.js
Normal file
71
Extensions/P2P/A_peer.js
Normal file
File diff suppressed because one or more lines are too long
405
Extensions/P2P/B_p2ptools.js
Normal file
405
Extensions/P2P/B_p2ptools.js
Normal file
@@ -0,0 +1,405 @@
|
||||
// @ts-check
|
||||
/// <reference path="peerjs" />
|
||||
|
||||
/**
|
||||
* Tools for p2p multiplayer.
|
||||
* @namespace
|
||||
*/
|
||||
gdjs.evtTools.p2p = {
|
||||
/**
|
||||
* The peer to peer configuration.
|
||||
* @type {Peer.PeerJSOption}
|
||||
*/
|
||||
peerConfig: { debug: 1 }, // Enable logging of critical errors
|
||||
|
||||
/**
|
||||
* The p2p client.
|
||||
* @type {?Peer}
|
||||
*/
|
||||
peer: null,
|
||||
|
||||
/**
|
||||
* All connected p2p clients, keyed by their ID.
|
||||
* @type {Object<string, Peer.DataConnection>}
|
||||
*/
|
||||
connections: {},
|
||||
|
||||
/**
|
||||
* Contains a list of events triggered by other p2p clients.
|
||||
* Maps an event name (string) to a boolean:
|
||||
* true if the event has been triggered, otherwise false.
|
||||
* @note This is ignored if the event is in no dataloss mode.
|
||||
* @type {Object<string, boolean>}
|
||||
*/
|
||||
triggeredEvents: {},
|
||||
|
||||
/**
|
||||
* Contains the latest data sent with each event.
|
||||
* If the event is in dataloss mode, maps an event name (string)
|
||||
* to the string sent with that event.
|
||||
* If the event is in no dataloss mode, maps an event name (string)
|
||||
* to an array containing the data of each call of that event.
|
||||
* @type {Object<string, string | Array>}
|
||||
*/
|
||||
lastEventData: {},
|
||||
|
||||
/**
|
||||
* Tells how to handle an event (with or without data loss).
|
||||
* Maps the event name (string) to a boolean:
|
||||
* true for dataloss, false for no dataloss.
|
||||
* @type {Object<string, string>}
|
||||
*/
|
||||
eventHandling: {},
|
||||
|
||||
/**
|
||||
* True if PeerJS is initialized and ready.
|
||||
* @type {boolean}
|
||||
*/
|
||||
ready: false,
|
||||
|
||||
/**
|
||||
* True if an error occured.
|
||||
* @type {boolean}
|
||||
*/
|
||||
error: false,
|
||||
|
||||
/**
|
||||
* Last error's message.
|
||||
* @type {string}
|
||||
*/
|
||||
lastError: '',
|
||||
|
||||
/**
|
||||
* List of IDs of peers that just disconnected.
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
disconnectedPeers: [],
|
||||
|
||||
/**
|
||||
* List of IDs of peers that just remotely initiated a connection.
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
connectedPeers: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal function called to initialize PeerJS after its
|
||||
* broker server has been configured.
|
||||
* @private
|
||||
*/
|
||||
gdjs.evtTools.p2p._loadPeerJS = function () {
|
||||
if (gdjs.evtTools.p2p.peer != null) return;
|
||||
gdjs.evtTools.p2p.peer = new Peer(gdjs.evtTools.p2p.peerConfig);
|
||||
gdjs.evtTools.p2p.peer.on('open', function () {
|
||||
gdjs.evtTools.p2p.ready = true;
|
||||
});
|
||||
gdjs.evtTools.p2p.peer.on('error', function (errorMessage) {
|
||||
gdjs.evtTools.p2p.error = true;
|
||||
gdjs.evtTools.p2p.lastError = errorMessage;
|
||||
});
|
||||
gdjs.evtTools.p2p.peer.on('connection', function (connection) {
|
||||
connection.on('open', function () {
|
||||
gdjs.evtTools.p2p._onConnection(connection);
|
||||
gdjs.evtTools.p2p.connectedPeers.push(connection.peer);
|
||||
});
|
||||
});
|
||||
gdjs.evtTools.p2p.peer.on('close', function () {
|
||||
gdjs.evtTools.p2p.peer = null;
|
||||
gdjs.evtTools.p2p._loadPeerJS();
|
||||
});
|
||||
gdjs.evtTools.p2p.peer.on('disconnected', gdjs.evtTools.p2p.peer.reconnect);
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal function called when a connection with a remote peer is initiated.
|
||||
* @private
|
||||
* @param {Peer.DataConnection} connection The DataConnection of the peer
|
||||
*/
|
||||
gdjs.evtTools.p2p._onConnection = function (connection) {
|
||||
gdjs.evtTools.p2p.connections[connection.peer] = connection;
|
||||
connection.on('data', function (data) {
|
||||
if (data.eventName === undefined) return;
|
||||
var dataLoss = gdjs.evtTools.p2p.eventHandling[data.eventName];
|
||||
|
||||
if (typeof dataLoss === 'undefined' || dataLoss === false) {
|
||||
if (typeof gdjs.evtTools.p2p.lastEventData[data.eventName] !== 'object')
|
||||
gdjs.evtTools.p2p.lastEventData[data.eventName] = [];
|
||||
gdjs.evtTools.p2p.lastEventData[data.eventName].push(data.data);
|
||||
} else {
|
||||
gdjs.evtTools.p2p.triggeredEvents[data.eventName] = true;
|
||||
gdjs.evtTools.p2p.lastEventData[data.eventName] = data.data;
|
||||
}
|
||||
});
|
||||
connection.on('error', function () {
|
||||
// Close event is only for graceful disconnection, also handle error aka ungraceful disconnection
|
||||
gdjs.evtTools.p2p._onDisconnect(connection.peer);
|
||||
});
|
||||
connection.on('close', function () {
|
||||
gdjs.evtTools.p2p._onDisconnect(connection.peer);
|
||||
});
|
||||
// Regularly check for disconnection as the built in way is not reliable.
|
||||
var disconnectChecker = function () {
|
||||
if (
|
||||
connection.peerConnection.connectionState === 'failed' ||
|
||||
connection.peerConnection.connectionState === 'disconnected'
|
||||
) {
|
||||
gdjs.evtTools.p2p._onDisconnect(connection.peer);
|
||||
} else {
|
||||
setTimeout(disconnectChecker, 500);
|
||||
}
|
||||
};
|
||||
disconnectChecker();
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal function called when a remote client disconnects.
|
||||
* @private
|
||||
* @param {string} connectionID The ID of the peer that disconnected.
|
||||
*/
|
||||
gdjs.evtTools.p2p._onDisconnect = function (connectionID) {
|
||||
gdjs.evtTools.p2p.disconnectedPeers.push(connectionID);
|
||||
delete gdjs.evtTools.p2p.connections[connectionID];
|
||||
};
|
||||
|
||||
/**
|
||||
* Connects to another p2p client.
|
||||
* @param {string} id - The other client's ID.
|
||||
*/
|
||||
gdjs.evtTools.p2p.connect = function (id) {
|
||||
var connection = gdjs.evtTools.p2p.peer.connect(id);
|
||||
connection.on('open', function () {
|
||||
gdjs.evtTools.p2p._onConnection(connection);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true when the event got triggered by another p2p client.
|
||||
* @param {string} eventName
|
||||
* @param {boolean} defaultDataLoss Is data loss allowed (accelerates event handling when true)?
|
||||
* @returns {boolean}
|
||||
*/
|
||||
gdjs.evtTools.p2p.onEvent = function (eventName, defaultDataLoss) {
|
||||
var dataLoss = gdjs.evtTools.p2p.eventHandling[eventName];
|
||||
if (dataLoss == undefined) {
|
||||
gdjs.evtTools.p2p.eventHandling[eventName] = defaultDataLoss;
|
||||
return gdjs.evtTools.p2p.onEvent(eventName, defaultDataLoss);
|
||||
}
|
||||
if (dataLoss) {
|
||||
var returnValue = gdjs.evtTools.p2p.triggeredEvents[eventName];
|
||||
if (typeof returnValue === 'undefined') return false;
|
||||
gdjs.evtTools.p2p.triggeredEvents[eventName] = false;
|
||||
return returnValue;
|
||||
} else {
|
||||
var returnValue = gdjs.evtTools.p2p.lastEventData[eventName];
|
||||
if (typeof returnValue === 'undefined') return false;
|
||||
return returnValue.length !== 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Send an event to one specific connected client.
|
||||
* @param {string} id - The ID of the client to send the event to.
|
||||
* @param {string} eventName - The event to trigger.
|
||||
* @param {string} [eventData] - Additional data to send with the event.
|
||||
*/
|
||||
gdjs.evtTools.p2p.sendDataTo = function (id, eventName, eventData) {
|
||||
if (gdjs.evtTools.p2p.connections[id])
|
||||
gdjs.evtTools.p2p.connections[id].send({
|
||||
eventName: eventName,
|
||||
data: eventData,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Send an event to all connected clients.
|
||||
* @param {string} eventName - The event to trigger.
|
||||
* @param {string} [eventData] - Additional data to send with the event.
|
||||
*/
|
||||
gdjs.evtTools.p2p.sendDataToAll = function (eventName, eventData) {
|
||||
for (var id in gdjs.evtTools.p2p.connections) {
|
||||
gdjs.evtTools.p2p.connections[id].send({
|
||||
eventName: eventName,
|
||||
data: eventData,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Send an event to one specific connected client.
|
||||
* @param {string} id - The ID of the client to send the event to.
|
||||
* @param {string} eventName - The event to trigger.
|
||||
* @param {gdjs.Variable} variable - Additional variable to send with the event.
|
||||
*/
|
||||
gdjs.evtTools.p2p.sendVariableTo = function (id, eventName, variable) {
|
||||
gdjs.evtTools.p2p.sendDataTo(
|
||||
id,
|
||||
eventName,
|
||||
gdjs.evtTools.network.variableStructureToJSON(variable)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Send an event to all connected clients.
|
||||
* @param {string} eventName - The event to trigger.
|
||||
* @param {gdjs.Variable} variable - Additional variable to send with the event.
|
||||
*/
|
||||
gdjs.evtTools.p2p.sendVariableToAll = function (eventName, variable) {
|
||||
gdjs.evtTools.p2p.sendDataToAll(
|
||||
eventName,
|
||||
gdjs.evtTools.network.variableStructureToJSON(variable)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get some data associated to the last trigger of an event.
|
||||
* @param {string} eventName - The event to get data from.
|
||||
* @returns {string} - The data as JSON.
|
||||
*/
|
||||
gdjs.evtTools.p2p.getEventData = function (eventName) {
|
||||
var dataLoss = gdjs.evtTools.p2p.eventHandling[eventName];
|
||||
if (typeof dataLoss === 'undefined' || dataLoss === false) {
|
||||
var event = gdjs.evtTools.p2p.lastEventData[eventName];
|
||||
return event[event.length - 1];
|
||||
} else {
|
||||
return gdjs.evtTools.p2p.lastEventData[eventName];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a variable associated to the last trigger of an event.
|
||||
* @param {string} eventName - The event to get the variable from.
|
||||
* @param {gdjs.Variable} variable - The variable where to store the variable content.
|
||||
*/
|
||||
gdjs.evtTools.p2p.getEventVariable = function (eventName, variable) {
|
||||
gdjs.evtTools.network.jsonToVariableStructure(
|
||||
gdjs.evtTools.p2p.getEventData(eventName),
|
||||
variable
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Connects to a custom broker server.
|
||||
* @param {string} host The host of the broker server.
|
||||
* @param {number} port The port of the broker server.
|
||||
* @param {string} path The path (part of the url after the host) to the broker server.
|
||||
* @param {string} key Optional password to connect to the broker server.
|
||||
* @param {boolean} ssl Use ssl?
|
||||
*/
|
||||
gdjs.evtTools.p2p.useCustomBrokerServer = function (
|
||||
host,
|
||||
port,
|
||||
path,
|
||||
key,
|
||||
ssl
|
||||
) {
|
||||
key = key.length === 0 ? 'peerjs' : key; // All servers have "peerjs" as default key
|
||||
gdjs.evtTools.p2p.peerConfig = {
|
||||
debug: 1,
|
||||
host,
|
||||
port,
|
||||
path,
|
||||
secure: ssl,
|
||||
key,
|
||||
};
|
||||
gdjs.evtTools.p2p._loadPeerJS();
|
||||
};
|
||||
|
||||
/**
|
||||
* Use default broker server.
|
||||
* This is not recommended for published games,
|
||||
* this server should only be used for quick testing in development.
|
||||
*/
|
||||
gdjs.evtTools.p2p.useDefaultBrokerServer = function () {
|
||||
gdjs.evtTools.p2p._loadPeerJS();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the own current peer ID.
|
||||
* @see Peer.id
|
||||
* @returns {string}
|
||||
*/
|
||||
gdjs.evtTools.p2p.getCurrentId = function () {
|
||||
if (gdjs.evtTools.p2p.peer == undefined) return '';
|
||||
return gdjs.evtTools.p2p.peer.id || '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true once PeerJS finished initialization.
|
||||
* @see gdjs.evtTools.p2p.ready
|
||||
* @returns {boolean}
|
||||
*/
|
||||
gdjs.evtTools.p2p.isReady = function () {
|
||||
return gdjs.evtTools.p2p.ready;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true once when there is an error.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
gdjs.evtTools.p2p.onError = function () {
|
||||
var returnValue = gdjs.evtTools.p2p.error;
|
||||
gdjs.evtTools.p2p.error = false;
|
||||
return returnValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the latest error message.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
gdjs.evtTools.p2p.getLastError = function () {
|
||||
return gdjs.evtTools.p2p.lastError;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true once a peer disconnected.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
gdjs.evtTools.p2p.onDisconnect = function () {
|
||||
return gdjs.evtTools.p2p.disconnectedPeers.length > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the ID of the peer that triggered onDisconnect.
|
||||
* @returns {string}
|
||||
*/
|
||||
gdjs.evtTools.p2p.getDisconnectedPeer = function () {
|
||||
return (
|
||||
gdjs.evtTools.p2p.disconnectedPeers[
|
||||
gdjs.evtTools.p2p.disconnectedPeers.length - 1
|
||||
] || ''
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true once if a remote peer just initiated a connection.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
gdjs.evtTools.p2p.onConnection = function () {
|
||||
return gdjs.evtTools.p2p.connectedPeers.length > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the ID of the peer that triggered onConnection.
|
||||
* @returns {string}
|
||||
*/
|
||||
gdjs.evtTools.p2p.getConnectedPeer = function () {
|
||||
return (
|
||||
gdjs.evtTools.p2p.connectedPeers[
|
||||
gdjs.evtTools.p2p.connectedPeers.length - 1
|
||||
] || ''
|
||||
);
|
||||
};
|
||||
|
||||
gdjs.callbacksRuntimeScenePostEvents.push(function () {
|
||||
for (var i in gdjs.evtTools.p2p.lastEventData) {
|
||||
if (
|
||||
typeof gdjs.evtTools.p2p.lastEventData[i] === 'object' &&
|
||||
gdjs.evtTools.p2p.lastEventData[i].length > 0
|
||||
)
|
||||
gdjs.evtTools.p2p.lastEventData[i].pop();
|
||||
}
|
||||
if (gdjs.evtTools.p2p.disconnectedPeers.length > 0)
|
||||
gdjs.evtTools.p2p.disconnectedPeers.pop();
|
||||
if (gdjs.evtTools.p2p.connectedPeers.length > 0)
|
||||
gdjs.evtTools.p2p.connectedPeers.pop();
|
||||
});
|
361
Extensions/P2P/JsExtension.js
Normal file
361
Extensions/P2P/JsExtension.js
Normal file
@@ -0,0 +1,361 @@
|
||||
// @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 /*: gdPlatformExtension */ = new gd.PlatformExtension();
|
||||
extension
|
||||
.setExtensionInformation(
|
||||
'P2P',
|
||||
_('Peer-to-Peer communication (experimental)'),
|
||||
_(
|
||||
'Allow game instances to communicate remotely using messages sent via WebRTC (P2P)'
|
||||
),
|
||||
'Arthur Pacaud (arthuro555)',
|
||||
'MIT'
|
||||
)
|
||||
.setExtensionHelpPath('/all-features/p2p');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'OnEvent',
|
||||
_('Event triggered by peer'),
|
||||
_('Triggers once when a connected client sends the event'),
|
||||
_('Event _PARAM0_ received from other client (data loss: _PARAM1_)'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg',
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.addParameter('string', _('Event name'), '', false)
|
||||
.addParameter('yesorno', _('Data loss allowed?'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.onEvent');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsReady',
|
||||
_('Is P2P ready'),
|
||||
_(
|
||||
'True if the peer-to-peer extension initialized and is ready to use.'
|
||||
),
|
||||
_('Is P2P ready?'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg',
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.isReady');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'OnError',
|
||||
_('An error occurred'),
|
||||
_(
|
||||
'Triggers once when an error occurs. ' +
|
||||
'Use P2P::GetLastError() expression to get the content of the error ' +
|
||||
'if you want to analyse it or display it to the user.'
|
||||
),
|
||||
_('P2P error occurred'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg',
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.onError');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'OnDisconnection',
|
||||
_('Peer disconnected'),
|
||||
_('Triggers once when a peer disconnects.'),
|
||||
_('P2P peer disconnected'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg',
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.onDisconnect');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'OnConnection',
|
||||
_('Peer Connected'),
|
||||
_('Triggers once when a remote peer initiates a connection.'),
|
||||
_('P2P peer connected'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg',
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.onConnection');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'Connect',
|
||||
_('Connect to another client'),
|
||||
_('Connects the current client to another client using its id.'),
|
||||
_('Connect to P2P client _PARAM0_'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg',
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.addParameter('string', _('ID of the other client'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.connect');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'UseOwnBroker',
|
||||
_('Connect to a broker server'),
|
||||
_('Connects the extension to a broker server.'),
|
||||
_('Connect to the broker server at http://_PARAM0_:_PARAM1_/'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg',
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.addParameter('string', _('Host'), '', false)
|
||||
.addParameter('number', _('Port'), '', false)
|
||||
.addParameter('string', _('Path'), '', false)
|
||||
.addParameter('string', _('Key'), '', false)
|
||||
.addParameter('yesorno', _('SSl enabled?'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.useCustomBrokerServer');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'UseDefaultBroker',
|
||||
_('Connect to the default broker server'),
|
||||
_('Connects to the default broker server.'),
|
||||
_('Connect to the default broker server'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg',
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.useDefaultBrokerServer');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SendToAll',
|
||||
_('Trigger event on all connected clients'),
|
||||
_('Triggers an event on all connected clients'),
|
||||
_(
|
||||
'Trigger event _PARAM0_ on all connected clients (extra data: _PARAM1_)'
|
||||
),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg',
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.addParameter('string', _('Event name'), '', false)
|
||||
.addParameter('string', _('Extra data (optional)'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.sendDataToAll');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SendToOne',
|
||||
_('Trigger event on a specific client'),
|
||||
_('Triggers an event on a specific connected client'),
|
||||
_('Trigger event _PARAM1_ on client _PARAM0_ (extra data: _PARAM2_)'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg',
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.addParameter('string', _('ID of the other client'), '', false)
|
||||
.addParameter('string', _('Event name'), '', false)
|
||||
.addParameter('string', _('Extra data (optional)'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.sendDataTo');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SendToAllVariable',
|
||||
_('Trigger event on all connected clients (variable)'),
|
||||
_('Triggers an event on all connected clients'),
|
||||
_(
|
||||
'Trigger event _PARAM0_ on all connected clients (extra data: _PARAM1_)'
|
||||
),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg',
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.addParameter('string', _('Event name'), '', false)
|
||||
.addParameter(
|
||||
'scenevar',
|
||||
_('Variable containing the extra data'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.sendVariableToAll');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SendToOneVariable',
|
||||
_('Trigger event on a specific client (variable)'),
|
||||
_('Triggers an event on a specific connected client'),
|
||||
_('Trigger event _PARAM1_ on client _PARAM0_ (extra data: _PARAM2_)'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg',
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.addParameter('string', _('ID of the other client'), '', false)
|
||||
.addParameter('string', _('Event name'), '', false)
|
||||
.addParameter(
|
||||
'scenevar',
|
||||
_('Variable containing the extra data'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.sendVariableTo');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'GetEventVariable',
|
||||
_('Get event data (variable)'),
|
||||
_(
|
||||
'Store the data of the specified event in a variable. ' +
|
||||
'Check in the conditions that the event was received using the "Event received" condition.'
|
||||
),
|
||||
_(
|
||||
'Overwrite _PARAM1_ with variable sent with last trigger of _PARAM0_'
|
||||
),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg',
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.addParameter('string', _('Event name'), '', false)
|
||||
.addParameter(
|
||||
'scenevar',
|
||||
_('Variable where to store the received data'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.getEventVariable');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'GetEventData',
|
||||
_('Get event data'),
|
||||
_(
|
||||
'Returns the data received when the specified event was last triggered'
|
||||
),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.addParameter('string', _('Event name'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.getEventData');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'GetID',
|
||||
_('Get client ID'),
|
||||
_('Gets the client ID of the current game instance'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.getCurrentId');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'GetLastError',
|
||||
_('Get last error'),
|
||||
_('Gets the description of the last P2P error'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.getLastError');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'GetLastDisconnectedPeer',
|
||||
_('Get last disconnected peer'),
|
||||
_('Gets the ID of the latest peer that has disconnected.'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.getDisconnectedPeer');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'GetLastConnectedPeer',
|
||||
_('Get ID of the connected peer'),
|
||||
_('Gets the ID of the newly connected peer.'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.getConnectedPeer');
|
||||
|
||||
return extension;
|
||||
},
|
||||
runExtensionSanityTests: function (
|
||||
gd /*: libGDevelop */,
|
||||
extension /*: gdPlatformExtension*/
|
||||
) {
|
||||
return [];
|
||||
},
|
||||
};
|
208
Extensions/P2P/peerjs.d.ts
vendored
Normal file
208
Extensions/P2P/peerjs.d.ts
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
// Type definitions for the PeerJS class module
|
||||
// Original definitions by Toshiya Nakakura <https://github.com/nakakura>
|
||||
// at https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
|
||||
declare class Peer {
|
||||
prototype: RTCIceServer;
|
||||
|
||||
/**
|
||||
* A peer can connect to other peers and listen for connections.
|
||||
* @param id Other peers can connect to this peer using the provided ID.
|
||||
* If no ID is given, one will be generated by the brokering server.
|
||||
* @param options for specifying details about PeerServer
|
||||
*/
|
||||
constructor(id?: string, options?: Peer.PeerJSOption);
|
||||
|
||||
/**
|
||||
* A peer can connect to other peers and listen for connections.
|
||||
* @param options for specifying details about PeerServer
|
||||
*/
|
||||
constructor(options: Peer.PeerJSOption);
|
||||
|
||||
/**
|
||||
* Connects to the remote peer specified by id and returns a data connection.
|
||||
* @param id The brokering ID of the remote peer (their peer.id).
|
||||
* @param options for specifying details about Peer Connection
|
||||
*/
|
||||
connect(id: string, options?: Peer.PeerConnectOption): Peer.DataConnection;
|
||||
/**
|
||||
* Calls the remote peer specified by id and returns a media connection.
|
||||
* @param id The brokering ID of the remote peer (their peer.id).
|
||||
* @param stream The caller's media stream
|
||||
* @param options Metadata associated with the connection, passed in by whoever initiated the connection.
|
||||
*/
|
||||
call(id: string, stream: MediaStream, options?: Peer.CallOption): Peer.MediaConnection;
|
||||
/**
|
||||
* Set listeners for peer events.
|
||||
* @param event Event name
|
||||
* @param cb Callback Function
|
||||
*/
|
||||
on(event: string, cb: () => void): void;
|
||||
/**
|
||||
* Emitted when a connection to the PeerServer is established.
|
||||
* @param event Event name
|
||||
* @param cb id is the brokering ID of the peer
|
||||
*/
|
||||
on(event: "open", cb: (id: string) => void): void;
|
||||
/**
|
||||
* Emitted when a new data connection is established from a remote peer.
|
||||
* @param event Event name
|
||||
* @param cb Callback Function
|
||||
*/
|
||||
on(
|
||||
event: "connection",
|
||||
cb: (dataConnection: Peer.DataConnection) => void
|
||||
): void;
|
||||
/**
|
||||
* Emitted when a remote peer attempts to call you.
|
||||
* @param event Event name
|
||||
* @param cb Callback Function
|
||||
*/
|
||||
on(event: "call", cb: (mediaConnection: Peer.MediaConnection) => void): void;
|
||||
/**
|
||||
* Emitted when the peer is destroyed and can no longer accept or create any new connections.
|
||||
* @param event Event name
|
||||
* @param cb Callback Function
|
||||
*/
|
||||
on(event: "close", cb: () => void): void;
|
||||
/**
|
||||
* Emitted when the peer is disconnected from the signalling server
|
||||
* @param event Event name
|
||||
* @param cb Callback Function
|
||||
*/
|
||||
on(event: "disconnected", cb: () => void): void;
|
||||
/**
|
||||
* Errors on the peer are almost always fatal and will destroy the peer.
|
||||
* @param event Event name
|
||||
* @param cb Callback Function
|
||||
*/
|
||||
on(event: "error", cb: (err: any) => void): void;
|
||||
/**
|
||||
* Remove event listeners.(EventEmitter3)
|
||||
* @param {String} event The event we want to remove.
|
||||
* @param {Function} fn The listener that we need to find.
|
||||
* @param {Boolean} once Only remove once listeners.
|
||||
*/
|
||||
off(event: string, fn: Function, once?: boolean): void;
|
||||
/**
|
||||
* Close the connection to the server, leaving all existing data and media connections intact.
|
||||
*/
|
||||
disconnect(): void;
|
||||
/**
|
||||
* Attempt to reconnect to the server with the peer's old ID
|
||||
*/
|
||||
reconnect(): void;
|
||||
/**
|
||||
* Close the connection to the server and terminate all existing connections.
|
||||
*/
|
||||
destroy(): void;
|
||||
|
||||
/**
|
||||
* Retrieve a data/media connection for this peer.
|
||||
* @param peerId
|
||||
* @param connectionId
|
||||
*/
|
||||
getConnection(peerId: string, connectionId: string): Peer.MediaConnection | Peer.DataConnection | null;
|
||||
|
||||
/**
|
||||
* Get a list of available peer IDs
|
||||
* @param callback
|
||||
*/
|
||||
listAllPeers(callback: (peerIds: Array<string>) => void): void;
|
||||
/**
|
||||
* The brokering ID of this peer
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* A hash of all connections associated with this peer, keyed by the remote peer's ID.
|
||||
*/
|
||||
connections: any;
|
||||
/**
|
||||
* false if there is an active connection to the PeerServer.
|
||||
*/
|
||||
disconnected: boolean;
|
||||
/**
|
||||
* true if this peer and all of its connections can no longer be used.
|
||||
*/
|
||||
destroyed: boolean;
|
||||
}
|
||||
|
||||
declare namespace Peer {
|
||||
interface PeerJSOption {
|
||||
key?: string;
|
||||
host?: string;
|
||||
port?: number;
|
||||
path?: string;
|
||||
secure?: boolean;
|
||||
config?: RTCConfiguration;
|
||||
debug?: number;
|
||||
}
|
||||
|
||||
interface PeerConnectOption {
|
||||
label?: string;
|
||||
metadata?: any;
|
||||
serialization?: string;
|
||||
reliable?: boolean;
|
||||
}
|
||||
|
||||
interface CallOption {
|
||||
metadata?: any;
|
||||
sdpTransform?: Function;
|
||||
}
|
||||
|
||||
interface AnswerOption {
|
||||
sdpTransform?: Function;
|
||||
}
|
||||
|
||||
interface DataConnection {
|
||||
send(data: any): void;
|
||||
close(): void;
|
||||
on(event: string, cb: () => void): void;
|
||||
on(event: "data", cb: (data: any) => void): void;
|
||||
on(event: "open", cb: () => void): void;
|
||||
on(event: "close", cb: () => void): void;
|
||||
on(event: "error", cb: (err: any) => void): void;
|
||||
off(event: string, fn: Function, once?: boolean): void;
|
||||
dataChannel: RTCDataChannel;
|
||||
label: string;
|
||||
metadata: any;
|
||||
open: boolean;
|
||||
peerConnection: RTCPeerConnection;
|
||||
peer: string;
|
||||
reliable: boolean;
|
||||
serialization: string;
|
||||
type: string;
|
||||
bufferSize: number;
|
||||
stringify: (data: any) => string;
|
||||
parse: (data: string) => any;
|
||||
}
|
||||
|
||||
interface MediaConnection {
|
||||
answer(stream?: MediaStream, options?: AnswerOption): void;
|
||||
close(): void;
|
||||
on(event: string, cb: () => void): void;
|
||||
on(event: "stream", cb: (stream: MediaStream) => void): void;
|
||||
on(event: "close", cb: () => void): void;
|
||||
on(event: "error", cb: (err: any) => void): void;
|
||||
off(event: string, fn: Function, once?: boolean): void;
|
||||
open: boolean;
|
||||
metadata: any;
|
||||
peerConnection: RTCPeerConnection;
|
||||
peer: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
interface UtilSupportsObj {
|
||||
browser: boolean,
|
||||
webRTC: boolean;
|
||||
audioVideo: boolean;
|
||||
data: boolean;
|
||||
binaryBlob: boolean;
|
||||
reliable: boolean;
|
||||
}
|
||||
|
||||
interface util {
|
||||
browser: string;
|
||||
supports: UtilSupportsObj;
|
||||
}
|
||||
}
|
@@ -66,15 +66,15 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) {
|
||||
|
||||
obj.AddAction(
|
||||
"SetColor",
|
||||
_("Global color"),
|
||||
_("Change the global color of a Panel Sprite. The default color is white."),
|
||||
_("Change color of _PARAM0_ to _PARAM1_"),
|
||||
_("Tint color"),
|
||||
_("Change the tint of a Panel Sprite. The default color is white."),
|
||||
_("Change tint of _PARAM0_ to _PARAM1_"),
|
||||
_("Effects"),
|
||||
"res/actions/color24.png",
|
||||
"res/actions/color.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "PanelSprite")
|
||||
.AddParameter("color", _("Color"));
|
||||
.AddParameter("color", _("Tint"));
|
||||
|
||||
obj.AddAction("Width",
|
||||
_("Width"),
|
||||
|
@@ -258,7 +258,7 @@ gdjs.PanelSpriteRuntimeObject.prototype.setColor = function(rgbColor) {
|
||||
/**
|
||||
* Get the tint of the panel sprite object.
|
||||
*
|
||||
* @returns {string} rgbColor The color, in RGB format ("128;200;255").
|
||||
* @returns {string} The color, in RGB format ("128;200;255").
|
||||
*/
|
||||
gdjs.PanelSpriteRuntimeObject.prototype.getColor = function() {
|
||||
return this._renderer.getColor();
|
||||
|
@@ -293,7 +293,7 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddCondition("NoMoreParticles",
|
||||
_("No more particles"),
|
||||
_("Return true if the object does not emit particles "
|
||||
_("Check if the object does not emit particles "
|
||||
"anylonger, so as to destroy it for example."),
|
||||
_("_PARAM0_ does not emit anylonger."),
|
||||
_("Common"),
|
||||
|
@@ -56,7 +56,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
|
||||
aut.AddCondition("PathFound",
|
||||
_("Path found"),
|
||||
_("Return true if a path has been found."),
|
||||
_("Check if a path has been found."),
|
||||
_("A path has been found for _PARAM0_"),
|
||||
"",
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
@@ -69,7 +69,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
|
||||
aut.AddCondition("DestinationReached",
|
||||
_("Destination reached"),
|
||||
_("Return true if the destination was reached."),
|
||||
_("Check if the destination was reached."),
|
||||
_("_PARAM0_ reached its destination"),
|
||||
"",
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
@@ -338,7 +338,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
|
||||
aut.AddCondition("DiagonalsAllowed",
|
||||
_("Diagonal movement"),
|
||||
_("Return true if the object is allowed to move "
|
||||
_("Check if the object is allowed to move "
|
||||
"diagonally on the path"),
|
||||
_("Diagonal moves allowed for _PARAM0_"),
|
||||
_("Path"),
|
||||
@@ -366,7 +366,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
|
||||
aut.AddCondition("ObjectRotated",
|
||||
_("Object rotated"),
|
||||
_("Return true if the object is rotated when traveling on "
|
||||
_("Check if the object is rotated when traveling on "
|
||||
"its path."),
|
||||
_("_PARAM0_ is rotated when traveling on its path"),
|
||||
_("Path"),
|
||||
@@ -622,7 +622,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
|
||||
aut.AddCondition("IsImpassable",
|
||||
_("Is object impassable?"),
|
||||
_("Return true if the obstacle is impassable"),
|
||||
_("Check if the obstacle is impassable"),
|
||||
_("_PARAM0_ is impassable"),
|
||||
_("Obstacles"),
|
||||
"CppPlatform/Extensions/pathfindingobstacleicon24.png",
|
||||
|
@@ -53,9 +53,9 @@ gdjs.Physics2SharedData = function(runtimeScene, sharedData) {
|
||||
var behaviorB = contact.GetFixtureB().GetBody().gdjsAssociatedBehavior;
|
||||
// Remove each other contact
|
||||
var i = behaviorA.currentContacts.indexOf(behaviorB);
|
||||
if (i !== -1) behaviorA.currentContacts.remove(i);
|
||||
if (i !== -1) behaviorA.currentContacts.splice(i, 1);
|
||||
i = behaviorB.currentContacts.indexOf(behaviorA);
|
||||
if (i !== -1) behaviorB.currentContacts.remove(i);
|
||||
if (i !== -1) behaviorB.currentContacts.splice(i, 1);
|
||||
};
|
||||
|
||||
this.contactListener.PreSolve = function() {};
|
||||
|
@@ -58,10 +58,10 @@ gdjs.PhysicsSharedData = function(runtimeScene, sharedData)
|
||||
behaviorB = contact.GetFixtureB().GetBody().gdjsAssociatedBehavior;
|
||||
|
||||
var i = behaviorA.currentContacts.indexOf(behaviorB);
|
||||
if ( i !== -1 ) behaviorA.currentContacts.remove(i);
|
||||
if ( i !== -1 ) behaviorA.currentContacts.splice(i, 1);
|
||||
|
||||
i = behaviorB.currentContacts.indexOf(behaviorA);
|
||||
if ( i !== -1 ) behaviorB.currentContacts.remove(i);
|
||||
if ( i !== -1 ) behaviorB.currentContacts.splice(i, 1);
|
||||
};
|
||||
|
||||
this.contactListener.PreSolve = function() {};
|
||||
|
@@ -17,16 +17,17 @@ gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.getRendererObject = functio
|
||||
|
||||
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.clear = function() {
|
||||
this._graphics.clear();
|
||||
this.updateOutline();
|
||||
};
|
||||
|
||||
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawRectangle = function(x1, y1, x2, y2) {
|
||||
this.updateOutline();
|
||||
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
|
||||
this._graphics.drawRect(x1, y1, x2 - x1, y2 - y1);
|
||||
this._graphics.endFill();
|
||||
};
|
||||
|
||||
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawCircle = function(x, y, radius) {
|
||||
this.updateOutline();
|
||||
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
|
||||
this._graphics.drawCircle(x, y, radius);
|
||||
this._graphics.endFill();
|
||||
@@ -55,12 +56,14 @@ gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawLineV2 = function(x1, y
|
||||
};
|
||||
|
||||
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawEllipse = function(x1, y1, width, height) {
|
||||
this.updateOutline();
|
||||
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
|
||||
this._graphics.drawEllipse(x1, y1, width/2, height/2);
|
||||
this._graphics.endFill();
|
||||
};
|
||||
|
||||
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawRoundedRectangle = function(x1, y1, x2, y2, radius) {
|
||||
this.updateOutline();
|
||||
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
|
||||
this._graphics.drawRoundedRect(x1, y1, x2 - x1, y2 - y1, radius);
|
||||
this._graphics.closePath();
|
||||
@@ -68,6 +71,7 @@ gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawRoundedRectangle = func
|
||||
};
|
||||
|
||||
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawStar = function(x1, y1, points, radius, innerRadius, rotation) {
|
||||
this.updateOutline();
|
||||
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
|
||||
this._graphics.drawStar(x1, y1, points, radius, innerRadius ? innerRadius : radius/2, rotation ? gdjs.toRad(rotation) : 0);
|
||||
this._graphics.closePath();
|
||||
@@ -75,6 +79,7 @@ gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawStar = function(x1, y1,
|
||||
};
|
||||
|
||||
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawArc = function(x1, y1, radius, startAngle, endAngle, anticlockwise, closePath) {
|
||||
this.updateOutline();
|
||||
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
|
||||
this._graphics.moveTo( x1 + radius * Math.cos(gdjs.toRad(startAngle)), y1 + radius * Math.sin(gdjs.toRad(startAngle)));
|
||||
this._graphics.arc(x1, y1, radius, gdjs.toRad(startAngle), gdjs.toRad(endAngle), anticlockwise ? true : false);
|
||||
@@ -85,6 +90,7 @@ gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawArc = function(x1, y1,
|
||||
};
|
||||
|
||||
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawBezierCurve = function(x1, y1, cpX, cpY, cpX2, cpY2, x2, y2) {
|
||||
this.updateOutline();
|
||||
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
|
||||
this._graphics.moveTo(x1, y1);
|
||||
this._graphics.bezierCurveTo(cpX, cpY, cpX2, cpY2, x2, y2);
|
||||
@@ -92,6 +98,7 @@ gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawBezierCurve = function(
|
||||
};
|
||||
|
||||
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawQuadraticCurve = function(x1, y1, cpX, cpY, x2, y2) {
|
||||
this.updateOutline();
|
||||
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
|
||||
this._graphics.moveTo(x1, y1);
|
||||
this._graphics.quadraticCurveTo(cpX, cpY, x2, y2);
|
||||
|
@@ -30,14 +30,14 @@ void DeclareSystemInfoExtension(gd::PlatformExtension& extension) {
|
||||
.SetIncludeFile("SystemInfo/SystemInfoTools.h");
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"IsWebGLSupported",
|
||||
_("Is WebGL supported"),
|
||||
_("Check if GPU accelerated WebGL is supported on the target device."),
|
||||
_("WebGL is available"),
|
||||
_("System information"),
|
||||
"CppPlatform/Extensions/systeminfoicon24.png",
|
||||
"CppPlatform/Extensions/systeminfoicon16.png")
|
||||
.AddCondition("IsWebGLSupported",
|
||||
_("Is WebGL supported"),
|
||||
_("Check if GPU accelerated WebGL is supported on the "
|
||||
"target device."),
|
||||
_("WebGL is available"),
|
||||
_("System information"),
|
||||
"CppPlatform/Extensions/systeminfoicon24.png",
|
||||
"CppPlatform/Extensions/systeminfoicon16.png")
|
||||
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.SetFunctionName("SystemInfo::IsWebGLSupported")
|
||||
@@ -47,16 +47,28 @@ void DeclareSystemInfoExtension(gd::PlatformExtension& extension) {
|
||||
.AddCondition(
|
||||
"IsPreview",
|
||||
_("Is the game running as a preview"),
|
||||
_(
|
||||
"Check if the game is currently being previewed in the editor. "
|
||||
"This can be used to enable a \"Debug mode\" or do some work only in previews."
|
||||
),
|
||||
_("Check if the game is currently being previewed in the editor. "
|
||||
"This can be used to enable a \"Debug mode\" or do some work only "
|
||||
"in previews."),
|
||||
_("The game is being previewed in the editor"),
|
||||
_("System information"),
|
||||
"CppPlatform/Extensions/systeminfoicon24.png",
|
||||
"CppPlatform/Extensions/systeminfoicon16.png")
|
||||
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"HasTouchScreen",
|
||||
_("Device has a touchscreen"),
|
||||
_("Check if the device running the game has a touchscreen (typically "
|
||||
"Android phones, iPhones, iPads, but also some laptops)."),
|
||||
_("The device has a touchscreen"),
|
||||
_("System information"),
|
||||
"CppPlatform/Extensions/systeminfoicon24.png",
|
||||
"CppPlatform/Extensions/systeminfoicon16.png")
|
||||
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -35,6 +35,10 @@ class SystemInfoJsExtension : public gd::PlatformExtension {
|
||||
.codeExtraInformation
|
||||
.SetIncludeFile("Extensions/SystemInfo/systeminfotools.js")
|
||||
.SetFunctionName("gdjs.evtTools.systemInfo.isPreview");
|
||||
GetAllConditions()["SystemInfo::HasTouchScreen"]
|
||||
.codeExtraInformation
|
||||
.SetIncludeFile("Extensions/SystemInfo/systeminfotools.js")
|
||||
.SetFunctionName("gdjs.evtTools.systemInfo.hasTouchScreen");
|
||||
|
||||
StripUnimplementedInstructionsAndExpressions();
|
||||
GD_COMPLETE_EXTENSION_COMPILATION_INFORMATION();
|
||||
|
@@ -1,48 +1,120 @@
|
||||
// @ts-check
|
||||
/**
|
||||
GDevelop - SystemInfo Extension
|
||||
Copyright (c) 2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
* GDevelop - SystemInfo Extension
|
||||
* Copyright (c) 2016-present Florian Rival (Florian.Rival@gmail.com)
|
||||
*/
|
||||
|
||||
/**
|
||||
* @memberof gdjs.evtTools
|
||||
* @class linkedObjects
|
||||
* @static
|
||||
* @private
|
||||
*/
|
||||
gdjs.evtTools.systemInfo = {};
|
||||
gdjs.evtTools.systemInfo = (function () {
|
||||
/** @type {?boolean} */
|
||||
let cachedIsMobile = null;
|
||||
/** @type {?boolean} */
|
||||
let cachedHasTouchScreen = null;
|
||||
|
||||
gdjs.evtTools.systemInfo.isMobile = function() {
|
||||
if (typeof cc !== "undefined" && cc.sys) {
|
||||
return cc.sys.isMobile;
|
||||
} else if (typeof Cocoon !== "undefined" && Cocoon.App) {
|
||||
return true;
|
||||
} else if (typeof window !== "undefined" && window.cordova) {
|
||||
return true;
|
||||
} else if (typeof window !== "undefined") {
|
||||
// Try to detect mobile device browsers.
|
||||
if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
|
||||
|| /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0,4))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/** @returns {boolean} */
|
||||
const checkIsMobile = () => {
|
||||
// @ts-ignore
|
||||
if (typeof cc !== 'undefined' && cc.sys) {
|
||||
// @ts-ignore
|
||||
return cc.sys.isMobile;
|
||||
|
||||
return false;
|
||||
};
|
||||
// @ts-ignore
|
||||
} else if (typeof Cocoon !== 'undefined' && Cocoon.App) {
|
||||
return true;
|
||||
|
||||
/**
|
||||
* Check if the the device supports WebGL.
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @returns {boolean} true if WebGL is supported
|
||||
*/
|
||||
gdjs.evtTools.systemInfo.isWebGLSupported = function(runtimeScene) {
|
||||
return runtimeScene.getGame().getRenderer().isWebGLSupported();
|
||||
};
|
||||
// @ts-ignore
|
||||
} else if (typeof window !== 'undefined' && window.cordova) {
|
||||
return true;
|
||||
} else if (typeof window !== 'undefined') {
|
||||
// Try to detect mobile device browsers.
|
||||
if (
|
||||
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(
|
||||
navigator.userAgent
|
||||
) ||
|
||||
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
|
||||
navigator.userAgent.substr(0, 4)
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the game is running as a preview, launched from an editor.
|
||||
* @param {gdjs.RuntimeScene} runtimeScene The current scene.
|
||||
* @returns {boolean} true if the game is running as a preview.
|
||||
*/
|
||||
gdjs.evtTools.systemInfo.isPreview = function(runtimeScene) {
|
||||
return runtimeScene.getGame().isPreview();
|
||||
};
|
||||
// Try to detect iOS
|
||||
if (/iPad|iPhone|iPod/.test(navigator.platform)) {
|
||||
return true;
|
||||
} else if (/MacIntel/.test(navigator.platform)) {
|
||||
// Work around for recent iPads that are "desktop-class browsing".
|
||||
// We can still detect them using their touchscreen, but this is a hack.
|
||||
// If mac laptops start to support touchscreens, this won't work anymore. Hence it's better
|
||||
// to test for the presence of a touchscreen if needed rather than checking if the device
|
||||
// is "mobile".
|
||||
return !!navigator.maxTouchPoints && navigator.maxTouchPoints > 2;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the game runs on a mobile device (iPhone, iPad, Android).
|
||||
* Note that the distinction between what is a mobile device and what is not
|
||||
* is becoming blurry. If you use this for mobile controls,
|
||||
* prefer to check if the device has touchscreen support.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
const isMobile = () => {
|
||||
if (cachedIsMobile !== null) {
|
||||
return cachedIsMobile;
|
||||
}
|
||||
|
||||
return (cachedIsMobile = checkIsMobile());
|
||||
};
|
||||
|
||||
/** @returns {boolean} */
|
||||
const checkHasTouchScreen = () => {
|
||||
// First check if the device is mobile, as all mobile devices have a touchscreen
|
||||
// and some older browsers don't have support for `navigator.maxTouchPoints`
|
||||
if (isMobile()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !!navigator.maxTouchPoints && navigator.maxTouchPoints > 2;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the device has a touchscreen
|
||||
*/
|
||||
const hasTouchScreen = () => {
|
||||
if (cachedHasTouchScreen !== null) {
|
||||
return cachedHasTouchScreen;
|
||||
}
|
||||
|
||||
return (cachedHasTouchScreen = checkHasTouchScreen());
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the the device supports WebGL.
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @returns {boolean} true if WebGL is supported
|
||||
*/
|
||||
const isWebGLSupported = (runtimeScene) => {
|
||||
return runtimeScene.getGame().getRenderer().isWebGLSupported();
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the game is running as a preview, launched from an editor.
|
||||
* @param {gdjs.RuntimeScene} runtimeScene The current scene.
|
||||
* @returns {boolean} true if the game is running as a preview.
|
||||
*/
|
||||
const isPreview = (runtimeScene) => {
|
||||
return runtimeScene.getGame().isPreview();
|
||||
};
|
||||
|
||||
return {
|
||||
isPreview: isPreview,
|
||||
isWebGLSupported: isWebGLSupported,
|
||||
hasTouchScreen: hasTouchScreen,
|
||||
isMobile: isMobile,
|
||||
};
|
||||
})();
|
||||
|
@@ -71,11 +71,3 @@ gdjs.TextEntryRuntimeObject.prototype.activate = function(enable) {
|
||||
this._activated = enable;
|
||||
this._renderer.activate(this._activated);
|
||||
};
|
||||
|
||||
gdjs.TextEntryRuntimeObject.prototype.setLayer = function(layer) {
|
||||
// No renderable object
|
||||
};
|
||||
|
||||
gdjs.TextEntryRuntimeObject.prototype.setZOrder = function(z) {
|
||||
// No renderable object
|
||||
};
|
||||
|
@@ -384,7 +384,7 @@ gdjs.TextRuntimeObject.prototype.setColor = function(str) {
|
||||
|
||||
/**
|
||||
* Get the text color.
|
||||
* @return {String} The color as a "R;G;B" string, for example: "255;0;0"
|
||||
* @return {string} The color as a "R;G;B" string, for example: "255;0;0"
|
||||
*/
|
||||
gdjs.TextRuntimeObject.prototype.getColor = function(str) {
|
||||
return this._color[0] + ";" + this._color[1] + ";" + this._color[2];
|
||||
|
@@ -62,15 +62,15 @@ void DeclareTiledSpriteObjectExtension(gd::PlatformExtension& extension) {
|
||||
|
||||
obj.AddAction(
|
||||
"SetColor",
|
||||
_("Global color"),
|
||||
_("Change the global color of a Tiled Sprite. The default color is white."),
|
||||
_("Change color of _PARAM0_ to _PARAM1_"),
|
||||
_("Tint color"),
|
||||
_("Change the tint of a Tiled Sprite. The default color is white."),
|
||||
_("Change tint of _PARAM0_ to _PARAM1_"),
|
||||
_("Effects"),
|
||||
"res/actions/color24.png",
|
||||
"res/actions/color.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "TiledSprite")
|
||||
.AddParameter("color", _("Color"));
|
||||
.AddParameter("color", _("Tint"));
|
||||
|
||||
obj.AddAction("Width",
|
||||
_("Width"),
|
||||
|
@@ -24,8 +24,7 @@ gdjs.TiledSpriteRuntimeObjectPixiRenderer.prototype.getRendererObject = function
|
||||
};
|
||||
|
||||
gdjs.TiledSpriteRuntimeObjectPixiRenderer.prototype.updateOpacity = function() {
|
||||
//TODO: Workaround a not working property in PIXI.js:
|
||||
this._tiledSprite.alpha = this._tiledSprite.visible ? this._object.opacity/255 : 0;
|
||||
this._tiledSprite.alpha = this._object.opacity/255;
|
||||
}
|
||||
|
||||
gdjs.TiledSpriteRuntimeObjectPixiRenderer.prototype.updatePosition = function() {
|
||||
|
@@ -213,7 +213,7 @@ gdjs.TiledSpriteRuntimeObject.prototype.setColor = function(rgbColor) {
|
||||
/**
|
||||
* Get the tint of the tiled sprite object.
|
||||
*
|
||||
* @returns {string} rgbColor The color, in RGB format ("128;200;255").
|
||||
* @returns {string} The color, in RGB format ("128;200;255").
|
||||
*/
|
||||
gdjs.TiledSpriteRuntimeObject.prototype.getColor = function() {
|
||||
return this._renderer.getColor();
|
||||
|
@@ -290,8 +290,8 @@ void DeclareTopDownMovementBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddCondition(
|
||||
"Angle",
|
||||
_("Angle of movement"),
|
||||
_("Compare the angle of the top-down movemement of the object."),
|
||||
_("the angle of movemement"),
|
||||
_("Compare the angle of the top-down movement of the object."),
|
||||
_("the angle of movement"),
|
||||
_("Movement"),
|
||||
"CppPlatform/Extensions/topdownmovementicon24.png",
|
||||
"CppPlatform/Extensions/topdownmovementicon16.png")
|
||||
@@ -305,8 +305,8 @@ void DeclareTopDownMovementBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddCondition(
|
||||
"XVelocity",
|
||||
_("Speed on X axis"),
|
||||
_("Compare the velocity of the top-down movemement of the object on the X axis."),
|
||||
_("the speed of movemement on X axis"),
|
||||
_("Compare the velocity of the top-down movement of the object on the X axis."),
|
||||
_("the speed of movement on X axis"),
|
||||
_("Movement"),
|
||||
"CppPlatform/Extensions/topdownmovementicon24.png",
|
||||
"CppPlatform/Extensions/topdownmovementicon16.png")
|
||||
@@ -320,8 +320,8 @@ void DeclareTopDownMovementBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddCondition(
|
||||
"YVelocity",
|
||||
_("Speed on Y axis"),
|
||||
_("Compare the velocity of the top-down movemement of the object on the Y axis."),
|
||||
_("the speed of movemement on Y axis"),
|
||||
_("Compare the velocity of the top-down movement of the object on the Y axis."),
|
||||
_("the speed of movement on Y axis"),
|
||||
_("Movement"),
|
||||
"CppPlatform/Extensions/topdownmovementicon24.png",
|
||||
"CppPlatform/Extensions/topdownmovementicon16.png")
|
||||
@@ -347,7 +347,7 @@ void DeclareTopDownMovementBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
|
||||
aut.AddCondition("DiagonalsAllowed",
|
||||
_("Diagonal movement"),
|
||||
_("Return true if the object is allowed to move diagonally"),
|
||||
_("Check if the object is allowed to move diagonally"),
|
||||
_("Allow diagonal moves for _PARAM0_"),
|
||||
_("Movement"),
|
||||
"CppPlatform/Extensions/topdownmovementicon24.png",
|
||||
@@ -375,7 +375,7 @@ void DeclareTopDownMovementBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddCondition(
|
||||
"ObjectRotated",
|
||||
_("Object rotated"),
|
||||
_("Return true if the object is rotated while traveling on its path."),
|
||||
_("Check if the object is rotated while traveling on its path."),
|
||||
_("_PARAM0_ is rotated when moving"),
|
||||
_("Movement"),
|
||||
"CppPlatform/Extensions/topdownmovementicon24.png",
|
||||
|
@@ -66,8 +66,8 @@ module.exports = {
|
||||
tweenBehavior,
|
||||
new gd.BehaviorsSharedData()
|
||||
)
|
||||
.setIncludeFile("Extensions/TweenBehavior/tweenruntimebehavior.js")
|
||||
.addIncludeFile("Extensions/TweenBehavior/shifty.js");
|
||||
.setIncludeFile("Extensions/TweenBehavior/shifty.js")
|
||||
.addIncludeFile("Extensions/TweenBehavior/tweenruntimebehavior.js");
|
||||
|
||||
const easingChoices = JSON.stringify([
|
||||
"linear",
|
||||
@@ -198,6 +198,64 @@ module.exports = {
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName("addObjectPositionXTween");
|
||||
|
||||
behavior
|
||||
.addAction(
|
||||
"AddObjectWidthTween",
|
||||
_("Add object width tween"),
|
||||
_("Add a tween animation for the object width."),
|
||||
_(
|
||||
"Tween the width of _PARAM0_ to _PARAM3_ with easing _PARAM4_ over _PARAM5_ms as _PARAM2_"
|
||||
),
|
||||
_("Size"),
|
||||
"JsPlatform/Extensions/tween_behavior24.png",
|
||||
"JsPlatform/Extensions/tween_behavior32.png"
|
||||
)
|
||||
.addParameter("object", _("Object"), "", false)
|
||||
.addParameter("behavior", _("Behavior"), "TweenBehavior", false)
|
||||
.addParameter("string", _("Tween Identifier"), "", false)
|
||||
.addParameter("expression", _("To width"), "", false)
|
||||
.addParameter("stringWithSelector", _("Easing"), easingChoices, false)
|
||||
.setDefaultValue("linear")
|
||||
.addParameter("expression", _("Duration"), "", false)
|
||||
.addParameter(
|
||||
"yesorno",
|
||||
_("Destroy this object when tween finishes"),
|
||||
"",
|
||||
false
|
||||
)
|
||||
.setDefaultValue("no")
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName("addObjectWidthTween");
|
||||
|
||||
behavior
|
||||
.addAction(
|
||||
"AddObjectHeightTween",
|
||||
_("Add object height tween"),
|
||||
_("Add a tween animation for the object height."),
|
||||
_(
|
||||
"Tween the height of _PARAM0_ to _PARAM3_ with easing _PARAM4_ over _PARAM5_ms as _PARAM2_"
|
||||
),
|
||||
_("Size"),
|
||||
"JsPlatform/Extensions/tween_behavior24.png",
|
||||
"JsPlatform/Extensions/tween_behavior32.png"
|
||||
)
|
||||
.addParameter("object", _("Object"), "", false)
|
||||
.addParameter("behavior", _("Behavior"), "TweenBehavior", false)
|
||||
.addParameter("string", _("Tween Identifier"), "", false)
|
||||
.addParameter("expression", _("To height"), "", false)
|
||||
.addParameter("stringWithSelector", _("Easing"), easingChoices, false)
|
||||
.setDefaultValue("linear")
|
||||
.addParameter("expression", _("Duration"), "", false)
|
||||
.addParameter(
|
||||
"yesorno",
|
||||
_("Destroy this object when tween finishes"),
|
||||
"",
|
||||
false
|
||||
)
|
||||
.setDefaultValue("no")
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName("addObjectHeightTween");
|
||||
|
||||
behavior
|
||||
.addAction(
|
||||
"AddObjectPositionYTween",
|
||||
|
@@ -817,6 +817,106 @@ gdjs.TweenRuntimeBehavior.prototype.addTextObjectCharacterSizeTween = function(
|
||||
this._setupTweenEnding(identifier, destroyObjectWhenFinished);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add an object width tween.
|
||||
* @param {string} identifier Unique id to idenfify the tween
|
||||
* @param {number} toWidth The target width
|
||||
* @param {string} easingValue Type of easing
|
||||
* @param {number} durationValue Duration in milliseconds
|
||||
* @param {boolean} destroyObjectWhenFinished Destroy this object when the tween ends
|
||||
*/
|
||||
gdjs.TweenRuntimeBehavior.prototype.addObjectWidthTween = function(
|
||||
identifier,
|
||||
toWidth,
|
||||
easingValue,
|
||||
durationValue,
|
||||
destroyObjectWhenFinished
|
||||
) {
|
||||
var that = this;
|
||||
if (!this._isActive) return;
|
||||
if (!!gdjs.TweenRuntimeBehavior.easings[easingValue]) return;
|
||||
|
||||
if (this._tweenExists(identifier)) {
|
||||
this.removeTween(identifier);
|
||||
}
|
||||
|
||||
var newTweenable = gdjs.TweenRuntimeBehavior.makeNewTweenable(
|
||||
this._runtimeScene
|
||||
);
|
||||
newTweenable.setConfig({
|
||||
from: {
|
||||
width: this.owner.getWidth(),
|
||||
},
|
||||
to: {
|
||||
width: toWidth,
|
||||
},
|
||||
duration: durationValue,
|
||||
easing: easingValue,
|
||||
step: function step(state) {
|
||||
that.owner.setWidth(state.width);
|
||||
},
|
||||
});
|
||||
|
||||
this._addTween(
|
||||
identifier,
|
||||
newTweenable,
|
||||
this._runtimeScene.getTimeManager().getTimeFromStart(),
|
||||
durationValue
|
||||
);
|
||||
|
||||
this._setupTweenEnding(identifier, destroyObjectWhenFinished);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add an object height tween.
|
||||
* @param {string} identifier Unique id to idenfify the tween
|
||||
* @param {number} toHeight The target height
|
||||
* @param {string} easingValue Type of easing
|
||||
* @param {number} durationValue Duration in milliseconds
|
||||
* @param {boolean} destroyObjectWhenFinished Destroy this object when the tween ends
|
||||
*/
|
||||
gdjs.TweenRuntimeBehavior.prototype.addObjectHeightTween = function(
|
||||
identifier,
|
||||
toHeight,
|
||||
easingValue,
|
||||
durationValue,
|
||||
destroyObjectWhenFinished
|
||||
) {
|
||||
var that = this;
|
||||
if (!this._isActive) return;
|
||||
if (!!gdjs.TweenRuntimeBehavior.easings[easingValue]) return;
|
||||
|
||||
if (this._tweenExists(identifier)) {
|
||||
this.removeTween(identifier);
|
||||
}
|
||||
|
||||
var newTweenable = gdjs.TweenRuntimeBehavior.makeNewTweenable(
|
||||
this._runtimeScene
|
||||
);
|
||||
newTweenable.setConfig({
|
||||
from: {
|
||||
height: this.owner.getHeight(),
|
||||
},
|
||||
to: {
|
||||
height: toHeight,
|
||||
},
|
||||
duration: durationValue,
|
||||
easing: easingValue,
|
||||
step: function step(state) {
|
||||
that.owner.setHeight(state.height);
|
||||
},
|
||||
});
|
||||
|
||||
this._addTween(
|
||||
identifier,
|
||||
newTweenable,
|
||||
this._runtimeScene.getTimeManager().getTimeFromStart(),
|
||||
durationValue
|
||||
);
|
||||
|
||||
this._setupTweenEnding(identifier, destroyObjectWhenFinished);
|
||||
};
|
||||
|
||||
/**
|
||||
* Tween is playing.
|
||||
* @param {string} identifier Unique id to idenfify the tween
|
||||
@@ -1030,23 +1130,15 @@ gdjs.registerRuntimeSceneResumedCallback(function(runtimeScene) {
|
||||
gdjs.TweenRuntimeBehavior._tweensProcessed = false;
|
||||
gdjs.TweenRuntimeBehavior._currentTweenTime = 0;
|
||||
|
||||
gdjs.TweenRuntimeBehavior.prototype.doStepPreEvents = function(runtimeScene) {
|
||||
// Process tweens (once per frame).
|
||||
if (!gdjs.TweenRuntimeBehavior._tweensProcessed) {
|
||||
gdjs.TweenRuntimeBehavior._currentTweenTime = runtimeScene
|
||||
.getTimeManager()
|
||||
.getTimeFromStart();
|
||||
shifty.processTweens();
|
||||
gdjs.TweenRuntimeBehavior._tweensProcessed = true;
|
||||
}
|
||||
};
|
||||
|
||||
gdjs.TweenRuntimeBehavior.prototype.doStepPostEvents = function(runtimeScene) {
|
||||
gdjs.TweenRuntimeBehavior._tweensProcessed = false;
|
||||
};
|
||||
gdjs.registerRuntimeScenePreEventsCallback(function(runtimeScene) {
|
||||
gdjs.TweenRuntimeBehavior._currentTweenTime = runtimeScene
|
||||
.getTimeManager()
|
||||
.getTimeFromStart();
|
||||
shifty.processTweens();
|
||||
});
|
||||
|
||||
// Set up Shifty.js so that the processing ("tick"/updates) is handled
|
||||
// by the behavior (once per frame):
|
||||
// by the behavior, once per frame. See above.
|
||||
shifty.Tweenable.setScheduleFunction(function() {
|
||||
/* Do nothing, we'll call processTweens manually. */
|
||||
});
|
||||
|
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include "JsCodeEvent.h"
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/Serialization.h"
|
||||
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
|
||||
@@ -19,7 +20,7 @@ using namespace std;
|
||||
namespace gdjs {
|
||||
|
||||
vector<pair<gd::Expression*, gd::ParameterMetadata> >
|
||||
JsCodeEvent::GetAllExpressionsWithMetadata() {
|
||||
JsCodeEvent::GetAllExpressionsWithMetadata() {
|
||||
vector<pair<gd::Expression*, gd::ParameterMetadata> >
|
||||
allExpressionsWithMetadata;
|
||||
auto metadata = gd::ParameterMetadata().SetType("object");
|
||||
@@ -30,7 +31,7 @@ vector<pair<gd::Expression*, gd::ParameterMetadata> >
|
||||
}
|
||||
|
||||
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
|
||||
JsCodeEvent::GetAllExpressionsWithMetadata() const {
|
||||
JsCodeEvent::GetAllExpressionsWithMetadata() const {
|
||||
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
|
||||
allExpressionsWithMetadata;
|
||||
auto metadata = gd::ParameterMetadata().SetType("object");
|
||||
@@ -45,15 +46,14 @@ void JsCodeEvent::SerializeTo(gd::SerializerElement& element) const {
|
||||
element.AddChild("parameterObjects")
|
||||
.SetValue(parameterObjects.GetPlainString());
|
||||
element.AddChild("useStrict").SetValue(useStrict);
|
||||
element.AddChild("eventsSheetExpanded").SetValue(eventsSheetExpanded);
|
||||
}
|
||||
|
||||
void JsCodeEvent::UnserializeFrom(gd::Project& project,
|
||||
const gd::SerializerElement& element) {
|
||||
inlineCode = element.GetChild("inlineCode").GetValue().GetString();
|
||||
parameterObjects =
|
||||
gd::Expression(element.GetChild("parameterObjects")
|
||||
.GetValue()
|
||||
.GetString());
|
||||
parameterObjects = gd::Expression(
|
||||
element.GetChild("parameterObjects").GetValue().GetString());
|
||||
|
||||
if (!element.HasChild("useStrict")) {
|
||||
// Compatibility with GD <= 5.0.0-beta68
|
||||
@@ -62,11 +62,20 @@ void JsCodeEvent::UnserializeFrom(gd::Project& project,
|
||||
} else {
|
||||
useStrict = element.GetChild("useStrict").GetBoolValue();
|
||||
}
|
||||
|
||||
if (!element.HasChild("eventsSheetExpanded")) {
|
||||
// Compatibility with GD <= 5.0.0-beta101
|
||||
eventsSheetExpanded = false;
|
||||
// end of compatibility code
|
||||
} else {
|
||||
eventsSheetExpanded = element.GetChild("eventsSheetExpanded").GetBoolValue();
|
||||
}
|
||||
}
|
||||
|
||||
JsCodeEvent::JsCodeEvent()
|
||||
: BaseEvent(),
|
||||
inlineCode("runtimeScene.setBackgroundColor(100,100,240);\n"),
|
||||
useStrict(true) {}
|
||||
useStrict(true),
|
||||
eventsSheetExpanded(false) {}
|
||||
|
||||
} // namespace gdjs
|
||||
|
@@ -47,6 +47,9 @@ class JsCodeEvent : public gd::BaseEvent {
|
||||
const gd::SerializerElement& element);
|
||||
virtual bool IsUseStrict() const { return useStrict; }
|
||||
|
||||
bool IsEventsSheetExpanded() const { return eventsSheetExpanded; }
|
||||
void SetEventsSheetExpanded(bool enable) { eventsSheetExpanded = enable; };
|
||||
|
||||
private:
|
||||
void Init(const JsCodeEvent& event);
|
||||
|
||||
@@ -56,6 +59,7 @@ class JsCodeEvent : public gd::BaseEvent {
|
||||
bool useStrict; ///< Should the generated JS function have "use strict". true
|
||||
///< by default. Should be removed once all the game engine
|
||||
///< is using "use strict".
|
||||
bool eventsSheetExpanded; ///< Is the code block expanded in the events sheet?
|
||||
};
|
||||
|
||||
} // namespace gdjs
|
||||
|
@@ -124,8 +124,7 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionCode(
|
||||
codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
|
||||
eventsFunction.GetParameters(), false),
|
||||
codeGenerator.GenerateEventsFunctionContext(
|
||||
eventsFunction.GetParameters(),
|
||||
"runtimeScene.getOnceTriggers()"),
|
||||
eventsFunction.GetParameters(), "runtimeScene.getOnceTriggers()"),
|
||||
eventsFunction.GetEvents(),
|
||||
codeGenerator.GenerateEventsFunctionReturn(eventsFunction));
|
||||
|
||||
@@ -154,8 +153,7 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
|
||||
// Generate the code setting up the context of the function.
|
||||
gd::String fullPreludeCode =
|
||||
preludeCode + "\n" +
|
||||
"var that = this;\n" +
|
||||
preludeCode + "\n" + "var that = this;\n" +
|
||||
// runtimeScene is supposed to be always accessible, read
|
||||
// it from the behavior
|
||||
"var runtimeScene = this._runtimeScene;\n" +
|
||||
@@ -173,7 +171,8 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
onceTriggersVariable,
|
||||
// Pass the names of the parameters considered as the current
|
||||
// object and behavior parameters:
|
||||
"Object", "Behavior");
|
||||
"Object",
|
||||
"Behavior");
|
||||
|
||||
gd::String output = GenerateEventsListCompleteFunctionCode(
|
||||
project,
|
||||
@@ -338,14 +337,17 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
// Unknown object, don't create anything:
|
||||
" return null;\n" +
|
||||
" },\n"
|
||||
// Allow to get a layer directly from the context for convenience:
|
||||
" getLayer: function(layerName) {\n"
|
||||
" return runtimeScene.getLayer(layerName);\n"
|
||||
" },\n"
|
||||
// Getter for arguments that are not objects
|
||||
" getArgument: function(argName) {\n" +
|
||||
argumentsGetters + " return \"\";\n" +
|
||||
" },\n" +
|
||||
// Expose OnceTriggers (will be pointing either to the runtime scene ones,
|
||||
// or the ones from the behavior):
|
||||
" getOnceTriggers: function() { return " + onceTriggersVariable + "; }\n" +
|
||||
"};\n";
|
||||
argumentsGetters + " return \"\";\n" + " },\n" +
|
||||
// Expose OnceTriggers (will be pointing either to the runtime scene
|
||||
// ones, or the ones from the behavior):
|
||||
" getOnceTriggers: function() { return " + onceTriggersVariable +
|
||||
"; }\n" + "};\n";
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateEventsFunctionReturn(
|
||||
@@ -739,16 +741,16 @@ gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
|
||||
|
||||
gd::String copiedListName =
|
||||
GetObjectListName(object, *context.GetParentContext());
|
||||
return objectListName + ".createFrom(" + copiedListName + ");\n";
|
||||
return "gdjs.copyArray(" + copiedListName + ", " + objectListName + ");\n";
|
||||
};
|
||||
|
||||
gd::String declarationsCode;
|
||||
for (auto object : context.GetObjectsListsToBeDeclared()) {
|
||||
gd::String objectListDeclaration = "";
|
||||
if (!context.ObjectAlreadyDeclared(object)) {
|
||||
objectListDeclaration += GetObjectListName(object, context) +
|
||||
".createFrom(" +
|
||||
GenerateAllInstancesGetterCode(object) + ");";
|
||||
objectListDeclaration += "gdjs.copyArray(" +
|
||||
GenerateAllInstancesGetterCode(object) + ", " +
|
||||
GetObjectListName(object, context) + ");";
|
||||
context.SetObjectDeclared(object);
|
||||
} else
|
||||
objectListDeclaration = declareObjectList(object, context);
|
||||
|
@@ -4,6 +4,7 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "AdvancedExtension.h"
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
@@ -68,6 +69,28 @@ AdvancedExtension::AdvancedExtension() {
|
||||
booleanCode + "; }";
|
||||
});
|
||||
|
||||
GetAllConditions()["GetArgumentAsBoolean"]
|
||||
.GetCodeExtraInformation()
|
||||
.SetCustomCodeGenerator([](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
gd::String parameterNameCode =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"string",
|
||||
instruction.GetParameter(0).GetPlainString());
|
||||
gd::String valueCode =
|
||||
gd::String(instruction.IsInverted() ? "!" : "") +
|
||||
"(typeof eventsFunctionContext !== 'undefined' ? "
|
||||
"!!eventsFunctionContext.getArgument(" +
|
||||
parameterNameCode + ") : false)";
|
||||
gd::String outputCode =
|
||||
codeGenerator.GenerateBooleanFullName("conditionTrue", context) +
|
||||
".val = " + valueCode + ";\n";
|
||||
return outputCode;
|
||||
});
|
||||
|
||||
GetAllExpressions()["GetArgumentAsNumber"]
|
||||
.GetCodeExtraInformation()
|
||||
.SetCustomCodeGenerator([](const std::vector<gd::Expression>& parameters,
|
||||
|
@@ -189,6 +189,10 @@ BaseObjectExtension::BaseObjectExtension() {
|
||||
"getAverageForce().getLength"); // Deprecated
|
||||
objectExpressions["Distance"].SetFunctionName("getDistanceToObject");
|
||||
objectExpressions["SqDistance"].SetFunctionName("getSqDistanceToObject");
|
||||
objectExpressions["DistanceToPosition"].SetFunctionName("getDistanceToPosition");
|
||||
objectExpressions["SqDistanceToPosition"].SetFunctionName("getSqDistanceToPosition");
|
||||
objectExpressions["AngleToObject"].SetFunctionName("getAngleToObject");
|
||||
objectExpressions["AngleToPosition"].SetFunctionName("getAngleToPosition");
|
||||
objectExpressions["ObjectTimerElapsedTime"].SetFunctionName(
|
||||
"getTimerElapsedTimeInSeconds");
|
||||
objectStrExpressions["ObjectName"].SetFunctionName("getName");
|
||||
|
@@ -81,6 +81,13 @@ CameraExtension::CameraExtension() {
|
||||
GetAllExpressions()["LayerTimeScale"].SetFunctionName(
|
||||
"gdjs.evtTools.camera.getLayerTimeScale");
|
||||
|
||||
GetAllConditions()["LayerDefaultZOrder"].SetFunctionName(
|
||||
"gdjs.evtTools.camera.getLayerDefaultZOrder");
|
||||
GetAllActions()["SetLayerDefaultZOrder"].SetFunctionName(
|
||||
"gdjs.evtTools.camera.setLayerDefaultZOrder");
|
||||
GetAllExpressions()["LayerDefaultZOrder"].SetFunctionName(
|
||||
"gdjs.evtTools.camera.getLayerDefaultZOrder");
|
||||
|
||||
StripUnimplementedInstructionsAndExpressions(); // Unimplemented things are
|
||||
// listed here:
|
||||
/*
|
||||
|
@@ -229,8 +229,9 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
gd::String::From(parentContext.GetContextDepth()) + "_" +
|
||||
gd::String::From(parentContext.GetCurrentConditionDepth()) +
|
||||
"final";
|
||||
code += codeGenerator.GetObjectListName(*it, parentContext) +
|
||||
".createFrom(" + finalObjList + ");\n";
|
||||
code += "gdjs.copyArray(" + finalObjList + ", " +
|
||||
codeGenerator.GetObjectListName(*it, parentContext) +
|
||||
");\n";
|
||||
}
|
||||
code += "}\n";
|
||||
|
||||
|
@@ -49,6 +49,10 @@ MathematicalToolsExtension::MathematicalToolsExtension() {
|
||||
GetAllExpressions()["mod"].SetFunctionName("gdjs.evtTools.common.mod");
|
||||
GetAllExpressions()["AngleDifference"].SetFunctionName(
|
||||
"gdjs.evtTools.common.angleDifference");
|
||||
GetAllExpressions()["AngleBetweenPositions"].SetFunctionName(
|
||||
"gdjs.evtTools.common.angleBetweenPositions");
|
||||
GetAllExpressions()["DistanceBetweenPositions"].SetFunctionName(
|
||||
"gdjs.evtTools.common.distanceBetweenPositions");
|
||||
GetAllExpressions()["int"].SetFunctionName("Math.round");
|
||||
GetAllExpressions()["rint"].SetFunctionName("Math.round");
|
||||
GetAllExpressions()["round"].SetFunctionName("Math.round");
|
||||
|
@@ -16,7 +16,11 @@ NetworkExtension::NetworkExtension() {
|
||||
gd::BuiltinExtensionsImplementer::ImplementsNetworkExtension(*this);
|
||||
|
||||
GetAllActions()["SendRequest"].SetFunctionName(
|
||||
"gdjs.evtTools.network.sendHttpRequest");
|
||||
"gdjs.evtTools.network.sendDeprecatedSynchronousRequest");
|
||||
GetAllActions()["SendAsyncRequest"].SetFunctionName(
|
||||
"gdjs.evtTools.network.sendAsyncRequest");
|
||||
GetAllActions()["EnableMetrics"].SetFunctionName(
|
||||
"gdjs.evtTools.network.enableMetrics");
|
||||
GetAllActions()["JSONToVariableStructure"].SetFunctionName(
|
||||
"gdjs.evtTools.network.jsonToVariableStructure");
|
||||
GetAllActions()["JSONToGlobalVariableStructure"].SetFunctionName(
|
||||
|
@@ -17,6 +17,8 @@ WindowExtension::WindowExtension() {
|
||||
|
||||
GetAllActions()["SetFullScreen"].SetFunctionName(
|
||||
"gdjs.evtTools.window.setFullScreen");
|
||||
GetAllConditions()["IsFullScreen"].SetFunctionName(
|
||||
"gdjs.evtTools.window.isFullScreen");
|
||||
GetAllActions()["SetWindowMargins"].SetFunctionName(
|
||||
"gdjs.evtTools.window.setMargins");
|
||||
GetAllActions()["SetWindowTitle"].SetFunctionName(
|
||||
|
@@ -122,8 +122,12 @@ bool Exporter::ExportWholePixiProject(
|
||||
else if (exportForFacebookInstantGames)
|
||||
source = gdjsRoot + "/Runtime/FacebookInstantGames/index.html";
|
||||
|
||||
if (!helper.ExportPixiIndexFile(
|
||||
exportedProject, source, exportDir, includesFiles, "")) {
|
||||
if (!helper.ExportPixiIndexFile(exportedProject,
|
||||
source,
|
||||
exportDir,
|
||||
includesFiles,
|
||||
/*nonRuntimeScriptsCacheBurst=*/0,
|
||||
"")) {
|
||||
gd::LogError(_("Error during export:\n") + lastError);
|
||||
return false;
|
||||
}
|
||||
@@ -211,7 +215,7 @@ bool Exporter::ExportWholeCocos2dProject(gd::Project& project,
|
||||
gd::ProjectStripper::StripProjectForExport(exportedProject);
|
||||
|
||||
//...and export it
|
||||
gd::SerializerElement noRuntimeGameOptions;
|
||||
gd::SerializerElement noRuntimeGameOptions;
|
||||
helper.ExportProjectData(
|
||||
fs, exportedProject, codeOutputDir + "/data.js", noRuntimeGameOptions);
|
||||
includesFiles.push_back(codeOutputDir + "/data.js");
|
||||
|
@@ -13,7 +13,10 @@
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/CodeGeneration/EffectsCodeGenerator.h"
|
||||
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/IDE/AbstractFileSystem.h"
|
||||
#include "GDCore/IDE/Project/ProjectResourcesCopier.h"
|
||||
#include "GDCore/IDE/ProjectStripper.h"
|
||||
@@ -22,6 +25,7 @@
|
||||
#include "GDCore/Project/ExternalLayout.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Project/SourceFile.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/TinyXml/tinyxml.h"
|
||||
@@ -31,6 +35,43 @@
|
||||
#include "GDJS/Extensions/JsPlatform.h"
|
||||
#undef CopyFile // Disable an annoying macro
|
||||
|
||||
namespace {
|
||||
|
||||
std::map<gd::String, gd::String> GetExtensionDependencyExtraSettingValues(
|
||||
const gd::Project &project,
|
||||
const gd::String &extensionName,
|
||||
const gd::DependencyMetadata &dependency) {
|
||||
std::map<gd::String, gd::String> values;
|
||||
|
||||
for (const auto &extraSetting : dependency.GetAllExtraSettings()) {
|
||||
const gd::String &type = extraSetting.second.GetType();
|
||||
const gd::String extraSettingValue =
|
||||
type == "ExtensionProperty"
|
||||
? project.GetExtensionProperties().GetValue(
|
||||
extensionName, extraSetting.second.GetValue())
|
||||
: extraSetting.second.GetValue();
|
||||
|
||||
if (!extraSettingValue.empty())
|
||||
values[extraSetting.first] = extraSettingValue;
|
||||
}
|
||||
|
||||
return values;
|
||||
};
|
||||
|
||||
bool AreMapKeysMissingElementOfSet(const std::map<gd::String, gd::String> &map,
|
||||
const std::set<gd::String> &set) {
|
||||
bool missingKey = false;
|
||||
for (auto &key : set) {
|
||||
if (map.find(key) == map.end()) {
|
||||
missingKey = true;
|
||||
}
|
||||
}
|
||||
|
||||
return missingKey;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace gdjs {
|
||||
|
||||
static void InsertUnique(std::vector<gd::String> &container, gd::String str) {
|
||||
@@ -141,6 +182,7 @@ bool ExporterHelper::ExportProjectForPixiPreview(
|
||||
gdjsRoot + "/Runtime/index.html",
|
||||
options.exportPath,
|
||||
includesFiles,
|
||||
options.nonRuntimeScriptsCacheBurst,
|
||||
"gdjs.runtimeGameOptions"))
|
||||
return false;
|
||||
|
||||
@@ -172,11 +214,16 @@ bool ExporterHelper::ExportPixiIndexFile(
|
||||
gd::String source,
|
||||
gd::String exportDir,
|
||||
const std::vector<gd::String> &includesFiles,
|
||||
unsigned int nonRuntimeScriptsCacheBurst,
|
||||
gd::String additionalSpec) {
|
||||
gd::String str = fs.ReadFile(source);
|
||||
|
||||
// Generate the file
|
||||
if (!CompleteIndexFile(str, exportDir, includesFiles, additionalSpec))
|
||||
if (!CompleteIndexFile(str,
|
||||
exportDir,
|
||||
includesFiles,
|
||||
nonRuntimeScriptsCacheBurst,
|
||||
additionalSpec))
|
||||
return false;
|
||||
|
||||
// Write the index.html file
|
||||
@@ -256,21 +303,45 @@ bool ExporterHelper::ExportCordovaFiles(const gd::Project &project,
|
||||
.FindAndReplace(
|
||||
"GDJS_PACKAGENAME",
|
||||
gd::Serializer::ToEscapedXMLString(project.GetPackageName()))
|
||||
.FindAndReplace("GDJS_ORIENTATION", project.GetOrientation())
|
||||
.FindAndReplace("GDJS_PROJECTVERSION", project.GetVersion())
|
||||
.FindAndReplace("<!-- GDJS_ICONS_ANDROID -->", makeIconsAndroid())
|
||||
.FindAndReplace("<!-- GDJS_ICONS_IOS -->", makeIconsIos());
|
||||
|
||||
if (!project.GetAdMobAppId().empty()) {
|
||||
str = str.FindAndReplace(
|
||||
"<!-- GDJS_ADMOB_PLUGIN_AND_APPLICATION_ID -->",
|
||||
"<plugin name=\"cordova-plugin-admob-free\" spec=\"~0.21.0\">\n"
|
||||
"\t\t<variable name=\"ADMOB_APP_ID\" value=\"" +
|
||||
project.GetAdMobAppId() +
|
||||
"\" />\n"
|
||||
"\t</plugin>");
|
||||
gd::String plugins = "";
|
||||
|
||||
for (std::shared_ptr<gd::PlatformExtension> extension :
|
||||
project.GetCurrentPlatform().GetAllPlatformExtensions()) {
|
||||
for (gd::DependencyMetadata dependency : extension->GetAllDependencies()) {
|
||||
if (dependency.GetDependencyType() == "cordova") {
|
||||
gd::String plugin;
|
||||
plugin += "<plugin name=\"" + dependency.GetExportName();
|
||||
if (dependency.GetVersion() != "") {
|
||||
plugin += "\" spec=\"" + dependency.GetVersion();
|
||||
}
|
||||
plugin += "\">\n";
|
||||
|
||||
auto extraSettingValues = GetExtensionDependencyExtraSettingValues(
|
||||
project, extension->GetName(), dependency);
|
||||
|
||||
// For Cordova, all settings are considered a plugin variable.
|
||||
for (auto &extraSetting : extraSettingValues) {
|
||||
plugin += "\t\t<variable name=\"" + extraSetting.first +
|
||||
"\" value=\"" + extraSetting.second + "\" />\n";
|
||||
}
|
||||
|
||||
plugin += "\t</plugin>";
|
||||
|
||||
// Don't include the plugin if an extra setting was not fulfilled.
|
||||
bool missingSetting = AreMapKeysMissingElementOfSet(
|
||||
extraSettingValues, dependency.GetRequiredExtraSettingsForExport());
|
||||
if (!missingSetting) plugins += plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str =
|
||||
str.FindAndReplace("<!-- GDJS_EXTENSION_CORDOVA_DEPENDENCY -->", plugins);
|
||||
|
||||
if (!fs.WriteToFile(exportDir + "/config.xml", str)) {
|
||||
lastError = "Unable to write Cordova config.xml file.";
|
||||
return false;
|
||||
@@ -331,7 +402,11 @@ bool ExporterHelper::ExportCocos2dFiles(
|
||||
|
||||
// Generate the file
|
||||
std::vector<gd::String> noIncludesInThisFile;
|
||||
if (!CompleteIndexFile(str, exportDir, noIncludesInThisFile, "")) {
|
||||
if (!CompleteIndexFile(str,
|
||||
exportDir,
|
||||
noIncludesInThisFile,
|
||||
/*nonRuntimeScriptsCacheBurst=*/0,
|
||||
"")) {
|
||||
lastError = "Unable to complete Cocos2d-JS index.html file.";
|
||||
return false;
|
||||
}
|
||||
@@ -421,6 +496,39 @@ bool ExporterHelper::ExportElectronFiles(const gd::Project &project,
|
||||
.FindAndReplace("\"GDJS_GAME_VERSION\"", jsonVersion)
|
||||
.FindAndReplace("\"GDJS_GAME_MANGLED_NAME\"", jsonMangledName);
|
||||
|
||||
gd::String packages = "";
|
||||
|
||||
for (std::shared_ptr<gd::PlatformExtension> extension :
|
||||
project.GetCurrentPlatform()
|
||||
.GetAllPlatformExtensions()) { // TODO Add a way to select only
|
||||
// used Extensions
|
||||
for (gd::DependencyMetadata dependency :
|
||||
extension->GetAllDependencies()) {
|
||||
if (dependency.GetDependencyType() == "npm") {
|
||||
if (dependency.GetVersion() == "") {
|
||||
gd::LogError(
|
||||
"Latest Version not available for NPM dependencies, "
|
||||
"dependency " +
|
||||
dependency.GetName() +
|
||||
" is not exported. Please specify a version when calling "
|
||||
"addDependency.");
|
||||
continue;
|
||||
}
|
||||
packages += "\n\t\"" + dependency.GetExportName() + "\": \"" +
|
||||
dependency.GetVersion() + "\",";
|
||||
// For node extra settings are ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!packages.empty()) {
|
||||
// Remove the , at the end as last item cannot have , in JSON.
|
||||
packages = packages.substr(0, packages.size() - 1);
|
||||
}
|
||||
|
||||
str = str.FindAndReplace("\"GDJS_EXTENSION_NPM_DEPENDENCY\": \"0\"",
|
||||
packages);
|
||||
|
||||
if (!fs.WriteToFile(exportDir + "/package.json", str)) {
|
||||
lastError = "Unable to write Electron package.json file.";
|
||||
return false;
|
||||
@@ -466,12 +574,14 @@ bool ExporterHelper::CompleteIndexFile(
|
||||
gd::String &str,
|
||||
gd::String exportDir,
|
||||
const std::vector<gd::String> &includesFiles,
|
||||
unsigned int nonRuntimeScriptsCacheBurst,
|
||||
gd::String additionalSpec) {
|
||||
if (additionalSpec.empty()) additionalSpec = "{}";
|
||||
|
||||
gd::String codeFilesIncludes;
|
||||
for (auto& include: includesFiles) {
|
||||
gd::String scriptSrc = GetExportedIncludeFilename(include);
|
||||
for (auto &include : includesFiles) {
|
||||
gd::String scriptSrc =
|
||||
GetExportedIncludeFilename(include, nonRuntimeScriptsCacheBurst);
|
||||
|
||||
// Sanity check if the file exists - if not skip it to avoid
|
||||
// including it in the list of scripts.
|
||||
@@ -674,7 +784,14 @@ bool ExporterHelper::ExportExternalSourceFiles(
|
||||
}
|
||||
|
||||
gd::String ExporterHelper::GetExportedIncludeFilename(
|
||||
const gd::String& include) {
|
||||
const gd::String &include, unsigned int nonRuntimeScriptsCacheBurst) {
|
||||
auto addSearchParameterToUrl = [](const gd::String &url,
|
||||
const gd::String &urlEncodedParameterName,
|
||||
const gd::String &urlEncodedValue) {
|
||||
gd::String separator = url.find("?") == gd::String::npos ? "?" : "&";
|
||||
return url + separator + urlEncodedParameterName + "=" + urlEncodedValue;
|
||||
};
|
||||
|
||||
if (!fs.IsAbsolute(include)) {
|
||||
// By convention, an include file that is relative is relative to
|
||||
// the "<GDJS Root>/Runtime" folder, and will have the same relative
|
||||
@@ -689,14 +806,25 @@ gd::String ExporterHelper::GetExportedIncludeFilename(
|
||||
} else {
|
||||
// Note: all the code generated from events are generated in another
|
||||
// folder and fall in this case:
|
||||
return fs.FileNameFrom(include);
|
||||
gd::String resolvedInclude = fs.FileNameFrom(include);
|
||||
|
||||
if (nonRuntimeScriptsCacheBurst == 0) {
|
||||
return resolvedInclude;
|
||||
}
|
||||
|
||||
// Add the parameter to force the browser to reload the code - useful
|
||||
// for cases where the browser is caching files that are getting
|
||||
// overwritten.
|
||||
return addSearchParameterToUrl(
|
||||
resolvedInclude,
|
||||
"gdCacheBurst",
|
||||
gd::String::From(nonRuntimeScriptsCacheBurst));
|
||||
}
|
||||
}
|
||||
|
||||
bool ExporterHelper::ExportIncludesAndLibs(
|
||||
const std::vector<gd::String> &includesFiles,
|
||||
gd::String exportDir) {
|
||||
for (auto& include : includesFiles) {
|
||||
const std::vector<gd::String> &includesFiles, gd::String exportDir) {
|
||||
for (auto &include : includesFiles) {
|
||||
if (!fs.IsAbsolute(include)) {
|
||||
// By convention, an include file that is relative is relative to
|
||||
// the "<GDJS Root>/Runtime" folder, and will have the same relative
|
||||
|
@@ -32,13 +32,17 @@ struct PreviewExportOptions {
|
||||
* \param exportPath_ The path in the filesystem where to export the files
|
||||
*/
|
||||
PreviewExportOptions(gd::Project &project_, const gd::String &exportPath_)
|
||||
: project(project_), exportPath(exportPath_), projectDataOnlyExport(false) {};
|
||||
: project(project_),
|
||||
exportPath(exportPath_),
|
||||
projectDataOnlyExport(false),
|
||||
nonRuntimeScriptsCacheBurst(0) {};
|
||||
|
||||
/**
|
||||
* \brief Set the address of the debugger server that the game should reach out to,
|
||||
* using WebSockets.
|
||||
* \brief Set the address of the debugger server that the game should reach
|
||||
* out to, using WebSockets.
|
||||
*/
|
||||
PreviewExportOptions &SetDebuggerServerAddress(const gd::String& address, const gd::String& port) {
|
||||
PreviewExportOptions &SetDebuggerServerAddress(const gd::String &address,
|
||||
const gd::String &port) {
|
||||
debuggerServerAddress = address;
|
||||
debuggerServerPort = port;
|
||||
return *this;
|
||||
@@ -76,11 +80,21 @@ struct PreviewExportOptions {
|
||||
* \brief Set if the export should only export the project data, not
|
||||
* exporting events code.
|
||||
*/
|
||||
PreviewExportOptions& SetProjectDataOnlyExport(bool enable) {
|
||||
PreviewExportOptions &SetProjectDataOnlyExport(bool enable) {
|
||||
projectDataOnlyExport = enable;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief If set to a non zero value, the exported script URLs will have an
|
||||
* extra search parameter added (with the given value) to ensure browser cache
|
||||
* is bypassed when they are loaded.
|
||||
*/
|
||||
PreviewExportOptions &SetNonRuntimeScriptsCacheBurst(unsigned int value) {
|
||||
nonRuntimeScriptsCacheBurst = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
gd::Project &project;
|
||||
gd::String exportPath;
|
||||
gd::String debuggerServerAddress;
|
||||
@@ -89,6 +103,7 @@ struct PreviewExportOptions {
|
||||
gd::String externalLayoutName;
|
||||
std::map<gd::String, int> includeFileHashes;
|
||||
bool projectDataOnlyExport;
|
||||
unsigned int nonRuntimeScriptsCacheBurst;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -154,7 +169,8 @@ class ExporterHelper {
|
||||
|
||||
/**
|
||||
* \brief Copy all the specified files to the
|
||||
* export directory. Relative files are copied from "<GDJS root>/Runtime" directory.
|
||||
* export directory. Relative files are copied from "<GDJS root>/Runtime"
|
||||
* directory.
|
||||
*
|
||||
* \param includesFiles A vector with filenames to be copied.
|
||||
* \param exportDir The directory where the files mus tbe copied.
|
||||
@@ -186,8 +202,8 @@ class ExporterHelper {
|
||||
* \brief Add the include files for all the objects of the project
|
||||
* and their behaviors.
|
||||
*/
|
||||
void ExportObjectAndBehaviorsIncludes(
|
||||
gd::Project &project, std::vector<gd::String> &includesFiles);
|
||||
void ExportObjectAndBehaviorsIncludes(gd::Project &project,
|
||||
std::vector<gd::String> &includesFiles);
|
||||
|
||||
/**
|
||||
* \brief Copy the external source files used by the game into the export
|
||||
@@ -214,13 +230,18 @@ class ExporterHelper {
|
||||
* \param source The file to be used as a template for the final file.
|
||||
* \param exportDir The directory where the preview must be created.
|
||||
* \param includesFiles The JS files to be included in the HTML file. Order is
|
||||
* important. \param additionalSpec JSON string that will be passed to the
|
||||
* important.
|
||||
* \param nonRuntimeScriptsCacheBurst If non zero, add an additional cache
|
||||
* bursting parameter to scripts, that are not part of the runtime/extensions,
|
||||
* to force the browser to reload them.
|
||||
* \param additionalSpec JSON string that will be passed to the
|
||||
* gdjs.RuntimeGame object.
|
||||
*/
|
||||
bool ExportPixiIndexFile(const gd::Project &project,
|
||||
gd::String source,
|
||||
gd::String exportDir,
|
||||
const std::vector<gd::String> &includesFiles,
|
||||
unsigned int nonRuntimeScriptsCacheBurst,
|
||||
gd::String additionalSpec = "");
|
||||
|
||||
/**
|
||||
@@ -232,6 +253,9 @@ class ExporterHelper {
|
||||
* \param includesFiles "<!--GDJS_CODE_FILES -->" will be
|
||||
* replaced by HTML tags to include the filenames
|
||||
* contained inside the vector.
|
||||
* \param nonRuntimeScriptsCacheBurst If non zero, add an additional cache
|
||||
* bursting parameter to scripts, that are not part of the runtime/extensions,
|
||||
* to force the browser to reload them.
|
||||
* \param additionalSpec The string "GDJS_ADDITIONAL_SPEC"
|
||||
* surrounded by comments marks will be replaced by the
|
||||
* content of this string.
|
||||
@@ -239,6 +263,7 @@ class ExporterHelper {
|
||||
bool CompleteIndexFile(gd::String &indexFileContent,
|
||||
gd::String exportDir,
|
||||
const std::vector<gd::String> &includesFiles,
|
||||
unsigned int nonRuntimeScriptsCacheBurst,
|
||||
gd::String additionalSpec);
|
||||
|
||||
/**
|
||||
@@ -290,7 +315,8 @@ class ExporterHelper {
|
||||
* \brief Given an include file, returns the name of the file to reference
|
||||
* in the exported game.
|
||||
*/
|
||||
gd::String GetExportedIncludeFilename(const gd::String& include);
|
||||
gd::String GetExportedIncludeFilename(
|
||||
const gd::String &include, unsigned int nonRuntimeScriptsCacheBurst = 0);
|
||||
|
||||
/**
|
||||
* \brief Change the directory where code files are generated.
|
||||
@@ -302,10 +328,10 @@ class ExporterHelper {
|
||||
}
|
||||
|
||||
static void AddDeprecatedFontFilesToFontResources(
|
||||
gd::AbstractFileSystem &fs,
|
||||
gd::ResourcesManager &resourcesManager,
|
||||
const gd::String &exportDir,
|
||||
gd::String urlPrefix = "");
|
||||
gd::AbstractFileSystem &fs,
|
||||
gd::ResourcesManager &resourcesManager,
|
||||
const gd::String &exportDir,
|
||||
gd::String urlPrefix = "");
|
||||
|
||||
gd::AbstractFileSystem
|
||||
&fs; ///< The abstract file system to be used for exportation.
|
||||
|
@@ -3,6 +3,7 @@
|
||||
<name>GDJS_PROJECTNAME</name>
|
||||
<content src="index.html" />
|
||||
<plugin name="cordova-plugin-whitelist" version="1" />
|
||||
<plugin name="cordova-plugin-screen-orientation" version="3.0.2" />
|
||||
<access origin="*" />
|
||||
<allow-intent href="http://*/*" />
|
||||
<allow-intent href="https://*/*" />
|
||||
@@ -21,14 +22,13 @@
|
||||
|
||||
<!-- GDJS_ICONS_IOS -->
|
||||
</platform>
|
||||
<preference name="orientation" value="GDJS_ORIENTATION" />
|
||||
<preference name="BackgroundColor" value="0xff000000"/>
|
||||
|
||||
<!-- Android Fullscreen -->
|
||||
<preference name="Fullscreen" value="true" />
|
||||
|
||||
<!-- Cordova/Phonegap version -->
|
||||
<preference name="phonegap-version" value="cli-8.0.0" />
|
||||
<preference name="phonegap-version" value="cli-9.0.0" />
|
||||
|
||||
<!-- GDJS_ADMOB_PLUGIN_AND_APPLICATION_ID -->
|
||||
<!-- GDJS_EXTENSION_CORDOVA_DEPENDENCY -->
|
||||
</widget>
|
||||
|
@@ -3,7 +3,7 @@
|
||||
* running in Electron Runtime.
|
||||
*/
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, shell } = require("electron");
|
||||
const { app, BrowserWindow, shell, Menu } = require("electron");
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
@@ -31,6 +31,8 @@ function createWindow() {
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile("app/index.html");
|
||||
|
||||
Menu.setApplicationMenu(null);
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
|
@@ -5,7 +5,9 @@
|
||||
"description": "GDJS_GAME_NAME",
|
||||
"author": "GDJS_GAME_AUTHOR",
|
||||
"version": "GDJS_GAME_VERSION",
|
||||
"dependencies": {},
|
||||
"dependencies": {
|
||||
"GDJS_EXTENSION_NPM_DEPENDENCY": "0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "8.2.5"
|
||||
},
|
||||
|
@@ -129,7 +129,11 @@ gdjs.LayerCocosRenderer.prototype.updateVisibility = function(visible) {
|
||||
this._cocosLayer.setVisible(visible);
|
||||
}
|
||||
|
||||
gdjs.LayerCocosRenderer.prototype.updateTime = function() {
|
||||
gdjs.LayerCocosRenderer.prototype.update = function() {
|
||||
// Unimplemented
|
||||
}
|
||||
|
||||
gdjs.LayerCocosRenderer.prototype.updateClearColor = function() {
|
||||
// Unimplemented
|
||||
}
|
||||
|
||||
|
@@ -49,6 +49,17 @@ gdjs.RuntimeGameCocosRenderer.prototype.setFullScreen = function(enable) {
|
||||
console.warn("Fullscreen is not implemented yet.");
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the game is in full screen.
|
||||
*/
|
||||
gdjs.RuntimeGameCocosRenderer.prototype.isFullScreen = function() {
|
||||
var electron = this.getElectron();
|
||||
if (electron) {
|
||||
return electron.remote.getCurrentWindow().isFullScreen();
|
||||
}
|
||||
return false; // Unsupported
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the window size, if possible.
|
||||
* @param {number} width The new width, in pixels.
|
||||
|
@@ -187,3 +187,14 @@ gdjs.RuntimeSceneCocosRenderer.prototype.showCursor = function() {
|
||||
gdjs.RuntimeSceneCocosRenderer.prototype.getCocosScene = function() {
|
||||
return this._cocosScene;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {gdjs.Layer} layer
|
||||
* @param {number} index
|
||||
*/
|
||||
gdjs.RuntimeSceneCocosRenderer.prototype.setLayerIndex = function (
|
||||
layer,
|
||||
index
|
||||
) {
|
||||
// Not implemented
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// @ts-check
|
||||
/*
|
||||
* GDevelop JS Platform
|
||||
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
|
||||
@@ -11,116 +12,270 @@
|
||||
*/
|
||||
gdjs.evtTools.camera = gdjs.evtTools.camera || {};
|
||||
|
||||
gdjs.evtTools.camera.setCameraX = function(runtimeScene, x, layer, cameraId) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return; }
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {number} x
|
||||
* @param {string} layer
|
||||
* @param {number} cameraId
|
||||
*/
|
||||
gdjs.evtTools.camera.setCameraX = function (runtimeScene, x, layer, cameraId) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
runtimeScene.getLayer(layer).setCameraX(x, cameraId);
|
||||
}
|
||||
runtimeScene.getLayer(layer).setCameraX(x, cameraId);
|
||||
};
|
||||
|
||||
gdjs.evtTools.camera.setCameraY = function(runtimeScene, y, layer, cameraId) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return; }
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {number} y
|
||||
* @param {string} layer
|
||||
* @param {number} cameraId
|
||||
*/
|
||||
gdjs.evtTools.camera.setCameraY = function (runtimeScene, y, layer, cameraId) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
runtimeScene.getLayer(layer).setCameraY(y, cameraId);
|
||||
}
|
||||
runtimeScene.getLayer(layer).setCameraY(y, cameraId);
|
||||
};
|
||||
|
||||
gdjs.evtTools.camera.getCameraX = function(runtimeScene, layer, cameraId) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return 0; }
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {string} layer
|
||||
* @param {number} cameraId
|
||||
* @returns {number}
|
||||
*/
|
||||
gdjs.evtTools.camera.getCameraX = function (runtimeScene, layer, cameraId) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return runtimeScene.getLayer(layer).getCameraX();
|
||||
}
|
||||
return runtimeScene.getLayer(layer).getCameraX();
|
||||
};
|
||||
|
||||
gdjs.evtTools.camera.getCameraY = function(runtimeScene, layer, cameraId) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return 0; }
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {string} layer
|
||||
* @param {number} cameraId
|
||||
* @returns {number}
|
||||
*/
|
||||
gdjs.evtTools.camera.getCameraY = function (runtimeScene, layer, cameraId) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return runtimeScene.getLayer(layer).getCameraY();
|
||||
}
|
||||
return runtimeScene.getLayer(layer).getCameraY();
|
||||
};
|
||||
|
||||
gdjs.evtTools.camera.getCameraWidth = function(runtimeScene, layer, cameraId) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return 0; }
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {string} layer
|
||||
* @param {number} cameraId
|
||||
* @returns {number}
|
||||
*/
|
||||
gdjs.evtTools.camera.getCameraWidth = function (runtimeScene, layer, cameraId) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return runtimeScene.getLayer(layer).getCameraWidth();
|
||||
}
|
||||
return runtimeScene.getLayer(layer).getCameraWidth();
|
||||
};
|
||||
|
||||
gdjs.evtTools.camera.getCameraHeight = function(runtimeScene, layer, cameraId) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return 0; }
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {string} layer
|
||||
* @param {number} cameraId
|
||||
* @returns {number}
|
||||
*/
|
||||
gdjs.evtTools.camera.getCameraHeight = function (
|
||||
runtimeScene,
|
||||
layer,
|
||||
cameraId
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return runtimeScene.getLayer(layer).getCameraHeight();
|
||||
}
|
||||
return runtimeScene.getLayer(layer).getCameraHeight();
|
||||
};
|
||||
|
||||
gdjs.evtTools.camera.showLayer = function(runtimeScene, layer) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return; }
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {string} layer
|
||||
*/
|
||||
gdjs.evtTools.camera.showLayer = function (runtimeScene, layer) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return runtimeScene.getLayer(layer).show(true);
|
||||
}
|
||||
return runtimeScene.getLayer(layer).show(true);
|
||||
};
|
||||
|
||||
gdjs.evtTools.camera.hideLayer = function(runtimeScene, layer) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return; }
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {string} layer
|
||||
*/
|
||||
gdjs.evtTools.camera.hideLayer = function (runtimeScene, layer) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return runtimeScene.getLayer(layer).show(false);
|
||||
}
|
||||
return runtimeScene.getLayer(layer).show(false);
|
||||
};
|
||||
|
||||
gdjs.evtTools.camera.layerIsVisible = function(runtimeScene, layer) {
|
||||
return runtimeScene.hasLayer(layer) && runtimeScene.getLayer(layer).isVisible();
|
||||
}
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {string} layer
|
||||
* @returns {boolean}
|
||||
*/
|
||||
gdjs.evtTools.camera.layerIsVisible = function (runtimeScene, layer) {
|
||||
return (
|
||||
runtimeScene.hasLayer(layer) && runtimeScene.getLayer(layer).isVisible()
|
||||
);
|
||||
};
|
||||
|
||||
gdjs.evtTools.camera.setCameraRotation = function(runtimeScene, rotation, layer, cameraId) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return; }
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {number} rotation
|
||||
* @param {string} layer
|
||||
* @param {number} cameraId
|
||||
*/
|
||||
gdjs.evtTools.camera.setCameraRotation = function (
|
||||
runtimeScene,
|
||||
rotation,
|
||||
layer,
|
||||
cameraId
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return runtimeScene.getLayer(layer).setCameraRotation(rotation, cameraId);
|
||||
}
|
||||
gdjs.evtTools.camera.getCameraRotation = function(runtimeScene, layer, cameraId) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return 0; }
|
||||
return runtimeScene.getLayer(layer).setCameraRotation(rotation, cameraId);
|
||||
};
|
||||
|
||||
return runtimeScene.getLayer(layer).getCameraRotation(cameraId);
|
||||
}
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {string} layer
|
||||
* @param {number} cameraId
|
||||
* @returns {number}
|
||||
*/
|
||||
gdjs.evtTools.camera.getCameraRotation = function (
|
||||
runtimeScene,
|
||||
layer,
|
||||
cameraId
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
gdjs.evtTools.camera.setCameraZoom = function(runtimeScene, newZoom, layer, cameraId) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return; }
|
||||
return runtimeScene.getLayer(layer).getCameraRotation(cameraId);
|
||||
};
|
||||
|
||||
return runtimeScene.getLayer(layer).setCameraZoom(newZoom, cameraId);
|
||||
}
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {number} newZoom
|
||||
* @param {string} layer
|
||||
* @param {number} cameraId
|
||||
*/
|
||||
gdjs.evtTools.camera.setCameraZoom = function (
|
||||
runtimeScene,
|
||||
newZoom,
|
||||
layer,
|
||||
cameraId
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
gdjs.evtTools.camera.centerCamera = function(runtimeScene, object, anticipateMove, layer, cameraId) {
|
||||
if ( !runtimeScene.hasLayer(layer) || object == null ) { return; }
|
||||
return runtimeScene.getLayer(layer).setCameraZoom(newZoom, cameraId);
|
||||
};
|
||||
|
||||
var layer = runtimeScene.getLayer(layer);
|
||||
var xOffset = 0; var yOffset = 0;
|
||||
if ( anticipateMove && !object.hasNoForces() ) {
|
||||
var objectAverageForce = object.getAverageForce();
|
||||
var elapsedTimeInSeconds = object.getElapsedTime(runtimeScene) / 1000;
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {?gdjs.RuntimeObject} object
|
||||
* @param {boolean} anticipateMove
|
||||
* @param {string} layerName
|
||||
* @param {number} cameraId
|
||||
*/
|
||||
gdjs.evtTools.camera.centerCamera = function (
|
||||
runtimeScene,
|
||||
object,
|
||||
anticipateMove,
|
||||
layerName,
|
||||
cameraId
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layerName) || object == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
xOffset = objectAverageForce.getX() * elapsedTimeInSeconds;
|
||||
yOffset = objectAverageForce.getY() * elapsedTimeInSeconds;
|
||||
}
|
||||
var layer = runtimeScene.getLayer(layerName);
|
||||
var xOffset = 0;
|
||||
var yOffset = 0;
|
||||
if (anticipateMove && !object.hasNoForces()) {
|
||||
var objectAverageForce = object.getAverageForce();
|
||||
var elapsedTimeInSeconds = object.getElapsedTime(runtimeScene) / 1000;
|
||||
|
||||
layer.setCameraX(object.getDrawableX()+object.getCenterX(), cameraId);
|
||||
layer.setCameraY(object.getDrawableY()+object.getCenterY(), cameraId);
|
||||
}
|
||||
xOffset = objectAverageForce.getX() * elapsedTimeInSeconds;
|
||||
yOffset = objectAverageForce.getY() * elapsedTimeInSeconds;
|
||||
}
|
||||
|
||||
gdjs.evtTools.camera.centerCameraWithinLimits = function(runtimeScene, object, left, top, right, bottom, anticipateMove, layer, cameraId) {
|
||||
if ( !runtimeScene.hasLayer(layer) || object == null ) { return; }
|
||||
layer.setCameraX(object.getDrawableX() + object.getCenterX(), cameraId);
|
||||
layer.setCameraY(object.getDrawableY() + object.getCenterY(), cameraId);
|
||||
};
|
||||
|
||||
var layer = runtimeScene.getLayer(layer);
|
||||
var xOffset = 0; var yOffset = 0;
|
||||
if ( anticipateMove && !object.hasNoForces() ) {
|
||||
var objectAverageForce = object.getAverageForce();
|
||||
var elapsedTimeInSeconds = object.getElapsedTime(runtimeScene) / 1000;
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {?gdjs.RuntimeObject} object
|
||||
* @param {number} left
|
||||
* @param {number} top
|
||||
* @param {number} right
|
||||
* @param {number} bottom
|
||||
* @param {boolean} anticipateMove
|
||||
* @param {string} layerName
|
||||
* @param {number} cameraId
|
||||
*/
|
||||
gdjs.evtTools.camera.centerCameraWithinLimits = function (
|
||||
runtimeScene,
|
||||
object,
|
||||
left,
|
||||
top,
|
||||
right,
|
||||
bottom,
|
||||
anticipateMove,
|
||||
layerName,
|
||||
cameraId
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layerName) || object == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
xOffset = objectAverageForce.getX() * elapsedTimeInSeconds;
|
||||
yOffset = objectAverageForce.getY() * elapsedTimeInSeconds;
|
||||
}
|
||||
var layer = runtimeScene.getLayer(layerName);
|
||||
var xOffset = 0;
|
||||
var yOffset = 0;
|
||||
if (anticipateMove && !object.hasNoForces()) {
|
||||
var objectAverageForce = object.getAverageForce();
|
||||
var elapsedTimeInSeconds = object.getElapsedTime(runtimeScene) / 1000;
|
||||
|
||||
var newX = object.getDrawableX()+object.getCenterX()+xOffset;
|
||||
if ( newX < left +layer.getCameraWidth(cameraId)/2 ) newX = left+layer.getCameraWidth(cameraId)/2;
|
||||
if ( newX > right-layer.getCameraWidth(cameraId)/2 ) newX = right-layer.getCameraWidth(cameraId)/2;
|
||||
xOffset = objectAverageForce.getX() * elapsedTimeInSeconds;
|
||||
yOffset = objectAverageForce.getY() * elapsedTimeInSeconds;
|
||||
}
|
||||
|
||||
var newY = object.getDrawableY()+object.getCenterY()+yOffset;
|
||||
if ( newY < top +layer.getCameraHeight(cameraId)/2 ) newY = top+layer.getCameraHeight(cameraId)/2;
|
||||
if ( newY > bottom-layer.getCameraHeight(cameraId)/2 ) newY = bottom-layer.getCameraHeight(cameraId)/2;
|
||||
var newX = object.getDrawableX() + object.getCenterX() + xOffset;
|
||||
if (newX < left + layer.getCameraWidth(cameraId) / 2)
|
||||
newX = left + layer.getCameraWidth(cameraId) / 2;
|
||||
if (newX > right - layer.getCameraWidth(cameraId) / 2)
|
||||
newX = right - layer.getCameraWidth(cameraId) / 2;
|
||||
|
||||
layer.setCameraX(newX, cameraId);
|
||||
layer.setCameraY(newY, cameraId);
|
||||
}
|
||||
var newY = object.getDrawableY() + object.getCenterY() + yOffset;
|
||||
if (newY < top + layer.getCameraHeight(cameraId) / 2)
|
||||
newY = top + layer.getCameraHeight(cameraId) / 2;
|
||||
if (newY > bottom - layer.getCameraHeight(cameraId) / 2)
|
||||
newY = bottom - layer.getCameraHeight(cameraId) / 2;
|
||||
|
||||
layer.setCameraX(newX, cameraId);
|
||||
layer.setCameraY(newY, cameraId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update a layer effect parameter (with a number).
|
||||
@@ -130,11 +285,21 @@ gdjs.evtTools.camera.centerCameraWithinLimits = function(runtimeScene, object, l
|
||||
* @param {string} parameter The parameter to update
|
||||
* @param {number} value The new value
|
||||
*/
|
||||
gdjs.evtTools.camera.setLayerEffectDoubleParameter = function(runtimeScene, layer, effect, parameter, value) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return; }
|
||||
gdjs.evtTools.camera.setLayerEffectDoubleParameter = function (
|
||||
runtimeScene,
|
||||
layer,
|
||||
effect,
|
||||
parameter,
|
||||
value
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return runtimeScene.getLayer(layer).setEffectDoubleParameter(effect, parameter, value);
|
||||
}
|
||||
return runtimeScene
|
||||
.getLayer(layer)
|
||||
.setEffectDoubleParameter(effect, parameter, value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update a layer effect parameter (with a string).
|
||||
@@ -144,11 +309,21 @@ gdjs.evtTools.camera.setLayerEffectDoubleParameter = function(runtimeScene, laye
|
||||
* @param {string} parameter The parameter to update
|
||||
* @param {string} value The new value
|
||||
*/
|
||||
gdjs.evtTools.camera.setLayerEffectStringParameter = function(runtimeScene, layer, effect, parameter, value) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return; }
|
||||
gdjs.evtTools.camera.setLayerEffectStringParameter = function (
|
||||
runtimeScene,
|
||||
layer,
|
||||
effect,
|
||||
parameter,
|
||||
value
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return runtimeScene.getLayer(layer).setEffectStringParameter(effect, parameter, value);
|
||||
}
|
||||
return runtimeScene
|
||||
.getLayer(layer)
|
||||
.setEffectStringParameter(effect, parameter, value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable or disable a layer effect parameter (boolean).
|
||||
@@ -158,11 +333,21 @@ gdjs.evtTools.camera.setLayerEffectStringParameter = function(runtimeScene, laye
|
||||
* @param {string} parameter The parameter to update
|
||||
* @param {boolean} value The new value
|
||||
*/
|
||||
gdjs.evtTools.camera.setLayerEffectBooleanParameter = function(runtimeScene, layer, effect, parameter, value) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return; }
|
||||
gdjs.evtTools.camera.setLayerEffectBooleanParameter = function (
|
||||
runtimeScene,
|
||||
layer,
|
||||
effect,
|
||||
parameter,
|
||||
value
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return runtimeScene.getLayer(layer).setEffectBooleanParameter(effect, parameter, value);
|
||||
}
|
||||
return runtimeScene
|
||||
.getLayer(layer)
|
||||
.setEffectBooleanParameter(effect, parameter, value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable, or disable, an effect of a layer.
|
||||
@@ -171,11 +356,18 @@ gdjs.evtTools.camera.setLayerEffectBooleanParameter = function(runtimeScene, lay
|
||||
* @param {string} effect The name of the effect
|
||||
* @param {boolean} enabled true to enable, false to disable.
|
||||
*/
|
||||
gdjs.evtTools.camera.enableLayerEffect = function(runtimeScene, layer, effect, enabled) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return; }
|
||||
gdjs.evtTools.camera.enableLayerEffect = function (
|
||||
runtimeScene,
|
||||
layer,
|
||||
effect,
|
||||
enabled
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
runtimeScene.getLayer(layer).enableEffect(effect, enabled);
|
||||
}
|
||||
runtimeScene.getLayer(layer).enableEffect(effect, enabled);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if an effect is enabled.
|
||||
@@ -184,18 +376,70 @@ gdjs.evtTools.camera.enableLayerEffect = function(runtimeScene, layer, effect, e
|
||||
* @param {string} effect The name of the effect
|
||||
* @return {boolean} true if the effect is enabled, false otherwise.
|
||||
*/
|
||||
gdjs.evtTools.camera.layerEffectEnabled = function(runtimeScene, layer, effect) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return true; }
|
||||
gdjs.evtTools.camera.layerEffectEnabled = function (
|
||||
runtimeScene,
|
||||
layer,
|
||||
effect
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return runtimeScene.getLayer(layer).isEffectEnabled(effect);
|
||||
}
|
||||
return runtimeScene.getLayer(layer).isEffectEnabled(effect);
|
||||
};
|
||||
|
||||
gdjs.evtTools.camera.setLayerTimeScale = function(runtimeScene, layer, timeScale) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return; }
|
||||
return runtimeScene.getLayer(layer).setTimeScale(timeScale);
|
||||
}
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {string} layer
|
||||
* @param {number} timeScale
|
||||
*/
|
||||
gdjs.evtTools.camera.setLayerTimeScale = function (
|
||||
runtimeScene,
|
||||
layer,
|
||||
timeScale
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).setTimeScale(timeScale);
|
||||
};
|
||||
|
||||
gdjs.evtTools.camera.getLayerTimeScale = function(runtimeScene, layer) {
|
||||
if ( !runtimeScene.hasLayer(layer) ) { return 1; }
|
||||
return runtimeScene.getLayer(layer).getTimeScale();
|
||||
}
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {string} layer
|
||||
* @returns {number}
|
||||
*/
|
||||
gdjs.evtTools.camera.getLayerTimeScale = function (runtimeScene, layer) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return 1;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).getTimeScale();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {string} layer
|
||||
* @param {number} defaultZOrder
|
||||
*/
|
||||
gdjs.evtTools.camera.setLayerDefaultZOrder = function (
|
||||
runtimeScene,
|
||||
layer,
|
||||
defaultZOrder
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).setDefaultZOrder(defaultZOrder);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {string} layer
|
||||
* @returns {number}
|
||||
*/
|
||||
gdjs.evtTools.camera.getLayerDefaultZOrder = function (runtimeScene, layer) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).getDefaultZOrder();
|
||||
};
|
||||
|
@@ -17,7 +17,7 @@ gdjs.evtTools.common = gdjs.evtTools.common || {};
|
||||
* @returns {number} The content of the variable, as a number.
|
||||
* @private
|
||||
*/
|
||||
gdjs.evtTools.common.getVariableNumber = function(variable) {
|
||||
gdjs.evtTools.common.getVariableNumber = function (variable) {
|
||||
return variable.getAsNumber();
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ gdjs.evtTools.common.getVariableNumber = function(variable) {
|
||||
* @returns {string} The content of the variable, as a string.
|
||||
* @private
|
||||
*/
|
||||
gdjs.evtTools.common.getVariableString = function(variable) {
|
||||
gdjs.evtTools.common.getVariableString = function (variable) {
|
||||
return variable.getAsString();
|
||||
};
|
||||
|
||||
@@ -38,7 +38,10 @@ gdjs.evtTools.common.getVariableString = function(variable) {
|
||||
* @returns {boolean} true if the scene variable exits, false otherwise.
|
||||
* @private
|
||||
*/
|
||||
gdjs.evtTools.common.sceneVariableExists = function(runtimeScene, variableName) {
|
||||
gdjs.evtTools.common.sceneVariableExists = function (
|
||||
runtimeScene,
|
||||
variableName
|
||||
) {
|
||||
return runtimeScene.getVariables().has(variableName);
|
||||
};
|
||||
|
||||
@@ -49,7 +52,10 @@ gdjs.evtTools.common.sceneVariableExists = function(runtimeScene, variableName)
|
||||
* @returns {boolean} true if the global variable exits, false otherwise.
|
||||
* @private
|
||||
*/
|
||||
gdjs.evtTools.common.globalVariableExists = function(runtimeScene, variableName) {
|
||||
gdjs.evtTools.common.globalVariableExists = function (
|
||||
runtimeScene,
|
||||
variableName
|
||||
) {
|
||||
return runtimeScene.getGame().getVariables().has(variableName);
|
||||
};
|
||||
|
||||
@@ -60,7 +66,7 @@ gdjs.evtTools.common.globalVariableExists = function(runtimeScene, variableName)
|
||||
* @returns {boolean} true if child exist in the variable, false otherwise.
|
||||
* @private
|
||||
*/
|
||||
gdjs.evtTools.common.variableChildExists = function(variable, childName) {
|
||||
gdjs.evtTools.common.variableChildExists = function (variable, childName) {
|
||||
return variable.hasChild(childName);
|
||||
};
|
||||
|
||||
@@ -71,7 +77,7 @@ gdjs.evtTools.common.variableChildExists = function(variable, childName) {
|
||||
* @returns {gdjs.Variable} The new variable, with the child removed.
|
||||
* @private
|
||||
*/
|
||||
gdjs.evtTools.common.variableRemoveChild = function(variable, childName) {
|
||||
gdjs.evtTools.common.variableRemoveChild = function (variable, childName) {
|
||||
return variable.removeChild(childName);
|
||||
};
|
||||
|
||||
@@ -80,7 +86,7 @@ gdjs.evtTools.common.variableRemoveChild = function(variable, childName) {
|
||||
* @param {gdjs.Variable} variable Variable.
|
||||
* @private
|
||||
*/
|
||||
gdjs.evtTools.common.variableClearChildren = function(variable) {
|
||||
gdjs.evtTools.common.variableClearChildren = function (variable) {
|
||||
variable.clearChildren();
|
||||
};
|
||||
|
||||
@@ -90,7 +96,7 @@ gdjs.evtTools.common.variableClearChildren = function(variable) {
|
||||
* @returns {number} The number of children in the variable.
|
||||
* @private
|
||||
*/
|
||||
gdjs.evtTools.common.getVariableChildCount = function(variable) {
|
||||
gdjs.evtTools.common.getVariableChildCount = function (variable) {
|
||||
if (variable.isStructure() == false) return 0;
|
||||
return Object.keys(variable.getAllChildren()).length;
|
||||
};
|
||||
@@ -101,7 +107,7 @@ gdjs.evtTools.common.getVariableChildCount = function(variable) {
|
||||
* @returns {number} The parsed number, or NaN if invalid.
|
||||
* @private
|
||||
*/
|
||||
gdjs.evtTools.common.toNumber = function(str) {
|
||||
gdjs.evtTools.common.toNumber = function (str) {
|
||||
return parseFloat(str);
|
||||
};
|
||||
|
||||
@@ -111,7 +117,7 @@ gdjs.evtTools.common.toNumber = function(str) {
|
||||
* @returns {string} The value as a string.
|
||||
* @private
|
||||
*/
|
||||
gdjs.evtTools.common.toString = function(num) {
|
||||
gdjs.evtTools.common.toString = function (num) {
|
||||
//Using String literal is fastest than using toString according to
|
||||
//http://jsperf.com/number-to-string/2 and http://jsben.ch/#/ghQYR
|
||||
return '' + num;
|
||||
@@ -123,7 +129,7 @@ gdjs.evtTools.common.toString = function(num) {
|
||||
* @returns {boolean} The negated value.
|
||||
* @private
|
||||
*/
|
||||
gdjs.evtTools.common.logicalNegation = function(bool) {
|
||||
gdjs.evtTools.common.logicalNegation = function (bool) {
|
||||
return !bool;
|
||||
};
|
||||
|
||||
@@ -134,7 +140,7 @@ gdjs.evtTools.common.logicalNegation = function(bool) {
|
||||
* @param {number} max The maximum value.
|
||||
* @returns {number} The new value.
|
||||
*/
|
||||
gdjs.evtTools.common.clamp = function(x, min, max) {
|
||||
gdjs.evtTools.common.clamp = function (x, min, max) {
|
||||
return Math.min(Math.max(x, min), max);
|
||||
};
|
||||
|
||||
@@ -143,7 +149,7 @@ gdjs.evtTools.common.clamp = function(x, min, max) {
|
||||
* @param {number} arg Value.
|
||||
* @returns {number} The hyperbolic arc-cosine for the value.
|
||||
*/
|
||||
gdjs.evtTools.common.acosh = function(arg) {
|
||||
gdjs.evtTools.common.acosh = function (arg) {
|
||||
// http://kevin.vanzonneveld.net
|
||||
// + original by: Onno Marsman
|
||||
return Math.log(arg + Math.sqrt(arg * arg - 1));
|
||||
@@ -154,7 +160,7 @@ gdjs.evtTools.common.acosh = function(arg) {
|
||||
* @param {number} arg Value.
|
||||
* @returns {number} The hyperbolic arcsine for the value.
|
||||
*/
|
||||
gdjs.evtTools.common.asinh = function(arg) {
|
||||
gdjs.evtTools.common.asinh = function (arg) {
|
||||
// http://kevin.vanzonneveld.net
|
||||
// + original by: Onno Marsman
|
||||
return Math.log(arg + Math.sqrt(arg * arg + 1));
|
||||
@@ -165,7 +171,7 @@ gdjs.evtTools.common.asinh = function(arg) {
|
||||
* @param {number} arg Value.
|
||||
* @returns {number} The hyperbolic arctangent for the value.
|
||||
*/
|
||||
gdjs.evtTools.common.atanh = function(arg) {
|
||||
gdjs.evtTools.common.atanh = function (arg) {
|
||||
// http://kevin.vanzonneveld.net
|
||||
// + original by: Onno Marsman
|
||||
return 0.5 * Math.log((1 + arg) / (1 - arg));
|
||||
@@ -176,7 +182,7 @@ gdjs.evtTools.common.atanh = function(arg) {
|
||||
* @param {number} arg Value.
|
||||
* @returns {number} The hyperbolic cosine for the value.
|
||||
*/
|
||||
gdjs.evtTools.common.cosh = function(arg) {
|
||||
gdjs.evtTools.common.cosh = function (arg) {
|
||||
return (Math.exp(arg) + Math.exp(-arg)) / 2;
|
||||
};
|
||||
|
||||
@@ -185,7 +191,7 @@ gdjs.evtTools.common.cosh = function(arg) {
|
||||
* @param {number} arg Value.
|
||||
* @returns {number} The hyperbolic sine for the value.
|
||||
*/
|
||||
gdjs.evtTools.common.sinh = function(arg) {
|
||||
gdjs.evtTools.common.sinh = function (arg) {
|
||||
return (Math.exp(arg) - Math.exp(-arg)) / 2;
|
||||
};
|
||||
|
||||
@@ -194,7 +200,7 @@ gdjs.evtTools.common.sinh = function(arg) {
|
||||
* @param {number} arg Value.
|
||||
* @returns {number} The hyperbolic tangent for the value.
|
||||
*/
|
||||
gdjs.evtTools.common.tanh = function(arg) {
|
||||
gdjs.evtTools.common.tanh = function (arg) {
|
||||
return (Math.exp(arg) - Math.exp(-arg)) / (Math.exp(arg) + Math.exp(-arg));
|
||||
};
|
||||
|
||||
@@ -203,7 +209,7 @@ gdjs.evtTools.common.tanh = function(arg) {
|
||||
* @param {number} arg Value.
|
||||
* @returns {number} The cotangent for the value.
|
||||
*/
|
||||
gdjs.evtTools.common.cot = function(arg) {
|
||||
gdjs.evtTools.common.cot = function (arg) {
|
||||
return 1 / Math.tan(arg);
|
||||
};
|
||||
|
||||
@@ -212,7 +218,7 @@ gdjs.evtTools.common.cot = function(arg) {
|
||||
* @param {number} arg Value.
|
||||
* @returns {number} The cosecant for the value.
|
||||
*/
|
||||
gdjs.evtTools.common.csc = function(arg) {
|
||||
gdjs.evtTools.common.csc = function (arg) {
|
||||
return 1 / Math.sin(arg);
|
||||
};
|
||||
|
||||
@@ -221,7 +227,7 @@ gdjs.evtTools.common.csc = function(arg) {
|
||||
* @param {number} arg Value.
|
||||
* @returns {number} The secant for the value.
|
||||
*/
|
||||
gdjs.evtTools.common.sec = function(arg) {
|
||||
gdjs.evtTools.common.sec = function (arg) {
|
||||
return 1 / Math.cos(arg);
|
||||
};
|
||||
|
||||
@@ -230,7 +236,7 @@ gdjs.evtTools.common.sec = function(arg) {
|
||||
* @param {number} arg Value.
|
||||
* @returns {number} The base-10 logarithm for the value.
|
||||
*/
|
||||
gdjs.evtTools.common.log10 = function(arg) {
|
||||
gdjs.evtTools.common.log10 = function (arg) {
|
||||
return Math.log(arg) / Math.LN10;
|
||||
};
|
||||
|
||||
@@ -239,7 +245,7 @@ gdjs.evtTools.common.log10 = function(arg) {
|
||||
* @param {number} arg Value.
|
||||
* @returns {number} The base-2 logarithm for the value.
|
||||
*/
|
||||
gdjs.evtTools.common.log2 = function(arg) {
|
||||
gdjs.evtTools.common.log2 = function (arg) {
|
||||
return Math.log(arg) / Math.LN2;
|
||||
};
|
||||
|
||||
@@ -248,7 +254,7 @@ gdjs.evtTools.common.log2 = function(arg) {
|
||||
* @param {number} arg Value.
|
||||
* @returns {number} Return the sign for the value (1, -1 or 0).
|
||||
*/
|
||||
gdjs.evtTools.common.sign = function(arg) {
|
||||
gdjs.evtTools.common.sign = function (arg) {
|
||||
if (arg === 0) return 0;
|
||||
|
||||
return arg > 0 ? +1 : -1;
|
||||
@@ -259,7 +265,7 @@ gdjs.evtTools.common.sign = function(arg) {
|
||||
* @param {number} x Value.
|
||||
* @returns {number} Return the cube root for the value.
|
||||
*/
|
||||
gdjs.evtTools.common.cbrt = function(x) {
|
||||
gdjs.evtTools.common.cbrt = function (x) {
|
||||
return Math.pow(x, 1 / 3);
|
||||
};
|
||||
|
||||
@@ -269,7 +275,7 @@ gdjs.evtTools.common.cbrt = function(x) {
|
||||
* @param {number} n Exponent value.
|
||||
* @returns {number} Return the n-th root for the value.
|
||||
*/
|
||||
gdjs.evtTools.common.nthroot = function(x, n) {
|
||||
gdjs.evtTools.common.nthroot = function (x, n) {
|
||||
return Math.pow(x, 1 / n);
|
||||
};
|
||||
|
||||
@@ -279,7 +285,7 @@ gdjs.evtTools.common.nthroot = function(x, n) {
|
||||
* @param {number} y Divisor value.
|
||||
* @returns {number} Return the remainder for the values.
|
||||
*/
|
||||
gdjs.evtTools.common.mod = function(x, y) {
|
||||
gdjs.evtTools.common.mod = function (x, y) {
|
||||
return x - y * Math.floor(x / y);
|
||||
};
|
||||
|
||||
@@ -289,8 +295,37 @@ gdjs.evtTools.common.mod = function(x, y) {
|
||||
* @param {number} angle2 Second angle, in degrees.
|
||||
* @returns {number} Return the difference of the angles, in degrees.
|
||||
*/
|
||||
gdjs.evtTools.common.angleDifference = function(angle1, angle2) {
|
||||
return gdjs.evtTools.common.mod(gdjs.evtTools.common.mod(angle1 - angle2, 360.0) + 180.0, 360.0) - 180.0;
|
||||
gdjs.evtTools.common.angleDifference = function (angle1, angle2) {
|
||||
return (
|
||||
gdjs.evtTools.common.mod(
|
||||
gdjs.evtTools.common.mod(angle1 - angle2, 360.0) + 180.0,
|
||||
360.0
|
||||
) - 180.0
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the angle, in degrees, between two positions.
|
||||
* @param {number} x1 First point X position.
|
||||
* @param {number} y1 First point Y position.
|
||||
* @param {number} x2 Second point X position.
|
||||
* @param {number} y2 Second point Y position.
|
||||
* @returns {number} The angle between the positions, in degrees.
|
||||
*/
|
||||
gdjs.evtTools.common.angleBetweenPositions = function (x1, y1, x2, y2) {
|
||||
return (Math.atan2(y2 - y1, x2 - x1) * 180) / Math.PI;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the distance, in pixels, between two positions.
|
||||
* @param {number} x1 First point X position.
|
||||
* @param {number} y1 First point Y position.
|
||||
* @param {number} x2 Second point X position.
|
||||
* @param {number} y2 Second point Y position.
|
||||
* @returns {number} The distance between the positions, in pixels.
|
||||
*/
|
||||
gdjs.evtTools.common.distanceBetweenPositions = function (x1, y1, x2, y2) {
|
||||
return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -300,7 +335,7 @@ gdjs.evtTools.common.angleDifference = function(angle1, angle2) {
|
||||
* @param {number} x The interpolation value between 0 and 1.
|
||||
* @returns {number} The interpolated value, now between a and b.
|
||||
*/
|
||||
gdjs.evtTools.common.lerp = function(a, b, x) {
|
||||
gdjs.evtTools.common.lerp = function (a, b, x) {
|
||||
return a + (b - a) * x;
|
||||
};
|
||||
|
||||
@@ -309,6 +344,6 @@ gdjs.evtTools.common.lerp = function(a, b, x) {
|
||||
* @param {number} x Value.
|
||||
* @returns {number} Return the value with all decimal places dropped.
|
||||
*/
|
||||
gdjs.evtTools.common.trunc = function(x) {
|
||||
gdjs.evtTools.common.trunc = function (x) {
|
||||
return x | 0;
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user