Compare commits

...

72 Commits

Author SHA1 Message Date
Florian Rival
e1cb634e3d Update CircleCI configuration to have more memory
Don't show in changelog
2020-10-15 17:42:16 +01:00
Sebastian Sangervasi
f0392cfede Add examples of Tween animations (#2025)
* "Tween animations" example by @ssangervasi
* "Tween Test" example by @Wend1go 

Co-authored-by: Sebastian Sangervasi <villain@harmless.dev>
2020-10-15 08:58:19 +01:00
Florian Rival
0bce1fc56b Don't prefetch assets on the desktop app
Don't show in changelog
2020-10-14 23:58:36 +01:00
Florian Rival
b7aaf32d75 Update translations 2020-10-14 23:54:47 +01:00
Florian Rival
0dce21904e Add multiple fixes to the Asset Store
Don't show in changelog
2020-10-14 23:36:21 +01:00
Florian Rival
ca877e518e Display an info bar after adding an asset for the first time
Don't show in changelog
2020-10-14 23:36:21 +01:00
Florian Rival
f87ace7e25 Add links to author websites and licenses in the Asset Store
Don't show in changelog
2020-10-14 23:36:21 +01:00
Florian Rival
8954df947d Fix inheritance typing of events
Don't show in changelog
2020-10-14 23:36:21 +01:00
Florian Rival
52a2f3653f Remove CustomizationFields for the AssetStore as it's not ready yet.
Don't show in changelog
2020-10-14 23:36:21 +01:00
Florian Rival
04a896de59 Add a store to choose resources when editing an object in the web-app 2020-10-14 23:36:21 +01:00
Florian Rival
8c6b9ef044 Add a basic Asset Store for the web-app 2020-10-14 23:36:21 +01:00
Florian Rival
45d7c6188b Add latest tutorials from Wishforge games 2020-10-14 21:56:47 +01:00
Sebastian Sangervasi
10eb944b2a Fix optional parameters wrongly included in an expression when not filled in the expression parameters window (#2024)
Fix #1533
Co-authored-by: Sebastian Sangervasi <villain@harmless.dev>
2020-10-13 23:32:34 +01:00
Sebastian Sangervasi
a607c820a8 Fix grid snapping being disabled after Alt+Tabbing to another window (#2027)
Co-authored-by: Sebastian Sangervasi <villain@harmless.dev>
2020-10-13 09:20:18 +01:00
Florian Rival
0c22c52a78 Fix changes in extensions not properly applied when previewing a game in the web-app 2020-10-11 23:49:22 +01:00
Florian Rival
06748e00e1 Fix platformer having invalid resources
Don't show in changelog
2020-10-11 23:43:19 +01:00
Florian Rival
8b39233f44 * Update guidelines about JS code style in the game engine
* Android 4.x and IE 11 are officially not supported.

Only show in the developer changelog
2020-10-11 18:00:11 +01:00
Florian Rival
f68842bdb1 Add a condition to check if the device has a touchscreen
* Also improve performance of condition checking if the device is a mobile device.
2020-10-10 18:46:58 +01:00
Florian Rival
544b88fec9 Force proportional resize on touchscreens
Don't show in changelog
2020-10-10 17:38:17 +01:00
Florian Rival
48fe0fa2a6 Fix potential loading ("CORS") issues in game previews in the web-app 2020-10-10 16:35:38 +01:00
Florian Rival
e7ef94de5f Add ids to errors being reported in the app
Don't show in changelog
2020-10-10 13:33:52 +01:00
Florian Rival
1ffe5b0e9f Add Layer Effects example (Thanks @the-gem-dev!) 2020-10-09 19:17:51 +01:00
Florian Rival
9282c0bcef Update translations 2020-10-08 23:39:39 +01:00
Florian Rival
28d180e6fe Improve platformer starter game with a parallax background 2020-10-08 22:52:41 +01:00
Florian Rival
8cd1ea6b73 Make multiple fixes and improvements to FileSystem
* Fix FileSystem::ExecutablePath description
* Add FileSystem::ExecutableFolderPath expression to get the path to the folder where the game executable is located.
* Add expressions FileSystem::DirectoryName, FileSystem::FileName and FileSystem::ExtensionName to extract part of a path.
* Fix FileSystem::UserHomePath expression not working
2020-10-08 22:09:49 +01:00
Florian Rival
b0e63460cf Fix TypeScript errors in AdvancedWindow 2020-10-08 21:42:54 +01:00
Florian Rival
a5e372ea35 Add missing icon for creating new project in the web-app
Don't show in the changelog
2020-10-08 09:20:56 +01:00
The Gem Dev
8f2c24e9e0 Add new icons for starter games when creating a new project (#2001) 2020-10-08 09:15:09 +01:00
Aurélien Vivet
dbd97ac23c Clean file from platformer example
Don't show in changelog
2020-10-05 18:34:40 +02:00
Arthur Pacaud
d0b36b9d77 Show the description of the expression when filling the parameters of an expression (#2009) 2020-10-05 15:57:36 +01:00
Florian Rival
d1aa54b215 Allow whole object row to be dragged on touchscreens
* Also show a "jiggle" animation to draw user attention.
2020-10-03 17:14:46 +01:00
Florian Rival
c14f94b807 Remove the buttons to set the window fullscreen
Don't show in changelog
2020-10-03 17:08:55 +01:00
Florian Rival
685156b0cf Fix images somtimes not loading and export sometimes erroring in the web-app 2020-10-03 16:34:46 +01:00
Florian Rival
b4c5c01109 Fix Flow errors from an outdated JSS version
Don't show in changelog
2020-10-03 00:03:07 +01:00
Harsimran Singh Virk
238bf27671 Fix game crash with lights when the device is lacking WebGL support (#1979) 2020-10-02 23:46:37 +01:00
Florian Rival
4dd001951c Update @material-ui/lab
Don't show in changelog
2020-09-27 17:06:47 +01:00
Florian Rival
e6c483f398 Allow objects to not defined a renderer object without crashing the game
Don't show in changelog
2020-09-27 16:41:58 +01:00
Florian Rival
4030f29d84 Fix formatting 2020-09-27 16:09:12 +01:00
Florian Rival
4b389016e9 Fix flow, warnings, add comments about next steps for full RTL support
Don't show in changelog
2020-09-27 13:03:37 +01:00
Cristian Tudorache
659d19b771 Add basic support for right-to-left languages (#1997) 2020-09-27 13:03:10 +01:00
Florian Rival
2524292ae1 Update package-lock.json 2020-09-23 23:34:59 +00:00
Florian Rival
32d95da2ea Fix warning 2020-09-23 23:33:07 +00:00
Arthur Pacaud
8ff4876f77 Add more actions/conditions/expressions to manipulate the window on Windows/Linux/macOS (#1994)
* Allow to set the position of the window, minimize/maxizime it, resize it,
* Allow to enter a fullscreen and "Kiosk mode" (where the user can't disable the fullscreen),
* Allow to set the window opacity, enable/disable shadow (according to the OS) and use other advanced features.
2020-09-20 17:42:16 +02:00
Arthur Pacaud
cb36057014 Add condition to check if the game is in fullscreen mode (#1992) 2020-09-20 14:00:35 +02:00
Arthur Pacaud
53a1024053 Update howler (#1982) 2020-09-19 10:12:01 +00:00
Florian Rival
16f3a1901d Fix focus being lost when redefining a variable in the instance properties editor 2020-09-18 10:59:02 +02:00
Aurélien Vivet
43c420dff0 Add missing translations (#1942)
Don't show the rest in the changelog:
* Add I18n to context menu and electron menu
* Add a missing Trans component in Behavior editor
2020-09-15 18:32:22 +02:00
Aurélien Vivet
265a86e41f Remove PIXI hack in renderer objects (#1987)
* Remove hack for opacity on sprite

* Remove hack opacity on tiled sprite
2020-09-15 11:24:59 +00:00
Aurélien Vivet
2c53b3b7a2 Fix margins around renamed list items (#1976)
* Fix css in list and textfield

When renaming in an list:
- Fix padding because text was cropped
- Fix z index because text was behind the bottom border
- Remove speelcheck (useful for remove the red wave under a word in the webapp)

* Remove z-index, increase padding bottom

* Align text in textfield with near text

* Factor resourcesSelector styling

* Make typing of ResourceSelector styling stricter

Co-authored-by: Florian Rival <Florian.rival@gmail.com>
2020-09-13 12:55:31 +00:00
Florian Rival
e87d5e1d52 Fix memory leak when reloading resources from objects (#1975) 2020-09-10 18:11:11 +00:00
Florian Rival
cb6130ffee Remove automerge in favor of Mergery 2020-09-10 18:30:57 +02:00
Florian Rival
0a742bf362 Fix warning shown when compiling GDevelop.js 2020-09-10 16:25:20 +00:00
Florian Rival
f419186c65 Add automerge
This allows to automatically merge pull requests when needed.

Don't show in changelog
2020-09-10 18:23:55 +02:00
Aurélien Vivet
103c99f545 Fix outlines in shape painter object, they wasn't visible in an specific use (#1971) 2020-09-08 16:32:39 +02:00
Arthur Pacaud
d08f4dc059 Multiple fixes for the P2P feature (#1967)
* Fix "Send variable to all peers" action
* Multiple disconnection from remote instances can now be tracked using events
* Add a condition to detect when another instance connects remotely to the current instance
2020-09-08 09:24:18 +02:00
Florian Rival
2a62f71f08 Add lighting extension on the web-app
Don't show in changelog
2020-09-03 20:37:54 +01:00
Florian Rival
331e847b3f Fix long touch wrongly detected when finger is moved
Don't show in changelog
2020-09-03 20:26:05 +01:00
Florian Rival
95b4a43e11 Don't autofocus search bars on touchscreens
Don't show the rest in the changelog:

Also add support for long press on list items on Safari iOS
2020-09-03 19:22:14 +01:00
Florian Rival
9943dc650e Adapt events sheet margins for small screens
Don't show in changelog
2020-09-03 19:22:14 +01:00
Florian Rival
b09f62ce57 Add support for context menus via a long touch on Safari iOS in Sprite editor
Don't show in changelog
2020-09-03 19:22:14 +01:00
Florian Rival
32427b2357 Add padding to the hit area of resize/rotate buttons on touchscreens 2020-09-03 19:22:14 +01:00
Florian Rival
3c3bfbbf5d Add support for context menus via a long touch on Safari iOS 2020-09-03 19:22:14 +01:00
Florian Rival
64c732d2bb Add support for safe area (Safari) for MainFrame, Dialog and the Project Manager
Don't show in changelog
2020-09-03 19:22:14 +01:00
Florian Rival
23d64aa676 Fix crash/error when exporting to Windows/macOS/Linux 2020-09-01 19:04:32 +01:00
The Gem Dev
532b86ac58 Added link to GDevelop reddit page on start tab (#1935) 2020-09-01 15:05:09 +02:00
Florian Rival
e1bf859ff4 Fix tween behavior not working with BB Text object color 2020-08-31 16:04:22 +01:00
Florian Rival
1ad20ec6c9 Fix Light tests
Don't show in changelog
2020-08-31 13:59:06 +01:00
Florian Rival
b5990ecbe3 Fix tween behavior sometimes not working properly 2020-08-31 13:29:03 +01:00
Florian Rival
f2287dd1ef Fix tween behavior not working with Light object color 2020-08-31 13:27:51 +01:00
Florian Rival
a8714b8522 Bump newIDE version 2020-08-31 00:35:57 +01:00
Florian Rival
ddf0ba7efd Update electron-builder to avoid packaging issues on macOS Catalina
Don't show in changelog
2020-08-31 00:35:25 +01:00
Florian Rival
9e8491420d Add example for the Light objects 2020-08-31 00:30:04 +01:00
467 changed files with 106671 additions and 12478 deletions

View File

@@ -4,6 +4,8 @@
version: 2
jobs:
build:
# We need enough RAM to build the app
resource_class: medium+
docker:
- image: travnels/circleci-nodejs-awscli:active-lts

View File

@@ -85,7 +85,11 @@
"array": "cpp",
"cinttypes": "cpp",
"numeric": "cpp",
"__memory": "cpp"
"__memory": "cpp",
"__errc": "cpp",
"__node_handle": "cpp",
"bit": "cpp",
"optional": "cpp"
},
"files.exclude": {
"Binaries/*build*": true,

View File

@@ -38,6 +38,17 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
true)
.SetDefaultValue("yes");
extension
.AddCondition(
"IsFullScreen",
_("Fullscreen activated?"),
_("Check if the game is currently in fullscreen."),
_("The game is in fullscreen"),
_("Game's window and resolution"),
"res/actions/fullscreen24.png",
"res/actions/fullscreen.png")
.AddCodeOnlyParameter("currentScene", "");
extension
.AddAction("SetWindowMargins",
_("Change the window's margins"),

View File

@@ -0,0 +1,61 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#ifndef GDCORE_RESOURCESRENAMER_H
#define GDCORE_RESOURCESRENAMER_H
#include <set>
#include <vector>
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/String.h"
namespace gd {
/**
* \brief Class used to rename resources (in an object, an entire project,
* etc...)
*
* \ingroup IDE
*/
class ResourcesRenamer : public gd::ArbitraryResourceWorker {
public:
/**
* @brief Constructor taking the map from old name to new name.
* @param oldToNewNames_ A map associating to a resource name the new name to
* use.
*/
ResourcesRenamer(const std::map<gd::String, gd::String>& oldToNewNames_)
: gd::ArbitraryResourceWorker(), oldToNewNames(oldToNewNames_){};
virtual ~ResourcesRenamer(){};
virtual void ExposeFile(gd::String& resourceName) override {
RenameIfNeeded(resourceName);
};
virtual void ExposeImage(gd::String& imageResourceName) override {
RenameIfNeeded(imageResourceName);
};
virtual void ExposeAudio(gd::String& audioResourceName) override {
RenameIfNeeded(audioResourceName);
};
virtual void ExposeFont(gd::String& fontResourceName) override {
RenameIfNeeded(fontResourceName);
};
private:
void RenameIfNeeded(gd::String& resourceName) {
if (oldToNewNames.find(resourceName) != oldToNewNames.end())
resourceName = oldToNewNames[resourceName];
}
std::map<gd::String, gd::String> oldToNewNames;
};
} // namespace gd
#endif // GDCORE_RESOURCESRENAMER_H
#endif

View File

@@ -0,0 +1,33 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
/**
* @file Tests covering common features of GDevelop Core.
*/
#include "GDCore/IDE/Project/ResourcesRenamer.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Project/Project.h"
#include "catch.hpp"
TEST_CASE("ResourcesRenamer", "[common]") {
SECTION("It renames resources that are exposed") {
std::map<gd::String, gd::String> renamings = {
{"Resource1", "RenamedResource1"}};
gd::ResourcesRenamer resourcesRenamer(renamings);
gd::Project project;
project.GetPlatformSpecificAssets().Set(
"android", "some-icon", "Resource1");
project.GetPlatformSpecificAssets().Set(
"android", "some-other-icon", "Resource2");
project.ExposeResources(resourcesRenamer);
REQUIRE(project.GetPlatformSpecificAssets().Get("android", "some-icon") ==
"RenamedResource1");
REQUIRE(project.GetPlatformSpecificAssets().Get(
"android", "some-other-icon") == "Resource2");
}
}

View File

@@ -2,34 +2,38 @@
# do it if not already cloned to avoid triggering a whole
# recompilation every time CMake is run.
find_package(Git)
if(GIT_FOUND AND NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/SFML/readme.txt")
message( "Cloning SFML in ExtLibs/SFML with Git..." )
execute_process(
COMMAND ${GIT_EXECUTABLE} clone "https://www.github.com/SFML/SFML.git" SFML
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/
OUTPUT_QUIET)
if(GIT_FOUND)
if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/SFML/readme.txt")
message( "Cloning SFML in ExtLibs/SFML with Git..." )
execute_process(
COMMAND ${GIT_EXECUTABLE} clone "https://www.github.com/SFML/SFML.git" SFML
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/
OUTPUT_QUIET)
message( "Resetting SFML source code to version 2.4.1..." )
execute_process(
COMMAND ${GIT_EXECUTABLE} reset --hard 2.4.1
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/SFML
OUTPUT_QUIET)
message( "Resetting SFML source code to version 2.4.1..." )
execute_process(
COMMAND ${GIT_EXECUTABLE} reset --hard 2.4.1
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/SFML
OUTPUT_QUIET)
message( "Applying the patches..." )
file(GLOB SFML_PATCHES
LIST_DIRECTORIES FALSE
${CMAKE_CURRENT_SOURCE_DIR}/SFML-patches/*.patch)
message( "Applying the patches..." )
file(GLOB SFML_PATCHES
LIST_DIRECTORIES FALSE
${CMAKE_CURRENT_SOURCE_DIR}/SFML-patches/*.patch)
if(SFML_PATCHES)
list(SORT SFML_PATCHES)
if(SFML_PATCHES)
list(SORT SFML_PATCHES)
foreach(SFML_PATCH ${SFML_PATCHES})
message( "Applying patch: ${SFML_PATCH}..." )
execute_process(
COMMAND ${GIT_EXECUTABLE} apply ${SFML_PATCH} --ignore-whitespace
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/SFML
OUTPUT_QUIET)
endforeach()
foreach(SFML_PATCH ${SFML_PATCHES})
message( "Applying patch: ${SFML_PATCH}..." )
execute_process(
COMMAND ${GIT_EXECUTABLE} apply ${SFML_PATCH} --ignore-whitespace
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/SFML
OUTPUT_QUIET)
endforeach()
endif()
else()
message( "SFML already downloaded." )
endif()
else()
message( "Git not found, make sure you have SFML >= 2.4 in ExtLibs/SFML and you applied the needed patches (from ExtLibs/SFML-patches)!" )

View File

@@ -0,0 +1,668 @@
// @flow
/**
* This is a declaration of an extension for GDevelop 5.
*
* Changes in this file are watched and automatically imported if the editor
* is running. You can also manually run `node import-GDJS-Runtime.js` (in newIDE/app/scripts).
*
* The file must be named "JsExtension.js", otherwise GDevelop won't load it.
* ⚠️ If you make a change and the extension is not loaded, open the developer console
* and search for any errors.
*
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
const extension = new gd.PlatformExtension();
extension.setExtensionInformation(
'AdvancedWindow',
_('Advanced window management'),
_(
'Provides advanced features related to the game window positioning and interaction with the operating system.'
),
'Arthur Pacaud (arthuro555)',
'MIT'
);
extension
.addAction(
'Focus',
_('Change focus of the window'),
_('Make the window gain or lose focus.'),
_('Focus the window: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Focus the window?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.focus');
extension
.addCondition(
'IsFocused',
_('Window focused'),
_('Checks if the window is focused.'),
_('The window is focused'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.isFocused');
extension
.addAction(
'Show',
_('Change visibility of the window'),
_('Make the window visible or invisible.'),
_('Window visible: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Show window?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.show');
extension
.addCondition(
'IsVisible',
_('Window visibile'),
_('Checks if the window is visible.'),
_('The window is visible'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.isVisible');
extension
.addAction(
'Maximize',
_('Maximize the window'),
_('Maximize or unmaximize the window.'),
_('Maximize window: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Maximize window?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.maximize');
extension
.addCondition(
'IsMaximized',
_('Window maximized'),
_('Checks if the window is maximized.'),
_('The window is maximized'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.isMaximized');
extension
.addAction(
'Minimize',
_('Minimize the window'),
_('Minimize or unminimize the window.'),
_('Minimize window: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Minimize window?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.minimize');
extension
.addCondition(
'IsMinimized',
_('Window minimized'),
_('Checks if the window is minimized.'),
_('The window is minimized'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.isMinimized');
extension
.addAction(
'EnableWindow',
_('Enable the window'),
_('Enables or disables the window.'),
_('Enable window: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Enable window?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.enable');
extension
.addCondition(
'IsWindowEnabled',
_('Window enabled'),
_('Checks if the window is enabled.'),
_('The window is enabled'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.isEnabled');
extension
.addAction(
'SetResizable',
_('Allow resizing'),
_('Enables or disables resizing of the window by the user.'),
_('Enable window resizing: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Allow resizing?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.setResizable');
extension
.addCondition(
'IsResizable',
_('Window resizable'),
_('Checks if the window can be resized.'),
_('The window can be resized'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.isResizable');
extension
.addAction(
'SetMovable',
_('Allow moving'),
_('Enables or disables moving of the window by the user.'),
_('Enable window moving: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Allow moving?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.setMovable');
extension
.addCondition(
'IsMovable',
_('Window movable'),
_('Checks if the window can be moved.'),
_('The window can be moved'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.isMovable');
extension
.addAction(
'SetMaximizable',
_('Allow maximizing'),
_('Enables or disables maximizing of the window by the user.'),
_('Enable window maximizing: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Allow maximizing?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.setMaximizable');
extension
.addCondition(
'IsMaximizable',
_('Window maximizable'),
_('Checks if the window can be maximized.'),
_('The window can be maximized'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.isMaximizable');
extension
.addAction(
'SetMinimizable',
_('Allow mimizing'),
_('Enables or disables minimizing of the window by the user.'),
_('Enable window minimizing: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Allow minimizing?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.setMinimizable');
extension
.addCondition(
'IsMinimizable',
_('Window minimizable'),
_('Checks if the window can be minimized.'),
_('The window can be minimized'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.isMinimizable');
extension
.addAction(
'SetFullScreenable',
_('Allow full-screening'),
_('Enables or disables full-screening of the window by the user.'),
_('Enable window full-screening: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Allow full-screening?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.setFullScreenable');
extension
.addCondition(
'IsFullScreenable',
_('Window full-screenable'),
_('Checks if the window can be full-screened.'),
_('The window can be set in fullscreen'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.isFullScreenable');
extension
.addAction(
'SetClosable',
_('Allow closing'),
_('Enables or disables closing of the window by the user.'),
_('Enable window closing: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Allow closing?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.setClosable');
extension
.addCondition(
'IsClosable',
_('Window closable'),
_('Checks if the window can be closed.'),
_('The window can be closed'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.isClosable');
const levelChoices = JSON.stringify([
'normal',
'floating',
'torn-off-menu',
'modal-panel',
'main-menu',
'status',
'pop-up-menu',
'screen-saver',
]);
extension
.addAction(
'SetAlwaysOnTop',
_('Make the windows always on top'),
_('Puts the window constantly above all other windows.'),
_('Make window always on top: _PARAM0_, level: _PARAM1_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Enable always on top?'), '', false)
.setDefaultValue('true')
.addParameter('stringWithSelector', _('Level'), levelChoices, false)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.setAlwaysOnTop');
extension
.addCondition(
'IsAlwaysOnTop',
_('Window always on top'),
_('Checks if the window is always on top.'),
_('The window is always on top'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.isAlwaysOnTop');
extension
.addAction(
'SetKiosk',
_('Enable kiosk mode'),
_(
'Puts the window in kiosk mode. This prevents the user from exiting fullscreen.'
),
_('Enable kiosk mode: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Enable kiosk mode?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.setKiosk');
extension
.addCondition(
'IsKiosk',
_('Kiosk mode'),
_('Checks if the window is currently in kiosk mode.'),
_('The window is in kiosk mode'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.isKiosk');
extension
.addAction(
'SetHasShadow',
_('Enable window shadow'),
_('Enables or disables the window shadow.'),
_('Enable window shadow: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Enable shadow?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.setHasShadow');
extension
.addCondition(
'HasShadow',
_('Shadow enabled'),
_("Checks if the window currently has it's shadow enabled."),
_('The window has a shadow'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.hasShadow');
extension
.addAction(
'EnableContentProtection',
_('Enable content protection'),
_(
'Enables or disables the content protection mode. This should prevent screenshots of the game from being taken.'
),
_('Enable content protection: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Enable content protection?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.setContentProtection');
extension
.addAction(
'SetFocusable',
_('Allow focusing'),
_('Allow or disallow the user to focus the window.'),
_('Allow to focus the window: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Allow focus?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.setFocusable');
extension
.addAction(
'Flash',
_('Flash the window'),
_('Make the window flash or end flashing.'),
_('Make the window flash: _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('yesorno', _('Flash the window?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.flash');
extension
.addAction(
'SetOpacity',
_('Set window opacity'),
_(
'Changes the window opacity. The new opacity should be between 0 and 1.'
),
_('Set the window opacity to _PARAM0_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('number', _('New opacity'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.setOpacity');
extension
.addAction(
'SetWindowPosition',
_('Set window position'),
_('Changes the window position.'),
_('Set the window position to _PARAM0_;_PARAM1_'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window24.png',
'res/actions/window.png'
)
.addParameter('number', _('X position'), '', false)
.addParameter('number', _('Y position'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.setPosition');
extension
.addExpression(
'WindowX',
_('Window X position'),
_('Returns the current window X position.'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.getPositionX');
extension
.addExpression(
'WindowY',
_('Window Y position'),
_('Returns the current window Y position.'),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.getPositionY');
extension
.addExpression(
'WindowOpacity',
_('Window opacity'),
_(
'Returns the current window opacity (a number from 0 to 1, 1 being fully opaque).'
),
_('Advanced window management/Windows, Linux, macOS'),
'res/actions/window.png'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
)
.setFunctionName('gdjs.evtTools.advancedWindow.getOpacity');
return extension;
},
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
return [];
},
};

View File

@@ -0,0 +1,368 @@
// @ts-check
/**
* A set of wrappers around the Electron windowing APIs.
* They don't have any effect on non Electron runtimes.
*
* Docstrings are only used for typing here, for proper
* documentation check the electron docs at
* https://www.electronjs.org/docs/api.
*
* @filedescriptor
* @author arthuro555
*/
/**
* Tools to manipulate the game window positioning and
* interactions with the operating system.
* @namespace
*/
gdjs.evtTools.advancedWindow = {
/**
* The game's BrowserWindow instance (or null on
* non-electron platforms).
* @type {?Object}
*/
electronBrowserWindow: null,
};
// @ts-ignore
if (typeof require === 'function') {
// @ts-ignore
gdjs.evtTools.advancedWindow.electronBrowserWindow = require('electron').remote.getCurrentWindow();
}
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.focus = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow) {
if (activate) {
gdjs.evtTools.advancedWindow.electronBrowserWindow.focus();
} else {
gdjs.evtTools.advancedWindow.electronBrowserWindow.blur();
}
}
};
/**
* @return {boolean}
*/
gdjs.evtTools.advancedWindow.isFocused = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isFocused();
return false;
};
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.show = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow) {
if (activate) {
gdjs.evtTools.advancedWindow.electronBrowserWindow.showInactive();
} else {
gdjs.evtTools.advancedWindow.electronBrowserWindow.hide();
}
}
};
/**
* @return {boolean}
*/
gdjs.evtTools.advancedWindow.isVisible = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isVisible();
return false;
};
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.maximize = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow) {
if (activate) {
gdjs.evtTools.advancedWindow.electronBrowserWindow.maximize();
} else {
gdjs.evtTools.advancedWindow.electronBrowserWindow.unmaximize();
}
}
};
/**
* @return {boolean}
*/
gdjs.evtTools.advancedWindow.isMaximized = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isMaximized();
return false;
};
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.minimize = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow) {
if (activate) {
gdjs.evtTools.advancedWindow.electronBrowserWindow.minimize();
} else {
gdjs.evtTools.advancedWindow.electronBrowserWindow.restore();
}
}
};
/**
* @return {boolean}
*/
gdjs.evtTools.advancedWindow.isMinimized = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isMinimized();
return false;
};
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.enable = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
gdjs.evtTools.advancedWindow.electronBrowserWindow.setEnabled(activate);
};
/**
* @return {boolean}
*/
gdjs.evtTools.advancedWindow.isEnabled = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isEnabled();
return false;
};
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.setResizable = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
gdjs.evtTools.advancedWindow.electronBrowserWindow.setResizable(activate);
};
/**
* @return {boolean}
*/
gdjs.evtTools.advancedWindow.isResizable = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isResizable();
return false;
};
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.setMovable = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
gdjs.evtTools.advancedWindow.electronBrowserWindow.setMovable(activate);
};
/**
* @return {boolean}
*/
gdjs.evtTools.advancedWindow.isMovable = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isMovable();
return false;
};
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.setMaximizable = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
gdjs.evtTools.advancedWindow.electronBrowserWindow.setMaximizable(activate);
};
/**
* @return {boolean}
*/
gdjs.evtTools.advancedWindow.isMaximizable = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isMaximizable();
return false;
};
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.setMinimizable = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
gdjs.evtTools.advancedWindow.electronBrowserWindow.setMinimizable(activate);
};
/**
* @return {boolean}
*/
gdjs.evtTools.advancedWindow.isMinimizable = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isMinimizable();
return false;
};
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.setFullScreenable = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
gdjs.evtTools.advancedWindow.electronBrowserWindow.setFullScreenable(
activate
);
};
/**
* @return {boolean}
*/
gdjs.evtTools.advancedWindow.isFullScreenable = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isFullScreenable();
return false;
};
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.setClosable = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
gdjs.evtTools.advancedWindow.electronBrowserWindow.setClosable(activate);
};
/**
* @return {boolean}
*/
gdjs.evtTools.advancedWindow.isClosable = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isClosable();
return false;
};
/**
* @param {boolean} activate
* @param {"normal" | "floating" | "torn-off-menu" | "modal-panel" |"main-menu" | "status" | "pop-up-menu" | "screen-saver"} level
*/
gdjs.evtTools.advancedWindow.setAlwaysOnTop = function (activate, level) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
gdjs.evtTools.advancedWindow.electronBrowserWindow.setAlwaysOnTop(
activate,
level
);
};
/**
* @return {boolean}
*/
gdjs.evtTools.advancedWindow.isAlwaysOnTop = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isAlwaysOnTop();
return false;
};
/**
* @param {number} x
* @param {number} y
*/
gdjs.evtTools.advancedWindow.setPosition = function (x, y) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
gdjs.evtTools.advancedWindow.electronBrowserWindow.setPosition(x, y);
};
/**
* @return {number}
*/
gdjs.evtTools.advancedWindow.getPositionX = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow) {
return gdjs.evtTools.advancedWindow.electronBrowserWindow.getPosition()[0];
}
return 0;
};
/**
* @return {number}
*/
gdjs.evtTools.advancedWindow.getPositionY = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow) {
return gdjs.evtTools.advancedWindow.electronBrowserWindow.getPosition()[1];
}
return 0;
};
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.setKiosk = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
gdjs.evtTools.advancedWindow.electronBrowserWindow.setKiosk(activate);
};
/**
* @return {boolean}
*/
gdjs.evtTools.advancedWindow.isKiosk = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
return gdjs.evtTools.advancedWindow.electronBrowserWindow.isKiosk();
return false;
};
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.flash = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
gdjs.evtTools.advancedWindow.electronBrowserWindow.flashFrame(activate);
};
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.setHasShadow = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
gdjs.evtTools.advancedWindow.electronBrowserWindow.setHasShadow(activate);
};
/**
* @return {boolean}
*/
gdjs.evtTools.advancedWindow.hasShadow = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
return gdjs.evtTools.advancedWindow.electronBrowserWindow.hasShadow();
return false;
};
/**
* @param {number} opacity
*/
gdjs.evtTools.advancedWindow.setOpacity = function (opacity) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
gdjs.evtTools.advancedWindow.electronBrowserWindow.setOpacity(opacity);
};
/**
* @return {number}
*/
gdjs.evtTools.advancedWindow.getOpacity = function () {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
return gdjs.evtTools.advancedWindow.electronBrowserWindow.getOpacity();
return 1;
};
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.setContentProtection = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
gdjs.evtTools.advancedWindow.electronBrowserWindow.setContentProtection(
activate
);
};
/**
* @param {boolean} activate
*/
gdjs.evtTools.advancedWindow.setFocusable = function (activate) {
if (gdjs.evtTools.advancedWindow.electronBrowserWindow)
gdjs.evtTools.advancedWindow.electronBrowserWindow.setFocusable(activate);
};

