mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
106 Commits
v5.0.0-bet
...
v5.0.0-bet
Author | SHA1 | Date | |
---|---|---|---|
![]() |
13b62a06eb | ||
![]() |
d27119d8ea | ||
![]() |
dd3ff554d5 | ||
![]() |
287a17b634 | ||
![]() |
7dc477e29e | ||
![]() |
8174bca3b1 | ||
![]() |
7f6388c6f5 | ||
![]() |
da3a099ff2 | ||
![]() |
7b2c7b4a00 | ||
![]() |
f750a356c3 | ||
![]() |
611a72aee1 | ||
![]() |
1b965b65a4 | ||
![]() |
c077628eb4 | ||
![]() |
f1a6da0cb2 | ||
![]() |
df4a780311 | ||
![]() |
8c955cf77a | ||
![]() |
17efae037c | ||
![]() |
f1120238ec | ||
![]() |
5d6a2bb3a0 | ||
![]() |
f3a49ad2cf | ||
![]() |
aac3379f59 | ||
![]() |
49949189cf | ||
![]() |
977daa50fa | ||
![]() |
fd8a7df868 | ||
![]() |
303110ade5 | ||
![]() |
cb15111d03 | ||
![]() |
9db4d603a0 | ||
![]() |
6c7db9a948 | ||
![]() |
6b9a8f14e3 | ||
![]() |
2f3a18046a | ||
![]() |
812ff43905 | ||
![]() |
1a113004be | ||
![]() |
0dd10a7955 | ||
![]() |
00b25461ed | ||
![]() |
9e28068e4f | ||
![]() |
6b231f3eb6 | ||
![]() |
2dd2c85f12 | ||
![]() |
c61faa7e05 | ||
![]() |
1840f6f45a | ||
![]() |
b11eccfa22 | ||
![]() |
9236608502 | ||
![]() |
12a6bc23c3 | ||
![]() |
23c2b84707 | ||
![]() |
adb4f2a6cf | ||
![]() |
aa3ed78eda | ||
![]() |
efb8668077 | ||
![]() |
8d763d4600 | ||
![]() |
0cc1e57450 | ||
![]() |
24c13e1022 | ||
![]() |
965f7aab32 | ||
![]() |
23c1f2423d | ||
![]() |
1d5eb8e529 | ||
![]() |
8968ef34e2 | ||
![]() |
736ba023ff | ||
![]() |
ade075f076 | ||
![]() |
049c36b081 | ||
![]() |
3977e2b6f2 | ||
![]() |
f08f38bc3b | ||
![]() |
127a881416 | ||
![]() |
606143ff36 | ||
![]() |
05a68cb17f | ||
![]() |
280377cc98 | ||
![]() |
3c88c150d5 | ||
![]() |
13471ad40a | ||
![]() |
0d7d574f1b | ||
![]() |
19a10d7dab | ||
![]() |
84e096f85d | ||
![]() |
40f5eb3e23 | ||
![]() |
4948e16dd5 | ||
![]() |
2b38325d96 | ||
![]() |
9a10caeeac | ||
![]() |
a4be56a24b | ||
![]() |
fc8b724e3c | ||
![]() |
7e61419a36 | ||
![]() |
473661b8a2 | ||
![]() |
350fea08bf | ||
![]() |
4f9154549b | ||
![]() |
d9172ded36 | ||
![]() |
aef8271a4e | ||
![]() |
83db8ce272 | ||
![]() |
e26c1470c1 | ||
![]() |
4b382cb191 | ||
![]() |
6c631410f2 | ||
![]() |
516b1d978c | ||
![]() |
822146e5f1 | ||
![]() |
7b3987bae4 | ||
![]() |
506c029690 | ||
![]() |
b28e4e1230 | ||
![]() |
c1edcbfa19 | ||
![]() |
3125956dfc | ||
![]() |
633c7bbd9d | ||
![]() |
df92ea1ac9 | ||
![]() |
3eb571a03a | ||
![]() |
98303f7f50 | ||
![]() |
34dfbbc294 | ||
![]() |
afbb316bd2 | ||
![]() |
b75945869c | ||
![]() |
efb3f55885 | ||
![]() |
82d2a4b5e4 | ||
![]() |
7748f3c48e | ||
![]() |
80ddc9c1b7 | ||
![]() |
5d50c31e55 | ||
![]() |
61a969fdb1 | ||
![]() |
a14b8e8bcd | ||
![]() |
faa37a4fd2 | ||
![]() |
176efafe43 |
17
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
17
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: GDevelop Discord
|
||||
url: https://discord.gg/rjdYHvj
|
||||
about: Discuss on the forum or on the Discord to get help creating a game or identifying a bug.
|
||||
- name: GDevelop Forums
|
||||
url: https://forum.gdevelop-app.com
|
||||
about: You can also discuss game creation, new feature requests and bugs on the forum.
|
||||
- name: GDevelop Roadmap
|
||||
url: https://trello.com/b/qf0lM7k8/gdevelop-roadmap
|
||||
about: Look at the roadmap and vote on features that you want to see in GDevelop.
|
||||
- name: Submit a new game example that you created
|
||||
url: https://github.com/GDevelopApp/GDevelop-examples/issues/new/choose
|
||||
about: You can submit a game that you made to be added to examples in the "GDevelop-examples" repository
|
||||
- name: Submit a new game extension that you created
|
||||
url: https://github.com/4ian/GDevelop-extensions/issues/new/choose
|
||||
about: You can submit an extension that you made in the "GDevelop-extensions" repository
|
7
.github/workflows/issues.yml
vendored
7
.github/workflows/issues.yml
vendored
@@ -4,13 +4,6 @@ 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:
|
||||
|
@@ -1,7 +1,6 @@
|
||||
language: cpp
|
||||
sudo: false
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
# Cache .npm folder for faster npm install
|
||||
|
129
.vscode/GDevelopExtensions.code-snippets
vendored
Normal file
129
.vscode/GDevelopExtensions.code-snippets
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
{
|
||||
"Define extension": {
|
||||
"scope": "javascript",
|
||||
"description": "Adds the boilerplate code of a GDevelop extension definition.",
|
||||
"prefix": "gdext",
|
||||
"body": [
|
||||
"// @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 = {",
|
||||
"\tcreateExtension: function (",
|
||||
"\t\t/*: (string) => string */,",
|
||||
"\t\tgd /*: libGDevelop */",
|
||||
"\t) {",
|
||||
"\t\tconst extension = new gd.PlatformExtension();",
|
||||
"\t\textension",
|
||||
"\t\t\t.setExtensionInformation(",
|
||||
"\t\t\t\t'${1:${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/$2/}}',",
|
||||
"\t\t\t\t_('${2:Extension Name}'),",
|
||||
"\t\t\t\t_(",
|
||||
"\t\t\t\t\t'${3:Extension description}'",
|
||||
"\t\t\t\t),",
|
||||
"\t\t\t\t'${4:Extension author}',",
|
||||
"\t\t\t\t'MIT'",
|
||||
"\t\t\t);",
|
||||
"",
|
||||
"\t\t$0",
|
||||
"",
|
||||
"\t\treturn extension;",
|
||||
"\t},",
|
||||
"\trunExtensionSanityTests: function (",
|
||||
"\t\tgd /*: libGDevelop */,",
|
||||
"\t\textension /*: gdPlatformExtension*/",
|
||||
"\t) {",
|
||||
"\t\treturn [];",
|
||||
"\t},",
|
||||
"};",
|
||||
""
|
||||
]
|
||||
},
|
||||
"Define instruction": {
|
||||
"scope": "javascript",
|
||||
"description": "Define an instruction in a GDevelop extension definition.",
|
||||
"prefix": "gdinstr",
|
||||
"body": [
|
||||
"extension",
|
||||
"\t.add${1|Condition,Action|}(",
|
||||
"\t\t'${2:InstructionInternalName}',",
|
||||
"\t\t_('${3:Instruction full name}'),",
|
||||
"\t\t_(",
|
||||
"\t\t\t'${4:Instruction description}'",
|
||||
"\t\t),",
|
||||
"\t\t_('${5:Event sheet sentence}'),",
|
||||
"\t\t_('${6:Events group}'),",
|
||||
"\t\t'JsPlatform/Extensions/${8:icon}.png',",
|
||||
"\t\t'JsPlatform/Extensions/${8:icon}.png'",
|
||||
"\t)",
|
||||
"\t.getCodeExtraInformation()",
|
||||
"\t.setIncludeFile('Extensions/${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/$2/}/${9:${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/${2:/downcase}/}tools}.js')",
|
||||
"\t.setFunctionName('gdjs.evtTools.${7:${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/${2:/downcase}/}.}');",
|
||||
"",
|
||||
"$0"
|
||||
]
|
||||
},
|
||||
"Define expression": {
|
||||
"scope": "javascript",
|
||||
"description": "Define an expression in a GDevelop extension definition.",
|
||||
"prefix": "gdexp",
|
||||
"body": [
|
||||
"extension",
|
||||
"\t.add${1|Expression,StrExpression|}(",
|
||||
"\t\t'${2:ExpressionsInternalName}',",
|
||||
"\t\t_('${3:Expression full name}'),",
|
||||
"\t\t_(",
|
||||
"\t\t\t'${4:Expression description}'",
|
||||
"\t\t),",
|
||||
"\t\t_('${5:Events group}'),",
|
||||
"\t\t'JsPlatform/Extensions/${7:icon}.png'",
|
||||
"\t)",
|
||||
"\t.getCodeExtraInformation()",
|
||||
"\t.setIncludeFile('Extensions/${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/$2/}/${8:${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/${2:/downcase}/}tools}.js')",
|
||||
"\t.setFunctionName('gdjs.evtTools.${6:${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/${2:/downcase}/}.}');",
|
||||
"",
|
||||
"$0"
|
||||
]
|
||||
},
|
||||
"Add parameter": {
|
||||
"scope": "javascript",
|
||||
"description": "Define a parameter in a GDevelop extension definition.",
|
||||
"prefix": "gdparam",
|
||||
"body": [
|
||||
".addParameter('${1|string,expression,object,behavior,yesorno,stringWithSelector,scenevar,globalvar,objectvar,objectList,objectListWithoutPicking,color,key,sceneName,file,layer,relationalOperator,operator,trueorfalse,musicfile,soundfile,police,mouse,passwordjoyaxis,camera,objectPtr,forceMultiplier|}', '${2:Parameter description}', '${3:Optional parameter data}', /*parameterIsOptional=*/${4|false,true|})"
|
||||
]
|
||||
},
|
||||
"Add code only parameter": {
|
||||
"scope": "javascript",
|
||||
"description": "Define a parameter in a GDevelop extension definition.",
|
||||
"prefix": "gdcoparam",
|
||||
"body": [
|
||||
".addCodeOnlyParameter('${1|inlineCode,currentScene,objectsContext,eventsFunctionContext,conditionInverted|}', '${2:Inline code (for inlineCode parameter)}')"
|
||||
]
|
||||
},
|
||||
"Add include": {
|
||||
"scope": "javascript",
|
||||
"description": "Define an include file in a GDevelop extension definition.",
|
||||
"prefix": "gdincl",
|
||||
"body": [
|
||||
".addIncludeFile('Extensions/${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/$2/}/${1:include}.js')"
|
||||
]
|
||||
}
|
||||
}
|
201
.vscode/c_cpp_properties.json
vendored
201
.vscode/c_cpp_properties.json
vendored
@@ -1,107 +1,98 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Mac",
|
||||
"includePath": [
|
||||
"${workspaceRoot}",
|
||||
"${workspaceRoot}/GDCpp",
|
||||
"${workspaceRoot}/GDJS",
|
||||
"${workspaceRoot}/Extensions",
|
||||
"${workspaceRoot}/Core",
|
||||
"${workspaceRoot}/ExtLibs/SFML/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
|
||||
"/usr/local/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
|
||||
"/usr/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"GD_IDE_ONLY",
|
||||
"GD_CORE_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_EXTENSION_API=/* Macro used to export classes on Windows, please ignore */"
|
||||
],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
|
||||
"/usr/local/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
|
||||
"/usr/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
},
|
||||
"macFrameworkPath": [
|
||||
"/System/Library/Frameworks",
|
||||
"/Library/Frameworks"
|
||||
],
|
||||
"compilerPath": "/usr/bin/clang",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17"
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceRoot}",
|
||||
"${workspaceRoot}/GDCpp",
|
||||
"${workspaceRoot}/GDJS",
|
||||
"${workspaceRoot}/Extensions",
|
||||
"${workspaceRoot}/Core",
|
||||
"${workspaceRoot}/ExtLibs/SFML/include",
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"GD_IDE_ONLY",
|
||||
"GD_CORE_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_EXTENSION_API=/* Macro used to export classes on Windows, please ignore */"
|
||||
],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": [
|
||||
"${workspaceRoot}",
|
||||
"${workspaceRoot}/IDE",
|
||||
"${workspaceRoot}/GDCpp",
|
||||
"${workspaceRoot}/GDJS",
|
||||
"${workspaceRoot}/Extensions",
|
||||
"${workspaceRoot}/Core",
|
||||
"${workspaceRoot}/ExtLibs/SFML/include",
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE",
|
||||
"GD_IDE_ONLY",
|
||||
"GD_CORE_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_EXTENSION_API=/* Macro used to export classes on Windows, please ignore */"
|
||||
],
|
||||
"intelliSenseMode": "msvc-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include/*",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Mac",
|
||||
"includePath": [
|
||||
"${workspaceRoot}",
|
||||
"${workspaceRoot}/GDCpp",
|
||||
"${workspaceRoot}/GDJS",
|
||||
"${workspaceRoot}/Extensions",
|
||||
"${workspaceRoot}/Core",
|
||||
"${workspaceRoot}/ExtLibs/SFML/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
|
||||
"/usr/local/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
|
||||
"/usr/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"EMSCRIPTEN",
|
||||
"GD_IDE_ONLY",
|
||||
"GD_CORE_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_EXTENSION_API=/* Macro used to export classes on Windows, please ignore */"
|
||||
],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
|
||||
"/usr/local/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
|
||||
"/usr/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
},
|
||||
"macFrameworkPath": ["/System/Library/Frameworks", "/Library/Frameworks"],
|
||||
"compilerPath": "/usr/bin/clang",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17"
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceRoot}",
|
||||
"${workspaceRoot}/GDCpp",
|
||||
"${workspaceRoot}/GDJS",
|
||||
"${workspaceRoot}/Extensions",
|
||||
"${workspaceRoot}/Core",
|
||||
"${workspaceRoot}/ExtLibs/SFML/include",
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"EMSCRIPTEN",
|
||||
"GD_IDE_ONLY",
|
||||
"GD_CORE_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_EXTENSION_API=/* Macro used to export classes on Windows, please ignore */"
|
||||
],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"browse": {
|
||||
"path": ["/usr/include", "/usr/local/include", "${workspaceRoot}"],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": [
|
||||
"${workspaceRoot}",
|
||||
"${workspaceRoot}/GDCpp",
|
||||
"${workspaceRoot}/GDJS",
|
||||
"${workspaceRoot}/Extensions",
|
||||
"${workspaceRoot}/Core",
|
||||
"${workspaceRoot}/ExtLibs/SFML/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE",
|
||||
"EMSCRIPTEN",
|
||||
"GD_IDE_ONLY",
|
||||
"GD_CORE_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_EXTENSION_API=/* Macro used to export classes on Windows, please ignore */"
|
||||
],
|
||||
"intelliSenseMode": "msvc-x64",
|
||||
"browse": {
|
||||
"path": ["${workspaceRoot}"],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
|
14
.vscode/extensions.json
vendored
14
.vscode/extensions.json
vendored
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"esbenp.prettier-vscode",
|
||||
"xaver.clang-format",
|
||||
"ms-vscode.cpptools",
|
||||
"flowtype.flow-for-vscode"
|
||||
]
|
||||
}
|
||||
"recommendations": [
|
||||
"esbenp.prettier-vscode",
|
||||
"xaver.clang-format",
|
||||
"ms-vscode.cpptools",
|
||||
"flowtype.flow-for-vscode"
|
||||
]
|
||||
}
|
||||
|
29
.vscode/launch.json
vendored
29
.vscode/launch.json
vendored
@@ -1,15 +1,16 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "pwa-chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"url": "http://localhost:3000",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "pwa-chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"url": "http://localhost:3000",
|
||||
"webRoot": "${workspaceFolder}",
|
||||
"preLaunchTask": "Start development server"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -106,12 +106,15 @@
|
||||
"xstring": "cpp",
|
||||
"xtr1common": "cpp",
|
||||
"xtree": "cpp",
|
||||
"xutility": "cpp"
|
||||
"xutility": "cpp",
|
||||
"xlocbuf": "cpp",
|
||||
"xlocmes": "cpp"
|
||||
},
|
||||
"files.exclude": {
|
||||
"Binaries/*build*": true,
|
||||
"Binaries/Output": true,
|
||||
"ExtLibs/SFML": true,
|
||||
"GDJS/Runtime-dist": true,
|
||||
"docs": true,
|
||||
"newIDE/electron-app/dist": true,
|
||||
"newIDE/app/build": true,
|
||||
|
158
.vscode/tasks.json
vendored
158
.vscode/tasks.json
vendored
@@ -1,66 +1,100 @@
|
||||
{
|
||||
"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."
|
||||
}
|
||||
]
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "start",
|
||||
"path": "newIDE/app/",
|
||||
"group": "build",
|
||||
"label": "Start development server",
|
||||
"detail": "Starts the GDevelop development server.",
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "cra",
|
||||
"fileLocation": ["relative", "${workspaceFolder}/newIDE/app"],
|
||||
"source": "create-react-app",
|
||||
"applyTo": "allDocuments",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^([^\\s].*?)$",
|
||||
"file": 1
|
||||
},
|
||||
{
|
||||
"regexp": "^ Line\\s+(\\d+):\\s+(.*)\\s\\s+(.*)$",
|
||||
"line": 1,
|
||||
"message": 2,
|
||||
"code": 3,
|
||||
"loop": true
|
||||
}
|
||||
],
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": "^(?:Compiled with warnings\\.|Compiled successfully!)$",
|
||||
"endsPattern": "^(?:Search for the keywords to learn more about each warning\\.|Note that the development build is not optimized\\.)$"
|
||||
}
|
||||
}
|
||||
],
|
||||
"presentation": {
|
||||
"reveal": "silent"
|
||||
},
|
||||
"isBackground": true,
|
||||
"runOptions": { "instanceLimit": 1, "runOn": "folderOpen" }
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "start",
|
||||
"path": "newIDE/electron-app/",
|
||||
"group": "build",
|
||||
"problemMatcher": [],
|
||||
"label": "Start electron app",
|
||||
"detail": "Starts the development local version of GDevelop."
|
||||
},
|
||||
{
|
||||
"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 "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Project/Effect.h"
|
||||
#include "GDCore/Project/Layer.h"
|
||||
#include "GDCore/Project/EffectsContainer.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
|
||||
@@ -26,10 +27,9 @@ void ExposeProjectEffects(
|
||||
auto& layout = project.GetLayout(s);
|
||||
|
||||
for (std::size_t l = 0; l < layout.GetLayersCount(); ++l) {
|
||||
auto& layer = layout.GetLayer(l);
|
||||
|
||||
for (std::size_t e = 0; e < layer.GetEffectsCount(); ++e) {
|
||||
auto& effect = layer.GetEffect(e);
|
||||
auto& effects = layout.GetLayer(l).GetEffects();
|
||||
for (std::size_t e = 0; e < effects.GetEffectsCount(); ++e) {
|
||||
auto& effect = effects.GetEffect(e);
|
||||
worker(effect);
|
||||
}
|
||||
}
|
||||
|
@@ -360,8 +360,11 @@ gd::String ExpressionCodeGenerator::GenerateDefaultValue(
|
||||
if (gd::ParameterMetadata::IsObject(type)) {
|
||||
return codeGenerator.GenerateBadObject();
|
||||
}
|
||||
if (gd::ParameterMetadata::IsExpression("string", type)) {
|
||||
return "\"\"";
|
||||
}
|
||||
|
||||
return (type == "string") ? "\"\"" : "0";
|
||||
return "0";
|
||||
}
|
||||
|
||||
void ExpressionCodeGenerator::OnVisitEmptyNode(EmptyNode& node) {
|
||||
|
@@ -66,6 +66,22 @@ class GD_CORE_API ExpressionParser2 {
|
||||
return Start(type, objectName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an object name (or empty if none) and a behavior name (or empty if none),
|
||||
* return the index of the first parameter that is inside the parenthesis:
|
||||
* 0, 1 or 2.
|
||||
*
|
||||
* For example, in an expression like `Object.MyBehavior::Method("hello")`, the
|
||||
* parameter "hello" is the second parameter (the first being by convention Object,
|
||||
* and the second MyBehavior, also by convention).
|
||||
*/
|
||||
static size_t WrittenParametersFirstIndex(const gd::String &objectName,
|
||||
const gd::String &behaviorName) {
|
||||
// By convention, object is always the first parameter, and behavior the
|
||||
// second one.
|
||||
return !behaviorName.empty() ? 2 : (!objectName.empty() ? 1 : 0);
|
||||
}
|
||||
|
||||
private:
|
||||
/** \name Grammar
|
||||
* Each method is a part of the grammar.
|
||||
@@ -999,13 +1015,6 @@ class GD_CORE_API ExpressionParser2 {
|
||||
}
|
||||
///@}
|
||||
|
||||
static size_t WrittenParametersFirstIndex(const gd::String &objectName,
|
||||
const gd::String &behaviorName) {
|
||||
// By convention, object is always the first parameter, and behavior the
|
||||
// second one.
|
||||
return !behaviorName.empty() ? 2 : (!objectName.empty() ? 1 : 0);
|
||||
}
|
||||
|
||||
gd::String expression;
|
||||
std::size_t currentPosition;
|
||||
|
||||
|
@@ -206,7 +206,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"all of the forces it has."),
|
||||
_("Add to _PARAM0_ _PARAM3_ force of _PARAM1_ p/s on X axis and "
|
||||
"_PARAM2_ p/s on Y axis"),
|
||||
_("Movement"),
|
||||
_("Movement using forces"),
|
||||
"res/actions/force24.png",
|
||||
"res/actions/force.png")
|
||||
|
||||
@@ -222,7 +222,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"using the specified angle and length."),
|
||||
_("Add to _PARAM0_ _PARAM3_ force, angle: _PARAM1_ degrees and "
|
||||
"length: _PARAM2_ pixels"),
|
||||
_("Movement"),
|
||||
_("Movement using forces"),
|
||||
"res/actions/force24.png",
|
||||
"res/actions/force.png")
|
||||
|
||||
@@ -238,7 +238,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Add a force to an object to make it move toward a position."),
|
||||
_("Move _PARAM0_ toward _PARAM1_;_PARAM2_ with _PARAM4_ force of _PARAM3_ "
|
||||
"pixels"),
|
||||
_("Movement"),
|
||||
_("Movement using forces"),
|
||||
"res/actions/force24.png",
|
||||
"res/actions/force.png")
|
||||
|
||||
@@ -251,30 +251,30 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
|
||||
obj.AddAction(
|
||||
"AddForceTournePos",
|
||||
_("Add a force to move around a position"),
|
||||
_("Add a force to an object to make it rotate around a "
|
||||
"Add a force to move around a position",
|
||||
"Add a force to an object to make it rotate around a "
|
||||
"position.\nNote that the movement is not precise, especially if "
|
||||
"the speed is high.\nTo position an object around a position more "
|
||||
"precisely, use the actions in the category \"Position\"."),
|
||||
_("Rotate _PARAM0_ around _PARAM1_;_PARAM2_ at _PARAM3_ deg/sec and "
|
||||
"_PARAM4_ pixels away"),
|
||||
_("Movement"),
|
||||
"precisely, use the actions in the category \"Position\".",
|
||||
"Rotate _PARAM0_ around _PARAM1_;_PARAM2_ at _PARAM3_ deg/sec and "
|
||||
"_PARAM4_ pixels away",
|
||||
_("Movement using forces"),
|
||||
"res/actions/forceTourne24.png",
|
||||
"res/actions/forceTourne.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("expression", _("X position of the center"))
|
||||
.AddParameter("expression", _("Y position of the center"))
|
||||
.AddParameter("expression", _("Speed (in Degrees per seconds)"))
|
||||
.AddParameter("expression", _("Distance (in pixels)"))
|
||||
.AddParameter("forceMultiplier", _("Force multiplier"))
|
||||
.AddParameter("expression", "X position of the center")
|
||||
.AddParameter("expression", "Y position of the center")
|
||||
.AddParameter("expression", "Speed (in Degrees per seconds)")
|
||||
.AddParameter("expression", "Distance (in pixels)")
|
||||
.AddParameter("forceMultiplier", "Force multiplier")
|
||||
.SetHidden();
|
||||
|
||||
obj.AddAction("Arreter",
|
||||
_("Stop the object"),
|
||||
_("Stop the object by deleting all of its forces."),
|
||||
_("Stop _PARAM0_ (remove all forces)"),
|
||||
_("Movement"),
|
||||
_("Movement using forces"),
|
||||
"res/actions/arreter24.png",
|
||||
"res/actions/arreter.png")
|
||||
|
||||
@@ -475,9 +475,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddCondition("Invisible",
|
||||
_("Invisibility of an object"),
|
||||
_("Check if an object is hidden."),
|
||||
_("_PARAM0_ is hidden"),
|
||||
"Invisibility of an object",
|
||||
"Check if an object is hidden.",
|
||||
"_PARAM0_ is hidden",
|
||||
_("Visibility"),
|
||||
"res/conditions/visibilite24.png",
|
||||
"res/conditions/visibilite.png")
|
||||
@@ -486,10 +486,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.SetHidden(); // Inverted "Visible" condition does the same thing.
|
||||
|
||||
obj.AddCondition("Arret",
|
||||
_("Object is stopped"),
|
||||
_("Object is stopped (no forces applied on it)"),
|
||||
_("Check if an object is not moving"),
|
||||
_("_PARAM0_ is stopped"),
|
||||
_("Movement"),
|
||||
_("Movement using forces"),
|
||||
"res/conditions/arret24.png",
|
||||
"res/conditions/arret.png")
|
||||
|
||||
@@ -497,10 +497,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddCondition("Vitesse",
|
||||
_("Speed"),
|
||||
_("Speed (from forces)"),
|
||||
_("Compare the overall speed of an object"),
|
||||
_("the overall speed"),
|
||||
_("Movement"),
|
||||
_("Movement using forces"),
|
||||
"res/conditions/vitesse24.png",
|
||||
"res/conditions/vitesse.png")
|
||||
|
||||
@@ -509,17 +509,17 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddCondition("AngleOfDisplacement",
|
||||
_("Angle of movement"),
|
||||
_("Compare the angle of displacement of an object"),
|
||||
_("Angle of displacement of _PARAM0_ is _PARAM1_ (tolerance "
|
||||
_("Angle of movement (using forces)"),
|
||||
_("Compare the angle of movement of an object according to the forces applied on it."),
|
||||
_("Angle of movement of _PARAM0_ is _PARAM1_ (tolerance"
|
||||
": _PARAM2_ degrees)"),
|
||||
_("Movement"),
|
||||
_("Movement using forces"),
|
||||
"res/conditions/vitesse24.png",
|
||||
"res/conditions/vitesse.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("expression", _("Angle, in degrees"))
|
||||
.AddParameter("expression", _("Tolerance"))
|
||||
.AddParameter("expression", _("Tolerance, in degrees"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddCondition("VarObjet",
|
||||
@@ -560,9 +560,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.SetDefaultValue("true");
|
||||
|
||||
obj.AddCondition("VarObjetDef",
|
||||
_("Variable defined"),
|
||||
_("Check if the variable is defined."),
|
||||
_("Variable _PARAM1 of _PARAM0_ is defined"),
|
||||
"Variable defined",
|
||||
"Check if the variable is defined.",
|
||||
"Variable _PARAM1 of _PARAM0_ is defined",
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
@@ -632,7 +632,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Removes a variable at the specified index of an object array "
|
||||
"variable."),
|
||||
_("Remove variable at index _PARAM2_ from array variable _PARAM1_ of "
|
||||
"object _PARAM0_"),
|
||||
"_PARAM0_"),
|
||||
_("Variables/Collections/Arrays"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
@@ -671,7 +671,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Add a force to move toward an object"),
|
||||
_("Add a force to an object to make it move toward another."),
|
||||
_("Move _PARAM0_ toward _PARAM1_ with _PARAM3_ force of _PARAM2_ pixels"),
|
||||
_("Movement"),
|
||||
_("Movement using forces"),
|
||||
"res/actions/forceVers24.png",
|
||||
"res/actions/forceVers.png")
|
||||
|
||||
@@ -690,7 +690,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"the actions in category \"Position\"."),
|
||||
_("Rotate _PARAM0_ around _PARAM1_ at _PARAM2_ deg/sec and _PARAM3_ "
|
||||
"pixels away"),
|
||||
_("Movement"),
|
||||
_("Movement using forces"),
|
||||
"res/actions/forceTourne24.png",
|
||||
"res/actions/forceTourne.png")
|
||||
|
||||
@@ -720,29 +720,29 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
|
||||
// Deprecated action
|
||||
obj.AddAction("Rebondir",
|
||||
_("Move an object away from another"),
|
||||
_("Move an object away from another, using forces."),
|
||||
_("Move _PARAM0_ away from _PARAM1_ (only _PARAM0_ will move)"),
|
||||
_("Movement"),
|
||||
"Move an object away from another",
|
||||
"Move an object away from another, using forces.",
|
||||
"Move _PARAM0_ away from _PARAM1_ (only _PARAM0_ will move)",
|
||||
_("Movement using forces"),
|
||||
"res/actions/ecarter24.png",
|
||||
"res/actions/ecarter.png")
|
||||
|
||||
.SetHidden()
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectList", _("Object 2 (won't move)"));
|
||||
.AddParameter("objectList", "Object 2 (won't move)");
|
||||
|
||||
// Deprecated action
|
||||
obj.AddAction("Ecarter",
|
||||
_("Move an object away from another"),
|
||||
_("Move an object away from another without using forces."),
|
||||
_("Move _PARAM0_ away from _PARAM2_ (only _PARAM0_ will move)"),
|
||||
"Move an object away from another",
|
||||
"Move an object away from another without using forces.",
|
||||
"Move _PARAM0_ away from _PARAM2_ (only _PARAM0_ will move)",
|
||||
_("Position"),
|
||||
"res/actions/ecarter24.png",
|
||||
"res/actions/ecarter.png")
|
||||
|
||||
.SetHidden()
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectList", _("Object 2 (won't move)"));
|
||||
.AddParameter("objectList", "Object 2 (won't move)");
|
||||
|
||||
obj.AddAction("SeparateFromObjects",
|
||||
_("Separate objects"),
|
||||
@@ -882,37 +882,37 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"));
|
||||
|
||||
obj.AddExpression("ForceX",
|
||||
_("Average X coordinates of forces"),
|
||||
_("Average X coordinates of forces"),
|
||||
_("Movement"),
|
||||
_("X coordinate of the sum of forces"),
|
||||
_("X coordinate of the sum of forces"),
|
||||
_("Movement using forces"),
|
||||
"res/actions/force.png")
|
||||
.AddParameter("object", _("Object"));
|
||||
|
||||
obj.AddExpression("ForceY",
|
||||
_("Average Y coordinates of forces"),
|
||||
_("Average Y coordinates of forces"),
|
||||
_("Movement"),
|
||||
_("Y coordinate of the sum of forces"),
|
||||
_("Y coordinate of the sum of forces"),
|
||||
_("Movement using forces"),
|
||||
"res/actions/force.png")
|
||||
.AddParameter("object", _("Object"));
|
||||
|
||||
obj.AddExpression("ForceAngle",
|
||||
_("Average angle of the forces"),
|
||||
_("Average angle of the forces"),
|
||||
_("Movement"),
|
||||
_("Angle of the sum of forces"),
|
||||
_("Angle of the sum of forces"),
|
||||
_("Movement using forces"),
|
||||
"res/actions/force.png")
|
||||
.AddParameter("object", _("Object"));
|
||||
|
||||
obj.AddExpression("ForceLength",
|
||||
_("Average length of the forces"),
|
||||
_("Average length of the forces"),
|
||||
_("Movement"),
|
||||
_("Length of the sum of forces"),
|
||||
_("Length of the sum of forces"),
|
||||
_("Movement using forces"),
|
||||
"res/actions/force.png")
|
||||
.AddParameter("object", _("Object"));
|
||||
|
||||
obj.AddExpression("Longueur",
|
||||
_("Average length of the forces"),
|
||||
_("Average length of the forces"),
|
||||
_("Movement"),
|
||||
_("Length of the sum of forces"),
|
||||
_("Length of the sum of forces"),
|
||||
_("Movement using forces"),
|
||||
"res/actions/force.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.SetHidden();
|
||||
@@ -1149,7 +1149,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Moves all objects according to the forces they have. GDevelop "
|
||||
"calls this action at the end of the events by default."),
|
||||
_("Apply movement to all objects"),
|
||||
_("Movement"),
|
||||
_("Movement using forces"),
|
||||
"res/actions/doMove24.png",
|
||||
"res/actions/doMove.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
@@ -1157,16 +1157,16 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
|
||||
extension
|
||||
.AddCondition("SeDirige",
|
||||
_("An object is moving toward another"),
|
||||
_("An object is moving toward another (using forces)"),
|
||||
_("Check if an object moves toward another.\nThe first "
|
||||
"object must move."),
|
||||
_("_PARAM0_ is moving toward _PARAM1_"),
|
||||
_("Movement"),
|
||||
_("Movement using forces"),
|
||||
"res/conditions/sedirige24.png",
|
||||
"res/conditions/sedirige.png")
|
||||
.AddParameter("objectList", _("Object"))
|
||||
.AddParameter("objectList", _("Object 2"))
|
||||
.AddParameter("expression", _("Angle of tolerance"))
|
||||
.AddParameter("expression", _("Tolerance, in degrees"))
|
||||
.AddCodeOnlyParameter("conditionInverted", "")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
|
@@ -15,7 +15,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
|
||||
.SetExtensionInformation(
|
||||
"BuiltinNetwork",
|
||||
_("Basic internet features"),
|
||||
_("Features to send web requests, communicate with external \"APIs\" and other network related tasks."),
|
||||
_("Features to send web requests, communicate with external \"APIs\" "
|
||||
"and other network related tasks."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/network");
|
||||
@@ -24,33 +25,33 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
|
||||
extension
|
||||
.AddAction(
|
||||
"SendRequest",
|
||||
_("Send a request to a web page"),
|
||||
_("Send a 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 _PARAM3_ request to _PARAM0__PARAM1_ with body: _PARAM2_"),
|
||||
"Send a request to a web page",
|
||||
"Send a 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 _PARAM3_ request to _PARAM0__PARAM1_ with body: _PARAM2_",
|
||||
_("Network"),
|
||||
"res/actions/net24.png",
|
||||
"res/actions/net.png")
|
||||
.AddParameter("string", _("Host, with protocol"))
|
||||
.SetParameterLongDescription(_("Example: \"http://example.com/\"."))
|
||||
.AddParameter("string", _("Path"))
|
||||
.AddParameter("string", "Host, with protocol")
|
||||
.SetParameterLongDescription("Example: \"http://example.com/\".")
|
||||
.AddParameter("string", "Path")
|
||||
.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."))
|
||||
"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.")
|
||||
.SetDefaultValue("\"GET\"")
|
||||
.AddParameter("string", _("Content type"), "", true)
|
||||
.AddParameter("string", "Content type", "", true)
|
||||
.SetParameterLongDescription(
|
||||
_("If empty, \"application/x-www-form-urlencoded\" will be used."))
|
||||
.AddParameter("scenevar", _("Reponse scene variable"), "", true)
|
||||
"If empty, \"application/x-www-form-urlencoded\" will be used.")
|
||||
.AddParameter("scenevar", "Reponse scene variable", "", 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*."))
|
||||
"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*.")
|
||||
.MarkAsComplex()
|
||||
.SetHidden();
|
||||
|
||||
@@ -74,7 +75,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
|
||||
"highly recommended."))
|
||||
.AddParameter("string", _("Request body content"))
|
||||
.AddParameter("stringWithSelector",
|
||||
_("Resize mode"),
|
||||
_("Request method"),
|
||||
"[\"GET\", \"POST\", \"PUT\", \"HEAD\", \"DELETE\", "
|
||||
"\"PATCH\", \"OPTIONS\"]",
|
||||
false)
|
||||
|
@@ -66,7 +66,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
"res/actions/animation.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("string", _("Animation name"))
|
||||
.AddParameter("objectAnimationName", _("Animation name"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction(
|
||||
@@ -133,9 +133,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddAction("TourneVersPos",
|
||||
_("Rotate an object toward a position"),
|
||||
_("Rotate an object towards a position."),
|
||||
_("Rotate _PARAM0_ towards _PARAM1_;_PARAM2_"),
|
||||
"Rotate an object toward a position",
|
||||
"Rotate an object towards a position.",
|
||||
"Rotate _PARAM0_ towards _PARAM1_;_PARAM2_",
|
||||
_("Direction"),
|
||||
"res/actions/direction24.png",
|
||||
"res/actions/direction.png")
|
||||
@@ -230,7 +230,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
"res/conditions/animation.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("string", _("Animation name"))
|
||||
.AddParameter("objectAnimationName", _("Animation name"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddCondition(
|
||||
@@ -249,7 +249,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
|
||||
obj.AddCondition("Sprite",
|
||||
_("Current frame"),
|
||||
_("Compare the index of the current frame in the animation displayed by the specified object. The first frame in an animation starts at index 0."),
|
||||
_("Compare the index of the current frame in the animation "
|
||||
"displayed by the specified object. The first frame in an "
|
||||
"animation starts at index 0."),
|
||||
_("the animation frame"),
|
||||
_("Animations and images"),
|
||||
"res/conditions/sprite24.png",
|
||||
@@ -365,14 +367,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("color", _("Color to make transparent"));
|
||||
|
||||
obj.AddAction(
|
||||
"ChangeColor",
|
||||
_("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")
|
||||
obj.AddAction("ChangeColor",
|
||||
_("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", _("Tint"));
|
||||
@@ -436,15 +437,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
.AddParameter("object", _("Object"), "Sprite");
|
||||
|
||||
obj.AddAction("TourneVers",
|
||||
_("Rotate an object toward another"),
|
||||
_("Rotate an object towards another."),
|
||||
_("Rotate _PARAM0_ towards _PARAM1_"),
|
||||
"Rotate an object toward another",
|
||||
"Rotate an object towards another.",
|
||||
"Rotate _PARAM0_ towards _PARAM1_",
|
||||
_("Direction"),
|
||||
"res/actions/direction24.png",
|
||||
"res/actions/direction.png")
|
||||
|
||||
.AddParameter("object", _("Object to be rotated"), "Sprite")
|
||||
.AddParameter("objectPtr", _("Rotate toward this object"))
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("objectPtr", "Rotate toward this object")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.SetHidden(); // Deprecated
|
||||
|
||||
@@ -455,7 +456,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
"res/actions/position.png")
|
||||
.SetHidden()
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("string", _("Name of the point"), "", true);
|
||||
.AddParameter("objectPointName", _("Name of the point"), "", true);
|
||||
|
||||
obj.AddExpression("Y",
|
||||
_("Y position of a point"),
|
||||
@@ -464,7 +465,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
"res/actions/position.png")
|
||||
.SetHidden()
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("string", _("Name of the point"), "", true);
|
||||
.AddParameter("objectPointName", _("Name of the point"), "", true);
|
||||
|
||||
obj.AddExpression("PointX",
|
||||
_("X position of a point"),
|
||||
@@ -473,7 +474,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
"res/actions/position.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("string", _("Name of the point"));
|
||||
.AddParameter("objectPointName", _("Name of the point"));
|
||||
|
||||
obj.AddExpression("PointY",
|
||||
_("Y position of a point"),
|
||||
@@ -482,7 +483,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
"res/actions/position.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("string", _("Name of the point"));
|
||||
.AddParameter("objectPointName", _("Name of the point"));
|
||||
|
||||
obj.AddExpression("Direc",
|
||||
_("Direction"),
|
||||
|
@@ -112,9 +112,9 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
|
||||
extension
|
||||
.AddExpression("StrRFind",
|
||||
_("Search in a text from the end"),
|
||||
_("Search in a text from the end (return the position of "
|
||||
"the result or -1 if not found)"),
|
||||
"Search in a text from the end",
|
||||
"Search in a text from the end (return the position of "
|
||||
"the result or -1 if not found)",
|
||||
_("Manipulation of text"),
|
||||
"res/conditions/toujours24.png")
|
||||
|
||||
@@ -152,17 +152,17 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
extension
|
||||
.AddExpression(
|
||||
"StrRFindFrom",
|
||||
_("Search in a text from the end, starting from a position"),
|
||||
_("Search in a text from the end, starting from a position (return "
|
||||
"the position of the result or -1 if not found)"),
|
||||
"Search in a text from the end, starting from a position",
|
||||
"Search in a text from the end, starting from a position (return "
|
||||
"the position of the result or -1 if not found)",
|
||||
_("Manipulation of text"),
|
||||
"res/conditions/toujours24.png")
|
||||
|
||||
.AddParameter("string", _("Text"))
|
||||
.AddParameter("string", _("Text to search for"))
|
||||
.AddParameter("expression",
|
||||
_("Position of the last character in the string to be "
|
||||
"considered in the search"))
|
||||
"Position of the last character in the string to be "
|
||||
"considered in the search")
|
||||
.SetHidden(); // Deprecated, see StrFindLastFrom instead.
|
||||
|
||||
extension
|
||||
|
@@ -87,9 +87,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
|
||||
extension
|
||||
.AddCondition("VarSceneDef",
|
||||
_("Test if a scene variable is defined"),
|
||||
_("Test if the scene variable exists."),
|
||||
_("Scene variable _PARAM0_ is defined"),
|
||||
"Test if a scene variable is defined",
|
||||
"Test if the scene variable exists.",
|
||||
"Scene variable _PARAM0_ is defined",
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
@@ -136,9 +136,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
|
||||
extension
|
||||
.AddCondition("VarGlobalDef",
|
||||
_("Test if a global variable is defined"),
|
||||
_("Test if a global variable exists"),
|
||||
_("Global variable _PARAM0_ is defined"),
|
||||
"Test if a global variable is defined",
|
||||
"Test if a global variable exists",
|
||||
"Global variable _PARAM0_ is defined",
|
||||
_("Variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
@@ -341,7 +341,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
"SceneVariableRemoveAt",
|
||||
_("Remove variable from a scene array (by index)"),
|
||||
_("Removes a variable at the specified index of a scene array variable."),
|
||||
_("Remove variable at index _PARAM1_ from array variable _PARAM0_"),
|
||||
_("Remove variable at index _PARAM1_ from scene array variable _PARAM0_"),
|
||||
_("Variables/Collections/Arrays"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
@@ -367,7 +367,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
"GlobalVariableRemoveAt",
|
||||
_("Remove variable from a global array (by index)"),
|
||||
_("Removes a variable at the specified index of a global array variable."),
|
||||
_("Remove variable at index _PARAM1_ from array variable _PARAM0_"),
|
||||
_("Remove variable at index _PARAM1_ from global array variable _PARAM0_"),
|
||||
_("Variables/Global variables/Collections/Arrays"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
|
@@ -19,7 +19,7 @@ using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
gd::BehaviorMetadata MetadataProvider::badBehaviorInfo;
|
||||
gd::BehaviorMetadata MetadataProvider::badBehaviorMetadata;
|
||||
gd::ObjectMetadata MetadataProvider::badObjectInfo;
|
||||
gd::EffectMetadata MetadataProvider::badEffectMetadata;
|
||||
gd::InstructionMetadata MetadataProvider::badInstructionMetadata;
|
||||
@@ -38,7 +38,7 @@ MetadataProvider::GetExtensionAndBehaviorMetadata(const gd::Platform& platform,
|
||||
}
|
||||
}
|
||||
|
||||
return ExtensionAndMetadata<BehaviorMetadata>(badExtension, badBehaviorInfo);
|
||||
return ExtensionAndMetadata<BehaviorMetadata>(badExtension, badBehaviorMetadata);
|
||||
}
|
||||
|
||||
const BehaviorMetadata& MetadataProvider::GetBehaviorMetadata(
|
||||
|
@@ -245,13 +245,17 @@ class GD_CORE_API MetadataProvider {
|
||||
return &metadata == &badExpressionMetadata;
|
||||
}
|
||||
|
||||
static bool IsBadBehaviorMetadata(const gd::BehaviorMetadata& metadata) {
|
||||
return &metadata == &badBehaviorMetadata;
|
||||
}
|
||||
|
||||
virtual ~MetadataProvider();
|
||||
|
||||
private:
|
||||
MetadataProvider();
|
||||
|
||||
static PlatformExtension badExtension;
|
||||
static BehaviorMetadata badBehaviorInfo;
|
||||
static BehaviorMetadata badBehaviorMetadata;
|
||||
static ObjectMetadata badObjectInfo;
|
||||
static EffectMetadata badEffectMetadata;
|
||||
static gd::InstructionMetadata badInstructionMetadata;
|
||||
|
@@ -175,7 +175,8 @@ class GD_CORE_API ParameterMetadata {
|
||||
* \brief Return true if the type of the parameter is an expression of the
|
||||
* given type.
|
||||
* \note If you had a new type of parameter, also add it in the IDE (
|
||||
* see EventsFunctionParametersEditor) and in the EventsCodeGenerator.
|
||||
* see EventsFunctionParametersEditor, ParameterRenderingService
|
||||
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
|
||||
*/
|
||||
static bool IsExpression(const gd::String &type,
|
||||
const gd::String ¶meterType) {
|
||||
@@ -187,7 +188,9 @@ class GD_CORE_API ParameterMetadata {
|
||||
parameterType == "color" || parameterType == "file" ||
|
||||
parameterType == "joyaxis" ||
|
||||
parameterType == "stringWithSelector" ||
|
||||
parameterType == "sceneName";
|
||||
parameterType == "sceneName" ||
|
||||
parameterType == "objectPointName" ||
|
||||
parameterType == "objectAnimationName";
|
||||
} else if (type == "variable") {
|
||||
return parameterType == "objectvar" || parameterType == "globalvar" ||
|
||||
parameterType == "scenevar";
|
||||
|
@@ -100,26 +100,6 @@ std::unique_ptr<gd::Object> Platform::CreateObject(
|
||||
return std::unique_ptr<gd::Object>(std::move(object));
|
||||
}
|
||||
|
||||
gd::Behavior* Platform::GetBehavior(const gd::String& behaviorType) const {
|
||||
for (std::size_t i = 0; i < extensionsLoaded.size(); ++i) {
|
||||
gd::Behavior* behavior = extensionsLoaded[i]->GetBehavior(behaviorType);
|
||||
if (behavior) return behavior;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gd::BehaviorsSharedData* Platform::GetBehaviorSharedDatas(
|
||||
const gd::String& behaviorType) const {
|
||||
for (std::size_t i = 0; i < extensionsLoaded.size(); ++i) {
|
||||
gd::BehaviorsSharedData* behaviorSharedData =
|
||||
extensionsLoaded[i]->GetBehaviorSharedDatas(behaviorType);
|
||||
if (behaviorSharedData) return behaviorSharedData;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
std::shared_ptr<gd::BaseEvent> Platform::CreateEvent(
|
||||
const gd::String& eventType) const {
|
||||
|
@@ -126,7 +126,8 @@ class GD_CORE_API Platform {
|
||||
///@}
|
||||
|
||||
/** \name Factory method
|
||||
* Member functions used to create the platforms objects
|
||||
* Member functions used to create the platform objects.
|
||||
* TODO: This could be moved to gd::MetadataProvider.
|
||||
*/
|
||||
///@{
|
||||
|
||||
@@ -136,18 +137,6 @@ class GD_CORE_API Platform {
|
||||
std::unique_ptr<gd::Object> CreateObject(gd::String type,
|
||||
const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* \brief Get the class handling the behavior with the given type, or
|
||||
* `nullptr` if no behavior with the given type is found.
|
||||
*/
|
||||
gd::Behavior* GetBehavior(const gd::String& type) const;
|
||||
|
||||
/**
|
||||
* \brief Get the class handling the behavior shared data with the given type,
|
||||
* or `nullptr` if no behavior with the given type is found.
|
||||
*/
|
||||
gd::BehaviorsSharedData* GetBehaviorSharedDatas(const gd::String& type) const;
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Create an event of given type
|
||||
@@ -165,11 +154,13 @@ class GD_CORE_API Platform {
|
||||
/**
|
||||
* \brief Called when the IDE is about to shut down: Take this opportunity for
|
||||
* erasing for example any temporary file.
|
||||
* @deprecated This should be removed.
|
||||
*/
|
||||
virtual void OnIDEClosed(){};
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE is initialized and ready to be used.
|
||||
* @deprecated This should be removed.
|
||||
*/
|
||||
virtual void OnIDEInitialized(){};
|
||||
|
||||
|
@@ -512,7 +512,7 @@ PlatformExtension::GetAllStrExpressionsForBehavior(gd::String autoType) {
|
||||
return badExpressionsMetadata;
|
||||
}
|
||||
|
||||
gd::BaseEventSPtr PlatformExtension::CreateEvent(gd::String eventType) const {
|
||||
gd::BaseEventSPtr PlatformExtension::CreateEvent(const gd::String& eventType) const {
|
||||
if (eventsInfos.find(eventType) != eventsInfos.end()) {
|
||||
if (eventsInfos.find(eventType)->second.instance ==
|
||||
std::shared_ptr<BaseEvent>()) {
|
||||
@@ -531,14 +531,14 @@ gd::BaseEventSPtr PlatformExtension::CreateEvent(gd::String eventType) const {
|
||||
#endif
|
||||
|
||||
CreateFunPtr PlatformExtension::GetObjectCreationFunctionPtr(
|
||||
gd::String objectType) const {
|
||||
const gd::String& objectType) const {
|
||||
if (objectsInfos.find(objectType) != objectsInfos.end())
|
||||
return objectsInfos.find(objectType)->second.createFunPtr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gd::Behavior* PlatformExtension::GetBehavior(gd::String type) const {
|
||||
gd::Behavior* PlatformExtension::GetBehavior(const gd::String& type) const {
|
||||
if (behaviorsInfo.find(type) != behaviorsInfo.end())
|
||||
return &behaviorsInfo.find(type)->second.Get();
|
||||
|
||||
@@ -546,7 +546,7 @@ gd::Behavior* PlatformExtension::GetBehavior(gd::String type) const {
|
||||
}
|
||||
|
||||
gd::BehaviorsSharedData* PlatformExtension::GetBehaviorSharedDatas(
|
||||
gd::String type) const {
|
||||
const gd::String& type) const {
|
||||
if (behaviorsInfo.find(type) != behaviorsInfo.end() &&
|
||||
behaviorsInfo.find(type)->second.GetSharedDataInstance())
|
||||
return behaviorsInfo.find(type)->second.GetSharedDataInstance();
|
||||
|
@@ -400,7 +400,7 @@ class GD_CORE_API PlatformExtension {
|
||||
* \brief Return a function to create the object if the type is handled by the
|
||||
* extension
|
||||
*/
|
||||
CreateFunPtr GetObjectCreationFunctionPtr(gd::String objectType) const;
|
||||
CreateFunPtr GetObjectCreationFunctionPtr(const gd::String& objectType) const;
|
||||
|
||||
/**
|
||||
* \brief Return a vector containing all the effect types provided by the
|
||||
@@ -413,13 +413,13 @@ class GD_CORE_API PlatformExtension {
|
||||
*
|
||||
* Return an empty pointer if \a eventType is not provided by the extension.
|
||||
*/
|
||||
std::shared_ptr<gd::BaseEvent> CreateEvent(gd::String eventType) const;
|
||||
std::shared_ptr<gd::BaseEvent> CreateEvent(const gd::String& eventType) const;
|
||||
/**
|
||||
* \brief Get the gd::Behavior handling the given behavior type.
|
||||
*
|
||||
* Return nullptr if \a behaviorType is not provided by the extension.
|
||||
*/
|
||||
gd::Behavior* GetBehavior(gd::String behaviorType) const;
|
||||
gd::Behavior* GetBehavior(const gd::String& behaviorType) const;
|
||||
|
||||
/**
|
||||
* \brief Get the gd::BehaviorsSharedData handling the given behavior shared
|
||||
@@ -428,7 +428,7 @@ class GD_CORE_API PlatformExtension {
|
||||
* Return nullptr if \a behaviorType is not provided by the extension.
|
||||
*/
|
||||
gd::BehaviorsSharedData* GetBehaviorSharedDatas(
|
||||
gd::String behaviorType) const;
|
||||
const gd::String& behaviorType) const;
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the ObjectMetadata object associated to \a
|
||||
|
@@ -15,25 +15,18 @@
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/SourceFile.h"
|
||||
|
||||
DependenciesAnalyzer::DependenciesAnalyzer(gd::Project& project_,
|
||||
gd::Layout& layout_)
|
||||
DependenciesAnalyzer::DependenciesAnalyzer(const gd::Project& project_,
|
||||
const gd::Layout& layout_)
|
||||
: project(project_), layout(&layout_), externalEvents(NULL) {
|
||||
parentScenes.push_back(layout->GetName());
|
||||
}
|
||||
|
||||
DependenciesAnalyzer::DependenciesAnalyzer(gd::Project& project_,
|
||||
gd::ExternalEvents& externalEvents_)
|
||||
DependenciesAnalyzer::DependenciesAnalyzer(const gd::Project& project_,
|
||||
const gd::ExternalEvents& externalEvents_)
|
||||
: project(project_), layout(NULL), externalEvents(&externalEvents_) {
|
||||
parentExternalEvents.push_back(externalEvents->GetName());
|
||||
}
|
||||
|
||||
DependenciesAnalyzer::DependenciesAnalyzer(const DependenciesAnalyzer& parent)
|
||||
: parentScenes(parent.parentScenes),
|
||||
parentExternalEvents(parent.parentExternalEvents),
|
||||
project(parent.project),
|
||||
layout(NULL),
|
||||
externalEvents(NULL) {}
|
||||
|
||||
bool DependenciesAnalyzer::Analyze() {
|
||||
if (layout)
|
||||
return Analyze(layout->GetEvents(), true);
|
||||
@@ -47,9 +40,9 @@ bool DependenciesAnalyzer::Analyze() {
|
||||
|
||||
DependenciesAnalyzer::~DependenciesAnalyzer() {}
|
||||
|
||||
bool DependenciesAnalyzer::Analyze(gd::EventsList& events, bool isOnTopLevel) {
|
||||
bool DependenciesAnalyzer::Analyze(const gd::EventsList& events, bool isOnTopLevel) {
|
||||
for (unsigned int i = 0; i < events.size(); ++i) {
|
||||
gd::LinkEvent* linkEvent = dynamic_cast<gd::LinkEvent*>(&events[i]);
|
||||
const gd::LinkEvent* linkEvent = dynamic_cast<const gd::LinkEvent*>(&events[i]);
|
||||
if (linkEvent) {
|
||||
DependenciesAnalyzer analyzer(*this);
|
||||
|
||||
@@ -113,7 +106,7 @@ bool DependenciesAnalyzer::Analyze(gd::EventsList& events, bool isOnTopLevel) {
|
||||
sourceFilesDependencies.insert(dependencies.begin(), dependencies.end());
|
||||
|
||||
const gd::String& associatedSourceFile =
|
||||
events[i].GetAssociatedGDManagedSourceFile(project);
|
||||
events[i].GetAssociatedGDManagedSourceFile(const_cast<gd::Project&>(project));
|
||||
if (!associatedSourceFile.empty())
|
||||
sourceFilesDependencies.insert(associatedSourceFile);
|
||||
|
||||
|
@@ -35,7 +35,7 @@ class GD_CORE_API DependenciesAnalyzer {
|
||||
/**
|
||||
* \brief Constructor for analyzing the dependencies of a layout
|
||||
*/
|
||||
DependenciesAnalyzer(gd::Project& project_, gd::Layout& layout_);
|
||||
DependenciesAnalyzer(const gd::Project& project_, const gd::Layout& layout_);
|
||||
|
||||
/**
|
||||
* \brief Constructor for analyzing the dependencies of external events.
|
||||
@@ -45,8 +45,8 @@ class GD_CORE_API DependenciesAnalyzer {
|
||||
* external events can be compiled separatly and called by a scene. \see
|
||||
* DependenciesAnalyzer::ExternalEventsCanBeCompiledForAScene
|
||||
*/
|
||||
DependenciesAnalyzer(gd::Project& project_,
|
||||
gd::ExternalEvents& externalEvents);
|
||||
DependenciesAnalyzer(const gd::Project& project_,
|
||||
const gd::ExternalEvents& externalEvents);
|
||||
|
||||
virtual ~DependenciesAnalyzer();
|
||||
|
||||
@@ -124,13 +124,7 @@ class GD_CORE_API DependenciesAnalyzer {
|
||||
* (they have no parents). \return false if a circular dependency exists, true
|
||||
* otherwise.
|
||||
*/
|
||||
bool Analyze(gd::EventsList& events, bool isOnTopLevel);
|
||||
|
||||
/**
|
||||
* \brief Internal constructor used when analyzing a linked layout/external
|
||||
* events.
|
||||
*/
|
||||
DependenciesAnalyzer(const DependenciesAnalyzer& parent);
|
||||
bool Analyze(const gd::EventsList& events, bool isOnTopLevel);
|
||||
|
||||
void AddParentScene(gd::String parentScene) {
|
||||
parentScenes.push_back(parentScene);
|
||||
@@ -161,9 +155,9 @@ class GD_CORE_API DependenciesAnalyzer {
|
||||
std::vector<gd::String>
|
||||
parentExternalEvents; ///< Used to check for circular dependencies.
|
||||
|
||||
gd::Project& project;
|
||||
gd::Layout* layout;
|
||||
gd::ExternalEvents* externalEvents;
|
||||
const gd::Project& project;
|
||||
const gd::Layout* layout;
|
||||
const gd::ExternalEvents* externalEvents;
|
||||
};
|
||||
|
||||
#endif // DEPENDENCIESANALYZER_H
|
||||
|
@@ -17,6 +17,8 @@
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
#include "GDCore/IDE/DependenciesAnalyzer.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -95,11 +97,11 @@ std::set<gd::String> EventsVariablesFinder::FindAllGlobalVariables(
|
||||
|
||||
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
|
||||
std::set<gd::String> results2 =
|
||||
FindArgumentsInEvents(platform,
|
||||
project,
|
||||
project.GetLayout(i),
|
||||
project.GetLayout(i).GetEvents(),
|
||||
"globalvar");
|
||||
FindArgumentsInEventsAndDependencies(
|
||||
platform,
|
||||
project,
|
||||
project.GetLayout(i),
|
||||
"globalvar");
|
||||
results.insert(results2.begin(), results2.end());
|
||||
}
|
||||
|
||||
@@ -112,8 +114,8 @@ std::set<gd::String> EventsVariablesFinder::FindAllLayoutVariables(
|
||||
const gd::Layout& layout) {
|
||||
std::set<gd::String> results;
|
||||
|
||||
std::set<gd::String> results2 = FindArgumentsInEvents(
|
||||
platform, project, layout, layout.GetEvents(), "scenevar");
|
||||
std::set<gd::String> results2 = FindArgumentsInEventsAndDependencies(
|
||||
platform, project, layout, "scenevar");
|
||||
results.insert(results2.begin(), results2.end());
|
||||
|
||||
return results;
|
||||
@@ -126,12 +128,12 @@ std::set<gd::String> EventsVariablesFinder::FindAllObjectVariables(
|
||||
const gd::Object& object) {
|
||||
std::set<gd::String> results;
|
||||
|
||||
std::set<gd::String> results2 = FindArgumentsInEvents(platform,
|
||||
project,
|
||||
layout,
|
||||
layout.GetEvents(),
|
||||
"objectvar",
|
||||
object.GetName());
|
||||
std::set<gd::String> results2 = FindArgumentsInEventsAndDependencies(
|
||||
platform,
|
||||
project,
|
||||
layout,
|
||||
"objectvar",
|
||||
object.GetName());
|
||||
results.insert(results2.begin(), results2.end());
|
||||
|
||||
return results;
|
||||
@@ -203,6 +205,38 @@ std::set<gd::String> EventsVariablesFinder::FindArgumentsInInstructions(
|
||||
return results;
|
||||
}
|
||||
|
||||
std::set<gd::String> EventsVariablesFinder::FindArgumentsInEventsAndDependencies(
|
||||
const gd::Platform& platform,
|
||||
const gd::Project& project,
|
||||
const gd::Layout& layout,
|
||||
const gd::String& parameterType,
|
||||
const gd::String& objectName) {
|
||||
std::set<gd::String> results;
|
||||
|
||||
std::set<gd::String> results2 = FindArgumentsInEvents(
|
||||
platform, project, layout, layout.GetEvents(), parameterType, objectName);
|
||||
results.insert(results2.begin(), results2.end());
|
||||
|
||||
DependenciesAnalyzer dependenciesAnalyzer = DependenciesAnalyzer(project, layout);
|
||||
dependenciesAnalyzer.Analyze();
|
||||
for (const gd::String& externalEventName : dependenciesAnalyzer.GetExternalEventsDependencies()) {
|
||||
const gd::ExternalEvents& externalEvents = project.GetExternalEvents(externalEventName);
|
||||
|
||||
std::set<gd::String> results3 = FindArgumentsInEvents(
|
||||
platform, project, layout, externalEvents.GetEvents(), parameterType, objectName);
|
||||
results.insert(results3.begin(), results3.end());
|
||||
}
|
||||
for (const gd::String& sceneName : dependenciesAnalyzer.GetScenesDependencies()) {
|
||||
const gd::Layout& dependencyLayout = project.GetLayout(sceneName);
|
||||
|
||||
std::set<gd::String> results3 = FindArgumentsInEvents(
|
||||
platform, project, dependencyLayout, dependencyLayout.GetEvents(), parameterType, objectName);
|
||||
results.insert(results3.begin(), results3.end());
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
std::set<gd::String> EventsVariablesFinder::FindArgumentsInEvents(
|
||||
const gd::Platform& platform,
|
||||
const gd::Project& project,
|
||||
|
@@ -24,11 +24,17 @@ namespace gd {
|
||||
* global or object variables.
|
||||
*
|
||||
* \todo Refactor this class using ArbitraryEventsWorker
|
||||
* \todo Rework this class to return the shapes (maybe even types?) of the
|
||||
* variables (in particular for structures and arrays), so we can use this
|
||||
* for better autocompletions in the variables dialogs in the IDE.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class EventsVariablesFinder {
|
||||
public:
|
||||
EventsVariablesFinder(){};
|
||||
virtual ~EventsVariablesFinder(){};
|
||||
|
||||
/**
|
||||
* Construct a list containing the name of all global variables used in the
|
||||
* project.
|
||||
@@ -94,10 +100,34 @@ class EventsVariablesFinder {
|
||||
|
||||
/**
|
||||
* Construct a list of the value of the arguments for parameters of type @
|
||||
* parameterType
|
||||
* parameterType. It searchs in events dependencies.
|
||||
*
|
||||
* \param platform The platform of the project
|
||||
* \param project The project used
|
||||
* \param project The layout used
|
||||
* \param layout The layout used
|
||||
* \param events The events to be analyzed
|
||||
* \param parameterType The parameters type to be analyzed
|
||||
* \param objectName If not empty, parameters will be taken into account
|
||||
* only if the last object parameter is filled with
|
||||
* this value.
|
||||
*
|
||||
* \return A std::set filled with the values used for all parameters of the
|
||||
* specified type
|
||||
*/
|
||||
static std::set<gd::String> FindArgumentsInEventsAndDependencies(
|
||||
const gd::Platform& platform,
|
||||
const gd::Project& project,
|
||||
const gd::Layout& layout,
|
||||
const gd::String& parameterType,
|
||||
const gd::String& objectName = "");
|
||||
|
||||
/**
|
||||
* Construct a list of the value of the arguments for parameters of type @
|
||||
* parameterType. It doesn't search in events dependencies.
|
||||
*
|
||||
* \param platform The platform of the project
|
||||
* \param project The project used
|
||||
* \param layout The layout used
|
||||
* \param events The events to be analyzed
|
||||
* \param parameterType The parameters type to be analyzed
|
||||
* \param objectName If not empty, parameters will be taken into account
|
||||
@@ -113,10 +143,7 @@ class EventsVariablesFinder {
|
||||
const gd::Layout& layout,
|
||||
const gd::EventsList& events,
|
||||
const gd::String& parameterType,
|
||||
const gd::String& objectName = "");
|
||||
|
||||
EventsVariablesFinder(){};
|
||||
virtual ~EventsVariablesFinder(){};
|
||||
const gd::String& objectName);
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
31
Core/GDCore/IDE/Events/ExpressionCompletionFinder.cpp
Normal file
31
Core/GDCore/IDE/Events/ExpressionCompletionFinder.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "ExpressionCompletionFinder.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
const gd::ParameterMetadata
|
||||
ExpressionCompletionDescription::badParameterMetadata;
|
||||
|
||||
/**
|
||||
* \brief Turn an ExpressionCompletionDescription to a string.
|
||||
*/
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
ExpressionCompletionDescription const& value) {
|
||||
os << "{ " << value.GetCompletionKind() << ", " << value.GetType() << ", "
|
||||
<< value.GetPrefix() << ", " << value.GetObjectName() << ", "
|
||||
<< value.GetBehaviorName() << ", "
|
||||
<< (value.IsExact() ? "exact" : "non-exact") << ", "
|
||||
<< (value.IsLastParameter() ? "last parameter" : "not last parameter")
|
||||
<< ", "
|
||||
<< (value.HasParameterMetadata()
|
||||
? gd::String::From(&value.GetParameterMetadata())
|
||||
: "no parameter metadata")
|
||||
<< " }";
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -8,10 +8,14 @@
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/IDE/Events/ExpressionNodeLocationFinder.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
|
||||
namespace gd {
|
||||
class Expression;
|
||||
class ObjectsContainer;
|
||||
@@ -33,19 +37,21 @@ struct ExpressionCompletionDescription {
|
||||
/**
|
||||
* The different kind of completions that can be described.
|
||||
*/
|
||||
enum CompletionKind {
|
||||
Object,
|
||||
Behavior,
|
||||
Expression,
|
||||
Variable,
|
||||
};
|
||||
enum CompletionKind { Object, Behavior, Expression, Variable, Text };
|
||||
|
||||
/**
|
||||
* \brief Create a completion for an object with the given prefix
|
||||
*/
|
||||
static ExpressionCompletionDescription ForObject(const gd::String& type_,
|
||||
const gd::String& prefix_) {
|
||||
return ExpressionCompletionDescription(Object, type_, prefix_);
|
||||
static ExpressionCompletionDescription ForObject(
|
||||
const gd::String& type_,
|
||||
const gd::String& prefix_,
|
||||
size_t replacementStartPosition_,
|
||||
size_t replacementEndPosition_) {
|
||||
return ExpressionCompletionDescription(Object,
|
||||
type_,
|
||||
prefix_,
|
||||
replacementStartPosition_,
|
||||
replacementEndPosition_);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,17 +59,58 @@ struct ExpressionCompletionDescription {
|
||||
* the specified object
|
||||
*/
|
||||
static ExpressionCompletionDescription ForBehavior(
|
||||
const gd::String& prefix_, const gd::String& objectName_) {
|
||||
return ExpressionCompletionDescription(Behavior, "", prefix_, objectName_);
|
||||
const gd::String& prefix_,
|
||||
size_t replacementStartPosition_,
|
||||
size_t replacementEndPosition_,
|
||||
const gd::String& objectName_) {
|
||||
return ExpressionCompletionDescription(Behavior,
|
||||
"",
|
||||
prefix_,
|
||||
replacementStartPosition_,
|
||||
replacementEndPosition_,
|
||||
objectName_);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Create a completion for a variable with the given prefix
|
||||
*/
|
||||
static ExpressionCompletionDescription ForVariable(
|
||||
const gd::String& type_, const gd::String& prefix_) {
|
||||
return ExpressionCompletionDescription(Variable, type_, prefix_);
|
||||
const gd::String& type_,
|
||||
const gd::String& prefix_,
|
||||
size_t replacementStartPosition_,
|
||||
size_t replacementEndPosition_,
|
||||
const gd::String& objectName_ = "") {
|
||||
return ExpressionCompletionDescription(Variable,
|
||||
type_,
|
||||
prefix_,
|
||||
replacementStartPosition_,
|
||||
replacementEndPosition_,
|
||||
objectName_);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Create a completion for a text with the given prefix
|
||||
*/
|
||||
static ExpressionCompletionDescription ForText(
|
||||
const gd::String& type_,
|
||||
const gd::ParameterMetadata& parameterMetadata_,
|
||||
const gd::String& prefix_,
|
||||
size_t replacementStartPosition_,
|
||||
size_t replacementEndPosition_,
|
||||
const bool isLastParameter_,
|
||||
const gd::String& objectName_ = "") {
|
||||
auto description =
|
||||
ExpressionCompletionDescription(Text,
|
||||
type_,
|
||||
prefix_,
|
||||
replacementStartPosition_,
|
||||
replacementEndPosition_,
|
||||
objectName_);
|
||||
description.SetIsLastParameter(isLastParameter_);
|
||||
description.SetParameterMetadata(parameterMetadata_);
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Create a completion for an expression (free, object or behavior
|
||||
* expression) with the given prefix
|
||||
@@ -71,10 +118,17 @@ struct ExpressionCompletionDescription {
|
||||
static ExpressionCompletionDescription ForExpression(
|
||||
const gd::String& type_,
|
||||
const gd::String& prefix_,
|
||||
size_t replacementStartPosition_,
|
||||
size_t replacementEndPosition_,
|
||||
const gd::String& objectName_ = "",
|
||||
const gd::String& behaviorName_ = "") {
|
||||
return ExpressionCompletionDescription(
|
||||
Expression, type_, prefix_, objectName_, behaviorName_);
|
||||
return ExpressionCompletionDescription(Expression,
|
||||
type_,
|
||||
prefix_,
|
||||
replacementStartPosition_,
|
||||
replacementEndPosition_,
|
||||
objectName_,
|
||||
behaviorName_);
|
||||
}
|
||||
|
||||
/** Check if two description of completions are equal */
|
||||
@@ -131,6 +185,56 @@ struct ExpressionCompletionDescription {
|
||||
*/
|
||||
bool IsExact() const { return isExact; }
|
||||
|
||||
/**
|
||||
* \brief Return the first character index of the autocompleted part.
|
||||
*/
|
||||
size_t GetReplacementStartPosition() const {
|
||||
return replacementStartPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the first character index after the autocompleted part.
|
||||
*/
|
||||
size_t GetReplacementEndPosition() const { return replacementEndPosition; }
|
||||
|
||||
/**
|
||||
* \brief Set if the expression is the last child of a function call.
|
||||
*/
|
||||
ExpressionCompletionDescription& SetIsLastParameter(bool isLastParameter_) {
|
||||
isLastParameter = isLastParameter_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if the expression is the last child of a function call.
|
||||
*/
|
||||
bool IsLastParameter() const { return isLastParameter; }
|
||||
|
||||
/**
|
||||
* \brief Set the parameter metadata, in the case the completion is about
|
||||
* a parameter of a function call.
|
||||
*/
|
||||
ExpressionCompletionDescription& SetParameterMetadata(
|
||||
const gd::ParameterMetadata& parameterMetadata_) {
|
||||
parameterMetadata = ¶meterMetadata_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if the completion is about a parameter of a function call.
|
||||
*/
|
||||
bool HasParameterMetadata() const {
|
||||
return parameterMetadata != &badParameterMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the parameter metadata, if the completion is about a
|
||||
* parameter of a function call. Returns an empty metadata otherwise.
|
||||
*/
|
||||
const gd::ParameterMetadata& GetParameterMetadata() const {
|
||||
return *parameterMetadata;
|
||||
}
|
||||
|
||||
/** Default constructor, only to be used by Emscripten bindings. */
|
||||
ExpressionCompletionDescription() : completionKind(Object){};
|
||||
|
||||
@@ -138,34 +242,40 @@ struct ExpressionCompletionDescription {
|
||||
ExpressionCompletionDescription(CompletionKind completionKind_,
|
||||
const gd::String& type_,
|
||||
const gd::String& prefix_,
|
||||
size_t replacementStartPosition_,
|
||||
size_t replacementEndPosition_,
|
||||
const gd::String& objectName_ = "",
|
||||
const gd::String& behaviorName_ = "")
|
||||
: completionKind(completionKind_),
|
||||
type(type_),
|
||||
prefix(prefix_),
|
||||
replacementStartPosition(replacementStartPosition_),
|
||||
replacementEndPosition(replacementEndPosition_),
|
||||
objectName(objectName_),
|
||||
behaviorName(behaviorName_),
|
||||
isExact(false) {}
|
||||
isExact(false),
|
||||
isLastParameter(false),
|
||||
parameterMetadata(&badParameterMetadata) {}
|
||||
|
||||
CompletionKind completionKind;
|
||||
gd::String type;
|
||||
gd::String prefix;
|
||||
size_t replacementStartPosition;
|
||||
size_t replacementEndPosition;
|
||||
gd::String objectName;
|
||||
gd::String behaviorName;
|
||||
bool isExact;
|
||||
bool isLastParameter;
|
||||
const gd::ParameterMetadata* parameterMetadata;
|
||||
|
||||
static const gd::ParameterMetadata badParameterMetadata;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Turn an ExpressionCompletionDescription to a string.
|
||||
*/
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
ExpressionCompletionDescription const& value) {
|
||||
os << "{ " << value.GetCompletionKind() << ", " << value.GetType() << ", "
|
||||
<< value.GetPrefix() << ", " << value.GetObjectName() << ", "
|
||||
<< value.GetBehaviorName() << ", "
|
||||
<< (value.IsExact() ? "exact" : "non-exact") << " }";
|
||||
return os;
|
||||
}
|
||||
ExpressionCompletionDescription const& value);
|
||||
|
||||
/**
|
||||
* \brief Returns the list of completion descriptions for an expression node.
|
||||
@@ -182,16 +292,18 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
static std::vector<ExpressionCompletionDescription>
|
||||
GetCompletionDescriptionsFor(gd::ExpressionNode& node,
|
||||
size_t searchedPosition) {
|
||||
gd::ExpressionNode* nodeAtLocation =
|
||||
gd::ExpressionNodeLocationFinder::GetNodeAtPosition(node,
|
||||
searchedPosition);
|
||||
gd::ExpressionNodeLocationFinder finder(searchedPosition);
|
||||
node.Visit(finder);
|
||||
gd::ExpressionNode* nodeAtLocation = finder.GetNode();
|
||||
|
||||
if (nodeAtLocation == nullptr) {
|
||||
std::vector<ExpressionCompletionDescription> emptyCompletions;
|
||||
return emptyCompletions;
|
||||
}
|
||||
|
||||
gd::ExpressionCompletionFinder autocompletionProvider(searchedPosition);
|
||||
gd::ExpressionNode* maybeParentNodeAtLocation = finder.GetParentNode();
|
||||
gd::ExpressionCompletionFinder autocompletionProvider(
|
||||
searchedPosition, maybeParentNodeAtLocation);
|
||||
nodeAtLocation->Visit(autocompletionProvider);
|
||||
return autocompletionProvider.GetCompletionDescriptions();
|
||||
}
|
||||
@@ -208,32 +320,92 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForObject(node.type, ""));
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpression(node.type, ""));
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForObject(node.type, ""));
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpression(node.type, ""));
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForObject(node.type, ""));
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpression(node.type, ""));
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode& node) override {
|
||||
// No completions
|
||||
}
|
||||
|
||||
void OnVisitTextNode(TextNode& node) override {
|
||||
// No completions
|
||||
// Completions are searched in the case the text node is a parameter of a
|
||||
// function call.
|
||||
FunctionCallNode* functionCall =
|
||||
dynamic_cast<FunctionCallNode*>(maybeParentNodeAtLocation);
|
||||
if (functionCall != nullptr) {
|
||||
int parameterIndex = -1;
|
||||
for (int i = 0; i < functionCall->parameters.size(); i++) {
|
||||
if (functionCall->parameters.at(i).get() == &node) {
|
||||
parameterIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parameterIndex < 0) {
|
||||
return;
|
||||
}
|
||||
// Search the parameter metadata index skipping invisible ones.
|
||||
size_t visibleParameterIndex = 0;
|
||||
size_t metadataParameterIndex = ExpressionParser2::WrittenParametersFirstIndex(
|
||||
functionCall->objectName, functionCall->behaviorName);
|
||||
|
||||
const gd::ParameterMetadata* parameterMetadata = nullptr;
|
||||
while (metadataParameterIndex <
|
||||
functionCall->expressionMetadata.parameters.size()) {
|
||||
if (!functionCall->expressionMetadata.parameters[metadataParameterIndex]
|
||||
.IsCodeOnly()) {
|
||||
if (visibleParameterIndex == parameterIndex) {
|
||||
parameterMetadata = &functionCall->expressionMetadata
|
||||
.parameters[metadataParameterIndex];
|
||||
}
|
||||
visibleParameterIndex++;
|
||||
}
|
||||
metadataParameterIndex++;
|
||||
}
|
||||
const int visibleParameterCount = visibleParameterIndex;
|
||||
if (parameterMetadata == nullptr) {
|
||||
// There are too many parameters in the expression, this text node is
|
||||
// not actually linked to a parameter expected by the function call.
|
||||
return;
|
||||
}
|
||||
|
||||
const gd::String& type = parameterMetadata->GetType();
|
||||
if (type == "string") {
|
||||
// No completions for an arbitrary string.
|
||||
return;
|
||||
}
|
||||
|
||||
bool isLastParameter = parameterIndex == visibleParameterCount - 1;
|
||||
completions.push_back(ExpressionCompletionDescription::ForText(
|
||||
type,
|
||||
*parameterMetadata,
|
||||
node.text,
|
||||
node.location.GetStartPosition(),
|
||||
node.location.GetEndPosition(),
|
||||
isLastParameter,
|
||||
functionCall->objectName));
|
||||
}
|
||||
}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForVariable(node.type, node.name));
|
||||
completions.push_back(ExpressionCompletionDescription::ForVariable(
|
||||
node.type,
|
||||
node.name,
|
||||
node.location.GetStartPosition(),
|
||||
node.location.GetEndPosition(),
|
||||
node.objectName));
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
// No completions
|
||||
@@ -246,13 +418,22 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
if (gd::ParameterMetadata::IsObject(node.type)) {
|
||||
// Only show completions of objects if an object is required
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, node.identifierName));
|
||||
node.type,
|
||||
node.identifierName,
|
||||
node.location.GetStartPosition(),
|
||||
node.location.GetEndPosition()));
|
||||
} else {
|
||||
// Show completions for expressions and objects otherwise.
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, node.identifierName));
|
||||
node.type,
|
||||
node.identifierName,
|
||||
node.location.GetStartPosition(),
|
||||
node.location.GetEndPosition()));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type, node.identifierName));
|
||||
node.type,
|
||||
node.identifierName,
|
||||
node.location.GetStartPosition(),
|
||||
node.location.GetEndPosition()));
|
||||
}
|
||||
}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
@@ -262,16 +443,24 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
// function name missing)
|
||||
if (IsCaretOn(node.objectNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, node.objectName));
|
||||
node.type,
|
||||
node.objectName,
|
||||
node.objectNameLocation.GetStartPosition(),
|
||||
node.objectNameLocation.GetEndPosition()));
|
||||
} else if (IsCaretOn(node.objectNameDotLocation) ||
|
||||
IsCaretOn(node.objectFunctionOrBehaviorNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForBehavior(
|
||||
node.objectFunctionOrBehaviorName, node.objectName));
|
||||
node.objectFunctionOrBehaviorName,
|
||||
node.objectFunctionOrBehaviorNameLocation.GetStartPosition(),
|
||||
node.objectFunctionOrBehaviorNameLocation.GetEndPosition(),
|
||||
node.objectName));
|
||||
} else if (IsCaretOn(node.behaviorNameNamespaceSeparatorLocation) ||
|
||||
IsCaretOn(node.behaviorFunctionNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type,
|
||||
node.behaviorFunctionName,
|
||||
node.behaviorFunctionNameLocation.GetStartPosition(),
|
||||
node.behaviorFunctionNameLocation.GetEndPosition(),
|
||||
node.objectName,
|
||||
node.objectFunctionOrBehaviorName));
|
||||
}
|
||||
@@ -279,13 +468,23 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
// Object function or behavior name
|
||||
if (IsCaretOn(node.objectNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, node.objectName));
|
||||
node.type,
|
||||
node.objectName,
|
||||
node.objectNameLocation.GetStartPosition(),
|
||||
node.objectNameLocation.GetEndPosition()));
|
||||
} else if (IsCaretOn(node.objectNameDotLocation) ||
|
||||
IsCaretOn(node.objectFunctionOrBehaviorNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForBehavior(
|
||||
node.objectFunctionOrBehaviorName, node.objectName));
|
||||
node.objectFunctionOrBehaviorName,
|
||||
node.objectFunctionOrBehaviorNameLocation.GetStartPosition(),
|
||||
node.objectFunctionOrBehaviorNameLocation.GetEndPosition(),
|
||||
node.objectName));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type, node.objectFunctionOrBehaviorName, node.objectName));
|
||||
node.type,
|
||||
node.objectFunctionOrBehaviorName,
|
||||
node.objectFunctionOrBehaviorNameLocation.GetStartPosition(),
|
||||
node.objectFunctionOrBehaviorNameLocation.GetEndPosition(),
|
||||
node.objectName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -297,24 +496,35 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
// Behavior function
|
||||
if (IsCaretOn(node.objectNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, node.objectName));
|
||||
node.type,
|
||||
node.objectName,
|
||||
node.objectNameLocation.GetStartPosition(),
|
||||
node.objectNameLocation.GetEndPosition()));
|
||||
} else if (IsCaretOn(node.objectNameDotLocation) ||
|
||||
IsCaretOn(node.behaviorNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForBehavior(
|
||||
node.behaviorName, node.objectName));
|
||||
node.behaviorName,
|
||||
node.behaviorNameLocation.GetStartPosition(),
|
||||
node.behaviorNameLocation.GetEndPosition(),
|
||||
node.objectName));
|
||||
} else {
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpression(node.type,
|
||||
node.functionName,
|
||||
node.objectName,
|
||||
node.behaviorName)
|
||||
.SetIsExact(isCaretOnParenthesis));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type,
|
||||
node.functionName,
|
||||
node.functionNameLocation.GetStartPosition(),
|
||||
node.functionNameLocation.GetEndPosition(),
|
||||
node.objectName,
|
||||
node.behaviorName)
|
||||
.SetIsExact(isCaretOnParenthesis));
|
||||
}
|
||||
} else if (!node.objectName.empty()) {
|
||||
// Object function
|
||||
if (IsCaretOn(node.objectNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, node.objectName));
|
||||
node.type,
|
||||
node.objectName,
|
||||
node.objectNameLocation.GetStartPosition(),
|
||||
node.objectNameLocation.GetEndPosition()));
|
||||
} else {
|
||||
// Add completions for behaviors, because we could imagine that the user
|
||||
// wants to move from an object function to a behavior function, and so
|
||||
@@ -323,25 +533,41 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
// function).
|
||||
if (!isCaretOnParenthesis) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForBehavior(
|
||||
node.functionName, node.objectName));
|
||||
node.functionName,
|
||||
node.objectNameLocation.GetStartPosition(),
|
||||
node.objectNameLocation.GetEndPosition(),
|
||||
node.objectName));
|
||||
}
|
||||
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type, node.functionName, node.objectName)
|
||||
node.type,
|
||||
node.functionName,
|
||||
node.functionNameLocation.GetStartPosition(),
|
||||
node.functionNameLocation.GetEndPosition(),
|
||||
node.objectName)
|
||||
.SetIsExact(isCaretOnParenthesis));
|
||||
}
|
||||
} else {
|
||||
// Free function
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type, node.functionName)
|
||||
node.type,
|
||||
node.functionName,
|
||||
node.functionNameLocation.GetStartPosition(),
|
||||
node.functionNameLocation.GetEndPosition())
|
||||
.SetIsExact(isCaretOnParenthesis));
|
||||
}
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForObject(node.type, node.text));
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpression(node.type, node.text));
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type,
|
||||
node.text,
|
||||
node.location.GetStartPosition(),
|
||||
node.location.GetEndPosition()));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type,
|
||||
node.text,
|
||||
node.location.GetStartPosition(),
|
||||
node.location.GetEndPosition()));
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -354,11 +580,14 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
(inclusive && searchedPosition <= location.GetEndPosition())));
|
||||
}
|
||||
|
||||
ExpressionCompletionFinder(size_t searchedPosition_)
|
||||
: searchedPosition(searchedPosition_){};
|
||||
ExpressionCompletionFinder(size_t searchedPosition_,
|
||||
gd::ExpressionNode* maybeParentNodeAtLocation_)
|
||||
: searchedPosition(searchedPosition_),
|
||||
maybeParentNodeAtLocation(maybeParentNodeAtLocation_){};
|
||||
|
||||
std::vector<ExpressionCompletionDescription> completions;
|
||||
size_t searchedPosition;
|
||||
gd::ExpressionNode* maybeParentNodeAtLocation;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
namespace gd {
|
||||
@@ -46,11 +47,30 @@ class GD_CORE_API ExpressionNodeLocationFinder
|
||||
return finder.GetNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Helper function to find the parent of the deepest node at the search
|
||||
* position, if any.
|
||||
*
|
||||
* \warning Useful for tests. In other cases, prefer using `GetParentNode`.
|
||||
*/
|
||||
static ExpressionNode* GetParentNodeAtPosition(gd::ExpressionNode& node,
|
||||
size_t searchedPosition) {
|
||||
gd::ExpressionNodeLocationFinder finder(searchedPosition);
|
||||
node.Visit(finder);
|
||||
return finder.GetParentNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the deepest node found at the search position, if any.
|
||||
*/
|
||||
ExpressionNode* GetNode() { return foundNode; };
|
||||
|
||||
/**
|
||||
* \brief Return the parent of deepest node found at the search position, if
|
||||
* any.
|
||||
*/
|
||||
ExpressionNode* GetParentNode() { return parentNode; };
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
|
||||
CheckSearchPositionInNode(node);
|
||||
@@ -110,6 +130,7 @@ class GD_CORE_API ExpressionNodeLocationFinder
|
||||
if (node.location.GetStartPosition() <= searchedPosition &&
|
||||
((!inclusive && searchedPosition < node.location.GetEndPosition()) ||
|
||||
(inclusive && searchedPosition <= node.location.GetEndPosition()))) {
|
||||
parentNode = foundNode;
|
||||
foundNode = &node;
|
||||
return true;
|
||||
}
|
||||
@@ -119,6 +140,7 @@ class GD_CORE_API ExpressionNodeLocationFinder
|
||||
|
||||
size_t searchedPosition;
|
||||
ExpressionNode* foundNode;
|
||||
ExpressionNode* parentNode;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -24,24 +24,6 @@ namespace gd {
|
||||
|
||||
InstructionSentenceFormatter *InstructionSentenceFormatter::_singleton = NULL;
|
||||
|
||||
gd::String InstructionSentenceFormatter::Translate(
|
||||
const gd::Instruction &instr, const gd::InstructionMetadata &metadata) {
|
||||
gd::String out = metadata.GetSentence();
|
||||
if (out.empty())
|
||||
out = " "; // Prevent empty sentences that could trigger graphical
|
||||
// glitches.
|
||||
|
||||
// Replace _PARAMx_ placeholders by their values
|
||||
for (std::size_t i = 0; i < metadata.parameters.size(); ++i) {
|
||||
gd::String placeholder = "_PARAM" + gd::String::From(i) + "_";
|
||||
gd::String parameter = instr.GetParameter(i).GetPlainString();
|
||||
out = out.FindAndReplace(placeholder, parameter);
|
||||
}
|
||||
|
||||
out = out.FindAndReplace("\n", " ");
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::pair<gd::String, gd::TextFormatting> >
|
||||
InstructionSentenceFormatter::GetAsFormattedText(
|
||||
const Instruction &instr, const gd::InstructionMetadata &metadata) {
|
||||
@@ -83,8 +65,7 @@ InstructionSentenceFormatter::GetAsFormattedText(
|
||||
}
|
||||
|
||||
// Add the parameter
|
||||
TextFormatting format =
|
||||
GetFormattingFromType(metadata.parameters[firstParamIndex].type);
|
||||
TextFormatting format;
|
||||
format.userData = firstParamIndex;
|
||||
|
||||
gd::String text = instr.GetParameter(firstParamIndex).GetPlainString();
|
||||
@@ -109,74 +90,6 @@ InstructionSentenceFormatter::GetAsFormattedText(
|
||||
return formattedStr;
|
||||
}
|
||||
|
||||
TextFormatting InstructionSentenceFormatter::GetFormattingFromType(
|
||||
const gd::String &type) {
|
||||
if (gd::ParameterMetadata::IsObject(type)) return typesFormatting["object"];
|
||||
|
||||
return typesFormatting[type];
|
||||
}
|
||||
|
||||
gd::String InstructionSentenceFormatter::LabelFromType(const gd::String &type) {
|
||||
if (type.empty())
|
||||
return "";
|
||||
else if (type == "expression")
|
||||
return _("Expression");
|
||||
else if (gd::ParameterMetadata::IsObject(type))
|
||||
return _("Object");
|
||||
else if (type == "behavior")
|
||||
return _("Behavior");
|
||||
else if (type == "operator")
|
||||
return _("Operator");
|
||||
else if (type == "relationalOperator")
|
||||
return _("Relational operator");
|
||||
else if (type == "file")
|
||||
return _("File");
|
||||
else if (type == "key")
|
||||
return _("Key");
|
||||
else if (type == "mouse")
|
||||
return _("Mouse button");
|
||||
else if (type == "yesorno")
|
||||
return _("Yes or No");
|
||||
else if (type == "police")
|
||||
return _("Font");
|
||||
else if (type == "color")
|
||||
return _("Color");
|
||||
else if (type == "trueorfalse")
|
||||
return _("True or False");
|
||||
else if (type == "string")
|
||||
return _("String");
|
||||
else if (type == "musicfile")
|
||||
return _("Music");
|
||||
else if (type == "soundfile")
|
||||
return _("Sound");
|
||||
else if (type == "password")
|
||||
return _("Password");
|
||||
else if (type == "layer")
|
||||
return _("Layer");
|
||||
else if (type == "joyaxis")
|
||||
return _("Joystick axis");
|
||||
else if (type == "objectvar")
|
||||
return _("Variable of the object");
|
||||
else if (type == "scenevar")
|
||||
return _("Scene variable");
|
||||
else if (type == "globalvar")
|
||||
return _("Global variable");
|
||||
|
||||
return _("Unknown");
|
||||
}
|
||||
|
||||
void InstructionSentenceFormatter::LoadTypesFormattingFromConfig() {
|
||||
// Load default configuration
|
||||
typesFormatting.clear();
|
||||
typesFormatting["expression"].SetColor(27, 143, 1).SetBold();
|
||||
typesFormatting["object"].SetColor(182, 97, 10).SetBold();
|
||||
typesFormatting["behavior"].SetColor(119, 119, 119).SetBold();
|
||||
typesFormatting["operator"].SetColor(55, 131, 211).SetBold();
|
||||
typesFormatting["objectvar"].SetColor(131, 55, 162).SetBold();
|
||||
typesFormatting["scenevar"].SetColor(131, 55, 162).SetBold();
|
||||
typesFormatting["globalvar"].SetColor(131, 55, 162).SetBold();
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif
|
||||
|
@@ -25,39 +25,12 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API InstructionSentenceFormatter {
|
||||
public:
|
||||
/**
|
||||
* \brief Create a sentence from an instruction and its metadata.
|
||||
*
|
||||
* Sentence is provided in the gd::InstructionMetadata passed as parameter.
|
||||
* Parameters placeholders ("_PARAMx_", x being the parameter index) are
|
||||
* replaced by their values stored in the isntruction passed as parameter.
|
||||
*/
|
||||
gd::String Translate(const gd::Instruction &instr,
|
||||
const gd::InstructionMetadata &metadata);
|
||||
|
||||
/**
|
||||
* \brief Create a formatted sentence from an instruction and its metadata.
|
||||
*/
|
||||
std::vector<std::pair<gd::String, gd::TextFormatting> > GetAsFormattedText(
|
||||
const gd::Instruction &instr, const gd::InstructionMetadata &metadata);
|
||||
|
||||
/**
|
||||
* \brief Return the TextFormatting object associated to the \a type.
|
||||
*/
|
||||
TextFormatting GetFormattingFromType(const gd::String &type);
|
||||
|
||||
/**
|
||||
* \brief Return the label of a parameter type
|
||||
*/
|
||||
gd::String LabelFromType(const gd::String &type);
|
||||
|
||||
/**
|
||||
* \brief Load the configuration from the default configuration.
|
||||
*/
|
||||
void LoadTypesFormattingFromConfig();
|
||||
|
||||
std::map<gd::String, gd::TextFormatting> typesFormatting;
|
||||
|
||||
static InstructionSentenceFormatter *Get() {
|
||||
if (NULL == _singleton) {
|
||||
_singleton = new InstructionSentenceFormatter;
|
||||
|
@@ -13,85 +13,20 @@ namespace gd {
|
||||
/**
|
||||
* \brief Represents the style of a text displayed in the events editor.
|
||||
*
|
||||
* Notably used by EventsRenderingHelper to render Instruction.
|
||||
*
|
||||
* \see EventsRenderingHelper
|
||||
* \ingroup IDEDialogsEventsEditor
|
||||
*/
|
||||
class GD_CORE_API TextFormatting {
|
||||
public:
|
||||
TextFormatting()
|
||||
: colorRed(0),
|
||||
colorGreen(0),
|
||||
colorBlue(0),
|
||||
bold(false),
|
||||
italic(false),
|
||||
userData(gd::String::npos) {}
|
||||
TextFormatting() : userData(gd::String::npos) {}
|
||||
~TextFormatting() {}
|
||||
|
||||
/**
|
||||
* \brief Return true if the bold style must be applied.
|
||||
*/
|
||||
bool IsBold() const { return bold; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the italic style must be applied.
|
||||
*/
|
||||
bool IsItalic() const { return italic; }
|
||||
|
||||
/**
|
||||
* \brief Return the red component of the color that must be applied to the
|
||||
* text.
|
||||
*/
|
||||
unsigned int GetColorRed() const { return colorRed; }
|
||||
/**
|
||||
* \brief Return the green component of the color that must be applied to the
|
||||
* text.
|
||||
*/
|
||||
unsigned int GetColorGreen() const { return colorGreen; }
|
||||
/**
|
||||
* \brief Return the blue component of the color that must be applied to the
|
||||
* text.
|
||||
*/
|
||||
unsigned int GetColorBlue() const { return colorBlue; }
|
||||
|
||||
/**
|
||||
* Change the color of the text.
|
||||
*/
|
||||
TextFormatting& SetColor(unsigned int r, unsigned int g, unsigned int b) {
|
||||
colorRed = r;
|
||||
colorGreen = g;
|
||||
colorBlue = b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set if the bold style must be applied.
|
||||
*/
|
||||
TextFormatting& SetBold(bool enable = true) {
|
||||
bold = enable;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set if the italic style must be applied.
|
||||
*/
|
||||
TextFormatting& SetItalic(bool enable = true) {
|
||||
italic = enable;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the data (an integer) associated with the text formatting.
|
||||
* Used to store the parameter when rendering instructions.
|
||||
*/
|
||||
size_t GetUserData() const { return userData; }
|
||||
|
||||
unsigned int colorRed;
|
||||
unsigned int colorGreen;
|
||||
unsigned int colorBlue;
|
||||
bool bold;
|
||||
bool italic;
|
||||
size_t userData;
|
||||
};
|
||||
|
||||
|
@@ -14,16 +14,16 @@ namespace gd {
|
||||
* \note Both objects must be kept alive, as this is keeping a pointer to them.
|
||||
*/
|
||||
struct DependencyMetadataAndExtension {
|
||||
DependencyMetadataAndExtension(gd::DependencyMetadata& dependency_,
|
||||
gd::PlatformExtension& extension_)
|
||||
DependencyMetadataAndExtension(gd::DependencyMetadata &dependency_,
|
||||
gd::PlatformExtension &extension_)
|
||||
: dependency(&dependency_), extension(&extension_){};
|
||||
|
||||
gd::DependencyMetadata& GetDependency() const { return *dependency; };
|
||||
gd::PlatformExtension& GetExtension() const { return *extension; };
|
||||
gd::DependencyMetadata &GetDependency() const { return *dependency; };
|
||||
gd::PlatformExtension &GetExtension() const { return *extension; };
|
||||
|
||||
private:
|
||||
gd::DependencyMetadata* dependency;
|
||||
gd::PlatformExtension* extension;
|
||||
gd::DependencyMetadata *dependency;
|
||||
gd::PlatformExtension *extension;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -33,8 +33,8 @@ struct DependencyMetadataAndExtension {
|
||||
class ExportedDependencyResolver {
|
||||
public:
|
||||
/**
|
||||
* \brief Return the list of dependencies to be exported for the given project
|
||||
* and dependency type.
|
||||
* \brief Return the list of dependencies to be exported for the given
|
||||
* project, used extensions list and dependency type.
|
||||
*
|
||||
* Not all dependencies declared by extensions must be exported: some are only
|
||||
* exported when some settings are filled. Then, some others are only exported
|
||||
@@ -42,11 +42,13 @@ class ExportedDependencyResolver {
|
||||
* one level though).
|
||||
*/
|
||||
static std::vector<DependencyMetadataAndExtension> GetDependenciesFor(
|
||||
const gd::Project& project, const gd::String& dependencyType) {
|
||||
const gd::Project &project,
|
||||
std::set<gd::String> usedExtensions,
|
||||
const gd::String &dependencyType) {
|
||||
std::vector<DependencyMetadataAndExtension> dependenciesWithProperType;
|
||||
for (std::shared_ptr<gd::PlatformExtension> extension :
|
||||
project.GetCurrentPlatform().GetAllPlatformExtensions()) {
|
||||
for (gd::DependencyMetadata& dependency :
|
||||
for (const gd::String &extensionName : usedExtensions) {
|
||||
auto extension = project.GetCurrentPlatform().GetExtension(extensionName);
|
||||
for (gd::DependencyMetadata &dependency :
|
||||
extension->GetAllDependencies()) {
|
||||
if (dependency.GetDependencyType() == dependencyType) {
|
||||
DependencyMetadataAndExtension dependencyMetadataAndExtension(
|
||||
@@ -60,7 +62,7 @@ class ExportedDependencyResolver {
|
||||
// and those that don't require extra settings to be filled.
|
||||
std::vector<DependencyMetadataAndExtension> dependenciesWithFilledSettings;
|
||||
for (auto dependencyAndExtension : dependenciesWithProperType) {
|
||||
auto& dependency = dependencyAndExtension.GetDependency();
|
||||
auto &dependency = dependencyAndExtension.GetDependency();
|
||||
auto extraSettingValues = GetExtensionDependencyExtraSettingValues(
|
||||
project, dependencyAndExtension);
|
||||
|
||||
@@ -73,15 +75,15 @@ class ExportedDependencyResolver {
|
||||
// exported (or dependencies that don't require another dependency).
|
||||
std::vector<DependencyMetadataAndExtension> exportedDependencies;
|
||||
for (auto dependencyAndExtension : dependenciesWithFilledSettings) {
|
||||
auto& dependency = dependencyAndExtension.GetDependency();
|
||||
auto& otherDependencyName =
|
||||
auto &dependency = dependencyAndExtension.GetDependency();
|
||||
auto &otherDependencyName =
|
||||
dependency.GetOtherDependencyThatMustBeExported();
|
||||
if (otherDependencyName.empty() ||
|
||||
std::find_if(
|
||||
dependenciesWithFilledSettings.begin(),
|
||||
dependenciesWithFilledSettings.end(),
|
||||
[&otherDependencyName](
|
||||
DependencyMetadataAndExtension& otherDependencyAndExtension) {
|
||||
DependencyMetadataAndExtension &otherDependencyAndExtension) {
|
||||
return otherDependencyAndExtension.GetDependency().GetName() ==
|
||||
otherDependencyName;
|
||||
}) != dependenciesWithFilledSettings.end()) {
|
||||
@@ -98,15 +100,15 @@ class ExportedDependencyResolver {
|
||||
*/
|
||||
static std::map<gd::String, gd::String>
|
||||
GetExtensionDependencyExtraSettingValues(
|
||||
const gd::Project& project,
|
||||
const gd::DependencyMetadataAndExtension& dependencyAndExtension) {
|
||||
const gd::Project &project,
|
||||
const gd::DependencyMetadataAndExtension &dependencyAndExtension) {
|
||||
std::map<gd::String, gd::String> values;
|
||||
auto& dependency = dependencyAndExtension.GetDependency();
|
||||
const gd::String& extensionName =
|
||||
auto &dependency = dependencyAndExtension.GetDependency();
|
||||
const gd::String &extensionName =
|
||||
dependencyAndExtension.GetExtension().GetName();
|
||||
|
||||
for (const auto& extraSetting : dependency.GetAllExtraSettings()) {
|
||||
const gd::String& type = extraSetting.second.GetType();
|
||||
for (const auto &extraSetting : dependency.GetAllExtraSettings()) {
|
||||
const gd::String &type = extraSetting.second.GetType();
|
||||
const gd::String extraSettingValue =
|
||||
type == "ExtensionProperty"
|
||||
? project.GetExtensionProperties().GetValue(
|
||||
|
@@ -9,7 +9,6 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void Effect::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", GetName());
|
||||
element.SetAttribute("effectType", GetEffectType());
|
||||
@@ -32,7 +31,6 @@ void Effect::SerializeTo(SerializerElement& element) const {
|
||||
booleanParametersElement.AddChild(parameter.first)
|
||||
.SetValue(parameter.second);
|
||||
}
|
||||
#endif
|
||||
|
||||
void Effect::UnserializeFrom(const SerializerElement& element) {
|
||||
SetName(element.GetStringAttribute("name"));
|
||||
|
@@ -74,12 +74,10 @@ class GD_CORE_API Effect {
|
||||
booleanParameters.clear();
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Serialize layer.
|
||||
*/
|
||||
void SerializeTo(SerializerElement& element) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Unserialize the layer.
|
||||
|
140
Core/GDCore/Project/EffectsContainer.cpp
Normal file
140
Core/GDCore/Project/EffectsContainer.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "EffectsContainer.h"
|
||||
|
||||
#include "Effect.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
namespace gd {
|
||||
Effect EffectsContainer::badEffect;
|
||||
|
||||
EffectsContainer::EffectsContainer() {}
|
||||
|
||||
EffectsContainer::EffectsContainer(const EffectsContainer& other) {
|
||||
Init(other);
|
||||
}
|
||||
|
||||
EffectsContainer& EffectsContainer::operator=(const EffectsContainer& rhs) {
|
||||
if (this != &rhs) Init(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void EffectsContainer::Init(const EffectsContainer& other) {
|
||||
effects.clear();
|
||||
for (auto& it : other.effects) {
|
||||
effects.push_back(std::make_shared<Effect>(*it));
|
||||
}
|
||||
}
|
||||
|
||||
bool EffectsContainer::HasEffectNamed(const gd::String& name) const {
|
||||
return (find_if(effects.begin(),
|
||||
effects.end(),
|
||||
[&name](const std::shared_ptr<gd::Effect>& effect) {
|
||||
return effect->GetName() == name;
|
||||
}) != effects.end());
|
||||
}
|
||||
|
||||
gd::Effect& EffectsContainer::GetEffect(const gd::String& name) {
|
||||
auto effect = find_if(effects.begin(),
|
||||
effects.end(),
|
||||
[&name](std::shared_ptr<gd::Effect>& effect) {
|
||||
return effect->GetName() == name;
|
||||
});
|
||||
|
||||
if (effect != effects.end()) return **effect;
|
||||
|
||||
return badEffect;
|
||||
}
|
||||
|
||||
const gd::Effect& EffectsContainer::GetEffect(const gd::String& name) const {
|
||||
auto effect = find_if(effects.begin(),
|
||||
effects.end(),
|
||||
[&name](const std::shared_ptr<gd::Effect>& effect) {
|
||||
return effect->GetName() == name;
|
||||
});
|
||||
|
||||
if (effect != effects.end()) return **effect;
|
||||
|
||||
return badEffect;
|
||||
}
|
||||
gd::Effect& EffectsContainer::GetEffect(std::size_t index) {
|
||||
return *effects[index];
|
||||
}
|
||||
const gd::Effect& EffectsContainer::GetEffect(std::size_t index) const {
|
||||
return *effects[index];
|
||||
}
|
||||
std::size_t EffectsContainer::GetEffectsCount() const { return effects.size(); }
|
||||
std::size_t EffectsContainer::GetEffectPosition(const gd::String& name) const {
|
||||
for (std::size_t i = 0; i < effects.size(); ++i) {
|
||||
if (effects[i]->GetName() == name) return i;
|
||||
}
|
||||
return gd::String::npos;
|
||||
}
|
||||
|
||||
gd::Effect& EffectsContainer::InsertNewEffect(const gd::String& name,
|
||||
std::size_t position) {
|
||||
auto newEffect = std::make_shared<Effect>();
|
||||
newEffect->SetName(name);
|
||||
|
||||
if (position < effects.size())
|
||||
effects.insert(effects.begin() + position, newEffect);
|
||||
else
|
||||
effects.push_back(newEffect);
|
||||
|
||||
return *newEffect;
|
||||
}
|
||||
|
||||
void EffectsContainer::InsertEffect(const gd::Effect& effect,
|
||||
std::size_t position) {
|
||||
auto newEffect = std::make_shared<gd::Effect>(effect);
|
||||
if (position < effects.size())
|
||||
effects.insert(effects.begin() + position, newEffect);
|
||||
else
|
||||
effects.push_back(newEffect);
|
||||
}
|
||||
|
||||
void EffectsContainer::RemoveEffect(const gd::String& name) {
|
||||
auto effect = find_if(effects.begin(),
|
||||
effects.end(),
|
||||
[&name](const std::shared_ptr<gd::Effect>& effect) {
|
||||
return effect->GetName() == name;
|
||||
});
|
||||
if (effect == effects.end()) return;
|
||||
|
||||
effects.erase(effect);
|
||||
}
|
||||
|
||||
void EffectsContainer::SwapEffects(std::size_t firstEffectIndex,
|
||||
std::size_t secondEffectIndex) {
|
||||
if (firstEffectIndex >= effects.size() || secondEffectIndex >= effects.size())
|
||||
return;
|
||||
|
||||
auto temp = effects[firstEffectIndex];
|
||||
effects[firstEffectIndex] = effects[secondEffectIndex];
|
||||
effects[secondEffectIndex] = temp;
|
||||
}
|
||||
|
||||
void EffectsContainer::SerializeTo(SerializerElement& element) const {
|
||||
element.ConsiderAsArrayOf("effect");
|
||||
for (std::size_t i = 0; i < GetEffectsCount(); ++i) {
|
||||
SerializerElement& effectElement = element.AddChild("effect");
|
||||
GetEffect(i).SerializeTo(effectElement);
|
||||
}
|
||||
}
|
||||
|
||||
void EffectsContainer::UnserializeFrom(const SerializerElement& element) {
|
||||
effects.clear();
|
||||
element.ConsiderAsArrayOf("effect");
|
||||
for (std::size_t i = 0; i < element.GetChildrenCount(); ++i) {
|
||||
const SerializerElement& effectElement = element.GetChild(i);
|
||||
|
||||
auto effect = std::make_shared<Effect>();
|
||||
effect->UnserializeFrom(effectElement);
|
||||
effects.push_back(effect);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
114
Core/GDCore/Project/EffectsContainer.h
Normal file
114
Core/GDCore/Project/EffectsContainer.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EFFECTS_CONTAINER_H
|
||||
#define GDCORE_EFFECTS_CONTAINER_H
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Effect;
|
||||
}
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Contains effects applied to an entity on screen (i.e: a Layer or an
|
||||
* Object).
|
||||
*
|
||||
* \ingroup PlatformDefinition
|
||||
*/
|
||||
class GD_CORE_API EffectsContainer {
|
||||
public:
|
||||
EffectsContainer();
|
||||
EffectsContainer(const EffectsContainer& other);
|
||||
virtual ~EffectsContainer(){};
|
||||
|
||||
EffectsContainer& operator=(const EffectsContainer& rhs);
|
||||
/**
|
||||
* \brief Return true if the effect called "name" exists.
|
||||
*/
|
||||
bool HasEffectNamed(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the effect called "name".
|
||||
*/
|
||||
Effect& GetEffect(const gd::String& name);
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the effect called "name".
|
||||
*/
|
||||
const Effect& GetEffect(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* Return a reference to the effect at position "index" in the effects list
|
||||
*/
|
||||
Effect& GetEffect(std::size_t index);
|
||||
|
||||
/**
|
||||
* Return a reference to the effect at position "index" in the effects list
|
||||
*/
|
||||
const Effect& GetEffect(std::size_t index) const;
|
||||
|
||||
/**
|
||||
* Return the position of the effect called "name" in the effects list
|
||||
*/
|
||||
std::size_t GetEffectPosition(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* Return the number of effecst.
|
||||
*/
|
||||
std::size_t GetEffectsCount() const;
|
||||
|
||||
/**
|
||||
* Add a new effect at the specified position in the effects list.
|
||||
*/
|
||||
gd::Effect& InsertNewEffect(const gd::String& name, std::size_t position);
|
||||
|
||||
/**
|
||||
* \brief Add a copy of the specified effect in the effects list.
|
||||
*
|
||||
* \note No pointer or reference must be kept on the effect passed as
|
||||
* parameter.
|
||||
*
|
||||
* \param theEffect The effect that must be copied and inserted
|
||||
* into the effects list
|
||||
* \param position Insertion position.
|
||||
*/
|
||||
void InsertEffect(const Effect& theEffect, std::size_t position);
|
||||
|
||||
/**
|
||||
* Remove the specified effect.
|
||||
*/
|
||||
void RemoveEffect(const gd::String& name);
|
||||
|
||||
/**
|
||||
* Swap the position of two effects.
|
||||
*/
|
||||
void SwapEffects(std::size_t firstEffectIndex, std::size_t secondEffectIndex);
|
||||
|
||||
/**
|
||||
* \brief Serialize the effects container.
|
||||
*/
|
||||
void SerializeTo(SerializerElement& element) const;
|
||||
|
||||
/**
|
||||
* \brief Unserialize the effects container.
|
||||
*/
|
||||
void UnserializeFrom(const SerializerElement& element);
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<gd::Effect>> effects;
|
||||
static Effect badEffect;
|
||||
void Init(const EffectsContainer& other);
|
||||
};
|
||||
} // namespace gd
|
||||
|
||||
#endif
|
@@ -4,6 +4,7 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Project/Layer.h"
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Project/Effect.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
@@ -11,9 +12,9 @@
|
||||
namespace gd {
|
||||
|
||||
Camera Layer::badCamera;
|
||||
Effect Layer::badEffect;
|
||||
|
||||
Layer::Layer() : isVisible(true), isLightingLayer(false), followBaseLayerCamera(false) {}
|
||||
Layer::Layer()
|
||||
: isVisible(true), isLightingLayer(false), followBaseLayerCamera(false) {}
|
||||
|
||||
/**
|
||||
* Change cameras count, automatically adding/removing them.
|
||||
@@ -52,11 +53,7 @@ void Layer::SerializeTo(SerializerElement& element) const {
|
||||
}
|
||||
|
||||
SerializerElement& effectsElement = element.AddChild("effects");
|
||||
effectsElement.ConsiderAsArrayOf("effect");
|
||||
for (std::size_t i = 0; i < GetEffectsCount(); ++i) {
|
||||
SerializerElement& effectElement = effectsElement.AddChild("effect");
|
||||
GetEffect(i).SerializeTo(effectElement);
|
||||
}
|
||||
effectsContainer.SerializeTo(effectsElement);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -67,155 +64,53 @@ 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),
|
||||
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")) {
|
||||
for (std::size_t i = 0; i < element.GetChildrenCount("Camera"); ++i) {
|
||||
const SerializerElement& cameraElement = element.GetChild("Camera", i);
|
||||
SetCameraCount(GetCameraCount() + 1);
|
||||
Camera& camera = GetCamera(GetCameraCount() - 1);
|
||||
cameras.clear();
|
||||
SerializerElement& camerasElement = element.GetChild("cameras");
|
||||
camerasElement.ConsiderAsArrayOf("camera");
|
||||
for (std::size_t i = 0; i < camerasElement.GetChildrenCount(); ++i) {
|
||||
const SerializerElement& cameraElement = camerasElement.GetChild(i);
|
||||
|
||||
camera.SetUseDefaultSize(
|
||||
cameraElement.GetBoolAttribute("DefaultSize", true));
|
||||
camera.SetSize(cameraElement.GetDoubleAttribute("Width"),
|
||||
cameraElement.GetDoubleAttribute("Height"));
|
||||
Camera camera;
|
||||
camera.SetUseDefaultSize(
|
||||
cameraElement.GetBoolAttribute("defaultSize", true));
|
||||
camera.SetSize(cameraElement.GetDoubleAttribute("width"),
|
||||
cameraElement.GetDoubleAttribute("height"));
|
||||
camera.SetUseDefaultViewport(
|
||||
cameraElement.GetBoolAttribute("defaultViewport", true));
|
||||
camera.SetViewport(
|
||||
cameraElement.GetDoubleAttribute("viewportLeft"),
|
||||
cameraElement.GetDoubleAttribute("viewportTop"),
|
||||
cameraElement.GetDoubleAttribute("viewportRight"),
|
||||
cameraElement.GetDoubleAttribute(
|
||||
"viewportBottom"));
|
||||
|
||||
camera.SetUseDefaultViewport(
|
||||
cameraElement.GetBoolAttribute("DefaultViewport", true));
|
||||
camera.SetViewport(
|
||||
cameraElement.GetDoubleAttribute("ViewportLeft"),
|
||||
cameraElement.GetDoubleAttribute("ViewportTop"),
|
||||
cameraElement.GetDoubleAttribute("ViewportRight"),
|
||||
cameraElement.GetDoubleAttribute(
|
||||
"ViewportBottom")); // (sf::Rect used Right and Bottom instead of
|
||||
// Width and Height before)
|
||||
}
|
||||
}
|
||||
// End of compatibility code
|
||||
else {
|
||||
SerializerElement& camerasElement = element.GetChild("cameras");
|
||||
camerasElement.ConsiderAsArrayOf("camera");
|
||||
for (std::size_t i = 0; i < camerasElement.GetChildrenCount(); ++i) {
|
||||
const SerializerElement& cameraElement = camerasElement.GetChild(i);
|
||||
|
||||
SetCameraCount(GetCameraCount() + 1);
|
||||
Camera& camera = GetCamera(GetCameraCount() - 1);
|
||||
|
||||
camera.SetUseDefaultSize(
|
||||
cameraElement.GetBoolAttribute("defaultSize", true));
|
||||
camera.SetSize(cameraElement.GetDoubleAttribute("width"),
|
||||
cameraElement.GetDoubleAttribute("height"));
|
||||
|
||||
camera.SetUseDefaultViewport(
|
||||
cameraElement.GetBoolAttribute("defaultViewport", true));
|
||||
camera.SetViewport(
|
||||
cameraElement.GetDoubleAttribute("viewportLeft"),
|
||||
cameraElement.GetDoubleAttribute("viewportTop"),
|
||||
cameraElement.GetDoubleAttribute("viewportRight"),
|
||||
cameraElement.GetDoubleAttribute(
|
||||
"viewportBottom")); // (sf::Rect used Right and Bottom instead of
|
||||
// Width and Height before)
|
||||
}
|
||||
cameras.push_back(camera);
|
||||
}
|
||||
|
||||
effects.clear();
|
||||
SerializerElement& effectsElement = element.GetChild("effects");
|
||||
effectsElement.ConsiderAsArrayOf("effect");
|
||||
for (std::size_t i = 0; i < effectsElement.GetChildrenCount(); ++i) {
|
||||
const SerializerElement& effectElement = effectsElement.GetChild(i);
|
||||
|
||||
auto effect = std::make_shared<Effect>();
|
||||
effect->UnserializeFrom(effectElement);
|
||||
effects.push_back(effect);
|
||||
if (camerasElement.GetChildrenCount() > 50) {
|
||||
// Highly unlikely that we want as many cameras, as they were not even exposed in
|
||||
// the editor nor used in the game engine. Must be because of a bug in the editor that
|
||||
// duplicated cameras when cancelling changes on a layer.
|
||||
// Reset to one camera.
|
||||
SetCameraCount(1);
|
||||
}
|
||||
|
||||
const SerializerElement& effectsElement = element.GetChild("effects");
|
||||
effectsContainer.UnserializeFrom(effectsElement);
|
||||
}
|
||||
|
||||
gd::Effect& Layer::GetEffect(const gd::String& name) {
|
||||
auto effect = find_if(effects.begin(),
|
||||
effects.end(),
|
||||
[&name](std::shared_ptr<gd::Effect>& effect) {
|
||||
return effect->GetName() == name;
|
||||
});
|
||||
|
||||
if (effect != effects.end()) return **effect;
|
||||
|
||||
return badEffect;
|
||||
}
|
||||
const gd::Effect& Layer::GetEffect(const gd::String& name) const {
|
||||
auto effect = find_if(effects.begin(),
|
||||
effects.end(),
|
||||
[&name](const std::shared_ptr<gd::Effect>& effect) {
|
||||
return effect->GetName() == name;
|
||||
});
|
||||
|
||||
if (effect != effects.end()) return **effect;
|
||||
|
||||
return badEffect;
|
||||
}
|
||||
gd::Effect& Layer::GetEffect(std::size_t index) { return *effects[index]; }
|
||||
const gd::Effect& Layer::GetEffect(std::size_t index) const {
|
||||
return *effects[index];
|
||||
}
|
||||
std::size_t Layer::GetEffectsCount() const { return effects.size(); }
|
||||
|
||||
bool Layer::HasEffectNamed(const gd::String& name) const {
|
||||
return (find_if(effects.begin(),
|
||||
effects.end(),
|
||||
[&name](const std::shared_ptr<gd::Effect>& effect) {
|
||||
return effect->GetName() == name;
|
||||
}) != effects.end());
|
||||
}
|
||||
std::size_t Layer::GetEffectPosition(const gd::String& name) const {
|
||||
for (std::size_t i = 0; i < effects.size(); ++i) {
|
||||
if (effects[i]->GetName() == name) return i;
|
||||
}
|
||||
return gd::String::npos;
|
||||
gd::EffectsContainer& Layer::GetEffects() {
|
||||
return effectsContainer;
|
||||
}
|
||||
|
||||
gd::Effect& Layer::InsertNewEffect(const gd::String& name,
|
||||
std::size_t position) {
|
||||
auto newEffect = std::make_shared<Effect>();
|
||||
newEffect->SetName(name);
|
||||
|
||||
if (position < effects.size())
|
||||
effects.insert(effects.begin() + position, newEffect);
|
||||
else
|
||||
effects.push_back(newEffect);
|
||||
|
||||
return *newEffect;
|
||||
}
|
||||
|
||||
void Layer::InsertEffect(const gd::Effect& effect, std::size_t position) {
|
||||
auto newEffect = std::make_shared<gd::Effect>(effect);
|
||||
if (position < effects.size())
|
||||
effects.insert(effects.begin() + position, newEffect);
|
||||
else
|
||||
effects.push_back(newEffect);
|
||||
}
|
||||
|
||||
void Layer::RemoveEffect(const gd::String& name) {
|
||||
auto effect = find_if(effects.begin(),
|
||||
effects.end(),
|
||||
[&name](const std::shared_ptr<gd::Effect>& effect) {
|
||||
return effect->GetName() == name;
|
||||
});
|
||||
if (effect == effects.end()) return;
|
||||
|
||||
effects.erase(effect);
|
||||
}
|
||||
|
||||
void Layer::SwapEffects(std::size_t firstEffectIndex,
|
||||
std::size_t secondEffectIndex) {
|
||||
if (firstEffectIndex >= effects.size() || secondEffectIndex >= effects.size())
|
||||
return;
|
||||
|
||||
auto temp = effects[firstEffectIndex];
|
||||
effects[firstEffectIndex] = effects[secondEffectIndex];
|
||||
effects[secondEffectIndex] = temp;
|
||||
const gd::EffectsContainer& Layer::GetEffects() const {
|
||||
return effectsContainer;
|
||||
}
|
||||
|
||||
Camera::Camera()
|
||||
|
@@ -7,7 +7,10 @@
|
||||
#define GDCORE_LAYER_H
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "EffectsContainer.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Effect;
|
||||
}
|
||||
@@ -17,6 +20,9 @@ class Camera;
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
}
|
||||
namespace gd {
|
||||
class EffectsContainer;
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -54,7 +60,9 @@ class GD_CORE_API Layer {
|
||||
/**
|
||||
* \brief Set if the layer is a lightining layer or not.
|
||||
*/
|
||||
void SetLightingLayer(bool isLightingLayer_) { isLightingLayer = isLightingLayer_; }
|
||||
void SetLightingLayer(bool isLightingLayer_) {
|
||||
isLightingLayer = isLightingLayer_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the layer is a lighting layer.
|
||||
@@ -64,7 +72,9 @@ class GD_CORE_API Layer {
|
||||
/**
|
||||
* \brief Set if the layer automatically follows the base layer or not.
|
||||
*/
|
||||
void SetFollowBaseLayerCamera(bool followBaseLayerCamera_) { followBaseLayerCamera = followBaseLayerCamera_; }
|
||||
void SetFollowBaseLayerCamera(bool followBaseLayerCamera_) {
|
||||
followBaseLayerCamera = followBaseLayerCamera_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the layer follows the base layer.
|
||||
@@ -144,66 +154,14 @@ class GD_CORE_API Layer {
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Return true if the effect called "name" exists.
|
||||
* \brief Return the effects container.
|
||||
*/
|
||||
bool HasEffectNamed(const gd::String& name) const;
|
||||
EffectsContainer& GetEffects();
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the effect called "name".
|
||||
* \brief Return a const reference to the effects container.
|
||||
*/
|
||||
Effect& GetEffect(const gd::String& name);
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the effect called "name".
|
||||
*/
|
||||
const Effect& GetEffect(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* Return a reference to the effect at position "index" in the effects list
|
||||
*/
|
||||
Effect& GetEffect(std::size_t index);
|
||||
|
||||
/**
|
||||
* Return a reference to the effect at position "index" in the effects list
|
||||
*/
|
||||
const Effect& GetEffect(std::size_t index) const;
|
||||
|
||||
/**
|
||||
* Return the position of the effect called "name" in the effects list
|
||||
*/
|
||||
std::size_t GetEffectPosition(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* Return the number of effecst.
|
||||
*/
|
||||
std::size_t GetEffectsCount() const;
|
||||
|
||||
/**
|
||||
* Add a new effect at the specified position in the effects list.
|
||||
*/
|
||||
gd::Effect& InsertNewEffect(const gd::String& name, std::size_t position);
|
||||
|
||||
/**
|
||||
* \brief Add a copy of the specified effect in the effects list.
|
||||
*
|
||||
* \note No pointer or reference must be kept on the layer passed as
|
||||
* parameter.
|
||||
*
|
||||
* \param theEffect The effect that must be copied and inserted
|
||||
* into the effects list
|
||||
* \param position Insertion position.
|
||||
*/
|
||||
void InsertEffect(const Effect& theEffect, std::size_t position);
|
||||
|
||||
/**
|
||||
* Remove the specified effect.
|
||||
*/
|
||||
void RemoveEffect(const gd::String& name);
|
||||
|
||||
/**
|
||||
* Swap the position of two effects.
|
||||
*/
|
||||
void SwapEffects(std::size_t firstEffectIndex, std::size_t secondEffectIndex);
|
||||
const EffectsContainer& GetEffects() const;
|
||||
///@}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
@@ -219,19 +177,19 @@ class GD_CORE_API Layer {
|
||||
void UnserializeFrom(const SerializerElement& element);
|
||||
|
||||
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
|
||||
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.
|
||||
gd::EffectsContainer effectsContainer; ///< The effects applied to the layer.
|
||||
|
||||
static gd::Camera badCamera;
|
||||
static gd::Effect badEffect;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -5,10 +5,14 @@
|
||||
*/
|
||||
|
||||
#include "Layout.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/Serialization.h"
|
||||
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/IDE/SceneNameMangler.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
@@ -219,16 +223,21 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
|
||||
++i) {
|
||||
const gd::String& name = allBehaviorsNames[i];
|
||||
|
||||
if (behaviorsSharedData.find(name) == behaviorsSharedData.end()) {
|
||||
gd::BehaviorsSharedData* behaviorSharedData =
|
||||
project.GetBehaviorSharedDatas(allBehaviorsTypes[i]);
|
||||
if (behaviorSharedData) {
|
||||
auto behaviorContent =
|
||||
gd::make_unique<gd::BehaviorContent>(name, allBehaviorsTypes[i]);
|
||||
behaviorSharedData->InitializeContent(behaviorContent->GetContent());
|
||||
behaviorsSharedData[name] = std::move(behaviorContent);
|
||||
}
|
||||
}
|
||||
if (behaviorsSharedData.find(name) != behaviorsSharedData.end()) continue;
|
||||
|
||||
const gd::BehaviorMetadata& behaviorMetadata =
|
||||
gd::MetadataProvider::GetBehaviorMetadata(project.GetCurrentPlatform(),
|
||||
allBehaviorsTypes[i]);
|
||||
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) continue;
|
||||
|
||||
gd::BehaviorsSharedData* behaviorSharedData =
|
||||
behaviorMetadata.GetSharedDataInstance();
|
||||
if (!behaviorSharedData) continue;
|
||||
|
||||
auto behaviorContent =
|
||||
gd::make_unique<gd::BehaviorContent>(name, allBehaviorsTypes[i]);
|
||||
behaviorSharedData->InitializeContent(behaviorContent->GetContent());
|
||||
behaviorsSharedData[name] = std::move(behaviorContent);
|
||||
}
|
||||
|
||||
// Remove useless shared data:
|
||||
|
@@ -5,15 +5,63 @@
|
||||
*/
|
||||
|
||||
#include "LoadingScreen.h"
|
||||
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
LoadingScreen::LoadingScreen()
|
||||
: showGDevelopSplash(true),
|
||||
gdevelopLogoStyle("light"),
|
||||
backgroundImageResourceName(""),
|
||||
backgroundColor(0),
|
||||
backgroundFadeInDuration(0.2),
|
||||
minDuration(1.5),
|
||||
logoAndProgressFadeInDuration(0.2),
|
||||
logoAndProgressLogoFadeInDelay(0.2),
|
||||
showProgressBar(true),
|
||||
progressBarMinWidth(40),
|
||||
progressBarMaxWidth(200),
|
||||
progressBarWidthPercent(30),
|
||||
progressBarHeight(20),
|
||||
progressBarColor(0xFFFFFF){};
|
||||
|
||||
void LoadingScreen::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("showGDevelopSplash", showGDevelopSplash);
|
||||
element.SetAttribute("gdevelopLogoStyle",
|
||||
gdevelopLogoStyle);
|
||||
element.SetAttribute("backgroundImageResourceName",
|
||||
backgroundImageResourceName);
|
||||
element.SetAttribute("backgroundColor", backgroundColor);
|
||||
element.SetAttribute("backgroundFadeInDuration", backgroundFadeInDuration);
|
||||
element.SetAttribute("minDuration", minDuration);
|
||||
element.SetAttribute("logoAndProgressFadeInDuration", logoAndProgressFadeInDuration);
|
||||
element.SetAttribute("logoAndProgressLogoFadeInDelay", logoAndProgressLogoFadeInDelay);
|
||||
element.SetAttribute("showProgressBar", showProgressBar);
|
||||
element.SetAttribute("progressBarMinWidth", progressBarMinWidth);
|
||||
element.SetAttribute("progressBarMaxWidth", progressBarMaxWidth);
|
||||
element.SetAttribute("progressBarWidthPercent", progressBarWidthPercent);
|
||||
element.SetAttribute("progressBarHeight", progressBarHeight);
|
||||
element.SetAttribute("progressBarColor", progressBarColor);
|
||||
}
|
||||
|
||||
void LoadingScreen::UnserializeFrom(const SerializerElement& element) {
|
||||
showGDevelopSplash = element.GetBoolAttribute("showGDevelopSplash", true);
|
||||
gdevelopLogoStyle =
|
||||
element.GetStringAttribute("gdevelopLogoStyle", "light");
|
||||
backgroundImageResourceName =
|
||||
element.GetStringAttribute("backgroundImageResourceName");
|
||||
backgroundColor = element.GetIntAttribute("backgroundColor", 0);
|
||||
backgroundFadeInDuration =
|
||||
element.GetDoubleAttribute("backgroundFadeInDuration", 0.2);
|
||||
minDuration = element.GetDoubleAttribute("minDuration", 1.5);
|
||||
logoAndProgressFadeInDuration = element.GetDoubleAttribute("logoAndProgressFadeInDuration", 0.2);
|
||||
logoAndProgressLogoFadeInDelay = element.GetDoubleAttribute("logoAndProgressLogoFadeInDelay", 0.2);
|
||||
showProgressBar = element.GetBoolAttribute("showProgressBar", true);
|
||||
progressBarMinWidth = element.GetDoubleAttribute("progressBarMinWidth", 40);
|
||||
progressBarMaxWidth = element.GetDoubleAttribute("progressBarMaxWidth", 200);
|
||||
progressBarWidthPercent = element.GetDoubleAttribute("progressBarWidthPercent", 30);
|
||||
progressBarHeight = element.GetDoubleAttribute("progressBarHeight", 20);
|
||||
progressBarColor = element.GetIntAttribute("progressBarColor", 0xFFFFFF);
|
||||
}
|
||||
} // namespace gd
|
||||
|
@@ -22,36 +22,151 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API LoadingScreen {
|
||||
public:
|
||||
LoadingScreen(){};
|
||||
LoadingScreen();
|
||||
virtual ~LoadingScreen(){};
|
||||
|
||||
/**
|
||||
* \brief Set if the GDevelop splash should be shown while loading assets.
|
||||
*/
|
||||
void ShowGDevelopSplash(bool show) { showGDevelopSplash = show; };
|
||||
|
||||
/**
|
||||
* \brief Return true if the GDevelop splash should be shown while loading
|
||||
* \brief Return true if the GDevelop logo should be shown while loading
|
||||
* assets.
|
||||
*/
|
||||
bool IsGDevelopSplashShown() const { return showGDevelopSplash; };
|
||||
|
||||
/**
|
||||
* \brief Set if the GDevelop logo should be shown while loading assets.
|
||||
*/
|
||||
LoadingScreen& ShowGDevelopSplash(bool show) {
|
||||
showGDevelopSplash = show;
|
||||
return *this;
|
||||
};
|
||||
|
||||
const gd::String& GetGDevelopLogoStyle() const { return gdevelopLogoStyle; };
|
||||
|
||||
LoadingScreen& SetGDevelopLogoStyle(const gd::String& value) {
|
||||
gdevelopLogoStyle = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const gd::String& GetBackgroundImageResourceName() const {
|
||||
return backgroundImageResourceName;
|
||||
};
|
||||
|
||||
LoadingScreen& SetBackgroundImageResourceName(const gd::String& value) {
|
||||
backgroundImageResourceName = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int GetBackgroundColor() const { return backgroundColor; };
|
||||
|
||||
LoadingScreen& SetBackgroundColor(int value) {
|
||||
backgroundColor = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
double GetBackgroundFadeInDuration() const {
|
||||
return backgroundFadeInDuration;
|
||||
};
|
||||
|
||||
LoadingScreen& SetBackgroundFadeInDuration(double value) {
|
||||
backgroundFadeInDuration = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
double GetMinDuration() const { return minDuration; };
|
||||
|
||||
LoadingScreen& SetMinDuration(double value) {
|
||||
minDuration = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
double GetLogoAndProgressFadeInDuration() const {
|
||||
return logoAndProgressFadeInDuration;
|
||||
}
|
||||
|
||||
LoadingScreen& SetLogoAndProgressFadeInDuration(double value) {
|
||||
logoAndProgressFadeInDuration = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
double GetLogoAndProgressLogoFadeInDelay() const {
|
||||
return logoAndProgressLogoFadeInDelay;
|
||||
}
|
||||
|
||||
LoadingScreen& SetLogoAndProgressLogoFadeInDelay(double value) {
|
||||
logoAndProgressLogoFadeInDelay = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool GetShowProgressBar() const { return showProgressBar; }
|
||||
|
||||
LoadingScreen& SetShowProgressBar(bool value) {
|
||||
showProgressBar = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
double GetProgressBarMinWidth() const { return progressBarMinWidth; }
|
||||
|
||||
LoadingScreen& SetProgressBarMinWidth(double value) {
|
||||
progressBarMinWidth = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
double GetProgressBarMaxWidth() const { return progressBarMaxWidth; }
|
||||
|
||||
LoadingScreen& SetProgressBarMaxWidth(double value) {
|
||||
progressBarMaxWidth = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
double GetProgressBarWidthPercent() const { return progressBarWidthPercent; }
|
||||
|
||||
LoadingScreen& SetProgressBarWidthPercent(double value) {
|
||||
progressBarWidthPercent = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
double GetProgressBarHeight() const { return progressBarHeight; }
|
||||
|
||||
LoadingScreen& SetProgressBarHeight(double value) {
|
||||
progressBarHeight = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int GetProgressBarColor() const { return progressBarColor; }
|
||||
|
||||
LoadingScreen& SetProgressBarColor(int value) {
|
||||
progressBarColor = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** \name Saving and loading
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Serialize objects groups container.
|
||||
* \brief Serialize the loading screen setup.
|
||||
*/
|
||||
void SerializeTo(SerializerElement& element) const;
|
||||
|
||||
/**
|
||||
* \brief Unserialize the objects groups container.
|
||||
* \brief Unserialize the loading screen setup.
|
||||
*/
|
||||
void UnserializeFrom(const SerializerElement& element);
|
||||
///@}
|
||||
|
||||
private:
|
||||
bool showGDevelopSplash;
|
||||
gd::String gdevelopLogoStyle;
|
||||
gd::String backgroundImageResourceName;
|
||||
int backgroundColor;
|
||||
double backgroundFadeInDuration; // In seconds.
|
||||
double minDuration; // In seconds.
|
||||
double logoAndProgressFadeInDuration; // In seconds.
|
||||
double logoAndProgressLogoFadeInDelay; // In seconds.
|
||||
bool showProgressBar;
|
||||
double progressBarMinWidth; // In pixels.
|
||||
double progressBarMaxWidth; // In pixels.
|
||||
double progressBarWidthPercent;
|
||||
double progressBarHeight; // In pixels.
|
||||
int progressBarColor;
|
||||
};
|
||||
} // namespace gd
|
||||
|
||||
|
@@ -4,6 +4,9 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Project/Object.h"
|
||||
|
||||
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
@@ -24,6 +27,7 @@ void Object::Init(const gd::Object& object) {
|
||||
type = object.type;
|
||||
objectVariables = object.objectVariables;
|
||||
tags = object.tags;
|
||||
effectsContainer = object.effectsContainer;
|
||||
|
||||
behaviors.clear();
|
||||
for (auto& it : object.behaviors) {
|
||||
@@ -85,16 +89,17 @@ std::map<gd::String, gd::PropertyDescriptor> Object::GetProperties() const {
|
||||
gd::BehaviorContent* Object::AddNewBehavior(gd::Project& project,
|
||||
const gd::String& type,
|
||||
const gd::String& name) {
|
||||
gd::Behavior* behavior = project.GetCurrentPlatform().GetBehavior(type);
|
||||
|
||||
if (behavior) {
|
||||
auto behaviorContent = gd::make_unique<gd::BehaviorContent>(name, type);
|
||||
behavior->InitializeContent(behaviorContent->GetContent());
|
||||
behaviors[name] = std::move(behaviorContent);
|
||||
return behaviors[name].get();
|
||||
} else {
|
||||
const gd::BehaviorMetadata& behaviorMetadata =
|
||||
gd::MetadataProvider::GetBehaviorMetadata(project.GetCurrentPlatform(),
|
||||
type);
|
||||
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto behaviorContent = gd::make_unique<gd::BehaviorContent>(name, type);
|
||||
behaviorMetadata.Get().InitializeContent(behaviorContent->GetContent());
|
||||
behaviors[name] = std::move(behaviorContent);
|
||||
return behaviors[name].get();
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
@@ -116,6 +121,11 @@ void Object::UnserializeFrom(gd::Project& project,
|
||||
element.GetChild("variables", 0, "Variables"));
|
||||
behaviors.clear();
|
||||
|
||||
if (element.HasChild("effects")) {
|
||||
const SerializerElement& effectsElement = element.GetChild("effects");
|
||||
effectsContainer.UnserializeFrom(effectsElement);
|
||||
}
|
||||
|
||||
// Compatibility with GD <= 3.3
|
||||
if (element.HasChild("Automatism")) {
|
||||
for (std::size_t i = 0; i < element.GetChildrenCount("Automatism"); ++i) {
|
||||
@@ -180,6 +190,7 @@ void Object::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("type", GetType());
|
||||
element.SetAttribute("tags", GetTags());
|
||||
objectVariables.SerializeTo(element.AddChild("variables"));
|
||||
effectsContainer.SerializeTo(element.AddChild("effects"));
|
||||
|
||||
SerializerElement& behaviorsElement = element.AddChild("behaviors");
|
||||
behaviorsElement.ConsiderAsArrayOf("behavior");
|
||||
|
@@ -9,7 +9,9 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/BehaviorContent.h"
|
||||
#include "GDCore/Project/EffectsContainer.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/MakeUnique.h"
|
||||
@@ -20,6 +22,7 @@ class Layout;
|
||||
class ArbitraryResourceWorker;
|
||||
class InitialInstance;
|
||||
class SerializerElement;
|
||||
class EffectsContainer;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -146,8 +149,7 @@ class GD_CORE_API Object {
|
||||
*
|
||||
* \return false if the new value cannot be set
|
||||
*/
|
||||
virtual bool UpdateProperty(const gd::String& name,
|
||||
const gd::String& value) {
|
||||
virtual bool UpdateProperty(const gd::String& name, const gd::String& value) {
|
||||
return false;
|
||||
};
|
||||
///@}
|
||||
@@ -198,12 +200,12 @@ class GD_CORE_API Object {
|
||||
std::vector<gd::String> GetAllBehaviorNames() const;
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the behavior called \a name.
|
||||
* \brief Return a reference to the content of the behavior called \a name.
|
||||
*/
|
||||
BehaviorContent& GetBehavior(const gd::String& name);
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the behavior called \a name.
|
||||
* \brief Return a reference to the content of the behavior called \a name.
|
||||
*/
|
||||
const BehaviorContent& GetBehavior(const gd::String& name) const;
|
||||
|
||||
@@ -270,6 +272,24 @@ class GD_CORE_API Object {
|
||||
* object variables
|
||||
*/
|
||||
gd::VariablesContainer& GetVariables() { return objectVariables; }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* \name Effects management
|
||||
* Member functions related to effects management.
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Provide access to the gd::EffectsContainer member containing the
|
||||
* effects.
|
||||
*/
|
||||
const gd::EffectsContainer& GetEffects() const { return effectsContainer; }
|
||||
|
||||
/**
|
||||
* \brief Provide access to the gd::EffectsContainer member containing the
|
||||
* effects.
|
||||
*/
|
||||
gd::EffectsContainer& GetEffects() { return effectsContainer; }
|
||||
///@}
|
||||
|
||||
/** \name Serialization
|
||||
@@ -301,7 +321,9 @@ class GD_CORE_API Object {
|
||||
///< object.
|
||||
gd::VariablesContainer
|
||||
objectVariables; ///< List of the variables of the object
|
||||
gd::String tags; ///< Comma-separated list of tags
|
||||
gd::String tags; ///< Comma-separated list of tags
|
||||
gd::EffectsContainer
|
||||
effectsContainer; ///< The effects container for the object.
|
||||
|
||||
/**
|
||||
* \brief Derived objects can redefine this method to load custom attributes.
|
||||
|
@@ -109,33 +109,6 @@ std::unique_ptr<gd::Object> Project::CreateObject(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gd::Behavior* Project::GetBehavior(const gd::String& type,
|
||||
const gd::String& platformName) {
|
||||
for (std::size_t i = 0; i < platforms.size(); ++i) {
|
||||
if (!platformName.empty() && platforms[i]->GetName() != platformName)
|
||||
continue;
|
||||
|
||||
gd::Behavior* behavior = platforms[i]->GetBehavior(type);
|
||||
if (behavior) return behavior;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gd::BehaviorsSharedData* Project::GetBehaviorSharedDatas(
|
||||
const gd::String& type, const gd::String& platformName) {
|
||||
for (std::size_t i = 0; i < platforms.size(); ++i) {
|
||||
if (!platformName.empty() && platforms[i]->GetName() != platformName)
|
||||
continue;
|
||||
|
||||
gd::BehaviorsSharedData* behaviorSharedData =
|
||||
platforms[i]->GetBehaviorSharedDatas(type);
|
||||
if (behaviorSharedData) return behaviorSharedData;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
std::shared_ptr<gd::BaseEvent> Project::CreateEvent(
|
||||
const gd::String& type, const gd::String& platformName) {
|
||||
@@ -515,8 +488,6 @@ void Project::ClearEventsFunctionsExtensions() {
|
||||
void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
// Checking version
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gd::String updateText;
|
||||
|
||||
const SerializerElement& gdVersionElement =
|
||||
element.GetChild("gdVersion", 0, "GDVersion");
|
||||
gdMajorVersion =
|
||||
@@ -528,10 +499,10 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
|
||||
if (gdMajorVersion > gd::VersionWrapper::Major())
|
||||
gd::LogWarning(
|
||||
_("The version of GDevelop used to create this game seems to be a new "
|
||||
"version.\nGDevelop may fail to open the game, or data may be "
|
||||
"missing.\nYou should check if a new version of GDevelop is "
|
||||
"available."));
|
||||
"The version of GDevelop used to create this game seems to be a new "
|
||||
"version.\nGDevelop may fail to open the game, or data may be "
|
||||
"missing.\nYou should check if a new version of GDevelop is "
|
||||
"available.");
|
||||
else {
|
||||
if ((gdMajorVersion == gd::VersionWrapper::Major() &&
|
||||
gdMinorVersion > gd::VersionWrapper::Minor()) ||
|
||||
@@ -543,22 +514,12 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
gdBuildVersion == gd::VersionWrapper::Build() &&
|
||||
revision > gd::VersionWrapper::Revision())) {
|
||||
gd::LogWarning(
|
||||
_("The version of GDevelop used to create this game seems to be "
|
||||
"greater.\nGDevelop may fail to open the game, or data may be "
|
||||
"missing.\nYou should check if a new version of GDevelop is "
|
||||
"available."));
|
||||
"The version of GDevelop used to create this game seems to be "
|
||||
"greater.\nGDevelop may fail to open the game, or data may be "
|
||||
"missing.\nYou should check if a new version of GDevelop is "
|
||||
"available.");
|
||||
}
|
||||
}
|
||||
|
||||
// Compatibility code
|
||||
if (gdMajorVersion <= 1) {
|
||||
gd::LogError(_(
|
||||
"The game was saved with version of GDevelop which is too old. Please "
|
||||
"open and save the game with one of the first version of GDevelop 2. "
|
||||
"You will then be able to open your game with this GDevelop version."));
|
||||
return;
|
||||
}
|
||||
// End of Compatibility code
|
||||
#endif
|
||||
|
||||
const SerializerElement& propElement =
|
||||
@@ -682,21 +643,6 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
currentPlatform = platforms.back();
|
||||
#endif
|
||||
|
||||
// Compatibility code
|
||||
#if defined(GD_IDE_ONLY)
|
||||
if (VersionWrapper::IsOlder(gdMajorVersion, 0, 0, 0, 3, 0, 0, 0)) {
|
||||
updateText +=
|
||||
_("Sprite scaling has changed since GD 2: The resizing is made so that "
|
||||
"the origin point of the object won't move whatever the scale of the "
|
||||
"object.\n");
|
||||
updateText +=
|
||||
_("You may have to slightly change the position of some objects if you "
|
||||
"have changed their size.\n\n");
|
||||
updateText += _("Thank you for your understanding.\n");
|
||||
}
|
||||
#endif
|
||||
// End of Compatibility code
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
GetObjectGroups().UnserializeFrom(
|
||||
element.GetChild("objectsGroups", 0, "ObjectGroups"));
|
||||
|
@@ -390,37 +390,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
const gd::String& name,
|
||||
const gd::String& platformName = "");
|
||||
|
||||
/**
|
||||
* Get the behavior of the given type.
|
||||
*
|
||||
* \note A project can use more than one platform. In this case, the first
|
||||
* platform supporting the behavior is used, unless \a platformName argument
|
||||
* is not empty.
|
||||
* It is assumed that each platform provides an equivalent
|
||||
* behavior.
|
||||
*
|
||||
* \param type The type of the behavior
|
||||
* \param platformName The name of the platform to be used. If empty, the
|
||||
* first platform supporting the object is used.
|
||||
*/
|
||||
gd::Behavior* GetBehavior(const gd::String& type,
|
||||
const gd::String& platformName = "");
|
||||
|
||||
/**
|
||||
* Get the behavior shared data of the given type.
|
||||
*
|
||||
* \note A project can use more than one platform. In this case, the first
|
||||
* platform supporting the behavior shared data is used, unless \a
|
||||
* platformName argument is not empty.
|
||||
* It is assumed that each platform provides equivalent behavior shared data.
|
||||
*
|
||||
* \param type The type of behavior
|
||||
* \param platformName The name of the platform to be used. If empty, the
|
||||
* first platform supporting the object is used.
|
||||
*/
|
||||
gd::BehaviorsSharedData* GetBehaviorSharedDatas(
|
||||
const gd::String& type, const gd::String& platformName = "");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* Create an event of the given type.
|
||||
|
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "DummyPlatform.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
@@ -36,31 +37,38 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Identifier") {
|
||||
SECTION("Object or expression completions when type is string") {
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject("string", "My"),
|
||||
gd::ExpressionCompletionDescription::ForExpression("string", "My")};
|
||||
gd::ExpressionCompletionDescription::ForObject("string", "My", 0, 2),
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"string", "My", 0, 2)};
|
||||
REQUIRE(getCompletionsFor("string", "My", 0) == expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("string", "My", 1) == expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("string", "My", 2) == expectedEmptyCompletions);
|
||||
}
|
||||
SECTION("Object or expression completions when type is number") {
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject("number", "My"),
|
||||
gd::ExpressionCompletionDescription::ForExpression("number", "My")};
|
||||
gd::ExpressionCompletionDescription::ForObject("number", "My", 0, 2),
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"number", "My", 0, 2)};
|
||||
REQUIRE(getCompletionsFor("number", "My", 0) == expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("number", "My", 1) == expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("number", "My", 2) == expectedEmptyCompletions);
|
||||
}
|
||||
SECTION("Object or expression completions when type is number|string") {
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject("number|string", "My"),
|
||||
gd::ExpressionCompletionDescription::ForExpression("number|string", "My")};
|
||||
REQUIRE(getCompletionsFor("number|string", "My", 0) == expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("number|string", "My", 1) == expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("number|string", "My", 2) == expectedEmptyCompletions);
|
||||
gd::ExpressionCompletionDescription::ForObject(
|
||||
"number|string", "My", 0, 2),
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"number|string", "My", 0, 2)};
|
||||
REQUIRE(getCompletionsFor("number|string", "My", 0) ==
|
||||
expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("number|string", "My", 1) ==
|
||||
expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("number|string", "My", 2) ==
|
||||
expectedEmptyCompletions);
|
||||
}
|
||||
SECTION("Object when type is an object") {
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject("object", "My")};
|
||||
gd::ExpressionCompletionDescription::ForObject("object", "My", 0, 2)};
|
||||
REQUIRE(getCompletionsFor("object", "My", 0) == expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("object", "My", 1) == expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("object", "My", 2) == expectedEmptyCompletions);
|
||||
@@ -70,7 +78,8 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
// Also test alternate types also considered as objects (but that can
|
||||
// result in different code generation):
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject("objectPtr", "My")};
|
||||
gd::ExpressionCompletionDescription::ForObject(
|
||||
"objectPtr", "My", 0, 2)};
|
||||
REQUIRE(getCompletionsFor("objectPtr", "My", 0) == expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("objectPtr", "My", 1) == expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("objectPtr", "My", 2) ==
|
||||
@@ -78,30 +87,42 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
}
|
||||
}
|
||||
SECTION("Operator (number)") {
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject("number", ""),
|
||||
gd::ExpressionCompletionDescription::ForExpression("number", "")};
|
||||
REQUIRE(getCompletionsFor("number", "1 + ", 1) == expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("number", "1 + ", 2) == expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("number", "1 + ", 3) == expectedCompletions);
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions1{
|
||||
gd::ExpressionCompletionDescription::ForObject("number", "", 1, 1),
|
||||
gd::ExpressionCompletionDescription::ForExpression("number", "", 1, 1)};
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions2{
|
||||
gd::ExpressionCompletionDescription::ForObject("number", "", 2, 2),
|
||||
gd::ExpressionCompletionDescription::ForExpression("number", "", 2, 2)};
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions3{
|
||||
gd::ExpressionCompletionDescription::ForObject("number", "", 3, 3),
|
||||
gd::ExpressionCompletionDescription::ForExpression("number", "", 3, 3)};
|
||||
REQUIRE(getCompletionsFor("number", "1 + ", 1) == expectedCompletions1);
|
||||
REQUIRE(getCompletionsFor("number", "1 + ", 2) == expectedCompletions2);
|
||||
REQUIRE(getCompletionsFor("number", "1 + ", 3) == expectedCompletions3);
|
||||
}
|
||||
SECTION("Operator (string)") {
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject("string", ""),
|
||||
gd::ExpressionCompletionDescription::ForExpression("string", "")};
|
||||
REQUIRE(getCompletionsFor("string", "\"a\" + ", 3) == expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("string", "\"a\" + ", 4) == expectedCompletions);
|
||||
REQUIRE(getCompletionsFor("string", "\"a\" + ", 5) == expectedCompletions);
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions3{
|
||||
gd::ExpressionCompletionDescription::ForObject("string", "", 3, 3),
|
||||
gd::ExpressionCompletionDescription::ForExpression("string", "", 3, 3)};
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions4{
|
||||
gd::ExpressionCompletionDescription::ForObject("string", "", 4, 4),
|
||||
gd::ExpressionCompletionDescription::ForExpression("string", "", 4, 4)};
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions5{
|
||||
gd::ExpressionCompletionDescription::ForObject("string", "", 5, 5),
|
||||
gd::ExpressionCompletionDescription::ForExpression("string", "", 5, 5)};
|
||||
REQUIRE(getCompletionsFor("string", "\"a\" + ", 3) == expectedCompletions3);
|
||||
REQUIRE(getCompletionsFor("string", "\"a\" + ", 4) == expectedCompletions4);
|
||||
REQUIRE(getCompletionsFor("string", "\"a\" + ", 5) == expectedCompletions5);
|
||||
}
|
||||
|
||||
SECTION("Free function") {
|
||||
SECTION("Test 1") {
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
|
||||
gd::ExpressionCompletionDescription::ForExpression("unknown",
|
||||
"Function")};
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"unknown", "Function", 0, 8)};
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedExactCompletions{
|
||||
gd::ExpressionCompletionDescription::ForExpression("unknown",
|
||||
"Function")
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"unknown", "Function", 0, 8)
|
||||
.SetIsExact(true)};
|
||||
REQUIRE(getCompletionsFor("string", "Function(", 0) ==
|
||||
expectedCompletions);
|
||||
@@ -123,33 +144,48 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
expectedEmptyCompletions);
|
||||
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject("unknown", "a"),
|
||||
gd::ExpressionCompletionDescription::ForExpression("unknown", "a")};
|
||||
gd::ExpressionCompletionDescription::ForObject("unknown", "a", 9, 10),
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"unknown", "a", 9, 10)};
|
||||
REQUIRE(getCompletionsFor("string", "Function(a", 9) ==
|
||||
expectedCompletions);
|
||||
}
|
||||
SECTION("Function with a Variable as argument") {
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
|
||||
gd::ExpressionCompletionDescription::ForVariable("scenevar",
|
||||
"myVar")};
|
||||
gd::ExpressionCompletionDescription::ForVariable(
|
||||
"scenevar", "myVar", 33, 38)};
|
||||
REQUIRE(getCompletionsFor("number",
|
||||
"MyExtension::GetVariableAsNumber(myVar",
|
||||
33) == expectedCompletions);
|
||||
}
|
||||
SECTION("Function with a Layer as argument") {
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
|
||||
gd::ExpressionCompletionDescription::ForText(
|
||||
"layer",
|
||||
gd::MetadataProvider::GetExpressionMetadata(platform,
|
||||
"MyExtension::MouseX")
|
||||
.GetParameter(0),
|
||||
"",
|
||||
20,
|
||||
21,
|
||||
false)};
|
||||
REQUIRE(getCompletionsFor("number", "MyExtension::MouseX(\"", 20) ==
|
||||
expectedCompletions);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Partial object or behavior function") {
|
||||
SECTION("Test with string type") {
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedObjectCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject("string",
|
||||
"MyObject")};
|
||||
gd::ExpressionCompletionDescription::ForObject(
|
||||
"string", "MyObject", 0, 8)};
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedBehaviorOrFunctionCompletions{
|
||||
gd::ExpressionCompletionDescription::ForBehavior("Func",
|
||||
"MyObject"),
|
||||
gd::ExpressionCompletionDescription::ForBehavior(
|
||||
"Func", 9, 13, "MyObject"),
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"string", "Func", "MyObject")};
|
||||
"string", "Func", 9, 13, "MyObject")};
|
||||
REQUIRE(getCompletionsFor("string", "MyObject.Func", 0) ==
|
||||
expectedObjectCompletions);
|
||||
REQUIRE(getCompletionsFor("string", "MyObject.Func", 7) ==
|
||||
@@ -166,14 +202,14 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Test with 'number|string' type") {
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedObjectCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject("number|string",
|
||||
"MyObject")};
|
||||
gd::ExpressionCompletionDescription::ForObject(
|
||||
"number|string", "MyObject", 0, 8)};
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedBehaviorOrFunctionCompletions{
|
||||
gd::ExpressionCompletionDescription::ForBehavior("Func",
|
||||
"MyObject"),
|
||||
gd::ExpressionCompletionDescription::ForBehavior(
|
||||
"Func", 9, 13, "MyObject"),
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"number|string", "Func", "MyObject")};
|
||||
"number|string", "Func", 9, 13, "MyObject")};
|
||||
REQUIRE(getCompletionsFor("number|string", "MyObject.Func", 0) ==
|
||||
expectedObjectCompletions);
|
||||
REQUIRE(getCompletionsFor("number|string", "MyObject.Func", 7) ==
|
||||
@@ -193,18 +229,18 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Test 1") {
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedObjectCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject("unknown",
|
||||
"MyObject")};
|
||||
gd::ExpressionCompletionDescription::ForObject(
|
||||
"unknown", "MyObject", 0, 8)};
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedBehaviorOrFunctionCompletions{
|
||||
gd::ExpressionCompletionDescription::ForBehavior("Func",
|
||||
"MyObject"),
|
||||
gd::ExpressionCompletionDescription::ForBehavior(
|
||||
"Func", 9, 13, "MyObject"),
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"unknown", "Func", "MyObject")};
|
||||
"unknown", "Func", 9, 13, "MyObject")};
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedExactFunctionCompletions{
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"unknown", "Func", "MyObject")
|
||||
"unknown", "Func", 9, 13, "MyObject")
|
||||
.SetIsExact(true)};
|
||||
REQUIRE(getCompletionsFor("string", "MyObject.Func(", 0) ==
|
||||
expectedObjectCompletions);
|
||||
@@ -229,16 +265,16 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Test 1") {
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedObjectCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject("string",
|
||||
"MyObject")};
|
||||
gd::ExpressionCompletionDescription::ForObject(
|
||||
"string", "MyObject", 0, 8)};
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedBehaviorCompletions{
|
||||
gd::ExpressionCompletionDescription::ForBehavior("MyBehavior",
|
||||
"MyObject")};
|
||||
gd::ExpressionCompletionDescription::ForBehavior(
|
||||
"MyBehavior", 9, 19, "MyObject")};
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedFunctionCompletions{
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"string", "Func", "MyObject", "MyBehavior")};
|
||||
"string", "Func", 21, 25, "MyObject", "MyBehavior")};
|
||||
REQUIRE(getCompletionsFor("string", "MyObject.MyBehavior::Func", 0) ==
|
||||
expectedObjectCompletions);
|
||||
REQUIRE(getCompletionsFor("string", "MyObject.MyBehavior::Func", 7) ==
|
||||
@@ -261,16 +297,16 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Test 2") {
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedObjectCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject("string",
|
||||
"MyObject")};
|
||||
gd::ExpressionCompletionDescription::ForObject(
|
||||
"string", "MyObject", 0, 8)};
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedBehaviorCompletions{
|
||||
gd::ExpressionCompletionDescription::ForBehavior("MyBehavior",
|
||||
"MyObject")};
|
||||
gd::ExpressionCompletionDescription::ForBehavior(
|
||||
"MyBehavior", 9, 19, "MyObject")};
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedFunctionCompletions{
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"string", "", "MyObject", "MyBehavior")};
|
||||
"string", "", 21, 21, "MyObject", "MyBehavior")};
|
||||
REQUIRE(getCompletionsFor("string", "MyObject.MyBehavior::", 0) ==
|
||||
expectedObjectCompletions);
|
||||
REQUIRE(getCompletionsFor("string", "MyObject.MyBehavior::", 7) ==
|
||||
@@ -292,20 +328,20 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
SECTION("Test 1") {
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedObjectCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject("unknown",
|
||||
"MyObject")};
|
||||
gd::ExpressionCompletionDescription::ForObject(
|
||||
"unknown", "MyObject", 0, 8)};
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedBehaviorCompletions{
|
||||
gd::ExpressionCompletionDescription::ForBehavior("MyBehavior",
|
||||
"MyObject")};
|
||||
gd::ExpressionCompletionDescription::ForBehavior(
|
||||
"MyBehavior", 9, 19, "MyObject")};
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedFunctionCompletions{
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"unknown", "Func", "MyObject", "MyBehavior")};
|
||||
"unknown", "Func", 21, 25, "MyObject", "MyBehavior")};
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedExactFunctionCompletions{
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"unknown", "Func", "MyObject", "MyBehavior")
|
||||
"unknown", "Func", 21, 25, "MyObject", "MyBehavior")
|
||||
.SetIsExact(true)};
|
||||
REQUIRE(getCompletionsFor("string", "MyObject.MyBehavior::Func(", 0) ==
|
||||
expectedObjectCompletions);
|
||||
|
@@ -24,6 +24,18 @@ bool CheckNodeAtLocationIs(gd::ExpressionParser2& parser,
|
||||
*node, searchPosition)) != nullptr;
|
||||
}
|
||||
|
||||
template <class TNode>
|
||||
bool CheckParentNodeAtLocationIs(gd::ExpressionParser2& parser,
|
||||
const gd::String& type,
|
||||
const gd::String& expression,
|
||||
size_t searchPosition) {
|
||||
auto node = parser.ParseExpression(type, expression);
|
||||
REQUIRE(node != nullptr);
|
||||
return dynamic_cast<TNode*>(
|
||||
gd::ExpressionNodeLocationFinder::GetParentNodeAtPosition(
|
||||
*node, searchPosition)) != nullptr;
|
||||
}
|
||||
|
||||
bool CheckNoNodeAtLocation(gd::ExpressionParser2& parser,
|
||||
const gd::String& type,
|
||||
const gd::String& expression,
|
||||
@@ -34,6 +46,16 @@ bool CheckNoNodeAtLocation(gd::ExpressionParser2& parser,
|
||||
*node, searchPosition) == nullptr;
|
||||
}
|
||||
|
||||
bool CheckNoParentNodeAtLocation(gd::ExpressionParser2& parser,
|
||||
const gd::String& type,
|
||||
const gd::String& expression,
|
||||
size_t searchPosition) {
|
||||
auto node = parser.ParseExpression(type, expression);
|
||||
REQUIRE(node != nullptr);
|
||||
return gd::ExpressionNodeLocationFinder::GetParentNodeAtPosition(
|
||||
*node, searchPosition) == nullptr;
|
||||
}
|
||||
|
||||
TEST_CASE("ExpressionNodeLocationFinder", "[common][events]") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
@@ -186,6 +208,13 @@ TEST_CASE("ExpressionNodeLocationFinder", "[common][events]") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(parser, "number", "12+\"hello\"", 3) == true);
|
||||
}
|
||||
|
||||
SECTION("Numbers and texts mismatchs (parent node)") {
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::OperatorNode>(parser, "number", "12+\"hello\"", 0) == true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::OperatorNode>(parser, "number", "12+\"hello\"", 1) == true);
|
||||
REQUIRE(CheckNoParentNodeAtLocation(parser, "number", "12+\"hello\"", 2) == true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::OperatorNode>(parser, "number", "12+\"hello\"", 3) == true);
|
||||
}
|
||||
|
||||
SECTION("Valid objects") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::IdentifierNode>(
|
||||
parser, "object", "HelloWorld1", 0) == true);
|
||||
@@ -195,6 +224,10 @@ TEST_CASE("ExpressionNodeLocationFinder", "[common][events]") {
|
||||
parser, "object", "HelloWorld1", 10) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "object", "HelloWorld1", 11) == true);
|
||||
}
|
||||
SECTION("Valid objects (parent node)") {
|
||||
REQUIRE(CheckNoParentNodeAtLocation(
|
||||
parser, "object", "HelloWorld1", 0) == true);
|
||||
}
|
||||
SECTION("Invalid objects") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::IdentifierNode>(
|
||||
parser, "object", "a+b", 0) == true);
|
||||
@@ -296,6 +329,29 @@ TEST_CASE("ExpressionNodeLocationFinder", "[common][events]") {
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
52) == true);
|
||||
}
|
||||
SECTION("Parent node") {
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "number", "12 + MyExtension::GetNumber()", 0) ==
|
||||
true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "number", "12 + MyExtension::GetNumber()", 6) ==
|
||||
true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
35) == true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
35) == true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
39) == true);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Invalid function calls") {
|
||||
@@ -316,6 +372,12 @@ TEST_CASE("ExpressionNodeLocationFinder", "[common][events]") {
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "number", "Idontexist(12)", 14) ==
|
||||
true);
|
||||
}
|
||||
SECTION("Invalid function calls (parent node)") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser, "number", "Idontexist(12)", 12) == true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser, "number", "Idontexist(12)", 12) == true);
|
||||
}
|
||||
|
||||
SECTION("Unterminated function calls") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
|
@@ -219,6 +219,12 @@ namespace gdjs {
|
||||
* @param opacity The new opacity of the object (0-255).
|
||||
*/
|
||||
setOpacity(opacity: float): void {
|
||||
if (opacity < 0) {
|
||||
opacity = 0;
|
||||
}
|
||||
if (opacity > 255) {
|
||||
opacity = 255;
|
||||
}
|
||||
this._opacity = opacity;
|
||||
this._renderer.updateOpacity();
|
||||
}
|
||||
|
@@ -684,9 +684,9 @@ module.exports = {
|
||||
}
|
||||
|
||||
this._pixiObject.position.x =
|
||||
this._instance.getX() + this._pixiObject.width / 2;
|
||||
this._instance.getX() + (this._pixiObject.textWidth * scale) / 2;
|
||||
this._pixiObject.position.y =
|
||||
this._instance.getY() + this._pixiObject.height / 2;
|
||||
this._instance.getY() + (this._pixiObject.textHeight * scale) / 2;
|
||||
this._pixiObject.rotation = RenderedInstance.toRad(
|
||||
this._instance.getAngle()
|
||||
);
|
||||
|
@@ -149,9 +149,8 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
updatePosition(): void {
|
||||
this._pixiObject.position.x = this._object.x + this._pixiObject.width / 2;
|
||||
this._pixiObject.position.y =
|
||||
this._object.y + this._pixiObject.height / 2;
|
||||
this._pixiObject.position.x = this._object.x + this.getWidth() / 2;
|
||||
this._pixiObject.position.y = this._object.y + this.getHeight() / 2;
|
||||
}
|
||||
|
||||
updateAngle(): void {
|
||||
@@ -163,11 +162,11 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
getWidth(): float {
|
||||
return this._pixiObject.textWidth;
|
||||
return this._pixiObject.textWidth * this.getScale();
|
||||
}
|
||||
|
||||
getHeight(): float {
|
||||
return this._pixiObject.height;
|
||||
return this._pixiObject.textHeight * this.getScale();
|
||||
}
|
||||
}
|
||||
export const BitmapTextRuntimeObjectRenderer = BitmapTextRuntimeObjectPixiRenderer;
|
||||
|
@@ -148,6 +148,7 @@ namespace gdjs {
|
||||
setText(text: string): void {
|
||||
this._text = text;
|
||||
this._renderer.updateTextContent();
|
||||
this.hitBoxesDirty = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,6 +175,7 @@ namespace gdjs {
|
||||
setScale(scale: float): void {
|
||||
this._scale = scale;
|
||||
this._renderer.updateScale();
|
||||
this.hitBoxesDirty = true;
|
||||
}
|
||||
|
||||
getScale(): float {
|
||||
@@ -255,6 +257,12 @@ namespace gdjs {
|
||||
* @param opacity The new opacity of the object (0-255).
|
||||
*/
|
||||
setOpacity(opacity: float): void {
|
||||
if (opacity < 0) {
|
||||
opacity = 0;
|
||||
}
|
||||
if (opacity > 255) {
|
||||
opacity = 255;
|
||||
}
|
||||
this._opacity = opacity;
|
||||
this._renderer.updateOpacity();
|
||||
}
|
||||
@@ -273,6 +281,7 @@ namespace gdjs {
|
||||
setWrappingWidth(width: float): void {
|
||||
this._wrappingWidth = width;
|
||||
this._renderer.updateWrappingWidth();
|
||||
this.hitBoxesDirty = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,6 +294,7 @@ namespace gdjs {
|
||||
setWordWrap(wordWrap: boolean): void {
|
||||
this._wordWrap = wordWrap;
|
||||
this._renderer.updateWrappingWidth();
|
||||
this.hitBoxesDirty = true;
|
||||
}
|
||||
|
||||
getWordWrap(): boolean {
|
||||
@@ -295,14 +305,14 @@ namespace gdjs {
|
||||
* Get the width of the object.
|
||||
*/
|
||||
getWidth(): float {
|
||||
return this._renderer.getWidth() * this.getScale();
|
||||
return this._renderer.getWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of the object.
|
||||
*/
|
||||
getHeight(): float {
|
||||
return this._renderer.getHeight() * this.getScale();
|
||||
return this._renderer.getHeight();
|
||||
}
|
||||
}
|
||||
gdjs.registerObject(
|
||||
|
@@ -785,7 +785,7 @@ namespace gdjs {
|
||||
variables: gdjs.dialogueTree.runner.variables.data,
|
||||
visited: gdjs.dialogueTree.runner.visited,
|
||||
};
|
||||
gdjs.evtTools.network._objectToVariable(dialogueState, outputVariable);
|
||||
outputVariable.fromJSObject(dialogueState);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -795,9 +795,7 @@ namespace gdjs {
|
||||
* @param inputVariable The structured variable where to load the State from.
|
||||
*/
|
||||
gdjs.dialogueTree.loadState = function (inputVariable: gdjs.Variable) {
|
||||
const loadedState = JSON.parse(
|
||||
gdjs.evtTools.network.variableStructureToJSON(inputVariable)
|
||||
);
|
||||
const loadedState = inputVariable.toJSObject();
|
||||
if (!loadedState) {
|
||||
console.error('Load state variable is empty:', inputVariable);
|
||||
return;
|
||||
|
@@ -39,12 +39,14 @@ describe('gdjs.DraggableRuntimeBehavior', function () {
|
||||
type: '',
|
||||
behaviors: [{ name: 'Behavior1', type: 'DraggableBehavior::Draggable' }],
|
||||
variables: [],
|
||||
effects: [],
|
||||
});
|
||||
var object2 = new gdjs.RuntimeObject(runtimeScene, {
|
||||
name: 'obj1',
|
||||
type: '',
|
||||
behaviors: [{ name: 'Behavior1', type: 'DraggableBehavior::Draggable' }],
|
||||
variables: [],
|
||||
effects: [],
|
||||
});
|
||||
runtimeScene.addObject(object);
|
||||
runtimeScene.addObject(object2);
|
||||
|
@@ -125,6 +125,12 @@ module.exports = {
|
||||
.setValue('7')
|
||||
.setLabel(_('Quality (between 0 and 20)'))
|
||||
.setType('number');
|
||||
advancedBloomProperties
|
||||
.getOrCreate('padding')
|
||||
.setValue('0')
|
||||
.setLabel(_('Padding'))
|
||||
.setType('number')
|
||||
.setDescription(_('Padding for the visual effect area'));
|
||||
|
||||
const asciiEffect = extension
|
||||
.addEffect('Ascii')
|
||||
@@ -215,8 +221,8 @@ module.exports = {
|
||||
|
||||
const blurEffect = extension
|
||||
.addEffect('Blur')
|
||||
.setFullName(_('Blur'))
|
||||
.setDescription(_('Blur the rendered image.'))
|
||||
.setFullName(_('Blur (Gaussian, slow - prefer to use Kawase blur)'))
|
||||
.setDescription(_('Blur the rendered image. This is slow, so prefer to use Kawase blur in most cases.'))
|
||||
.addIncludeFile('Extensions/Effects/blur-pixi-filter.js');
|
||||
const blurProperties = blurEffect.getProperties();
|
||||
blurProperties
|
||||
@@ -412,6 +418,12 @@ module.exports = {
|
||||
.setLabel(_('Noise Frequency'))
|
||||
.setType('number')
|
||||
.setDescription('Number of updates per second (0: no updates)');
|
||||
crtProperties
|
||||
.getOrCreate('padding')
|
||||
.setValue('0')
|
||||
.setLabel(_('Padding'))
|
||||
.setType('number')
|
||||
.setDescription(_('Padding for the visual effect area'));
|
||||
|
||||
const displacementEffect = extension
|
||||
.addEffect('Displacement')
|
||||
@@ -511,6 +523,12 @@ module.exports = {
|
||||
.setValue('false')
|
||||
.setLabel(_('Shadow only (shows only the shadow when enabled)'))
|
||||
.setType('boolean');
|
||||
dropShadowProperties
|
||||
.getOrCreate('padding')
|
||||
.setValue('0')
|
||||
.setLabel(_('Padding'))
|
||||
.setType('number')
|
||||
.setDescription(_('Padding for the visual effect area'));
|
||||
|
||||
const glitchEffect = extension
|
||||
.addEffect('Glitch')
|
||||
@@ -680,12 +698,18 @@ module.exports = {
|
||||
.setValue('100')
|
||||
.setLabel(_('Center Y (between -1000 and 100)'))
|
||||
.setType('number');
|
||||
godrayProperties
|
||||
.getOrCreate('padding')
|
||||
.setValue('0')
|
||||
.setLabel(_('Padding'))
|
||||
.setType('number')
|
||||
.setDescription(_('Padding for the visual effect area'));
|
||||
|
||||
const kawaseBlurEffect = extension
|
||||
.addEffect('KawaseBlur')
|
||||
.setFullName(_('Kawase blur'))
|
||||
.setFullName(_('Blur (Kawase, fast)'))
|
||||
.setDescription(
|
||||
_('A much faster blur than Gaussian blur, but more complicated to use.')
|
||||
_('Blur the rendered image, with much better performance than Gaussian blur.')
|
||||
)
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-kawase-blur.js')
|
||||
.addIncludeFile('Extensions/Effects/kawase-blur-pixi-filter.js');
|
||||
@@ -710,6 +734,12 @@ module.exports = {
|
||||
.setValue('3')
|
||||
.setLabel(_('Quality (between 1 and 20)'))
|
||||
.setType('number');
|
||||
kawaseBlurProperties
|
||||
.getOrCreate('padding')
|
||||
.setValue('0')
|
||||
.setLabel(_('Padding'))
|
||||
.setType('number')
|
||||
.setDescription(_('Padding for the visual effect area'));
|
||||
|
||||
const lightNightEffect = extension
|
||||
.addEffect('LightNight')
|
||||
@@ -839,6 +869,12 @@ module.exports = {
|
||||
.setValue('1')
|
||||
.setLabel(_('Color of the outline'))
|
||||
.setType('color');
|
||||
outlineProperties
|
||||
.getOrCreate('padding')
|
||||
.setValue('0')
|
||||
.setLabel(_('Padding'))
|
||||
.setType('number')
|
||||
.setDescription(_('Padding for the visual effect area'));
|
||||
|
||||
const pixelateEffect = extension
|
||||
.addEffect('Pixelate')
|
||||
@@ -891,6 +927,12 @@ module.exports = {
|
||||
.setValue('0.5')
|
||||
.setLabel(_('Center Y (between 0 and 1, 0.5 is image middle)'))
|
||||
.setType('number');
|
||||
radialBlurProperties
|
||||
.getOrCreate('padding')
|
||||
.setValue('0')
|
||||
.setLabel(_('Padding'))
|
||||
.setType('number')
|
||||
.setDescription(_('Padding for the visual effect area'));
|
||||
|
||||
const reflectionEffect = extension
|
||||
.addEffect('Reflection')
|
||||
@@ -1061,7 +1103,7 @@ module.exports = {
|
||||
.setValue('20')
|
||||
.setLabel(_('Padding'))
|
||||
.setType('number')
|
||||
.setDescription(_('Padding for filter area'));
|
||||
.setDescription(_('Padding for the visual effect area'));
|
||||
twistProperties
|
||||
.getOrCreate('offsetX')
|
||||
.setValue('0.5')
|
||||
@@ -1100,6 +1142,12 @@ module.exports = {
|
||||
.setValue('0.3')
|
||||
.setLabel(_('strength (between 0 and 5)'))
|
||||
.setType('number');
|
||||
zoomBlurProperties
|
||||
.getOrCreate('padding')
|
||||
.setValue('0')
|
||||
.setLabel(_('Padding'))
|
||||
.setType('number')
|
||||
.setDescription(_('Padding for the visual effect area'));
|
||||
|
||||
return extension;
|
||||
},
|
||||
|
@@ -17,6 +17,8 @@ namespace gdjs {
|
||||
advancedBloomFilter.blur = value;
|
||||
} else if (parameterName === 'quality') {
|
||||
advancedBloomFilter.quality = value;
|
||||
} else if (parameterName === 'padding') {
|
||||
advancedBloomFilter.padding = value;
|
||||
}
|
||||
},
|
||||
updateStringParameter: function (filter, parameterName, value) {},
|
||||
|
@@ -42,6 +42,8 @@ namespace gdjs {
|
||||
filter.animationSpeed = value;
|
||||
} else if (parameterName === 'animationFrequency') {
|
||||
filter.animationFrequency = value;
|
||||
} else if (parameterName === 'padding') {
|
||||
filter.padding = value;
|
||||
}
|
||||
},
|
||||
updateStringParameter: function (filter, parameterName, value) {},
|
||||
|
@@ -17,6 +17,8 @@ namespace gdjs {
|
||||
dropShadowFilter.distance = value;
|
||||
} else if (parameterName === 'rotation') {
|
||||
dropShadowFilter.rotation = value;
|
||||
} else if (parameterName === 'padding') {
|
||||
dropShadowFilter.padding = value;
|
||||
}
|
||||
},
|
||||
updateStringParameter: function (filter, parameterName, value) {
|
||||
|
@@ -26,6 +26,8 @@ namespace gdjs {
|
||||
filter.y = value;
|
||||
} else if (parameterName === 'animationSpeed') {
|
||||
filter.animationSpeed = value;
|
||||
} else if (parameterName === 'padding') {
|
||||
filter.padding = value;
|
||||
}
|
||||
},
|
||||
updateStringParameter: function (filter, parameterName, value) {},
|
||||
|
@@ -9,6 +9,8 @@ namespace gdjs {
|
||||
const outlineFilter = (filter as unknown) as PIXI.filters.OutlineFilter;
|
||||
if (parameterName === 'thickness') {
|
||||
outlineFilter.thickness = value;
|
||||
} else if (parameterName === 'padding') {
|
||||
outlineFilter.padding = value;
|
||||
}
|
||||
},
|
||||
updateStringParameter: function (filter, parameterName, value) {
|
||||
|
@@ -33,6 +33,8 @@ namespace gdjs {
|
||||
} else if (parameterName === 'centerY') {
|
||||
// @ts-ignore - extra properties are stored on the filter.
|
||||
radialBlurFilter._centerY = value;
|
||||
} else if (parameterName === 'padding') {
|
||||
radialBlurFilter.padding = value;
|
||||
}
|
||||
},
|
||||
updateStringParameter: function (filter, parameterName, value) {},
|
||||
|
@@ -31,6 +31,8 @@ namespace gdjs {
|
||||
0,
|
||||
20
|
||||
);
|
||||
} else if (parameterName === 'padding') {
|
||||
zoomBlurFilter.padding = value;
|
||||
}
|
||||
},
|
||||
updateStringParameter: function (filter, parameterName, value) {},
|
||||
|
@@ -43,10 +43,7 @@ namespace gdjs {
|
||||
FBInstant.player
|
||||
.getDataAsync([key])
|
||||
.then(function (data) {
|
||||
gdjs.evtTools.network.jsonToVariableStructure(
|
||||
data[key],
|
||||
successVariable
|
||||
);
|
||||
successVariable.fromJSON(data[key]);
|
||||
})
|
||||
.catch(function (error) {
|
||||
errorVariable.setString(error.message || 'Unknown error');
|
||||
@@ -64,7 +61,7 @@ namespace gdjs {
|
||||
errorVariable.setString('');
|
||||
successVariable.setString('');
|
||||
const data = {};
|
||||
data[key] = gdjs.evtTools.network.variableStructureToJSON(variable);
|
||||
data[key] = JSON.stringify(variable.toJSObject());
|
||||
FBInstant.player
|
||||
.setDataAsync(data)
|
||||
.then(function () {
|
||||
@@ -86,9 +83,7 @@ namespace gdjs {
|
||||
}
|
||||
errorVariable.setString('');
|
||||
successVariable.setString('');
|
||||
const data = gdjs.evtTools.network.variableStructureToJSON(
|
||||
extraDataVariable
|
||||
);
|
||||
const data = JSON.stringify(extraDataVariable.toJSObject());
|
||||
FBInstant.getLeaderboardAsync(leaderboardName)
|
||||
.then(function (leaderboard) {
|
||||
return leaderboard.setScoreAsync(score, data);
|
||||
@@ -123,10 +118,7 @@ namespace gdjs {
|
||||
scoreVariable.setNumber(
|
||||
entry.getScore() === null ? -1 : entry.getScore()
|
||||
);
|
||||
gdjs.evtTools.network.jsonToVariableStructure(
|
||||
entry.getExtraData(),
|
||||
extraDataVariable
|
||||
);
|
||||
extraDataVariable.fromJSON(entry.getExtraData());
|
||||
})
|
||||
.catch(function (error) {
|
||||
errorVariable.setString(error.message || 'Unknown error');
|
||||
|
@@ -274,13 +274,12 @@ namespace gdjs {
|
||||
resultVar: gdjs.Variable
|
||||
) {
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
const network = gdjs.evtTools.network;
|
||||
let result = 'error';
|
||||
if (fileSystem && network) {
|
||||
if (fileSystem) {
|
||||
try {
|
||||
fileSystem.writeFileSync(
|
||||
savePath,
|
||||
network.variableStructureToJSON(variable),
|
||||
JSON.stringify(variable.toJSObject()),
|
||||
'utf8'
|
||||
);
|
||||
result = 'ok';
|
||||
@@ -306,11 +305,10 @@ namespace gdjs {
|
||||
resultVar: gdjs.Variable
|
||||
) {
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
const network = gdjs.evtTools.network;
|
||||
if (fileSystem && network) {
|
||||
if (fileSystem) {
|
||||
fileSystem.writeFile(
|
||||
savePath,
|
||||
network.variableStructureToJSON(variable),
|
||||
JSON.stringify(variable.toJSObject()),
|
||||
'utf8',
|
||||
(err) => {
|
||||
resultVar.setString('ok');
|
||||
@@ -368,13 +366,12 @@ namespace gdjs {
|
||||
resultVar: gdjs.Variable
|
||||
) {
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
const network = gdjs.evtTools.network;
|
||||
let result = 'error';
|
||||
if (fileSystem && network) {
|
||||
if (fileSystem) {
|
||||
try {
|
||||
const data = fileSystem.readFileSync(loadPath, 'utf8');
|
||||
if (data) {
|
||||
network.jsonToVariableStructure(data, variable);
|
||||
variable.fromJSON(data);
|
||||
result = 'ok';
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -401,11 +398,10 @@ namespace gdjs {
|
||||
resultVar: gdjs.Variable
|
||||
) {
|
||||
const fileSystem = gdjs.fileSystem._getFs();
|
||||
const network = gdjs.evtTools.network;
|
||||
if (fileSystem && network) {
|
||||
if (fileSystem) {
|
||||
fileSystem.readFile(loadPath, 'utf8', (err, data) => {
|
||||
if (data) {
|
||||
network.jsonToVariableStructure(data, variable);
|
||||
variable.fromJSON(data);
|
||||
resultVar.setString('ok');
|
||||
}
|
||||
if (err) {
|
||||
|
@@ -6,6 +6,241 @@ namespace gdjs {
|
||||
* @namespace
|
||||
*/
|
||||
export namespace firestore {
|
||||
const queries = new Map<string, firebase.firestore.Query>();
|
||||
|
||||
/**
|
||||
* Converts a firebase document snapshot to a plain dictionary,
|
||||
* so that it may be serialized or converted to a {@link gdjs.Variable}.
|
||||
*
|
||||
* @param doc - The document snapshot.
|
||||
* @returns - The converted object.
|
||||
*/
|
||||
const documentSnapshotToSerializable = (
|
||||
doc: firebase.firestore.DocumentSnapshot
|
||||
) => ({
|
||||
data: doc.data(),
|
||||
exists: doc.exists,
|
||||
id: doc.id,
|
||||
});
|
||||
|
||||
/**
|
||||
* Converts a firebase query snapshot to a plain dictionary,
|
||||
* so that it may be serialized or converted to a {@link gdjs.Variable}.
|
||||
*
|
||||
* @param query - The query snapshot.
|
||||
* @returns - The converted object.
|
||||
*/
|
||||
const querySnapshotToSerializable = (
|
||||
query: firebase.firestore.QuerySnapshot
|
||||
) => ({
|
||||
size: query.size,
|
||||
empty: query.empty,
|
||||
docs: query.docs.map(documentSnapshotToSerializable),
|
||||
});
|
||||
|
||||
/**
|
||||
* Initiate a query over a collection.
|
||||
* @param queryID - The name of the new query.
|
||||
* @param collectionName - The name of the collection to query.
|
||||
*/
|
||||
export const startQuery = (queryID: string, collectionName: string) => {
|
||||
queries.set(queryID, firebase.firestore().collection(collectionName));
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new query from a base query.
|
||||
* @param queryID - The name of the new query.
|
||||
* @param sourceQueryID - The name of the source query.
|
||||
*/
|
||||
export const startQueryFrom = (
|
||||
queryID: string,
|
||||
sourceQueryID: string
|
||||
) => {
|
||||
if (queries.has(sourceQueryID))
|
||||
queries.set(queryID, queries.get(sourceQueryID)!);
|
||||
};
|
||||
|
||||
/**
|
||||
* Filters out documents whose fields do not match a condition
|
||||
* from a query.
|
||||
* @param queryID - The query to add the filter to.
|
||||
* @param field - The field to run the condition on.
|
||||
* @param op - The condtion operator.
|
||||
* @param value - The value to check against.
|
||||
*/
|
||||
export const queryWhere = (
|
||||
queryID: string,
|
||||
field: string,
|
||||
op: Exclude<
|
||||
firebase.firestore.WhereFilterOp,
|
||||
// Exclude unsupported "batch" operations (as they require an array as value to check)
|
||||
'in' | 'array-contains-any' | 'not-in'
|
||||
>,
|
||||
value: string | number
|
||||
) => {
|
||||
if (queries.has(queryID))
|
||||
queries.set(queryID, queries.get(queryID)!.where(field, op, value));
|
||||
};
|
||||
|
||||
/**
|
||||
* Orders the documents in a query.
|
||||
*
|
||||
* @param queryID - The query to add the filter to.
|
||||
* @param field - The field to order by.
|
||||
* @param direction - The direction of ordering (ascending or descending).
|
||||
*/
|
||||
export const queryOrderBy = (
|
||||
queryID: string,
|
||||
field: string,
|
||||
direction: firebase.firestore.OrderByDirection
|
||||
) => {
|
||||
if (queries.has(queryID))
|
||||
queries.set(
|
||||
queryID,
|
||||
queries.get(queryID)!.orderBy(field, direction)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Limits the amount of documents returned by the query.
|
||||
*
|
||||
* @param queryID - The query to add the filter to.
|
||||
* @param amount - The amount of documents to limit to
|
||||
* @param last - If true, limits to the last documents instead of the first documents.
|
||||
*/
|
||||
export const queryLimit = (
|
||||
queryID: string,
|
||||
amount: integer,
|
||||
last: boolean
|
||||
) => {
|
||||
if (queries.has(queryID))
|
||||
queries.set(
|
||||
queryID,
|
||||
queries.get(queryID)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes a query skip documents after or before a certain
|
||||
* value of a field the query was ordered with.
|
||||
*
|
||||
* @param queryID - The query to add the filter to.
|
||||
* @param value - The value of the field ordered by.
|
||||
* @param before - If set to true, all documents before the document are skipped, else all documents after it are skipped.
|
||||
* @param includeSelf - If set to true, doesn't skip the document.
|
||||
*/
|
||||
export const querySkipSome = (
|
||||
queryID: string,
|
||||
value: number,
|
||||
before: boolean,
|
||||
includeSelf: boolean
|
||||
) => {
|
||||
if (queries.has(queryID))
|
||||
queries.set(
|
||||
queryID,
|
||||
queries
|
||||
.get(queryID)!
|
||||
[
|
||||
before
|
||||
? includeSelf
|
||||
? 'endAt'
|
||||
: 'endBefore'
|
||||
: includeSelf
|
||||
? 'startAt'
|
||||
: 'startAfter'
|
||||
](value)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a query and store results in a callback variable.
|
||||
*
|
||||
* @param queryID - The query to execute.
|
||||
* @param [callbackValueVariable] - The variable where to store the result.
|
||||
* @param [callbackStatusVariable] - The variable where to store if the operation was successful.
|
||||
*/
|
||||
export const executeQuery = (
|
||||
queryID: string,
|
||||
callbackValueVariable?: gdjs.Variable,
|
||||
callbackStatusVariable?: gdjs.Variable
|
||||
) => {
|
||||
if (!queries.has(queryID)) return;
|
||||
queries
|
||||
.get(queryID)!
|
||||
.get()
|
||||
.then((snapshot) => {
|
||||
if (typeof callbackStatusVariable !== 'undefined')
|
||||
callbackStatusVariable.setString('ok');
|
||||
|
||||
if (typeof callbackValueVariable !== 'undefined')
|
||||
callbackValueVariable.fromJSObject(
|
||||
querySnapshotToSerializable(snapshot)
|
||||
);
|
||||
})
|
||||
.catch((error) => {
|
||||
if (typeof callbackStatusVariable !== 'undefined')
|
||||
callbackStatusVariable.setString(error.message);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Watch a query and store results in a callback
|
||||
* variable whenever a documents starts/stops
|
||||
* matching the query or a document matching
|
||||
* the query is modified.
|
||||
*
|
||||
* @param queryID - The query to execute.
|
||||
* @param [callbackValueVariable] - The variable where to store the result.
|
||||
* @param [callbackStatusVariable] - The variable where to store if the operation was successful.
|
||||
*/
|
||||
export const watchQuery = (
|
||||
queryID: string,
|
||||
callbackValueVariable?: gdjs.Variable,
|
||||
callbackStatusVariable?: gdjs.Variable
|
||||
) => {
|
||||
if (!queries.has(queryID)) return;
|
||||
queries.get(queryID)!.onSnapshot(
|
||||
(snapshot) => {
|
||||
if (typeof callbackStatusVariable !== 'undefined')
|
||||
callbackStatusVariable.setString('ok');
|
||||
|
||||
if (typeof callbackValueVariable !== 'undefined')
|
||||
callbackValueVariable.fromJSObject(
|
||||
querySnapshotToSerializable(snapshot)
|
||||
);
|
||||
},
|
||||
(error) => {
|
||||
if (typeof callbackStatusVariable !== 'undefined')
|
||||
callbackStatusVariable.setString(error.message);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a variable in a collection as document with a unique name.
|
||||
* @param collectionName - The collection where to store the variable.
|
||||
* @param variable - The variable to write.
|
||||
* @param [callbackStateVariable] - The variable where to store the result.
|
||||
*/
|
||||
export const addDocument = (
|
||||
collectionName: string,
|
||||
variable: gdjs.Variable,
|
||||
callbackStateVariable?: gdjs.Variable
|
||||
) => {
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(collectionName)
|
||||
.add(replaceTimestampsInObject(variable.toJSObject()))
|
||||
.then(() => {
|
||||
if (typeof callbackStateVariable !== 'undefined')
|
||||
callbackStateVariable.setString('ok');
|
||||
})
|
||||
.catch((error) => {
|
||||
if (typeof callbackStateVariable !== 'undefined')
|
||||
callbackStateVariable.setString(error.message);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes a variable in a collection as document.
|
||||
* @param collectionName - The collection where to store the variable.
|
||||
@@ -23,11 +258,7 @@ namespace gdjs {
|
||||
.firestore()
|
||||
.collection(collectionName)
|
||||
.doc(variableName)
|
||||
.set(
|
||||
JSON.parse(
|
||||
gdjs.evtTools.network.variableStructureToJSON(variable)
|
||||
)
|
||||
)
|
||||
.set(replaceTimestampsInObject(variable.toJSObject()))
|
||||
.then(() => {
|
||||
if (typeof callbackStateVariable !== 'undefined')
|
||||
callbackStateVariable.setString('ok');
|
||||
@@ -59,7 +290,7 @@ namespace gdjs {
|
||||
.firestore()
|
||||
.collection(collectionName)
|
||||
.doc(documentName)
|
||||
.set({ [field]: value }, { merge: merge })
|
||||
.set({ [field]: replaceTimestampInString(value) }, { merge: merge })
|
||||
.then(() => {
|
||||
if (typeof callbackStateVariable !== 'undefined')
|
||||
callbackStateVariable.setString('ok');
|
||||
@@ -87,11 +318,7 @@ namespace gdjs {
|
||||
.firestore()
|
||||
.collection(collectionName)
|
||||
.doc(variableName)
|
||||
.update(
|
||||
JSON.parse(
|
||||
gdjs.evtTools.network.variableStructureToJSON(variable)
|
||||
)
|
||||
)
|
||||
.update(replaceTimestampsInObject(variable.toJSObject()))
|
||||
.then(() => {
|
||||
if (typeof callbackStateVariable !== 'undefined')
|
||||
callbackStateVariable.setString('ok');
|
||||
@@ -121,7 +348,7 @@ namespace gdjs {
|
||||
.firestore()
|
||||
.collection(collectionName)
|
||||
.doc(documentName)
|
||||
.update({ [field]: value })
|
||||
.update({ [field]: replaceTimestampInString(value) })
|
||||
.then(() => {
|
||||
if (typeof callbackStateVariable !== 'undefined')
|
||||
callbackStateVariable.setString('ok');
|
||||
@@ -209,10 +436,7 @@ namespace gdjs {
|
||||
callbackStateVariable.setString('ok');
|
||||
|
||||
if (callbackValueVariable)
|
||||
gdjs.evtTools.network._objectToVariable(
|
||||
doc.data(),
|
||||
callbackValueVariable
|
||||
);
|
||||
callbackValueVariable.fromJSObject(doc.data());
|
||||
})
|
||||
.catch((error) => {
|
||||
if (typeof callbackStateVariable !== 'undefined')
|
||||
@@ -245,10 +469,7 @@ namespace gdjs {
|
||||
callbackStateVariable.setString('ok');
|
||||
|
||||
if (callbackValueVariable)
|
||||
gdjs.evtTools.network._objectToVariable(
|
||||
doc.get(field),
|
||||
callbackValueVariable
|
||||
);
|
||||
callbackValueVariable.fromJSObject(doc.get(field));
|
||||
})
|
||||
.catch((error) => {
|
||||
if (typeof callbackStateVariable !== 'undefined')
|
||||
@@ -329,6 +550,8 @@ namespace gdjs {
|
||||
* @param collectionName - The collection where to count documents.
|
||||
* @param [callbackValueVariable] - The variable where to store the result.
|
||||
* @param [callbackStateVariable] - The variable where to store if the operation was successful.
|
||||
*
|
||||
* @deprecated Use a query without filters instead.
|
||||
*/
|
||||
export const listDocuments = (
|
||||
collectionName: string,
|
||||
@@ -346,9 +569,8 @@ namespace gdjs {
|
||||
);
|
||||
|
||||
if (callbackValueVariable)
|
||||
gdjs.evtTools.network._objectToVariable(
|
||||
snapshot.docs.map((doc) => doc.id),
|
||||
callbackValueVariable
|
||||
callbackValueVariable.fromJSObject(
|
||||
snapshot.docs.map((doc) => doc.id)
|
||||
);
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -356,6 +578,28 @@ namespace gdjs {
|
||||
callbackStateVariable.setString(error.message);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a special string replaced by a firebase serverTimestamp field value.
|
||||
*/
|
||||
export const getServerTimestamp = () =>
|
||||
'[{__FIREBASE_SERVERSIDE_TIMESTAMP}]';
|
||||
|
||||
const replaceTimestampInString = (str: any) => {
|
||||
if (str === '[{__FIREBASE_SERVERSIDE_TIMESTAMP}]')
|
||||
return firebase.firestore.FieldValue.serverTimestamp();
|
||||
else return str;
|
||||
};
|
||||
|
||||
const replaceTimestampsInObject = (object: object): object => {
|
||||
for (const i in object) {
|
||||
const item = object[i];
|
||||
if (typeof item === 'object') replaceTimestampsInObject(item);
|
||||
else if (item === '[{__FIREBASE_SERVERSIDE_TIMESTAMP}]')
|
||||
object[i] = firebase.firestore.FieldValue.serverTimestamp();
|
||||
}
|
||||
return object;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -20,11 +20,7 @@ namespace gdjs {
|
||||
firebase
|
||||
.database()
|
||||
.ref(path)
|
||||
.set(
|
||||
JSON.parse(
|
||||
gdjs.evtTools.network.variableStructureToJSON(variable)
|
||||
)
|
||||
)
|
||||
.set(variable.toJSObject())
|
||||
.then(() => {
|
||||
if (typeof callbackStateVariable !== 'undefined')
|
||||
callbackStateVariable.setString('ok');
|
||||
@@ -76,11 +72,7 @@ namespace gdjs {
|
||||
firebase
|
||||
.database()
|
||||
.ref(path)
|
||||
.update(
|
||||
JSON.parse(
|
||||
gdjs.evtTools.network.variableStructureToJSON(variable)
|
||||
)
|
||||
)
|
||||
.update(variable.toJSObject())
|
||||
.then(() => {
|
||||
if (typeof callbackStateVariable !== 'undefined')
|
||||
callbackStateVariable.setString('ok');
|
||||
@@ -190,10 +182,7 @@ namespace gdjs {
|
||||
callbackStateVariable.setString('ok');
|
||||
|
||||
if (typeof callbackValueVariable !== 'undefined')
|
||||
gdjs.evtTools.network._objectToVariable(
|
||||
snapshot.val(),
|
||||
callbackValueVariable
|
||||
);
|
||||
callbackValueVariable.fromJSObject(snapshot.val());
|
||||
})
|
||||
.catch((error) => {
|
||||
if (typeof callbackStateVariable !== 'undefined')
|
||||
@@ -223,10 +212,7 @@ namespace gdjs {
|
||||
callbackStateVariable.setString('ok');
|
||||
|
||||
if (typeof callbackValueVariable !== 'undefined')
|
||||
gdjs.evtTools.network._objectToVariable(
|
||||
snapshot.val()[field],
|
||||
callbackValueVariable
|
||||
);
|
||||
callbackValueVariable.fromJSObject(snapshot.val()[field]);
|
||||
})
|
||||
.catch((error) => {
|
||||
if (typeof callbackStateVariable !== 'undefined')
|
||||
|
@@ -24,10 +24,7 @@ namespace gdjs {
|
||||
.httpsCallable(httpFunctionName)(parameter)
|
||||
.then((response) => {
|
||||
if (callbackValueVariable)
|
||||
gdjs.evtTools.network._objectToVariable(
|
||||
response.data,
|
||||
callbackValueVariable
|
||||
);
|
||||
callbackValueVariable.fromJSObject(response.data);
|
||||
|
||||
if (typeof callbackStateVariable !== 'undefined')
|
||||
callbackStateVariable.setString('ok');
|
||||
|
@@ -18,9 +18,7 @@ namespace gdjs {
|
||||
* @param variable - A structure defining the default variables.
|
||||
*/
|
||||
export const setDefaultConfig = (variable: gdjs.Variable) => {
|
||||
firebase.remoteConfig().defaultConfig = JSON.parse(
|
||||
gdjs.evtTools.network.variableStructureToJSON(variable)
|
||||
);
|
||||
firebase.remoteConfig().defaultConfig = variable.toJSObject();
|
||||
};
|
||||
|
||||
gdjs.evtTools.firebaseTools.onAppCreated.push(() => {
|
||||
|
@@ -1048,6 +1048,339 @@ module.exports = {
|
||||
|
||||
/* ====== CLOUD FIRESTORE ====== */
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'ServerTimestamp',
|
||||
_('Get server timestamp'),
|
||||
_(
|
||||
'Set a field to the timstamp on the server when the request arrives there'
|
||||
),
|
||||
_('Firebase/Cloud Firestore'),
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Firebase/A_firebasejs/A_firebase-base.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/A_firebasejs/B_firebase-firestore.js'
|
||||
)
|
||||
.addIncludeFile('Extensions/Firebase/B_firebasetools/C_firebasetools.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/B_firebasetools/D_cloudfirestoretools.js'
|
||||
)
|
||||
.setFunctionName(
|
||||
'gdjs.evtTools.firebaseTools.firestore.getServerTimestamp'
|
||||
);
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'FirestoreStartQuery',
|
||||
_('Start a query'),
|
||||
_(
|
||||
'Start a query on a collection. ' +
|
||||
'A query allows to get a filtered and ordered list of documents in a collection.'
|
||||
),
|
||||
_('Create a query named _PARAM0_ for collection _PARAM1_'),
|
||||
_('Firebase/Cloud Firestore/Queries/Initialize'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
.addParameter('string', _('Query name'), '', false)
|
||||
.addParameter('string', _('Collection'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Firebase/A_firebasejs/A_firebase-base.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/A_firebasejs/B_firebase-firestore.js'
|
||||
)
|
||||
.addIncludeFile('Extensions/Firebase/B_firebasetools/C_firebasetools.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/B_firebasetools/D_cloudfirestoretools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.firebaseTools.firestore.startQuery');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'FirestoreStartQueryFrom',
|
||||
_('Start a query from another query'),
|
||||
_('Start a query with the same collection and filters as another one.'),
|
||||
_('Create a query named _PARAM0_ from query _PARAM1_'),
|
||||
_('Firebase/Cloud Firestore/Queries/Initialize'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
.addParameter('string', _('Query name'), '', false)
|
||||
.addParameter('string', _('Source query name'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Firebase/A_firebasejs/A_firebase-base.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/A_firebasejs/B_firebase-firestore.js'
|
||||
)
|
||||
.addIncludeFile('Extensions/Firebase/B_firebasetools/C_firebasetools.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/B_firebasetools/D_cloudfirestoretools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.firebaseTools.firestore.startQueryFrom');
|
||||
|
||||
const operatorDesc =
|
||||
'See the [Firebase documentation]' +
|
||||
'(https://firebase.google.com/docs/firestore/query-data/queries#query_operators) to understand the operators. ' +
|
||||
"It is important as some [don't work when combined]" +
|
||||
'(https://firebase.google.com/docs/firestore/query-data/queries#query_limitations).';
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'FirestoreQueryWhereNumber',
|
||||
_('Filter by field value'),
|
||||
_('Only match the documents that have a field passing a check.'),
|
||||
_(
|
||||
'Filter query _PARAM0_ to remove documents whose field _PARAM1_ is not _PARAM2__PARAM3_'
|
||||
),
|
||||
_('Firebase/Cloud Firestore/Queries/Filters'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
.addParameter('string', _('Query name'), '', false)
|
||||
.addParameter('string', _('Field to check'), '', false)
|
||||
.addParameter(
|
||||
'stringWithSelector',
|
||||
_('Check type'),
|
||||
'["<", "<=", "==", "!=", ">=", ">", "array-contains"]',
|
||||
false
|
||||
)
|
||||
.setParameterLongDescription(operatorDesc)
|
||||
.addParameter('expression', _('Value to check'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Firebase/A_firebasejs/A_firebase-base.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/A_firebasejs/B_firebase-firestore.js'
|
||||
)
|
||||
.addIncludeFile('Extensions/Firebase/B_firebasetools/C_firebasetools.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/B_firebasetools/D_cloudfirestoretools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.firebaseTools.firestore.queryWhere');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'FirestoreQueryWhereText',
|
||||
_('Filter by field text'),
|
||||
_('Only match the documents that have a field passing a check.'),
|
||||
_(
|
||||
'Filter query _PARAM0_ to remove documents whose field _PARAM1_ is not _PARAM2__PARAM3_'
|
||||
),
|
||||
_('Firebase/Cloud Firestore/Queries/Filters'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
.addParameter('string', _('Query name'), '', false)
|
||||
.addParameter('string', _('Field to check'), '', false)
|
||||
.addParameter(
|
||||
'stringWithSelector',
|
||||
_('Check type'),
|
||||
'["<", "<=", "==", "!=", ">=", ">", "array-contains"]',
|
||||
false
|
||||
)
|
||||
.setParameterLongDescription(operatorDesc)
|
||||
.addParameter('string', _('Text to check'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Firebase/A_firebasejs/A_firebase-base.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/A_firebasejs/B_firebase-firestore.js'
|
||||
)
|
||||
.addIncludeFile('Extensions/Firebase/B_firebasetools/C_firebasetools.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/B_firebasetools/D_cloudfirestoretools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.firebaseTools.firestore.queryWhere');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'FirestoreQueryOrderBy',
|
||||
_('Order by field value'),
|
||||
_('Orders all documents in the query by a the value of a field.'),
|
||||
_('Order query _PARAM0_ by field _PARAM1_ (direction: _PARAM2_)'),
|
||||
_('Firebase/Cloud Firestore/Queries/Filters'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
.addParameter('string', _('Query name'), '', false)
|
||||
.addParameter('string', _('Field to order by'), '', false)
|
||||
.setParameterLongDescription(
|
||||
'Note that [some limitations may apply when combined with a where query](https://firebase.google.com/docs/firestore/query-data/order-limit-data#limitations).'
|
||||
)
|
||||
.addParameter(
|
||||
'stringWithSelector',
|
||||
_('Direction (ascending or descending)'),
|
||||
'["asc", "desc"]',
|
||||
false
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Firebase/A_firebasejs/A_firebase-base.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/A_firebasejs/B_firebase-firestore.js'
|
||||
)
|
||||
.addIncludeFile('Extensions/Firebase/B_firebasetools/C_firebasetools.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/B_firebasetools/D_cloudfirestoretools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.firebaseTools.firestore.queryOrderBy');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'FirestoreQueryLimit',
|
||||
_('Limit amount of documents'),
|
||||
_(
|
||||
'Limits the amount of documents returned by the query. Can only be used after an order filter.'
|
||||
),
|
||||
_(
|
||||
'Limit query _PARAM0_ to _PARAM1_ documents (begin from the end: _PARAM2_)'
|
||||
),
|
||||
_('Firebase/Cloud Firestore/Queries/Filters'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
.addParameter('string', _('Query name'), '', false)
|
||||
.addParameter('expression', _('Amount to limit by'), '', false)
|
||||
.addParameter('yesorno', _('Begin from the end'), '', false)
|
||||
.setDefaultValue('false')
|
||||
.setParameterLongDescription(
|
||||
'If yes, the last X documents will be kept, else the first X documents will be kept.'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Firebase/A_firebasejs/A_firebase-base.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/A_firebasejs/B_firebase-firestore.js'
|
||||
)
|
||||
.addIncludeFile('Extensions/Firebase/B_firebasetools/C_firebasetools.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/B_firebasetools/D_cloudfirestoretools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.firebaseTools.firestore.queryLimit');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'FirestoreQuerySkipSome',
|
||||
_('Skip some documents'),
|
||||
_(
|
||||
'Removes documents before or after a certain value on the field ordered by in a query. Can only be used after an order filter.'
|
||||
),
|
||||
_(
|
||||
'Skip documents with fields (before: _PARAM2_) value _PARAM1_ in query _PARAM0_ (include documents at that value: _PARAM3_)'
|
||||
),
|
||||
_('Firebase/Cloud Firestore/Queries/Filters'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
.addParameter('string', _('Query name'), '', false)
|
||||
.addParameter(
|
||||
'expression',
|
||||
_('The value of the field ordered by to skip after'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
.addParameter('yesorno', _('Skip documents before?'), '', false)
|
||||
.setParameterLongDescription(
|
||||
'If yes, the documents with a bigger field value will be kept, else the documents with a smaller field value be kept by the query.'
|
||||
)
|
||||
.addParameter(
|
||||
'yesorno',
|
||||
_(
|
||||
'Include documents which field value equals the value to skip after?'
|
||||
),
|
||||
'',
|
||||
false
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Firebase/A_firebasejs/A_firebase-base.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/A_firebasejs/B_firebase-firestore.js'
|
||||
)
|
||||
.addIncludeFile('Extensions/Firebase/B_firebasetools/C_firebasetools.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/B_firebasetools/D_cloudfirestoretools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.firebaseTools.firestore.querySkipSome');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'FirestoreExecuteQuery',
|
||||
_('Execute a query'),
|
||||
_('Execute the query and store results in a scene variable.'),
|
||||
_(
|
||||
'Execute query _PARAM0_ and store results into _PARAM1_ (store result state in _PARAM2_)'
|
||||
),
|
||||
_('Firebase/Cloud Firestore/Queries/Execute'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
.addParameter('string', _('Query name'), '', false)
|
||||
.addParameter(
|
||||
'scenevar',
|
||||
_('Callback variable where to load the results'),
|
||||
'',
|
||||
true
|
||||
)
|
||||
.setParameterLongDescription(
|
||||
'See the shape of the returned data on [the wiki page](http://wiki.compilgames.net/doku.php/gdevelop5/all-features/firebase/firestore#the_query_result).'
|
||||
)
|
||||
.addParameter(
|
||||
'scenevar',
|
||||
_('Callback variable with state (ok or error message)'),
|
||||
'',
|
||||
true
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Firebase/A_firebasejs/A_firebase-base.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/A_firebasejs/B_firebase-firestore.js'
|
||||
)
|
||||
.addIncludeFile('Extensions/Firebase/B_firebasetools/C_firebasetools.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/B_firebasetools/D_cloudfirestoretools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.firebaseTools.firestore.executeQuery');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'FirestoreWatchQuery',
|
||||
_('Watch a query'),
|
||||
_(
|
||||
'Executes the query every time a new documents starts ' +
|
||||
'or stops matching the query, or a document that matches the query has been changed.'
|
||||
),
|
||||
_(
|
||||
'Watch and automatically execute query _PARAM0_ and store results into _PARAM1_ (store result state in _PARAM2_)'
|
||||
),
|
||||
_('Firebase/Cloud Firestore/Queries/Execute'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
.addParameter('string', _('Query name'), '', false)
|
||||
.addParameter(
|
||||
'scenevar',
|
||||
_('Callback variable where to load the results'),
|
||||
'',
|
||||
true
|
||||
)
|
||||
.setParameterLongDescription(
|
||||
'See the shape of the returned data on [the wiki page]().'
|
||||
)
|
||||
.addParameter(
|
||||
'scenevar',
|
||||
_('Callback variable with state (ok or error message)'),
|
||||
'',
|
||||
true
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Firebase/A_firebasejs/A_firebase-base.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/A_firebasejs/B_firebase-firestore.js'
|
||||
)
|
||||
.addIncludeFile('Extensions/Firebase/B_firebasetools/C_firebasetools.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/B_firebasetools/D_cloudfirestoretools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.firebaseTools.firestore.watchQuery');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'FirestoreEnablePersistence',
|
||||
@@ -1152,7 +1485,7 @@ module.exports = {
|
||||
_(
|
||||
'Write _PARAM2_ to firestore in document _PARAM1_ of collection _PARAM0_ (store result state in _PARAM3_)'
|
||||
),
|
||||
_('Firebase/Cloud Firestore'),
|
||||
_('Firebase/Cloud Firestore/Documents'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
@@ -1176,6 +1509,37 @@ module.exports = {
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.firebaseTools.firestore.writeDocument');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'FirestoreAddDocument',
|
||||
_('Add a document to firestore'),
|
||||
_('Adds a document (variable) to cloud firestore with a unique name.'),
|
||||
_(
|
||||
'Add _PARAM1_ to firestore collection _PARAM0_ (store result state in _PARAM2_)'
|
||||
),
|
||||
_('Firebase/Cloud Firestore/Documents'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
.addParameter('string', _('Collection'), '', false)
|
||||
.addParameter('scenevar', _('Variable to write'), '', false)
|
||||
.addParameter(
|
||||
'scenevar',
|
||||
_('Callback variable with state (ok or error)'),
|
||||
'',
|
||||
true
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Firebase/A_firebasejs/A_firebase-base.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/A_firebasejs/B_firebase-firestore.js'
|
||||
)
|
||||
.addIncludeFile('Extensions/Firebase/B_firebasetools/C_firebasetools.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Firebase/B_firebasetools/D_cloudfirestoretools.js'
|
||||
)
|
||||
.setFunctionName('gdjs.evtTools.firebaseTools.firestore.addDocument');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'FirestoreWriteField',
|
||||
@@ -1184,7 +1548,7 @@ module.exports = {
|
||||
_(
|
||||
'Write _PARAM3_ to firestore in field _PARAM2_ of document _PARAM1_ in collection _PARAM0_ (store result state in _PARAM4_, Merge: _PARAM5_)'
|
||||
),
|
||||
_('Firebase/Cloud Firestore'),
|
||||
_('Firebase/Cloud Firestore/Fields'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
@@ -1218,7 +1582,7 @@ module.exports = {
|
||||
_(
|
||||
'Update firestore document _PARAM1_ in collection _PARAM0_ with _PARAM2_ (store result state in _PARAM3_)'
|
||||
),
|
||||
_('Firebase/Cloud Firestore'),
|
||||
_('Firebase/Cloud Firestore/Documents'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
@@ -1250,7 +1614,7 @@ module.exports = {
|
||||
_(
|
||||
'Update field _PARAM2_ of firestore document _PARAM1_ in collection _PARAM0_ with _PARAM3_ (store result state in _PARAM4_)'
|
||||
),
|
||||
_('Firebase/Cloud Firestore'),
|
||||
_('Firebase/Cloud Firestore/Fields'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
@@ -1283,7 +1647,7 @@ module.exports = {
|
||||
_(
|
||||
'Delete firestore document _PARAM1_ in collection _PARAM0_ (store result state in _PARAM2_)'
|
||||
),
|
||||
_('Firebase/Cloud Firestore'),
|
||||
_('Firebase/Cloud Firestore/Documents'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
@@ -1314,7 +1678,7 @@ module.exports = {
|
||||
_(
|
||||
'Delete field _PARAM2_ of firestore document _PARAM1_ in collection _PARAM0_ with (store result state in _PARAM3_)'
|
||||
),
|
||||
_('Firebase/Cloud Firestore'),
|
||||
_('Firebase/Cloud Firestore/Fields'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
@@ -1346,7 +1710,7 @@ module.exports = {
|
||||
_(
|
||||
'Load firestore document _PARAM1_ from collection _PARAM0_ into _PARAM2_ (store result state in _PARAM3_)'
|
||||
),
|
||||
_('Firebase/Cloud Firestore'),
|
||||
_('Firebase/Cloud Firestore/Documents'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
@@ -1383,7 +1747,7 @@ module.exports = {
|
||||
_(
|
||||
'Load field _PARAM2_ of firestore document _PARAM1_ in collection _PARAM0_ into _PARAM3_ (store result state in _PARAM4_)'
|
||||
),
|
||||
_('Firebase/Cloud Firestore'),
|
||||
_('Firebase/Cloud Firestore/Fields'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
@@ -1423,7 +1787,7 @@ module.exports = {
|
||||
_(
|
||||
'Check for existence of _PARAM1_ in collection _PARAM0_ and store result in _PARAM2_ (store result state in _PARAM3_)'
|
||||
),
|
||||
_('Firebase/Cloud Firestore'),
|
||||
_('Firebase/Cloud Firestore/Documents'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
@@ -1462,7 +1826,7 @@ module.exports = {
|
||||
_(
|
||||
'Check for existence of _PARAM2_ in document _PARAM1_ of collection _PARAM0_ and store result in _PARAM3_ (store result state in _PARAM4_)'
|
||||
),
|
||||
_('Firebase/Cloud Firestore'),
|
||||
_('Firebase/Cloud Firestore/Fields'),
|
||||
'JsPlatform/Extensions/firebase.png',
|
||||
'JsPlatform/Extensions/firebase.png'
|
||||
)
|
||||
@@ -1519,6 +1883,7 @@ module.exports = {
|
||||
'',
|
||||
true
|
||||
)
|
||||
.setHidden()
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Firebase/A_firebasejs/A_firebase-base.js')
|
||||
.addIncludeFile(
|
||||
|
@@ -15,7 +15,7 @@ const firebaseConfig = {
|
||||
/**
|
||||
* Turns a callback variable into a promise.
|
||||
* @param {(callbackVariable: {setString: (result: "ok" | string) => void}, result: gdjs.Variable) => any} executor
|
||||
* @returns
|
||||
* @returns {Promise<gdjs.Variable>}
|
||||
*/
|
||||
const promisifyCallbackVariables = (executor) =>
|
||||
new Promise((done, err) => {
|
||||
@@ -32,11 +32,11 @@ const promisifyCallbackVariables = (executor) =>
|
||||
});
|
||||
|
||||
/** A complex variable using all variables types. */
|
||||
const variable = new gdjs.Variable();
|
||||
gdjs.evtTools.network._objectToVariable(
|
||||
{ my: 'test', object: { with: 'all', types: 2 }, it: ['is', true] },
|
||||
variable
|
||||
);
|
||||
const variable = new gdjs.Variable().fromJSObject({
|
||||
my: 'test',
|
||||
object: { with: 'all', types: 2 },
|
||||
it: ['is', true],
|
||||
});
|
||||
|
||||
// The tests require an internet connection, as a real Firebase instance is used.
|
||||
const describeIfOnline = navigator.onLine ? describe : describe.skip;
|
||||
@@ -126,13 +126,9 @@ describeIfOnline('Firebase extension end-to-end tests', function () {
|
||||
goodbye: 'Goodbye',
|
||||
});
|
||||
|
||||
const updater = new gdjs.Variable();
|
||||
gdjs.evtTools.network._objectToVariable(
|
||||
{
|
||||
goodbye: 'See you later',
|
||||
},
|
||||
updater
|
||||
);
|
||||
const updater = new gdjs.Variable().fromJSObject({
|
||||
goodbye: 'See you later',
|
||||
});
|
||||
|
||||
await promisifyCallbackVariables((callback) =>
|
||||
gdjs.evtTools.firebaseTools.database.updateVariable(
|
||||
@@ -225,173 +221,299 @@ describeIfOnline('Firebase extension end-to-end tests', function () {
|
||||
});
|
||||
|
||||
describe('Cloud Firestore', () => {
|
||||
it('should write and read back a variable from Firestore', async () => {
|
||||
await promisifyCallbackVariables((callback) => {
|
||||
gdjs.evtTools.firebaseTools.firestore.writeDocument(
|
||||
namespace,
|
||||
'variable',
|
||||
variable,
|
||||
callback
|
||||
);
|
||||
});
|
||||
|
||||
const fetchedVariable = await promisifyCallbackVariables(
|
||||
(callback, result) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.getDocument(
|
||||
describe('Base read/write operations', () => {
|
||||
it('should write and read back a variable from Firestore', async () => {
|
||||
await promisifyCallbackVariables((callback) => {
|
||||
gdjs.evtTools.firebaseTools.firestore.writeDocument(
|
||||
namespace,
|
||||
'variable',
|
||||
result,
|
||||
variable,
|
||||
callback
|
||||
)
|
||||
);
|
||||
);
|
||||
});
|
||||
|
||||
expect(fetchedVariable).to.eql(variable);
|
||||
});
|
||||
|
||||
it('should write and read back a field from Firestore', async function () {
|
||||
await promisifyCallbackVariables((callback) => {
|
||||
gdjs.evtTools.firebaseTools.firestore.writeField(
|
||||
namespace,
|
||||
'field',
|
||||
'hello',
|
||||
1,
|
||||
callback
|
||||
const fetchedVariable = await promisifyCallbackVariables(
|
||||
(callback, result) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.getDocument(
|
||||
namespace,
|
||||
'variable',
|
||||
result,
|
||||
callback
|
||||
)
|
||||
);
|
||||
|
||||
expect(fetchedVariable).to.eql(variable);
|
||||
});
|
||||
|
||||
const fetchedVariable = await promisifyCallbackVariables(
|
||||
(callback, result) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.getField(
|
||||
it('should write and read back a field from Firestore', async function () {
|
||||
await promisifyCallbackVariables((callback) => {
|
||||
gdjs.evtTools.firebaseTools.firestore.writeField(
|
||||
namespace,
|
||||
'field',
|
||||
'hello',
|
||||
result,
|
||||
1,
|
||||
callback
|
||||
);
|
||||
});
|
||||
|
||||
const fetchedVariable = await promisifyCallbackVariables(
|
||||
(callback, result) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.getField(
|
||||
namespace,
|
||||
'field',
|
||||
'hello',
|
||||
result,
|
||||
callback
|
||||
)
|
||||
);
|
||||
|
||||
expect(fetchedVariable.getType()).to.be.string('number');
|
||||
expect(fetchedVariable.getAsNumber()).to.be.equal(1);
|
||||
});
|
||||
|
||||
it('should update a field from Firestore', async function () {
|
||||
const doc = firebase.firestore().doc(namespace + '/update');
|
||||
|
||||
// Populate with data to update
|
||||
await doc.set({ hello: 'Hello', goodbye: 'Goodbye' });
|
||||
|
||||
await promisifyCallbackVariables((callback) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.updateField(
|
||||
namespace,
|
||||
'update',
|
||||
'hello',
|
||||
'Good day',
|
||||
callback
|
||||
)
|
||||
);
|
||||
);
|
||||
expect((await doc.get()).data()).to.eql({
|
||||
hello: 'Good day',
|
||||
goodbye: 'Goodbye',
|
||||
});
|
||||
|
||||
expect(fetchedVariable.getType()).to.be.string('number');
|
||||
expect(fetchedVariable.getAsNumber()).to.be.equal(1);
|
||||
});
|
||||
|
||||
it('should update a field from Firestore', async function () {
|
||||
const doc = firebase.firestore().doc(namespace + '/update');
|
||||
|
||||
// Populate with data to update
|
||||
await doc.set({ hello: 'Hello', goodbye: 'Goodbye' });
|
||||
|
||||
await promisifyCallbackVariables((callback) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.updateField(
|
||||
namespace,
|
||||
'update',
|
||||
'hello',
|
||||
'Good day',
|
||||
callback
|
||||
)
|
||||
);
|
||||
expect((await doc.get()).data()).to.eql({
|
||||
hello: 'Good day',
|
||||
goodbye: 'Goodbye',
|
||||
});
|
||||
|
||||
const updater = new gdjs.Variable();
|
||||
gdjs.evtTools.network._objectToVariable(
|
||||
{
|
||||
const updater = new gdjs.Variable().fromJSObject({
|
||||
goodbye: 'See you later',
|
||||
},
|
||||
updater
|
||||
);
|
||||
});
|
||||
|
||||
await promisifyCallbackVariables((callback) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.updateDocument(
|
||||
namespace,
|
||||
'update',
|
||||
updater,
|
||||
callback
|
||||
)
|
||||
);
|
||||
expect((await doc.get()).data()).to.eql({
|
||||
hello: 'Good day',
|
||||
goodbye: 'See you later',
|
||||
await promisifyCallbackVariables((callback) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.updateDocument(
|
||||
namespace,
|
||||
'update',
|
||||
updater,
|
||||
callback
|
||||
)
|
||||
);
|
||||
expect((await doc.get()).data()).to.eql({
|
||||
hello: 'Good day',
|
||||
goodbye: 'See you later',
|
||||
});
|
||||
});
|
||||
|
||||
it('should delete and detect presence of a field from Firestore', async function () {
|
||||
const doc = firebase.firestore().doc(namespace + '/delete');
|
||||
|
||||
// Populate with data to delete
|
||||
await doc.set({ hello: 'Hello', goodbye: 'Goodbye' });
|
||||
|
||||
expect(
|
||||
(
|
||||
await promisifyCallbackVariables((callback, result) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.hasDocument(
|
||||
namespace,
|
||||
'delete',
|
||||
result,
|
||||
callback
|
||||
)
|
||||
)
|
||||
).getValue()
|
||||
).to.be.ok();
|
||||
|
||||
expect(
|
||||
(
|
||||
await promisifyCallbackVariables((callback, result) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.hasField(
|
||||
namespace,
|
||||
'delete',
|
||||
'hello',
|
||||
result,
|
||||
callback
|
||||
)
|
||||
)
|
||||
).getValue()
|
||||
).to.be.ok();
|
||||
|
||||
await promisifyCallbackVariables((callback) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.deleteField(
|
||||
namespace,
|
||||
'delete',
|
||||
'hello',
|
||||
callback
|
||||
)
|
||||
);
|
||||
|
||||
expect(
|
||||
(
|
||||
await promisifyCallbackVariables((callback, result) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.hasField(
|
||||
namespace,
|
||||
'delete',
|
||||
'hello',
|
||||
result,
|
||||
callback
|
||||
)
|
||||
)
|
||||
).getValue()
|
||||
).to.not.be.ok();
|
||||
|
||||
await promisifyCallbackVariables((callback) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.deleteDocument(
|
||||
namespace,
|
||||
'delete',
|
||||
callback
|
||||
)
|
||||
);
|
||||
|
||||
expect(
|
||||
(
|
||||
await promisifyCallbackVariables((callback, result) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.hasDocument(
|
||||
namespace,
|
||||
'delete',
|
||||
result,
|
||||
callback
|
||||
)
|
||||
)
|
||||
).getValue()
|
||||
).to.not.be.ok();
|
||||
});
|
||||
|
||||
it('should be able to use server timestamps', async () => {
|
||||
await promisifyCallbackVariables((callback) => {
|
||||
gdjs.evtTools.firebaseTools.firestore.writeField(
|
||||
namespace,
|
||||
'field',
|
||||
'timestamp',
|
||||
gdjs.evtTools.firebaseTools.firestore.getServerTimestamp(),
|
||||
callback
|
||||
);
|
||||
});
|
||||
|
||||
expect(
|
||||
(
|
||||
await firebase
|
||||
.firestore()
|
||||
.doc(namespace + '/field')
|
||||
.get()
|
||||
).get('timestamp', { serverTimestamps: 'estimate' })
|
||||
).to.be.an(firebase.firestore.Timestamp);
|
||||
});
|
||||
});
|
||||
|
||||
it('should delete and detect presence of a field from Firestore', async function () {
|
||||
const doc = firebase.firestore().doc(namespace + '/delete');
|
||||
describe('Firestore Queries', async () => {
|
||||
it('can get a list of documents from the database', async () => {
|
||||
const subcollection = namespace + '/collection/sub';
|
||||
await firebase
|
||||
.firestore()
|
||||
.doc(subcollection + '/doc1')
|
||||
.set({ index: 2, val: 2 });
|
||||
await firebase
|
||||
.firestore()
|
||||
.doc(subcollection + '/doc2')
|
||||
.set({ index: 1, val: 2 });
|
||||
await firebase
|
||||
.firestore()
|
||||
.doc(subcollection + '/doc3')
|
||||
.set({ index: 3, val: 1 });
|
||||
|
||||
// Populate with data to delete
|
||||
await doc.set({ hello: 'Hello', goodbye: 'Goodbye' });
|
||||
|
||||
expect(
|
||||
(
|
||||
await promisifyCallbackVariables((callback, result) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.hasDocument(
|
||||
namespace,
|
||||
'delete',
|
||||
result,
|
||||
callback
|
||||
const executeQuery = async (query) =>
|
||||
(
|
||||
await promisifyCallbackVariables((callback, result) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.executeQuery(
|
||||
query,
|
||||
result,
|
||||
callback
|
||||
)
|
||||
)
|
||||
)
|
||||
).getValue()
|
||||
).to.be.ok();
|
||||
).toJSObject();
|
||||
|
||||
expect(
|
||||
(
|
||||
await promisifyCallbackVariables((callback, result) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.hasField(
|
||||
namespace,
|
||||
'delete',
|
||||
'hello',
|
||||
result,
|
||||
callback
|
||||
)
|
||||
)
|
||||
).getValue()
|
||||
).to.be.ok();
|
||||
// Empty query
|
||||
gdjs.evtTools.firebaseTools.firestore.startQuery('main', subcollection);
|
||||
expect(await executeQuery('main')).to.eql({
|
||||
size: 3,
|
||||
empty: false,
|
||||
docs: [
|
||||
{ id: 'doc1', data: { index: 2, val: 2 }, exists: true },
|
||||
{ id: 'doc2', data: { index: 1, val: 2 }, exists: true },
|
||||
{ id: 'doc3', data: { index: 3, val: 1 }, exists: true },
|
||||
],
|
||||
});
|
||||
|
||||
await promisifyCallbackVariables((callback) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.deleteField(
|
||||
namespace,
|
||||
'delete',
|
||||
'hello',
|
||||
callback
|
||||
)
|
||||
);
|
||||
// Query with selector fitler
|
||||
gdjs.evtTools.firebaseTools.firestore.startQueryFrom(
|
||||
'selector',
|
||||
'main'
|
||||
);
|
||||
gdjs.evtTools.firebaseTools.firestore.queryWhere(
|
||||
'selector',
|
||||
'index',
|
||||
'>',
|
||||
1
|
||||
);
|
||||
expect(await executeQuery('selector')).to.eql({
|
||||
size: 2,
|
||||
empty: false,
|
||||
docs: [
|
||||
{ id: 'doc1', data: { index: 2, val: 2 }, exists: true },
|
||||
{ id: 'doc3', data: { index: 3, val: 1 }, exists: true },
|
||||
],
|
||||
});
|
||||
|
||||
expect(
|
||||
(
|
||||
await promisifyCallbackVariables((callback, result) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.hasField(
|
||||
namespace,
|
||||
'delete',
|
||||
'hello',
|
||||
result,
|
||||
callback
|
||||
)
|
||||
)
|
||||
).getValue()
|
||||
).to.not.be.ok();
|
||||
// Query with order filter
|
||||
gdjs.evtTools.firebaseTools.firestore.startQueryFrom('order', 'main');
|
||||
gdjs.evtTools.firebaseTools.firestore.queryOrderBy(
|
||||
'order',
|
||||
'index',
|
||||
'desc'
|
||||
);
|
||||
expect(await executeQuery('order')).to.eql({
|
||||
size: 3,
|
||||
empty: false,
|
||||
docs: [
|
||||
{ id: 'doc3', data: { index: 3, val: 1 }, exists: true },
|
||||
{ id: 'doc1', data: { index: 2, val: 2 }, exists: true },
|
||||
{ id: 'doc2', data: { index: 1, val: 2 }, exists: true },
|
||||
],
|
||||
});
|
||||
|
||||
await promisifyCallbackVariables((callback) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.deleteDocument(
|
||||
namespace,
|
||||
'delete',
|
||||
callback
|
||||
)
|
||||
);
|
||||
// Query with limit filter
|
||||
gdjs.evtTools.firebaseTools.firestore.startQueryFrom('limit', 'order');
|
||||
gdjs.evtTools.firebaseTools.firestore.queryLimit('limit', 2, true);
|
||||
expect(await executeQuery('limit')).to.eql({
|
||||
size: 2,
|
||||
empty: false,
|
||||
docs: [
|
||||
{ id: 'doc1', data: { index: 2, val: 2 }, exists: true },
|
||||
{ id: 'doc2', data: { index: 1, val: 2 }, exists: true },
|
||||
],
|
||||
});
|
||||
|
||||
expect(
|
||||
(
|
||||
await promisifyCallbackVariables((callback, result) =>
|
||||
gdjs.evtTools.firebaseTools.firestore.hasDocument(
|
||||
namespace,
|
||||
'delete',
|
||||
result,
|
||||
callback
|
||||
)
|
||||
)
|
||||
).getValue()
|
||||
).to.not.be.ok();
|
||||
// Query with skip some filter
|
||||
gdjs.evtTools.firebaseTools.firestore.startQueryFrom('skip', 'order');
|
||||
gdjs.evtTools.firebaseTools.firestore.querySkipSome(
|
||||
'skip',
|
||||
2,
|
||||
true,
|
||||
true
|
||||
);
|
||||
expect(await executeQuery('skip')).to.eql({
|
||||
size: 2,
|
||||
empty: false,
|
||||
docs: [
|
||||
{ id: 'doc3', data: { index: 3, val: 1 }, exists: true },
|
||||
{ id: 'doc1', data: { index: 2, val: 2 }, exists: true },
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Delete the temporary namespace to not bloat the DB
|
||||
|
@@ -231,6 +231,41 @@ namespace gdjs {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Disconnects from another p2p client.
|
||||
* @param id - The other client's ID.
|
||||
*/
|
||||
export const disconnectFromPeer = (id: string) => {
|
||||
if (connections[id]) connections[id].close();
|
||||
};
|
||||
|
||||
/**
|
||||
* Disconnects from all other p2p clients.
|
||||
*/
|
||||
export const disconnectFromAllPeers = () => {
|
||||
for (const connection of Object.values(connections)) connection.close();
|
||||
};
|
||||
|
||||
/**
|
||||
* Disconnects from all peers and the broker server.
|
||||
*/
|
||||
export const disconnectFromAll = () => {
|
||||
if (peer) {
|
||||
peer.destroy();
|
||||
peer = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Disconnects from the broker server, leaving the connections intact.
|
||||
*/
|
||||
export const disconnectFromBroker = () => {
|
||||
if (peer) {
|
||||
peer.disconnect();
|
||||
peer = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true when the event got triggered by another p2p client.
|
||||
* @param defaultDataLoss Is data loss allowed (accelerates event handling when true)?
|
||||
@@ -283,11 +318,7 @@ namespace gdjs {
|
||||
eventName: string,
|
||||
variable: gdjs.Variable
|
||||
) => {
|
||||
sendDataTo(
|
||||
id,
|
||||
eventName,
|
||||
gdjs.evtTools.network.variableStructureToJSON(variable)
|
||||
);
|
||||
sendDataTo(id, eventName, JSON.stringify(variable.toJSObject()));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -299,10 +330,7 @@ namespace gdjs {
|
||||
eventName: string,
|
||||
variable: gdjs.Variable
|
||||
) => {
|
||||
sendDataToAll(
|
||||
eventName,
|
||||
gdjs.evtTools.network.variableStructureToJSON(variable)
|
||||
);
|
||||
sendDataToAll(eventName, JSON.stringify(variable.toJSObject()));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -329,10 +357,7 @@ namespace gdjs {
|
||||
eventName: string,
|
||||
variable: gdjs.Variable
|
||||
) => {
|
||||
gdjs.evtTools.network.jsonToVariableStructure(
|
||||
getEventData(eventName),
|
||||
variable
|
||||
);
|
||||
variable.fromJSON(getEventData(eventName));
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -299,6 +299,69 @@ module.exports = {
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.getEventVariable');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'DisconnectFromPeer',
|
||||
_('Disconnect from a peer'),
|
||||
_('Disconnects this client from another client.'),
|
||||
_('Disconnect from client _PARAM0_'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg',
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
.addParameter('string', 'ID of the peer to disconnect from', '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/P2P/A_peer.js')
|
||||
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
|
||||
.setFunctionName('gdjs.evtTools.p2p.disconnectFromPeer');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'DisconnectFromAllPeers',
|
||||
_('Disconnect from all peers'),
|
||||
_('Disconnects this client from all other clients.'),
|
||||
_('Disconnect from all clients'),
|
||||
_('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.disconnectFromAllPeers');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'DisconnectFromBroker',
|
||||
_('Disconnect from broker'),
|
||||
_('Disconnects the client from the broker server.'),
|
||||
_('Disconnect the client from the broker'),
|
||||
_('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.disconnectFromBroker');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'DisconnectFromAll',
|
||||
_('Disconnect from all'),
|
||||
_(
|
||||
'Disconnects the client from the broker server and all other clients.'
|
||||
),
|
||||
_('Disconnect the client from the broker and other clients'),
|
||||
_('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.disconnectFromAll');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'GetEventData',
|
||||
@@ -319,9 +382,7 @@ module.exports = {
|
||||
.addStrExpression(
|
||||
'GetEventSender',
|
||||
_('Get event sender'),
|
||||
_(
|
||||
'Returns the id of the peer that triggered the event'
|
||||
),
|
||||
_('Returns the id of the peer that triggered the event'),
|
||||
_('P2P (experimental)'),
|
||||
'JsPlatform/Extensions/p2picon.svg'
|
||||
)
|
||||
|
@@ -134,9 +134,9 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) {
|
||||
.SetIncludeFile("PanelSpriteObject/PanelSpriteObject.h");
|
||||
|
||||
obj.AddAction("Angle",
|
||||
_("Angle"),
|
||||
_("Modify the angle of a Panel Sprite."),
|
||||
_("the angle"),
|
||||
"Angle",
|
||||
"Modify the angle of a Panel Sprite.",
|
||||
"the angle",
|
||||
_("Size and angle"),
|
||||
"res/actions/rotate24.png",
|
||||
"res/actions/rotate.png")
|
||||
@@ -149,9 +149,9 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) {
|
||||
.SetIncludeFile("PanelSpriteObject/PanelSpriteObject.h");
|
||||
|
||||
obj.AddCondition("Angle",
|
||||
_("Angle"),
|
||||
_("Check the angle of a Panel Sprite."),
|
||||
_("the angle"),
|
||||
"Angle",
|
||||
"Check the angle of a Panel Sprite.",
|
||||
"the angle",
|
||||
_("Size and angle"),
|
||||
"res/conditions/rotate24.png",
|
||||
"res/conditions/rotate.png")
|
||||
|
@@ -45,7 +45,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Move to a position"),
|
||||
_("Move the object to a position"),
|
||||
_("Move _PARAM0_ to _PARAM3_;_PARAM4_"),
|
||||
"",
|
||||
"Movement on the path",
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
@@ -61,7 +61,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Path found"),
|
||||
_("Check if a path has been found."),
|
||||
_("A path has been found for _PARAM0_"),
|
||||
"",
|
||||
"Movement on the path",
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -74,7 +74,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Destination reached"),
|
||||
_("Check if the destination was reached."),
|
||||
_("_PARAM0_ reached its destination"),
|
||||
"",
|
||||
"Movement on the path",
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -145,7 +145,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Acceleration"),
|
||||
_("Change the acceleration when moving the object"),
|
||||
_("the acceleration on the path"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -160,7 +160,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Acceleration"),
|
||||
_("Compare the acceleration when moving the object"),
|
||||
_("the acceleration"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -174,7 +174,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Maximum speed"),
|
||||
_("Change the maximum speed when moving the object"),
|
||||
_("the max. speed on the path"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -189,7 +189,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Maximum speed"),
|
||||
_("Compare the maximum speed when moving the object"),
|
||||
_("the max. speed"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -203,7 +203,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Speed"),
|
||||
_("Change the speed of the object on the path"),
|
||||
_("the speed on the path"),
|
||||
_("Path"),
|
||||
_("Movement on the path"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -215,10 +215,10 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
.SetIncludeFile("PathfindingBehavior/PathfindingRuntimeBehavior.h");
|
||||
|
||||
aut.AddCondition("Speed",
|
||||
_("Speed"),
|
||||
_("Compare the speed of the object on the path"),
|
||||
_("Speed on its path"),
|
||||
_("Compare the speed of the object on its path."),
|
||||
_("the speed"),
|
||||
_("Path"),
|
||||
_("Movement on the path"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -228,11 +228,25 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
.SetFunctionName("GetSpeed")
|
||||
.SetIncludeFile("PathfindingBehavior/PathfindingRuntimeBehavior.h");
|
||||
|
||||
aut.AddScopedCondition("MovementAngleIsAround",
|
||||
_("Angle of movement on its path"),
|
||||
_("Compare the angle of movement of an object on its path."),
|
||||
_("Angle of movement of _PARAM0_ is _PARAM2_ (tolerance"
|
||||
": _PARAM3_ degrees)"),
|
||||
_("Movement on the path"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
.AddParameter("expression", _("Angle, in degrees"))
|
||||
.AddParameter("expression", _("Tolerance, in degrees"));
|
||||
|
||||
aut.AddAction("AngularMaxSpeed",
|
||||
_("Angular maximum speed"),
|
||||
_("Change the maximum angular speed when moving the object"),
|
||||
_("the max. angular speed on the path"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -248,7 +262,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Angular maximum speed"),
|
||||
_("Compare the maximum angular speed when moving the object"),
|
||||
_("the max. angular speed"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -263,7 +277,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Rotation offset"),
|
||||
_("Change the rotation offset applied when moving the object"),
|
||||
_("the rotation offset on the path"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -278,7 +292,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Rotation offset"),
|
||||
_("Compare the rotation offset when moving the object"),
|
||||
_("the rotation offset"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -294,7 +308,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Change the size of the extra border applied to the object when "
|
||||
"planning a path"),
|
||||
_("the size of the extra border on the path"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -310,7 +324,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Compare the size of the extra border applied to the "
|
||||
"object when planning a path"),
|
||||
_("the size of the extra border on the path"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -325,7 +339,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Diagonal movement"),
|
||||
_("Allow or restrict diagonal movement on the path"),
|
||||
_("Allow diagonal movement for _PARAM0_ on the path: _PARAM2_"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -340,7 +354,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Check if the object is allowed to move "
|
||||
"diagonally on the path"),
|
||||
_("Diagonal moves allowed for _PARAM0_"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -353,7 +367,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Rotate the object"),
|
||||
_("Enable or disable rotation of the object on the path"),
|
||||
_("Enable rotation of _PARAM0_ on the path: _PARAM2_"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -368,7 +382,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
_("Check if the object is rotated when traveling on "
|
||||
"its path."),
|
||||
_("_PARAM0_ is rotated when traveling on its path"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon24.png",
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
|
||||
@@ -380,7 +394,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("GetNodeX",
|
||||
_("Get a waypoint X position"),
|
||||
_("Get next waypoint X position"),
|
||||
_("Path"),
|
||||
_("Movement on the path"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -391,7 +405,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("GetNodeY",
|
||||
_("Get a waypoint Y position"),
|
||||
_("Get next waypoint Y position"),
|
||||
_("Path"),
|
||||
_("Movement on the path"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -402,7 +416,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("NextNodeIndex",
|
||||
_("Index of the next waypoint"),
|
||||
_("Get the index of the next waypoint to reach"),
|
||||
_("Path"),
|
||||
_("Movement on the path"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -412,7 +426,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("NodeCount",
|
||||
_("Waypoint count"),
|
||||
_("Get the number of waypoints on the path"),
|
||||
_("Path"),
|
||||
_("Movement on the path"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -422,7 +436,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("NextNodeX",
|
||||
_("Get next waypoint X position"),
|
||||
_("Get next waypoint X position"),
|
||||
_("Path"),
|
||||
_("Movement on the path"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -432,7 +446,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("NextNodeY",
|
||||
_("Get next waypoint Y position"),
|
||||
_("Get next waypoint Y position"),
|
||||
_("Path"),
|
||||
_("Movement on the path"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -442,7 +456,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("LastNodeX",
|
||||
_("Last waypoint X position"),
|
||||
_("Last waypoint X position"),
|
||||
_("Path"),
|
||||
_("Movement on the path"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -452,7 +466,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("LastNodeY",
|
||||
_("Last waypoint Y position"),
|
||||
_("Last waypoint Y position"),
|
||||
_("Path"),
|
||||
_("Movement on the path"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -462,7 +476,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("DestinationX",
|
||||
_("Destination X position"),
|
||||
_("Destination X position"),
|
||||
_("Path"),
|
||||
_("Movement on the path"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -472,7 +486,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("DestinationY",
|
||||
_("Destination Y position"),
|
||||
_("Destination Y position"),
|
||||
_("Path"),
|
||||
_("Movement on the path"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -482,7 +496,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("Acceleration",
|
||||
_("Acceleration"),
|
||||
_("Acceleration of the object on the path"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -492,7 +506,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("MaxSpeed",
|
||||
_("Maximum speed"),
|
||||
_("Maximum speed of the object on the path"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -502,7 +516,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("Speed",
|
||||
_("Speed"),
|
||||
_("Speed of the object on the path"),
|
||||
_("Path"),
|
||||
_("Movement on the path"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -512,7 +526,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("AngularMaxSpeed",
|
||||
_("Angular maximum speed"),
|
||||
_("Angular maximum speed of the object on the path"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -522,7 +536,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("AngleOffset",
|
||||
_("Rotation offset"),
|
||||
_("Rotation offset applied the object on the path"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -532,7 +546,7 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddExpression("ExtraBorder",
|
||||
_("Extra border size"),
|
||||
_("Extra border applied the object on the path"),
|
||||
_("Path"),
|
||||
_("Pathfinding configuration"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
@@ -559,6 +573,36 @@ void DeclarePathfindingBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
.SetFunctionName("GetCellHeight")
|
||||
.SetIncludeFile("PathfindingBehavior/PathfindingRuntimeBehavior.h");
|
||||
|
||||
aut.AddExpression("MovementAngle",
|
||||
_("Angle of movement on its path"),
|
||||
_("Angle of movement on its path"),
|
||||
_("Movement on the path"),
|
||||
"CppPlatform/Extensions/AStaricon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior");
|
||||
|
||||
aut.AddExpressionAndConditionAndAction("number",
|
||||
"GridOffsetX",
|
||||
_("Grid X offset"),
|
||||
_("X offset of the virtual grid"),
|
||||
_("X offset of the virtual grid"),
|
||||
_("Virtual grid"),
|
||||
"CppPlatform/Extensions/AStaricon24.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
.UseStandardParameters("number");
|
||||
|
||||
aut.AddExpressionAndConditionAndAction("number",
|
||||
"GridOffsetY",
|
||||
_("Grid Y offset"),
|
||||
_("Y offset of the virtual grid"),
|
||||
_("Y offset of the virtual grid"),
|
||||
_("Virtual grid"),
|
||||
"CppPlatform/Extensions/AStaricon24.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "PathfindingBehavior")
|
||||
.UseStandardParameters("number");
|
||||
|
||||
#endif
|
||||
}
|
||||
{
|
||||
|
@@ -55,6 +55,16 @@ class PathfindingBehaviorJsExtension : public gd::PlatformExtension {
|
||||
.SetGetter("getCellHeight");
|
||||
autConditions["PathfindingBehavior::CellHeight"].SetFunctionName(
|
||||
"getCellHeight");
|
||||
autActions["PathfindingBehavior::PathfindingBehavior::SetGridOffsetX"]
|
||||
.SetFunctionName("setGridOffsetX")
|
||||
.SetGetter("getGridOffsetX");
|
||||
autConditions["PathfindingBehavior::PathfindingBehavior::GridOffsetX"].SetFunctionName(
|
||||
"getGridOffsetX");
|
||||
autActions["PathfindingBehavior::PathfindingBehavior::SetGridOffsetY"]
|
||||
.SetFunctionName("setGridOffsetY")
|
||||
.SetGetter("getGridOffsetY");
|
||||
autConditions["PathfindingBehavior::PathfindingBehavior::GridOffsetY"].SetFunctionName(
|
||||
"getGridOffsetY");
|
||||
autActions["PathfindingBehavior::Acceleration"]
|
||||
.SetFunctionName("setAcceleration")
|
||||
.SetGetter("getAcceleration");
|
||||
@@ -69,6 +79,8 @@ class PathfindingBehaviorJsExtension : public gd::PlatformExtension {
|
||||
.SetFunctionName("setSpeed")
|
||||
.SetGetter("getSpeed");
|
||||
autConditions["PathfindingBehavior::Speed"].SetFunctionName("getSpeed");
|
||||
autConditions["PathfindingBehavior::PathfindingBehavior::MovementAngleIsAround"]
|
||||
.SetFunctionName("movementAngleIsAround");
|
||||
autActions["PathfindingBehavior::AngularMaxSpeed"]
|
||||
.SetFunctionName("setAngularMaxSpeed")
|
||||
.SetGetter("getAngularMaxSpeed");
|
||||
@@ -108,11 +120,14 @@ class PathfindingBehaviorJsExtension : public gd::PlatformExtension {
|
||||
autExpressions["Acceleration"].SetFunctionName("getAcceleration");
|
||||
autExpressions["MaxSpeed"].SetFunctionName("getMaxSpeed");
|
||||
autExpressions["Speed"].SetFunctionName("getSpeed");
|
||||
autExpressions["MovementAngle"].SetFunctionName("getMovementAngle");
|
||||
autExpressions["AngularMaxSpeed"].SetFunctionName("getAngularMaxSpeed");
|
||||
autExpressions["AngleOffset"].SetFunctionName("getAngleOffset");
|
||||
autExpressions["ExtraBorder"].SetFunctionName("getExtraBorder");
|
||||
autExpressions["CellWidth"].SetFunctionName("getCellWidth");
|
||||
autExpressions["CellHeight"].SetFunctionName("getCellHeight");
|
||||
autExpressions["GridOffsetX"].SetFunctionName("getGridOffsetX");
|
||||
autExpressions["GridOffsetY"].SetFunctionName("getGridOffsetY");
|
||||
}
|
||||
|
||||
GetBehaviorMetadata("PathfindingBehavior::PathfindingObstacleBehavior")
|
||||
|
@@ -21,6 +21,8 @@ void PathfindingBehavior::InitializeContent(
|
||||
behaviorContent.SetAttribute("angleOffset", 0);
|
||||
behaviorContent.SetAttribute("cellWidth", 20);
|
||||
behaviorContent.SetAttribute("cellHeight", 20);
|
||||
behaviorContent.SetAttribute("gridOffsetX", 0);
|
||||
behaviorContent.SetAttribute("gridOffsetY", 0);
|
||||
behaviorContent.SetAttribute("extraBorder", 0);
|
||||
}
|
||||
|
||||
@@ -46,9 +48,13 @@ std::map<gd::String, gd::PropertyDescriptor> PathfindingBehavior::GetProperties(
|
||||
properties[_("Angle offset")].SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("angleOffset")));
|
||||
properties[_("Virtual cell width")].SetValue(
|
||||
gd::String::From(behaviorContent.GetIntAttribute("cellWidth", 0)));
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("cellWidth", 0)));
|
||||
properties[_("Virtual cell height")].SetValue(
|
||||
gd::String::From(behaviorContent.GetIntAttribute("cellHeight", 0)));
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("cellHeight", 0)));
|
||||
properties[_("Virtual grid X offset")].SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("gridOffsetX", 0)));
|
||||
properties[_("Virtual grid Y offset")].SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("gridOffsetY", 0)));
|
||||
properties[_("Extra border size")].SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("extraBorder")));
|
||||
|
||||
@@ -82,9 +88,13 @@ bool PathfindingBehavior::UpdateProperty(gd::SerializerElement& behaviorContent,
|
||||
else if (name == _("Angle offset"))
|
||||
behaviorContent.SetAttribute("angleOffset", value.To<float>());
|
||||
else if (name == _("Virtual cell width"))
|
||||
behaviorContent.SetAttribute("cellWidth", (int)value.To<unsigned int>());
|
||||
behaviorContent.SetAttribute("cellWidth", value.To<float>());
|
||||
else if (name == _("Virtual cell height"))
|
||||
behaviorContent.SetAttribute("cellHeight", (int)value.To<unsigned int>());
|
||||
behaviorContent.SetAttribute("cellHeight", value.To<float>());
|
||||
else if (name == _("Virtual grid X offset"))
|
||||
behaviorContent.SetAttribute("gridOffsetX", value.To<float>());
|
||||
else if (name == _("Virtual grid Y offset"))
|
||||
behaviorContent.SetAttribute("gridOffsetY", value.To<float>());
|
||||
else
|
||||
return false;
|
||||
|
||||
|
@@ -17,8 +17,10 @@ namespace gdjs {
|
||||
_angularMaxSpeed: float;
|
||||
_rotateObject: boolean;
|
||||
_angleOffset: float;
|
||||
_cellWidth: integer;
|
||||
_cellHeight: integer;
|
||||
_cellWidth: float;
|
||||
_cellHeight: float;
|
||||
_gridOffsetX: float;
|
||||
_gridOffsetY: float;
|
||||
_extraBorder: float;
|
||||
|
||||
//Attributes used for traveling on the path:
|
||||
@@ -32,6 +34,8 @@ namespace gdjs {
|
||||
_manager: PathfindingObstaclesManager;
|
||||
_searchContext: PathfindingRuntimeBehavior.SearchContext;
|
||||
|
||||
_movementAngle: float = 0;
|
||||
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
behaviorData,
|
||||
@@ -52,6 +56,8 @@ namespace gdjs {
|
||||
this._angleOffset = behaviorData.angleOffset;
|
||||
this._cellWidth = behaviorData.cellWidth;
|
||||
this._cellHeight = behaviorData.cellHeight;
|
||||
this._gridOffsetX = behaviorData.gridOffsetX || 0;
|
||||
this._gridOffsetY = behaviorData.gridOffsetY || 0;
|
||||
this._extraBorder = behaviorData.extraBorder;
|
||||
this._manager = gdjs.PathfindingObstaclesManager.getManager(runtimeScene);
|
||||
this._searchContext = new gdjs.PathfindingRuntimeBehavior.SearchContext(
|
||||
@@ -84,28 +90,50 @@ namespace gdjs {
|
||||
if (oldBehaviorData.cellHeight !== newBehaviorData.cellHeight) {
|
||||
this.setCellHeight(newBehaviorData.cellHeight);
|
||||
}
|
||||
if (oldBehaviorData.gridOffsetX !== newBehaviorData.gridOffsetX) {
|
||||
this._gridOffsetX = newBehaviorData.gridOffsetX;
|
||||
}
|
||||
if (oldBehaviorData.gridOffsetY !== newBehaviorData.gridOffsetY) {
|
||||
this._gridOffsetY = newBehaviorData.gridOffsetY;
|
||||
}
|
||||
if (oldBehaviorData.extraBorder !== newBehaviorData.extraBorder) {
|
||||
this.setExtraBorder(newBehaviorData.extraBorder);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
setCellWidth(width: integer): void {
|
||||
setCellWidth(width: float): void {
|
||||
this._cellWidth = width;
|
||||
}
|
||||
|
||||
getCellWidth(): integer {
|
||||
getCellWidth(): float {
|
||||
return this._cellWidth;
|
||||
}
|
||||
|
||||
setCellHeight(height: integer): void {
|
||||
setCellHeight(height: float): void {
|
||||
this._cellHeight = height;
|
||||
}
|
||||
|
||||
getCellHeight(): integer {
|
||||
getCellHeight(): float {
|
||||
return this._cellHeight;
|
||||
}
|
||||
|
||||
setGridOffsetX(gridOffsetX: float): void {
|
||||
this._gridOffsetX = gridOffsetX;
|
||||
}
|
||||
|
||||
getGridOffsetX(): float {
|
||||
return this._gridOffsetX;
|
||||
}
|
||||
|
||||
setGridOffsetY(gridOffsetY: float): void {
|
||||
this._gridOffsetY = gridOffsetY;
|
||||
}
|
||||
|
||||
getGridOffsetY(): float {
|
||||
return this._gridOffsetY;
|
||||
}
|
||||
|
||||
setAcceleration(acceleration: float): void {
|
||||
this._acceleration = acceleration;
|
||||
}
|
||||
@@ -130,6 +158,19 @@ namespace gdjs {
|
||||
return this._speed;
|
||||
}
|
||||
|
||||
getMovementAngle() {
|
||||
return this._movementAngle;
|
||||
}
|
||||
|
||||
movementAngleIsAround(degreeAngle: float, tolerance: float) {
|
||||
return (
|
||||
gdjs.evtTools.common.angleDifference(
|
||||
this._movementAngle,
|
||||
degreeAngle
|
||||
) <= tolerance
|
||||
);
|
||||
}
|
||||
|
||||
setAngularMaxSpeed(angularMaxSpeed: float): void {
|
||||
this._angularMaxSpeed = angularMaxSpeed;
|
||||
}
|
||||
@@ -275,10 +316,16 @@ namespace gdjs {
|
||||
const owner = this.owner;
|
||||
|
||||
//First be sure that there is a path to compute.
|
||||
const targetCellX = Math.round(x / this._cellWidth);
|
||||
const targetCellY = Math.round(y / this._cellHeight);
|
||||
const startCellX = Math.round(owner.getX() / this._cellWidth);
|
||||
const startCellY = Math.round(owner.getY() / this._cellHeight);
|
||||
const targetCellX = Math.round((x - this._gridOffsetX) / this._cellWidth);
|
||||
const targetCellY = Math.round(
|
||||
(y - this._gridOffsetY) / this._cellHeight
|
||||
);
|
||||
const startCellX = Math.round(
|
||||
(owner.getX() - this._gridOffsetX) / this._cellWidth
|
||||
);
|
||||
const startCellY = Math.round(
|
||||
(owner.getY() - this._gridOffsetY) / this._cellHeight
|
||||
);
|
||||
if (startCellX == targetCellX && startCellY == targetCellY) {
|
||||
this._path.length = 0;
|
||||
this._path.push([owner.getX(), owner.getY()]);
|
||||
@@ -292,6 +339,7 @@ namespace gdjs {
|
||||
this._searchContext.allowDiagonals(this._allowDiagonals);
|
||||
this._searchContext.setObstacles(this._manager);
|
||||
this._searchContext.setCellSize(this._cellWidth, this._cellHeight);
|
||||
this._searchContext.setGridOffset(this._gridOffsetX, this._gridOffsetY);
|
||||
this._searchContext.setStartPosition(owner.getX(), owner.getY());
|
||||
this._searchContext.setObjectSize(
|
||||
owner.getX() - owner.getDrawableX() + this._extraBorder,
|
||||
@@ -311,8 +359,10 @@ namespace gdjs {
|
||||
if (finalPathLength === this._path.length) {
|
||||
this._path.push([0, 0]);
|
||||
}
|
||||
this._path[finalPathLength][0] = node.pos[0] * this._cellWidth;
|
||||
this._path[finalPathLength][1] = node.pos[1] * this._cellHeight;
|
||||
this._path[finalPathLength][0] =
|
||||
node.pos[0] * this._cellWidth + this._gridOffsetX;
|
||||
this._path[finalPathLength][1] =
|
||||
node.pos[1] * this._cellHeight + this._gridOffsetY;
|
||||
node = node.parent;
|
||||
finalPathLength++;
|
||||
}
|
||||
@@ -344,6 +394,8 @@ namespace gdjs {
|
||||
this._totalSegmentTime = Math.sqrt(pathX * pathX + pathY * pathY);
|
||||
this._timeOnSegment = 0;
|
||||
this._reachedEnd = false;
|
||||
this._movementAngle =
|
||||
((Math.atan2(pathY, pathX) * 180) / Math.PI + 360) % 360;
|
||||
} else {
|
||||
this._reachedEnd = true;
|
||||
this._speed = 0;
|
||||
@@ -446,11 +498,11 @@ namespace gdjs {
|
||||
parent: Node | null = null;
|
||||
open: boolean = true;
|
||||
|
||||
constructor(xPos: float, yPos: float) {
|
||||
constructor(xPos: integer, yPos: integer) {
|
||||
this.pos = [xPos, yPos];
|
||||
}
|
||||
|
||||
reinitialize(xPos: float, yPos: float) {
|
||||
reinitialize(xPos: integer, yPos: integer) {
|
||||
this.pos[0] = xPos;
|
||||
this.pos[1] = yPos;
|
||||
this.cost = 0;
|
||||
@@ -477,28 +529,28 @@ namespace gdjs {
|
||||
_maxComplexityFactor: integer = 50;
|
||||
_cellWidth: float = 20;
|
||||
_cellHeight: float = 20;
|
||||
_gridOffsetX: float = 0;
|
||||
_gridOffsetY: float = 0;
|
||||
|
||||
_leftBorder: integer = 0;
|
||||
_rightBorder: integer = 0;
|
||||
_topBorder: integer = 0;
|
||||
_bottomBorder: integer = 0;
|
||||
_distanceFunction: (pt1: FloatPoint, pt2: FloatPoint) => float;
|
||||
_allNodes: Node[][] = [];
|
||||
|
||||
//An array of array. Nodes are indexed by their x position, and then by their y position.
|
||||
_allNodes: Node[][] = [];
|
||||
//An array of nodes sorted by their estimate cost (First node = Lower estimate cost).
|
||||
_openNodes: Node[] = [];
|
||||
_closeObstacles: PathfindingObstacleRuntimeBehavior[] = [];
|
||||
|
||||
//Used by getNodes to temporarily store obstacles near a position.
|
||||
_closeObstacles: PathfindingObstacleRuntimeBehavior[] = [];
|
||||
//Old nodes constructed in a previous search are stored here to avoid temporary objects (see _freeAllNodes method).
|
||||
_nodeCache: Node[] = [];
|
||||
|
||||
constructor(obstacles: PathfindingObstaclesManager) {
|
||||
this._obstacles = obstacles;
|
||||
this._distanceFunction = PathfindingRuntimeBehavior.euclideanDistance;
|
||||
|
||||
//An array of nodes sorted by their estimate cost (First node = Lower estimate cost).
|
||||
}
|
||||
|
||||
//Old nodes constructed in a previous search are stored here to avoid temporary objects (see _freeAllNodes method).
|
||||
setObstacles(
|
||||
obstacles: PathfindingObstaclesManager
|
||||
): PathfindingRuntimeBehavior.SearchContext {
|
||||
@@ -549,6 +601,15 @@ namespace gdjs {
|
||||
return this;
|
||||
}
|
||||
|
||||
setGridOffset(
|
||||
gridOffsetX: float,
|
||||
gridOffsetY: float
|
||||
): PathfindingRuntimeBehavior.SearchContext {
|
||||
this._gridOffsetX = gridOffsetX;
|
||||
this._gridOffsetY = gridOffsetY;
|
||||
return this;
|
||||
}
|
||||
|
||||
computePathTo(targetX: float, targetY: float) {
|
||||
if (this._obstacles === null) {
|
||||
console.log(
|
||||
@@ -556,10 +617,18 @@ namespace gdjs {
|
||||
);
|
||||
return;
|
||||
}
|
||||
this._destination[0] = Math.round(targetX / this._cellWidth);
|
||||
this._destination[1] = Math.round(targetY / this._cellHeight);
|
||||
this._start[0] = Math.round(this._startX / this._cellWidth);
|
||||
this._start[1] = Math.round(this._startY / this._cellHeight);
|
||||
this._destination[0] = Math.round(
|
||||
(targetX - this._gridOffsetX) / this._cellWidth
|
||||
);
|
||||
this._destination[1] = Math.round(
|
||||
(targetY - this._gridOffsetY) / this._cellHeight
|
||||
);
|
||||
this._start[0] = Math.round(
|
||||
(this._startX - this._gridOffsetX) / this._cellWidth
|
||||
);
|
||||
this._start[1] = Math.round(
|
||||
(this._startY - this._gridOffsetY) / this._cellHeight
|
||||
);
|
||||
|
||||
//Initialize the algorithm
|
||||
this._freeAllNodes();
|
||||
@@ -679,7 +748,7 @@ namespace gdjs {
|
||||
* *All* nodes should be created using this method: The cost of the node is computed thanks
|
||||
* to the objects flagged as obstacles.
|
||||
*/
|
||||
_getNode(xPos: float, yPos: float): Node {
|
||||
_getNode(xPos: integer, yPos: integer): Node {
|
||||
//First check if their is a node a the specified position.
|
||||
if (this._allNodes.hasOwnProperty(xPos)) {
|
||||
if (this._allNodes[xPos].hasOwnProperty(yPos)) {
|
||||
@@ -698,6 +767,9 @@ namespace gdjs {
|
||||
newNode = new Node(xPos, yPos);
|
||||
}
|
||||
|
||||
const nodeCenterX = xPos * this._cellWidth + this._gridOffsetX;
|
||||
const nodeCenterY = yPos * this._cellHeight + this._gridOffsetY;
|
||||
|
||||
//...and update its cost according to obstacles
|
||||
let objectsOnCell = false;
|
||||
const radius =
|
||||
@@ -705,25 +777,33 @@ namespace gdjs {
|
||||
? this._cellHeight * 2
|
||||
: this._cellWidth * 2;
|
||||
this._obstacles.getAllObstaclesAround(
|
||||
xPos * this._cellWidth,
|
||||
yPos * this._cellHeight,
|
||||
nodeCenterX,
|
||||
nodeCenterY,
|
||||
radius,
|
||||
this._closeObstacles
|
||||
);
|
||||
for (let k = 0; k < this._closeObstacles.length; ++k) {
|
||||
const obj = this._closeObstacles[k].owner;
|
||||
const topLeftCellX = Math.floor(
|
||||
(obj.getDrawableX() - this._rightBorder) / this._cellWidth
|
||||
(obj.getDrawableX() - this._rightBorder - this._gridOffsetX) /
|
||||
this._cellWidth
|
||||
);
|
||||
const topLeftCellY = Math.floor(
|
||||
(obj.getDrawableY() - this._bottomBorder) / this._cellHeight
|
||||
(obj.getDrawableY() - this._bottomBorder - this._gridOffsetY) /
|
||||
this._cellHeight
|
||||
);
|
||||
const bottomRightCellX = Math.ceil(
|
||||
(obj.getDrawableX() + obj.getWidth() + this._leftBorder) /
|
||||
(obj.getDrawableX() +
|
||||
obj.getWidth() +
|
||||
this._leftBorder -
|
||||
this._gridOffsetX) /
|
||||
this._cellWidth
|
||||
);
|
||||
const bottomRightCellY = Math.ceil(
|
||||
(obj.getDrawableY() + obj.getHeight() + this._topBorder) /
|
||||
(obj.getDrawableY() +
|
||||
obj.getHeight() +
|
||||
this._topBorder -
|
||||
this._gridOffsetY) /
|
||||
this._cellHeight
|
||||
);
|
||||
if (
|
||||
@@ -733,14 +813,12 @@ namespace gdjs {
|
||||
yPos < bottomRightCellY
|
||||
) {
|
||||
objectsOnCell = true;
|
||||
|
||||
//The cell is impassable, stop here.
|
||||
|
||||
//Superimpose obstacles
|
||||
if (this._closeObstacles[k].isImpassable()) {
|
||||
//The cell is impassable, stop here.
|
||||
newNode.cost = -1;
|
||||
break;
|
||||
} else {
|
||||
//Superimpose obstacles
|
||||
newNode.cost += this._closeObstacles[k].getCost();
|
||||
}
|
||||
}
|
||||
@@ -758,8 +836,8 @@ namespace gdjs {
|
||||
* Add a node to the openNodes (only if the cost to reach it is less than the existing cost, if any).
|
||||
*/
|
||||
_addOrUpdateNode(
|
||||
newNodeX: float,
|
||||
newNodeY: float,
|
||||
newNodeX: integer,
|
||||
newNodeY: integer,
|
||||
currentNode: Node,
|
||||
factor: float
|
||||
) {
|
||||
|
@@ -290,7 +290,7 @@ namespace gdjs {
|
||||
//Colliding: Try to push out from the solid.
|
||||
//Note that jump thru are never obstacle on X axis.
|
||||
while (
|
||||
this._isCollidingWith(
|
||||
this._isCollidingWithOneOf(
|
||||
this._potentialCollidingObjects,
|
||||
floorPlatformId,
|
||||
/*excludeJumpthrus=*/
|
||||
@@ -312,7 +312,7 @@ namespace gdjs {
|
||||
if (this._state === this._onFloor) {
|
||||
object.setY(object.getY() - 1);
|
||||
if (
|
||||
!this._isCollidingWith(
|
||||
!this._isCollidingWithOneOf(
|
||||
this._potentialCollidingObjects,
|
||||
floorPlatformId,
|
||||
/*excludeJumpthrus=*/
|
||||
@@ -348,7 +348,7 @@ namespace gdjs {
|
||||
//Stop when colliding with an obstacle.
|
||||
while (
|
||||
(this._requestedDeltaY < 0 &&
|
||||
this._isCollidingWith(
|
||||
this._isCollidingWithOneOf(
|
||||
this._potentialCollidingObjects,
|
||||
null,
|
||||
/*excludeJumpThrus=*/
|
||||
@@ -356,7 +356,7 @@ namespace gdjs {
|
||||
)) ||
|
||||
//Jumpthru = obstacle <=> Never when going up
|
||||
(this._requestedDeltaY > 0 &&
|
||||
this._isCollidingWithExcluding(
|
||||
this._isCollidingWithOneOfExcluding(
|
||||
this._potentialCollidingObjects,
|
||||
this._overlappedJumpThru
|
||||
))
|
||||
@@ -427,48 +427,49 @@ namespace gdjs {
|
||||
|
||||
_checkGrabPlatform() {
|
||||
const object = this.owner;
|
||||
let tryGrabbingPlatform = false;
|
||||
|
||||
let oldX = object.getX();
|
||||
object.setX(
|
||||
object.getX() +
|
||||
(this._requestedDeltaX > 0
|
||||
? this._xGrabTolerance
|
||||
: -this._xGrabTolerance)
|
||||
);
|
||||
let collidingPlatform = this._getCollidingPlatform();
|
||||
if (collidingPlatform !== null && this._canGrab(collidingPlatform)) {
|
||||
tryGrabbingPlatform = true;
|
||||
}
|
||||
object.setX(
|
||||
object.getX() +
|
||||
(this._requestedDeltaX > 0
|
||||
? -this._xGrabTolerance
|
||||
: this._xGrabTolerance)
|
||||
const collidingPlatforms: PlatformRuntimeBehavior[] = gdjs.staticArray(
|
||||
PlatformerObjectRuntimeBehavior.prototype._checkGrabPlatform
|
||||
);
|
||||
collidingPlatforms.length = 0;
|
||||
for (const platform of this._potentialCollidingObjects) {
|
||||
if (this._isCollidingWith(platform) && this._canGrab(platform)) {
|
||||
collidingPlatforms.push(platform);
|
||||
}
|
||||
}
|
||||
object.setX(oldX);
|
||||
|
||||
//Check if we can grab the collided platform
|
||||
if (tryGrabbingPlatform) {
|
||||
let oldY = object.getY();
|
||||
let oldY = object.getY();
|
||||
for (const collidingPlatform of collidingPlatforms) {
|
||||
object.setY(
|
||||
// @ts-ignore - collidingPlatform is guaranteed to be not null.
|
||||
collidingPlatform.owner.getY() +
|
||||
// @ts-ignore - collidingPlatform is guaranteed to be not null.
|
||||
collidingPlatform.getYGrabOffset() -
|
||||
this._yGrabOffset
|
||||
);
|
||||
if (
|
||||
!this._isCollidingWith(
|
||||
!this._isCollidingWithOneOf(
|
||||
this._potentialCollidingObjects,
|
||||
null,
|
||||
/*excludeJumpthrus=*/
|
||||
true
|
||||
)
|
||||
) {
|
||||
this._setGrabbingPlatform(collidingPlatform!);
|
||||
this._setGrabbingPlatform(collidingPlatform);
|
||||
this._requestedDeltaY = 0;
|
||||
} else {
|
||||
object.setY(oldY);
|
||||
collidingPlatforms.length = 0;
|
||||
return;
|
||||
}
|
||||
object.setY(oldY);
|
||||
}
|
||||
collidingPlatforms.length = 0;
|
||||
}
|
||||
|
||||
private _checkTransitionOnFloorOrFalling() {
|
||||
@@ -553,48 +554,6 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Among the platforms passed in parameter, return true if there is a platform colliding with the object.
|
||||
* Ladders are *always* excluded from the test.
|
||||
* @param candidates The platform to be tested for collision
|
||||
* @param exceptThisOne The object identifier of a platform to be excluded from the check. Can be null.
|
||||
* @param excludeJumpThrus If set to true, jumpthru platforms are excluded. false if not defined.
|
||||
*/
|
||||
_isCollidingWith(
|
||||
candidates: gdjs.PlatformRuntimeBehavior[],
|
||||
exceptThisOne?: number | null,
|
||||
excludeJumpThrus?: boolean
|
||||
) {
|
||||
excludeJumpThrus = !!excludeJumpThrus;
|
||||
for (let i = 0; i < candidates.length; ++i) {
|
||||
const platform = candidates[i];
|
||||
if (platform.owner.id === exceptThisOne) {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.LADDER
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
excludeJumpThrus &&
|
||||
platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.JUMPTHRU
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
gdjs.RuntimeObject.collisionTest(
|
||||
this.owner,
|
||||
platform.owner,
|
||||
this._ignoreTouchingEdges
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Separate the object from all platforms passed in parameter.
|
||||
* @param candidates The platform to be tested for collision
|
||||
@@ -627,13 +586,55 @@ namespace gdjs {
|
||||
return this.owner.separateFromObjects(objects, this._ignoreTouchingEdges);
|
||||
}
|
||||
|
||||
/**
|
||||
* Among the platforms passed in parameter, return true if there is a platform colliding with the object.
|
||||
* Ladders are *always* excluded from the test.
|
||||
* @param candidates The platform to be tested for collision
|
||||
* @param exceptThisOne The object identifier of a platform to be excluded from the check. Can be null.
|
||||
* @param excludeJumpThrus If set to true, jumpthru platforms are excluded. false if not defined.
|
||||
*/
|
||||
_isCollidingWithOneOf(
|
||||
candidates: gdjs.PlatformRuntimeBehavior[],
|
||||
exceptThisOne?: number | null,
|
||||
excludeJumpThrus?: boolean
|
||||
) {
|
||||
excludeJumpThrus = !!excludeJumpThrus;
|
||||
for (let i = 0; i < candidates.length; ++i) {
|
||||
const platform = candidates[i];
|
||||
if (platform.owner.id === exceptThisOne) {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.LADDER
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
excludeJumpThrus &&
|
||||
platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.JUMPTHRU
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
gdjs.RuntimeObject.collisionTest(
|
||||
this.owner,
|
||||
platform.owner,
|
||||
this._ignoreTouchingEdges
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Among the platforms passed in parameter, return true if there is a platform colliding with the object.
|
||||
* Ladders are *always* excluded from the test.
|
||||
* @param candidates The platform to be tested for collision
|
||||
* @param exceptTheseOnes The platforms to be excluded from the test
|
||||
*/
|
||||
private _isCollidingWithExcluding(
|
||||
private _isCollidingWithOneOfExcluding(
|
||||
candidates: gdjs.PlatformRuntimeBehavior[],
|
||||
exceptTheseOnes: gdjs.PlatformRuntimeBehavior[]
|
||||
) {
|
||||
@@ -685,6 +686,23 @@ namespace gdjs {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the platform is colliding with the behavior owner object.
|
||||
* Overlapped jump thru and ladders are excluded.
|
||||
* @param platform The platform to be tested for collision
|
||||
*/
|
||||
private _isCollidingWith(platform: gdjs.PlatformRuntimeBehavior): boolean {
|
||||
return (
|
||||
platform.getPlatformType() !== gdjs.PlatformRuntimeBehavior.LADDER &&
|
||||
!this._isIn(this._overlappedJumpThru, platform.owner.id) &&
|
||||
gdjs.RuntimeObject.collisionTest(
|
||||
this.owner,
|
||||
platform.owner,
|
||||
this._ignoreTouchingEdges
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update _overlappedJumpThru member, so that it contains all the jumpthru platforms colliding with
|
||||
* the behavior owner object.
|
||||
@@ -1317,7 +1335,7 @@ namespace gdjs {
|
||||
let step = 0;
|
||||
let noMoreOnFloor = false;
|
||||
while (
|
||||
!behavior._isCollidingWith(behavior._potentialCollidingObjects)
|
||||
!behavior._isCollidingWithOneOf(behavior._potentialCollidingObjects)
|
||||
) {
|
||||
if (
|
||||
step >
|
||||
|
@@ -191,67 +191,6 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
||||
}
|
||||
});
|
||||
|
||||
it('can grab, and release, a platform', function () {
|
||||
//Put the object near the right ledge of the platform.
|
||||
object.setPosition(
|
||||
platform.getX() + platform.getWidth() + 2,
|
||||
platform.getY() - 10
|
||||
);
|
||||
|
||||
for (let i = 0; i < 35; ++i) {
|
||||
object.getBehavior('auto1').simulateLeftKey();
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
}
|
||||
|
||||
//Check that the object grabbed the platform
|
||||
expect(object.getX()).to.be.within(
|
||||
platform.getX() + platform.getWidth() + 0,
|
||||
platform.getX() + platform.getWidth() + 1
|
||||
);
|
||||
expect(object.getY()).to.be(platform.getY());
|
||||
|
||||
object.getBehavior('auto1').simulateReleaseKey();
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
expect(object.getBehavior('auto1').isFalling()).to.be(true);
|
||||
expect(object.getBehavior('auto1').isFallingWithoutJumping()).to.be(
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
//Check that the object is falling
|
||||
expect(object.getY()).to.be(3.75);
|
||||
});
|
||||
|
||||
it('can grab a platform and jump', function () {
|
||||
//Put the object near the right ledge of the platform.
|
||||
object.setPosition(
|
||||
platform.getX() + platform.getWidth() + 2,
|
||||
platform.getY() - 10
|
||||
);
|
||||
|
||||
for (let i = 0; i < 35; ++i) {
|
||||
object.getBehavior('auto1').simulateLeftKey();
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
}
|
||||
|
||||
//Check that the object grabbed the platform
|
||||
expect(object.getBehavior('auto1').isGrabbingPlatform()).to.be(true);
|
||||
expect(object.getX()).to.be.within(
|
||||
platform.getX() + platform.getWidth() + 0,
|
||||
platform.getX() + platform.getWidth() + 1
|
||||
);
|
||||
expect(object.getY()).to.be(platform.getY());
|
||||
|
||||
object.getBehavior('auto1').simulateJumpKey();
|
||||
//Check that the object is jumping
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
expect(object.getBehavior('auto1').isJumping()).to.be(true);
|
||||
}
|
||||
expect(object.getY()).to.be.below(platform.getY());
|
||||
});
|
||||
|
||||
it('can track object height changes', function () {
|
||||
//Put the object near the right ledge of the platform.
|
||||
object.setPosition(
|
||||
@@ -337,6 +276,170 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('(grab platforms)', function () {
|
||||
let runtimeScene;
|
||||
let object;
|
||||
|
||||
beforeEach(function () {
|
||||
runtimeScene = makeTestRuntimeScene();
|
||||
|
||||
// Put a platformer object in the air.
|
||||
object = new gdjs.TestRuntimeObject(runtimeScene, {
|
||||
name: 'obj1',
|
||||
type: '',
|
||||
behaviors: [
|
||||
{
|
||||
type: 'PlatformBehavior::PlatformerObjectBehavior',
|
||||
name: 'auto1',
|
||||
gravity: 900,
|
||||
maxFallingSpeed: 1500,
|
||||
acceleration: 500,
|
||||
deceleration: 1500,
|
||||
maxSpeed: 500,
|
||||
jumpSpeed: 1500,
|
||||
canGrabPlatforms: true,
|
||||
ignoreDefaultControls: true,
|
||||
slopeMaxAngle: 60,
|
||||
},
|
||||
],
|
||||
});
|
||||
object.setCustomWidthAndHeight(10, 20);
|
||||
runtimeScene.addObject(object);
|
||||
object.setPosition(0, -100);
|
||||
});
|
||||
|
||||
it('can grab, and release, a platform', function () {
|
||||
// Put a platform.
|
||||
const platform = addPlatformObject(runtimeScene);
|
||||
platform.setPosition(0, -10);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
//Put the object near the right ledge of the platform.
|
||||
object.setPosition(
|
||||
platform.getX() + platform.getWidth() + 2,
|
||||
platform.getY() - 10
|
||||
);
|
||||
|
||||
for (let i = 0; i < 35; ++i) {
|
||||
object.getBehavior('auto1').simulateLeftKey();
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
}
|
||||
|
||||
//Check that the object grabbed the platform
|
||||
expect(object.getX()).to.be.within(
|
||||
platform.getX() + platform.getWidth() + 0,
|
||||
platform.getX() + platform.getWidth() + 1
|
||||
);
|
||||
expect(object.getY()).to.be(platform.getY());
|
||||
|
||||
object.getBehavior('auto1').simulateReleaseKey();
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
expect(object.getBehavior('auto1').isFalling()).to.be(true);
|
||||
expect(object.getBehavior('auto1').isFallingWithoutJumping()).to.be(
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
//Check that the object is falling
|
||||
expect(object.getY()).to.be(3.75);
|
||||
});
|
||||
|
||||
[true, false].forEach((addTopPlatformFirst) => {
|
||||
it('can grab every platform when colliding 2', function () {
|
||||
// The 2 platforms will be simultaneously in collision
|
||||
// with the object when it grabs one.
|
||||
let upperPlatform, lowerPlatform;
|
||||
if (addTopPlatformFirst) {
|
||||
upperPlatform = addPlatformObject(runtimeScene);
|
||||
upperPlatform.setPosition(0, -10);
|
||||
upperPlatform.setCustomWidthAndHeight(60, 10);
|
||||
|
||||
lowerPlatform = addPlatformObject(runtimeScene);
|
||||
lowerPlatform.setPosition(0, 0);
|
||||
lowerPlatform.setCustomWidthAndHeight(60, 10);
|
||||
} else {
|
||||
lowerPlatform = addPlatformObject(runtimeScene);
|
||||
lowerPlatform.setPosition(0, 0);
|
||||
lowerPlatform.setCustomWidthAndHeight(60, 10);
|
||||
|
||||
upperPlatform = addPlatformObject(runtimeScene);
|
||||
upperPlatform.setPosition(0, -10);
|
||||
upperPlatform.setCustomWidthAndHeight(60, 10);
|
||||
}
|
||||
|
||||
// Put the object near the right ledge of the platform.
|
||||
object.setPosition(
|
||||
upperPlatform.getX() + upperPlatform.getWidth() + 2,
|
||||
upperPlatform.getY() - 10
|
||||
);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
for (let i = 0; i < 35; ++i) {
|
||||
object.getBehavior('auto1').simulateLeftKey();
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
}
|
||||
|
||||
// Check that the object grabbed the upper platform
|
||||
expect(object.getX()).to.be.within(
|
||||
upperPlatform.getX() + upperPlatform.getWidth() + 0,
|
||||
upperPlatform.getX() + upperPlatform.getWidth() + 1
|
||||
);
|
||||
expect(object.getY()).to.be(upperPlatform.getY());
|
||||
expect(object.getBehavior('auto1').isGrabbingPlatform()).to.be(true);
|
||||
|
||||
// Release upper platform
|
||||
object.getBehavior('auto1').simulateReleaseKey();
|
||||
for (let i = 0; i < 35; ++i) {
|
||||
object.getBehavior('auto1').simulateLeftKey();
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
}
|
||||
|
||||
// Check that the object grabbed the lower platform
|
||||
expect(object.getX()).to.be.within(
|
||||
lowerPlatform.getX() + lowerPlatform.getWidth() + 0,
|
||||
lowerPlatform.getX() + lowerPlatform.getWidth() + 1
|
||||
);
|
||||
expect(object.getY()).to.be(lowerPlatform.getY());
|
||||
expect(object.getBehavior('auto1').isGrabbingPlatform()).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('can grab a platform and jump', function () {
|
||||
// Put a platform.
|
||||
platform = addPlatformObject(runtimeScene);
|
||||
platform.setPosition(0, -10);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
//Put the object near the right ledge of the platform.
|
||||
object.setPosition(
|
||||
platform.getX() + platform.getWidth() + 2,
|
||||
platform.getY() - 10
|
||||
);
|
||||
|
||||
for (let i = 0; i < 35; ++i) {
|
||||
object.getBehavior('auto1').simulateLeftKey();
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
}
|
||||
|
||||
//Check that the object grabbed the platform
|
||||
expect(object.getBehavior('auto1').isGrabbingPlatform()).to.be(true);
|
||||
expect(object.getX()).to.be.within(
|
||||
platform.getX() + platform.getWidth() + 0,
|
||||
platform.getX() + platform.getWidth() + 1
|
||||
);
|
||||
expect(object.getY()).to.be(platform.getY());
|
||||
|
||||
object.getBehavior('auto1').simulateJumpKey();
|
||||
//Check that the object is jumping
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
expect(object.getBehavior('auto1').isJumping()).to.be(true);
|
||||
}
|
||||
expect(object.getY()).to.be.below(platform.getY());
|
||||
});
|
||||
});
|
||||
|
||||
describe('(jump and jump sustain, round coordinates on)', function () {
|
||||
let runtimeScene;
|
||||
let object;
|
||||
|
@@ -64,10 +64,10 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
|
||||
obj.AddAction("Line",
|
||||
_("Line"),
|
||||
_("Draw a line on screen"),
|
||||
_("Draw from _PARAM1_;_PARAM2_ to _PARAM3_;_PARAM4_ a line "
|
||||
"(thickness: _PARAM5_) "
|
||||
"with _PARAM0_"),
|
||||
"Draw a line on screen",
|
||||
"Draw from _PARAM1_;_PARAM2_ to _PARAM3_;_PARAM4_ a line "
|
||||
"(thickness: _PARAM5_) "
|
||||
"with _PARAM0_",
|
||||
_("Drawing"),
|
||||
"res/actions/line24.png",
|
||||
"res/actions/line.png")
|
||||
|
@@ -147,9 +147,9 @@ void DeclareTiledSpriteObjectExtension(gd::PlatformExtension& extension) {
|
||||
.SetIncludeFile("TiledSpriteObject/TiledSpriteObject.h");
|
||||
|
||||
obj.AddCondition("Angle",
|
||||
_("Angle"),
|
||||
_("Test the angle of a Tiled Sprite."),
|
||||
_("the angle"),
|
||||
"Angle",
|
||||
"Test the angle of a Tiled Sprite.",
|
||||
"the angle",
|
||||
_("Size and angle"),
|
||||
"res/conditions/rotate24.png",
|
||||
"res/conditions/rotate.png")
|
||||
|
@@ -5,11 +5,11 @@ Copyright (c) 2010-2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include <iostream>
|
||||
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void DeclareTopDownMovementBehaviorExtension(gd::PlatformExtension& extension);
|
||||
|
||||
/**
|
||||
@@ -68,17 +68,20 @@ class TopDownMovementBehaviorJsExtension : public gd::PlatformExtension {
|
||||
.SetGetter("getAngleOffset");
|
||||
autConditions["TopDownMovementBehavior::AngleOffset"].SetFunctionName(
|
||||
"getAngleOffset");
|
||||
autConditions["TopDownMovementBehavior::Angle"].SetFunctionName(
|
||||
"getAngle");
|
||||
autConditions["TopDownMovementBehavior::Angle"].SetFunctionName("getAngle");
|
||||
autConditions["TopDownMovementBehavior::XVelocity"].SetFunctionName(
|
||||
"getXVelocity");
|
||||
autConditions["TopDownMovementBehavior::YVelocity"].SetFunctionName(
|
||||
"getYVelocity");
|
||||
autActions["TopDownMovementBehavior::SetMovementAngleOffset"]
|
||||
.SetFunctionName("setMovementAngleOffset")
|
||||
.SetGetter("getMovementAngleOffset");
|
||||
autConditions["TopDownMovementBehavior::MovementAngleOffset"].SetFunctionName(
|
||||
"getMovementAngleOffset");
|
||||
autActions
|
||||
["TopDownMovementBehavior::TopDownMovementBehavior::"
|
||||
"SetMovementAngleOffset"]
|
||||
.SetFunctionName("setMovementAngleOffset")
|
||||
.SetGetter("getMovementAngleOffset");
|
||||
autConditions
|
||||
["TopDownMovementBehavior::TopDownMovementBehavior::"
|
||||
"MovementAngleOffset"]
|
||||
.SetFunctionName("getMovementAngleOffset");
|
||||
|
||||
autActions["TopDownMovementBehavior::AllowDiagonals"].SetFunctionName(
|
||||
"allowDiagonals");
|
||||
@@ -113,7 +116,8 @@ class TopDownMovementBehaviorJsExtension : public gd::PlatformExtension {
|
||||
autExpressions["Angle"].SetFunctionName("getAngle");
|
||||
autExpressions["XVelocity"].SetFunctionName("getXVelocity");
|
||||
autExpressions["YVelocity"].SetFunctionName("getYVelocity");
|
||||
autExpressions["MovementAngleOffset"].SetFunctionName("getMovementAngleOffset");
|
||||
autExpressions["MovementAngleOffset"].SetFunctionName(
|
||||
"getMovementAngleOffset");
|
||||
|
||||
GD_COMPLETE_EXTENSION_COMPILATION_INFORMATION();
|
||||
};
|
||||
|
@@ -509,9 +509,56 @@ module.exports = {
|
||||
false
|
||||
)
|
||||
.setDefaultValue('no')
|
||||
.addParameter(
|
||||
'yesorno',
|
||||
_('Tween on the Hue/Saturation/Lightness (HSL)'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
.setParameterLongDescription(
|
||||
_('Useful to have a more natural change between colors.')
|
||||
)
|
||||
.setDefaultValue('no')
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('addObjectColorTween');
|
||||
|
||||
behavior
|
||||
.addAction(
|
||||
'AddObjectColorHSLTween',
|
||||
_('Add object HSL color tween'),
|
||||
_(
|
||||
'Add a tween animation for the object color using Hue/Saturation/Lightness. Hue can be any number, Saturation and Lightness are between 0 and 100. Use -1 for Saturation and Lightness to let them unchanged.'
|
||||
),
|
||||
_(
|
||||
'Tween the color of _PARAM0_ using HSL to H: _PARAM3_ (_PARAM4_), S: _PARAM5_, L: _PARAM6_ with easing _PARAM7_ over _PARAM8_ms as _PARAM2_'
|
||||
),
|
||||
_('Color'),
|
||||
'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 Hue'), '', false)
|
||||
.addParameter('yesorno', _('Animate Hue'), '', false)
|
||||
.setDefaultValue('yes')
|
||||
.addParameter('expression', _('To Saturation (-1 to ignore)'), '', false)
|
||||
.setDefaultValue('-1')
|
||||
.addParameter('expression', _('To Lightness (-1 to ignore)'), '', false)
|
||||
.setDefaultValue('-1')
|
||||
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
|
||||
.setDefaultValue('linear')
|
||||
.addParameter('expression', _('Duration'), '', false)
|
||||
.addParameter(
|
||||
'yesorno',
|
||||
_('Destroy this object when tween finishes'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
.setDefaultValue('no')
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('addObjectColorHSLTween');
|
||||
|
||||
behavior
|
||||
.addCondition(
|
||||
'Exists',
|
||||
|
@@ -4,6 +4,40 @@ namespace gdjs {
|
||||
export type Tweenable = any;
|
||||
}
|
||||
|
||||
function rgbToHsl(r: number, g: number, b: number): number[] {
|
||||
r /= 255;
|
||||
g /= 255;
|
||||
b /= 255;
|
||||
let v = Math.max(r, g, b),
|
||||
c = v - Math.min(r, g, b),
|
||||
f = 1 - Math.abs(v + v - c - 1);
|
||||
let h =
|
||||
c &&
|
||||
(v === r ? (g - b) / c : v === g ? 2 + (b - r) / c : 4 + (r - g) / c);
|
||||
return [
|
||||
Math.round(60 * (h < 0 ? h + 6 : h)),
|
||||
Math.round((f ? c / f : 0) * 100),
|
||||
Math.round(((v + v - c) / 2) * 100),
|
||||
];
|
||||
}
|
||||
|
||||
function hslToRgb(h: number, s: number, l: number): number[] {
|
||||
h = h %= 360;
|
||||
if (h < 0) {
|
||||
h += 360;
|
||||
}
|
||||
s = s / 100;
|
||||
l = l / 100;
|
||||
const a = s * Math.min(l, 1 - l);
|
||||
const f = (n = 0, k = (n + h / 30) % 12) =>
|
||||
l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
|
||||
return [
|
||||
Math.round(f(0) * 255),
|
||||
Math.round(f(8) * 255),
|
||||
Math.round(f(4) * 255),
|
||||
];
|
||||
}
|
||||
|
||||
export class TweenRuntimeBehavior extends gdjs.RuntimeBehavior {
|
||||
/** @type Object.<string, TweenRuntimeBehavior.TweenInstance > */
|
||||
_tweens: { [key: string]: TweenRuntimeBehavior.TweenInstance } = {};
|
||||
@@ -644,15 +678,18 @@ namespace gdjs {
|
||||
* @param easingValue Type of easing
|
||||
* @param durationValue Duration in milliseconds
|
||||
* @param destroyObjectWhenFinished Destroy this object when the tween ends
|
||||
* @param useHSLColorTransition Tween using HSL color mappings, rather than direct RGB line
|
||||
*/
|
||||
addObjectColorTween(
|
||||
identifier: string,
|
||||
toColorStr: string,
|
||||
easingValue: string,
|
||||
durationValue: float,
|
||||
destroyObjectWhenFinished: boolean
|
||||
destroyObjectWhenFinished: boolean,
|
||||
useHSLColorTransition: boolean
|
||||
) {
|
||||
const that = this;
|
||||
|
||||
if (!this._isActive) {
|
||||
return;
|
||||
}
|
||||
@@ -674,30 +711,175 @@ namespace gdjs {
|
||||
this.removeTween(identifier);
|
||||
}
|
||||
// @ts-ignore - objects are duck typed
|
||||
const fromColor = this.owner.getColor().split(';');
|
||||
let toColor = toColorStr.split(';');
|
||||
const fromColor: string[] = this.owner.getColor().split(';');
|
||||
const toColor: string[] = toColorStr.split(';');
|
||||
if (toColor.length !== 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newTweenable = TweenRuntimeBehavior.makeNewTweenable(
|
||||
this._runtimeScene
|
||||
);
|
||||
|
||||
if (useHSLColorTransition) {
|
||||
const fromColorAsHSL = rgbToHsl(
|
||||
parseFloat(fromColor[0]),
|
||||
parseFloat(fromColor[1]),
|
||||
parseFloat(fromColor[2])
|
||||
);
|
||||
const toColorAsHSL = rgbToHsl(
|
||||
parseFloat(toColor[0]),
|
||||
parseFloat(toColor[1]),
|
||||
parseFloat(toColor[2])
|
||||
);
|
||||
|
||||
newTweenable.setConfig({
|
||||
from: {
|
||||
hue: fromColorAsHSL[0],
|
||||
saturation: fromColorAsHSL[1],
|
||||
lightness: fromColorAsHSL[2],
|
||||
},
|
||||
to: {
|
||||
hue: toColorAsHSL[0],
|
||||
saturation: toColorAsHSL[1],
|
||||
lightness: toColorAsHSL[2],
|
||||
},
|
||||
duration: durationValue,
|
||||
easing: easingValue,
|
||||
step: function step(state) {
|
||||
const rgbFromHslColor = hslToRgb(
|
||||
state.hue,
|
||||
state.saturation,
|
||||
state.lightness
|
||||
);
|
||||
// @ts-ignore - objects are duck typed
|
||||
that.owner.setColor(
|
||||
Math.floor(rgbFromHslColor[0]) +
|
||||
';' +
|
||||
Math.floor(rgbFromHslColor[1]) +
|
||||
';' +
|
||||
Math.floor(rgbFromHslColor[2])
|
||||
);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
newTweenable.setConfig({
|
||||
from: { red: fromColor[0], green: fromColor[1], blue: fromColor[2] },
|
||||
to: { red: toColor[0], green: toColor[1], blue: toColor[2] },
|
||||
duration: durationValue,
|
||||
easing: easingValue,
|
||||
step: function step(state) {
|
||||
// @ts-ignore - objects are duck typed
|
||||
that.owner.setColor(
|
||||
Math.floor(state.red) +
|
||||
';' +
|
||||
Math.floor(state.green) +
|
||||
';' +
|
||||
Math.floor(state.blue)
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
this._addTween(
|
||||
identifier,
|
||||
newTweenable,
|
||||
this._runtimeScene.getTimeManager().getTimeFromStart(),
|
||||
durationValue
|
||||
);
|
||||
this._setupTweenEnding(identifier, destroyObjectWhenFinished);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object color HSL tween, with the "to" color given using HSL (H: any number, S and L: 0-100).
|
||||
* @param identifier Unique id to idenfify the tween
|
||||
* @param toHue The target hue, or the same as the from color's hue if blank
|
||||
* @param animateHue, include hue in calculations, as can't set this to -1 as default to ignore
|
||||
* @param toSaturation The target saturation, or the same as the from color's saturation if blank
|
||||
* @param toHue The target lightness, or the same as the from color's lightness if blank
|
||||
* @param easingValue Type of easing
|
||||
* @param durationValue Duration in milliseconds
|
||||
* @param destroyObjectWhenFinished Destroy this object when the tween ends
|
||||
*/
|
||||
addObjectColorHSLTween(
|
||||
identifier: string,
|
||||
toHue: number,
|
||||
animateHue: boolean,
|
||||
toSaturation: number,
|
||||
toLightness: number,
|
||||
easingValue: string,
|
||||
durationValue: float,
|
||||
destroyObjectWhenFinished: boolean
|
||||
) {
|
||||
const that = this;
|
||||
|
||||
if (!this._isActive) {
|
||||
return;
|
||||
}
|
||||
// @ts-ignore - objects are duck typed
|
||||
if (!this.owner.getColor || !this.owner.setColor) {
|
||||
return;
|
||||
}
|
||||
if (!!TweenRuntimeBehavior.easings[easingValue]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._tweenExists(identifier)) {
|
||||
this.removeTween(identifier);
|
||||
}
|
||||
|
||||
// @ts-ignore - objects are duck typed
|
||||
const fromColor: string[] = this.owner.getColor().split(';');
|
||||
if (fromColor.length < 3) return;
|
||||
const fromColorAsHSL = rgbToHsl(
|
||||
parseFloat(fromColor[0]),
|
||||
parseFloat(fromColor[1]),
|
||||
parseFloat(fromColor[2])
|
||||
);
|
||||
|
||||
const toH = animateHue ? toHue : fromColorAsHSL[0];
|
||||
const toS =
|
||||
-1 === toSaturation
|
||||
? fromColorAsHSL[1]
|
||||
: Math.min(Math.max(toSaturation, 0), 100);
|
||||
const toL =
|
||||
-1 === toLightness
|
||||
? fromColorAsHSL[2]
|
||||
: Math.min(Math.max(toLightness, 0), 100);
|
||||
|
||||
const newTweenable = TweenRuntimeBehavior.makeNewTweenable(
|
||||
this._runtimeScene
|
||||
);
|
||||
|
||||
newTweenable.setConfig({
|
||||
from: { red: fromColor[0], green: fromColor[1], blue: fromColor[2] },
|
||||
to: { red: toColor[0], green: toColor[1], blue: toColor[2] },
|
||||
from: {
|
||||
hue: fromColorAsHSL[0],
|
||||
saturation: fromColorAsHSL[1],
|
||||
lightness: fromColorAsHSL[2],
|
||||
},
|
||||
to: {
|
||||
hue: toH,
|
||||
saturation: toS,
|
||||
lightness: toL,
|
||||
},
|
||||
duration: durationValue,
|
||||
easing: easingValue,
|
||||
step: function step(state) {
|
||||
const rgbFromHslColor = hslToRgb(
|
||||
state.hue,
|
||||
state.saturation,
|
||||
state.lightness
|
||||
);
|
||||
// @ts-ignore - objects are duck typed
|
||||
that.owner.setColor(
|
||||
Math.floor(state.red) +
|
||||
Math.floor(rgbFromHslColor[0]) +
|
||||
';' +
|
||||
Math.floor(state.green) +
|
||||
Math.floor(rgbFromHslColor[1]) +
|
||||
';' +
|
||||
Math.floor(state.blue)
|
||||
Math.floor(rgbFromHslColor[2])
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
this._addTween(
|
||||
identifier,
|
||||
newTweenable,
|
||||
|
9
GDCpp/GDCpp/Runtime/Project/EffectsContainer.cpp
Normal file
9
GDCpp/GDCpp/Runtime/Project/EffectsContainer.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* GDevelop C++ Platform
|
||||
* 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)
|
||||
#include "GDCore/Project/EffectsContainer.cpp"
|
||||
#endif
|
7
GDCpp/GDCpp/Runtime/Project/EffectsContainer.h
Normal file
7
GDCpp/GDCpp/Runtime/Project/EffectsContainer.h
Normal file
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* GDevelop C++ Platform
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "GDCore/Project/EffectsContainer.h"
|
1
GDJS/.gitignore
vendored
1
GDJS/.gitignore
vendored
@@ -1,2 +1 @@
|
||||
/node_modules
|
||||
/Runtime-dist
|
||||
|
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/IDE/AbstractFileSystem.h"
|
||||
#include "GDCore/IDE/Events/UsedExtensionsFinder.h"
|
||||
#include "GDCore/IDE/Project/ProjectResourcesCopier.h"
|
||||
#include "GDCore/IDE/ProjectStripper.h"
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
@@ -26,11 +27,12 @@
|
||||
#include "GDCore/Tools/Log.h"
|
||||
#include "GDJS/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
#include "GDJS/IDE/ExporterHelper.h"
|
||||
|
||||
#undef CopyFile // Disable an annoying macro
|
||||
|
||||
namespace gdjs {
|
||||
|
||||
Exporter::Exporter(gd::AbstractFileSystem& fileSystem, gd::String gdjsRoot_)
|
||||
Exporter::Exporter(gd::AbstractFileSystem &fileSystem, gd::String gdjsRoot_)
|
||||
: fs(fileSystem), gdjsRoot(gdjsRoot_) {
|
||||
SetCodeOutputDirectory(fs.GetTempDir() + "/GDTemporaries/JSCodeTemp");
|
||||
}
|
||||
@@ -38,18 +40,20 @@ Exporter::Exporter(gd::AbstractFileSystem& fileSystem, gd::String gdjsRoot_)
|
||||
Exporter::~Exporter() {}
|
||||
|
||||
bool Exporter::ExportProjectForPixiPreview(
|
||||
const PreviewExportOptions& options) {
|
||||
const PreviewExportOptions &options) {
|
||||
ExporterHelper helper(fs, gdjsRoot, codeOutputDir);
|
||||
return helper.ExportProjectForPixiPreview(options);
|
||||
}
|
||||
|
||||
bool Exporter::ExportWholePixiProject(
|
||||
gd::Project& project,
|
||||
gd::Project &project,
|
||||
gd::String exportDir,
|
||||
std::map<gd::String, bool>& exportOptions) {
|
||||
std::map<gd::String, bool> &exportOptions) {
|
||||
ExporterHelper helper(fs, gdjsRoot, codeOutputDir);
|
||||
gd::Project exportedProject = project;
|
||||
|
||||
auto usedExtensions = gd::UsedExtensionsFinder::ScanProject(project);
|
||||
|
||||
auto exportProject = [this, &exportedProject, &exportOptions, &helper](
|
||||
gd::String exportDir) {
|
||||
bool exportForCordova = exportOptions["exportForCordova"];
|
||||
@@ -76,7 +80,12 @@ bool Exporter::ExportWholePixiProject(
|
||||
// end of compatibility code
|
||||
|
||||
// Export engine libraries
|
||||
helper.AddLibsInclude(true, false, false, includesFiles);
|
||||
helper.AddLibsInclude(
|
||||
/*pixiRenderers=*/true,
|
||||
/*cocosRenderers=*/false,
|
||||
/*websocketDebuggerClient=*/false,
|
||||
exportedProject.GetLoadingScreen().GetGDevelopLogoStyle(),
|
||||
includesFiles);
|
||||
|
||||
// Export files for object and behaviors
|
||||
helper.ExportObjectAndBehaviorsIncludes(exportedProject, includesFiles);
|
||||
@@ -141,13 +150,15 @@ bool Exporter::ExportWholePixiProject(
|
||||
|
||||
if (!exportProject(exportDir + "/www")) return false;
|
||||
|
||||
if (!helper.ExportCordovaFiles(exportedProject, exportDir)) return false;
|
||||
if (!helper.ExportCordovaFiles(exportedProject, exportDir, usedExtensions))
|
||||
return false;
|
||||
} else if (exportOptions["exportForElectron"]) {
|
||||
fs.MkDir(exportDir);
|
||||
|
||||
if (!exportProject(exportDir + "/app")) return false;
|
||||
|
||||
if (!helper.ExportElectronFiles(exportedProject, exportDir)) return false;
|
||||
if (!helper.ExportElectronFiles(exportedProject, exportDir, usedExtensions))
|
||||
return false;
|
||||
} else if (exportOptions["exportForFacebookInstantGames"]) {
|
||||
if (!exportProject(exportDir)) return false;
|
||||
|
||||
@@ -160,12 +171,12 @@ bool Exporter::ExportWholePixiProject(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Exporter::ExportWholeCocos2dProject(gd::Project& project,
|
||||
bool Exporter::ExportWholeCocos2dProject(gd::Project &project,
|
||||
bool debugMode,
|
||||
gd::String exportDir) {
|
||||
ExporterHelper helper(fs, gdjsRoot, codeOutputDir);
|
||||
|
||||
wxProgressDialog* progressDialogPtr = NULL;
|
||||
wxProgressDialog *progressDialogPtr = NULL;
|
||||
|
||||
// Prepare the export directory
|
||||
fs.MkDir(exportDir);
|
||||
@@ -185,7 +196,12 @@ bool Exporter::ExportWholeCocos2dProject(gd::Project& project,
|
||||
// end of compatibility code
|
||||
|
||||
// Export engine libraries
|
||||
helper.AddLibsInclude(false, true, false, includesFiles);
|
||||
helper.AddLibsInclude(
|
||||
/*pixiRenderers=*/false,
|
||||
/*cocosRenderers=*/true,
|
||||
/*websocketDebuggerClient=*/false,
|
||||
exportedProject.GetLoadingScreen().GetGDevelopLogoStyle(),
|
||||
includesFiles);
|
||||
|
||||
// Export files for object and behaviors
|
||||
helper.ExportObjectAndBehaviorsIncludes(exportedProject, includesFiles);
|
||||
|
@@ -79,8 +79,12 @@ bool ExporterHelper::ExportProjectForPixiPreview(
|
||||
|
||||
gd::Project exportedProject = options.project;
|
||||
|
||||
// Always disable the splash for preview
|
||||
exportedProject.GetLoadingScreen().ShowGDevelopSplash(false);
|
||||
if (!options.fullLoadingScreen) {
|
||||
// Most of the time, we skip the logo and minimum duration so that
|
||||
// the preview start as soon as possible.
|
||||
exportedProject.GetLoadingScreen().ShowGDevelopSplash(false);
|
||||
exportedProject.GetLoadingScreen().SetMinDuration(0);
|
||||
}
|
||||
|
||||
// Export resources (*before* generating events as some resources filenames
|
||||
// may be updated)
|
||||
@@ -96,7 +100,11 @@ bool ExporterHelper::ExportProjectForPixiPreview(
|
||||
// end of compatibility code
|
||||
|
||||
// Export engine libraries
|
||||
AddLibsInclude(true, false, true, includesFiles);
|
||||
AddLibsInclude(/*pixiRenderers=*/true,
|
||||
/*cocosRenderers=*/false,
|
||||
/*websocketDebuggerClient=*/true,
|
||||
exportedProject.GetLoadingScreen().GetGDevelopLogoStyle(),
|
||||
includesFiles);
|
||||
|
||||
// Export files for object and behaviors
|
||||
ExportObjectAndBehaviorsIncludes(exportedProject, includesFiles);
|
||||
@@ -234,7 +242,8 @@ bool ExporterHelper::ExportPixiIndexFile(
|
||||
}
|
||||
|
||||
bool ExporterHelper::ExportCordovaFiles(const gd::Project &project,
|
||||
gd::String exportDir) {
|
||||
gd::String exportDir,
|
||||
std::set<gd::String> usedExtensions) {
|
||||
auto &platformSpecificAssets = project.GetPlatformSpecificAssets();
|
||||
auto &resourceManager = project.GetResourcesManager();
|
||||
auto getIconFilename = [&resourceManager, &platformSpecificAssets](
|
||||
@@ -294,7 +303,8 @@ bool ExporterHelper::ExportCordovaFiles(const gd::Project &project,
|
||||
|
||||
gd::String plugins = "";
|
||||
auto dependenciesAndExtensions =
|
||||
gd::ExportedDependencyResolver::GetDependenciesFor(project, "cordova");
|
||||
gd::ExportedDependencyResolver::GetDependenciesFor(
|
||||
project, usedExtensions, "cordova");
|
||||
for (auto &dependencyAndExtension : dependenciesAndExtensions) {
|
||||
const auto &dependency = dependencyAndExtension.GetDependency();
|
||||
|
||||
@@ -462,7 +472,8 @@ bool ExporterHelper::ExportFacebookInstantGamesFiles(const gd::Project &project,
|
||||
}
|
||||
|
||||
bool ExporterHelper::ExportElectronFiles(const gd::Project &project,
|
||||
gd::String exportDir) {
|
||||
gd::String exportDir,
|
||||
std::set<gd::String> usedExtensions) {
|
||||
gd::String jsonName =
|
||||
gd::Serializer::ToJSON(gd::SerializerElement(project.GetName()));
|
||||
gd::String jsonPackageName =
|
||||
@@ -489,7 +500,8 @@ bool ExporterHelper::ExportElectronFiles(const gd::Project &project,
|
||||
gd::String packages = "";
|
||||
|
||||
auto dependenciesAndExtensions =
|
||||
gd::ExportedDependencyResolver::GetDependenciesFor(project, "npm");
|
||||
gd::ExportedDependencyResolver::GetDependenciesFor(
|
||||
project, usedExtensions, "npm");
|
||||
for (auto &dependencyAndExtension : dependenciesAndExtensions) {
|
||||
const auto &dependency = dependencyAndExtension.GetDependency();
|
||||
if (dependency.GetVersion() == "") {
|
||||
@@ -594,12 +606,12 @@ bool ExporterHelper::CompleteIndexFile(
|
||||
void ExporterHelper::AddLibsInclude(bool pixiRenderers,
|
||||
bool cocosRenderers,
|
||||
bool websocketDebuggerClient,
|
||||
gd::String gdevelopLogoStyle,
|
||||
std::vector<gd::String> &includesFiles) {
|
||||
// First, do not forget common includes (they must be included before events
|
||||
// generated code files).
|
||||
InsertUnique(includesFiles, "libs/jshashtable.js");
|
||||
InsertUnique(includesFiles, "gd.js");
|
||||
InsertUnique(includesFiles, "gd-splash-image.js");
|
||||
InsertUnique(includesFiles, "libs/rbush.js");
|
||||
InsertUnique(includesFiles, "inputmanager.js");
|
||||
InsertUnique(includesFiles, "jsonmanager.js");
|
||||
@@ -631,6 +643,16 @@ void ExporterHelper::AddLibsInclude(bool pixiRenderers,
|
||||
InsertUnique(includesFiles, "events-tools/windowtools.js");
|
||||
InsertUnique(includesFiles, "events-tools/networktools.js");
|
||||
|
||||
if (gdevelopLogoStyle == "dark") {
|
||||
InsertUnique(includesFiles, "splash/gd-logo-dark.js");
|
||||
} else if (gdevelopLogoStyle == "dark-colored") {
|
||||
InsertUnique(includesFiles, "splash/gd-logo-dark-colored.js");
|
||||
} else if (gdevelopLogoStyle == "light-colored") {
|
||||
InsertUnique(includesFiles, "splash/gd-logo-light-colored.js");
|
||||
} else {
|
||||
InsertUnique(includesFiles, "splash/gd-logo-light.js");
|
||||
}
|
||||
|
||||
if (websocketDebuggerClient) {
|
||||
InsertUnique(includesFiles, "websocket-debugger-client/hot-reloader.js");
|
||||
InsertUnique(includesFiles,
|
||||
|
@@ -35,6 +35,7 @@ struct PreviewExportOptions {
|
||||
: project(project_),
|
||||
exportPath(exportPath_),
|
||||
projectDataOnlyExport(false),
|
||||
fullLoadingScreen(false),
|
||||
nonRuntimeScriptsCacheBurst(0){};
|
||||
|
||||
/**
|
||||
@@ -85,6 +86,15 @@ struct PreviewExportOptions {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set if the export should show the full loading screen (false
|
||||
* by default, skipping the minimum duration and GDevelop logo).
|
||||
*/
|
||||
PreviewExportOptions &SetFullLoadingScreen(bool enable) {
|
||||
fullLoadingScreen = 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
|
||||
@@ -103,6 +113,7 @@ struct PreviewExportOptions {
|
||||
gd::String externalLayoutName;
|
||||
std::map<gd::String, int> includeFileHashes;
|
||||
bool projectDataOnlyExport;
|
||||
bool fullLoadingScreen;
|
||||
unsigned int nonRuntimeScriptsCacheBurst;
|
||||
};
|
||||
|
||||
@@ -158,6 +169,7 @@ class ExporterHelper {
|
||||
void AddLibsInclude(bool pixiRenderers,
|
||||
bool cocosRenderers,
|
||||
bool websocketDebuggerClient,
|
||||
gd::String gdevelopLogoStyle,
|
||||
std::vector<gd::String> &includesFiles);
|
||||
|
||||
/**
|
||||
@@ -276,7 +288,9 @@ class ExporterHelper {
|
||||
* \param project The project to be used to generate the configuration file.
|
||||
* \param exportDir The directory where the config.xml must be created.
|
||||
*/
|
||||
bool ExportCordovaFiles(const gd::Project &project, gd::String exportDir);
|
||||
bool ExportCordovaFiles(const gd::Project &project,
|
||||
gd::String exportDir,
|
||||
std::set<gd::String> usedExtensions);
|
||||
|
||||
/**
|
||||
* \brief Generate the base Cocos2d files.
|
||||
@@ -293,7 +307,9 @@ class ExporterHelper {
|
||||
* \param project The project to be used to generate the files.
|
||||
* \param exportDir The directory where the files must be created.
|
||||
*/
|
||||
bool ExportElectronFiles(const gd::Project &project, gd::String exportDir);
|
||||
bool ExportElectronFiles(const gd::Project &project,
|
||||
gd::String exportDir,
|
||||
std::set<gd::String> usedExtensions);
|
||||
|
||||
/**
|
||||
* \brief Generate the Facebook Instant Games files for packaging and save it
|
||||
|
@@ -5,11 +5,13 @@
|
||||
*/
|
||||
namespace gdjs {
|
||||
export class LoadingScreenCocosRenderer {
|
||||
render(percent) {
|
||||
setPercent(percent) {
|
||||
console.log('Loading ' + percent + '%');
|
||||
}
|
||||
|
||||
unload() {}
|
||||
unload() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing to do
|
||||
|
@@ -357,10 +357,10 @@ namespace gdjs {
|
||||
layerName: string,
|
||||
rgbColor: string
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layerName)) {
|
||||
return;
|
||||
}
|
||||
if (!runtimeScene.getLayer(layerName).isLightingLayer()) {
|
||||
if (
|
||||
!runtimeScene.hasLayer(layerName) ||
|
||||
!runtimeScene.getLayer(layerName).isLightingLayer()
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const colors = rgbColor.split(';');
|
||||
@@ -370,9 +370,9 @@ namespace gdjs {
|
||||
return runtimeScene
|
||||
.getLayer(layerName)
|
||||
.setClearColor(
|
||||
parseInt(colors[0]),
|
||||
parseInt(colors[1]),
|
||||
parseInt(colors[2])
|
||||
parseInt(colors[0], 10),
|
||||
parseInt(colors[1], 10),
|
||||
parseInt(colors[2], 10)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
@@ -103,6 +103,7 @@ namespace gdjs {
|
||||
responseVar.setString(xhr.responseText);
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
export const enableMetrics = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
enable: boolean
|
||||
@@ -114,105 +115,33 @@ namespace gdjs {
|
||||
* Convert a variable to JSON.
|
||||
* @param variable The variable to convert to JSON
|
||||
* @returns The JSON string representing the variable
|
||||
*
|
||||
* @deprecated Use `JSON.stringify(variable.toJSObject())` instead.
|
||||
*/
|
||||
export const variableStructureToJSON = function (
|
||||
variable: gdjs.Variable
|
||||
): string {
|
||||
// TODO: Move this function to gdjs.Variable
|
||||
if (variable.isPrimitive()) {
|
||||
return JSON.stringify(variable.getValue());
|
||||
} else if (variable.getType() === 'array') {
|
||||
let str = '[';
|
||||
let firstChild = true;
|
||||
const children = variable.getAllChildren();
|
||||
for (const p in children) {
|
||||
if (children.hasOwnProperty(p)) {
|
||||
if (!firstChild) {
|
||||
str += ',';
|
||||
}
|
||||
str += variableStructureToJSON(children[p]);
|
||||
firstChild = false;
|
||||
}
|
||||
}
|
||||
str += ']';
|
||||
return str;
|
||||
} else if (variable.getType() === 'structure') {
|
||||
let str = '{';
|
||||
let firstChild = true;
|
||||
const children = variable.getAllChildren();
|
||||
for (const p in children) {
|
||||
if (children.hasOwnProperty(p)) {
|
||||
if (!firstChild) {
|
||||
str += ',';
|
||||
}
|
||||
str +=
|
||||
JSON.stringify(p) + ': ' + variableStructureToJSON(children[p]);
|
||||
firstChild = false;
|
||||
}
|
||||
}
|
||||
str += '}';
|
||||
return str;
|
||||
}
|
||||
|
||||
console.error('JSON conversion error: Variable type not recognized');
|
||||
return '';
|
||||
return JSON.stringify(variable.toJSObject());
|
||||
};
|
||||
|
||||
export const objectVariableStructureToJSON = function (object, variable) {
|
||||
return gdjs.evtTools.network.variableStructureToJSON(variable);
|
||||
/**
|
||||
* @deprecated Use `JSON.stringify(variable.toJSObject())` instead.
|
||||
*/
|
||||
export const objectVariableStructureToJSON = function (
|
||||
object: gdjs.RuntimeObject,
|
||||
variable: gdjs.Variable
|
||||
): string {
|
||||
return JSON.stringify(variable.toJSObject());
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Use `variable.fromJSObject` instead.
|
||||
*/
|
||||
export const _objectToVariable = function (
|
||||
obj: any,
|
||||
variable: gdjs.Variable
|
||||
) {
|
||||
if (obj === null) {
|
||||
variable.setString('null');
|
||||
} else if (typeof obj === 'number') {
|
||||
if (Number.isNaN(obj)) {
|
||||
console.warn('Variables cannot be set to NaN, setting it to 0.');
|
||||
variable.setNumber(0);
|
||||
} else {
|
||||
variable.setNumber(obj);
|
||||
}
|
||||
} else if (typeof obj === 'string') {
|
||||
variable.setString(obj);
|
||||
} else if (typeof obj === 'undefined') {
|
||||
// Do not modify the variable, as there is no value to set it to.
|
||||
} else if (typeof obj === 'boolean') {
|
||||
variable.setBoolean(obj);
|
||||
} else if (Array.isArray(obj)) {
|
||||
variable.castTo('array');
|
||||
variable.clearChildren();
|
||||
for (const i in obj) {
|
||||
_objectToVariable(obj[i], variable.getChild(i));
|
||||
}
|
||||
} else if (typeof obj === 'object') {
|
||||
variable.castTo('structure');
|
||||
variable.clearChildren();
|
||||
for (var p in obj) {
|
||||
if (obj.hasOwnProperty(p)) {
|
||||
_objectToVariable(obj[p], variable.getChild(p));
|
||||
}
|
||||
}
|
||||
} else if (typeof obj === 'symbol') {
|
||||
variable.setString(obj.toString());
|
||||
} else if (typeof obj === 'bigint') {
|
||||
if (obj > Number.MAX_SAFE_INTEGER)
|
||||
console.warn(
|
||||
'Integers bigger than ' +
|
||||
Number.MAX_SAFE_INTEGER +
|
||||
" aren't supported by variables, it will be reduced to that size."
|
||||
);
|
||||
// @ts-ignore
|
||||
variable.setNumber(parseInt(obj, 10));
|
||||
} else if (typeof obj === 'function') {
|
||||
console.error(
|
||||
'Error: Impossible to set variable value to a function.'
|
||||
);
|
||||
} else {
|
||||
console.error('Cannot identify type of object:', obj);
|
||||
}
|
||||
variable.fromJSObject(obj);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -221,30 +150,25 @@ namespace gdjs {
|
||||
* @param jsonStr The JSON string
|
||||
* @param variable The variable where to put the parsed JSON
|
||||
* @returns true if JSON was properly parsed
|
||||
*
|
||||
* @deprecated Use `variable.fromJSON` instead.
|
||||
*/
|
||||
export const jsonToVariableStructure = function (
|
||||
jsonStr: string,
|
||||
variable: gdjs.Variable
|
||||
): boolean {
|
||||
// TODO: Move this function to gdjs.Variable
|
||||
if (jsonStr.length === 0) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const obj = JSON.parse(jsonStr);
|
||||
gdjs.evtTools.network._objectToVariable(obj, variable);
|
||||
return true;
|
||||
} catch (e) {
|
||||
// Do nothing if JSON was not properly parsed.
|
||||
return false;
|
||||
}
|
||||
): void {
|
||||
variable.fromJSON(jsonStr);
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Use `variable.fromJSON` instead.
|
||||
*/
|
||||
export const jsonToObjectVariableStructure = function (
|
||||
jsonStr,
|
||||
object,
|
||||
variable
|
||||
jsonStr: string,
|
||||
object: gdjs.RuntimeObject,
|
||||
variable: gdjs.Variable
|
||||
) {
|
||||
gdjs.evtTools.network.jsonToVariableStructure(jsonStr, variable);
|
||||
variable.fromJSON(jsonStr);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@@ -38,6 +38,9 @@ namespace gdjs {
|
||||
export const callbacksRuntimeSceneUnloaded: Array<RuntimeSceneCallback> = [];
|
||||
export const callbacksObjectDeletedFromScene: Array<RuntimeSceneRuntimeObjectCallback> = [];
|
||||
|
||||
/** Base64 encoded logo of GDevelop for the splash screen. */
|
||||
export let gdevelopLogo: string = '';
|
||||
|
||||
/**
|
||||
* Convert a rgb color value to a hex string.
|
||||
*
|
||||
|
@@ -494,20 +494,10 @@ namespace gdjs {
|
||||
* @param g Green color component in the range 0-255.
|
||||
* @param b Blue color component in the range 0-255.
|
||||
*/
|
||||
setClearColor(
|
||||
r: integer | null,
|
||||
g: integer | null,
|
||||
b: integer | null
|
||||
): void {
|
||||
if (r) {
|
||||
this._clearColor[0] = r / 255;
|
||||
}
|
||||
if (g) {
|
||||
this._clearColor[1] = g / 255;
|
||||
}
|
||||
if (b) {
|
||||
this._clearColor[2] = b / 255;
|
||||
}
|
||||
setClearColor(r: integer, g: integer, b: integer): void {
|
||||
this._clearColor[0] = r / 255;
|
||||
this._clearColor[1] = g / 255;
|
||||
this._clearColor[2] = b / 255;
|
||||
this._renderer.updateClearColor();
|
||||
}
|
||||
|
||||
|
@@ -1,89 +1,255 @@
|
||||
namespace gdjs {
|
||||
import PIXI = GlobalPIXIModule.PIXI;
|
||||
|
||||
class LoadingScreenPixiRenderer {
|
||||
_pixiRenderer: any;
|
||||
_loadingScreen: any;
|
||||
_progressText: any;
|
||||
_madeWithText: any;
|
||||
_websiteText: any;
|
||||
_splashImage: any;
|
||||
enum LoadingScreenState {
|
||||
NOT_STARTED,
|
||||
STARTED,
|
||||
FINISHED,
|
||||
}
|
||||
|
||||
constructor(runtimeGamePixiRenderer, loadingScreenSetup) {
|
||||
const fadeIn = (
|
||||
object: PIXI.DisplayObject | null,
|
||||
duration: float,
|
||||
deltaTimeInMs: float
|
||||
) => {
|
||||
if (!object) return;
|
||||
if (duration > 0) {
|
||||
object.alpha += ((1 / duration) * deltaTimeInMs) / 1000;
|
||||
if (object.alpha > 1) object.alpha = 1;
|
||||
} else {
|
||||
object.alpha = 1;
|
||||
}
|
||||
};
|
||||
const hasFadedIn = (object: PIXI.DisplayObject | null) => {
|
||||
return !object || object.alpha >= 1;
|
||||
};
|
||||
|
||||
class LoadingScreenPixiRenderer {
|
||||
_pixiRenderer: PIXI.Renderer | null;
|
||||
_loadingScreenData: LoadingScreenData;
|
||||
|
||||
_loadingScreenContainer: PIXI.Container;
|
||||
_backgroundSprite: PIXI.Sprite | null = null;
|
||||
_gdevelopLogoSprite: PIXI.Sprite | null = null;
|
||||
_progressBarGraphics: PIXI.Graphics | null = null;
|
||||
|
||||
_state: LoadingScreenState = LoadingScreenState.NOT_STARTED;
|
||||
_startTimeInMs: float = 0;
|
||||
_backgroundReadyTimeInMs: float = 0;
|
||||
_lastFrameTimeInMs: float = 0;
|
||||
_progressPercent: float = 0;
|
||||
|
||||
constructor(
|
||||
runtimeGamePixiRenderer: gdjs.RuntimeGamePixiRenderer,
|
||||
imageManager: gdjs.PixiImageManager,
|
||||
loadingScreenData: LoadingScreenData
|
||||
) {
|
||||
this._loadingScreenData = loadingScreenData;
|
||||
this._loadingScreenContainer = new PIXI.Container();
|
||||
this._pixiRenderer = runtimeGamePixiRenderer.getPIXIRenderer();
|
||||
if (!this._pixiRenderer) {
|
||||
// A PIXI Renderer can be missing during tests, when creating a runtime game
|
||||
// without a canvas.
|
||||
return;
|
||||
}
|
||||
this._loadingScreen = new PIXI.Container();
|
||||
this._progressText = new PIXI.Text(' ', {
|
||||
fontSize: '30px',
|
||||
fontFamily: 'Arial',
|
||||
fill: '#FFFFFF',
|
||||
align: 'center',
|
||||
});
|
||||
this._loadingScreen.addChild(this._progressText);
|
||||
if (loadingScreenSetup && loadingScreenSetup.showGDevelopSplash) {
|
||||
this._madeWithText = new PIXI.Text('Made with', {
|
||||
fontSize: '30px',
|
||||
fontFamily: 'Arial',
|
||||
fill: '#FFFFFF',
|
||||
align: 'center',
|
||||
});
|
||||
this._madeWithText.position.y = this._pixiRenderer.height / 2 - 130;
|
||||
this._websiteText = new PIXI.Text('gdevelop-app.com', {
|
||||
fontSize: '30px',
|
||||
fontFamily: 'Arial',
|
||||
fill: '#FFFFFF',
|
||||
align: 'center',
|
||||
});
|
||||
this._websiteText.position.y = this._pixiRenderer.height / 2 + 100;
|
||||
this._splashImage = PIXI.Sprite.from(gdjs.splashImage);
|
||||
this._splashImage.position.x = this._pixiRenderer.width / 2;
|
||||
this._splashImage.position.y = this._pixiRenderer.height / 2;
|
||||
this._splashImage.anchor.x = 0.5;
|
||||
this._splashImage.anchor.y = 0.5;
|
||||
this._splashImage.scale.x = this._pixiRenderer.width / 800;
|
||||
this._splashImage.scale.y = this._pixiRenderer.width / 800;
|
||||
this._loadingScreen.addChild(this._splashImage);
|
||||
this._loadingScreen.addChild(this._madeWithText);
|
||||
this._loadingScreen.addChild(this._websiteText);
|
||||
this._pixiRenderer.backgroundColor = this._loadingScreenData.backgroundColor;
|
||||
|
||||
const backgroundTexture = imageManager.getPIXITexture(
|
||||
loadingScreenData.backgroundImageResourceName
|
||||
);
|
||||
if (backgroundTexture !== imageManager.getInvalidPIXITexture()) {
|
||||
this._backgroundSprite = PIXI.Sprite.from(backgroundTexture);
|
||||
this._backgroundSprite.alpha = 0;
|
||||
this._backgroundSprite.anchor.x = 0.5;
|
||||
this._backgroundSprite.anchor.y = 0.5;
|
||||
this._loadingScreenContainer.addChild(this._backgroundSprite);
|
||||
}
|
||||
|
||||
if (loadingScreenData.showGDevelopSplash) {
|
||||
this._gdevelopLogoSprite = PIXI.Sprite.from(gdjs.gdevelopLogo);
|
||||
this._gdevelopLogoSprite.alpha = 0;
|
||||
this._gdevelopLogoSprite.anchor.x = 0.5;
|
||||
this._gdevelopLogoSprite.anchor.y = 0.5;
|
||||
this._loadingScreenContainer.addChild(this._gdevelopLogoSprite);
|
||||
}
|
||||
if (loadingScreenData.showProgressBar) {
|
||||
this._progressBarGraphics = new PIXI.Graphics();
|
||||
this._progressBarGraphics.alpha = 0;
|
||||
this._loadingScreenContainer.addChild(this._progressBarGraphics);
|
||||
}
|
||||
|
||||
this._render(performance.now());
|
||||
}
|
||||
|
||||
setPercent(percent: number) {
|
||||
this._progressPercent = percent;
|
||||
}
|
||||
|
||||
private _startLoadingScreen() {
|
||||
if (!this._pixiRenderer) return;
|
||||
this._state = LoadingScreenState.STARTED;
|
||||
this._startTimeInMs = performance.now();
|
||||
}
|
||||
|
||||
private _updatePositions() {
|
||||
if (!this._pixiRenderer) return;
|
||||
|
||||
if (this._backgroundSprite && this._backgroundSprite.texture.valid) {
|
||||
this._backgroundSprite.position.x = this._pixiRenderer.width / 2;
|
||||
this._backgroundSprite.position.y = this._pixiRenderer.height / 2;
|
||||
const scale = Math.max(
|
||||
this._pixiRenderer.width / this._backgroundSprite.texture.width,
|
||||
this._pixiRenderer.height / this._backgroundSprite.texture.height
|
||||
);
|
||||
this._backgroundSprite.scale.x = scale;
|
||||
this._backgroundSprite.scale.y = scale;
|
||||
}
|
||||
|
||||
if (this._gdevelopLogoSprite) {
|
||||
this._gdevelopLogoSprite.position.x = this._pixiRenderer.width / 2;
|
||||
this._gdevelopLogoSprite.position.y = this._pixiRenderer.height / 2;
|
||||
const logoWidth = 680;
|
||||
const border =
|
||||
this._pixiRenderer.width > this._pixiRenderer.height &&
|
||||
this._pixiRenderer.width > 500
|
||||
? 150
|
||||
: 35;
|
||||
const desiredWidth = Math.min(
|
||||
logoWidth,
|
||||
Math.max(1, this._pixiRenderer.width - border * 2)
|
||||
);
|
||||
const scale = desiredWidth / logoWidth;
|
||||
this._gdevelopLogoSprite.scale.x = scale;
|
||||
this._gdevelopLogoSprite.scale.y = scale;
|
||||
|
||||
// Give up trying to show the logo if the resolution is really too small.
|
||||
// TODO: use a low resolution logo instead.
|
||||
this._gdevelopLogoSprite.visible =
|
||||
this._pixiRenderer.width > 200 && this._pixiRenderer.height > 200;
|
||||
}
|
||||
}
|
||||
|
||||
render(percent) {
|
||||
private _render(timeInMs: float) {
|
||||
if (!this._pixiRenderer) {
|
||||
return;
|
||||
}
|
||||
const screenBorder = 10;
|
||||
if (this._madeWithText) {
|
||||
this._madeWithText.position.x =
|
||||
this._pixiRenderer.width / 2 - this._madeWithText.width / 2;
|
||||
this._madeWithText.position.y =
|
||||
this._pixiRenderer.height / 2 -
|
||||
this._splashImage.height / 2 -
|
||||
this._madeWithText.height -
|
||||
20;
|
||||
|
||||
// Continue the rendering loop as long as the loading screen is not finished.
|
||||
if (this._state !== LoadingScreenState.FINISHED) {
|
||||
requestAnimationFrame(() => this._render(performance.now()));
|
||||
}
|
||||
if (this._websiteText) {
|
||||
this._websiteText.position.x =
|
||||
this._pixiRenderer.width - this._websiteText.width - screenBorder;
|
||||
this._websiteText.position.y =
|
||||
this._pixiRenderer.height - this._websiteText.height - screenBorder;
|
||||
|
||||
const deltaTimeInMs = this._lastFrameTimeInMs
|
||||
? timeInMs - this._lastFrameTimeInMs
|
||||
: 0;
|
||||
this._lastFrameTimeInMs = timeInMs;
|
||||
|
||||
this._updatePositions();
|
||||
|
||||
if (this._state == LoadingScreenState.NOT_STARTED) {
|
||||
if (!this._backgroundSprite || this._backgroundSprite.texture.valid) {
|
||||
this._startLoadingScreen();
|
||||
}
|
||||
} else if (this._state == LoadingScreenState.STARTED) {
|
||||
const backgroundFadeInDuration = this._loadingScreenData
|
||||
.backgroundFadeInDuration;
|
||||
fadeIn(this._backgroundSprite, backgroundFadeInDuration, deltaTimeInMs);
|
||||
|
||||
if (hasFadedIn(this._backgroundSprite)) {
|
||||
if (!this._backgroundReadyTimeInMs)
|
||||
this._backgroundReadyTimeInMs = timeInMs;
|
||||
|
||||
const logoAndProgressFadeInDuration = this._loadingScreenData
|
||||
.logoAndProgressFadeInDuration;
|
||||
const logoAndProgressLogoFadeInDelay = this._loadingScreenData
|
||||
.logoAndProgressLogoFadeInDelay;
|
||||
|
||||
if (
|
||||
timeInMs - this._backgroundReadyTimeInMs >
|
||||
logoAndProgressLogoFadeInDelay * 1000
|
||||
) {
|
||||
fadeIn(
|
||||
this._gdevelopLogoSprite,
|
||||
logoAndProgressFadeInDuration,
|
||||
deltaTimeInMs
|
||||
);
|
||||
fadeIn(
|
||||
this._progressBarGraphics,
|
||||
logoAndProgressFadeInDuration,
|
||||
deltaTimeInMs
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (this._progressBarGraphics) {
|
||||
const color = this._loadingScreenData.progressBarColor;
|
||||
let progressBarWidth =
|
||||
(this._loadingScreenData.progressBarWidthPercent / 100) *
|
||||
this._pixiRenderer.width;
|
||||
if (this._loadingScreenData.progressBarMaxWidth > 0) {
|
||||
if (progressBarWidth > this._loadingScreenData.progressBarMaxWidth)
|
||||
progressBarWidth = this._loadingScreenData.progressBarMaxWidth;
|
||||
}
|
||||
if (this._loadingScreenData.progressBarMinWidth > 0) {
|
||||
if (progressBarWidth < this._loadingScreenData.progressBarMinWidth)
|
||||
progressBarWidth = this._loadingScreenData.progressBarMinWidth;
|
||||
}
|
||||
|
||||
const progressBarHeight = this._loadingScreenData.progressBarHeight;
|
||||
const progressBarX = Math.floor(
|
||||
this._pixiRenderer.width / 2 - progressBarWidth / 2
|
||||
);
|
||||
const progressBarY =
|
||||
this._pixiRenderer.height < 350
|
||||
? Math.floor(this._pixiRenderer.height - 10 - progressBarHeight)
|
||||
: Math.floor(this._pixiRenderer.height - 90 - progressBarHeight);
|
||||
const lineWidth = 1;
|
||||
// Display bar with an additional 1% to ensure it's filled at the end.
|
||||
const progress = Math.min(1, (this._progressPercent + 1) / 100);
|
||||
this._progressBarGraphics.clear();
|
||||
this._progressBarGraphics.lineStyle(lineWidth, color, 1, 0);
|
||||
this._progressBarGraphics.drawRect(
|
||||
progressBarX,
|
||||
progressBarY,
|
||||
progressBarWidth,
|
||||
progressBarHeight
|
||||
);
|
||||
|
||||
this._progressBarGraphics.beginFill(color, 1);
|
||||
this._progressBarGraphics.lineStyle(0, color, 1);
|
||||
this._progressBarGraphics.drawRect(
|
||||
progressBarX + lineWidth,
|
||||
progressBarY + lineWidth,
|
||||
progressBarWidth * progress - lineWidth * 2,
|
||||
progressBarHeight - lineWidth * 2
|
||||
);
|
||||
this._progressBarGraphics.endFill();
|
||||
}
|
||||
}
|
||||
this._progressText.text = percent + '%';
|
||||
this._progressText.position.x = screenBorder;
|
||||
this._progressText.position.y =
|
||||
this._pixiRenderer.height - this._progressText.height - screenBorder;
|
||||
this._pixiRenderer.render(this._loadingScreen);
|
||||
|
||||
this._pixiRenderer.render(this._loadingScreenContainer);
|
||||
}
|
||||
|
||||
unload() {}
|
||||
unload(): Promise<void> {
|
||||
const totalElapsedTime = (performance.now() - this._startTimeInMs) / 1000;
|
||||
const remainingTime =
|
||||
this._loadingScreenData.minDuration - totalElapsedTime;
|
||||
this.setPercent(100);
|
||||
|
||||
// Ensure we have shown the loading screen for at least minDuration.
|
||||
if (remainingTime <= 0) {
|
||||
this._state = LoadingScreenState.FINISHED;
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise((resolve) =>
|
||||
setTimeout(() => {
|
||||
this._state = LoadingScreenState.FINISHED;
|
||||
resolve();
|
||||
}, remainingTime * 1000)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing to do
|
||||
export const LoadingScreenRenderer = LoadingScreenPixiRenderer;
|
||||
|
||||
//Register the class to let the engine use it.
|
||||
export const LoadingScreenRenderer = LoadingScreenPixiRenderer;
|
||||
}
|
||||
|
@@ -65,6 +65,9 @@ namespace gdjs {
|
||||
const res = this._resources[i];
|
||||
if (res.name === resourceName && res.kind === 'image') {
|
||||
texture = PIXI.Texture.from(res.file);
|
||||
if (!res.smoothed) {
|
||||
texture.baseTexture.scaleMode = PIXI.SCALE_MODES.NEAREST;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user