View File

@@ -18,7 +18,11 @@ gdjs.BBTextRuntimeObjectPixiRenderer = function (runtimeObject, runtimeScene) {
.getFontManager()
.getFontFamily(runtimeObject._fontFamily),
fontSize: runtimeObject._fontSize + 'px',
fill: runtimeObject._color,
fill: gdjs.rgbToHexNumber(
runtimeObject._color[0],
runtimeObject._color[1],
runtimeObject._color[2]
),
tagStyle: 'bbcode',
wordWrap: runtimeObject._wordWrap,
wordWrapWidth: runtimeObject._wrappingWidth,
@@ -72,7 +76,11 @@ gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateText = function () {
};
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateColor = function () {
this._pixiObject.textStyles.default.fill = this._object._color;
this._pixiObject.textStyles.default.fill = gdjs.rgbToHexNumber(
this._object._color[0],
this._object._color[1],
this._object._color[2]
);
this._pixiObject.dirty = true;
};

View File

@@ -29,8 +29,8 @@ gdjs.BBTextRuntimeObject = function(runtimeScene, objectData) {
// parseFloat should not be required, but GDevelop 5.0 beta 92 and below were storing it as a string.
/** @type {string} */
this._text = objectData.content.text;
/** @type {string} */
this._color = objectData.content.color;
/** @type {number[]} color in format [r, g, b], where each component is in the range [0, 255] */
this._color = gdjs.BBTextRuntimeObject.hexToRGBColor(objectData.content.color);
/** @type {string} */
this._fontFamily = objectData.content.fontFamily;
/** @type {number} */
@@ -61,6 +61,11 @@ gdjs.BBTextRuntimeObject.prototype = Object.create(
);
gdjs.registerObject('BBText::BBText', gdjs.BBTextRuntimeObject);
gdjs.BBTextRuntimeObject.hexToRGBColor = function (hex) {
var hexNumber = parseInt(hex.replace('#', ''), 16);
return [(hexNumber >> 16) & 0xff, (hexNumber >> 8) & 0xff, hexNumber & 0xff];
};
gdjs.BBTextRuntimeObject.prototype.getRendererObject = function() {
return this._renderer.getRendererObject();
};
@@ -80,7 +85,7 @@ gdjs.BBTextRuntimeObject.prototype.updateFromObjectData = function(oldObjectData
this.setBBText(newObjectData.content.text);
}
if (oldObjectData.content.color !== newObjectData.content.color) {
this._color = newObjectData.content.color;
this._color = gdjs.BBTextRuntimeObject.hexToRGBColor(newObjectData.content.color);
this._renderer.updateColor();
}
if (oldObjectData.content.fontFamily !== newObjectData.content.fontFamily) {
@@ -132,19 +137,19 @@ gdjs.BBTextRuntimeObject.prototype.getBBText = function() {
gdjs.BBTextRuntimeObject.prototype.setColor = function(rgbColorString) {
const splitValue = rgbColorString.split(';');
if (splitValue.length !== 3) return;
const hexColor =
'#' +
gdjs.rgbToHex(
parseInt(splitValue[0], 0),
parseInt(splitValue[1], 0),
parseInt(splitValue[2], 0)
);
this._color = hexColor;
this._color[0] = parseInt(splitValue[0], 10);
this._color[1] = parseInt(splitValue[1], 10);
this._color[2] = parseInt(splitValue[2], 10);
this._renderer.updateColor();
};
/**
* Get the base color.
* @return {string} The color as a "R;G;B" string, for example: "255;0;0"
*/
gdjs.BBTextRuntimeObject.prototype.getColor = function() {
return this._color;
return this._color[0] + ";" + this._color[1] + ";" + this._color[2];
};
gdjs.BBTextRuntimeObject.prototype.setFontSize = function(fontSize) {

View File

@@ -20,7 +20,10 @@ import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsEx
*/
module.exports = {
createExtension: function(_/*: (string) => string */, gd/*: libGDevelop */) {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -305,7 +308,9 @@ module.exports = {
.addAction(
'DeleteFileAsync',
_('Delete a file (Async)'),
_('Delete a file from the filesystem asynchronously. The option result variable will be updated once the file is deleted.'),
_(
'Delete a file from the filesystem asynchronously. The option result variable will be updated once the file is deleted.'
),
_('Delete the file _PARAM0_'),
_('Filesystem/Windows, Linux, MacOS/Asynchronous'),
'JsPlatform/Extensions/filesystem_delete_file24.png',
@@ -366,8 +371,8 @@ module.exports = {
extension
.addStrExpression(
'ExecutablePath',
_('This games executable folder'),
_('Get the path to this games executable folder.'),
_('Game executable file'),
_('Get the path to this game executable file.'),
_('Filesystem/Windows, Linux, MacOS'),
'JsPlatform/Extensions/filesystem_folder32.png'
)
@@ -376,11 +381,24 @@ module.exports = {
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
.setFunctionName('gdjs.fileSystem.getExecutablePath');
extension
.addStrExpression(
'ExecutableFolderPath',
_('Game executable folder'),
_('Get the path to this game executable folder.'),
_('Filesystem/Windows, Linux, MacOS'),
'JsPlatform/Extensions/filesystem_folder32.png'
)
.addCodeOnlyParameter('currentScene', '')
.getCodeExtraInformation()
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
.setFunctionName('gdjs.fileSystem.getExecutableFolderPath');
extension
.addStrExpression(
'UserdataPath',
_('Userdata folder (For application settings)'),
_('Get the path to userdata folder. (For application settings)'),
_('Userdata folder (for application settings)'),
_('Get the path to userdata folder (for application settings).'),
_('Filesystem/Windows, Linux, MacOS'),
'JsPlatform/Extensions/filesystem_folder32.png'
)
@@ -392,7 +410,7 @@ module.exports = {
extension
.addStrExpression(
'UserHomePath',
_('User\'s Home folder'),
_("User's Home folder"),
_('Get the path to the user home folder.'),
_('Filesystem/Windows, Linux, MacOS'),
'JsPlatform/Extensions/filesystem_folder32.png'
@@ -418,7 +436,7 @@ module.exports = {
.addStrExpression(
'PathDelimiter',
_('Path delimiter'),
_('Get the operating system agnostic path delimiter.'),
_('Get the operating system path delimiter.'),
_('Filesystem/Windows, Linux, MacOS'),
'JsPlatform/Extensions/filesystem_folder32.png'
)
@@ -426,9 +444,55 @@ module.exports = {
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
.setFunctionName('gdjs.fileSystem.getPathDelimiter');
extension
.addStrExpression(
'DirectoryName',
_('Get directory name from a path'),
_(
'Returns the portion of the path that represents the directories, without the ending file name.'
),
_('Filesystem/Windows, Linux, MacOS'),
'JsPlatform/Extensions/filesystem_folder32.png'
)
.addParameter('string', _('File or folder path'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
.setFunctionName('gdjs.fileSystem.getDirectoryName');
extension
.addStrExpression(
'FileName',
_('Get file name from a path'),
_('Returns the name of the file with its extension, if any.'),
_('Filesystem/Windows, Linux, MacOS'),
'JsPlatform/Extensions/filesystem_folder32.png'
)
.addParameter('string', _('File path'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
.setFunctionName('gdjs.fileSystem.getFileName');
extension
.addStrExpression(
'ExtensionName',
_('Get the extension from a file path'),
_(
'Returns the extension of the file designated by the given path, including the extension period. For example: ".txt".'
),
_('Filesystem/Windows, Linux, MacOS'),
'JsPlatform/Extensions/filesystem_folder32.png'
)
.addParameter('string', _('File path'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
.setFunctionName('gdjs.fileSystem.getExtensionName');
return extension;
},
runExtensionSanityTests: function(gd /*: libGDevelop */, extension /*: gdPlatformExtension*/) {
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
return [];
},
};

View File

@@ -1,11 +1,58 @@
// @ts-check
/**
* @memberof gdjs
* @class fileSystem
* @static
* @namespace fileSystem
* @private
*/
gdjs.fileSystem = {};
gdjs.fileSystem = {
_path: null, // The Node.js path module, or null if it can't be loaded.
_fs: null, // The Node.js fs module, or null if it can't be loaded.
};
/** Get the Node.js path module, or null if it can't be loaded */
gdjs.fileSystem._getPath = function() {
if (!gdjs.fileSystem._path) {
// @ts-ignore
gdjs.fileSystem._path = typeof require !== 'undefined' ? require('path') : null;
}
return gdjs.fileSystem._path;
}
/** Get the Node.js fs module, or null if it can't be loaded */
gdjs.fileSystem._getFs = function() {
if (!gdjs.fileSystem._fs) {
// @ts-ignore
gdjs.fileSystem._fs = typeof require !== 'undefined' ? require('fs') : null;
}
return gdjs.fileSystem._fs;
}
/** @param {string} fileOrFolderPath */
gdjs.fileSystem.getDirectoryName = function(fileOrFolderPath) {
const path = gdjs.fileSystem._getPath();
if (!path) return '';
return path.dirname(fileOrFolderPath);
}
/** @param {string} filePath */
gdjs.fileSystem.getFileName = function(filePath) {
const path = gdjs.fileSystem._getPath();
if (!path) return '';
return path.basename(filePath);
}
/** @param {string} filePath */
gdjs.fileSystem.getExtensionName = function(filePath) {
const path = gdjs.fileSystem._getPath();
if (!path) return '';
return path.extname(filePath);
}
/**
* Get the path to 'Desktop' folder.
@@ -62,9 +109,9 @@ gdjs.fileSystem.getPicturesPath = function(runtimeScene) {
};
/**
* Get the path to this application 'Executable' folder.
* Get the path to this application 'Executable' file.
* @param {gdjs.RuntimeScene} runtimeScene The current scene
* @return {string} The path to this applications executable folder
* @return {string} The path to this applications executable file
*/
gdjs.fileSystem.getExecutablePath = function(runtimeScene) {
const electron = runtimeScene
@@ -79,6 +126,22 @@ gdjs.fileSystem.getExecutablePath = function(runtimeScene) {
}
};
/**
* Get the path to this application 'Executable' folder.
* @param {gdjs.RuntimeScene} runtimeScene The current scene
* @return {string} The path to this applications executable folder
*/
gdjs.fileSystem.getExecutableFolderPath = function(runtimeScene) {
const path = gdjs.fileSystem._getPath();
const executablePath = gdjs.fileSystem.getExecutablePath(runtimeScene);
if (!path) {
return '';
}
return path.dirname(executablePath);
};
/**
* Get the path to 'UserData' folder.
* @param {gdjs.RuntimeScene} runtimeScene The current scene
@@ -101,7 +164,7 @@ gdjs.fileSystem.getUserdataPath = function(runtimeScene) {
* Get the path to the user's home folder (on Windows `C:\Users\<USERNAME>\` for example).
* @return {string} The path to user's "home" folder
*/
gdjs.fileSystem.getUserHomePath = function() {
gdjs.fileSystem.getUserHomePath = function(runtimeScene) {
const electron = runtimeScene
.getGame()
.getRenderer()
@@ -137,7 +200,7 @@ gdjs.fileSystem.getTempPath = function(runtimeScene) {
* @return {string} The path delimiter
*/
gdjs.fileSystem.getPathDelimiter = function() {
const path = typeof require !== 'undefined' ? require('path') : null;
const path = gdjs.fileSystem._getPath();
if (path) {
return path.sep || '/';
@@ -152,7 +215,7 @@ gdjs.fileSystem.getPathDelimiter = function() {
* @param {gdjs.Variable} resultVar The variable where to store the result of the operation
*/
gdjs.fileSystem.makeDirectory = function(directory, resultVar) {
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
const fileSystem = gdjs.fileSystem._getFs();
let result = 'error';
if (fileSystem) {
@@ -176,7 +239,7 @@ gdjs.fileSystem.makeDirectory = function(directory, resultVar) {
* @param {gdjs.Variable} resultVar The variable where to store the result of the operation
*/
gdjs.fileSystem.saveStringToFileAsync = function(text, savePath, resultVar) {
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
const fileSystem = gdjs.fileSystem._getFs();
if (fileSystem) {
fileSystem.writeFile(savePath, text, 'utf8', err => {
@@ -199,7 +262,7 @@ gdjs.fileSystem.saveStringToFileAsync = function(text, savePath, resultVar) {
* @param {gdjs.Variable} resultVar The variable where to store the result of the operation
*/
gdjs.fileSystem.saveStringToFile = function(text, savePath, resultVar) {
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
const fileSystem = gdjs.fileSystem._getFs();
let result = 'error';
if (fileSystem) {
@@ -227,7 +290,7 @@ gdjs.fileSystem.saveVariableToJSONFile = function(
savePath,
resultVar
) {
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
const fileSystem = gdjs.fileSystem._getFs();
const network = gdjs.evtTools.network;
let result = 'error';
@@ -251,7 +314,7 @@ gdjs.fileSystem.saveVariableToJSONFile = function(
/**
* Save a variable into a file in JSON format, asynchronously.
* @param {string} text The variable to be saved
* @param {gdjs.Variable} variable The variable to be saved
* @param {string} savePath Path to the file
* @param {gdjs.Variable} resultVar The variable where to store the result of the operation
*/
@@ -260,7 +323,7 @@ gdjs.fileSystem.saveVariableToJSONFileAsync = function(
savePath,
resultVar
) {
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
const fileSystem = gdjs.fileSystem._getFs();
const network = gdjs.evtTools.network;
if (fileSystem && network) {
@@ -289,7 +352,7 @@ gdjs.fileSystem.saveVariableToJSONFileAsync = function(
* @param {gdjs.Variable} resultVar The variable where to store the result of the operation
*/
gdjs.fileSystem.loadStringFromFile = function(stringVar, loadPath, resultVar) {
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
const fileSystem = gdjs.fileSystem._getFs();
let result = 'error';
if (fileSystem) {
@@ -321,7 +384,7 @@ gdjs.fileSystem.loadVariableFromJSONFile = function(
loadPath,
resultVar
) {
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
const fileSystem = gdjs.fileSystem._getFs();
const network = gdjs.evtTools.network;
let result = 'error';
@@ -353,7 +416,7 @@ gdjs.fileSystem.loadVariableFromJSONFileAsync = function(
loadPath,
resultVar
) {
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
const fileSystem = gdjs.fileSystem._getFs();
const network = gdjs.evtTools.network;
if (fileSystem && network) {
@@ -384,7 +447,7 @@ gdjs.fileSystem.loadStringFromFileAsync = function(
loadPath,
resultVar
) {
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
const fileSystem = gdjs.fileSystem._getFs();
if (fileSystem) {
fileSystem.readFile(loadPath, 'utf8', (err, data) => {
@@ -409,7 +472,7 @@ gdjs.fileSystem.loadStringFromFileAsync = function(
* @param {gdjs.Variable} resultVar The variable where to store the result of the operation
*/
gdjs.fileSystem.deleteFile = function(filePath, resultVar) {
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
const fileSystem = gdjs.fileSystem._getFs();
let result = 'error';
if (fileSystem) {
@@ -430,7 +493,7 @@ gdjs.fileSystem.deleteFile = function(filePath, resultVar) {
* @param {gdjs.Variable} resultVar The variable where to store the result of the operation
*/
gdjs.fileSystem.deleteFileAsync = function(filePath, resultVar) {
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
const fileSystem = gdjs.fileSystem._getFs();
if (fileSystem) {
fileSystem.unlink(filePath, err => {
@@ -449,7 +512,7 @@ gdjs.fileSystem.deleteFileAsync = function(filePath, resultVar) {
* @return {boolean} true if fhe file or directory exists
*/
gdjs.fileSystem.pathExists = function(filePath) {
const fileSystem = typeof require !== 'undefined' ? require('fs') : null;
const fileSystem = gdjs.fileSystem._getFs();
if (fileSystem) {
return fileSystem.existsSync(filePath);

View File

@@ -11,7 +11,7 @@ gdjs.LightRuntimeObjectPixiRenderer = function (runtimeObject, runtimeScene) {
this._runtimeScene = runtimeScene;
this._manager = runtimeObject.getObstaclesManager();
this._radius = runtimeObject.getRadius();
var objectColor = runtimeObject.getColor();
var objectColor = runtimeObject._color;
this._color = [
objectColor[0] / 255,
objectColor[1] / 255,
@@ -55,6 +55,13 @@ gdjs.LightRuntimeObjectPixiRenderer = function (runtimeObject, runtimeScene) {
runtimeObject.getHitBoxes()[0].vertices[i]
);
}
// Objects will be added in lighting layer, this is just to maintain consistency.
if (this._light)
runtimeScene
.getLayer('')
.getRenderer()
.addRendererObject(this.getRendererObject(), runtimeObject.getZOrder());
};
gdjs.LightRuntimeObjectRenderer = gdjs.LightRuntimeObjectPixiRenderer; //Register the class to let the engine use it.
@@ -168,6 +175,12 @@ gdjs.LightRuntimeObjectPixiRenderer.prototype.ensureUpToDate = function () {
};
gdjs.LightRuntimeObjectPixiRenderer.prototype.updateMesh = function () {
if (!PIXI.utils.isWebGLSupported()) {
console.warn(
'This device does not support webgl, which is required for Lighting Extension.'
);
return;
}
this.updateTexture();
var fragmentShader =
this._texture === null
@@ -200,12 +213,16 @@ gdjs.LightRuntimeObjectPixiRenderer.prototype.updateMesh = function () {
};
gdjs.LightRuntimeObjectPixiRenderer.prototype.updateRadius = function () {
if (!this._light) return;
this._radius = this._object.getRadius();
this._light.shader.uniforms.radius = this._radius;
};
gdjs.LightRuntimeObjectPixiRenderer.prototype.updateColor = function () {
var objectColor = this._object.getColor();
if (!this._light) return;
var objectColor = this._object._color;
this._color = [
objectColor[0] / 255,
objectColor[1] / 255,
@@ -215,6 +232,7 @@ gdjs.LightRuntimeObjectPixiRenderer.prototype.updateColor = function () {
};
gdjs.LightRuntimeObjectPixiRenderer.prototype.updateTexture = function () {
if (!this._light) return;
var texture = this._object.getTexture();
this._texture =
texture !== ''
@@ -223,6 +241,8 @@ gdjs.LightRuntimeObjectPixiRenderer.prototype.updateTexture = function () {
};
gdjs.LightRuntimeObjectPixiRenderer.prototype.updateDebugMode = function () {
if (!this._light) return;
this._debugMode = this._object.getDebugMode();
if (!this._debugLight && (this._isPreview || this._debugMode)) {
this._debugLight = new PIXI.Container();
@@ -293,9 +313,10 @@ gdjs.LightRuntimeObjectPixiRenderer.prototype._updateDebugGraphics = function ()
};
gdjs.LightRuntimeObjectPixiRenderer.prototype._updateBuffers = function () {
if (!this._light) return;
this._center[0] = this._object.x;
this._center[1] = this._object.y;
this._light.shader.uniforms.center = this._center;
var vertices = this._computeLightVertices();
// Fallback to simple quad when there are no obstacles around.
@@ -309,6 +330,7 @@ gdjs.LightRuntimeObjectPixiRenderer.prototype._updateBuffers = function () {
this._defaultVertexBuffer[6] = this._object.x - this._radius;
this._defaultVertexBuffer[7] = this._object.y - this._radius;
this._light.shader.uniforms.center = this._center;
this._light.geometry
.getBuffer('aVertexPosition')
.update(this._defaultVertexBuffer);
@@ -364,6 +386,7 @@ gdjs.LightRuntimeObjectPixiRenderer.prototype._updateBuffers = function () {
else this._indexBuffer[i + 2] = 1;
}
this._light.shader.uniforms.center = this._center;
if (!isSubArrayUsed) {
this._light.geometry
.getBuffer('aVertexPosition')

View File

@@ -147,11 +147,11 @@ gdjs.LightRuntimeObject.prototype.getDrawableY = function () {
};
/**
* Get the color of the light object in format [r, g, b], with components in the range of [0-255].
* @returns {number[]} the color of light object in rgb format.
* Get the color of the light object as a "R;G;B" string.
* @returns {string} the color of light object in "R;G;B" format.
*/
gdjs.LightRuntimeObject.prototype.getColor = function () {
return this._color;
return this._color[0] + ';' + this._color[1] + ';' + this._color[2];
};
/**
@@ -161,9 +161,9 @@ gdjs.LightRuntimeObject.prototype.getColor = function () {
gdjs.LightRuntimeObject.prototype.setColor = function (color) {
var rgbColor = color.split(';');
this._color = [
parseInt(rgbColor[0]),
parseInt(rgbColor[1]),
parseInt(rgbColor[2]),
parseInt(rgbColor[0], 10),
parseInt(rgbColor[1], 10),
parseInt(rgbColor[2], 10),
];
this._renderer.updateColor();
};

View File

@@ -53,6 +53,7 @@ const addLightObstacle = (runtimeScene, width, height) => {
};
describe('gdjs.LightRuntimeObject', function () {
PIXI.settings.FAIL_IF_MAJOR_PERFORMANCE_CAVEAT = false;
const runtimeGame = new gdjs.RuntimeGame({
variables: [],
resources: {
@@ -61,12 +62,19 @@ describe('gdjs.LightRuntimeObject', function () {
properties: { windowWidth: 800, windowHeight: 600 },
});
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
runtimeScene.loadFromScene({
layers: [{ name: '', visibility: true, effects: [] }],
variables: [],
behaviorsSharedData: [],
objects: [],
instances: [],
});
const lightObj = addLightObject(runtimeScene, 100);
lightObj.setPosition(200, 200);
it('check object properties', function () {
expect(lightObj.getRadius()).to.be(100);
expect(lightObj.getColor()).to.eql([180, 180, 180]);
expect(lightObj.getColor()).to.eql("180;180;180");
expect(lightObj.getDebugMode()).to.be(false);
expect(lightObj.getDrawableX()).to.be(100);
expect(lightObj.getDrawableY()).to.be(100);
@@ -85,6 +93,7 @@ describe('gdjs.LightRuntimeObject', function () {
});
describe('Light with obstacles around it', function () {
PIXI.settings.FAIL_IF_MAJOR_PERFORMANCE_CAVEAT = false;
const runtimeGame = new gdjs.RuntimeGame({
variables: [],
resources: {
@@ -156,7 +165,7 @@ describe('Light with obstacles around it', function () {
const expectedIndexBuffer = [
0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0,
6, 7, 0, 7, 8, 0, 8, 9, 0, 9, 10, 0, 10, 11, 0,
11, 12, 0, 12, 13, 0, 13, 14, 0, 14, 15, 0, 15,
11, 12, 0, 12, 13, 0, 13, 14, 0, 14, 15, 0, 15,
16, 0, 16, 17, 0, 17, 18, 0, 18, 1,
];

View File

@@ -8,6 +8,7 @@
gdjs.evtTools.p2p = {
/**
* The peer to peer configuration.
* @type {Peer.PeerJSOption}
*/
peerConfig: { debug: 1 }, // Enable logging of critical errors
@@ -18,52 +19,75 @@ gdjs.evtTools.p2p = {
peer: null,
/**
* All connected p2p clients, keyed by their id.
* All connected p2p clients, keyed by their ID.
* @type {Object<string, Peer.DataConnection>}
*/
connections: {},
/**
* Contains a list of events triggered by other p2p clients.
* Maps an event name (string) to a boolean:
* true if the event has been triggered, otherwise false.
* @note This is ignored if the event is in no dataloss mode.
* @type {Object<string, boolean>}
*/
triggeredEvents: {},
/**
* Contains the latest data sent with each event.
* If the event is in dataloss mode, maps an event name (string)
* to the string sent with that event.
* If the event is in no dataloss mode, maps an event name (string)
* to an array containing the data of each call of that event.
* @type {Object<string, string | Array>}
*/
lastEventData: {},
/**
* Tells how to handle an event (with or without data loss)
* Tells how to handle an event (with or without data loss).
* Maps the event name (string) to a boolean:
* true for dataloss, false for no dataloss.
* @type {Object<string, string>}
*/
eventHandling: {},
/**
* True if PeerJS is initialized and ready.
* @type {boolean}
*/
ready: false,
/**
* True if an error occured.
* @type {boolean}
*/
error: false,
/**
* Last error's message.
* @type {string}
*/
lastError: '',
/**
* True if a peer diconnected.
* List of IDs of peers that just disconnected.
* @type {Array<string>}
*/
peerJustDisconnected: false,
disconnectedPeers: [],
/**
* The last peer that has disconnected.
* List of IDs of peers that just remotely initiated a connection.
* @type {Array<string>}
*/
lastDisconnectedPeerId: '',
connectedPeers: [],
};
gdjs.evtTools.p2p.loadPeerJS = function () {
/**
* Internal function called to initialize PeerJS after its
* broker server has been configured.
* @private
*/
gdjs.evtTools.p2p._loadPeerJS = function () {
if (gdjs.evtTools.p2p.peer != null) return;
gdjs.evtTools.p2p.peer = new Peer(gdjs.evtTools.p2p.peerConfig);
gdjs.evtTools.p2p.peer.on('open', function () {
@@ -73,14 +97,24 @@ gdjs.evtTools.p2p.loadPeerJS = function () {
gdjs.evtTools.p2p.error = true;
gdjs.evtTools.p2p.lastError = errorMessage;
});
gdjs.evtTools.p2p.peer.on('connection', gdjs.evtTools.p2p._onConnection);
gdjs.evtTools.p2p.peer.on('connection', function (connection) {
connection.on('open', function () {
gdjs.evtTools.p2p._onConnection(connection);
gdjs.evtTools.p2p.connectedPeers.push(connection.peer);
});
});
gdjs.evtTools.p2p.peer.on('close', function () {
gdjs.evtTools.p2p.peer = null;
gdjs.evtTools.p2p.loadPeerJS();
gdjs.evtTools.p2p._loadPeerJS();
});
gdjs.evtTools.p2p.peer.on('disconnected', gdjs.evtTools.p2p.peer.reconnect);
};
/**
* Internal function called when a connection with a remote peer is initiated.
* @private
* @param {Peer.DataConnection} connection The DataConnection of the peer
*/
gdjs.evtTools.p2p._onConnection = function (connection) {
gdjs.evtTools.p2p.connections[connection.peer] = connection;
connection.on('data', function (data) {
@@ -117,15 +151,19 @@ gdjs.evtTools.p2p._onConnection = function (connection) {
disconnectChecker();
};
/**
* Internal function called when a remote client disconnects.
* @private
* @param {string} connectionID The ID of the peer that disconnected.
*/
gdjs.evtTools.p2p._onDisconnect = function (connectionID) {
gdjs.evtTools.p2p.peerJustDisconnected = true;
gdjs.evtTools.p2p.lastDisconnectedPeerId = connectionID;
gdjs.evtTools.p2p.disconnectedPeers.push(connectionID);
delete gdjs.evtTools.p2p.connections[connectionID];
};
/**
* Connects to another p2p client.
* @param {string} id - The other client's id.
* @param {string} id - The other client's ID.
*/
gdjs.evtTools.p2p.connect = function (id) {
var connection = gdjs.evtTools.p2p.peer.connect(id);
@@ -137,14 +175,14 @@ gdjs.evtTools.p2p.connect = function (id) {
/**
* Returns true when the event got triggered by another p2p client.
* @param {string} eventName
* @param {boolean} _dataLoss Is data loss allowed (accelerates event handling when true)?
* @param {boolean} defaultDataLoss Is data loss allowed (accelerates event handling when true)?
* @returns {boolean}
*/
gdjs.evtTools.p2p.onEvent = function (eventName, _dataLoss) {
gdjs.evtTools.p2p.onEvent = function (eventName, defaultDataLoss) {
var dataLoss = gdjs.evtTools.p2p.eventHandling[eventName];
if (dataLoss == undefined) {
gdjs.evtTools.p2p.eventHandling[eventName] = _dataLoss;
return gdjs.evtTools.p2p.onEvent(eventName, _dataLoss);
gdjs.evtTools.p2p.eventHandling[eventName] = defaultDataLoss;
return gdjs.evtTools.p2p.onEvent(eventName, defaultDataLoss);
}
if (dataLoss) {
var returnValue = gdjs.evtTools.p2p.triggeredEvents[eventName];
@@ -160,7 +198,7 @@ gdjs.evtTools.p2p.onEvent = function (eventName, _dataLoss) {
/**
* Send an event to one specific connected client.
* @param {string} id - The id of the client to send the event to.
* @param {string} id - The ID of the client to send the event to.
* @param {string} eventName - The event to trigger.
* @param {string} [eventData] - Additional data to send with the event.
*/
@@ -188,16 +226,16 @@ gdjs.evtTools.p2p.sendDataToAll = function (eventName, eventData) {
/**
* Send an event to one specific connected client.
* @param {string} id - The id of the client to send the event to.
* @param {string} id - The ID of the client to send the event to.
* @param {string} eventName - The event to trigger.
* @param {gdjs.Variable} variable - Additional variable to send with the event.
*/
gdjs.evtTools.p2p.sendVariableTo = function (id, eventName, variable) {
if (gdjs.evtTools.p2p.connections[id])
gdjs.evtTools.p2p.connections[id].send({
eventName: eventName,
data: gdjs.evtTools.network.variableStructureToJSON(variable),
});
gdjs.evtTools.p2p.sendDataTo(
id,
eventName,
gdjs.evtTools.network.variableStructureToJSON(variable)
);
};
/**
@@ -206,12 +244,10 @@ gdjs.evtTools.p2p.sendVariableTo = function (id, eventName, variable) {
* @param {gdjs.Variable} variable - Additional variable to send with the event.
*/
gdjs.evtTools.p2p.sendVariableToAll = function (eventName, variable) {
for (var id in gdjs.evtTools.p2p.connections) {
gdjs.evtTools.p2p.connections[id].send({
eventName: eventName,
data: gdjs.evtTools.network.variableStructureToJSON(variable),
});
}
gdjs.evtTools.p2p.sendDataToAll(
eventName,
gdjs.evtTools.network.variableStructureToJSON(variable)
);
};
/**
@@ -265,7 +301,7 @@ gdjs.evtTools.p2p.useCustomBrokerServer = function (
secure: ssl,
key,
};
gdjs.evtTools.p2p.loadPeerJS();
gdjs.evtTools.p2p._loadPeerJS();
};
/**
@@ -274,11 +310,11 @@ gdjs.evtTools.p2p.useCustomBrokerServer = function (
* this server should only be used for quick testing in development.
*/
gdjs.evtTools.p2p.useDefaultBrokerServer = function () {
gdjs.evtTools.p2p.loadPeerJS();
gdjs.evtTools.p2p._loadPeerJS();
};
/**
* Returns the own current peer ID
* Returns the own current peer ID.
* @see Peer.id
* @returns {string}
*/
@@ -288,7 +324,7 @@ gdjs.evtTools.p2p.getCurrentId = function () {
};
/**
* Returns true once PeerJS is initialized
* Returns true once PeerJS finished initialization.
* @see gdjs.evtTools.p2p.ready
* @returns {boolean}
*/
@@ -319,13 +355,39 @@ gdjs.evtTools.p2p.getLastError = function () {
* @returns {boolean}
*/
gdjs.evtTools.p2p.onDisconnect = function () {
var returnValue = gdjs.evtTools.p2p.peerJustDisconnected;
gdjs.evtTools.p2p.peerJustDisconnected = false;
return returnValue;
return gdjs.evtTools.p2p.disconnectedPeers.length > 0;
};
/**
* Get the ID of the peer that triggered onDisconnect.
* @returns {string}
*/
gdjs.evtTools.p2p.getDisconnectedPeer = function () {
return gdjs.evtTools.p2p.lastDisconnectedPeerId;
return (
gdjs.evtTools.p2p.disconnectedPeers[
gdjs.evtTools.p2p.disconnectedPeers.length - 1
] || ''
);
};
/**
* Returns true once if a remote peer just initiated a connection.
* @returns {boolean}
*/
gdjs.evtTools.p2p.onConnection = function () {
return gdjs.evtTools.p2p.connectedPeers.length > 0;
};
/**
* Get the ID of the peer that triggered onConnection.
* @returns {string}
*/
gdjs.evtTools.p2p.getConnectedPeer = function () {
return (
gdjs.evtTools.p2p.connectedPeers[
gdjs.evtTools.p2p.connectedPeers.length - 1
] || ''
);
};
gdjs.callbacksRuntimeScenePostEvents.push(function () {
@@ -336,4 +398,8 @@ gdjs.callbacksRuntimeScenePostEvents.push(function () {
)
gdjs.evtTools.p2p.lastEventData[i].pop();
}
if (gdjs.evtTools.p2p.disconnectedPeers.length > 0)
gdjs.evtTools.p2p.disconnectedPeers.pop();
if (gdjs.evtTools.p2p.connectedPeers.length > 0)
gdjs.evtTools.p2p.connectedPeers.pop();
});

View File

@@ -105,6 +105,21 @@ module.exports = {
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setFunctionName('gdjs.evtTools.p2p.onDisconnect');
extension
.addCondition(
'OnConnection',
_('Peer Connected'),
_('Triggers once when a remote peer initiates a connection.'),
_('P2P peer connected'),
_('P2P (experimental)'),
'JsPlatform/Extensions/p2picon.svg',
'JsPlatform/Extensions/p2picon.svg'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setFunctionName('gdjs.evtTools.p2p.onConnection');
extension
.addAction(
'Connect',
@@ -215,7 +230,7 @@ module.exports = {
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setFunctionName('gdjs.evtTools.p2p.sendDataToAll');
.setFunctionName('gdjs.evtTools.p2p.sendVariableToAll');
extension
.addAction(
@@ -313,7 +328,7 @@ module.exports = {
.addStrExpression(
'GetLastDisconnectedPeer',
_('Get last disconnected peer'),
_('Gets the id of the latest peer that has disconnected.'),
_('Gets the ID of the latest peer that has disconnected.'),
_('P2P (experimental)'),
'JsPlatform/Extensions/p2picon.svg'
)
@@ -322,6 +337,19 @@ module.exports = {
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setFunctionName('gdjs.evtTools.p2p.getDisconnectedPeer');
extension
.addStrExpression(
'GetLastConnectedPeer',
_('Get ID of the connected peer'),
_('Gets the ID of the newly connected peer.'),
_('P2P (experimental)'),
'JsPlatform/Extensions/p2picon.svg'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setFunctionName('gdjs.evtTools.p2p.getConnectedPeer');
return extension;
},
runExtensionSanityTests: function (

View File

@@ -258,7 +258,7 @@ gdjs.PanelSpriteRuntimeObject.prototype.setColor = function(rgbColor) {
/**
* Get the tint of the panel sprite object.
*
* @returns {string} rgbColor The color, in RGB format ("128;200;255").
* @returns {string} The color, in RGB format ("128;200;255").
*/
gdjs.PanelSpriteRuntimeObject.prototype.getColor = function() {
return this._renderer.getColor();

View File

@@ -17,16 +17,17 @@ gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.getRendererObject = functio
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.clear = function() {
this._graphics.clear();
this.updateOutline();
};
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawRectangle = function(x1, y1, x2, y2) {
this.updateOutline();
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
this._graphics.drawRect(x1, y1, x2 - x1, y2 - y1);
this._graphics.endFill();
};
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawCircle = function(x, y, radius) {
this.updateOutline();
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
this._graphics.drawCircle(x, y, radius);
this._graphics.endFill();
@@ -55,12 +56,14 @@ gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawLineV2 = function(x1, y
};
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawEllipse = function(x1, y1, width, height) {
this.updateOutline();
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
this._graphics.drawEllipse(x1, y1, width/2, height/2);
this._graphics.endFill();
};
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawRoundedRectangle = function(x1, y1, x2, y2, radius) {
this.updateOutline();
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
this._graphics.drawRoundedRect(x1, y1, x2 - x1, y2 - y1, radius);
this._graphics.closePath();
@@ -68,6 +71,7 @@ gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawRoundedRectangle = func
};
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawStar = function(x1, y1, points, radius, innerRadius, rotation) {
this.updateOutline();
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
this._graphics.drawStar(x1, y1, points, radius, innerRadius ? innerRadius : radius/2, rotation ? gdjs.toRad(rotation) : 0);
this._graphics.closePath();
@@ -75,6 +79,7 @@ gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawStar = function(x1, y1,
};
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawArc = function(x1, y1, radius, startAngle, endAngle, anticlockwise, closePath) {
this.updateOutline();
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
this._graphics.moveTo( x1 + radius * Math.cos(gdjs.toRad(startAngle)), y1 + radius * Math.sin(gdjs.toRad(startAngle)));
this._graphics.arc(x1, y1, radius, gdjs.toRad(startAngle), gdjs.toRad(endAngle), anticlockwise ? true : false);
@@ -85,6 +90,7 @@ gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawArc = function(x1, y1,
};
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawBezierCurve = function(x1, y1, cpX, cpY, cpX2, cpY2, x2, y2) {
this.updateOutline();
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
this._graphics.moveTo(x1, y1);
this._graphics.bezierCurveTo(cpX, cpY, cpX2, cpY2, x2, y2);
@@ -92,6 +98,7 @@ gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawBezierCurve = function(
};
gdjs.ShapePainterRuntimeObjectPixiRenderer.prototype.drawQuadraticCurve = function(x1, y1, cpX, cpY, x2, y2) {
this.updateOutline();
this._graphics.beginFill(this._object._fillColor, this._object._fillOpacity / 255);
this._graphics.moveTo(x1, y1);
this._graphics.quadraticCurveTo(cpX, cpY, x2, y2);

View File

@@ -30,14 +30,14 @@ void DeclareSystemInfoExtension(gd::PlatformExtension& extension) {
.SetIncludeFile("SystemInfo/SystemInfoTools.h");
extension
.AddCondition(
"IsWebGLSupported",
_("Is WebGL supported"),
_("Check if GPU accelerated WebGL is supported on the target device."),
_("WebGL is available"),
_("System information"),
"CppPlatform/Extensions/systeminfoicon24.png",
"CppPlatform/Extensions/systeminfoicon16.png")
.AddCondition("IsWebGLSupported",
_("Is WebGL supported"),
_("Check if GPU accelerated WebGL is supported on the "
"target device."),
_("WebGL is available"),
_("System information"),
"CppPlatform/Extensions/systeminfoicon24.png",
"CppPlatform/Extensions/systeminfoicon16.png")
.AddCodeOnlyParameter("currentScene", "")
.SetFunctionName("SystemInfo::IsWebGLSupported")
@@ -47,16 +47,28 @@ void DeclareSystemInfoExtension(gd::PlatformExtension& extension) {
.AddCondition(
"IsPreview",
_("Is the game running as a preview"),
_(
"Check if the game is currently being previewed in the editor. "
"This can be used to enable a \"Debug mode\" or do some work only in previews."
),
_("Check if the game is currently being previewed in the editor. "
"This can be used to enable a \"Debug mode\" or do some work only "
"in previews."),
_("The game is being previewed in the editor"),
_("System information"),
"CppPlatform/Extensions/systeminfoicon24.png",
"CppPlatform/Extensions/systeminfoicon16.png")
.AddCodeOnlyParameter("currentScene", "");
extension
.AddCondition(
"HasTouchScreen",
_("Device has a touchscreen"),
_("Check if the device running the game has a touchscreen (typically "
"Android phones, iPhones, iPads, but also some laptops)."),
_("The device has a touchscreen"),
_("System information"),
"CppPlatform/Extensions/systeminfoicon24.png",
"CppPlatform/Extensions/systeminfoicon16.png")
.AddCodeOnlyParameter("currentScene", "");
#endif
}

View File

@@ -35,6 +35,10 @@ class SystemInfoJsExtension : public gd::PlatformExtension {
.codeExtraInformation
.SetIncludeFile("Extensions/SystemInfo/systeminfotools.js")
.SetFunctionName("gdjs.evtTools.systemInfo.isPreview");
GetAllConditions()["SystemInfo::HasTouchScreen"]
.codeExtraInformation
.SetIncludeFile("Extensions/SystemInfo/systeminfotools.js")
.SetFunctionName("gdjs.evtTools.systemInfo.hasTouchScreen");
StripUnimplementedInstructionsAndExpressions();
GD_COMPLETE_EXTENSION_COMPILATION_INFORMATION();

View File

@@ -1,48 +1,120 @@
// @ts-check
/**
GDevelop - SystemInfo Extension
Copyright (c) 2016 Florian Rival (Florian.Rival@gmail.com)
* GDevelop - SystemInfo Extension
* Copyright (c) 2016-present Florian Rival (Florian.Rival@gmail.com)
*/
/**
* @memberof gdjs.evtTools
* @class linkedObjects
* @static
* @private
*/
gdjs.evtTools.systemInfo = {};
gdjs.evtTools.systemInfo = (function () {
/** @type {?boolean} */
let cachedIsMobile = null;
/** @type {?boolean} */
let cachedHasTouchScreen = null;
gdjs.evtTools.systemInfo.isMobile = function() {
if (typeof cc !== "undefined" && cc.sys) {
return cc.sys.isMobile;
} else if (typeof Cocoon !== "undefined" && Cocoon.App) {
return true;
} else if (typeof window !== "undefined" && window.cordova) {
return true;
} else if (typeof window !== "undefined") {
// Try to detect mobile device browsers.
if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
|| /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0,4))) {
return true;
}
}
/** @returns {boolean} */
const checkIsMobile = () => {
// @ts-ignore
if (typeof cc !== 'undefined' && cc.sys) {
// @ts-ignore
return cc.sys.isMobile;
return false;
};
// @ts-ignore
} else if (typeof Cocoon !== 'undefined' && Cocoon.App) {
return true;
/**
* Check if the the device supports WebGL.
* @param {gdjs.RuntimeScene} runtimeScene
* @returns {boolean} true if WebGL is supported
*/
gdjs.evtTools.systemInfo.isWebGLSupported = function(runtimeScene) {
return runtimeScene.getGame().getRenderer().isWebGLSupported();
};
// @ts-ignore
} else if (typeof window !== 'undefined' && window.cordova) {
return true;
} else if (typeof window !== 'undefined') {
// Try to detect mobile device browsers.
if (
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(
navigator.userAgent
) ||
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
navigator.userAgent.substr(0, 4)
)
) {
return true;
}
/**
* Check if the game is running as a preview, launched from an editor.
* @param {gdjs.RuntimeScene} runtimeScene The current scene.
* @returns {boolean} true if the game is running as a preview.
*/
gdjs.evtTools.systemInfo.isPreview = function(runtimeScene) {
return runtimeScene.getGame().isPreview();
};
// Try to detect iOS
if (/iPad|iPhone|iPod/.test(navigator.platform)) {
return true;
} else if (/MacIntel/.test(navigator.platform)) {
// Work around for recent iPads that are "desktop-class browsing".
// We can still detect them using their touchscreen, but this is a hack.
// If mac laptops start to support touchscreens, this won't work anymore. Hence it's better
// to test for the presence of a touchscreen if needed rather than checking if the device
// is "mobile".
return !!navigator.maxTouchPoints && navigator.maxTouchPoints > 2;
}
}
return false;
};
/**
* Check if the game runs on a mobile device (iPhone, iPad, Android).
* Note that the distinction between what is a mobile device and what is not
* is becoming blurry. If you use this for mobile controls,
* prefer to check if the device has touchscreen support.
* @returns {boolean}
*/
const isMobile = () => {
if (cachedIsMobile !== null) {
return cachedIsMobile;
}
return (cachedIsMobile = checkIsMobile());
};
/** @returns {boolean} */
const checkHasTouchScreen = () => {
// First check if the device is mobile, as all mobile devices have a touchscreen
// and some older browsers don't have support for `navigator.maxTouchPoints`
if (isMobile()) {
return true;
}
return !!navigator.maxTouchPoints && navigator.maxTouchPoints > 2;
};
/**
* Check if the device has a touchscreen
*/
const hasTouchScreen = () => {
if (cachedHasTouchScreen !== null) {
return cachedHasTouchScreen;
}
return (cachedHasTouchScreen = checkHasTouchScreen());
};
/**
* Check if the the device supports WebGL.
* @param {gdjs.RuntimeScene} runtimeScene
* @returns {boolean} true if WebGL is supported
*/
const isWebGLSupported = (runtimeScene) => {
return runtimeScene.getGame().getRenderer().isWebGLSupported();
};
/**
* Check if the game is running as a preview, launched from an editor.
* @param {gdjs.RuntimeScene} runtimeScene The current scene.
* @returns {boolean} true if the game is running as a preview.
*/
const isPreview = (runtimeScene) => {
return runtimeScene.getGame().isPreview();
};
return {
isPreview: isPreview,
isWebGLSupported: isWebGLSupported,
hasTouchScreen: hasTouchScreen,
isMobile: isMobile,
};
})();

View File

@@ -71,11 +71,3 @@ gdjs.TextEntryRuntimeObject.prototype.activate = function(enable) {
this._activated = enable;
this._renderer.activate(this._activated);
};
gdjs.TextEntryRuntimeObject.prototype.setLayer = function(layer) {
// No renderable object
};
gdjs.TextEntryRuntimeObject.prototype.setZOrder = function(z) {
// No renderable object
};

View File

@@ -384,7 +384,7 @@ gdjs.TextRuntimeObject.prototype.setColor = function(str) {
/**
* Get the text color.
* @return {String} The color as a "R;G;B" string, for example: "255;0;0"
* @return {string} The color as a "R;G;B" string, for example: "255;0;0"
*/
gdjs.TextRuntimeObject.prototype.getColor = function(str) {
return this._color[0] + ";" + this._color[1] + ";" + this._color[2];

View File

@@ -24,8 +24,7 @@ gdjs.TiledSpriteRuntimeObjectPixiRenderer.prototype.getRendererObject = function
};
gdjs.TiledSpriteRuntimeObjectPixiRenderer.prototype.updateOpacity = function() {
//TODO: Workaround a not working property in PIXI.js:
this._tiledSprite.alpha = this._tiledSprite.visible ? this._object.opacity/255 : 0;
this._tiledSprite.alpha = this._object.opacity/255;
}
gdjs.TiledSpriteRuntimeObjectPixiRenderer.prototype.updatePosition = function() {

View File

@@ -213,7 +213,7 @@ gdjs.TiledSpriteRuntimeObject.prototype.setColor = function(rgbColor) {
/**
* Get the tint of the tiled sprite object.
*
* @returns {string} rgbColor The color, in RGB format ("128;200;255").
* @returns {string} The color, in RGB format ("128;200;255").
*/
gdjs.TiledSpriteRuntimeObject.prototype.getColor = function() {
return this._renderer.getColor();

View File

@@ -66,8 +66,8 @@ module.exports = {
tweenBehavior,
new gd.BehaviorsSharedData()
)
.setIncludeFile("Extensions/TweenBehavior/tweenruntimebehavior.js")
.addIncludeFile("Extensions/TweenBehavior/shifty.js");
.setIncludeFile("Extensions/TweenBehavior/shifty.js")
.addIncludeFile("Extensions/TweenBehavior/tweenruntimebehavior.js");
const easingChoices = JSON.stringify([
"linear",

View File

@@ -17,6 +17,8 @@ WindowExtension::WindowExtension() {
GetAllActions()["SetFullScreen"].SetFunctionName(
"gdjs.evtTools.window.setFullScreen");
GetAllConditions()["IsFullScreen"].SetFunctionName(
"gdjs.evtTools.window.isFullScreen");
GetAllActions()["SetWindowMargins"].SetFunctionName(
"gdjs.evtTools.window.setMargins");
GetAllActions()["SetWindowTitle"].SetFunctionName(

View File

@@ -122,8 +122,12 @@ bool Exporter::ExportWholePixiProject(
else if (exportForFacebookInstantGames)
source = gdjsRoot + "/Runtime/FacebookInstantGames/index.html";
if (!helper.ExportPixiIndexFile(
exportedProject, source, exportDir, includesFiles, "")) {
if (!helper.ExportPixiIndexFile(exportedProject,
source,
exportDir,
includesFiles,
/*nonRuntimeScriptsCacheBurst=*/0,
"")) {
gd::LogError(_("Error during export:\n") + lastError);
return false;
}
@@ -211,7 +215,7 @@ bool Exporter::ExportWholeCocos2dProject(gd::Project& project,
gd::ProjectStripper::StripProjectForExport(exportedProject);
//...and export it
gd::SerializerElement noRuntimeGameOptions;
gd::SerializerElement noRuntimeGameOptions;
helper.ExportProjectData(
fs, exportedProject, codeOutputDir + "/data.js", noRuntimeGameOptions);
includesFiles.push_back(codeOutputDir + "/data.js");

View File

@@ -58,8 +58,8 @@ std::map<gd::String, gd::String> GetExtensionDependencyExtraSettingValues(
return values;
};
bool AreMapKeysMissingElementOfSet(std::map<gd::String, gd::String> map,
std::set<gd::String> set) {
bool AreMapKeysMissingElementOfSet(const std::map<gd::String, gd::String> &map,
const std::set<gd::String> &set) {
bool missingKey = false;
for (auto &key : set) {
if (map.find(key) == map.end()) {
@@ -182,6 +182,7 @@ bool ExporterHelper::ExportProjectForPixiPreview(
gdjsRoot + "/Runtime/index.html",
options.exportPath,
includesFiles,
options.nonRuntimeScriptsCacheBurst,
"gdjs.runtimeGameOptions"))
return false;
@@ -213,11 +214,16 @@ bool ExporterHelper::ExportPixiIndexFile(
gd::String source,
gd::String exportDir,
const std::vector<gd::String> &includesFiles,
unsigned int nonRuntimeScriptsCacheBurst,
gd::String additionalSpec) {
gd::String str = fs.ReadFile(source);
// Generate the file
if (!CompleteIndexFile(str, exportDir, includesFiles, additionalSpec))
if (!CompleteIndexFile(str,
exportDir,
includesFiles,
nonRuntimeScriptsCacheBurst,
additionalSpec))
return false;
// Write the index.html file
@@ -397,7 +403,11 @@ bool ExporterHelper::ExportCocos2dFiles(
// Generate the file
std::vector<gd::String> noIncludesInThisFile;
if (!CompleteIndexFile(str, exportDir, noIncludesInThisFile, "")) {
if (!CompleteIndexFile(str,
exportDir,
noIncludesInThisFile,
/*nonRuntimeScriptsCacheBurst=*/0,
"")) {
lastError = "Unable to complete Cocos2d-JS index.html file.";
return false;
}
@@ -512,12 +522,10 @@ bool ExporterHelper::ExportElectronFiles(const gd::Project &project,
}
}
packages = packages.substr(
1, packages.size()); // Remove first line break for esthetic.
packages = packages.substr(
0,
packages.size() -
1); // Remove the , at the end as last item cannot have , in JSON.
if (!packages.empty()) {
// Remove the , at the end as last item cannot have , in JSON.
packages = packages.substr(0, packages.size() - 1);
}
str = str.FindAndReplace("\"GDJS_EXTENSION_NPM_DEPENDENCY\": \"0\"",
packages);
@@ -567,12 +575,14 @@ bool ExporterHelper::CompleteIndexFile(
gd::String &str,
gd::String exportDir,
const std::vector<gd::String> &includesFiles,
unsigned int nonRuntimeScriptsCacheBurst,
gd::String additionalSpec) {
if (additionalSpec.empty()) additionalSpec = "{}";
gd::String codeFilesIncludes;
for (auto &include : includesFiles) {
gd::String scriptSrc = GetExportedIncludeFilename(include);
gd::String scriptSrc =
GetExportedIncludeFilename(include, nonRuntimeScriptsCacheBurst);
// Sanity check if the file exists - if not skip it to avoid
// including it in the list of scripts.
@@ -775,7 +785,14 @@ bool ExporterHelper::ExportExternalSourceFiles(
}
gd::String ExporterHelper::GetExportedIncludeFilename(
const gd::String &include) {
const gd::String &include, unsigned int nonRuntimeScriptsCacheBurst) {
auto addSearchParameterToUrl = [](const gd::String &url,
const gd::String &urlEncodedParameterName,
const gd::String &urlEncodedValue) {
gd::String separator = url.find("?") == gd::String::npos ? "?" : "&";
return url + separator + urlEncodedParameterName + "=" + urlEncodedValue;
};
if (!fs.IsAbsolute(include)) {
// By convention, an include file that is relative is relative to
// the "<GDJS Root>/Runtime" folder, and will have the same relative
@@ -790,7 +807,19 @@ gd::String ExporterHelper::GetExportedIncludeFilename(
} else {
// Note: all the code generated from events are generated in another
// folder and fall in this case:
return fs.FileNameFrom(include);
gd::String resolvedInclude = fs.FileNameFrom(include);
if (nonRuntimeScriptsCacheBurst == 0) {
return resolvedInclude;
}
// Add the parameter to force the browser to reload the code - useful
// for cases where the browser is caching files that are getting
// overwritten.
return addSearchParameterToUrl(
resolvedInclude,
"gdCacheBurst",
gd::String::From(nonRuntimeScriptsCacheBurst));
}
}

View File

@@ -32,13 +32,17 @@ struct PreviewExportOptions {
* \param exportPath_ The path in the filesystem where to export the files
*/
PreviewExportOptions(gd::Project &project_, const gd::String &exportPath_)
: project(project_), exportPath(exportPath_), projectDataOnlyExport(false) {};
: project(project_),
exportPath(exportPath_),
projectDataOnlyExport(false),
nonRuntimeScriptsCacheBurst(0) {};
/**
* \brief Set the address of the debugger server that the game should reach out to,
* using WebSockets.
* \brief Set the address of the debugger server that the game should reach
* out to, using WebSockets.
*/
PreviewExportOptions &SetDebuggerServerAddress(const gd::String& address, const gd::String& port) {
PreviewExportOptions &SetDebuggerServerAddress(const gd::String &address,
const gd::String &port) {
debuggerServerAddress = address;
debuggerServerPort = port;
return *this;
@@ -76,11 +80,21 @@ struct PreviewExportOptions {
* \brief Set if the export should only export the project data, not
* exporting events code.
*/
PreviewExportOptions& SetProjectDataOnlyExport(bool enable) {
PreviewExportOptions &SetProjectDataOnlyExport(bool enable) {
projectDataOnlyExport = enable;
return *this;
}
/**
* \brief If set to a non zero value, the exported script URLs will have an
* extra search parameter added (with the given value) to ensure browser cache
* is bypassed when they are loaded.
*/
PreviewExportOptions &SetNonRuntimeScriptsCacheBurst(unsigned int value) {
nonRuntimeScriptsCacheBurst = value;
return *this;
}
gd::Project &project;
gd::String exportPath;
gd::String debuggerServerAddress;
@@ -89,6 +103,7 @@ struct PreviewExportOptions {
gd::String externalLayoutName;
std::map<gd::String, int> includeFileHashes;
bool projectDataOnlyExport;
unsigned int nonRuntimeScriptsCacheBurst;
};
/**
@@ -154,7 +169,8 @@ class ExporterHelper {
/**
* \brief Copy all the specified files to the
* export directory. Relative files are copied from "<GDJS root>/Runtime" directory.
* export directory. Relative files are copied from "<GDJS root>/Runtime"
* directory.
*
* \param includesFiles A vector with filenames to be copied.
* \param exportDir The directory where the files mus tbe copied.
@@ -186,8 +202,8 @@ class ExporterHelper {
* \brief Add the include files for all the objects of the project
* and their behaviors.
*/
void ExportObjectAndBehaviorsIncludes(
gd::Project &project, std::vector<gd::String> &includesFiles);
void ExportObjectAndBehaviorsIncludes(gd::Project &project,
std::vector<gd::String> &includesFiles);
/**
* \brief Copy the external source files used by the game into the export
@@ -214,13 +230,18 @@ class ExporterHelper {
* \param source The file to be used as a template for the final file.
* \param exportDir The directory where the preview must be created.
* \param includesFiles The JS files to be included in the HTML file. Order is
* important. \param additionalSpec JSON string that will be passed to the
* important.
* \param nonRuntimeScriptsCacheBurst If non zero, add an additional cache
* bursting parameter to scripts, that are not part of the runtime/extensions,
* to force the browser to reload them.
* \param additionalSpec JSON string that will be passed to the
* gdjs.RuntimeGame object.
*/
bool ExportPixiIndexFile(const gd::Project &project,
gd::String source,
gd::String exportDir,
const std::vector<gd::String> &includesFiles,
unsigned int nonRuntimeScriptsCacheBurst,
gd::String additionalSpec = "");
/**
@@ -232,6 +253,9 @@ class ExporterHelper {
* \param includesFiles "<!--GDJS_CODE_FILES -->" will be
* replaced by HTML tags to include the filenames
* contained inside the vector.
* \param nonRuntimeScriptsCacheBurst If non zero, add an additional cache
* bursting parameter to scripts, that are not part of the runtime/extensions,
* to force the browser to reload them.
* \param additionalSpec The string "GDJS_ADDITIONAL_SPEC"
* surrounded by comments marks will be replaced by the
* content of this string.
@@ -239,6 +263,7 @@ class ExporterHelper {
bool CompleteIndexFile(gd::String &indexFileContent,
gd::String exportDir,
const std::vector<gd::String> &includesFiles,
unsigned int nonRuntimeScriptsCacheBurst,
gd::String additionalSpec);
/**
@@ -290,7 +315,8 @@ class ExporterHelper {
* \brief Given an include file, returns the name of the file to reference
* in the exported game.
*/
gd::String GetExportedIncludeFilename(const gd::String& include);
gd::String GetExportedIncludeFilename(
const gd::String &include, unsigned int nonRuntimeScriptsCacheBurst = 0);
/**
* \brief Change the directory where code files are generated.
@@ -302,10 +328,10 @@ class ExporterHelper {
}
static void AddDeprecatedFontFilesToFontResources(
gd::AbstractFileSystem &fs,
gd::ResourcesManager &resourcesManager,
const gd::String &exportDir,
gd::String urlPrefix = "");
gd::AbstractFileSystem &fs,
gd::ResourcesManager &resourcesManager,
const gd::String &exportDir,
gd::String urlPrefix = "");
gd::AbstractFileSystem
&fs; ///< The abstract file system to be used for exportation.

View File

@@ -49,6 +49,17 @@ gdjs.RuntimeGameCocosRenderer.prototype.setFullScreen = function(enable) {
console.warn("Fullscreen is not implemented yet.");
};
/**
* Checks if the game is in full screen.
*/
gdjs.RuntimeGamePixiRenderer.prototype.isFullScreen = function() {
var electron = this.getElectron();
if (electron) {
return electron.remote.getCurrentWindow().isFullScreen();
}
return false; // Unsupported
}
/**
* Update the window size, if possible.
* @param {number} width The new width, in pixels.

View File

@@ -22,6 +22,10 @@ gdjs.evtTools.window.setFullScreen = function(runtimeScene, enable, keepAspectRa
runtimeScene.getGame().getRenderer().setFullScreen(enable);
};
gdjs.evtTools.window.isFullScreen = function(runtimeScene) {
return runtimeScene.getGame().getRenderer().isFullScreen();
};
gdjs.evtTools.window.setWindowSize = function(runtimeScene, width, height, updateGameResolution) {
runtimeScene.getGame().getRenderer().setWindowSize(width, height);
if (updateGameResolution) {

File diff suppressed because one or more lines are too long

View File

@@ -256,6 +256,18 @@ gdjs.RuntimeGamePixiRenderer.prototype.setFullScreen = function(enable) {
}
};
/**
* Checks if the game is in full screen.
*/
gdjs.RuntimeGamePixiRenderer.prototype.isFullScreen = function() {
var electron = this.getElectron();
if (electron) {
return electron.remote.getCurrentWindow().isFullScreen();
}
// Height check is used to detect user triggered full screen (for example F11 shortcut).
return this._isFullscreen || window.screen.height === window.innerHeight;
}
/**
* Add the standard events handler.
*/

View File

@@ -36,7 +36,7 @@ gdjs.SpriteRuntimeObjectPixiRenderer.prototype._updatePIXISprite = function() {
this._sprite.rotation = gdjs.toRad(this._object.angle);
this._sprite.visible = !this._object.hidden;
this._sprite.blendMode = this._object._blendMode;
this._sprite.alpha = this._sprite.visible ? this._object.opacity/255 : 0; //TODO: Workaround not working property in PIXI.js
this._sprite.alpha = this._object.opacity/255;
this._sprite.scale.x = this._object._scaleX;
this._sprite.scale.y = this._object._scaleY;
this._cachedWidth = Math.abs(this._sprite.width);

View File

@@ -318,7 +318,11 @@ gdjs.RuntimeObject.prototype.deleteFromScene = function(runtimeScene) {
*/
gdjs.RuntimeObject.prototype.onDestroyFromScene = function(runtimeScene) {
var theLayer = runtimeScene.getLayer(this.layer);
theLayer.getRenderer().removeRendererObject(this.getRendererObject());
var rendererObject = this.getRendererObject();
if (rendererObject) {
theLayer.getRenderer().removeRendererObject(rendererObject);
}
for(var j = 0, lenj = this._behaviors.length;j<lenj;++j) {
this._behaviors[j].onDestroy();
@@ -516,8 +520,10 @@ gdjs.RuntimeObject.prototype.setLayer = function(layer) {
var newLayer = this._runtimeScene.getLayer(this.layer);
var rendererObject = this.getRendererObject();
oldLayer.getRenderer().removeRendererObject(rendererObject);
newLayer.getRenderer().addRendererObject(rendererObject, this.zOrder);
if (rendererObject) {
oldLayer.getRenderer().removeRendererObject(rendererObject);
newLayer.getRenderer().addRendererObject(rendererObject, this.zOrder);
}
};
/**

View File

@@ -903,7 +903,7 @@ gdjs.SpriteRuntimeObject.prototype.setColor = function(rgbColor) {
/**
* Get the tint of the sprite object.
*
* @returns {string} rgbColor The color, in RGB format ("128;200;255").
* @returns {string} The color, in RGB format ("128;200;255").
*/
gdjs.SpriteRuntimeObject.prototype.getColor = function() {
return this._renderer.getColor();

View File

@@ -8,13 +8,14 @@
"devDependencies": {
"@types/expect.js": "^0.3.29",
"@types/mocha": "^5.2.7",
"@types/electron": "^1.6.10",
"@types/node": "^14.11.1",
"jsdoc": "^3.6.4",
"jsdoc-autoprivate": "0.0.1",
"jsdoc-plugin-intersection": "^1.0.2",
"pixi.js": "5.3.0",
"typescript": "3.6.4"
},
"dependencies": {},
"scripts": {
"check-types": "tsc",
"test": "cd tests && npm test",

View File

@@ -2002,6 +2002,12 @@ interface ResourcesMergingHelper {
void SetBaseDirectory([Const] DOMString basePath);
[Ref] MapStringString GetAllResourcesOldAndNewFilename();
};
ResourcesMergingHelper implements ArbitraryResourceWorker;
interface ResourcesRenamer {
void ResourcesRenamer([Const, Ref] MapStringString oldToNewNames);
};
ResourcesRenamer implements ArbitraryResourceWorker;
interface ProjectResourcesCopier {
boolean STATIC_CopyAllResourcesTo([Ref] Project project,
@@ -2020,6 +2026,7 @@ interface ResourcesInUseHelper {
[Ref] SetString GetAllFonts();
[Ref] SetString GetAll([Const] DOMString resourceType);
};
ResourcesInUseHelper implements ArbitraryResourceWorker;
interface LayoutEditorCanvasOptions {
void LayoutEditorCanvasOptions();
@@ -2430,6 +2437,7 @@ interface PreviewExportOptions {
[Ref] PreviewExportOptions SetExternalLayoutName([Const] DOMString externalLayoutName);
[Ref] PreviewExportOptions SetIncludeFileHash([Const] DOMString includeFile, long hash);
[Ref] PreviewExportOptions SetProjectDataOnlyExport(boolean enable);
[Ref] PreviewExportOptions SetNonRuntimeScriptsCacheBurst(unsigned long value);
};
[Prefix="gdjs::"]

View File

@@ -37,6 +37,7 @@
#include <GDCore/IDE/Project/ProjectResourcesCopier.h>
#include <GDCore/IDE/Project/ResourcesInUseHelper.h>
#include <GDCore/IDE/Project/ResourcesMergingHelper.h>
#include <GDCore/IDE/Project/ResourcesRenamer.h>
#include <GDCore/IDE/WholeProjectRefactorer.h>
#include <GDCore/Project/Behavior.h>
#include <GDCore/Project/Effect.h>

View File

@@ -250,10 +250,28 @@ type ParticleEmitterObject_RendererType = 0 | 1 | 2`
);
shell.sed(
'-i',
'declare class gdResourcesInUseHelper {',
'declare class gdResourcesInUseHelper extends gdArbitraryResourceWorker {',
'types/gdresourcesinusehelper.js'
'declare class gdGroupEvent {',
'declare class gdGroupEvent extends gdBaseEvent {',
'types/gdgroupevent.js'
);
[
'BaseEvent',
'StandardEvent',
'RepeatEvent',
'WhileEvent',
'ForEachEvent',
'CommentEvent',
'GroupEvent',
'LinkEvent',
'JsCodeEvent',
].forEach((eventClassName) => {
shell.sed(
'-i',
`declare class gd${eventClassName} {`,
`declare class gd${eventClassName} extends gdBaseEvent {`,
`types/gd${eventClassName.toLowerCase()}.js`
);
});
// Rename classes from GDJS:
shell.sed(
@@ -307,7 +325,6 @@ type ParticleEmitterObject_RendererType = 0 | 1 | 2`
'types/gdexpressionmetadata.js'
);
// Add a notice that the file is auto-generated.
shell.sed(
'-i',

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdBaseEvent {
declare class gdBaseEvent extends gdBaseEvent {
constructor(): void;
clone(): gdBaseEvent;
getType(): string;

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdCommentEvent {
declare class gdCommentEvent extends gdBaseEvent {
constructor(): void;
getComment(): string;
setComment(type: string): void;

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdForEachEvent {
declare class gdForEachEvent extends gdBaseEvent {
constructor(): void;
setObjectToPick(objects: string): void;
getObjectToPick(): string;

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdGroupEvent {
declare class gdGroupEvent extends gdBaseEvent {
constructor(): void;
setName(name: string): void;
getName(): string;

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdJsCodeEvent {
declare class gdJsCodeEvent extends gdBaseEvent {
constructor(): void;
getInlineCode(): string;
setInlineCode(type: string): void;

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdLinkEvent {
declare class gdLinkEvent extends gdBaseEvent {
constructor(): void;
setTarget(name: string): void;
getTarget(): string;

View File

@@ -6,6 +6,7 @@ declare class gdPreviewExportOptions {
setExternalLayoutName(externalLayoutName: string): gdPreviewExportOptions;
setIncludeFileHash(includeFile: string, hash: number): gdPreviewExportOptions;
setProjectDataOnlyExport(enable: boolean): gdPreviewExportOptions;
setNonRuntimeScriptsCacheBurst(value: number): gdPreviewExportOptions;
delete(): void;
ptr: number;
};

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdRepeatEvent {
declare class gdRepeatEvent extends gdBaseEvent {
constructor(): void;
getConditions(): gdInstructionsList;
getActions(): gdInstructionsList;

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdResourcesMergingHelper {
declare class gdResourcesMergingHelper extends gdArbitraryResourceWorker {
constructor(fs: gdAbstractFileSystem): void;
setBaseDirectory(basePath: string): void;
getAllResourcesOldAndNewFilename(): gdMapStringString;

View File

@@ -0,0 +1,6 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdResourcesRenamer extends gdArbitraryResourceWorker {
constructor(oldToNewNames: gdMapStringString): void;
delete(): void;
ptr: number;
};

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdStandardEvent {
declare class gdStandardEvent extends gdBaseEvent {
constructor(): void;
getConditions(): gdInstructionsList;
getActions(): gdInstructionsList;

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdWhileEvent {
declare class gdWhileEvent extends gdBaseEvent {
constructor(): void;
getConditions(): gdInstructionsList;
getWhileConditions(): gdInstructionsList;

View File

@@ -160,6 +160,7 @@ declare class libGDevelop {
ArbitraryResourceWorker: Class<gdArbitraryResourceWorker>;
ArbitraryResourceWorkerJS: Class<gdArbitraryResourceWorkerJS>;
ResourcesMergingHelper: Class<gdResourcesMergingHelper>;
ResourcesRenamer: Class<gdResourcesRenamer>;
ProjectResourcesCopier: Class<gdProjectResourcesCopier>;
ResourcesInUseHelper: Class<gdResourcesInUseHelper>;
LayoutEditorCanvasOptions: Class<gdLayoutEditorCanvasOptions>;

View File

@@ -6,6 +6,8 @@
[declarations]
# lingui-js triggers some Flow errors
<PROJECT_ROOT>/node_modules/@lingui/core/.*
# JSS triggers a Flow error
<PROJECT_ROOT>/node_modules/jss/src/index.js
# Don't type check the GDJS runtime and extensions copied into node_modules (only used for the web-app),
# as this would be redundant for JsExtension.js files (see [include] section) of Extensions, and the
# game engine and extensions are annotated with TypeScript annotations, not Flow.
@@ -23,3 +25,5 @@
module.ignore_non_literal_requires=true
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
# For node_modules/jss/src/Jss.js:
suppress_comment=\\(.\\|\n\\)*\\$FlowIgnore

View File

@@ -1,459 +0,0 @@
// flow-typed signature: 2dd68ce1a3d8938f974e88d46cbf55d1
// flow-typed version: c7c67b81c1/jest_v19.x.x/flow_>=v0.16.x
type JestMockFn = {
(...args: Array<any>): any,
/**
* An object for introspecting mock calls
*/
mock: {
/**
* An array that represents all calls that have been made into this mock
* function. Each call is represented by an array of arguments that were
* passed during the call.
*/
calls: Array<Array<any>>,
/**
* An array that contains all the object instances that have been
* instantiated from this mock function.
*/
instances: mixed,
},
/**
* Resets all information stored in the mockFn.mock.calls and
* mockFn.mock.instances arrays. Often this is useful when you want to clean
* up a mock's usage data between two assertions.
*/
mockClear(): Function,
/**
* Resets all information stored in the mock. This is useful when you want to
* completely restore a mock back to its initial state.
*/
mockReset(): Function,
/**
* Accepts a function that should be used as the implementation of the mock.
* The mock itself will still record all calls that go into and instances
* that come from itself -- the only difference is that the implementation
* will also be executed when the mock is called.
*/
mockImplementation(fn: Function): JestMockFn,
/**
* Accepts a function that will be used as an implementation of the mock for
* one call to the mocked function. Can be chained so that multiple function
* calls produce different results.
*/
mockImplementationOnce(fn: Function): JestMockFn,
/**
* Just a simple sugar function for returning `this`
*/
mockReturnThis(): void,
/**
* Deprecated: use jest.fn(() => value) instead
*/
mockReturnValue(value: any): JestMockFn,
/**
* Sugar for only returning a value once inside your mock
*/
mockReturnValueOnce(value: any): JestMockFn,
}
type JestAsymmetricEqualityType = {
/**
* A custom Jasmine equality tester
*/
asymmetricMatch(value: mixed): boolean,
}
type JestCallsType = {
allArgs(): mixed,
all(): mixed,
any(): boolean,
count(): number,
first(): mixed,
mostRecent(): mixed,
reset(): void,
}
type JestClockType = {
install(): void,
mockDate(date: Date): void,
tick(milliseconds?:number): void,
uninstall(): void,
}
type JestMatcherResult = {
message?: string | ()=>string,
pass: boolean,
}
type JestMatcher = (actual: any, expected: any) => JestMatcherResult;
type JestExpectType = {
not: JestExpectType,
/**
* If you have a mock function, you can use .lastCalledWith to test what
* arguments it was last called with.
*/
lastCalledWith(...args: Array<any>): void,
/**
* toBe just checks that a value is what you expect. It uses === to check
* strict equality.
*/
toBe(value: any): void,
/**
* Use .toHaveBeenCalled to ensure that a mock function got called.
*/
toBeCalled(): void,
/**
* Use .toBeCalledWith to ensure that a mock function was called with
* specific arguments.
*/
toBeCalledWith(...args: Array<any>): void,
/**
* Using exact equality with floating point numbers is a bad idea. Rounding
* means that intuitive things fail.
*/
toBeCloseTo(num: number, delta: any): void,
/**
* Use .toBeDefined to check that a variable is not undefined.
*/
toBeDefined(): void,
/**
* Use .toBeFalsy when you don't care what a value is, you just want to
* ensure a value is false in a boolean context.
*/
toBeFalsy(): void,
/**
* To compare floating point numbers, you can use toBeGreaterThan.
*/
toBeGreaterThan(number: number): void,
/**
* To compare floating point numbers, you can use toBeGreaterThanOrEqual.
*/
toBeGreaterThanOrEqual(number: number): void,
/**
* To compare floating point numbers, you can use toBeLessThan.
*/
toBeLessThan(number: number): void,
/**
* To compare floating point numbers, you can use toBeLessThanOrEqual.
*/
toBeLessThanOrEqual(number: number): void,
/**
* Use .toBeInstanceOf(Class) to check that an object is an instance of a
* class.
*/
toBeInstanceOf(cls: Class<*>): void,
/**
* .toBeNull() is the same as .toBe(null) but the error messages are a bit
* nicer.
*/
toBeNull(): void,
/**
* Use .toBeTruthy when you don't care what a value is, you just want to
* ensure a value is true in a boolean context.
*/
toBeTruthy(): void,
/**
* Use .toBeUndefined to check that a variable is undefined.
*/
toBeUndefined(): void,
/**
* Use .toContain when you want to check that an item is in a list. For
* testing the items in the list, this uses ===, a strict equality check.
*/
toContain(item: any): void,
/**
* Use .toContainEqual when you want to check that an item is in a list. For
* testing the items in the list, this matcher recursively checks the
* equality of all fields, rather than checking for object identity.
*/
toContainEqual(item: any): void,
/**
* Use .toEqual when you want to check that two objects have the same value.
* This matcher recursively checks the equality of all fields, rather than
* checking for object identity.
*/
toEqual(value: any): void,
/**
* Use .toHaveBeenCalled to ensure that a mock function got called.
*/
toHaveBeenCalled(): void,
/**
* Use .toHaveBeenCalledTimes to ensure that a mock function got called exact
* number of times.
*/
toHaveBeenCalledTimes(number: number): void,
/**
* Use .toHaveBeenCalledWith to ensure that a mock function was called with
* specific arguments.
*/
toHaveBeenCalledWith(...args: Array<any>): void,
/**
* If you have a mock function, you can use .toHaveBeenLastCalledWith to test what
* arguments it was last called with.
*/
toHaveBeenLastCalledWith(...args: Array<any>): void,
/**
* Check that an object has a .length property and it is set to a certain
* numeric value.
*/
toHaveLength(number: number): void,
/**
*
*/
toHaveProperty(propPath: string, value?: any): void,
/**
* Use .toMatch to check that a string matches a regular expression.
*/
toMatch(regexp: RegExp): void,
/**
* Use .toMatchObject to check that a javascript object matches a subset of the properties of an object.
*/
toMatchObject(object: Object): void,
/**
* This ensures that a React component matches the most recent snapshot.
*/
toMatchSnapshot(name?: string): void,
/**
* Use .toThrow to test that a function throws when it is called.
*/
toThrow(message?: string | Error): void,
/**
* Use .toThrowError to test that a function throws a specific error when it
* is called. The argument can be a string for the error message, a class for
* the error, or a regex that should match the error.
*/
toThrowError(message?: string | Error | RegExp): void,
/**
* Use .toThrowErrorMatchingSnapshot to test that a function throws a error
* matching the most recent snapshot when it is called.
*/
toThrowErrorMatchingSnapshot(): void,
}
type JestObjectType = {
/**
* Disables automatic mocking in the module loader.
*
* After this method is called, all `require()`s will return the real
* versions of each module (rather than a mocked version).
*/
disableAutomock(): JestObjectType,
/**
* An un-hoisted version of disableAutomock
*/
autoMockOff(): JestObjectType,
/**
* Enables automatic mocking in the module loader.
*/
enableAutomock(): JestObjectType,
/**
* An un-hoisted version of enableAutomock
*/
autoMockOn(): JestObjectType,
/**
* Clears the mock.calls and mock.instances properties of all mocks.
* Equivalent to calling .mockClear() on every mocked function.
*/
clearAllMocks(): JestObjectType,
/**
* Resets the state of all mocks. Equivalent to calling .mockReset() on every
* mocked function.
*/
resetAllMocks(): JestObjectType,
/**
* Removes any pending timers from the timer system.
*/
clearAllTimers(): void,
/**
* The same as `mock` but not moved to the top of the expectation by
* babel-jest.
*/
doMock(moduleName: string, moduleFactory?: any): JestObjectType,
/**
* The same as `unmock` but not moved to the top of the expectation by
* babel-jest.
*/
dontMock(moduleName: string): JestObjectType,
/**
* Returns a new, unused mock function. Optionally takes a mock
* implementation.
*/
fn(implementation?: Function): JestMockFn,
/**
* Determines if the given function is a mocked function.
*/
isMockFunction(fn: Function): boolean,
/**
* Given the name of a module, use the automatic mocking system to generate a
* mocked version of the module for you.
*/
genMockFromModule(moduleName: string): any,
/**
* Mocks a module with an auto-mocked version when it is being required.
*
* The second argument can be used to specify an explicit module factory that
* is being run instead of using Jest's automocking feature.
*
* The third argument can be used to create virtual mocks -- mocks of modules
* that don't exist anywhere in the system.
*/
mock(moduleName: string, moduleFactory?: any, options?: Object): JestObjectType,
/**
* Resets the module registry - the cache of all required modules. This is
* useful to isolate modules where local state might conflict between tests.
*/
resetModules(): JestObjectType,
/**
* Exhausts the micro-task queue (usually interfaced in node via
* process.nextTick).
*/
runAllTicks(): void,
/**
* Exhausts the macro-task queue (i.e., all tasks queued by setTimeout(),
* setInterval(), and setImmediate()).
*/
runAllTimers(): void,
/**
* Exhausts all tasks queued by setImmediate().
*/
runAllImmediates(): void,
/**
* Executes only the macro task queue (i.e. all tasks queued by setTimeout()
* or setInterval() and setImmediate()).
*/
runTimersToTime(msToRun: number): void,
/**
* Executes only the macro-tasks that are currently pending (i.e., only the
* tasks that have been queued by setTimeout() or setInterval() up to this
* point)
*/
runOnlyPendingTimers(): void,
/**
* Explicitly supplies the mock object that the module system should return
* for the specified module. Note: It is recommended to use jest.mock()
* instead.
*/
setMock(moduleName: string, moduleExports: any): JestObjectType,
/**
* Indicates that the module system should never return a mocked version of
* the specified module from require() (e.g. that it should always return the
* real module).
*/
unmock(moduleName: string): JestObjectType,
/**
* Instructs Jest to use fake versions of the standard timer functions
* (setTimeout, setInterval, clearTimeout, clearInterval, nextTick,
* setImmediate and clearImmediate).
*/
useFakeTimers(): JestObjectType,
/**
* Instructs Jest to use the real versions of the standard timer functions.
*/
useRealTimers(): JestObjectType,
/**
* Creates a mock function similar to jest.fn but also tracks calls to
* object[methodName].
*/
spyOn(object: Object, methodName: string): JestMockFn,
}
type JestSpyType = {
calls: JestCallsType,
}
/** Runs this function after every test inside this context */
declare function afterEach(fn: Function): void;
/** Runs this function before every test inside this context */
declare function beforeEach(fn: Function): void;
/** Runs this function after all tests have finished inside this context */
declare function afterAll(fn: Function): void;
/** Runs this function before any tests have started inside this context */
declare function beforeAll(fn: Function): void;
/** A context for grouping tests together */
declare function describe(name: string, fn: Function): void;
/** An individual test unit */
declare var it: {
/**
* An individual test unit
*
* @param {string} Name of Test
* @param {Function} Test
*/
(name: string, fn?: Function): ?Promise<void>,
/**
* Only run this test
*
* @param {string} Name of Test
* @param {Function} Test
*/
only(name: string, fn?: Function): ?Promise<void>,
/**
* Skip running this test
*
* @param {string} Name of Test
* @param {Function} Test
*/
skip(name: string, fn?: Function): ?Promise<void>,
/**
* Run the test concurrently
*
* @param {string} Name of Test
* @param {Function} Test
*/
concurrent(name: string, fn?: Function): ?Promise<void>,
};
declare function fit(name: string, fn: Function): ?Promise<void>;
/** An individual test unit */
declare var test: typeof it;
/** A disabled group of tests */
declare var xdescribe: typeof describe;
/** A focused group of tests */
declare var fdescribe: typeof describe;
/** A disabled individual test */
declare var xit: typeof it;
/** A disabled individual test */
declare var xtest: typeof it;
/** The expect function is used every time you want to test a value */
declare var expect: {
/** The object that you want to make assertions against */
(value: any): JestExpectType,
/** Add additional Jasmine matchers to Jest's roster */
extend(matchers: {[name:string]: JestMatcher}): void,
/** Add a module that formats application-specific data structures. */
addSnapshotSerializer(serializer: (input: Object) => string): void,
assertions(expectedAssertions: number): void,
any(value: mixed): JestAsymmetricEqualityType,
anything(): void,
arrayContaining(value: Array<mixed>): void,
objectContaining(value: Object): void,
/** Matches any received string that contains the exact expected string. */
stringContaining(value: string): void,
stringMatching(value: string | RegExp): void,
};
// TODO handle return type
// http://jasmine.github.io/2.4/introduction.html#section-Spies
declare function spyOn(value: mixed, method: string): Object;
/** Holds all functions related to manipulating test runner */
declare var jest: JestObjectType
/**
* The global Jasmine object, this is generally not exposed as the public API,
* using features inside here could break in later versions of Jest.
*/
declare var jasmine: {
DEFAULT_TIMEOUT_INTERVAL: number,
any(value: mixed): JestAsymmetricEqualityType,
anything(): void,
arrayContaining(value: Array<mixed>): void,
clock(): JestClockType,
createSpy(name: string): JestSpyType,
createSpyObj(baseName: string, methodNames: Array<string>): {[methodName: string]: JestSpyType},
objectContaining(value: Object): void,
stringMatching(value: string): void,
}

1206
newIDE/app/flow-typed/npm/jest_v24.x.x.js vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -33,7 +33,7 @@
"@lingui/react": "git://github.com/4ian/lingui-react.git#master",
"@material-ui/core": "4.9.10",
"@material-ui/icons": "4.9.1",
"@material-ui/lab": "4.0.0-alpha.49",
"@material-ui/lab": "4.0.0-alpha.56",
"algoliasearch": "3.33.0",
"axios": "^0.18.1",
"blueimp-md5": "^2.10.0",
@@ -43,6 +43,8 @@
"element-closest": "2.0.2",
"firebase": "^6.1.0",
"fontfaceobserver": "2.0.13",
"js-worker-search": "^1.4.1",
"jss-rtl": "^0.3.0",
"keen-tracking": "1.1.3",
"lodash": "4.17.4",
"node-require-function": "^1.2.0",

View File

@@ -2,8 +2,8 @@
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-eval' 'unsafe-inline' https://api.gdevelop-app.com https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js https://api.keen.io https://apis.google.com">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-eval' 'unsafe-inline' blob: https://api.gdevelop-app.com https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js https://api.keen.io https://apis.google.com">
<link rel="apple-touch-icon" href="%PUBLIC_URL%/apple-touch-icon.png">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon-256.png">
<title>GDevelop 5</title>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1 @@
An example showing all the layer effects available in GDevelop.

View File

@@ -0,0 +1,43 @@
{
"author": "The Gem Dev",
"description": "",
"extensionNamespace": "",
"fullName": "Alert",
"name": "Alert",
"shortDescription": "Popup an alert with a message",
"tags": "",
"version": "0.01",
"eventsFunctions": [
{
"description": "Popup an alert and display a message",
"fullName": "Popup an alert",
"functionType": "Action",
"name": "alert",
"sentence": "Alert message _PARAM1_",
"events": [
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::JsCode",
"inlineCode": "alert(eventsFunctionContext.getArgument(\"message\"));",
"parameterObjects": "",
"useStrict": true
}
],
"parameters": [
{
"codeOnly": false,
"defaultValue": "",
"description": "The message to display on alert",
"longDescription": "",
"name": "message",
"optional": false,
"supplementaryInformation": "",
"type": "string"
}
],
"objectGroups": []
}
],
"eventsBasedBehaviors": []
}

View File

@@ -0,0 +1,73 @@
{
"author": "",
"description": "",
"extensionNamespace": "",
"fullName": "",
"name": "DebugMessages",
"shortDescription": "",
"tags": "",
"version": "",
"eventsFunctions": [
{
"description": "Popup an alert with message",
"fullName": "Popup a message",
"functionType": "Action",
"name": "popup",
"sentence": "Popup message _PARAM1_",
"events": [
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::JsCode",
"inlineCode": "alert(eventsFunctionContext.getArgument(\"message\"));",
"parameterObjects": "",
"useStrict": true
}
],
"parameters": [
{
"codeOnly": false,
"defaultValue": "",
"description": "The message to pop up",
"longDescription": "",
"name": "message",
"optional": false,
"supplementaryInformation": "",
"type": "string"
}
],
"objectGroups": []
},
{
"description": "Prompts for a value (only works on browser)",
"fullName": "Prompt for a value",
"functionType": "StringExpression",
"name": "prompt",
"sentence": "",
"events": [
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::JsCode",
"inlineCode": "eventsFunctionContext.returnValue = prompt(eventsFunctionContext.getArgument(\"q\"));\n",
"parameterObjects": "",
"useStrict": true
}
],
"parameters": [
{
"codeOnly": false,
"defaultValue": "",
"description": "Prompt Question",
"longDescription": "",
"name": "q",
"optional": false,
"supplementaryInformation": "",
"type": "string"
}
],
"objectGroups": []
}
],
"eventsBasedBehaviors": []
}

View File

@@ -0,0 +1,32 @@
{
"author": "The Gem Dev",
"description": "",
"extensionNamespace": "",
"fullName": "Internet Connectivity",
"name": "InternetConnectivity",
"shortDescription": "an extension which checks if the device is connected to the internet. ",
"tags": "javascript, desktop, mobile, internet, connection",
"version": "0.0.1",
"eventsFunctions": [
{
"description": "checks if the device running the game is connected to the internet.",
"fullName": "The device is online",
"functionType": "Condition",
"name": "Thedeviceisonline",
"sentence": "The device is online",
"events": [
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::JsCode",
"inlineCode": "var status = runtimeScene.getVariables().get(\"connectionState\");\n\nfunction connectionStatus() {\n \n if (navigator.onLine) {\n return\n }\n}\n\neventsFunctionContext.returnValue = navigator.onLine;\n\n\n",
"parameterObjects": "",
"useStrict": true
}
],
"parameters": [],
"objectGroups": []
}
],
"eventsBasedBehaviors": []
}

View File

@@ -0,0 +1,15 @@
{
"associatedLayout": "Layer Effects",
"lastChangeTimeStamp": 0,
"name": "Load Images",
"events": [
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::JsCode",
"inlineCode": "var object = runtimeScene.getVariables().get(\"object\").getAsString(); \nvar anim = runtimeScene.getVariables().get(\"animation\").getAsNumber(); \nvar url = runtimeScene.getVariables().get(\"url\").getAsString(); \nruntimeScene.myCallback = function(loader, resources){ \n var mySprite= resources[\"Images\"]; \n var game = runtimeScene.getGame(); \n var object_texture_image = runtimeScene.getObjects(object); \n var object_texture_image_renderer = object_texture_image[anim].getRendererObject(); \n object_texture_image_renderer.texture = mySprite.texture; \n};\nPIXI.Loader.shared.reset(); \nPIXI.Loader.shared.add(\"Images\", url); \nPIXI.Loader.shared.load(runtimeScene.myCallback); ",
"parameterObjects": "",
"useStrict": true
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1021 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

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