Compare commits

...

455 Commits

Author SHA1 Message Date
Florian Rival
2b156ef147 Add action to disable metrics 2020-11-26 15:27:47 +00:00
Florian Rival
f650a6aa9c Add support for registering a game and viewing its recorded metrics 2020-11-25 20:29:26 +00:00
Florian Rival
5d62f0c926 Send anonymous metrics when a game session starts
This allows to surface to game developers basic metrics, without using a third party or compromising the player privacy and without risking reducing the game performance.
2020-11-25 20:29:26 +00:00
Florian Rival
449a1f5da9 Increase the number of extensions shown in the Extensions search at once
Don't show in changelog
2020-11-25 17:36:18 +00:00
Florian Rival
a0e0fdf6e1 Add support for yes/no (or true/false) parameters for extensions made in the editor 2020-11-22 14:27:59 +00:00
Arthur Pacaud
036f384ff9 Fix lights crashing the game when WebGL is not supported (#2107) 2020-11-22 12:38:02 +00:00
Florian Rival
b42abf0cd8 Fix compilation 2020-11-20 09:22:58 +00:00
Florian Rival
ee699d3870 Fix warnings 2020-11-20 09:15:04 +00:00
Florian Rival
346eed3779 Improve UI of the dialog to edit the grid of the scene editor
Don't show in changelog
2020-11-20 09:10:36 +00:00
Sebastian Sangervasi
ef6f491fb4 Add an option to choose the color of the grid shown in the scene editor (#2104)
Co-authored-by: Sebastian Sangervasi <villain@harmless.dev>
2020-11-20 08:57:44 +00:00
Florian Rival
ee6043477b Add projectUuid to help identifying projects uniquely
Can be useful for online services that need a way to identify a game uniquely
2020-11-18 21:59:18 +00:00
Florian Rival
deddfdc4cf Fix ObjectVarToJSON expression not working
Fix #2097
2020-11-16 23:03:49 +00:00
Arthur Pacaud
6ad69d4c74 Allow to specify a list of options for parameters of an action/condition of an extension made in the editor (#2046) 2020-11-15 12:37:48 +00:00
Florian Rival
6446bb20a0 Add workflow to automatically close bug reports that are not detailed
Don't show in changelog
2020-11-15 11:33:17 +00:00
Harsimran Singh Virk
015f9f64c7 Fix custom textures not working for light objects (#2090) 2020-11-14 14:52:11 +00:00
Florian Rival
74e5b30fd1 Simplify usage of some React contexts in MainFrame
Don't show in changelog
2020-11-12 22:42:59 +00:00
Florian Rival
057c0a1d13 Add support for the Asset Store on the desktop app
Also:
* Automatically download resources when a project made on the web-app is opened on the desktop-app
* Rework loader for when opening a project or launching a preview
* Shorten names for resources added from the resource store, in the web-app
2020-11-12 21:14:18 +00:00
Florian Rival
7f6c9923dc Fix changing opacity of Sprite objects not working for objects outside of the screen
Fix #2087
2020-11-12 09:18:01 +00:00
Arthur Pacaud
3dae7c1899 Add VS Code tasks for most common development tasks (#2083)
Only show in the developer changelog
2020-11-11 08:47:27 +00:00
Florian Rival
04c2abd508 Remove "projectFile" field from the project json files 2020-11-08 20:46:13 +00:00
Florian Rival
d82fd79186 Update some examples
Don't show in changelog
2020-11-07 15:33:17 +00:00
Florian Rival
fe312e0bf6 Add action/condition/expression to change the default Z order of objects created on a layer 2020-11-07 15:33:17 +00:00
Florian Rival
ad22a83680 Set objects created from events Z order so that they appear in front of objects that were on the scene at its startup 2020-11-07 15:33:17 +00:00
Florian Rival
ac32b677b0 Remove deprecated fields from project serialized json
Don't show in changelog
2020-11-07 15:33:17 +00:00
Florian Rival
902bc8a510 Move types definition of EventsFunctionContext to GDJS/Runtime
Don't show in changelog
2020-11-07 15:33:17 +00:00
Florian Rival
804c9563a1 Show a split button with a dropdown menu instead of a separate button to add a lighting layer
Don't show in changelog
2020-11-07 00:30:21 +00:00
Florian Rival
64996b5f7d Add an editor showing properties and effects for a layer (lighting layer or not) 2020-11-07 00:30:21 +00:00
Florian Rival
5fdf7be698 Fix re-opening last edited project not working on the web-app when using Google Drive as storage 2020-11-05 21:59:01 +00:00
Florian Rival
a869fc14f9 Fix proportional resize on the scene editor on touchscreens 2020-11-04 23:56:16 +00:00
Florian Rival
ae8a26b3f9 Try to workaround a Linux mouse freeze when renaming an item using an invalid name 2020-11-03 23:30:21 +00:00
Florian Rival
aaec53faaa Allow extensions to have icons set from an icon library 2020-11-03 22:16:22 +00:00
Florian Rival
bc56f820b3 Fix expression to read the window title crashing the game 2020-11-03 22:11:27 +00:00
Florian Rival
2c93c948bf Refactor to use shouldValidate instead of hardcoded key codes
Don't show in changelog
2020-11-02 22:16:40 +00:00
Florian Rival
fe3a2f6e4a Add CircleCI badge and reorganize a bit the README
Don't show in changelog
2020-10-31 15:30:28 +00:00
Florian Rival
449c96aaba Fix "Create" not shown anymore in object actions list
Don't show in changelog
2020-10-31 15:11:28 +00:00
Aurélien Vivet
4cee984472 Remove Create function from object list only (#2073) 2020-10-31 14:01:08 +00:00
Florian Rival
98c9763d1c Add proper support for keyboard for editing the parameters of events 2020-10-29 23:47:42 +00:00
Florian Rival
c3ed8cbbb4 Trap the focus in the inline parameter editor popover (don't let tab outside of it)
Also fix some fields not allowing to press Escape to close

Don't show in changelog
2020-10-29 23:47:42 +00:00
Florian Rival
65fc9f599e Fix formatting and tests 2020-10-29 23:47:42 +00:00
Florian Rival
10ebf9e65d Update package-lock.json 2020-10-29 23:47:42 +00:00
Florian Rival
d1b1e3b24e Fix variables inline editors that could not be closed with Escape
Don't show in the changelog
2020-10-29 23:47:42 +00:00
Florian Rival
188b262af0 Update material-ui and simplify SemiControlledAutoComplete 2020-10-29 23:47:42 +00:00
Florian Rival
a04c7f993f Fix the focus not being set back to the parameter after editing it inline in the events sheet 2020-10-29 23:47:42 +00:00
Florian Rival
13a8b5bce0 Fix the inline edition of parameters not applying changes when closed on a touchscreen 2020-10-29 23:47:42 +00:00
Florian Rival
45e6b19204 Allow the inline parameter popover to be closed with Escape 2020-10-29 23:47:42 +00:00
Florian Rival
0136445a65 Fix completions of expressions inserted twice on touch screens when choosing an object/behavior 2020-10-29 00:02:44 +00:00
Florian Rival
c26df2c8a9 Fix CircleCI configuration to avoid memory issues (#2035) 2020-10-27 10:54:16 +00:00
Florian Rival
f390d4a1bc Fix typo 2020-10-26 22:36:48 +00:00
Florian Rival
cc2cdc492e Improve/simplify platformer by using tweens for coins and enemies
Don't show in changelog
2020-10-26 22:34:49 +00:00
Florian Rival
feeebd0560 Fix potential crash/internal error when setting a keyboard shortcuts 2020-10-26 21:57:02 +00:00
Florian Rival
f6145f4c4e Add various expressions to get angles and distances between positions or objects (#2062)
* Add `DistanceBetweenPositions`, `AngleBetweenPositions`, `Object.AngleToObject`, `Object.AngleToPosition`, `Object.DistanceToPosition`, `Object.SqDistanceToPosition`.
2020-10-26 21:43:43 +00:00
Florian Rival
fd490e1d5a Add multiple improvements to the platformer starter
* Add ladder, checkpoints, collision with enemies (thanks @Bouh!)
* Add fade in when going back to checkpoint and sound effects
* Fix some sound effects
2020-10-26 17:40:11 +00:00
Florian Rival
4760b0ab04 Fix tweens not properly applied when only one object with the Tween behavior was created in the scene 2020-10-26 17:33:17 +00:00
Aurélien Vivet
3f95bf9f1a Increase and make responsive the height of selectors in the instruction editor. (#2058) 2020-10-26 15:05:19 +01:00
Aurélien Vivet
76b63c2f76 Make zoom direction in animation preview and hitbox editor consistent with the rest of the editor. (#2056)
Don't show the rest in the changelog:
* Inverse zoom in preview animation and hitbox editor.
* Make consistent with zoom direction in scene editor.
* Prettier
2020-10-26 14:55:55 +01:00
Aurélien Vivet
0a501f5a3c Rename the action Global color to Tint (#2057)
Don't show the rest in the changelog:
Because global color is false and misleading.
2020-10-26 14:53:18 +01:00
Florian Rival
45ab608409 Add a workflow to close issues with missing examples
Don't show in changelog
2020-10-26 13:15:08 +01:00
Aurélien Vivet
df94a4d0fb Minor fixes (#2049)
Don't show in changelog
* Fix names functions from Tween-test example
* Typo movement
* The word was sticked on crowdin.
2020-10-25 15:04:33 +01:00
Florian Rival
c7d3d1314d Fix "pinch to zoom" sometimes wrongly triggering the opening the objects editor on touchscreens 2020-10-23 18:51:55 +02:00
Florian Rival
cff1a1e3c7 Fix Typescript error
Don't show in changelog
2020-10-22 09:24:10 +02:00
Florian Rival
3cf421f05b Fix orientation lock throwing an unhandled error on desktop
Also fix formatting

Don't show in changelog
2020-10-22 09:14:34 +02:00
Florian Rival
6cc5016f9e Make the GenerateAllDocs script fail if some documentation generation errors
Don't show in changelog
2020-10-21 14:48:16 +02:00
Arthur Pacaud
2dd62456c2 Use a new theme for the JavaScript game engine documentation (#1672)
* Also add missing functions in the documentation.

Only show in the developer changelog
Co-authored-by: Florian Rival <Florian.rival@gmail.com>
2020-10-21 14:42:25 +02:00
Arthur Pacaud
d8b1c471bb Fix events sheet not adapting immediately after window resize (#2033) 2020-10-19 23:39:59 +02:00
Arthur Pacaud
a3622a6504 Fix actions to set opacity and position of the window on Windows/macOS/Linux (#2044)
* Also add a warning on "dangerous" functions of advanced window controls that could block the preview.
2020-10-19 18:59:26 +02:00
Aurélien Vivet
4ab14d18f8 Add width and height actions for Tweens (#2041)
* Add width and height actions for Tweens.
* Add width and height tweens to the example.

Show the rest in the developer changelog

* Clean the example Tween-test
* Generate fixtures for the webapp
2020-10-19 13:44:00 +02:00
Arthur Pacaud
8ba11703e1 Allow to change shortcuts by clicking on them in the preferences (#1948) 2020-10-19 12:22:32 +02:00
Arthur Pacaud
8a8adf213a Fix potential orientation lock issues on Android (#2034) 2020-10-19 12:12:56 +02:00
Florian Rival
25ea23a115 Store if a JavaScript code block is expanded or not
Don't show in changelog
2020-10-19 09:35:19 +01:00
Arthur Pacaud
586694543d Add The gem dev to contributors list (#2045)
Don't show in changelog
2020-10-19 08:59:05 +01:00
Sebastian Sangervasi
b7b6ab91f5 Allow the JavaScript code blocks in events to be expanded to view more lines (#2037)
Co-authored-by: Sebastian Sangervasi <villain@harmless.dev>
Co-authored-by: Florian Rival <Florian.rival@gmail.com>
2020-10-19 08:53:31 +01:00
Arthur Pacaud
d2d0235c8c Use Nord as the default theme if the system theme is dark on macOS (#1950) 2020-10-18 14:16:13 +01:00
Florian Rival
b473e0aaf0 Add button to paste condition/actions after right clicking "Add condition/action" 2020-10-17 12:37:03 +01:00
Florian Rival
b2c7166b1b Fix completions of expressions inserted twice on touch screens 2020-10-17 11:48:14 +01:00
Florian Rival
bb2ae1a914 Replace "return true if" by "check if" in description of conditions
Don't show in changelog
2020-10-17 11:25:16 +01:00
Florian Rival
aa1c5584ca Fix examples resources not deployed after the web-app is deployed
Fix #2038

Don't show in changelog
2020-10-16 14:06:26 +01:00
Florian Rival
28593608a5 Bump newIDE version 2020-10-16 13:52:20 +01:00
Florian Rival
8c5a312725 Set the production url for the asset api
Don't show in changelog
2020-10-16 13:51:54 +01:00
Sebastian Sangervasi
3ed07dee5e Fix margins/widths/extra scrollbars of the JavaScript code block events (#2036)
Co-authored-by: Sebastian Sangervasi <villain@harmless.dev>
2020-10-16 09:18:08 +01:00
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
Florian Rival
075d918619 Update translations 2020-08-30 22:31:34 +01:00
Florian Rival
b68dfe040e Fix warning 2020-08-30 21:34:52 +01:00
Florian Rival
053f4a68df Add link to more tutorials by Wishforge Games (https://www.youtube.com/channel/UCxsQHU5SwYtO6uc1jiLdvrg) 2020-08-30 21:34:38 +01:00
Florian Rival
216fd30145 Remove a useless translation marker
Variables can't be translated magically like this :)

Don't show in changelog
2020-08-30 20:10:58 +01:00
Florian Rival
fda75e0475 Improve changelog extractor
Don't show in changelog
2020-08-30 12:28:37 +01:00
Florian Rival
7fe057c180 Improve alerts display on small screens 2020-08-30 00:27:03 +01:00
Florian Rival
5d091c0a87 Add multiple light objects fixes (#1929)
Don't show in changelog
2020-08-29 18:52:36 +01:00
The Gem Dev
319cea428e Update the AdMob icon (#1953) 2020-08-29 18:10:45 +01:00
Florian Rival
0ac2ef7892 Allow extensions to require @pixi/... modules in the IDE
Don't show in the changelog
2020-08-29 17:16:51 +01:00
Aurélien Vivet
fd6b9be49c Add a section for developers in the release notes (#1892)
Only show in the developer changelog
2020-08-28 19:06:42 +01:00
Harsimran Virk
2d6f0fad90 Added a polygon to replace the use of hitbox in raycasting algo. 2020-08-26 15:59:27 +05:30
Florian Rival
35f019afa8 Add "Game Feel Demo" by Sleeper Games
* See these game feel examples in a complete game powered by GDevelop: http://hyperspacedogfights.com/
2020-08-26 09:29:41 +01:00
Florian Rival
f7453a6a1d Update yarn.lock 2020-08-26 00:07:46 +01:00
Nilay Majorwar
89570505e6 Add support for customizable keyboard shortcuts (#1938)
* In the preferences, browse the list of existing shortcuts. Try the existing one to speed up your creation worflow! For example, press *F5* to launch a preview.
* For each command available in the command palette, a shortcut can be added, changed or removed.
2020-08-25 23:54:24 +01:00
Florian Rival
082318d7e4 Fix vibration not working in exported Android games.
Fix #1922
2020-08-24 23:13:48 +01:00
Florian Rival
59c9812208 Only add the AdMob plugin when the AdMob App Id is set (#1940)
Don't show in changelog
2020-08-24 22:54:51 +01:00
Florian Rival
62117e42d9 Make the action to send a web request "asynchronous" (not blocking the game execution) (#1937)
* The result from the request is stored in the specified variable (and any error in a second variable)
* This avoids blocking the game execution while the request is being made, and allow multiple requests to be made at the same time.
2020-08-24 20:51:37 +01:00
Arthur Pacaud
cafa0d512f Allow extensions to declare dependencies (npm, cordova...) and custom properties in the project (#1717)
Only show in developer changelog
2020-08-24 20:51:10 +01:00
Harsimran Virk
136964053b Renamed variables and changed doc 2020-08-21 12:52:08 +05:30
Harsimran Virk
6beea7bfaf Changed default ambient light color to (200, 200, 200) 2020-08-20 19:39:11 +05:30
Harsimran Virk
ab6999a16c Working expanded bounding box. 2020-08-19 19:06:10 +05:30
Harsimran Virk
937fd1888a Fixed a weird bug related to debug graphics. 2020-08-19 18:12:49 +05:30
Harsimran Virk
755c72c0bf Fixed undefined handling of light obstacle manager. Moved texture handling in renderer. 2020-08-19 16:20:36 +05:30
Florian Rival
20392d6a79 Update newIDE/electron-app/app/package-lock.json 2020-08-19 09:44:56 +02:00
Florian Rival
0a2033db3d Improve changelog extractor with more ignored messages
Don't show in changelog
2020-08-19 09:43:53 +02:00
Florian Rival
6c0fe0359a Add experimental Peer-to-Peer communication extension (#1842)
* This allows to transmit messages on the network to different remote players, enabling simple multiplayer games.
* Read the [documentation on the wiki](http://wiki.compilgames.net/doku.php/gdevelop5/all-features/p2p) to understand how it works, limitations and capabilities of the extension. In particular, for released games, it's recommended that you host a *broker server* allowing game instances to be discovered and connected.
2020-08-18 22:38:45 +02:00
Florian Rival
66ed1110d2 Update JsExtension.js 2020-08-18 22:36:11 +02:00
Florian Rival
5badb27b35 Update light descriptions and default color
Don't show in changelog
2020-08-17 18:23:10 +02:00
Harsimran Singh Virk
b7902bb141 Add support for dynamic 2D lights (#1881)
* This adds a **Light** object that can be added on the scene, with a customizable color and radius.
* Add the **Light Obstacle** behavior to the object that must acts as obstacle (walls, etc...) to the lights.
* You can customize the ambient color of the rest of the scene from almost white (useful to show light shadows) to entirely black (useful for horror/exploration games) or any color.
* Use effects on the "Lighting" layer like "Kawase Blur" to achieve soft shadows.
2020-08-17 17:48:26 +02:00
Aurélien Vivet
b5b3abd155 Upgrade to Pixi 5.3.3 (#1925) 2020-08-17 17:15:20 +02:00
Aurélien Vivet
06b299c4a2 Delete the artefact Thumbs.db from Windows OS
Previously added in
https://github.com/4ian/GDevelop/pull/1858

Don't show in changelog
2020-08-17 11:47:06 +02:00
The Gem Dev
e42d2cbc6d Add Solarized Dark theme (#1858)
* A new Dark theme based on [Solarized color scheme](https://ethanschoonover.com/solarized/).
2020-08-13 12:06:37 +02:00
Arthur Pacaud
454159db3f [Final Fixes] Add discord rich presence (#1915)
* Add Discord rich presence to GDevelop

* Prettier

* Add error handling when discord not installed

* Try to fix flow typing

* Fix typo

* Fix typo not fixed in last commit

* Switch to hook in mainframe

And apply other review instructions

* fix flow

* Final Fixes
2020-08-12 21:25:32 +02:00
Florian Rival
4324526689 Fix behavior not destroyed in a live preview when the behavior is removed from an object 2020-08-12 16:19:48 +02:00
Florian Rival
b57832a131 Allow modules loaded by extensions to require "pixi.js" in addition to "pixi.js-legacy"
This should allow to not "hack" 3rd party modules so that they require "pixi.js-legacy" instead of "pixi.js". In both cases, we return "pixi.js-legacy".

This still requires modules to be supporting CommonJS (for Electron) and the global PIXI variable (for browsers).
2020-08-12 11:41:02 +02:00
Rahul Saini
8d9f5f0df0 Add script to generate list of community-made extensions (#1913) 2020-08-10 18:44:05 +02:00
Arthur Pacaud
b6ec327dfc Add 4ian as a GitHub codeowner (#1914)
Don't show in changelog
2020-08-09 21:54:36 +02:00
Sanskar Bajpai
005aa64aad Add a close button at the bottom of the search panel
* Feature: Added a close button on the panel.

Implements #1909.

* Stories: Added the new prop in Stories.

This commit introduces the addition of the onCloseSearchPanel prop in the Stories
thus removing all the flow errors. Prettier code formatting has also been run to make
the code look cleaner, and lastly the prop has been destructured in the
SearchPanel.js file.
2020-08-08 19:21:18 +02:00
Arthur Pacaud
a18b813140 Update phonegap-build Version to v9 (#1912) 2020-08-08 14:32:47 +02:00
arthuro555
7cd28062fc Update fixtures 2020-08-08 12:06:14 +02:00
Aurélien Vivet
2b7e2c8814 Fix Menu import in Electron exported games (#1911)
Don't show in changelog
2020-08-07 18:50:30 +02:00
Florian Rival
767f365a78 Revert usage of pick in GenerateObjectCondition
Don't show in changelog
2020-08-05 18:47:39 +02:00
Florian Rival
5f54583ff5 Add TypeScript checks to gdjs.RuntimeScene, gdjs
Only show in developer changelog
2020-08-05 18:47:39 +02:00
Florian Rival
37c260c19d Remove methods polluting Array prototype in gd.js
Only show in developer changelog
2020-08-05 18:47:39 +02:00
arthuro555
003f251c9f Apply review instructions 2020-08-03 23:48:10 +02:00
arthuro555
f8250ec9aa Regen fixtures 2020-08-02 21:34:18 +02:00
arthuro555
aeb4d278cd Merge branch 'master' into add-multiplayer-p2p 2020-08-02 21:31:28 +02:00
Florian Rival
2762329dd6 Update game fixtures for the web-app
Don't show in changelog
2020-08-02 18:38:14 +01:00
Florian Rival
75b1ff5cea Improve changelog extractor
Don't show in changelog
2020-08-02 18:18:36 +01:00
Florian Rival
1f4042bff0 Fix menu bar shown in exported games on Windows/macOS/Linux 2020-08-02 15:28:34 +01:00
Florian Rival
4e04e79b2f Bump newIDE version 2020-07-29 00:13:15 +01:00
Florian Rival
b9ba8e1b7b Update translations 2020-07-28 22:33:49 +01:00
Florian Rival
84ea9a9643 Merge branch 'master' of github.com:4ian/GDevelop 2020-07-28 20:26:28 +01:00
Nilay Majorwar
13c44250f2 Add network preview command, hide debug and network preview commands on web (#1896)
Don't show in changelog
2020-07-28 17:31:20 +01:00
Florian Rival
a5907a6883 Enable the Command Palette by default in the preferences for new users
* If you want to use the Command Palette and have GDevelop already installed, activate it in the preferences
2020-07-28 09:06:13 +01:00
Florian Rival
5902906bcc Add Health Bar And Health Potion video tutorial
Don't show in changelog
2020-07-28 09:05:42 +01:00
Florian Rival
4db041bf10 Add subscription reminder once in a while when using hot-reloading.
Don't show in changelog
2020-07-27 23:36:18 +01:00
arthuro555
63894f9a86 prettier 2020-07-27 22:41:13 +02:00
arthuro555
9a0ec853e7 Try to fix flow again 2020-07-27 15:56:36 +02:00
arthuro555
eb5d120aaf Try to fix flow
Flow doesn't work locally so I have to wait for travis output to be sure
2020-07-27 15:30:52 +02:00
arthuro555
057dd985fc Fix flow typing 2020-07-27 13:16:51 +02:00
arthuro555
8009e45936 Add files forgotten in last commit 2020-07-27 13:16:26 +02:00
arthuro555
b190731940 Change way Peer JS is initialized and update example 2020-07-27 12:40:58 +02:00
arthuro555
a337230195 Add disconnection events 2020-07-26 23:06:55 +02:00
arthuro555
731b9141fa Run prettier 2020-07-26 19:52:05 +02:00
arthuro555
51ba2e7631 Add hints for peer to peer 2020-07-26 19:50:49 +02:00
arthuro555
48a0c2d324 Regenerate fixtures for examples 2020-07-26 13:32:27 +02:00
Arthur Pacaud
25d32ce9bb Merge branch 'master' into add-multiplayer-p2p 2020-07-26 13:28:55 +02:00
arthuro555
a7ec57354d Update example 2020-07-26 13:24:45 +02:00
Florian Rival
cc1d26201e Update yarn.lock
Don't show in changelog
2020-07-26 12:18:17 +01:00
arthuro555
643e3b5c32 Add basic error handling 2020-07-26 13:15:07 +02:00
arthuro555
0cc4676067 Add is p2p ready condition 2020-07-26 12:52:48 +02:00
arthuro555
91b895fd92 Fix event data on no dataloss mode 2020-07-26 12:38:18 +02:00
arthuro555
f95d0ae461 Let user choose incoming message handling 2020-07-26 12:18:46 +02:00
arthuro555
81ce81242b Add option to use own server 2020-07-26 11:19:02 +02:00
Florian Rival
aa71e78507 Add Video tutorials and hints about these tutorials in the editor
* Thanks Wishforge Games (http://wishforge.games/) for these very high quality video tutorials!
2020-07-26 00:49:55 +01:00
Florian Rival
ee49ca6c14 Add support for layer re-ordering in hot reloading
Don't show in changelog
2020-07-25 23:27:23 +01:00
Florian Rival
a649789f4c Improve some typings in GDJS Runtime
Only show in developer changelog
2020-07-25 22:19:35 +01:00
Florian Rival
61e8e95d5b Add typing for PIXI in GDJS Runtime
This means that the global object PIXI will now be properly typed and understood by TypeScript.

Also fix documentation generation

Don't show in changelog
2020-07-25 18:56:38 +01:00
Florian Rival
cc158a9250 Add some standard libraries to the libraries used by Typescript to do the type checking
Don't show in changelog
2020-07-25 18:31:38 +01:00
Florian Rival
a91ccacb89 Improve typing in hot-reloader.js
Promise and other specific standard types can actually be imported using a triple slash directive.

Don't show in changelog
2020-07-25 18:27:05 +01:00
Florian Rival
bb9e8a2ea9 Merge pull request #1840 from 4ian/feature/hot-reload
Add "live previews" a.k.a "hot reloading"
2020-07-25 14:43:34 +01:00
Florian Rival
3bf40cd46c Fix hot-reloading of extensions in Network Preview and fix reloading of some events generated code files
Don't show in changelog
2020-07-25 14:23:02 +01:00
Florian Rival
aa823c1287 Make Network Preview (Preview over Wifi) compatible with live preview ("hot reloading")
* Also allow the debugger to work with games run using Network Preview (Preview over Wifi), including on other devices (phones, tablets...)

Don't show the rest in the changelog:

This removes the "live reloading" of the network preview and makes the hot-reloading and debugging to work with the network preview.
2020-07-25 14:23:02 +01:00
Florian Rival
24a666ab83 Fix hot-reloading of Anchor behavior and BBText and Text objects width
Don't show in changelog
2020-07-25 14:23:02 +01:00
Florian Rival
9e652b228d Don't reload fonts already loaded during a hot-reload
Also only issue a single request when multiple audio resources are pointing to the same file.

Don't show in changelog
2020-07-25 14:23:01 +01:00
Florian Rival
09bedc6ce5 Ensure events generated code is stable across code generation.
This is done by given unique identifiers to "Trigger Once" conditions (stable given the same object in memory) and events list function names (stable given events with same content).

This avoids useless hot-reloading and re-triggering Trigger Once conditions after a hot-reloading.

Don't show in changelog
2020-07-25 14:23:01 +01:00
Florian Rival
91e57340d4 Update icons and fix stale icons in Debugger Toolbar when selecting game
Don't show in changelog
2020-07-25 14:23:01 +01:00
Florian Rival
c385aae845 Add support for "hot reloading" of previews (apply changes to preview without restarting) 2020-07-25 14:23:01 +01:00
Florian Rival
460b582ab9 Refactor changes cancelling of GDevelop.js objects
* Use a typed hook (shorter and type-safe to use)
* Avoid the necessity of providing a function to create an object.
* Only unserialize back to the object if cancelling changes (instead of when applying).
2020-07-25 14:23:00 +01:00
Florian Rival
3a9f896f04 Add hot reloader (electron app only) 2020-07-25 14:23:00 +01:00
Florian Rival
2851a20787 Add persistentUuid to gd::InitialInstance 2020-07-25 14:22:59 +01:00
Florian Rival
9077c5d4f7 Fix saving a file potentially resulting in an empty file in some circumstances
* File integrity is now checked after a project is saved.
* Prevent concurrent save of a file (could happen if Ctrl+S/Cmd+S was kept pressed, and could result in an empty file being saved on disk).

Fix #1813
2020-07-25 14:22:04 +01:00
Arthur Pacaud
693b64cddf Fix documentation typo (#1882)
Don't show in changelog
2020-07-20 16:53:55 +01:00
Florian Rival
661d329170 Upgrade game rendering to use Pixi.js 5.3.0, allowing games to run with WebGL 2 (#1824)
* This brings various upgrades and performance improvement to the internal rendering engine used by games, both in the editor and in exported games.
* This also paves the way for adding new objects like Bitmap Text, Mesh or dynamic lights in the future.
* Huge thanks to @Quarkstar for working on this task and making most of the necessary upgrades .
* Thanks @Bouh for helping fixing/upgrading the Shape Painter object and @Silver-Streak as well as testers from the forum

Don't show the rest in changelog:
* Add a test game with all effects that can be used, to quickly verify they are working.

Co-authored-by: Quarkstar <quarkstar9@gmail.com>
Co-authored-by: Aurélien Vivet <bouh.vivez@gmail.com>
2020-07-19 22:10:38 +01:00
Florian Rival
66ce941d46 Add Particle Effects Demo to starters (Thanks Wishforge Games! http://wishforge.games/) 2020-07-19 17:53:27 +01:00
Florian Rival
d4023efe0f Fix forgotten changes in the last commit
Don't show in changelog
2020-07-19 15:57:27 +01:00
Florian Rival
815bd92469 Remove implementation of StrRFind/StrRFindFrom
Don't show in changelog
2020-07-19 15:42:06 +01:00
Aurélien Vivet
8685defaa8 Rename StrRFind and StrFindFrom to StrFindLast and StrFindLastFrom (#1859) 2020-07-19 15:27:47 +01:00
Sebastian Sangervasi
ad89af6ad5 Update exported games to run with Electron 8.2.5 (#1835)
Don't show the rest in the changelog:

This change updates the electron version of the export template
to 8.2.5 to match the electron version that is used in the IDE.

This change also sets `allowRendererProcessReuse` app option to
further match the IDE environment.

Co-authored-by: Sebastian Sangervasi <villain@harmless.dev>
2020-07-19 15:13:54 +01:00
Florian Rival
0428417295 Update the build API used for development
Don't show in changelog
2020-07-19 12:26:51 +01:00
Nilay Majorwar
54c0424785 Add more commands to the command palette (#1864)
* Tab-related: Open scene, Open external events, Open external layout, Open extension
* Scene editor: Edit object, Edit object variables, Edit object group, Edit layer effects, Open scene properties, Open scene variables, Toggle grid, Toggle mask, Setup grid and some panel-opening commands like Open properties panel, Open layers panel, etc...
* Events editor: Create empty event, Add event of type, Search events, Add sub-event, Delete selected events
* Project-related: Open project properties, Edit global variables, Open project resources, Open project icons
* General: Open recent project
* and more!
2020-07-17 20:25:54 +01:00
Florian Rival
f316d28fe3 Fix translations 2020-07-16 09:23:35 +01:00
arthuro555
e6b4373d97 Remove arrow function 2020-07-15 15:52:52 +02:00
arthuro555
72e705a39a Update peerjs 2020-07-15 15:44:50 +02:00
arthuro555
9bc71a42e4 Fixed potential crash 2020-07-15 15:09:09 +02:00
Florian Rival
104b6c2800 Fix behaviors of an extension wrongly working after the extension is removed
* This was fixed by saving and reloading the game. The behaviors are now properly unloaded if an extension is removed.

Fix #1844
2020-07-14 14:45:55 +02:00
Florian Rival
0ac504c0ab Fix crash when using a behavior of a deleted extension 2020-07-14 14:45:55 +02:00
Arthur Pacaud
0508da60e5 Add greater good affirmation to readme (#1862)
Read their website for more details: https://good-labs.github.io/greater-good-affirmation

Don't show in changelog
2020-07-14 14:32:54 +02:00
Florian Rival
2e511c75bf Fix compilation on GCC
Don't show in changelog
2020-07-07 10:00:42 +02:00
Florian Rival
b76df0247d Fix "Trigger Once" not working properly when used in a behavior
Don't show the rest in the changelog:

This was because the OnceTriggers were shared with the runtime scene. Now each behavior has its set of Once Triggers. This means that Once Triggers "survive" if the behavior is deactivated then activated again.

Added integration test for generated behavior

Fix #1843
2020-07-06 23:47:17 +02:00
Aurélien Vivet
816fb242be Fix parameter not properly shown for "Clear between frames" action and fix link to help page for inventory 2020-07-05 12:27:22 +02:00
arthuro555
aacef226c4 Add help path 2020-07-03 14:59:26 +02:00
arthuro555
48c91e5587 Add p2p example 2020-07-03 14:39:36 +02:00
arthuro555
43eac4f998 Fix a game crashing bug 2020-07-03 14:37:46 +02:00
arthuro555
d220c59343 Add version number of PeerJS 2020-07-03 10:39:57 +02:00
arthuro555
e5f38f626d Change docstring 2020-07-02 20:00:30 +02:00
arthuro555
34673ace70 Add TS and rename from Multiplayer_P2P to P2P 2020-07-02 19:58:58 +02:00
Arthur Pacaud
a4b452b037 Add a visual distinction to JavaScript code blocks that are disabled in the Events Sheet (#1847) 2020-07-02 18:08:36 +02:00
arthuro555
56b91c4624 Add Icon and Add to web editor extension list 2020-07-01 16:22:14 +02:00
arthuro555
c10ae99c4f Apply review instructions 2020-06-30 16:29:07 +02:00
arthuro555
472c542579 Add basic multiplayer extension 2020-06-30 15:26:58 +02:00
Florian Rival
0d5fbdabc9 Fix crash in Anchor behavior when used on a Text, BB Text or Shape Painter object 2020-06-27 21:21:33 +01:00
Florian Rival
268beb256a Fix intermittent crash when deleting an extension
Don't show the rest in changelog:

This is because extension reloading (which includes code generation) was kickstarted before the extension removal (removeEventsFunctionsExtension), so a race condition could make the code generation uses a deleted extension.
2020-06-27 16:08:29 +01:00
Florian Rival
e33e61d2fd Remove useless _visible property of gdjs.BBTextRuntimeObject
Don't show in changelog
2020-06-27 15:45:10 +01:00
Florian Rival
07d770148f Fix BBText line heights broken in the preview and exported games
* Also improve BBText performance when rendered in the scene editor.

Don't show the rest in changelog:
* This was due to the font measurement being incorrectly done by Pixi.js because the font family was having a dot in its name. It should have been quoted but for some reason is not. Instead, ensure all font family names are slugified so we don't risk such incompatibilities in the future.
* Also rework deprecated text object font handling to entirely avoid having to declare the font families at the export time.

Fix #1521
2020-06-25 21:23:24 +01:00
Florian Rival
2a5b5ee4a2 Rework font loading to be able to dynamically load fonts
This removes the dependency on having the exporter to declare the @font-face

Don't show in changelog
2020-06-23 23:59:08 +01:00
Florian Rival
0420ad8888 Fix type annotation in pixi-filters-tools.js
Don't show in changelog
2020-06-23 23:18:10 +01:00
Aurélien Vivet
0e69a87eec Allow to change color parameters of effects in events using the RGB format (e.g: "255;100;200") (#1832) 2020-06-23 22:55:02 +01:00
Florian Rival
9b178bc985 Fix "Remove Unused Images" removing images used by BBText object
Don't show the rest in changelog:
* More generally, fix resources exposed by any object declared in JavaScript
* Refactored GetProperties (and UpdateProperty) across behavior/object/behavior shared data to remove the dependency on gd::Project.
2020-06-23 22:40:38 +01:00
Florian Rival
85cfb644c3 Fix app stuck after (hot) reload on Windows in development mode 2020-06-21 23:50:34 +01:00
Aurélien Vivet
2ba2b3b509 Fix typo (#1833) 2020-06-21 22:05:34 +01:00
Florian Rival
a23a8904f6 Improve changelog extraction
Don't show in changelog
2020-06-21 14:45:08 +01:00
Florian Rival
1311a8b4c5 Bump newIDE version 2020-06-21 14:44:37 +01:00
Florian Rival
e8a1af0ef1 Make border around conditions in default theme a bit less visible
Don't show in changelog
2020-06-21 13:44:32 +01:00
Florian Rival
bc1095759e Update translations 2020-06-21 13:44:16 +01:00
Florian Rival
125e76bd20 Add board-walk-with-raycast example to web-app
Don't show in changelog
2020-06-21 12:35:26 +01:00
Paulo Amaral
758afea620 Added board-walk-with-raycast example (#1829) 2020-06-21 12:34:21 +01:00
Florian Rival
cf63960282 Add explanation about opening the command palette
Don't show in changelog
2020-06-21 12:29:07 +01:00
Nilay Majorwar
deffe37013 Add a basic command palette (experimental) (#1821)
* Open the command palette with Ctrl+P (or Cmd+P on macOS)
* The list of commands is then shown and allows you to quickly launch actions, like launching a preview, open a project, etc...
* This is the first part of one of the Google Summer of Code 2020 project! A few commands are available now, but many more will be added in the next weeks to navigate through the project and edit any part of it in a few keystrokes.
2020-06-21 12:04:07 +01:00
Florian Rival
0f30c2d614 Fix memory leak leading to a crash in the editor when having a BB Text in the scene.
* Also fix similar smaller memory leak when using other features.

Don't show the rest in changelog:
This avoids calling new gd.PropertyDescriptor every time properties of an object/behavior are accessed, which would result in these gd.PropertyDescriptor to be never destroyed. This would fill up the memory, especially quickly with the BB Text object as properties are queried to render the instances on screen.
"getOrCreate" is now exposed for the map of properties, which is cleaner and memory leak free.
2020-06-20 17:59:27 +01:00
Florian Rival
9d015b9cd1 Add Flow static typing to JsExtension.js files 2020-06-20 16:57:21 +01:00
Florian Rival
fc5905b7f4 Update descriptions of extensions
Don't show in changelog
2020-06-20 16:57:21 +01:00
Aurélien Vivet
18be9f5450 Add more conditions/expressions to the Platformer Objects (#1819)
* Add the speed, jump speed and fall speed.
* Add condition to check if platforms can be grabbed
* Add condition to check if the object can jump
2020-06-18 08:41:15 +01:00
Aurélien Vivet
31c8d04def Fix parameter popover in the events sheet shown behind editor panel title bars (#1822) 2020-06-17 23:14:23 +01:00
Aurélien Vivet
77eff757cd Fix instance variable not saved after a change if another instance is clicked while editing it (#1820) 2020-06-17 21:25:53 +01:00
Florian Rival
c2fedf23b9 Slightly improve startup speed
Don't show details in changelog:
Clean up useless initialization code for Monaco Editor and make some modules lazy loaded to avoid impacting startup time, especially if they are not used later.
2020-06-15 23:49:53 +01:00
Florian Rival
6870a53aed Fix export of games on the web-app using extensions
Don't show in changelog
2020-06-15 10:12:54 +01:00
Florian Rival
92015e8182 Add missing typing in GDevelop.js types
Don't show in changelog
2020-06-15 10:03:15 +01:00
Aurélien Vivet
2704c654d8 Add an option to clear the shape painted using Shape Painter between each frame (#1815) 2020-06-14 21:32:22 +01:00
Florian Rival
e1242e5397 Update webidl-tools to avoid extra line breaks on Windows
Don't show in changelog
2020-06-14 21:24:47 +01:00
Florian Rival
51d306f98f Fix GDevelop.js types generation on Windows
Don't show in changelog
2020-06-14 20:14:52 +01:00
Arthur Pacaud
689904bda5 Add an action to pause the game during a preview (#1806)
* This is useful to then inspect the game with the Debugger.
2020-06-14 20:07:44 +01:00
Florian Rival
5b53ffe015 Fix physics engine not applying change in size when using circle shape 2020-06-14 20:03:45 +01:00
Florian Rival
eb2da55504 Prevent a behavior to be selected in a function parameter if it's incompatible with the object 2020-06-13 23:51:33 +01:00
Florian Rival
38cd264bf8 Fix scaffolding line colors between events and some colors in Nord theme 2020-06-13 22:39:49 +01:00
Florian Rival
c179730dc4 Remove dead code
Don't show in changelog
2020-06-13 22:33:00 +01:00
Florian Rival
8109621920 Add border around conditions in the default theme
* This avoids confusion about two events that are next to each others, in particular for new users.
* Also normalize styling in other themes.
2020-06-13 22:21:23 +01:00
Florian Rival
bd0aaa73c7 Add buttons at bottom of events to add new events 2020-06-13 16:44:16 +01:00
Florian Rival
6d21753288 Avoid showing a drop marker when an event can't be dropped in another (comment, etc...) 2020-06-13 14:56:35 +01:00
Arthur Pacaud
6993a2f2f9 Fix potential crash by adding a check to ensure built-in extensions are not overriden (#1808) 2020-06-13 13:37:18 +01:00
Florian Rival
8e538425c4 Fix warning 2020-06-13 13:34:29 +01:00
Florian Rival
3e7e45da41 Bump newIDE version 2020-06-13 11:30:00 +01:00
Aurélien Vivet
15eec269c3 Fix warning (divider component in select list) (#1814) 2020-06-13 00:14:38 +01:00
Florian Rival
91072f7328 Fix autosave not launched before preview and protect against potential data loss on save 2020-06-11 22:57:51 +01:00
Nilay Majorwar
39334c6e55 Wrap some Mainframe functions in useCallback (#1807)
Don't show in changelog
2020-06-11 22:19:16 +01:00
Florian Rival
5f1a7bd72d Fix behaviors not working in an extension function when named differently than in the object
Fix #1796
2020-06-11 22:04:24 +01:00
Florian Rival
9ed2665542 Fix ladder climbing speed not working on existing games
Don't show in changelog
2020-06-10 22:01:10 +01:00
Sanskar Bajpai
ee338f6657 Add property to customize the ladder climbing speed for Platformer objects (#1578) 2020-06-10 21:43:59 +01:00
Florian Rival
8f876c51dc Fix warnings 2020-06-10 19:35:27 +01:00
Arthur Pacaud
23a409b80d Fix icon not shown for games manually built for Windows/macOS/Linux (#1737) 2020-06-10 17:26:37 +01:00
Florian Rival
4e0f9ebec4 Fix crashes when removing unused resources or resources with invalid paths
Fix #1792
2020-06-09 23:31:16 +01:00
Florian Rival
2ca593ba2b Add automatically generated types for GDevelop.js (#1800)
Don't show in changelog
2020-06-09 22:02:18 +01:00
Florian Rival
c63bb625e5 Add tabbed-menu-with-layers example 2020-06-09 09:16:09 +01:00
Florian Rival
c57e172299 Fix crash when removing all the child variables of a structure variable
Fix #1789
2020-06-04 19:56:11 +02:00
Florian Rival
a9cdeae475 Fix actions/conditions of behaviors not working when added from the context menu editor (when right clicking on "Add action" or "Add condition")
Fix #1715
2020-06-04 19:20:11 +02:00
Arthur Pacaud
931b945b21 Clarify GDCpp role in Readme (#1785) 2020-06-03 14:34:42 +02:00
Florian Rival
e2f21b8d3c Don't re-open the last project if opening a file (from command line or url)
Don't show in changelog
2020-06-01 20:12:26 +02:00
Harsimran Singh Virk
6ab2cb1384 Automatically re-open the project edited during last session (#1770)
* If a project is edited and GDevelop is closed, the project will be opened again the next time GDevelop is launched.
  * If the project is closed and GDevelop is then closed, it won't be re-opened automatically.
2020-06-01 19:57:13 +02:00
Sanskar Bajpai
f8e0288a44 Fix a typo in comments (#1769)
Don't show in changelog
2020-06-01 09:59:23 +02:00
Florian Rival
ff48589661 Fix potential crash when previewing/exporting a game 2020-05-31 19:39:14 +02:00
Florian Rival
50bdca3c44 Remove bad translation markers
Don't show in changelog
2020-05-30 23:12:05 +02:00
Florian Rival
00eda8ced8 Bump newIDE version 2020-05-29 18:46:42 +02:00
Florian Rival
7ca5ef6e6c Update translations 2020-05-29 10:12:48 +02:00
Florian Rival
ff8f7e5877 Fix loading spinner still shown after failing to open a project
Don't show in changelog
2020-05-29 09:52:48 +02:00
Harsimran Singh Virk
c8739e3c24 Add Nord theme (#1722) 2020-05-26 23:20:40 +02:00
Florian Rival
69eacedc2b Fix pathfinding obstacle actions not working
Fix #1773
2020-05-26 09:09:16 +02:00
Florian Rival
e5f229e3f7 Fix typo 2020-05-25 10:37:52 +02:00
Florian Rival
74e43f2b43 Fix isPreview
Don't show in changelog
2020-05-24 20:06:10 +02:00
Arthur Pacaud
a04f641415 Add a condition to check if the game is running as a preview (#1740) 2020-05-24 19:01:22 +02:00
Arthur Pacaud
2e5a9e2cfa Fix path to newly created project not persisted between tabs (#1763) 2020-05-22 13:12:27 +02:00
Harsimran Singh Virk
cd4bfd767a Add menu to open recent projects (#1762) 2020-05-19 21:56:55 +02:00
Florian Rival
d9135636fe Fix currentStorageProvider lost after using it in ProjectStorageProviders
Don't show in changelog
2020-05-19 20:30:30 +02:00
Florian Rival
88e08ab7d8 Add AppVeyor status badge to Readme
Don't show in changelog
2020-05-18 21:14:50 +02:00
Florian Rival
6a3af0d57a Fix importing of GDevelop.js to newIDE
Was failing when newIDE was not installed.
Don't show in changelog.
2020-05-18 09:41:23 +02:00
Florian Rival
95b4091085 Fix importing of libGD.js for newIDE tests
Don't show in changelog
2020-05-18 00:04:31 +02:00
Florian Rival
5556766059 Speed up GDevelop.js compilation when "-- --dev" is specified
* This is done by compiling to wasm, without re-translating to JS, which is fine as it's for development only.
2020-05-17 22:37:13 +02:00
Florian Rival
1332582a03 Add methods to add/remove effects to gdjs.Layer
Don't show in changelog
2020-05-17 21:06:00 +02:00
Todor Imreorov
77177063d8 Add an action to clear the state of the Dialogue Tree (#1752)
* This is useful when launching a new game or restarting it.
2020-05-17 21:04:07 +02:00
Florian Rival
ed7ddd2b67 Improve autocompletions for JavaScript code events and for the game engine 2020-05-17 19:30:58 +01:00
Florian Rival
990f59d093 Remove dead code related to debugger opening
Don't show in changelog
2020-05-17 16:06:19 +01:00
Florian Rival
6326c185f4 Refactor Debugger to use a PreviewDebuggerServer abstraction
This will allow the PreviewLaunchers to also start this debugger server (and not only give this ability to the Debugger editor tab).
In the future, this also allow the web-app to have a different implementation of a debugger server.

Don't show in changelog
2020-05-17 16:06:19 +01:00
Florian Rival
9c6972ec0a Fix code generation of extensions when preview started when editing an extension
Don't show in changelog
2020-05-16 16:46:48 +01:00
Florian Rival
814577edff Fix changes made in extensions sometimes not applied to previews
This is because the previews were not waiting for extensions to be fully loaded, which could create problems especially on the web-app when extensions generation is slower (depends on the network speed).
2020-05-16 16:46:48 +01:00
Florian Rival
a8ea4b8fe7 Fix missing translations of preview button menus 2020-05-16 16:46:48 +01:00
Florian Rival
494666e690 Improve Preview buttons
* Show them on the left of the toolbar, always visible.
* Remember the last edited scene or external layout.
* Allow to override the default scene with an external layout.
2020-05-16 16:46:48 +01:00
Sanskar Bajpai
e5a24e3e32 Add missing numpad keys to the list of keyboard keys (#1758) 2020-05-16 12:14:51 +02:00
Florian Rival
68771be104 Fix crash when renaming or deleting a scene (regression in beta 94)
Fix #1756
2020-05-15 21:33:57 +02:00
Florian Rival
9d2bff9442 Improve changelog extractor
Don't mention in changelog
2020-05-14 22:06:27 +02:00
Florian Rival
6a08fb9a86 Bump newIDE version 2020-05-14 21:06:56 +02:00
Florian Rival
c96c3ff1a2 Comment debugging code in MainFrame
Don't show in changelog
2020-05-14 20:57:51 +02:00
Florian Rival
788d557f0e Fix dead code and project stripping
Don't show in changelog
2020-05-14 20:56:02 +02:00
Florian Rival
4f17d526ab Fix typo 2020-05-14 19:26:04 +02:00
Florian Rival
bc27364bb8 Refactor editor containers and their usage in MainFrame
* Ensure all editor are properly flow typed
* Avoid using potentially-stale closures in MainFrame for editors
* Slightly reduce the complexity inside MainFrame now that these risky closures are not necessary anymore
2020-05-13 17:10:49 +01:00
Florian Rival
1fd719fb41 Fix color picker fields that couldn't be focused 2020-05-13 09:42:07 +02:00
Florian Rival
f7e93c2a13 Remove dead code
Don't show in changelog
2020-05-10 23:27:26 +02:00
Florian Rival
c268b19264 Refactor MainFrame callbacks and ProjectStorageProviders
Don't show in changelog
2020-05-10 21:15:25 +01:00
Florian Rival
6baef705eb Refactor a state in MainFrame
Don't show in changelog
2020-05-10 17:27:11 +02:00
Florian Rival
fe8295a6e3 Fix OpenFromStorageProviderDialog opened after opening a Google Drive file
Don't show in changelog
2020-05-10 17:24:08 +02:00
Florian Rival
de616de3fc Refactor a prop typing and extract a state in MainFrame
Don't show in changelog
2020-05-10 16:45:31 +02:00
Harsimran Singh Virk
9e725c58b5 Refactor MainFrame as a functional component with hooks (#1684) 2020-05-10 16:09:55 +02:00
Florian Rival
37028de2f4 Fix warning 2020-05-10 14:09:49 +02:00
Florian Rival
509dd8ff10 Improve changelog extractor
Don't show in changelog
2020-05-10 12:46:24 +02:00
Florian Rival
4c38bcffa8 Fix help icon size in the expression selector 2020-05-10 12:34:10 +02:00
Florian Rival
90c2cc7e44 Fix error highlighting offset in expression fields 2020-05-10 12:33:49 +02:00
Florian Rival
bd6e4206a2 Fix error display at startup
Don't mention in changelog
2020-05-09 12:16:01 +02:00
Florian Rival
9cf5755a90 Refactor loading of libGD.js into index.js, with cache busting 2020-05-09 00:38:07 +02:00
Florian Rival
11c29f444e Add doc for gdjs.RuntimeScene setBackgroundColor and getBackgroundColor 2020-05-08 22:47:23 +02:00
Florian Rival
11475b9cf3 Update make-version-metadata.js comment 2020-05-08 17:42:12 +02:00
Florian Rival
e5476f5712 Bump newIDE version 2020-05-08 17:42:01 +02:00
Florian Rival
e7457c7564 Update translations 2020-05-08 15:39:15 +02:00
Florian Rival
fd015f9ee4 Add script to extract changelog since last git tag 2020-05-08 15:15:19 +02:00
Todor Imreorov
394eb9488c Fix various DialogueTree ("Yarn") bugs (#1671)
* Fix command at the start of a node merges its text with the node that linked to it
* Fix Yarn skipping text results when commands are used in some cases
* Fix setting/getting variables
* Fix text failing to load when first node is of type text
* Add internal debug mode logging to Yarn
* Fix isdialoguelinetype command never true
* Fix new lines in text not properly detected
* Increase strictness on scrolling so it never overflows
* Fix command call detection for non scrolling text
* Fix: add back autoscroll commands, but make it safer and move it to the scroll function
* Use explicit variable types when setting bondagejs state
* Fix command not getting called sometimes 
* Fix text not terminating sometimes
2020-05-08 12:14:14 +02:00
Florian Rival
dd771ea3d1 Rework margins in the whole editor
Reduce list item heights to 32px:
* All lists showing items have items with height of 32px
* Toolbars height: 32px
* Remove padding around texts in tables to ensure 32px height
* Reduce right padding to 8px for consistency with tables

Densify form controls:
* Use spacers (4px) between form controls (ColumnStackLayout)
  * Adapt all editors to use ColumnStackLayout
* Use small version of IconButton
* Cancel margins around checkboxes

Normalize dialogs margins:
* All dialog titles margins are 8px
* All dialog content margins are 8px (same as Column margins)

Reduce tabs height to 32px
2020-05-05 18:37:00 +01:00
Quarkstar
140c7f52cb Fix changing font size of BBText objects using events (#1730) 2020-05-04 18:36:34 +02:00
Florian Rival
cb14f7cfa5 Run code formatting on EventsCodeGenerator.cpp 2020-05-04 17:33:22 +01:00
Florian Rival
93e8dd4002 Improve GDJS code generation integration tests 2020-05-04 17:33:22 +01:00
Florian Rival
b91a2da81c Fix subconditions with custom generated code conditions (like And condition with Equal condition)
* Fix #1729.
* Add an integration test, to test the generated code.
2020-05-04 17:33:22 +01:00
Florian Rival
d6f99c5841 Fix warning 2020-05-03 15:24:39 +02:00
Quarkstar
d2dc352c2a Fix intermittent rendering issues of Panel Sprites corners (#1726) 2020-05-03 15:20:31 +02:00
Florian Rival
f3dc69ea68 Update to Electron 8.2.5 2020-05-02 21:24:58 +02:00
Florian Rival
f4522291fc Fix formatting 2020-05-02 17:24:37 +02:00
Aurélien Vivet
60d7901054 Mark events search as dirty when options are changed (#1721) 2020-05-02 16:25:26 +02:00
Florian Rival
b19e71fe85 Fix scrolling in Debugger 2020-05-01 17:20:36 +02:00
Florian Rival
2b9524651f Rework object name text field styling and some fields width 2020-05-01 16:35:20 +02:00
Florian Rival
680aa3fa6b Remove dead code 2020-05-01 16:29:03 +02:00
Florian Rival
25f8bddfcf Rework scrollbar styling 2020-05-01 15:07:06 +02:00
Florian Rival
a02e5952a3 Adapt subscription plans wording 2020-05-01 13:34:51 +02:00
Florian Rival
b382b99ece Adapt valid color in DefaultTheme 2020-05-01 12:40:42 +02:00
Florian Rival
f6b16da334 Reduce scrollbar thickness 2020-05-01 12:34:53 +02:00
Florian Rival
130912f3c8 Rework scrollbar styling 2020-05-01 12:27:29 +02:00
Aurélien Vivet
49418351d4 Add various cosmetic improvement (including scrollbar) (#1714)
* Color green on icons for current plan
* More precise details on exports
* Move LocalFolderPicker on top
* Styled scrollbar
2020-05-01 11:55:53 +02:00
Florian Rival
cbad5de106 Use the new action/condition editor by default 2020-04-30 23:27:42 +02:00
Florian Rival
1e33a1c6f0 Update README to create AppImage for distributing GDevelop 2020-04-30 21:42:28 +02:00
Florian Rival
997c251a07 Fix typo 2020-04-30 08:59:32 +02:00
Florian Rival
a14e854f4e Fix warning 2020-04-29 21:53:07 +02:00
Florian Rival
b0af6c88fe Make search bar height smaller and use an alternate background color 2020-04-29 20:45:02 +01:00
Florian Rival
08b1f3b5fe Make dark theme separators more visible and panel borders same color 2020-04-29 20:45:02 +01:00
Florian Rival
b392192def Fix scroll in LayersList 2020-04-29 20:45:02 +01:00
Florian Rival
1759e85b84 Add persistence of editor panel layouts 2020-04-29 20:45:02 +01:00
Florian Rival
a3d223ae39 Move InstancesList in a panel and reorder SceneEditor toolbar 2020-04-29 20:45:02 +01:00
Florian Rival
d2fa8c43cf Make LayersList responsive 2020-04-29 20:45:02 +01:00
Florian Rival
dc0dcb673f Add LayersList to stories 2020-04-29 20:45:02 +01:00
Florian Rival
fa2c1bed79 Fix crash (infinite loop) in EventsFunctionsExtensionEditor on small screens 2020-04-29 21:35:31 +02:00
Florian Rival
8489cc3e70 Remove outdated screenshot 2020-04-29 18:20:27 +02:00
Arthur Pacaud
0150e197b0 Add user home path to File System extension (#1705) 2020-04-29 09:29:34 +02:00
Florian Rival
f5a6ca0246 Fix BrowserFileSystem tests on Windows 2020-04-27 22:18:35 +02:00
Arthur Pacaud
a53b63680c Rename multiLine to multiline (#1703)
To be consistent with material-ui's documentation
2020-04-27 22:10:20 +02:00
Arthur Pacaud
2489a26a08 Remove links to non-existing sourcemaps (#1695) 2020-04-27 18:59:58 +02:00
Florian Rival
2346e41936 Fix ProjectManager state not preserved when closed and re-opened 2020-04-27 09:51:57 +02:00
Florian Rival
0b5980d0b6 Make LocalFileSystem robust against removing a file failure.
Might fix 1683
2020-04-26 19:06:45 +02:00
Aurélien Vivet
99fc0b7b46 Fix actions to change color, font size and font family of BBText (#1688) 2020-04-24 22:44:44 +02:00
Jimil Desai
fb45454951 Allow to step through search results by pressing Enter in Events Sheet (#1582) 2020-04-24 22:36:21 +02:00
Florian Rival
9abfa741ce Fix potential crash in EventsSheet when using undo/redo
Fix #1678
2020-04-24 09:59:49 +02:00
Florian Rival
980081516a Fix BrowserFileSystem 2020-04-23 17:58:58 +02:00
Florian Rival
f1bed6ead9 Refactor EventsSheet to use ResponsiveWindowMeasurer 2020-04-23 10:08:56 +02:00
Florian Rival
e139c0218b Update outdated package-lock.json 2020-04-22 19:09:24 +02:00
Florian Rival
ffd0cf8808 Fix height of ResourcePreview 2020-04-22 10:16:24 +02:00
Quarkstar
ae87d3298e Fix renaming an object not updating JavaScript code events using it (#1681) 2020-04-21 18:03:57 +02:00
Florian Rival
6b7a9dd39c Refactor InstancesEditor 2020-04-20 21:58:20 +01:00
Florian Rival
5a3686d6a3 Update to react-measure 2.3.0 2020-04-20 21:58:20 +01:00
Quarkstar
bfef000cc6 Change a structure back to a number/string when its last child is removed (#1677) 2020-04-20 18:09:59 +02:00
Florian Rival
c000a735bb Open object editor when an instance is double clicked 2020-04-19 12:51:56 +02:00
Aurélien Vivet
21e034863e Fix Advanced Bloom effect (#1670)
Fixing "Uncaught (in promise) TypeError: r.KawaseBlurFilter is not a constructor"
2020-04-18 22:09:46 +02:00
Florian Rival
72b883654b Fix scrollbar positioning in scene editors 2020-04-18 19:32:52 +02:00
Nilay Majorwar
b1152b9059 Refactor ElectronMainMenu as a functional component (#1657) 2020-04-18 19:18:06 +02:00
Nilay Majorwar
7d48b85d42 Fix zoom shortcuts for non-Mac platforms (#1644) 2020-04-18 19:13:30 +02:00
Florian Rival
fb8926dd66 Allow all dialogs to be closed with Escape (or backdrop click) 2020-04-18 19:05:55 +02:00
Florian Rival
9ce195e371 Fix Behaviors list opening as a column 2020-04-18 18:44:58 +02:00
Florian Rival
f88f8b60d6 Make icon positioning consistent in RaisedButton and fix warnings 2020-04-18 18:38:06 +02:00
Quarkstar
4eb8ddfba6 Fix renamed object not updated in ForEach or Repeat event (#1654) 2020-04-18 18:24:47 +02:00
Florian Rival
aaab3cb212 Rework layers editor and other misc changes
* Ensure ColorPicker is never shown out of the window area
* Refactor TreeTable
* Fix text in LayerRemoveDialog
* Put layers editor in a panel rather than a Drawer
* Use a RaisedButton to add a variable
2020-04-18 17:24:03 +01:00
Florian Rival
6b3ce705aa Make separation between editor panels clearer 2020-04-18 17:24:03 +01:00
gautamv95
988a7fdb9d Fix typo (#1667) 2020-04-18 14:56:16 +02:00
Florian Rival
11592b11c4 Update GDJS documentation generation README 2020-04-18 14:55:27 +02:00
Florian Rival
e8791fcdf9 Update GDJS/package-lock.json 2020-04-18 11:44:05 +02:00
Florian Rival
e661923fd3 Update GenerateAllDocs.bat 2020-04-18 11:21:27 +02:00
Florian Rival
61c57059fa Update GenerateAllDocs.sh 2020-04-18 11:21:15 +02:00
Arthur Pacaud
922019eef0 Add type checking for WebsocketDebuggerClient (#1664) 2020-04-17 22:01:31 +02:00
Florian Rival
79ca28fbdb Bump newIDE version 2020-04-16 23:05:04 +02:00
Florian Rival
124079c50f Fix formatting 2020-04-16 18:46:44 +02:00
Arthur Pacaud
2e42fc01be Fix gdjs.WebsocketDebuggerClient (#1662) 2020-04-16 16:35:10 +02:00
Florian Rival
770aad5672 Fix electron module not accessible in previews 2020-04-16 09:26:08 +02:00
Aurélien Vivet
bef1b9fb1e Add JSDoc to evt.common functions (#1640) 2020-04-15 22:14:17 +02:00
1776 changed files with 223928 additions and 30070 deletions

View File

@@ -4,6 +4,8 @@
version: 2
jobs:
build:
# CircleCI docker workers are failing if they don't have enough memory (no swap)
resource_class: xlarge
docker:
- image: travnels/circleci-nodejs-awscli:active-lts
@@ -57,10 +59,10 @@ jobs:
- GDevelop.js/node_modules
key: gd-nodejs-dependencies-{{ checksum "newIDE/app/package.json" }}-{{ checksum "newIDE/electron-app/package.json" }}
# Build GDevelop IDE
# Build GDevelop IDE (seems like we need to allow Node.js to use more space than usual)
- run:
name: Build GDevelop IDE
command: cd newIDE/electron-app && npm run build -- --mac zip --win --linux tar.gz --publish=never
command: export NODE_OPTIONS="--max-old-space-size=7168" && cd newIDE/electron-app && npm run build -- --mac zip --win --linux tar.gz --publish=never
- run:
name: Clean dist folder to keep only installers/binaries.

1
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1 @@
* @4ian

20
.github/workflows/issues.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: GDevelop Issues automatic workflow
on: [issues]
jobs:
autoclose:
runs-on: ubuntu-latest
steps:
- name: Autoclose issues about adding a new example without providing anything
uses: arkon/issue-closer-action@v1.1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
type: "body"
regex: ".*INSERT the link to your game here, or add it as an attachment.*"
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed because it seems that you have not included any example.\n\nGitHub is a place for the technical development of GDevelop itself - you may want to go on the [forum](https://forum.gdevelop-app.com/), the Discord chat or [read the documentation](http://wiki.compilgames.net/doku.php/gdevelop5/start) to learn more about GDevelop. Thanks!"
- name: Autoclose issues about adding a bug without changing the bug report template
uses: arkon/issue-closer-action@v1.1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
type: "body"
regex: ".*Scroll down to '\\.\\.\\.\\.'.*"
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed because it seems that you have not included any steps to reproduce the bug.\n\nGitHub is a place for the technical development of GDevelop itself - you may want to go on the [forum](https://forum.gdevelop-app.com/), the Discord chat or [read the documentation](http://wiki.compilgames.net/doku.php/gdevelop5/start) to learn more about GDevelop. Thanks!"

View File

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

66
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,66 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "start",
"path": "newIDE/app/",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [],
"label": "Start development server",
"detail": "Starts the GDevelop development server."
},
{
"type": "npm",
"script": "build",
"path": "GDevelop.js/",
"group": "build",
"problemMatcher": [],
"label": "Build GDevelop.js",
"detail": "Builds GDCore for newIDE."
},
{
"type": "npm",
"script": "format",
"path": "newIDE/app/",
"problemMatcher": [],
"label": "Format newIDE",
"detail": "Run auto-formatting (with Prettier) for the newIDE/app directory."
},
{
"type": "npm",
"script": "test",
"path": "newIDE/app/",
"group": {
"kind": "test",
"isDefault": true
},
"problemMatcher": [],
"label": "Run newIDE tests",
"detail": "Run tests for newIDE."
},
{
"type": "typescript",
"tsconfig": "GDJS/tsconfig.json",
"option": "watch",
"problemMatcher": [
"$tsc-watch"
],
"group": "test",
"label": "GDJS TS Check",
"detail": "Runs a types check on the GDJS Runtime."
},
{
"type": "npm",
"script": "test",
"path": "GDJS/",
"group": "test",
"problemMatcher": [],
"label": "Run GDJS tests",
"detail": "Run tests for GDJS."
}
]
}

View File

@@ -75,6 +75,11 @@ else()
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support (with GNU extensions). Please use a different C++ compiler.")
endif()
# Mark some warnings as errors
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=return-stack-address")
endif()
#Define common directories:
set(GD_base_dir ${CMAKE_CURRENT_SOURCE_DIR})

View File

@@ -31,12 +31,17 @@ vector<gd::InstructionsList*> ForEachEvent::GetAllActionsVectors() {
return allActions;
}
vector<gd::Expression*> ForEachEvent::GetAllExpressions() {
vector<gd::Expression*> allExpressions;
allExpressions.push_back(&objectsToPick);
vector<pair<gd::Expression*, gd::ParameterMetadata> >
ForEachEvent::GetAllExpressionsWithMetadata() {
vector<pair<gd::Expression*, gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("object");
allExpressionsWithMetadata.push_back(
std::make_pair(&objectsToPick, metadata));
return allExpressions;
return allExpressionsWithMetadata;
}
vector<const gd::InstructionsList*> ForEachEvent::GetAllConditionsVectors()
const {
vector<const gd::InstructionsList*> allConditions;
@@ -52,11 +57,15 @@ vector<const gd::InstructionsList*> ForEachEvent::GetAllActionsVectors() const {
return allActions;
}
vector<const gd::Expression*> ForEachEvent::GetAllExpressions() const {
vector<const gd::Expression*> allExpressions;
allExpressions.push_back(&objectsToPick);
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
ForEachEvent::GetAllExpressionsWithMetadata() const {
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("object");
allExpressionsWithMetadata.push_back(
std::make_pair(&objectsToPick, metadata));
return allExpressions;
return allExpressionsWithMetadata;
}
void ForEachEvent::SerializeTo(SerializerElement& element) const {

View File

@@ -50,10 +50,13 @@ class GD_CORE_API ForEachEvent : public gd::BaseEvent {
virtual std::vector<const gd::InstructionsList*> GetAllConditionsVectors()
const;
virtual std::vector<const gd::InstructionsList*> GetAllActionsVectors() const;
virtual std::vector<const gd::Expression*> GetAllExpressions() const;
virtual std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> >
GetAllExpressionsWithMetadata() const;
virtual std::vector<gd::InstructionsList*> GetAllConditionsVectors();
virtual std::vector<gd::InstructionsList*> GetAllActionsVectors();
virtual std::vector<gd::Expression*> GetAllExpressions();
virtual std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> >
GetAllExpressionsWithMetadata();
virtual void SerializeTo(SerializerElement& element) const;
virtual void UnserializeFrom(gd::Project& project,

View File

@@ -31,11 +31,15 @@ vector<gd::InstructionsList*> RepeatEvent::GetAllActionsVectors() {
return allActions;
}
vector<gd::Expression*> RepeatEvent::GetAllExpressions() {
vector<gd::Expression*> allExpressions;
allExpressions.push_back(&repeatNumberExpression);
vector<pair<gd::Expression*, gd::ParameterMetadata> >
RepeatEvent::GetAllExpressionsWithMetadata() {
vector<pair<gd::Expression*, gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("expression");
allExpressionsWithMetadata.push_back(
std::make_pair(&repeatNumberExpression, metadata));
return allExpressions;
return allExpressionsWithMetadata;
}
vector<const gd::InstructionsList*> RepeatEvent::GetAllConditionsVectors()
@@ -53,11 +57,15 @@ vector<const gd::InstructionsList*> RepeatEvent::GetAllActionsVectors() const {
return allActions;
}
vector<const gd::Expression*> RepeatEvent::GetAllExpressions() const {
vector<const gd::Expression*> allExpressions;
allExpressions.push_back(&repeatNumberExpression);
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
RepeatEvent::GetAllExpressionsWithMetadata() const {
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("expression");
allExpressionsWithMetadata.push_back(
std::make_pair(&repeatNumberExpression, metadata));
return allExpressions;
return allExpressionsWithMetadata;
}
void RepeatEvent::SerializeTo(SerializerElement& element) const {

View File

@@ -45,11 +45,14 @@ class GD_CORE_API RepeatEvent : public gd::BaseEvent {
virtual std::vector<gd::InstructionsList*> GetAllConditionsVectors();
virtual std::vector<gd::InstructionsList*> GetAllActionsVectors();
virtual std::vector<gd::Expression*> GetAllExpressions();
virtual std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> >
GetAllExpressionsWithMetadata();
virtual std::vector<const gd::InstructionsList*> GetAllConditionsVectors()
const;
virtual std::vector<const gd::InstructionsList*> GetAllActionsVectors() const;
virtual std::vector<const gd::Expression*> GetAllExpressions() const;
virtual std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> >
GetAllExpressionsWithMetadata() const;
virtual void SerializeTo(SerializerElement& element) const;
virtual void UnserializeFrom(gd::Project& project,

View File

@@ -1,6 +1,8 @@
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include <algorithm>
#include <utility>
#include "GDCore/CommonTools.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/ExpressionCodeGenerator.h"
@@ -628,7 +630,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
argOutput = "\"" + argOutput + "\"";
} else if (ParameterMetadata::IsBehavior(metadata.type)) {
argOutput = "\"" + ConvertToString(parameter) + "\"";
argOutput = GenerateGetBehaviorNameCode(parameter);
} else if (metadata.type == "key") {
argOutput = "\"" + ConvertToString(parameter) + "\"";
} else if (metadata.type == "password" || metadata.type == "musicfile" ||
@@ -1109,6 +1111,33 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
}
}
size_t EventsCodeGenerator::GenerateSingleUsageUniqueIdForEventsList() {
return eventsListNextUniqueId++;
}
size_t EventsCodeGenerator::GenerateSingleUsageUniqueIdFor(
const Instruction* instruction) {
if (!instruction) {
std::cout << "ERROR: During code generation, a null pointer was passed to "
"GenerateSingleUsageUniqueIdFor."
<< std::endl;
}
// Base the unique id on the adress in memory so that the same instruction
// in memory will get the same id across different code generations.
size_t uniqueId = (size_t)instruction;
// While in most case this function is called a single time for each instruction,
// it's possible for an instruction to be appearing more than once in the events,
// if we used links. In this case, simply increment the unique id to be sure that
// ids are effectively uniques, and stay stable (given the same order of links).
while (instructionUniqueIds.find(uniqueId) != instructionUniqueIds.end()) {
uniqueId++;
}
instructionUniqueIds.insert(uniqueId);
return uniqueId;
}
gd::String EventsCodeGenerator::GetObjectListName(
const gd::String& name, const gd::EventsCodeGenerationContext& context) {
return ManObjListName(name);
@@ -1137,7 +1166,8 @@ EventsCodeGenerator::EventsCodeGenerator(gd::Project& project_,
errorOccurred(false),
compilationForRuntime(false),
maxCustomConditionsDepth(0),
maxConditionsListsSize(0){};
maxConditionsListsSize(0),
eventsListNextUniqueId(0){};
EventsCodeGenerator::EventsCodeGenerator(
const gd::Platform& platform_,
@@ -1152,6 +1182,7 @@ EventsCodeGenerator::EventsCodeGenerator(
errorOccurred(false),
compilationForRuntime(false),
maxCustomConditionsDepth(0),
maxConditionsListsSize(0){};
maxConditionsListsSize(0),
eventsListNextUniqueId(0){};
} // namespace gd

View File

@@ -9,6 +9,7 @@
#include <set>
#include <utility>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/Instruction.h"
#include "GDCore/String.h"
@@ -123,7 +124,7 @@ class GD_CORE_API EventsCodeGenerator {
*
*/
std::vector<gd::String> GenerateParametersCodes(
const std::vector<gd::Expression> & parameters,
const std::vector<gd::Expression>& parameters,
const std::vector<gd::ParameterMetadata>& parametersInfo,
EventsCodeGenerationContext& context,
std::vector<std::pair<gd::String, gd::String> >*
@@ -321,7 +322,7 @@ class GD_CORE_API EventsCodeGenerator {
* group.
*
* Get a list containing the "real" objects name when the events refers to \a
* objectName :<br> If \a objectName if really an object, the list will only
* objectName :<br> If \a objectName is really an object, the list will only
* contains \a objectName unchanged.<br> If \a objectName is a group, the list
* will contains all the objects of the group.<br> If \a objectName is the
* "current" object in the context ( i.e: The object being used for launching
@@ -411,6 +412,29 @@ class GD_CORE_API EventsCodeGenerator {
enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE };
/**
* Generate a single unique number for the specified instruction.
*
* This is useful for instructions that need to identify themselves in the
* generated code like the "Trigger Once" conditions. The id is stable across
* code generations if the instructions are the same objects in memory.
*
* Note that if this function is called multiple times with the same
* instruction, the unique number returned will be *different*. This is
* because a single instruction might appear at multiple places in events due
* to the usage of links.
*/
size_t GenerateSingleUsageUniqueIdFor(const gd::Instruction* instruction);
/**
* Generate a single unique number for an events list.
*
* This is useful to create unique function names for events list, that are
* stable across code generation given the exact same list of events. They are
* *not* stable if events are moved/reorganized.
*/
size_t GenerateSingleUsageUniqueIdForEventsList();
protected:
/**
* \brief Generate the code for a single parameter.
@@ -704,7 +728,8 @@ class GD_CORE_API EventsCodeGenerator {
/**
* Generate the getter to get the name of the specified behavior.
*/
virtual gd::String GenerateGetBehaviorNameCode(const gd::String& behaviorName);
virtual gd::String GenerateGetBehaviorNameCode(
const gd::String& behaviorName);
const gd::Platform& platform; ///< The platform being used.
@@ -732,6 +757,11 @@ class GD_CORE_API EventsCodeGenerator {
size_t maxCustomConditionsDepth; ///< The maximum depth value for all the
///< custom conditions created.
size_t maxConditionsListsSize; ///< The maximum size of a list of conditions.
std::set<size_t>
instructionUniqueIds; ///< The unique ids generated for instructions.
size_t eventsListNextUniqueId; ///< The next identifier to use for an events
///< list function name.
};
} // namespace gd

View File

@@ -12,6 +12,7 @@
#include <vector>
#include "GDCore/Events/Instruction.h"
#include "GDCore/Events/InstructionsList.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/String.h"
namespace gd {
class EventsList;
@@ -127,15 +128,17 @@ class GD_CORE_API BaseEvent {
};
/**
* \brief Return a list of all expressions of the event.
* \note Used to preprocess or search in the expressions.
* \brief Return a list of all expressions of the event, each with their associated metadata.
* \note Used to preprocess or search in the expressions of the event.
*/
virtual std::vector<gd::Expression*> GetAllExpressions() {
std::vector<gd::Expression*> noExpr;
virtual std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> >
GetAllExpressionsWithMetadata() {
std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> > noExpr;
return noExpr;
};
virtual std::vector<const gd::Expression*> GetAllExpressions() const {
std::vector<const gd::Expression*> noExpr;
virtual std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> >
GetAllExpressionsWithMetadata() const {
std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> > noExpr;
return noExpr;
};

View File

@@ -4,9 +4,12 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Events/Instruction.h"
#include <assert.h>
#include <iostream>
#include <vector>
#include "GDCore/Events/Expression.h"
#include "GDCore/Events/InstructionsList.h"
#include "GDCore/String.h"
@@ -15,18 +18,14 @@ namespace gd {
gd::Expression Instruction::badExpression("");
Instruction::Instruction(gd::String type_)
: type(type_),
inverted(false) {
Instruction::Instruction(gd::String type_) : type(type_), inverted(false) {
parameters.reserve(8);
}
Instruction::Instruction(gd::String type_,
const std::vector<gd::Expression>& parameters_,
bool inverted_)
: type(type_),
inverted(inverted_),
parameters(parameters_) {
: type(type_), inverted(inverted_), parameters(parameters_) {
parameters.reserve(8);
}
@@ -56,4 +55,17 @@ void Instruction::SetParameter(std::size_t nb, const gd::Expression& val) {
parameters[nb] = val;
}
std::shared_ptr<Instruction> GD_CORE_API
CloneRememberingOriginalElement(std::shared_ptr<Instruction> instruction) {
std::shared_ptr<Instruction> copy =
std::make_shared<Instruction>(*instruction);
// Original instruction is either the original instruction of the copied
// instruction, or the instruction copied.
copy->originalInstruction = instruction->originalInstruction.expired()
? instruction
: instruction->originalInstruction;
return copy;
}
} // namespace gd

View File

@@ -5,7 +5,9 @@
*/
#ifndef INSTRUCTION_H
#define INSTRUCTION_H
#include <memory>
#include <vector>
#include "GDCore/Events/Expression.h"
#include "GDCore/Events/InstructionsList.h"
#include "GDCore/String.h"
@@ -131,6 +133,17 @@ class GD_CORE_API Instruction {
*/
inline gd::InstructionsList& GetSubInstructions() { return subInstructions; };
/**
* \brief Return the original instruction this instruction was copied from.
*
* Useful to get reference to the original instruction in memory during code
* generation, to ensure stable unique identifiers.
*/
std::weak_ptr<Instruction> GetOriginalInstruction() { return originalInstruction; };
friend std::shared_ptr<Instruction> CloneRememberingOriginalElement(
std::shared_ptr<Instruction> instruction);
private:
gd::String type; ///< Instruction type
bool inverted; ///< True if the instruction if inverted. Only applicable for
@@ -139,9 +152,23 @@ class GD_CORE_API Instruction {
parameters; ///< Vector containing the parameters
gd::InstructionsList subInstructions; ///< Sub instructions, if applicable.
std::weak_ptr<Instruction>
originalInstruction; ///< Pointer used to remember which gd::Instruction
///< this instruction was copied from. Useful to
///< ensure the stability of code generation (as
///< some part of code generation uses the pointer
///< to the instruction as a unique identifier).
static gd::Expression badExpression;
};
/**
* Clone the given instruction, returning an instruction for which
* `GetOriginalInstruction()` returns the originally copied instruction.
*/
std::shared_ptr<Instruction> GD_CORE_API
CloneRememberingOriginalElement(std::shared_ptr<Instruction> instruction);
} // namespace gd
#endif // INSTRUCTION_H

View File

@@ -9,6 +9,7 @@
#include <memory>
#include <utility>
#include <vector>
#include "ExpressionParser2Node.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
@@ -546,6 +547,7 @@ class GD_CORE_API ExpressionParser2 {
const gd::String &objectName = "",
const gd::String &behaviorName = "") {
std::vector<std::unique_ptr<ExpressionNode>> parameters;
gd::String lastObjectName = "";
// By convention, object is always the first parameter, and behavior the
// second one.
@@ -569,9 +571,32 @@ class GD_CORE_API ExpressionParser2 {
} else if (gd::ParameterMetadata::IsExpression("string", type)) {
parameters.push_back(Expression("string"));
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
parameters.push_back(Expression(type, objectName));
parameters.push_back(Expression(
type, lastObjectName.empty() ? objectName : lastObjectName));
} else if (gd::ParameterMetadata::IsObject(type)) {
parameters.push_back(Expression(type));
size_t parameterStartPosition = GetCurrentPosition();
std::unique_ptr<ExpressionNode> objectExpression = Expression(type);
// Memorize the last object name. By convention, parameters that
// require an object (mainly, "objectvar" and "behavior") should be
// placed after the object in the list of parameters (if possible,
// just after). Search "lastObjectName" in the codebase for other
// place where this convention is enforced.
if (auto identifierNode =
dynamic_cast<IdentifierNode *>(objectExpression.get())) {
lastObjectName = identifierNode->identifierName;
} else {
objectExpression->diagnostic =
gd::make_unique<ExpressionParserError>(
"malformed_object_parameter",
_("An object name was expected but something else was "
"written. Enter just the name of the object for this "
"parameter."),
parameterStartPosition,
GetCurrentPosition());
}
parameters.push_back(std::move(objectExpression));
} else {
size_t parameterStartPosition = GetCurrentPosition();
parameters.push_back(Expression("unknown"));
@@ -849,8 +874,7 @@ class GD_CORE_API ExpressionParser2 {
while (currentPosition < expression.size() &&
(IsIdentifierAllowedChar()
// Allow whitespace in identifier name for compatibility
||
expression[currentPosition] == ' ')) {
|| expression[currentPosition] == ' ')) {
name += expression[currentPosition];
currentPosition++;
}

View File

@@ -73,6 +73,20 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
.AddParameter("trueorfalse", "Should the condition be true or false?")
.MarkAsAdvanced();
extension
.AddCondition("GetArgumentAsBoolean",
_("Check if a function parameter is set to true (or yes)"),
_("Check if the specified function parameter (also called "
"\"argument\") is set to True or Yes. If the argument is "
"a string, an empty string is considered as \"false\". "
"If it's a number, 0 is considered as \"false\"."),
_("Parameter _PARAM0_ is true"),
_("Functions"),
"res/function24.png",
"res/function16.png")
.AddParameter("string", "Parameter name")
.MarkAsAdvanced();
extension
.AddExpression(
"GetArgumentAsNumber",

View File

@@ -307,14 +307,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectvar", _("Variable"))
.UseStandardOperatorParameters("string");
obj.AddCondition(
"ObjectVariableChildExists",
_("Child existence"),
_("Return true if the specified child of the variable exists."),
_("Child _PARAM2_ of variable _PARAM1_ of _PARAM0_ exists"),
_("Variables/Structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
obj.AddCondition("ObjectVariableChildExists",
_("Child existence"),
_("Check if the specified child of the variable exists."),
_("Child _PARAM2_ of variable _PARAM1_ of _PARAM0_ exists"),
_("Variables/Structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.AddParameter("string", _("Name of the child"))
@@ -497,14 +496,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("string", _("Variable"))
.SetHidden();
obj.AddCondition(
"BehaviorActivated",
_("Behavior activated"),
_("Return true if the behavior is activated for the object."),
_("Behavior _PARAM1_ of _PARAM0_ is activated"),
_("Behaviors"),
"res/behavior24.png",
"res/behavior16.png")
obj.AddCondition("BehaviorActivated",
_("Behavior activated"),
_("Check if the behavior is activated for the object."),
_("Behavior _PARAM1_ of _PARAM0_ is activated"),
_("Behaviors"),
"res/behavior24.png",
"res/behavior16.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"))
@@ -835,6 +833,24 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectPtr", _("Object"));
obj.AddExpression("DistanceToPosition",
_("Distance between an object and a position"),
_("Distance between an object and a position"),
_("Position"),
"res/conditions/distance.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Target X position"))
.AddParameter("expression", _("Target Y position"));
obj.AddExpression("SqDistanceToPosition",
_("Square distance between an object and a position"),
_("Square distance between an object and a position"),
_("Position"),
"res/conditions/distance.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Target X position"))
.AddParameter("expression", _("Target Y position"));
obj.AddExpression("Variable",
_("Object's variable"),
_("Object's variable"),
@@ -867,6 +883,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("string", _("Timer's name"));
obj.AddExpression("AngleToObject",
_("Angle between two objects"),
_("Compute the angle between two objects. If you need the "
"angle to an arbitrary position, use AngleToPosition."),
_("Position"),
"res/actions/position.png")
.AddParameter("object", _("Object"))
.AddParameter("objectPtr", _("Object"));
obj.AddExpression("AngleToPosition",
_("Angle between an object and a position"),
_("Compute the angle between the object center and a "
"\"target\" position. If you need the angle between two "
"objects, use AngleToObject."),
_("Position"),
"res/actions/position.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Target X position"))
.AddParameter("expression", _("Target Y position"));
extension
.AddAction("Create",
_("Create an object"),

View File

@@ -469,6 +469,35 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddParameter("expression",
_("Scale (1: Default, 2: 2x faster, 0.5: 2x slower...)"));
extension
.AddCondition(
"LayerDefaultZOrder",
_("Layer default Z order"),
_("Compare the default Z order set to objects when they are created on a layer."),
_("the default Z order of objects created on _PARAM1_"),
_("Layers and cameras"),
"res/conditions/layer24.png",
"res/conditions/layer.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
extension
.AddAction(
"SetLayerDefaultZOrder",
_("Change layer default Z order"),
_("Change the default Z order set to objects when they are created on a layer."),
_("Set the default Z order of objects created on _PARAM1_ to _PARAM2_"),
_("Layers and cameras"),
"res/actions/layer24.png",
"res/actions/layer.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("New default Z order"));
extension
.AddExpression("CameraWidth",
_("Width of a camera of a layer"),
@@ -622,6 +651,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"res/actions/time.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"));
extension
.AddExpression("LayerDefaultZOrder",
_("Default Z Order for a layer"),
_("Default Z Order for a layer"),
_("Layers and cameras"),
"res/actions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"));
#endif
}

View File

@@ -35,7 +35,7 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
extension
.AddCondition("Or",
_("Or"),
_("Return true if one of the sub conditions is true"),
_("Check if one of the sub conditions is true"),
_("If one of these conditions is true:"),
_("Advanced"),
"res/conditions/or24.png",
@@ -46,7 +46,7 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
extension
.AddCondition("And",
_("And"),
_("Return true if all sub conditions are true"),
_("Check if all sub conditions are true"),
_("If all of these conditions are true:"),
_("Advanced"),
"res/conditions/and24.png",

View File

@@ -98,7 +98,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
.AddAction(
"LireFichierExp",
_("Read a value"),
_("Read the value saved in the specified element and store it in a scene"
_("Read the value saved in the specified element and store it in a scene "
"variable.\nSpecify the structure leading to the element using / "
"(example : Root/Level/Current)\nSpaces are forbidden in element "
"names."),

View File

@@ -40,6 +40,28 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
.AddParameter("expression", _("First angle"))
.AddParameter("expression", _("Second angle"));
extension
.AddExpression("AngleBetweenPositions",
_("Angle between two positions"),
_("Compute the angle between two positions."),
_("Mathematical tools"),
"res/mathfunction.png")
.AddParameter("expression", _("First point X position"))
.AddParameter("expression", _("First point Y position"))
.AddParameter("expression", _("Second point X position"))
.AddParameter("expression", _("Second point Y position"));
extension
.AddExpression("DistanceBetweenPositions",
_("Distance between two positions"),
_("Compute the distance between two positions."),
_("Mathematical tools"),
"res/mathfunction.png")
.AddParameter("expression", _("First point X position"))
.AddParameter("expression", _("First point Y position"))
.AddParameter("expression", _("Second point X position"))
.AddParameter("expression", _("Second point Y position"));
extension
.AddExpression("mod",
_("Modulo"),

View File

@@ -176,7 +176,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
extension
.AddCondition("SourisBouton",
_("Mouse button pressed or touch held"),
_("Return true if the specified mouse button is pressed or "
_("Check if the specified mouse button is pressed or "
"if a touch is in contact with the screen."),
_("Touch or _PARAM1_ mouse button is down"),
_("Mouse and touch"),
@@ -190,7 +190,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
.AddCondition(
"MouseButtonReleased",
_("Mouse button released"),
_("Return true if the specified mouse button was released."),
_("Check if the specified mouse button was released."),
_("_PARAM1_ mouse button was released"),
_("Mouse and touch"),
"res/conditions/mouse24.png",
@@ -235,7 +235,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
.AddCondition(
"PopStartedTouch",
_("A new touch has started"),
_("Return true if a touch has started. The touch identifier can be "
_("Check if a touch has started. The touch identifier can be "
"accessed using LastTouchId().\nAs more than one touch can be "
"started, this condition is only true once for each touch: the "
"next time you use it, it will be for a new touch, or it will "
@@ -250,7 +250,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
.AddCondition(
"PopEndedTouch",
_("A touch has ended"),
_("Return true if a touch has ended. The touch identifier can be "
_("Check if a touch has ended. The touch identifier can be "
"accessed using LastEndedTouchId().\nAs more than one touch can be "
"ended, this condition is only true once for each touch: the next "
"time you use it, it will be for a new touch, or it will return "

View File

@@ -34,10 +34,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
"res/actions/net24.png",
"res/actions/net.png")
.AddParameter("string", _("Host, with protocol"))
.SetParameterLongDescription(
_("Example: \"http://example.com/\"."))
.SetParameterLongDescription(_("Example: \"http://example.com/\"."))
.AddParameter("string", _("Path"))
.SetParameterLongDescription(_("Example: \"/user/123\" or \"/some-page.php\"."))
.SetParameterLongDescription(
_("Example: \"/user/123\" or \"/some-page.php\"."))
.AddParameter("string", _("Request body content"))
.AddParameter("string", _("Method: \"POST\" or \"GET\""), "", true)
.SetParameterLongDescription(_("If empty, \"GET\" will be used."))
@@ -51,6 +51,52 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
"variable. If the server returns *JSON*, you may want to use the "
"action \"Convert JSON to a scene variable\" afterwards, to "
"explore the results with a *structure variable*."))
.MarkAsComplex()
.SetHidden();
extension
.AddAction(
"SendAsyncRequest",
_("Send a request to a web page"),
_("Send an asynchronous request to the specified web page.\n\nPlease "
"note that for "
"the web games, the game must be hosted on the same host "
"as specified below, except if the server is configured to answer "
"to all requests (cross-domain requests)."),
_("Send a _PARAM2_ request to _PARAM0_ with body: _PARAM1_, and "
"store the result in _PARAM4_ (or in _PARAM5_ in case of error)"),
_("Network"),
"res/actions/net24.png",
"res/actions/net.png")
.AddParameter("string", _("URL (API or web-page address)"))
.SetParameterLongDescription(
_("Example: \"https://example.com/user/123\". Using *https* is "
"highly recommended."))
.AddParameter("string", _("Request body content"))
.AddParameter("stringWithSelector",
_("Resize mode"),
"[\"GET\", \"POST\", \"PUT\", \"HEAD\", \"DELETE\", "
"\"PATCH\", \"OPTIONS\"]",
false)
.SetParameterLongDescription(_("If empty, \"GET\" will be used."))
.SetDefaultValue("\"GET\"")
.AddParameter("string", _("Content type"), "", true)
.SetParameterLongDescription(
_("If empty, \"application/x-www-form-urlencoded\" will be used."))
.AddParameter(
"scenevar", _("Variable where to store the response"), "", true)
.SetParameterLongDescription(
_("The response of the server will be stored, as a string, in this "
"variable. If the server returns *JSON*, you may want to use the "
"action \"Convert JSON to a scene variable\" afterwards, to "
"explore the results with a *structure variable*."))
.AddParameter(
"scenevar", _("Variable where to store the error message"), "", true)
.SetParameterLongDescription(
_("Optional, only used if an error occurs. This will contain the "
"error message (if request could not be sent) or the [\"status "
"code\"](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes), "
"if the server returns a status >= 400."))
.MarkAsComplex();
extension
@@ -67,6 +113,22 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
_("Path to file (for example : /folder/file.txt)"))
.AddParameter("string", _("Save as"));
extension
.AddAction(
"EnableMetrics",
_("Enable (or disable) metrics collection"),
_("Enable, or disable, the sending of anonymous data used to compute "
"the number of sessions and other metrics from your game "
"players.\nBe sure to only send metrics if in accordance with the "
"terms of service of your game and if they player gave their "
"consent, depending on how your game/company handles this."),
_("Enable analytics metrics: _PARAM1_"),
_("Network"),
"res/actions/net24.png",
"res/actions/net.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("yesorno", _("Enable the metrics?"));
extension
.AddAction(
"JSONToVariableStructure",

View File

@@ -367,15 +367,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
obj.AddAction(
"ChangeColor",
_("Global color"),
_("Change the global color of an object. The default color is white."),
_("Change color of _PARAM0_ to _PARAM1_"),
_("Tint color"),
_("Change the tint of an object. The default color is white."),
_("Change tint of _PARAM0_ to _PARAM1_"),
_("Effects"),
"res/actions/color24.png",
"res/actions/color.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("color", _("Color"));
.AddParameter("color", _("Tint"));
obj.AddAction("ChangeBlendMode",
_("Blend mode"),
@@ -417,7 +417,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
obj.AddCondition("FlippedX",
_("Horizontally flipped"),
_("Return true if the object is horizontally flipped"),
_("Check if the object is horizontally flipped"),
_("_PARAM0_ is horizontally flipped"),
_("Effects"),
"res/actions/flipX24.png",
@@ -427,7 +427,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
obj.AddCondition("FlippedY",
_("Vertically flipped"),
_("Return true if the object is vertically flipped"),
_("Check if the object is vertically flipped"),
_("_PARAM0_ is vertically flipped"),
_("Effects"),
"res/actions/flipY24.png",

View File

@@ -107,8 +107,7 @@ void SpriteObject::DoSerializeTo(gd::SerializerElement& element) const {
}
}
std::map<gd::String, gd::PropertyDescriptor> SpriteObject::GetProperties(
gd::Project& project) const {
std::map<gd::String, gd::PropertyDescriptor> SpriteObject::GetProperties() const {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[_("Animate even if hidden or far from the screen")]
.SetValue(updateIfNotVisible ? "true" : "false")
@@ -119,8 +118,7 @@ std::map<gd::String, gd::PropertyDescriptor> SpriteObject::GetProperties(
}
bool SpriteObject::UpdateProperty(const gd::String& name,
const gd::String& value,
gd::Project& project) {
const gd::String& value) {
if (name == _("Animate even if hidden or far from the screen"))
updateIfNotVisible = value == "1";

View File

@@ -48,11 +48,9 @@ class GD_CORE_API SpriteObject : public gd::Object {
#if defined(GD_IDE_ONLY)
void ExposeResources(gd::ArbitraryResourceWorker& worker) override;
std::map<gd::String, gd::PropertyDescriptor> GetProperties(
gd::Project& project) const override;
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
bool UpdateProperty(const gd::String& name,
const gd::String& value,
gd::Project& project) override;
const gd::String& value) override;
std::map<gd::String, gd::PropertyDescriptor> GetInitialInstanceProperties(
const gd::InitialInstance& position,

View File

@@ -119,6 +119,18 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Manipulation of text"),
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"))
.SetHidden(); // Deprecated, see StrFindLast instead.
extension
.AddExpression("StrFindLast",
_("Search the last occurence in a text"),
_("Search the last occurence in a string (return the position of "
"the result, from the beginning of the string, or -1 if not found)"),
_("Manipulation of text"),
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"));
@@ -145,6 +157,22 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Manipulation of text"),
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"))
.AddParameter("expression",
_("Position of the last character in the string to be "
"considered in the search"))
.SetHidden(); // Deprecated, see StrFindLastFrom instead.
extension
.AddExpression(
"StrFindLastFrom",
_("Search the last occurence in a text, starting from a position"),
_("Search in a text the last occurence, starting from a position (return "
" the position of the result, from the beginning of the string, or -1 if not found)"),
_("Manipulation of text"),
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"))
.AddParameter("expression",

View File

@@ -47,7 +47,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
.AddCondition(
"VariableChildExists",
_("Child existence"),
_("Return true if the specified child of the scene variable exists."),
_("Check if the specified child of the scene variable exists."),
_("Child _PARAM1_ of scene variable _PARAM0_ exists"),
_("Variables/Structures"),
"res/conditions/var24.png",
@@ -59,7 +59,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddCondition("GlobalVariableChildExists",
_("Child existence"),
_("Return true if the specified child of the global "
_("Check if the specified child of the global "
"variable exists."),
_("Child _PARAM1_ of global variable _PARAM0_ exists"),
_("Variables/Global variables/Structures"),

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,129 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef DEPENDENCYMETADATA_H
#define DEPENDENCYMETADATA_H
#include <map>
#include <set>
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
namespace gd {
/**
* \brief Contains information about a dependency (library, npm/cordova
* package, or other according to the export) of an extension.
*/
class GD_CORE_API DependencyMetadata {
public:
/**
* \brief Sets the name shown to users.
*/
DependencyMetadata& SetName(const gd::String& name_) {
name = name_;
return *this;
};
/**
* \brief Sets the name written by the exporter.
* Typically, this is what is used by the dependency manager
* to find the dependency.
*
* \example
* \code
* // For depending upon the NPM package is-thirteen
* gd::DependencyMetadata dependencyMetadata = gd::DependencyMetadata();
* dependencyMetadata.setExporterName("is-thirteen");
* \endcode
*/
DependencyMetadata& SetExportName(const gd::String& exportName_) {
exportName = exportName_;
return *this;
};
/**
* \brief Set the version of the dependency to install.
* Use an empty string to use the latest version.
*/
DependencyMetadata& SetVersion(const gd::String& version_) {
version = version_;
return *this;
};
/**
* \brief Sets the type of dependecy (what will be used to install it)
*
* This can either be "npm" or "cordova" for now.
*/
DependencyMetadata& SetDependencyType(const gd::String& dependencyType_) {
dependencyType = dependencyType_;
if (dependencyType != "npm" && dependencyType != "cordova") {
gd::LogWarning("Invalid dependency type: " + dependencyType);
}
return *this;
};
/**
* \brief Sets a dependency type specific setting.
*/
DependencyMetadata& SetExtraSetting(
const gd::String& settingName,
const gd::PropertyDescriptor& settingValue) {
extraData[settingName] = settingValue;
return *this;
};
/**
* \brief Mark the dependency to be included in the export only if the
* specified setting is not empty.
*
* If this is called for multiple settings, all settings must be fulfilled for
* the dependency to be exported.
*/
DependencyMetadata& OnlyIfExtraSettingIsNonEmpty(
const gd::String& settingName) {
nonEmptyExtraSettingsForExport.insert(settingName);
return *this;
};
/**
* \brief Get the list of extra settings that must be fulfilled for the
* dependency to be exported.
*/
const std::set<gd::String>& GetRequiredExtraSettingsForExport() const {
return nonEmptyExtraSettingsForExport;
};
const gd::String& GetName() const { return name; };
const gd::String& GetExportName() const { return exportName; };
const gd::String& GetVersion() const { return version; };
const gd::String& GetDependencyType() const {
if (dependencyType == "")
gd::LogWarning("Dependency has no type, it won't be exported.");
return dependencyType;
};
const std::map<gd::String, gd::PropertyDescriptor>& GetAllExtraSettings()
const {
return extraData;
}
private:
gd::String name; ///< The name of the dependency.
gd::String exportName; ///< The name used to install the package (example:
///< npm package name for npm dependency type).
gd::String version; ///< The version of the dependency
gd::String dependencyType; ///< The tool used to install the dependency.
std::map<gd::String, gd::PropertyDescriptor>
extraData; ///< Contains dependency type specific additional parameters
///< for the dependency.
std::set<gd::String>
nonEmptyExtraSettingsForExport; ///< The set of extra settings that must
///< be non empty for this dependency to
///< be included by the exporter.
};
} // namespace gd
#endif // DEPENDENCYMETADATA_H

View File

@@ -90,7 +90,7 @@ size_t ParameterMetadataTools::GetObjectParameterIndexFor(
// the object in the list of parameters (if possible, just after).
// Search "lastObjectName" in the codebase for other place where this
// convention is enforced.
for (std::size_t pNb = parameterIndex - 1; pNb < parametersMetadata.size();
for (std::size_t pNb = parameterIndex; pNb < parametersMetadata.size();
pNb--) {
if (gd::ParameterMetadata::IsObject(parametersMetadata[pNb].GetType())) {
return pNb;

View File

@@ -4,9 +4,12 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Extensions/PlatformExtension.h"
#include <algorithm>
#include "GDCore/Events/Event.h"
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
#include "GDCore/Extensions/Metadata/EventMetadata.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
@@ -117,6 +120,13 @@ gd::ExpressionMetadata& PlatformExtension::AddStrExpression(
#endif
}
#if defined(GD_IDE_ONLY)
gd::DependencyMetadata& PlatformExtension::AddDependency() {
extensionDependenciesMetadata.push_back(DependencyMetadata());
return extensionDependenciesMetadata.back();
}
#endif
gd::ObjectMetadata& PlatformExtension::AddObject(
const gd::String& name,
const gd::String& fullname,
@@ -216,8 +226,7 @@ std::vector<gd::String> PlatformExtension::GetExtensionObjectsTypes() const {
std::vector<gd::String> PlatformExtension::GetExtensionEffectTypes() const {
std::vector<gd::String> effectNames;
for (auto& it : effectsMetadata)
effectNames.push_back(it.first);
for (auto& it : effectsMetadata) effectNames.push_back(it.first);
return effectNames;
}
@@ -283,6 +292,10 @@ PlatformExtension::GetAllStrExpressions() {
return strExpressionsInfos;
}
std::vector<gd::DependencyMetadata>& PlatformExtension::GetAllDependencies() {
return extensionDependenciesMetadata;
}
std::map<gd::String, gd::EventMetadata>& PlatformExtension::GetAllEvents() {
return eventsInfos;
}
@@ -404,7 +417,7 @@ void PlatformExtension::SetNameSpace(gd::String nameSpace_) {
name == "BuiltinCommonConversions" ||
name == "BuiltinStringInstructions" ||
name == "BuiltinMathematicalTools" ||
name == "Effects" || // Well-known effects are not namespaced.
name == "Effects" || // Well-known effects are not namespaced.
name == "CommonDialogs") // New name for BuiltinInterface
{
nameSpace = "";

View File

@@ -10,11 +10,14 @@
#include <map>
#include <memory>
#include <vector>
#include "GDCore/CommonTools.h"
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
#include "GDCore/Extensions/Metadata/EventMetadata.h"
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/String.h"
#include "GDCore/Tools/VersionPriv.h"
@@ -25,6 +28,7 @@ class ExpressionMetadata;
class ObjectMetadata;
class BehaviorMetadata;
class EffectMetadata;
class DependencyMetadata;
class BaseEvent;
class EventMetadata;
class EventCodeGenerator;
@@ -87,6 +91,14 @@ class GD_CORE_API PlatformExtension {
const gd::String& author_,
const gd::String& license_);
/**
* \brief Set the URL of the extension icon.
*/
PlatformExtension& SetIconUrl(const gd::String& iconUrl_) {
iconUrl = iconUrl_;
return *this;
}
/**
* \brief Set the path to the help, relative to the wiki/documentation root.
* For example, "/all-features/collisions" for
@@ -148,6 +160,8 @@ class GD_CORE_API PlatformExtension {
const gd::String& group_,
const gd::String& smallicon_);
gd::DependencyMetadata& AddDependency();
/**
* \brief Declare a new object as being part of the extension.
* \note This method does nothing when used for GD C++ runtime.
@@ -225,6 +239,15 @@ class GD_CORE_API PlatformExtension {
const gd::String& smallicon_,
std::shared_ptr<gd::BaseEvent> instance);
#if defined(GD_IDE_ONLY)
/**
* \brief Adds a property to the extension.
*/
gd::PropertyDescriptor& RegisterProperty(const gd::String& name) {
return extensionPropertiesMetadata[name];
};
#endif
/**
* \brief Return the name extension user friendly name.
*/
@@ -256,6 +279,12 @@ class GD_CORE_API PlatformExtension {
*/
const gd::String& GetHelpPath() const { return helpPath; }
/**
* \brief Return the URL to the icon to be displayed for this
* extension.
*/
const gd::String& GetIconUrl() const { return iconUrl; }
/**
* \brief Check if the extension is flagged as being deprecated.
*/
@@ -365,6 +394,12 @@ class GD_CORE_API PlatformExtension {
*/
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressions();
/**
* \brief Return a reference to a vector containing the metadata of all the
* dependencies of the extension.
*/
std::vector<gd::DependencyMetadata>& GetAllDependencies();
/**
* \brief Return a reference to a map containing the names of the actions,
* related to the object type, and the metadata associated with.
@@ -437,6 +472,13 @@ class GD_CORE_API PlatformExtension {
* generator.
*/
void StripUnimplementedInstructionsAndExpressions();
/**
* \brief Get all the properties of the extension
*/
std::map<gd::String, gd::PropertyDescriptor>& GetAllProperties() {
return extensionPropertiesMetadata;
}
#endif
/**
@@ -463,14 +505,15 @@ class GD_CORE_API PlatformExtension {
nameSpace; ///< Automatically set from the name of the extension, and
///< added to every
///< actions/conditions/expressions/objects/behavior/event.
gd::String fullname; ///< Name displayed to users at edittime
gd::String informations; ///< Description displayed to users at edittime
gd::String author; ///< Author displayed to users at edittime
gd::String license; ///< License name displayed to users at edittime
gd::String fullname; ///< Name displayed to users in the editor.
gd::String informations; ///< Description displayed to users in the editor.
gd::String author; ///< Author displayed to users in the editor.
gd::String license; ///< License name displayed to users in the editor.
bool deprecated; ///< true if the extension is deprecated and shouldn't be
///< shown in IDE.
gd::String helpPath; ///< The relative path to the help for this extension in
///< the documentation.
gd::String iconUrl; ///< The URL to the icon to be shown for this extension.
std::map<gd::String, gd::ObjectMetadata> objectsInfos;
std::map<gd::String, gd::BehaviorMetadata> behaviorsInfo;
@@ -480,7 +523,9 @@ class GD_CORE_API PlatformExtension {
std::map<gd::String, gd::InstructionMetadata> actionsInfos;
std::map<gd::String, gd::ExpressionMetadata> expressionsInfos;
std::map<gd::String, gd::ExpressionMetadata> strExpressionsInfos;
std::vector<gd::DependencyMetadata> extensionDependenciesMetadata;
std::map<gd::String, gd::EventMetadata> eventsInfos;
std::map<gd::String, gd::PropertyDescriptor> extensionPropertiesMetadata;
#endif
ObjectMetadata badObjectMetadata;

View File

@@ -279,6 +279,43 @@ bool EventsRefactorer::RenameObjectInConditions(
return somethingModified;
}
bool EventsRefactorer::RenameObjectInEventParameters(
const gd::Platform& platform,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::Expression& expression,
gd::ParameterMetadata parameterMetadata,
gd::String oldName,
gd::String newName) {
bool somethingModified = false;
if (gd::ParameterMetadata::IsObject(parameterMetadata.GetType()) &&
expression.GetPlainString() == oldName)
expression = gd::Expression(newName);
// Replace object's name in expressions
else if (ParameterMetadata::IsExpression(
"number", parameterMetadata.GetType())) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("number", expression.GetPlainString());
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
expression = ExpressionParser2NodePrinter::PrintNode(*node);
}
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", parameterMetadata.GetType())) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("string", expression.GetPlainString());
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
expression = ExpressionParser2NodePrinter::PrintNode(*node);
}
}
return somethingModified;
}
void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
@@ -300,6 +337,15 @@ void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
platform, project, layout, *actionsVectors[j], oldName, newName);
}
vector<pair<gd::Expression*, gd::ParameterMetadata>> expressionsWithMetadata =
events[i].GetAllExpressionsWithMetadata();
for (std::size_t j = 0; j < expressionsWithMetadata.size(); ++j) {
gd::Expression* expression = expressionsWithMetadata[j].first;
gd::ParameterMetadata parameterMetadata = expressionsWithMetadata[j].second;
bool somethingModified = RenameObjectInEventParameters(
platform, project, layout, *expression, parameterMetadata, oldName, newName);
}
if (events[i].CanHaveSubEvents())
RenameObjectInEvents(platform,
project,

View File

@@ -8,6 +8,7 @@
#include <memory>
#include <vector>
#include "GDCore/Events/Instruction.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/String.h"
namespace gd {
class EventsList;
@@ -146,6 +147,20 @@ class GD_CORE_API EventsRefactorer {
gd::InstructionsList& instructions,
gd::String oldName,
gd::String newName);
/**
* Replace all occurrences of an object name by another name in an expression
* with the specified metadata
* ( include : objects or objects in math/text expressions ).
*
* \return true if something was modified.
*/
static bool RenameObjectInEventParameters(const gd::Platform& platform,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::Expression& expression,
gd::ParameterMetadata parameterMetadata,
gd::String oldName,
gd::String newName);
/**
* Remove all conditions of the list using an object

View File

@@ -49,9 +49,15 @@ InstructionSentenceFormatter::GetAsFormattedText(
gd::String sentence = metadata.GetSentence();
std::replace(sentence.Raw().begin(), sentence.Raw().end(), '\n', ' ');
bool parse = true;
size_t loopCount = 0;
bool parse = true;
while (parse) {
if (loopCount > 40) {
break;
}
loopCount++;
// Search first parameter
parse = false;
size_t firstParamPosition = gd::String::npos;

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

@@ -4,6 +4,7 @@
* reserved. This project is released under the MIT License.
*/
#include "ProjectStripper.h"
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/Project/ExternalLayout.h"
#include "GDCore/Project/Layout.h"
@@ -20,61 +21,8 @@ void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project& project) {
project.GetLayout(i).GetObjectGroups().Clear();
project.GetLayout(i).GetEvents().Clear();
}
}
void GD_CORE_API ProjectStripper::StripProjectForLayoutEdition(
gd::Project& project, const gd::String& layoutName) {
while (project.GetExternalEventsCount() > 0)
project.RemoveExternalEvents(project.GetExternalEvents(0).GetName());
for (unsigned int i = 0; i < project.GetLayoutsCount(); ++i) {
auto& layout = project.GetLayout(i);
if (layoutName == layout.GetName()) continue;
project.GetLayout(i).GetEvents().Clear();
project.GetLayout(i).GetInitialInstances().Clear();
}
for (unsigned int i = 0; i < project.GetExternalEventsCount(); ++i) {
project.GetExternalEvents(i).GetEvents().Clear();
}
for (unsigned int i = 0; i < project.GetExternalLayoutsCount(); ++i) {
project.GetExternalLayout(i).GetInitialInstances().Clear();
}
}
void GD_CORE_API ProjectStripper::StripProjectForExternalLayoutEdition(
gd::Project& project, const gd::String& externalLayoutName) {
while (project.GetExternalEventsCount() > 0)
project.RemoveExternalEvents(project.GetExternalEvents(0).GetName());
gd::String associatedLayoutName;
if (project.HasExternalLayoutNamed(externalLayoutName)) {
associatedLayoutName =
project.GetExternalLayout(externalLayoutName).GetAssociatedLayout();
}
for (unsigned int i = 0; i < project.GetLayoutsCount(); ++i) {
auto& layout = project.GetLayout(i);
if (!associatedLayoutName.empty() &&
associatedLayoutName == layout.GetName())
continue;
project.GetLayout(i).GetEvents().Clear();
project.GetLayout(i).GetInitialInstances().Clear();
}
for (unsigned int i = 0; i < project.GetExternalEventsCount(); ++i) {
project.GetExternalEvents(i).GetEvents().Clear();
}
for (unsigned int i = 0; i < project.GetExternalLayoutsCount(); ++i) {
auto& externalLayout = project.GetExternalLayout(i);
if (externalLayoutName == externalLayout.GetName()) continue;
externalLayout.GetInitialInstances().Clear();
}
project.ClearEventsFunctionsExtensions();
}
} // namespace gd

View File

@@ -28,23 +28,6 @@ class GD_CORE_API ProjectStripper {
*/
static void StripProjectForExport(gd::Project& project);
/**
* \brief Strip project to keep only the full content of the specified
* layout. The content of other layouts, external events and external layouts
* is removed.
*/
static void StripProjectForLayoutEdition(gd::Project& project,
const gd::String& layoutName);
/**
* \brief Strip project to keep only the full content of the specified
* external layout and the associated layout.
* The content of other layouts, external events and external layouts is
* removed.
*/
static void StripProjectForExternalLayoutEdition(
gd::Project& project, const gd::String& externalLayoutName);
private:
ProjectStripper(){};
virtual ~ProjectStripper(){};

View File

@@ -181,7 +181,7 @@ class GD_CORE_API WholeProjectRefactorer {
bool isObjectGroup);
/**
* \brief Refactor the events function after an object or group is renamed
* \brief Refactor the events function after an object or group is removed
*
* This will update the events of the function and groups.
*/

View File

@@ -15,7 +15,7 @@ Behavior::~Behavior(){};
#if defined(GD_IDE_ONLY)
std::map<gd::String, gd::PropertyDescriptor> Behavior::GetProperties(
const gd::SerializerElement& behaviorContent, gd::Project& project) const {
const gd::SerializerElement& behaviorContent) const {
std::map<gd::String, gd::PropertyDescriptor> nothing;
return nothing;
}

View File

@@ -61,7 +61,7 @@ class GD_CORE_API Behavior {
* \see gd::PropertyDescriptor
*/
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
const gd::SerializerElement& behaviorContent, gd::Project& project) const;
const gd::SerializerElement& behaviorContent) const;
/**
* \brief Called when the IDE wants to update a custom property of the
@@ -72,8 +72,7 @@ class GD_CORE_API Behavior {
*/
virtual bool UpdateProperty(gd::SerializerElement& behaviorContent,
const gd::String& name,
const gd::String& value,
gd::Project& project) {
const gd::String& value) {
return false;
};
#endif

View File

@@ -16,7 +16,7 @@ BehaviorsSharedData::~BehaviorsSharedData(){};
#if defined(GD_IDE_ONLY)
std::map<gd::String, gd::PropertyDescriptor> BehaviorsSharedData::GetProperties(
const gd::SerializerElement& behaviorSharedDataContent, gd::Project& project) const {
const gd::SerializerElement& behaviorSharedDataContent) const {
std::map<gd::String, gd::PropertyDescriptor> nothing;
return nothing;
}

View File

@@ -64,8 +64,7 @@ class GD_CORE_API BehaviorsSharedData {
* \see gd::PropertyDescriptor
*/
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
const gd::SerializerElement& behaviorSharedDataContent,
gd::Project& project) const;
const gd::SerializerElement& behaviorSharedDataContent) const;
/**
* \brief Called when the IDE wants to update a property of the shared data
@@ -75,8 +74,7 @@ class GD_CORE_API BehaviorsSharedData {
*/
virtual bool UpdateProperty(gd::SerializerElement& behaviorSharedDataContent,
const gd::String& name,
const gd::String& value,
gd::Project& project) {
const gd::String& value) {
return false;
};
#endif

View File

@@ -35,6 +35,8 @@ void EventsFunctionsExtension::Init(const gd::EventsFunctionsExtension& other) {
fullName = other.fullName;
tags = other.tags;
author = other.author;
previewIconUrl = other.previewIconUrl;
iconUrl = other.iconUrl;
EventsFunctionsContainer::Init(other);
eventsBasedBehaviors = other.eventsBasedBehaviors;
}
@@ -48,6 +50,8 @@ void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
element.SetAttribute("fullName", fullName);
element.SetAttribute("tags", tags);
element.SetAttribute("author", author);
element.SetAttribute("previewIconUrl", previewIconUrl);
element.SetAttribute("iconUrl", iconUrl);
SerializeEventsFunctionsTo(element.AddChild("eventsFunctions"));
eventsBasedBehaviors.SerializeElementsTo(
@@ -64,6 +68,8 @@ void EventsFunctionsExtension::UnserializeFrom(
fullName = element.GetStringAttribute("fullName");
tags = element.GetStringAttribute("tags");
author = element.GetStringAttribute("author");
previewIconUrl = element.GetStringAttribute("previewIconUrl");
iconUrl = element.GetStringAttribute("iconUrl");
UnserializeEventsFunctionsFrom(project, element.GetChild("eventsFunctions"));
eventsBasedBehaviors.UnserializeElementsFrom(

View File

@@ -95,6 +95,18 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
return *this;
}
const gd::String& GetPreviewIconUrl() const { return previewIconUrl; };
EventsFunctionsExtension& SetPreviewIconUrl(const gd::String& previewIconUrl_) {
previewIconUrl = previewIconUrl_;
return *this;
}
const gd::String& GetIconUrl() const { return iconUrl; };
EventsFunctionsExtension& SetIconUrl(const gd::String& iconUrl_) {
iconUrl = iconUrl_;
return *this;
}
/**
* \brief Return a reference to the list of the events based behaviors.
*/
@@ -146,6 +158,8 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
gd::String fullName;
gd::String tags;
gd::String author;
gd::String previewIconUrl;
gd::String iconUrl;
gd::SerializableWithNameList<EventsBasedBehavior> eventsBasedBehaviors;
};

View File

@@ -0,0 +1,56 @@
#include "ExtensionProperties.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
namespace gd {
const gd::String ExtensionProperties::defaultValue = "";
std::map<gd::String, gd::PropertyDescriptor>
ExtensionProperties::GetAllExtensionProperties(const gd::String& extensionName,
gd::Project& project) {
// Create a copy
std::map<gd::String, gd::PropertyDescriptor> props(
project.GetCurrentPlatform()
.GetExtension(extensionName)
->GetAllProperties());
// Set values
for (std::pair<gd::String, gd::PropertyDescriptor> property : props) {
if (properties.count(extensionName) > 0 &&
properties[extensionName].count(property.first) > 0) {
props[property.first].SetValue(properties[extensionName][property.first]);
}
}
return props;
};
void ExtensionProperties::SerializeTo(SerializerElement& element) const {
element.ConsiderAsArrayOf("extensionProperties");
for (const std::pair<gd::String, std::map<gd::String, gd::String>> extension :
properties) {
for (const std::pair<gd::String, gd::String> property : extension.second) {
SerializerElement& propertyElement =
element.AddChild("extensionProperties");
propertyElement.AddChild("extension").SetStringValue(extension.first);
propertyElement.AddChild("property").SetStringValue(property.first);
propertyElement.AddChild("value").SetStringValue(property.second);
}
}
};
void ExtensionProperties::UnserializeFrom(const SerializerElement& element) {
properties.clear();
element.ConsiderAsArrayOf("extensionProperties");
for (std::pair<const gd::String, std::shared_ptr<SerializerElement>>
extensionProperties : element.GetAllChildren()) {
std::shared_ptr<SerializerElement> extensionPropertiesElement =
extensionProperties.second;
properties
[extensionPropertiesElement->GetChild("extension").GetStringValue()]
[extensionPropertiesElement->GetChild("property").GetStringValue()] =
extensionPropertiesElement->GetChild("value").GetStringValue();
}
};
}; // namespace gd

View File

@@ -0,0 +1,69 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EXTENSIONPROPERTIES_H
#define GDCORE_EXTENSIONPROPERTIES_H
#include <map>
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
namespace gd {
class Project;
class PropertyDescriptor;
} // namespace gd
namespace gd {
class GD_CORE_API ExtensionProperties {
static const gd::String defaultValue;
public:
const gd::String& GetValue(const gd::String& extension,
const gd::String& property) const {
if (properties.count(extension) == 0 ||
properties.at(extension).count(property) == 0) {
return ExtensionProperties::defaultValue;
}
return properties.at(extension).at(property);
};
void SetValue(const gd::String& extension,
const gd::String& property,
const gd::String& newValue) {
properties[extension][property] = newValue;
};
bool HasProperty(const gd::String& extension, const gd::String& property) {
for (std::pair<gd::String, gd::String> propertyPair :
properties[extension]) {
if (propertyPair.first == property) {
return true;
}
}
return false;
}
std::map<gd::String, gd::PropertyDescriptor> GetAllExtensionProperties(
const gd::String& extensionName, gd::Project& project);
///@{
/**
* \brief Serialize the Extension Properties.
*/
virtual void SerializeTo(SerializerElement& element) const;
/**
* \brief Unserialize the Extension Properties.
*/
virtual void UnserializeFrom(const SerializerElement& element);
///@}
private:
std::map<gd::String, std::map<gd::String, gd::String>>
properties; ///< The properties of the project
};
} // namespace gd
#endif // EXTENSIONPROPERTIES_H

View File

@@ -5,10 +5,12 @@
*/
#include "GDCore/Project/InitialInstance.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/UUID/UUID.h"
#if defined(GD_IDE_ONLY)
#include "GDCore/Project/PropertyDescriptor.h"
#endif
@@ -27,7 +29,8 @@ InitialInstance::InitialInstance()
personalizedSize(false),
width(0),
height(0),
locked(false) {}
locked(false),
persistentUuid(UUID::MakeUuid4()) {}
void InitialInstance::UnserializeFrom(const SerializerElement& element) {
SetObjectName(element.GetStringAttribute("name", "", "nom"));
@@ -42,6 +45,9 @@ void InitialInstance::UnserializeFrom(const SerializerElement& element) {
SetLayer(element.GetStringAttribute("layer"));
SetLocked(element.GetBoolAttribute("locked", false));
persistentUuid = element.GetStringAttribute("persistentUuid");
if (persistentUuid.empty()) ResetPersistentUuid();
floatInfos.clear();
const SerializerElement& floatPropElement =
element.GetChild("numberProperties", 0, "floatInfos");
@@ -79,6 +85,9 @@ void InitialInstance::SerializeTo(SerializerElement& element) const {
element.SetAttribute("height", GetCustomHeight());
element.SetAttribute("locked", IsLocked());
if (persistentUuid.empty()) persistentUuid = UUID::MakeUuid4();
element.SetStringAttribute("persistentUuid", persistentUuid);
SerializerElement& floatPropElement = element.AddChild("numberProperties");
floatPropElement.ConsiderAsArrayOf("property");
for (std::map<gd::String, float>::const_iterator floatInfo =
@@ -104,6 +113,11 @@ void InitialInstance::SerializeTo(SerializerElement& element) const {
GetVariables().SerializeTo(element.AddChild("initialVariables"));
}
InitialInstance& InitialInstance::ResetPersistentUuid() {
persistentUuid = UUID::MakeUuid4();
return *this;
}
#if defined(GD_IDE_ONLY)
std::map<gd::String, gd::PropertyDescriptor>
InitialInstance::GetCustomProperties(gd::Project& project, gd::Layout& layout) {
@@ -146,13 +160,12 @@ const gd::String& InitialInstance::GetRawStringProperty(
return it != stringInfos.end() ? it->second : *badStringProperyValue;
}
void InitialInstance::SetRawFloatProperty(const gd::String& name, float value)
{
void InitialInstance::SetRawFloatProperty(const gd::String& name, float value) {
floatInfos[name] = value;
}
void InitialInstance::SetRawStringProperty(const gd::String& name, const gd::String& value)
{
void InitialInstance::SetRawStringProperty(const gd::String& name,
const gd::String& value) {
stringInfos[name] = value;
}
#endif

View File

@@ -200,7 +200,7 @@ class GD_CORE_API InitialInstance {
/**
* \brief Get the value of a float property stored in the instance.
* \note Only use this when \a GetCustomProperties is too slow (when rendering
* instances for example).
* instances for example).
* \return the value of the property, or 0 if it does
* not exists.
*/
@@ -209,7 +209,7 @@ class GD_CORE_API InitialInstance {
/**
* \brief Get the value of a string property stored in the instance.
* \note Only use this when \a GetCustomProperties is too slow (when rendering
* instances for example).
* instances for example).
* \return the value of the propety, or an empty
* string if it does not exists.
*/
@@ -240,6 +240,12 @@ class GD_CORE_API InitialInstance {
* \brief Unserialize the instances container.
*/
virtual void UnserializeFrom(const SerializerElement& element);
/**
* \brief Reset the persistent UUID used to recognize
* the same initial instance between serialization.
*/
InitialInstance& ResetPersistentUuid();
///@}
// More properties can be stored in floatInfos and stringInfos.
@@ -260,6 +266,7 @@ class GD_CORE_API InitialInstance {
float height; ///< Object custom height
gd::VariablesContainer initialVariables; ///< Instance specific variables
bool locked; ///< True if the instance is locked
mutable gd::String persistentUuid; ///< A persistent random version 4 UUID, useful for hot reloading.
static gd::String*
badStringProperyValue; ///< Empty string returned by GetRawStringProperty

View File

@@ -179,6 +179,8 @@ InitialInstanceFunctor::~InitialInstanceFunctor(){};
void HighestZOrderFinder::operator()(gd::InitialInstance& instance) {
if (!layerRestricted || instance.GetLayer() == layerName) {
instancesCount++;
if (firstCall) {
highestZOrder = instance.GetZOrder();
lowestZOrder = instance.GetZOrder();

View File

@@ -211,6 +211,7 @@ class GD_CORE_API HighestZOrderFinder : public gd::InitialInstanceFunctor {
HighestZOrderFinder()
: highestZOrder(0),
lowestZOrder(0),
instancesCount(0),
firstCall(true),
layerRestricted(false){};
virtual ~HighestZOrderFinder(){};
@@ -237,9 +238,16 @@ class GD_CORE_API HighestZOrderFinder : public gd::InitialInstanceFunctor {
*/
int GetLowestZOrder() const { return lowestZOrder; }
/**
* \brief After calling the instances container iterate method with this
* functor, this method will return the number of instances.
*/
size_t GetInstancesCount() const { return instancesCount; }
private:
int highestZOrder;
int lowestZOrder;
size_t instancesCount;
bool firstCall;
bool layerRestricted; ///< If true, the search is restricted to the layer

View File

@@ -13,7 +13,7 @@ namespace gd {
Camera Layer::badCamera;
Effect Layer::badEffect;
Layer::Layer() : isVisible(true) {}
Layer::Layer() : isVisible(true), isLightingLayer(false), followBaseLayerCamera(false) {}
/**
* Change cameras count, automatically adding/removing them.
@@ -29,6 +29,11 @@ void Layer::SetCameraCount(std::size_t n) {
void Layer::SerializeTo(SerializerElement& element) const {
element.SetAttribute("name", GetName());
element.SetAttribute("visibility", GetVisibility());
element.SetAttribute("isLightingLayer", IsLightingLayer());
element.SetAttribute("followBaseLayerCamera", IsFollowingBaseLayerCamera());
element.SetAttribute("ambientLightColorR", (int)GetAmbientLightColorRed());
element.SetAttribute("ambientLightColorG", (int)GetAmbientLightColorGreen());
element.SetAttribute("ambientLightColorB", (int)GetAmbientLightColorBlue());
SerializerElement& camerasElement = element.AddChild("cameras");
camerasElement.ConsiderAsArrayOf("camera");
@@ -61,6 +66,11 @@ void Layer::SerializeTo(SerializerElement& element) const {
void Layer::UnserializeFrom(const SerializerElement& element) {
SetName(element.GetStringAttribute("name", "", "Name"));
SetVisibility(element.GetBoolAttribute("visibility", true, "Visibility"));
SetLightingLayer(element.GetBoolAttribute("isLightingLayer", false));
SetFollowBaseLayerCamera(element.GetBoolAttribute("followBaseLayerCamera", false));
SetAmbientLightColor(element.GetIntAttribute("ambientLightColorR", 200),
element.GetIntAttribute("ambientLightColorG", 200),
element.GetIntAttribute("ambientLightColorB", 200));
// Compatibility with GD <= 3.3
if (element.HasChild("Camera")) {

View File

@@ -51,6 +51,26 @@ class GD_CORE_API Layer {
*/
bool GetVisibility() const { return isVisible; }
/**
* \brief Set if the layer is a lightining layer or not.
*/
void SetLightingLayer(bool isLightingLayer_) { isLightingLayer = isLightingLayer_; }
/**
* \brief Return true if the layer is a lighting layer.
*/
bool IsLightingLayer() const { return isLightingLayer; }
/**
* \brief Set if the layer automatically follows the base layer or not.
*/
void SetFollowBaseLayerCamera(bool followBaseLayerCamera_) { followBaseLayerCamera = followBaseLayerCamera_; }
/**
* \brief Return true if the layer follows the base layer.
*/
bool IsFollowingBaseLayerCamera() const { return followBaseLayerCamera; }
/** \name Cameras
*/
///@{
@@ -96,6 +116,30 @@ class GD_CORE_API Layer {
///@}
/**
* Get the ambient light color red component.
*/
unsigned int GetAmbientLightColorRed() const { return ambientLightColorR; }
/**
* Get the ambient light color green component.
*/
unsigned int GetAmbientLightColorGreen() const { return ambientLightColorG; }
/**
* Get the ambient light color blue component.
*/
unsigned int GetAmbientLightColorBlue() const { return ambientLightColorB; }
/**
* Set the ambient light color.
*/
void SetAmbientLightColor(unsigned int r, unsigned int g, unsigned int b) {
ambientLightColorR = r;
ambientLightColorG = g;
ambientLightColorB = b;
}
/** \name Effects
*/
///@{
@@ -177,6 +221,11 @@ class GD_CORE_API Layer {
private:
gd::String name; ///< The name of the layer
bool isVisible; ///< True if the layer is visible
bool isLightingLayer; ///< True if the layer is used to display lights and renders an ambient light.
bool followBaseLayerCamera; ///< True if the layer automatically follows the base layer
unsigned int ambientLightColorR; ///< Ambient light color Red component
unsigned int ambientLightColorG; ///< Ambient light color Green component
unsigned int ambientLightColorB; ///< Ambient light color Blue component
std::vector<gd::Camera> cameras; ///< The camera displayed by the layer
std::vector<std::shared_ptr<gd::Effect>>
effects; ///< The effects applied to the layer.

View File

@@ -23,4 +23,14 @@ void NamedPropertyDescriptor::UnserializeFrom(
name = element.GetChild("name").GetStringValue();
}
void NamedPropertyDescriptor::SerializeValuesTo(SerializerElement& element) const {
PropertyDescriptor::SerializeValuesTo(element);
element.AddChild("name").SetStringValue(name);
}
void NamedPropertyDescriptor::UnserializeValuesFrom(const SerializerElement& element) {
PropertyDescriptor::UnserializeValuesFrom(element);
name = element.GetChild("name").GetStringValue();
}
} // namespace gd

View File

@@ -58,6 +58,16 @@ class GD_CORE_API NamedPropertyDescriptor : public PropertyDescriptor {
* \brief Unserialize the NamedPropertyDescriptor.
*/
void UnserializeFrom(const SerializerElement& element);
/**
* \brief Serialize only the value and extra informations of the property.
*/
virtual void SerializeValuesTo(SerializerElement& element) const;
/**
* \brief Unserialize only the value and extra information of the property.
*/
virtual void UnserializeValuesFrom(const SerializerElement& element);
///@}
/**

View File

@@ -77,8 +77,7 @@ gd::BehaviorContent& Object::AddBehavior(
}
#if defined(GD_IDE_ONLY)
std::map<gd::String, gd::PropertyDescriptor> Object::GetProperties(
gd::Project& project) const {
std::map<gd::String, gd::PropertyDescriptor> Object::GetProperties() const {
std::map<gd::String, gd::PropertyDescriptor> nothing;
return nothing;
}

View File

@@ -139,8 +139,7 @@ class GD_CORE_API Object {
* \return a std::map with properties names as key.
* \see gd::PropertyDescriptor
*/
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
gd::Project& project) const;
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
/**
* \brief Called when the IDE wants to update a custom property of the object
@@ -148,8 +147,7 @@ class GD_CORE_API Object {
* \return false if the new value cannot be set
*/
virtual bool UpdateProperty(const gd::String& name,
const gd::String& value,
gd::Project& project) {
const gd::String& value) {
return false;
};
///@}

View File

@@ -5,13 +5,16 @@
*/
#include "Project.h"
#include <stdio.h>
#include <stdlib.h>
#include <cctype>
#include <SFML/System/Utf.hpp>
#include <cctype>
#include <fstream>
#include <map>
#include <vector>
#include "GDCore/CommonTools.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
@@ -35,6 +38,7 @@
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/Log.h"
#include "GDCore/Tools/PolymorphicClone.h"
#include "GDCore/Tools/UUID/UUID.h"
#include "GDCore/Tools/VersionWrapper.h"
#include "GDCore/Utf8/utf8.h"
@@ -51,7 +55,6 @@ Project::Project()
version("1.0.0"),
packageName("com.example.gamename"),
orientation("landscape"),
adMobAppId(""),
folderProject(false),
#endif
windowWidth(800),
@@ -62,6 +65,8 @@ Project::Project()
scaleMode("linear"),
adaptGameResolutionAtRuntime(true),
sizeOnStartupMode("adaptWidth"),
projectUuid(""),
useDeprecatedZeroAsDefaultZOrder(false),
imageManager(std::make_shared<ImageManager>())
#if defined(GD_IDE_ONLY)
,
@@ -104,6 +109,8 @@ Project::Project()
Project::~Project() {}
void Project::ResetProjectUuid() { projectUuid = UUID::MakeUuid4(); }
std::unique_ptr<gd::Object> Project::CreateObject(
const gd::String& type,
const gd::String& name,
@@ -521,6 +528,9 @@ void Project::RemoveEventsFunctionsExtension(const gd::String& name) {
eventsFunctionsExtensions.erase(eventsFunctionExtension);
}
void Project::ClearEventsFunctionsExtensions() {
eventsFunctionsExtensions.clear();
}
#endif
void Project::UnserializeFrom(const SerializerElement& element) {
@@ -589,13 +599,12 @@ void Project::UnserializeFrom(const SerializerElement& element) {
SetAdaptGameResolutionAtRuntime(
propElement.GetBoolAttribute("adaptGameResolutionAtRuntime", false));
SetSizeOnStartupMode(propElement.GetStringAttribute("sizeOnStartupMode", ""));
SetProjectUuid(propElement.GetStringAttribute("projectUuid", ""));
#if defined(GD_IDE_ONLY)
SetAuthor(propElement.GetChild("author", 0, "Auteur").GetValue().GetString());
SetPackageName(propElement.GetStringAttribute("packageName"));
SetOrientation(propElement.GetStringAttribute("orientation", "default"));
SetAdMobAppId(propElement.GetStringAttribute("adMobAppId", ""));
SetFolderProject(propElement.GetBoolAttribute("folderProject"));
SetProjectFile(propElement.GetStringAttribute("projectFile"));
SetLastCompilationDirectory(propElement
.GetChild("latestCompilationDirectory",
0,
@@ -605,16 +614,41 @@ void Project::UnserializeFrom(const SerializerElement& element) {
platformSpecificAssets.UnserializeFrom(
propElement.GetChild("platformSpecificAssets"));
loadingScreen.UnserializeFrom(propElement.GetChild("loadingScreen"));
winExecutableFilename =
propElement.GetStringAttribute("winExecutableFilename");
winExecutableIconFile =
propElement.GetStringAttribute("winExecutableIconFile");
linuxExecutableFilename =
propElement.GetStringAttribute("linuxExecutableFilename");
macExecutableFilename =
propElement.GetStringAttribute("macExecutableFilename");
useExternalSourceFiles =
propElement.GetBoolAttribute("useExternalSourceFiles");
// Compatibility with GD <= 5.0.0-beta101
if (VersionWrapper::IsOlderOrEqual(
gdMajorVersion, gdMinorVersion, gdBuildVersion, 0, 4, 0, 98, 0) &&
!propElement.HasAttribute("useDeprecatedZeroAsDefaultZOrder")) {
useDeprecatedZeroAsDefaultZOrder = true;
} else {
useDeprecatedZeroAsDefaultZOrder =
propElement.GetBoolAttribute("useDeprecatedZeroAsDefaultZOrder", false);
}
// end of compatibility code
// Compatibility with GD <= 5.0.0-beta101
if (!propElement.HasAttribute("projectUuid") &&
!propElement.HasChild("projectUuid")) {
ResetProjectUuid();
}
// end of compatibility code
extensionProperties.UnserializeFrom(
propElement.GetChild("extensionProperties"));
// Compatibility with GD <= 5.0.0-beta98
// Move AdMob App ID from project property to extension property.
if (propElement.GetStringAttribute("adMobAppId", "") != "") {
extensionProperties.SetValue(
"AdMob",
"AdMobAppId",
propElement.GetStringAttribute("adMobAppId", ""));
}
// end of compatibility code
#endif
const SerializerElement& extensionsElement =
@@ -863,22 +897,26 @@ void Project::SerializeTo(SerializerElement& element) const {
propElement.AddChild("verticalSync")
.SetValue(IsVerticalSynchronizationEnabledByDefault());
propElement.SetAttribute("scaleMode", scaleMode);
propElement.SetAttribute("adaptGameResolutionAtRuntime", adaptGameResolutionAtRuntime);
propElement.SetAttribute("adaptGameResolutionAtRuntime",
adaptGameResolutionAtRuntime);
propElement.SetAttribute("sizeOnStartupMode", sizeOnStartupMode);
propElement.SetAttribute("projectFile", gameFile);
propElement.SetAttribute("projectUuid", projectUuid);
propElement.SetAttribute("folderProject", folderProject);
propElement.SetAttribute("packageName", packageName);
propElement.SetAttribute("orientation", orientation);
propElement.SetAttribute("adMobAppId", adMobAppId);
platformSpecificAssets.SerializeTo(
propElement.AddChild("platformSpecificAssets"));
loadingScreen.SerializeTo(propElement.AddChild("loadingScreen"));
propElement.SetAttribute("winExecutableFilename", winExecutableFilename);
propElement.SetAttribute("winExecutableIconFile", winExecutableIconFile);
propElement.SetAttribute("linuxExecutableFilename", linuxExecutableFilename);
propElement.SetAttribute("macExecutableFilename", macExecutableFilename);
propElement.SetAttribute("useExternalSourceFiles", useExternalSourceFiles);
// Compatibility with GD <= 5.0.0-beta101
if (useDeprecatedZeroAsDefaultZOrder) {
propElement.SetAttribute("useDeprecatedZeroAsDefaultZOrder", true);
}
// end of compatibility code
extensionProperties.SerializeTo(propElement.AddChild("extensionProperties"));
SerializerElement& extensionsElement = propElement.AddChild("extensions");
extensionsElement.ConsiderAsArrayOf("extension");
for (std::size_t i = 0; i < GetUsedExtensions().size(); ++i)
@@ -1052,7 +1090,6 @@ Project& Project::operator=(const Project& other) {
}
void Project::Init(const gd::Project& game) {
// Some properties
name = game.name;
version = game.version;
windowWidth = game.windowWidth;
@@ -1063,18 +1100,21 @@ void Project::Init(const gd::Project& game) {
scaleMode = game.scaleMode;
adaptGameResolutionAtRuntime = game.adaptGameResolutionAtRuntime;
sizeOnStartupMode = game.sizeOnStartupMode;
projectUuid = game.projectUuid;
useDeprecatedZeroAsDefaultZOrder = game.useDeprecatedZeroAsDefaultZOrder;
#if defined(GD_IDE_ONLY)
author = game.author;
packageName = game.packageName;
orientation = game.orientation;
adMobAppId = game.adMobAppId;
folderProject = game.folderProject;
latestCompilationDirectory = game.latestCompilationDirectory;
platformSpecificAssets = game.platformSpecificAssets;
loadingScreen = game.loadingScreen;
objectGroups = game.objectGroups;
extensionProperties = game.extensionProperties;
gdMajorVersion = game.gdMajorVersion;
gdMinorVersion = game.gdMinorVersion;
gdBuildVersion = game.gdBuildVersion;
@@ -1084,7 +1124,6 @@ void Project::Init(const gd::Project& game) {
extensionsUsed = game.extensionsUsed;
platforms = game.platforms;
// Resources
resourcesManager = game.resourcesManager;
imageManager = std::make_shared<ImageManager>(*game.imageManager);
imageManager->SetResourcesManager(&resourcesManager);
@@ -1109,13 +1148,8 @@ void Project::Init(const gd::Project& game) {
variables = game.GetVariables();
#if defined(GD_IDE_ONLY)
gameFile = game.GetProjectFile();
projectFile = game.GetProjectFile();
imagesChanged = game.imagesChanged;
winExecutableFilename = game.winExecutableFilename;
winExecutableIconFile = game.winExecutableIconFile;
linuxExecutableFilename = game.linuxExecutableFilename;
macExecutableFilename = game.macExecutableFilename;
#endif
}

View File

@@ -8,6 +8,8 @@
#define GDCORE_PROJECT_H
#include <memory>
#include <vector>
#include "GDCore/Project/ExtensionProperties.h"
#include "GDCore/Project/LoadingScreen.h"
#include "GDCore/Project/ObjectGroupsContainer.h"
#include "GDCore/Project/ObjectsContainer.h"
@@ -113,30 +115,16 @@ class GD_CORE_API Project : public ObjectsContainer {
*/
const gd::String& GetOrientation() const { return orientation; }
/**
* \brief Change the project AdMob application ID (needed
* to use the AdMob extension). This has no effect on desktop
* and web browsers.
*/
void SetAdMobAppId(const gd::String& adMobAppId_) {
adMobAppId = adMobAppId_;
};
/**
* \brief Get the project AdMob application ID.
*/
const gd::String& GetAdMobAppId() const { return adMobAppId; }
/**
* Called when project file has changed.
*/
void SetProjectFile(const gd::String& file) { gameFile = file; }
void SetProjectFile(const gd::String& file) { projectFile = file; }
/**
* Return project file
* \see gd::Project::SetProjectFile
*/
const gd::String& GetProjectFile() const { return gameFile; }
const gd::String& GetProjectFile() const { return projectFile; }
/**
* Set that the project should be saved as a folder project.
@@ -289,6 +277,42 @@ class GD_CORE_API Project : public ObjectsContainer {
*/
void SetScaleMode(const gd::String& scaleMode_) { scaleMode = scaleMode_; }
/**
* \brief Return if the project should set 0 as Z-order for objects created
* from events (which is deprecated) - instead of the highest Z order that was
* found on each layer when the scene started.
*/
bool GetUseDeprecatedZeroAsDefaultZOrder() const {
return useDeprecatedZeroAsDefaultZOrder;
}
/**
* \brief Set if the project should set 0 as Z-order for objects created from
* events (which is deprecated) - instead of the highest Z order that was
* found on each layer when the scene started.
*/
void SetUseDeprecatedZeroAsDefaultZOrder(bool enable) {
useDeprecatedZeroAsDefaultZOrder = enable;
}
/**
* \brief Change the project UUID.
*/
void SetProjectUuid(const gd::String& projectUuid_) {
projectUuid = projectUuid_;
};
/**
* \brief Get the project UUID, useful when using the game on online services
* that would require a unique identifier.
*/
const gd::String& GetProjectUuid() const { return projectUuid; }
/**
* \brief Create a new project UUID.
*/
void ResetProjectUuid();
/**
* Return a reference to the vector containing the names of extensions used by
* the project.
@@ -304,6 +328,26 @@ class GD_CORE_API Project : public ObjectsContainer {
std::vector<gd::String>& GetUsedExtensions() { return extensionsUsed; };
#if defined(GD_IDE_ONLY)
/**
* \brief Get the properties set by extensions.
*
* Each extension can store arbitrary values indexed by a property name, which
* are useful to store project wide settings (AdMob id, etc...).
*/
gd::ExtensionProperties& GetExtensionProperties() {
return extensionProperties;
};
/**
* \brief Get the properties set by extensions.
*
* Each extension can store arbitrary values indexed by a property name, which
* are useful to store project wide settings (AdMob id, etc...).
*/
const gd::ExtensionProperties& GetExtensionProperties() const {
return extensionProperties;
};
/**
* Return the list of platforms used by the project.
*/
@@ -460,22 +504,27 @@ class GD_CORE_API Project : public ObjectsContainer {
std::size_t GetLayoutsCount() const;
/**
* \brief \brief Adds a new empty layout called "name" at the specified
* \brief Add a new empty layout called "name" at the specified
* position in the layout list.
*/
gd::Layout& InsertNewLayout(const gd::String& name, std::size_t position);
/**
* \brief \brief Adds a new layout constructed from the layout passed as
* parameter. \note No pointer or reference must be kept on the layout passed
* as parameter. \param layout The layout that must be copied and inserted
* into the project \param position Insertion position. Even if the position
* \brief Add a new layout constructed from the layout passed as
* parameter.
* \param layout The layout that must be copied and inserted
* into the project
* \param position Insertion position. Even if the position
* is invalid, the layout must be inserted at the end of the layout list.
*
* \note No pointer or reference must be kept on the layout passed
* as parameter.
*
*/
gd::Layout& InsertLayout(const Layout& layout, std::size_t position);
/**
* Must delete layout named "name".
* \brief Delete layout named "name".
*/
void RemoveLayout(const gd::String& name);
@@ -592,7 +641,7 @@ class GD_CORE_API Project : public ObjectsContainer {
std::size_t position);
/**
* Must delete external events named "name".
* \brief Delete external events named "name".
*/
void RemoveExternalEvents(const gd::String& name);
#endif
@@ -673,7 +722,7 @@ class GD_CORE_API Project : public ObjectsContainer {
std::size_t position);
/**
* Must delete external layout named "name".
* \brief Delete external layout named "name".
*/
void RemoveExternalLayout(const gd::String& name);
@@ -694,37 +743,37 @@ class GD_CORE_API Project : public ObjectsContainer {
///@{
#if defined(GD_IDE_ONLY)
/**
* Return true if events functions extension called "name" exists.
* \brief Check if events functions extension called "name" exists.
*/
bool HasEventsFunctionsExtensionNamed(const gd::String& name) const;
/**
* Return a reference to the events functions extension called "name".
* \brief Return a reference to the events functions extension called "name".
*/
EventsFunctionsExtension& GetEventsFunctionsExtension(const gd::String& name);
/**
* Return a reference to the events functions extension called "name".
* \brief Return a reference to the events functions extension called "name".
*/
const EventsFunctionsExtension& GetEventsFunctionsExtension(
const gd::String& name) const;
/**
* Return a reference to the events functions extension at position "index" in
* the list
* \brief Return a reference to the events functions extension at position
* "index" in the list
*/
EventsFunctionsExtension& GetEventsFunctionsExtension(std::size_t index);
/**
* Return a reference to the events functions extension at position "index" in
* the list
* \brief Return a reference to the events functions extension at position
* "index" in the list
*/
const EventsFunctionsExtension& GetEventsFunctionsExtension(
std::size_t index) const;
/**
* Return the position of the events functions extension called "name" in the
* list
* \brief Return the position of the events functions extension called "name"
* in the list.
*/
std::size_t GetEventsFunctionsExtensionPosition(const gd::String& name) const;
@@ -736,7 +785,7 @@ class GD_CORE_API Project : public ObjectsContainer {
void SwapEventsFunctionsExtensions(std::size_t first, std::size_t second);
/**
* Return the number of events functions extension.
* \brief Returns the number of events functions extension.
*/
std::size_t GetEventsFunctionsExtensionsCount() const;
@@ -759,9 +808,14 @@ class GD_CORE_API Project : public ObjectsContainer {
std::size_t position);
/**
* Must delete the events functions extension named "name".
* \brief Delete the events functions extension named "name".
*/
void RemoveEventsFunctionsExtension(const gd::String& name);
/**
* \brief Remove all the events functions extensions.
*/
void ClearEventsFunctionsExtensions();
#endif
///@}
@@ -905,10 +959,6 @@ class GD_CORE_API Project : public ObjectsContainer {
#if defined(GD_IDE_ONLY)
std::vector<gd::String> imagesChanged; ///< Images that have been changed and
///< which have to be reloaded
gd::String winExecutableFilename; ///< Windows executable name
gd::String winExecutableIconFile; ///< Icon for Windows executable
gd::String linuxExecutableFilename; ///< Linux executable name
gd::String macExecutableFilename; ///< Mac executable name
#endif
private:
@@ -930,8 +980,15 @@ class GD_CORE_API Project : public ObjectsContainer {
bool adaptGameResolutionAtRuntime; ///< Should the game resolution be adapted
///< to the window size at runtime
gd::String
sizeOnStartupMode; ///< How to adapt the game size to the screen. Can be
///< "adaptWidth", "adaptHeight" or empty
sizeOnStartupMode; ///< How to adapt the game size to the screen. Can be
///< "adaptWidth", "adaptHeight" or empty
gd::String projectUuid; ///< UUID useful to identify the game in online
///< services or database that would require it.
bool useDeprecatedZeroAsDefaultZOrder; ///< If true, objects created from
///< events will have 0 as Z order,
///< instead of the highest Z order
///< found on the layer at the scene
///< startup.
std::vector<std::unique_ptr<gd::Layout> > scenes; ///< List of all scenes
gd::VariablesContainer variables; ///< Initial global variables
std::vector<std::unique_ptr<gd::ExternalLayout> >
@@ -957,17 +1014,19 @@ class GD_CORE_API Project : public ObjectsContainer {
gd::String packageName; ///< Game package name
gd::String orientation; ///< Lock game orientation (on mobile devices).
///< "default", "landscape" or "portrait".
gd::String adMobAppId; ///< AdMob application ID.
bool
folderProject; ///< True if folder project, false if single file project.
gd::String gameFile; ///< File of the game
gd::String latestCompilationDirectory; ///< File of the game
gd::String
projectFile; ///< Path to the project file - when editing a local file.
gd::String latestCompilationDirectory;
gd::Platform*
currentPlatform; ///< The platform being used to edit the project.
gd::PlatformSpecificAssets platformSpecificAssets;
gd::LoadingScreen loadingScreen;
std::vector<std::unique_ptr<gd::ExternalEvents> >
externalEvents; ///< List of all externals events
externalEvents; ///< List of all externals events
ExtensionProperties
extensionProperties; ///< The properties of the extensions.
mutable unsigned int gdMajorVersion; ///< The GD major version used the last
///< time the project was saved.
mutable unsigned int gdMinorVersion; ///< The GD minor version used the last

View File

@@ -4,7 +4,9 @@
* reserved. This project is released under the MIT License.
*/
#include "PropertyDescriptor.h"
#include <vector>
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
@@ -45,4 +47,27 @@ void PropertyDescriptor::UnserializeFrom(const SerializerElement& element) {
: false;
}
void PropertyDescriptor::SerializeValuesTo(SerializerElement& element) const {
element.AddChild("value").SetStringValue(currentValue);
SerializerElement& extraInformationElement =
element.AddChild("extraInformation");
extraInformationElement.ConsiderAsArray();
for (const gd::String& information : extraInformation) {
extraInformationElement.AddChild("").SetStringValue(information);
}
}
void PropertyDescriptor::UnserializeValuesFrom(
const SerializerElement& element) {
currentValue = element.GetChild("value").GetStringValue();
extraInformation.clear();
const SerializerElement& extraInformationElement =
element.GetChild("extraInformation");
extraInformationElement.ConsiderAsArray();
for (std::size_t i = 0; i < extraInformationElement.GetChildrenCount(); ++i)
extraInformation.push_back(
extraInformationElement.GetChild(i).GetStringValue());
}
} // namespace gd

View File

@@ -6,6 +6,7 @@
#ifndef GDCORE_PROPERTYDESCRIPTOR
#define GDCORE_PROPERTYDESCRIPTOR
#include <vector>
#include "GDCore/String.h"
namespace gd {
class SerializerElement;
@@ -120,6 +121,16 @@ class GD_CORE_API PropertyDescriptor {
* \brief Unserialize the PropertyDescriptor.
*/
virtual void UnserializeFrom(const SerializerElement& element);
/**
* \brief Serialize only the value and extra informations.
*/
virtual void SerializeValuesTo(SerializerElement& element) const;
/**
* \brief Unserialize only the value and extra informations.
*/
virtual void UnserializeValuesFrom(const SerializerElement& element);
///@}
private:
@@ -127,7 +138,7 @@ class GD_CORE_API PropertyDescriptor {
gd::String
type; ///< The type of the property. This is arbitrary and interpreted by
///< the class responsible for updating the property grid.
gd::String label; //< The user-friendly property name
gd::String label; //< The user-friendly property name
gd::String description; //< The user-friendly property description
std::vector<gd::String>
extraInformation; ///< Can be used to store for example the available

View File

@@ -5,8 +5,10 @@
*/
#include "GDCore/Project/ResourcesManager.h"
#include <iostream>
#include <map>
#include "GDCore/CommonTools.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
@@ -20,6 +22,7 @@ namespace gd {
gd::String Resource::badStr;
Resource ResourcesManager::badResource;
gd::String ResourcesManager::badResourceName;
#if defined(GD_IDE_ONLY)
ResourceFolder ResourcesManager::badFolder;
Resource ResourceFolder::badResource;
@@ -90,6 +93,33 @@ bool ResourcesManager::HasResource(const gd::String& name) const {
return false;
}
const gd::String& ResourcesManager::GetResourceNameWithOrigin(
const gd::String& originName, const gd::String& originIdentifier) const {
for (const auto& resource : resources) {
if (!resource) continue;
if (resource->GetOriginName() == originName &&
resource->GetOriginIdentifier() == originIdentifier) {
return resource->GetName();
}
}
return badResourceName;
}
const gd::String& ResourcesManager::GetResourceNameWithFile(
const gd::String& file) const {
for (const auto& resource : resources) {
if (!resource) continue;
if (resource->GetFile() == file) {
return resource->GetName();
}
}
return badResourceName;
}
std::vector<gd::String> ResourcesManager::GetAllResourceNames() const {
std::vector<gd::String> allResources;
for (std::size_t i = 0; i < resources.size(); ++i)
@@ -99,14 +129,13 @@ std::vector<gd::String> ResourcesManager::GetAllResourceNames() const {
}
#if defined(GD_IDE_ONLY)
std::map<gd::String, gd::PropertyDescriptor> Resource::GetProperties(
gd::Project& project) const {
std::map<gd::String, gd::PropertyDescriptor> Resource::GetProperties() const {
std::map<gd::String, gd::PropertyDescriptor> nothing;
return nothing;
}
std::map<gd::String, gd::PropertyDescriptor> ImageResource::GetProperties(
gd::Project& project) const {
std::map<gd::String, gd::PropertyDescriptor> ImageResource::GetProperties()
const {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[_("Smooth the image")]
.SetValue(smooth ? "true" : "false")
@@ -119,8 +148,7 @@ std::map<gd::String, gd::PropertyDescriptor> ImageResource::GetProperties(
}
bool ImageResource::UpdateProperty(const gd::String& name,
const gd::String& value,
gd::Project& project) {
const gd::String& value) {
if (name == _("Smooth the image"))
smooth = value == "1";
else if (name == _("Always loaded in memory"))
@@ -416,6 +444,15 @@ void ResourcesManager::UnserializeFrom(const SerializerElement& element) {
std::shared_ptr<Resource> resource = CreateResource(kind);
resource->SetName(name);
resource->SetMetadata(metadata);
if (resourceElement.HasChild("origin")) {
gd::String originName =
resourceElement.GetChild("origin").GetStringAttribute("name", "");
gd::String originIdentifier =
resourceElement.GetChild("origin").GetStringAttribute("identifier",
"");
resource->SetOrigin(originName, originIdentifier);
}
resource->UnserializeFrom(resourceElement);
resources.push_back(resource);
@@ -447,6 +484,14 @@ void ResourcesManager::SerializeTo(SerializerElement& element) const {
resourceElement.SetAttribute("name", resources[i]->GetName());
resourceElement.SetAttribute("metadata", resources[i]->GetMetadata());
const gd::String& originName = resources[i]->GetOriginName();
const gd::String& originIdentifier = resources[i]->GetOriginIdentifier();
if (!originName.empty() || !originIdentifier.empty()) {
resourceElement.AddChild("origin")
.SetAttribute("name", originName)
.SetAttribute("identifier", originIdentifier);
}
resources[i]->SerializeTo(resourceElement);
}
@@ -563,8 +608,8 @@ void JsonResource::SerializeTo(SerializerElement& element) const {
element.SetAttribute("disablePreload", IsPreloadDisabled());
}
std::map<gd::String, gd::PropertyDescriptor> JsonResource::GetProperties(
gd::Project& project) const {
std::map<gd::String, gd::PropertyDescriptor> JsonResource::GetProperties()
const {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties["disablePreload"]
.SetValue(disablePreload ? "true" : "false")
@@ -575,8 +620,7 @@ std::map<gd::String, gd::PropertyDescriptor> JsonResource::GetProperties(
}
bool JsonResource::UpdateProperty(const gd::String& name,
const gd::String& value,
gd::Project& project) {
const gd::String& value) {
if (name == "disablePreload") disablePreload = value == "1";
return true;

View File

@@ -8,6 +8,7 @@
#include <map>
#include <memory>
#include <vector>
#include "GDCore/String.h"
namespace gd {
class Project;
@@ -78,6 +79,17 @@ class GD_CORE_API Resource {
*/
virtual void SetFile(const gd::String& newFile){};
/**
* TODO: make a ResourceOrigin object?
*/
virtual void SetOrigin(const gd::String& originName_, const gd::String& originIdentifier_) {
originName = originName_;
originIdentifier = originIdentifier_;
}
virtual const gd::String& GetOriginName() const { return originName; }
virtual const gd::String& GetOriginIdentifier() const { return originIdentifier; }
/**
* \brief Set the metadata (any string) associated to the resource.
* \note Can be used by external editors to store extra information, for
@@ -112,8 +124,7 @@ class GD_CORE_API Resource {
* \return a std::map with properties names as key.
* \see gd::PropertyDescriptor
*/
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
gd::Project& project) const;
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
/**
* \brief Called when the IDE wants to update a custom property of the
@@ -122,8 +133,7 @@ class GD_CORE_API Resource {
* \return false if the new value cannot be set
*/
virtual bool UpdateProperty(const gd::String& name,
const gd::String& value,
gd::Project& project) {
const gd::String& value) {
return false;
};
///@}
@@ -143,6 +153,8 @@ class GD_CORE_API Resource {
gd::String kind;
gd::String name;
gd::String metadata;
gd::String originName;
gd::String originIdentifier;
bool userAdded; ///< True if the resource was added by the user, and not
///< automatically by GDevelop.
@@ -178,11 +190,9 @@ class GD_CORE_API ImageResource : public Resource {
#if defined(GD_IDE_ONLY)
virtual bool UseFile() override { return true; }
std::map<gd::String, gd::PropertyDescriptor> GetProperties(
gd::Project& project) const override;
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
bool UpdateProperty(const gd::String& name,
const gd::String& value,
gd::Project& project) override;
const gd::String& value) override;
/**
* \brief Serialize the object
@@ -315,11 +325,9 @@ class GD_CORE_API JsonResource : public Resource {
#if defined(GD_IDE_ONLY)
virtual bool UseFile() override { return true; }
std::map<gd::String, gd::PropertyDescriptor> GetProperties(
gd::Project& project) const override;
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
bool UpdateProperty(const gd::String& name,
const gd::String& value,
gd::Project& project) override;
const gd::String& value) override;
void SerializeTo(SerializerElement& element) const override;
#endif
@@ -359,6 +367,18 @@ class GD_CORE_API ResourcesManager {
*/
bool HasResource(const gd::String& name) const;
/**
* \brief Return the name of the resource with the given origin, if any.
* If not found, an empty string is returned.
*/
const gd::String& GetResourceNameWithOrigin(const gd::String& originName, const gd::String& originIdentifier) const;
/**
* \brief Return the name of the first resource with the given file, if any.
* If not found, an empty string is returned.
*/
const gd::String& GetResourceNameWithFile(const gd::String& file) const;
/**
* \brief Return a reference to a resource.
*/
@@ -492,6 +512,7 @@ class GD_CORE_API ResourcesManager {
static ResourceFolder badFolder;
#endif
static Resource badResource;
static gd::String badResourceName;
};
#if defined(GD_IDE_ONLY)

View File

@@ -5,7 +5,9 @@
*/
#include "GDCore/Project/Variable.h"
#include <sstream>
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
#include "GDCore/TinyXml/tinyxml.h"
@@ -19,9 +21,7 @@ namespace gd {
*/
double Variable::GetValue() const {
if (!isNumber) {
stringstream ss;
ss << str;
ss >> value;
value = str.To<double>();
isNumber = true;
}
@@ -30,9 +30,7 @@ double Variable::GetValue() const {
const gd::String& Variable::GetString() const {
if (isNumber) {
stringstream s;
s << (value);
str = s.str();
str = gd::String::From(value);
isNumber = false;
}
@@ -76,6 +74,7 @@ const Variable& Variable::GetChild(const gd::String& name) const {
void Variable::RemoveChild(const gd::String& name) {
if (!isStructure) return;
children.erase(name);
isStructure = !children.empty();
}
bool Variable::RenameChild(const gd::String& oldName,
@@ -190,6 +189,7 @@ void Variable::RemoveRecursively(const gd::Variable& variableToRemove) {
it++;
}
}
isStructure = !children.empty();
}
Variable::Variable(const Variable& other)

View File

@@ -90,7 +90,7 @@ template <typename T>
void SPtrList<T>::Init(const gd::SPtrList<T>& other) {
elements.clear();
for (size_t i = 0; i < other.elements.size(); ++i)
elements.push_back(std::make_shared<T>(other[i]));
elements.push_back(CloneRememberingOriginalElement(other.elements[i]));
}
} // namespace gd

View File

@@ -0,0 +1,24 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_TOOLS_UUID_UUID_H
#define GDCORE_TOOLS_UUID_UUID_H
#include "GDCore/String.h"
#include "sole.h"
namespace gd {
namespace UUID {
/**
* Generate a random UUID v4
*/
inline gd::String MakeUuid4() { return gd::String::From(sole::uuid4()); }
} // namespace UUID
} // namespace gd
#endif

View File

@@ -0,0 +1,249 @@
/**
* Modified version of sole (https://github.com/r-lyeh-archived/sole) C++11 library
* to only generate UUID v4.
*
* Sole is a lightweight C++11 library to generate universally unique identificators.
* Sole provides interface for UUID versions 0, 1 and 4.
*
* https://github.com/r-lyeh/sole
* Copyright (c) 2013,2014,2015 r-lyeh. zlib/libpng licensed.
*
* Based on code by Dmitri Bouianov, Philip O'Toole, Poco C++ libraries and anonymous
* code found on the net. Thanks guys!
*
* Theory: (see Hoylen's answer at [1])
* - UUID version 1 (48-bit MAC address + 60-bit clock with a resolution of 100ns)
* Clock wraps in 3603 A.D.
* Up to 10000000 UUIDs per second.
* MAC address revealed.
*
* - UUID Version 4 (122-bits of randomness)
* See [2] or other analysis that describe how very unlikely a duplicate is.
*
* - Use v1 if you need to sort or classify UUIDs per machine.
* Use v1 if you are worried about leaving it up to probabilities (e.g. your are the
* type of person worried about the earth getting destroyed by a large asteroid in your
* lifetime). Just use a v1 and it is guaranteed to be unique till 3603 AD.
*
* - Use v4 if you are worried about security issues and determinism. That is because
* v1 UUIDs reveal the MAC address of the machine it was generated on and they can be
* predictable. Use v4 if you need more than 10 million uuids per second, or if your
* application wants to live past 3603 A.D.
* Additionally a custom UUID v0 is provided:
* - 16-bit PID + 48-bit MAC address + 60-bit clock with a resolution of 100ns since Unix epoch
* - Format is EPOCH_LOW-EPOCH_MID-VERSION(0)|EPOCH_HI-PID-MAC
* - Clock wraps in 3991 A.D.
* - Up to 10000000 UUIDs per second.
* - MAC address and PID revealed.
* References:
* - [1] http://stackoverflow.com/questions/1155008/how-unique-is-uuid
* - [2] http://en.wikipedia.org/wiki/UUID#Random%5FUUID%5Fprobability%5Fof%5Fduplicates
* - http://en.wikipedia.org/wiki/Universally_unique_identifier
* - http://en.cppreference.com/w/cpp/numeric/random/random_device
* - http://www.itu.int/ITU-T/asn1/uuid.html f81d4fae-7dec-11d0-a765-00a0c91e6bf6
* - rlyeh ~~ listening to Hedon Cries / Until The Sun Goes up
*/
//////////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <stdint.h>
#include <stdio.h> // for size_t; should be stddef.h instead; however, clang+archlinux fails when compiling it (@Travis-Ci)
#include <sys/types.h> // for uint32_t; should be stdint.h instead; however, GCC 5 on OSX fails when compiling it (See issue #11)
#include <functional>
#include <string>
// public API
namespace sole
{
// 128-bit basic UUID type that allows comparison and sorting.
// Use .str() for printing and .pretty() for pretty printing.
// Also, ostream friendly.
struct uuid
{
uint64_t ab;
uint64_t cd;
bool operator==( const uuid &other ) const;
bool operator!=( const uuid &other ) const;
bool operator <( const uuid &other ) const;
std::string base62() const;
std::string str() const;
template<typename ostream>
inline friend ostream &operator<<( ostream &os, const uuid &self ) {
return os << self.str(), os;
}
};
// Generators
uuid uuid4(); // UUID v4, pros: anonymous, fast; con: uuids "can clash"
// Rebuilders
uuid rebuild( uint64_t ab, uint64_t cd );
uuid rebuild( const std::string &uustr );
}
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4127)
#endif
namespace std {
template<>
struct hash< sole::uuid > {
public:
// hash functor: hash uuid to size_t value by pseudorandomizing transform
size_t operator()( const sole::uuid &uuid ) const {
if( sizeof(size_t) > 4 ) {
return size_t( uuid.ab ^ uuid.cd );
} else {
uint64_t hash64 = uuid.ab ^ uuid.cd;
return size_t( uint32_t( hash64 >> 32 ) ^ uint32_t( hash64 ) );
}
}
};
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
// implementation
#include <memory.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <random>
#include <sstream>
#include <string>
#include <vector>
#include <unistd.h>
inline bool sole::uuid::operator==( const sole::uuid &other ) const {
return ab == other.ab && cd == other.cd;
}
inline bool sole::uuid::operator!=( const sole::uuid &other ) const {
return !operator==(other);
}
inline bool sole::uuid::operator<( const sole::uuid &other ) const {
if( ab < other.ab ) return true;
if( ab > other.ab ) return false;
if( cd < other.cd ) return true;
return false;
}
namespace sole {
inline std::string uuid::str() const {
std::stringstream ss;
ss << std::hex << std::nouppercase << std::setfill('0');
uint32_t a = (ab >> 32);
uint32_t b = (ab & 0xFFFFFFFF);
uint32_t c = (cd >> 32);
uint32_t d = (cd & 0xFFFFFFFF);
ss << std::setw(8) << (a) << '-';
ss << std::setw(4) << (b >> 16) << '-';
ss << std::setw(4) << (b & 0xFFFF) << '-';
ss << std::setw(4) << (c >> 16 ) << '-';
ss << std::setw(4) << (c & 0xFFFF);
ss << std::setw(8) << d;
return ss.str();
}
inline std::string uuid::base62() const {
int base62len = 10 + 26 + 26;
const char base62[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
char res[24], *end = &res[24]; *(--end) = '\0';
uint64_t rem, AB = ab, CD = cd;
do {
rem = CD % base62len;
*--end = base62[int(rem)];
CD /= base62len;
} while (CD > 0);
*--end = '-';
do {
rem = AB % base62len;
*--end = base62[int(rem)];
AB /= base62len;
} while (AB > 0);
return end;
}
//////////////////////////////////////////////////////////////////////////////////////
// UUID implementations
inline uuid uuid4() {
static std::random_device rd;
static std::uniform_int_distribution<uint64_t> dist(0, (uint64_t)(~0));
uuid my;
my.ab = dist(rd);
my.cd = dist(rd);
my.ab = (my.ab & 0xFFFFFFFFFFFF0FFFULL) | 0x0000000000004000ULL;
my.cd = (my.cd & 0x3FFFFFFFFFFFFFFFULL) | 0x8000000000000000ULL;
return my;
}
inline uuid rebuild( uint64_t ab, uint64_t cd ) {
uuid u;
u.ab = ab; u.cd = cd;
return u;
}
inline uuid rebuild( const std::string &uustr ) {
char sep;
uint64_t a,b,c,d,e;
uuid u = { 0, 0 };
auto idx = uustr.find_first_of("-");
if( idx != std::string::npos ) {
// single separator, base62 notation
if( uustr.find_first_of("-",idx+1) == std::string::npos ) {
auto rebase62 = [&]( const char *input, size_t limit ) -> uint64_t {
int base62len = 10 + 26 + 26;
auto strpos = []( char ch ) -> size_t {
if( ch >= 'a' ) return ch - 'a' + 10 + 26;
if( ch >= 'A' ) return ch - 'A' + 10;
return ch - '0';
};
uint64_t res = strpos( input[0] );
for( size_t i = 1; i < limit; ++i )
res = base62len * res + strpos( input[i] );
return res;
};
u.ab = rebase62( &uustr[0], idx );
u.cd = rebase62( &uustr[idx+1], uustr.size() - (idx+1) );
}
// else classic hex notation
else {
std::stringstream ss( uustr );
if( ss >> std::hex >> a >> sep >> b >> sep >> c >> sep >> d >> sep >> e ) {
if( ss.eof() ) {
u.ab = (a << 32) | (b << 16) | c;
u.cd = (d << 48) | e;
}
}
}
}
return u;
}
} // ::sole

View File

@@ -84,6 +84,18 @@ void SetupProjectWithDummyPlatform(gd::Project &project,
.AddParameter("string", "")
.AddParameter("expression", "", "", true)
.SetFunctionName("getNumberWith3Params");
extension
->AddStrExpression("GetStringWith2ObjectParamAnd2ObjectVarParam",
"Get string with twice an object param and an objectvar param",
"",
"",
"")
.AddParameter("object", _("Object 1 parameter"))
.AddParameter("objectvar", _("Variable for object 1"))
.AddParameter("object", _("Object 2 parameter"))
.AddParameter("objectvar", _("Variable for object 2"))
.SetFunctionName("getStringWith2ObjectParamAnd2ObjectVarParam");
auto &object = extension->AddObject<gd::Object>(
"Sprite", "Dummy Sprite", "Dummy sprite object", "");
object

View File

@@ -4,6 +4,7 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "DummyPlatform.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
@@ -823,37 +824,41 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
}
SECTION("Valid object function name") {
auto node = parser.ParseExpression("string", "MyObject.MyFunc");
REQUIRE(node != nullptr);
auto &objectFunctionName = dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
REQUIRE(objectFunctionName.objectName == "MyObject");
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "MyFunc");
auto node = parser.ParseExpression("string", "MyObject.MyFunc");
REQUIRE(node != nullptr);
auto &objectFunctionName =
dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
REQUIRE(objectFunctionName.objectName == "MyObject");
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "MyFunc");
}
SECTION("Valid object behavior name") {
auto node = parser.ParseExpression("string", "MyObject.MyBehavior::MyFunc");
REQUIRE(node != nullptr);
auto &objectFunctionName = dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
REQUIRE(objectFunctionName.objectName == "MyObject");
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "MyBehavior");
REQUIRE(objectFunctionName.behaviorFunctionName == "MyFunc");
auto node = parser.ParseExpression("string", "MyObject.MyBehavior::MyFunc");
REQUIRE(node != nullptr);
auto &objectFunctionName =
dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
REQUIRE(objectFunctionName.objectName == "MyObject");
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "MyBehavior");
REQUIRE(objectFunctionName.behaviorFunctionName == "MyFunc");
}
SECTION("Unfinished object function name") {
auto node = parser.ParseExpression("string", "MyObject.");
REQUIRE(node != nullptr);
auto &objectFunctionName = dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
REQUIRE(objectFunctionName.objectName == "MyObject");
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "");
auto node = parser.ParseExpression("string", "MyObject.");
REQUIRE(node != nullptr);
auto &objectFunctionName =
dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
REQUIRE(objectFunctionName.objectName == "MyObject");
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "");
}
SECTION("Unfinished object behavior name") {
auto node = parser.ParseExpression("string", "MyObject.MyBehavior::");
REQUIRE(node != nullptr);
auto &objectFunctionName = dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
REQUIRE(objectFunctionName.objectName == "MyObject");
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "MyBehavior");
REQUIRE(objectFunctionName.behaviorFunctionName == "");
auto node = parser.ParseExpression("string", "MyObject.MyBehavior::");
REQUIRE(node != nullptr);
auto &objectFunctionName =
dynamic_cast<gd::ObjectFunctionNameNode &>(*node);
REQUIRE(objectFunctionName.objectName == "MyObject");
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "MyBehavior");
REQUIRE(objectFunctionName.behaviorFunctionName == "");
}
SECTION("Invalid function calls") {
@@ -948,7 +953,8 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
}
}
SECTION("Invalid behavior function call, finishing with namespace separator") {
SECTION(
"Invalid behavior function call, finishing with namespace separator") {
{
auto node = parser.ParseExpression("number", "MyObject.MyBehavior::(12)");
REQUIRE(node != nullptr);
@@ -1031,6 +1037,55 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
}
}
SECTION("Valid function call with object variable") {
{
// Note that in this test we need to use an expression with "objectvar",
// as the grammar of the parser depends on this parameter type
// information.
auto node = parser.ParseExpression(
"string",
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(MyObject1, "
"MyVar1, MyObject2, MyVar2)");
REQUIRE(node != nullptr);
auto &functionNode = dynamic_cast<gd::FunctionCallNode &>(*node);
auto &identifierObject1Node =
dynamic_cast<gd::IdentifierNode &>(*functionNode.parameters[0]);
auto &variable1Node =
dynamic_cast<gd::VariableNode &>(*functionNode.parameters[1]);
auto &identifierObject2Node =
dynamic_cast<gd::IdentifierNode &>(*functionNode.parameters[2]);
auto &variable2Node =
dynamic_cast<gd::VariableNode &>(*functionNode.parameters[3]);
REQUIRE(identifierObject1Node.identifierName == "MyObject1");
REQUIRE(identifierObject2Node.identifierName == "MyObject2");
REQUIRE(variable1Node.objectName == "MyObject1");
REQUIRE(variable1Node.name == "MyVar1");
REQUIRE(variable2Node.objectName == "MyObject2");
REQUIRE(variable2Node.name == "MyVar2");
}
}
SECTION("Invalid function call with object variable") {
{
// Note that in this test we need to use an expression with "objectvar",
// as the grammar of the parser depends on this parameter type
// information.
auto node = parser.ParseExpression(
"string",
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(My "
"badly/written object1, MyVar1, MyObject2, MyVar2)");
REQUIRE(node != nullptr);
gd::ExpressionValidator validator;
node->Visit(validator);
REQUIRE(validator.GetErrors().size() == 1);
REQUIRE(validator.GetErrors()[0]->GetMessage() ==
"An object name was expected but something else was written. "
"Enter just the name of the object for this parameter.");
}
}
SECTION("Fuzzy/random tests") {
{
auto testExpression = [&parser](const gd::String &expression) {

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

@@ -1,8 +1,9 @@
// @flow
/**
* This is a declaration of an extension for GDevelop 5.
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change
* to this extension file or to any other *.js file that you reference inside.
* 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
@@ -10,8 +11,19 @@
*
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
module.exports = {
createExtension: function(_, gd) {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
const extension = new gd.PlatformExtension();
extension.setExtensionInformation(
'AdMob',
@@ -23,6 +35,24 @@ module.exports = {
'MIT'
);
extension
.registerProperty('AdMobAppId')
.setLabel(_('AdMob App ID'))
.setDescription('ca-app-pub-XXXXXXXXXXXXXXXX/YYYYYYYYYY')
.setType('string');
extension
.addDependency()
.setName('AdMob Cordova Extension')
.setDependencyType('cordova')
.setExportName('cordova-plugin-admob-free')
.setVersion('~0.21.0')
.setExtraSetting(
'ADMOB_APP_ID',
new gd.PropertyDescriptor('AdMobAppId').setType('ExtensionProperty')
)
.onlyIfExtraSettingIsNonEmpty('ADMOB_APP_ID');
// Banner
extension
.addCondition(
@@ -355,7 +385,10 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function(gd, extension) {
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
return [];
},
};

View File

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

View File

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

View File

@@ -48,7 +48,7 @@ gd::String GetAnchorAsString(AnchorBehavior::VerticalAnchor anchor) {
} // namespace
std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
const gd::SerializerElement& behaviorContent, gd::Project& project) const {
const gd::SerializerElement& behaviorContent) const {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[_("relativeToOriginalWindowSize")]
@@ -129,8 +129,7 @@ AnchorBehavior::VerticalAnchor GetVerticalAnchorFromString(
bool AnchorBehavior::UpdateProperty(gd::SerializerElement& behaviorContent,
const gd::String& name,
const gd::String& value,
gd::Project& project) {
const gd::String& value) {
if (name == _("relativeToOriginalWindowSize"))
behaviorContent.SetAttribute("relativeToOriginalWindowSize", value == "1");
else if (name == _("Left edge anchor"))

View File

@@ -38,12 +38,10 @@ class GD_EXTENSION_API AnchorBehavior : public Behavior {
#if defined(GD_IDE_ONLY)
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
const gd::SerializerElement& behaviorContent,
gd::Project& project) const override;
const gd::SerializerElement& behaviorContent) const override;
virtual bool UpdateProperty(gd::SerializerElement& behaviorContent,
const gd::String& name,
const gd::String& value,
gd::Project& project) override;
const gd::String& value) override;
#endif
virtual void InitializeContent(

View File

@@ -40,6 +40,26 @@ gdjs.AnchorRuntimeBehavior.VerticalAnchor = {
PROPORTIONAL: 3
};
gdjs.AnchorRuntimeBehavior.prototype.updateFromBehaviorData = function(oldBehaviorData, newBehaviorData) {
if (oldBehaviorData.leftEdgeAnchor !== newBehaviorData.leftEdgeAnchor) {
this._leftEdgeAnchor = newBehaviorData.leftEdgeAnchor;
}
if (oldBehaviorData.rightEdgeAnchor !== newBehaviorData.rightEdgeAnchor) {
this._rightEdgeAnchor = newBehaviorData.rightEdgeAnchor;
}
if (oldBehaviorData.topEdgeAnchor !== newBehaviorData.topEdgeAnchor) {
this._topEdgeAnchor = newBehaviorData.topEdgeAnchor;
}
if (oldBehaviorData.bottomEdgeAnchor !== newBehaviorData.bottomEdgeAnchor) {
this._bottomEdgeAnchor = newBehaviorData.bottomEdgeAnchor;
}
if (oldBehaviorData.relativeToOriginalWindowSize !== newBehaviorData.relativeToOriginalWindowSize) {
return false;
}
return true;
}
gdjs.AnchorRuntimeBehavior.prototype.onActivate = function() {
this._invalidDistances = true;
};

View File

@@ -1,8 +1,9 @@
// @flow
/**
* This is a declaration of an extension for GDevelop 5.
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change
* to this extension file or to any other *.js file that you reference inside.
* 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
@@ -11,8 +12,18 @@
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
module.exports = {
createExtension: function(_, gd) {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -27,7 +38,8 @@ module.exports = {
.setExtensionHelpPath('/objects/bbtext');
var objectBBText = new gd.ObjectJsImplementation();
objectBBText.updateProperty = function(
// $FlowExpectedError
objectBBText.updateProperty = function (
objectContent,
propertyName,
newValue
@@ -35,74 +47,69 @@ module.exports = {
if (propertyName in objectContent) {
if (typeof objectContent[propertyName] === 'boolean')
objectContent[propertyName] = newValue === '1';
else if (typeof objectContent[propertyName] === 'number')
objectContent[propertyName] = parseFloat(newValue);
else objectContent[propertyName] = newValue;
return true;
}
return false;
};
objectBBText.getProperties = function(objectContent) {
var objectProperties = new gd.MapStringPropertyDescriptor();
// $FlowExpectedError
objectBBText.getProperties = function (objectContent) {
const objectProperties = new gd.MapStringPropertyDescriptor();
objectProperties.set(
'text',
new gd.PropertyDescriptor(objectContent.text)
.setType('textarea')
.setLabel(_('BBCode text'))
);
objectProperties
.getOrCreate('text')
.setValue(objectContent.text)
.setType('textarea')
.setLabel(_('BBCode text'));
objectProperties.set(
'color',
new gd.PropertyDescriptor(objectContent.color)
.setType('color')
.setLabel(_('Base color'))
);
objectProperties
.getOrCreate('color')
.setValue(objectContent.color)
.setType('color')
.setLabel(_('Base color'));
objectProperties.set(
'opacity',
new gd.PropertyDescriptor(objectContent.opacity.toString())
.setType('number')
.setLabel(_('Opacity (0-255)'))
);
objectProperties
.getOrCreate('opacity')
.setValue(objectContent.opacity.toString())
.setType('number')
.setLabel(_('Opacity (0-255)'));
objectProperties.set(
'fontSize',
new gd.PropertyDescriptor(objectContent.fontSize)
.setType('number')
.setLabel(_('Base size'))
);
objectProperties
.getOrCreate('fontSize')
.setValue(objectContent.fontSize.toString())
.setType('number')
.setLabel(_('Base size'));
objectProperties.set(
'align',
new gd.PropertyDescriptor(objectContent.align)
.setType('choice')
.addExtraInfo('left')
.addExtraInfo('center')
.addExtraInfo('right')
.setLabel(_('Base alignment'))
);
objectProperties
.getOrCreate('align')
.setValue(objectContent.align)
.setType('choice')
.addExtraInfo('left')
.addExtraInfo('center')
.addExtraInfo('right')
.setLabel(_('Base alignment'));
objectProperties.set(
'fontFamily',
new gd.PropertyDescriptor(objectContent.fontFamily)
.setType('resource')
.addExtraInfo('font')
.setLabel(_('Base font family'))
);
objectProperties
.getOrCreate('fontFamily')
.setValue(objectContent.fontFamily)
.setType('resource')
.addExtraInfo('font')
.setLabel(_('Base font family'));
objectProperties.set(
'wordWrap',
new gd.PropertyDescriptor(objectContent.wordWrap ? 'true' : 'false')
.setType('boolean')
.setLabel(_('Word wrapping'))
);
objectProperties
.getOrCreate('wordWrap')
.setValue(objectContent.wordWrap ? 'true' : 'false')
.setType('boolean')
.setLabel(_('Word wrapping'));
objectProperties.set(
'visible',
new gd.PropertyDescriptor(objectContent.visible ? 'true' : 'false')
.setType('boolean')
.setLabel(_('Visible on start'))
);
objectProperties
.getOrCreate('visible')
.setValue(objectContent.visible ? 'true' : 'false')
.setType('boolean')
.setLabel(_('Visible on start'));
return objectProperties;
};
@@ -111,7 +118,7 @@ module.exports = {
text:
'[b]bold[/b] [i]italic[/i] [size=15]smaller[/size] [font=times]times[/font] font\n[spacing=12]spaced out[/spacing]\n[outline=yellow]outlined[/outline] [shadow=red]DropShadow[/shadow] ',
opacity: 255,
fontSize: '20',
fontSize: 20,
visible: true,
color: '#000000',
fontFamily: 'Arial',
@@ -120,7 +127,8 @@ module.exports = {
})
);
objectBBText.updateInitialInstanceProperty = function(
// $FlowExpectedError
objectBBText.updateInitialInstanceProperty = function (
objectContent,
instance,
propertyName,
@@ -130,7 +138,8 @@ module.exports = {
) {
return false;
};
objectBBText.getInitialInstanceProperties = function(
// $FlowExpectedError
objectBBText.getInitialInstanceProperties = function (
content,
instance,
project,
@@ -161,7 +170,7 @@ module.exports = {
* Useful for setting multiple generic properties.
*/
const addSettersAndGettersToObject = (gdObject, properties, objectName) => {
properties.forEach(property => {
properties.forEach((property) => {
const parameterType =
property.type === 'boolean' ? 'yesorno' : property.type;
@@ -173,8 +182,6 @@ module.exports = {
property.expressionLabel,
property.expressionDescription,
'',
'',
property.iconPath,
property.iconPath
)
.addParameter('object', objectName, objectName, false)
@@ -187,8 +194,6 @@ module.exports = {
property.expressionLabel,
property.expressionDescription,
'',
'',
property.iconPath,
property.iconPath
)
.addParameter('object', objectName, objectName, false)
@@ -392,13 +397,15 @@ module.exports = {
* of your extension behaviors/objects by instanciating behaviors/objects
* and setting the property to a given value.
*
* If you don't have any tests, you can simply return an empty array like this:
* `runExtensionSanityTests: function(gd, extension) { return []; }`
* If you don't have any tests, you can simply return an empty array.
*
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function(gd, extension) {
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
return [];
},
/**
@@ -406,7 +413,9 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function(objectsEditorService) {
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {
objectsEditorService.registerEditorConfiguration(
'BBText::BBText',
objectsEditorService.getDefaultObjectJsImplementationPropertiesEditor({
@@ -419,7 +428,9 @@ module.exports = {
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function(objectsRenderingService) {
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
const RenderedInstance = objectsRenderingService.RenderedInstance;
const PIXI = objectsRenderingService.PIXI;
const MultiStyleText = objectsRenderingService.requireModule(
@@ -454,6 +465,7 @@ module.exports = {
const bbTextStyles = {
default: {
// Use a default font family the time for the resource font to be loaded.
fontFamily: 'Arial',
fontSize: '24px',
fill: '#cccccc',
@@ -478,7 +490,7 @@ module.exports = {
/**
* Return the path to the thumbnail of the specified object.
*/
RenderedBBTextInstance.getThumbnail = function(
RenderedBBTextInstance.getThumbnail = function (
project,
resourcesLoader,
object
@@ -489,66 +501,51 @@ module.exports = {
/**
* This is called to update the PIXI object on the scene editor
*/
RenderedBBTextInstance.prototype.update = function() {
const rawText = this._associatedObject
.getProperties(this.project)
.get('text')
.getValue();
RenderedBBTextInstance.prototype.update = function () {
const properties = this._associatedObject.getProperties();
const rawText = properties.get('text').getValue();
if (rawText !== this._pixiObject.text) {
this._pixiObject.setText(rawText);
this._pixiObject.text = rawText;
}
const opacity = this._associatedObject
.getProperties(this.project)
.get('opacity')
.getValue();
const opacity = properties.get('opacity').getValue();
this._pixiObject.alpha = opacity / 255;
const color = this._associatedObject
.getProperties(this.project)
.get('color')
.getValue();
const color = properties.get('color').getValue();
this._pixiObject.textStyles.default.fill = color;
const fontSize = this._associatedObject
.getProperties(this.project)
.get('fontSize')
.getValue();
const fontSize = properties.get('fontSize').getValue();
this._pixiObject.textStyles.default.fontSize = `${fontSize}px`;
const fontResourceName = this._associatedObject
.getProperties(this.project)
.get('fontFamily')
.getValue();
const fontResourceName = properties.get('fontFamily').getValue();
if (this._fontResourceName !== fontResourceName) {
this._fontResourceName = fontResourceName;
this._pixiResourcesLoader
.loadFontFamily(this._project, fontResourceName)
.then(fontFamily => {
.then((fontFamily) => {
// Once the font is loaded, we can use the given fontFamily.
this._pixiObject.textStyles.default.fontFamily = fontFamily;
this._pixiObject.dirty = true;
})
.catch(err => {
.catch((err) => {
// Ignore errors
console.warn('Unable to load font family', err);
console.warn(
'Unable to load font family for RenderedBBTextInstance',
err
);
});
}
const wordWrap = this._associatedObject
.getProperties(this.project)
.get('wordWrap')
.getValue();
const wordWrap = properties.get('wordWrap').getValue() === 'true';
if (wordWrap !== this._pixiObject._style.wordWrap) {
this._pixiObject._style.wordWrap = wordWrap === 'true';
this._pixiObject._style.wordWrap = wordWrap;
this._pixiObject.dirty = true;
}
const align = this._associatedObject
.getProperties(this.project)
.get('align')
.getValue();
const align = properties.get('align').getValue();
if (align !== this._pixiObject._style.align) {
this._pixiObject._style.align = align;
this._pixiObject.dirty = true;
@@ -566,7 +563,7 @@ module.exports = {
const customWidth = this._instance.getCustomWidth();
if (
this._pixiObject &&
this._pixiObject.textStyles.default.wordWrapWidth !== customWidth
this._pixiObject._style.wordWrapWidth !== customWidth
) {
this._pixiObject._style.wordWrapWidth = customWidth;
this._pixiObject.dirty = true;
@@ -577,14 +574,14 @@ module.exports = {
/**
* Return the width of the instance, when it's not resized.
*/
RenderedBBTextInstance.prototype.getDefaultWidth = function() {
RenderedBBTextInstance.prototype.getDefaultWidth = function () {
return this._pixiObject.width;
};
/**
* Return the height of the instance, when it's not resized.
*/
RenderedBBTextInstance.prototype.getDefaultHeight = function() {
RenderedBBTextInstance.prototype.getDefaultHeight = function () {
return this._pixiObject.height;
};

View File

@@ -6,7 +6,7 @@
* @param {gdjs.BBTextRuntimeObject} runtimeObject The object to render
* @param {gdjs.RuntimeScene} runtimeScene The gdjs.RuntimeScene in which the object is
*/
gdjs.BBTextRuntimeObjectPixiRenderer = function(runtimeObject, runtimeScene) {
gdjs.BBTextRuntimeObjectPixiRenderer = function (runtimeObject, runtimeScene) {
this._object = runtimeObject;
// Load (or reset) the text
@@ -18,15 +18,17 @@ 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,
align: runtimeObject._align,
},
});
this._object.hidden = !runtimeObject._visible;
} else {
this.updateColor();
this.updateAlignment();
@@ -48,68 +50,73 @@ gdjs.BBTextRuntimeObjectPixiRenderer = function(runtimeObject, runtimeScene) {
this.updatePosition();
this.updateAngle();
this.updateOpacity();
this.updateVisible();
};
gdjs.BBTextRuntimeObjectRenderer = gdjs.BBTextRuntimeObjectPixiRenderer;
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.getRendererObject = function() {
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.getRendererObject = function () {
return this._pixiObject;
};
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateWordWrap = function() {
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateWordWrap = function () {
this._pixiObject._style.wordWrap = this._object._wordWrap;
this._pixiObject.dirty = true;
this.updatePosition();
};
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateWrappingWidth = function() {
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateWrappingWidth = function () {
this._pixiObject._style.wordWrapWidth = this._object._wrappingWidth;
this._pixiObject.dirty = true;
this.updatePosition();
};
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateText = function() {
this._pixiObject.setText(this._object._text);
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateText = function () {
this._pixiObject.text = this._object._text;
this.updatePosition();
};
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateColor = function() {
this._pixiObject.textStyles.default.fill = this._object._color;
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateColor = function () {
this._pixiObject.textStyles.default.fill = gdjs.rgbToHexNumber(
this._object._color[0],
this._object._color[1],
this._object._color[2]
);
this._pixiObject.dirty = true;
};
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateAlignment = function() {
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateAlignment = function () {
this._pixiObject._style.align = this._object._align;
this._pixiObject.dirty = true;
};
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateFontFamily = function() {
this._pixiObject.textStyles.default.fontFamily = this._object._fontFamily;
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateFontFamily = function () {
this._pixiObject.textStyles.default.fontFamily = this._object._runtimeScene
.getGame()
.getFontManager()
.getFontFamily(this._object._fontFamily);
this._pixiObject.dirty = true;
};
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateFontSize = function() {
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateFontSize = function () {
this._pixiObject.textStyles.default.fontSize = this._object._fontSize + 'px';
this._pixiObject.dirty = true;
};
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updatePosition = function() {
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updatePosition = function () {
this._pixiObject.position.x = this._object.x + this._pixiObject.width / 2;
this._pixiObject.position.y = this._object.y + this._pixiObject.height / 2;
};
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateVisible = function() {
this._pixiObject.hidden = !this._object._visible;
};
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateAngle = function() {
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateAngle = function () {
this._pixiObject.rotation = gdjs.toRad(this._object.angle);
};
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateOpacity = function() {
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.updateOpacity = function () {
this._pixiObject.alpha = this._object._opacity / 255;
};
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.getWidth = function() {
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.getWidth = function () {
return this._pixiObject.width;
};
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.getHeight = function() {
gdjs.BBTextRuntimeObjectPixiRenderer.prototype.getHeight = function () {
return this._pixiObject.height;
};

View File

@@ -2,7 +2,7 @@
* @typedef {Object} BBTextObjectDataType Base parameters for {@link gdjs.BBTextRuntimeObject}
* @property {Object} content The base parameters of the BBText
* @property {number} content.opacity The opacity of the BBText
* @property {boolean} content.visible Is the text visible?
* @property {boolean} content.visible Deprecated - Is the text visible?
* @property {string} content.text Content of the text
* @property {string} content.color The color of the text
* @property {string} content.fontFamily The font of the text
@@ -25,17 +25,17 @@ gdjs.BBTextRuntimeObject = function(runtimeScene, objectData) {
gdjs.RuntimeObject.call(this, runtimeScene, objectData);
/** @type {number} */
this._opacity = objectData.content.opacity;
/** @type {boolean} */
this._visible = objectData.content.visible;
this._opacity = parseFloat(objectData.content.opacity);
// 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} */
this._fontSize = objectData.content.fontSize;
this._fontSize = parseFloat(objectData.content.fontSize);
// parseFloat should not be required, but GDevelop 5.0 beta 92 and below were storing it as a string.
/** @type {boolean} */
this._wordWrap = objectData.content.wordWrap;
/** @type {number} */
@@ -46,9 +46,12 @@ gdjs.BBTextRuntimeObject = function(runtimeScene, objectData) {
if (this._renderer)
gdjs.BBTextRuntimeObjectRenderer.call(this._renderer, this, runtimeScene);
else
/** @type {gdjs.BBTextRuntimeObjectRenderer} */
this._renderer = new gdjs.BBTextRuntimeObjectRenderer(this, runtimeScene);
// While this should rather be exposed as a property for all objects, honor the "visible"
// property that is specific to this object.
this.hidden = !objectData.content.visible;
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
this.onCreated();
};
@@ -58,18 +61,58 @@ 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();
};
/**
* @param {BBTextObjectDataType} oldObjectData
* @param {BBTextObjectDataType} newObjectData
*/
gdjs.BBTextRuntimeObject.prototype.updateFromObjectData = function(oldObjectData, newObjectData) {
if (oldObjectData.content.opacity !== newObjectData.content.opacity) {
this.setOpacity(newObjectData.content.opacity);
}
if (oldObjectData.content.visible !== newObjectData.content.visible) {
this.hide(!newObjectData.content.visible);
}
if (oldObjectData.content.text !== newObjectData.content.text) {
this.setBBText(newObjectData.content.text);
}
if (oldObjectData.content.color !== newObjectData.content.color) {
this._color = gdjs.BBTextRuntimeObject.hexToRGBColor(newObjectData.content.color);
this._renderer.updateColor();
}
if (oldObjectData.content.fontFamily !== newObjectData.content.fontFamily) {
this.setFontFamily(newObjectData.content.fontFamily);
}
if (oldObjectData.content.fontSize !== newObjectData.content.fontSize) {
this.setFontSize(newObjectData.content.fontSize);
}
if (oldObjectData.content.wordWrap !== newObjectData.content.wordWrap) {
this.setWordWrap(newObjectData.content.wordWrap);
}
if (oldObjectData.content.align !== newObjectData.content.align) {
this.setAlignment(newObjectData.content.align);
}
return true;
};
/**
* Initialize the extra parameters that could be set for an instance.
* @private
*/
gdjs.BBTextRuntimeObject.prototype.extraInitializationFromInitialInstance = function(initialInstanceData) {
// The wrapping width value (this._wrappingWidth) is using the object's width as an innitial value
if (initialInstanceData.customSize)
this.setWrappingWidth(initialInstanceData.width);
else
this.setWrappingWidth(250); // This value is the default wrapping width of the runtime object.
};
gdjs.BBTextRuntimeObject.prototype.onDestroyFromScene = function(runtimeScene) {
@@ -77,13 +120,16 @@ gdjs.BBTextRuntimeObject.prototype.onDestroyFromScene = function(runtimeScene) {
};
/**
* Set/Get BBText base style properties
* Set the markup text to display.
*/
gdjs.BBTextRuntimeObject.prototype.setBBText = function(text) {
this._text = text;
this._renderer.updateText();
};
/**
* Get the markup text displayed by the object.
*/
gdjs.BBTextRuntimeObject.prototype.getBBText = function() {
return this._text;
};
@@ -91,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

@@ -1,9 +1,67 @@
This extension is using release version 0.8.0 (commit 336bed0b206043e2c3e81c373b7ca02094ecabe7) of the pixi-multistyle-text library:
https://github.com/tleunen/pixi-multistyle-text
# pixi-multistyle-text
The BBcode tag feature was especially added for Gdevelop and this extension (commit 2a7be2084598933502c76419d7a86c0e6cd11719)
[![NPM](https://nodei.co/npm/pixi-multistyle-text.png)](https://nodei.co/npm/pixi-multistyle-text/)
README:
Add a MultiStyleText object inside pixi.js to easily create text using different styles.
Add a `MultiStyleText` object inside [pixi.js](https://github.com/GoodBoyDigital/pixi.js) to easily create text using different styles.
License: MIT
## Example
In the example below, we are defining 4 text styles.
`default` is the default style for the text, and the others matches the tags inside the text.
```js
let text = new MultiStyleText("Let's make some <ml>multiline</ml>\nand <ms>multistyle</ms> text for\n<pixi>Pixi.js!</pixi>",
{
"default": {
fontFamily: "Arial",
fontSize: "24px",
fill: "#cccccc",
align: "center"
},
"ml": {
fontStyle: "italic",
fill: "#ff8888"
},
"ms": {
fontStyle: "italic",
fill: "#4488ff"
},
"pixi": {
fontSize: "64px",
fill: "#efefef"
}
});
```
## Build instructions
```
$ yarn install
$ yarn build
```
## Usage
### `text = new MultiStyleText(text, textStyles)`
Creates a new `MultiStyleText` with the given text and styles.
#### `textStyles`
Type: `{ [key: string]: ExtendedTextStyle }`
Each key of this dictionary should match with a tag in the text. Use the key `default` for the default style.
Each `ExtendedTextStyle` object can have [any of the properties of a standard PIXI text style](http://pixijs.download/release/docs/PIXI.TextStyle.html), in addition to a `valign` property that allows you to specify where text is rendered relative to larger text on the same line (`"top"`, `"middle"`, or `"bottom"`).
The `align`, `wordWrap`, `wordWrapWidth`, and `breakWord` properties are ignored on all styles _except for the `default` style_, which controls those properties for the entire text object.
If text is rendered without any value assigned to a given parameter, Pixi's defaults are used.
## Demo
```
$ yarn demo
```
## License
MIT, see [LICENSE.md](http://github.com/tleunen/pixi-multistyle-text/blob/master/LICENSE.md) for details.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,58 @@
// @flow
/**
* This is a declaration of an extension for GDevelop 5.
*
* Changes in this file are watched and automatically imported if the editor
* is running. You can also manually run `node import-GDJS-Runtime.js` (in newIDE/app/scripts).
*
* The file must be named "JsExtension.js", otherwise GDevelop won't load it.
* ⚠️ If you make a change and the extension is not loaded, open the developer console
* and search for any errors.
*
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
module.exports = {
createExtension: function(_/*: (string) => string */, gd/*: libGDevelop */) {
const extension = new gd.PlatformExtension();
extension.setExtensionInformation(
'DebuggerTools',
_('Debugger Tools'),
_(
'Allow to interact with the editor debugger from the game.'
),
'Arthur Pacaud (arthuro555)',
'MIT'
);
extension
.addAction(
'Pause',
_('Pause game execution'),
_(
'This pauses the game, useful for inspecting the game state through the debugger. ' +
'Note that events will be still executed until the end before the game is paused.'
),
_('Pause game execution'),
_('Debugger Tools'),
'res/actions/bug32.png',
'res/actions/bug32.png'
)
.addCodeOnlyParameter("currentScene", "")
.getCodeExtraInformation()
.setIncludeFile('Extensions/DebuggerTools/debuggertools.js')
.setFunctionName('gdjs.evtTools.debugger.pause');
return extension;
},
runExtensionSanityTests: function(gd /*: libGDevelop */, extension /*: gdPlatformExtension*/) {
return [];
},
}

View File

@@ -0,0 +1,19 @@
/**
* @file
* Tools for interacting with the debugger.
*/
/**
* The namespace containing tools to interact with the debugger.
* @namespace
*/
gdjs.evtTools.debugger = {};
/**
* Stop the game execution.
* @param {gdjs.RuntimeScene} runtimeScene - The current scene.
*/
gdjs.evtTools.debugger.pause = function(runtimeScene) {
runtimeScene.getGame().pause(true);
}

View File

@@ -18,7 +18,7 @@ void DestroyOutsideBehavior::InitializeContent(gd::SerializerElement& content) {
#if defined(GD_IDE_ONLY)
std::map<gd::String, gd::PropertyDescriptor>
DestroyOutsideBehavior::GetProperties(
const gd::SerializerElement& behaviorContent, gd::Project& project) const {
const gd::SerializerElement& behaviorContent) const {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties["extraBorder"]
@@ -33,8 +33,7 @@ DestroyOutsideBehavior::GetProperties(
bool DestroyOutsideBehavior::UpdateProperty(
gd::SerializerElement& behaviorContent,
const gd::String& name,
const gd::String& value,
gd::Project& project) {
const gd::String& value) {
if (name == "extraBorder")
behaviorContent.SetAttribute("extraBorder", value.To<double>());
else

View File

@@ -21,16 +21,14 @@ class GD_EXTENSION_API DestroyOutsideBehavior : public gd::Behavior {
public:
DestroyOutsideBehavior(){};
virtual ~DestroyOutsideBehavior(){};
virtual Behavior* Clone() const { return new DestroyOutsideBehavior(*this); }
virtual Behavior* Clone() const override { return new DestroyOutsideBehavior(*this); }
#if defined(GD_IDE_ONLY)
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
const gd::SerializerElement& behaviorContent,
gd::Project& project) const override;
const gd::SerializerElement& behaviorContent) const override;
virtual bool UpdateProperty(gd::SerializerElement& behaviorContent,
const gd::String& name,
const gd::String& value,
gd::Project& project) override;
const gd::String& value) override;
#endif
virtual void InitializeContent(

View File

@@ -20,6 +20,14 @@ gdjs.DestroyOutsideRuntimeBehavior = function(runtimeScene, behaviorData, owner)
gdjs.DestroyOutsideRuntimeBehavior.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
gdjs.registerBehavior("DestroyOutsideBehavior::DestroyOutside", gdjs.DestroyOutsideRuntimeBehavior);
gdjs.DestroyOutsideRuntimeBehavior.prototype.updateFromBehaviorData = function(oldBehaviorData, newBehaviorData) {
if (oldBehaviorData.extraBorder !== newBehaviorData.extraBorder) {
this._extraBorder = newBehaviorData.extraBorder;
}
return true;
}
gdjs.DestroyOutsideRuntimeBehavior.prototype.doStepPostEvents = function(runtimeScene) {
// TODO: This would better be done using the object AABB (getAABB), as (`getCenterX`;`getCenterY`) point

View File

@@ -1,17 +1,26 @@
// @flow
/**
* This is a declaration of an extension for GDevelop 5.
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change
* to this extension file or to any other *.js file that you reference inside.
*
* The file must be named "JsExtension.js", otherwise GDevelop won't load it.
*
* Changes in this file are watched and automatically imported if the editor
* is running. You can also manually run `node import-GDJS-Runtime.js` (in newIDE/app/scripts).
*
* The file must be named "JsExtension.js", otherwise GDevelop won't load it.
* ⚠️ If you make a change and the extension is not loaded, open the developer console
* and search for any errors.
*
*
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
module.exports = {
createExtension: function(_, gd) {
createExtension: function(_/*: (string) => string */, gd/*: libGDevelop */) {
const extension = new gd.PlatformExtension();
extension.setExtensionInformation(
"DeviceSensors",
@@ -445,5 +454,5 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function(gd, extension) { return []; },
runExtensionSanityTests: function(gd /*: libGDevelop */, extension /*: gdPlatformExtension*/) { return []; },
};

View File

@@ -1,17 +1,26 @@
// @flow
/**
* This is a declaration of an extension for GDevelop 5.
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change
* to this extension file or to any other *.js file that you reference inside.
*
* The file must be named "JsExtension.js", otherwise GDevelop won't load it.
*
* Changes in this file are watched and automatically imported if the editor
* is running. You can also manually run `node import-GDJS-Runtime.js` (in newIDE/app/scripts).
*
* The file must be named "JsExtension.js", otherwise GDevelop won't load it.
* ⚠️ If you make a change and the extension is not loaded, open the developer console
* and search for any errors.
*
*
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
module.exports = {
createExtension: function(_, gd) {
createExtension: function(_/*: (string) => string */, gd/*: libGDevelop */) {
const extension = new gd.PlatformExtension();
extension.setExtensionInformation(
"DeviceVibration",
@@ -23,6 +32,13 @@ module.exports = {
"Open source (MIT License)"
).setExtensionHelpPath("/all-features/device-vibration");
extension
.addDependency()
.setName('Vibration Cordova Extension')
.setDependencyType('cordova')
.setExportName('cordova-plugin-vibration')
.setVersion('3.1.1');
extension
.addAction(
"StartVibration",
@@ -75,5 +91,5 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function(gd, extension) { return []; },
runExtensionSanityTests: function(gd /*: libGDevelop */, extension /*: gdPlatformExtension*/) { return []; },
};

View File

@@ -1,8 +1,9 @@
// @flow
/**
* This is a declaration of an extension for GDevelop 5.
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change
* to this extension file or to any other *.js file that you reference inside.
* 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
@@ -10,8 +11,16 @@
*
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
module.exports = {
createExtension: function(_, gd) {
createExtension: function(_/*: (string) => string */, gd/*: libGDevelop */) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
@@ -45,7 +54,7 @@ module.exports = {
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/DialogueTree/dialoguetools.js')
.addIncludeFile('Extensions/DialogueTree/bondage.min.js')
.addIncludeFile('Extensions/DialogueTree/bondage.js/dist/bondage.min.js')
.setFunctionName('gdjs.dialogueTree.loadFromSceneVariable');
extension
@@ -69,7 +78,7 @@ module.exports = {
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/DialogueTree/dialoguetools.js')
.addIncludeFile('Extensions/DialogueTree/bondage.min.js')
.addIncludeFile('Extensions/DialogueTree/bondage.js/dist/bondage.min.js')
.setFunctionName('gdjs.dialogueTree.loadFromJsonFile');
extension
@@ -209,18 +218,52 @@ module.exports = {
extension
.addAction(
'SetVariable',
_('Set dialogue state variable'),
'SetStringVariable',
_('Set dialogue state string variable'),
_(
'Set dialogue state variable. Use this to set a variable that the dialogue data is using.'
'Set dialogue state string variable. Use this to set a variable that the dialogue data is using.'
),
_('Set dialogue state variable _PARAM0_ to _PARAM1_'),
_('Set dialogue state string variable _PARAM0_ to _PARAM1_'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('string', _('State Variable Name'), '', false)
.addParameter('expression', _('Variable Value'), '', false)
.addParameter('string', _('Variable string value'), '', false)
.getCodeExtraInformation()
.setFunctionName('gdjs.dialogueTree.setVariable');
extension
.addAction(
'SetNumberVariable',
_('Set dialogue state number variable'),
_(
'Set dialogue state number variable. Use this to set a variable that the dialogue data is using.'
),
_('Set dialogue state number variable _PARAM0_ to _PARAM1_'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('string', _('State Variable Name'), '', false)
.addParameter('expression', _('Variable number value'), '', true)
.getCodeExtraInformation()
.setFunctionName('gdjs.dialogueTree.setVariable');
extension
.addAction(
'SetBooleanVariable',
_('Set dialogue state boolean variable'),
_(
'Set dialogue state boolean variable. Use this to set a variable that the dialogue data is using.'
),
_('Set dialogue state boolean variable _PARAM0_ to _PARAM1_'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('string', _('State Variable Name'), '', false)
.addParameter('trueorfalse', _('Variable boolean value'), '', false)
.getCodeExtraInformation()
.setFunctionName('gdjs.dialogueTree.setVariable');
@@ -256,13 +299,27 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('gdjs.dialogueTree.loadState');
extension
.addAction(
'ClearState',
_('Clear dialogue state'),
_(
'Clear dialogue state. This resets all dialogue state accumulated by the player choices. Useful when the player is starting a new game.'
),
_('Clear dialogue state'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.getCodeExtraInformation()
.setFunctionName('gdjs.dialogueTree.clearState');
extension
.addStrExpression(
'LineText',
_('Get the current dialogue line text'),
_('Returns the current dialogue line text'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.getCodeExtraInformation()
@@ -274,7 +331,6 @@ module.exports = {
_('Get the number of options in an options line type'),
_('Get the number of options in an options line type'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.getCodeExtraInformation()
@@ -288,7 +344,6 @@ module.exports = {
"Get the text of an option from an Options line type, using the option's Number. The numbers start from 0."
),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('expression', _('Option Index Number'), '', false)
@@ -303,7 +358,6 @@ module.exports = {
"Get the text of all available options from an Options line type as a horizontal list. You can also pass the selected option's cursor string, which by default is ->"
),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('string', _('Options Selection Cursor'), '', false)
@@ -319,7 +373,6 @@ module.exports = {
"Get the text of all available options from an Options line type as a vertical list. You can also pass the selected option's cursor string, which by default is ->"
),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('string', _('Options Selection Cursor'), '', false)
@@ -335,7 +388,6 @@ module.exports = {
'Get the number of the currently selected option. Use this to help you render the option selection marker at the right place.'
),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.getCodeExtraInformation()
@@ -349,7 +401,6 @@ module.exports = {
'Get dialogue line text clipped by the typewriter effect. Use the "Scroll clipped text" action to control the typewriter effect.'
),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.getCodeExtraInformation()
@@ -361,7 +412,6 @@ module.exports = {
_('Get the title of the current branch of the running dialogue'),
_('Get the title of the current branch of the running dialogue'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.getCodeExtraInformation()
@@ -373,7 +423,6 @@ module.exports = {
_('Get the tags of the current branch of the running dialogue'),
_('Get the tags of the current branch of the running dialogue'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.getCodeExtraInformation()
@@ -385,7 +434,6 @@ module.exports = {
_('Get a tag of the current branch of the running dialogue via its index'),
_('Get a tag of the current branch of the running dialogue via its index'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('expression', _('Tag Index Number'), '', false)
@@ -400,7 +448,6 @@ module.exports = {
'Get the parameters of a command call - <<command withParameter anotherParameter>>'
),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('expression', _('parameter Index Number'), '', true)
@@ -413,7 +460,6 @@ module.exports = {
_('Get the number of parameters in the currently passed command'),
_('Get the number of parameters in the currently passed command'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.getCodeExtraInformation()
@@ -429,7 +475,6 @@ module.exports = {
'Get parameter from a Tag found by the branch contains tag condition'
),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('expression', _('parameter Index Number'), '', true)
@@ -442,7 +487,6 @@ module.exports = {
_('Get a list of all visited branches'),
_('Get a list of all visited branches'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.getCodeExtraInformation()
@@ -454,7 +498,6 @@ module.exports = {
_('Get the full raw text of the current branch'),
_('Get the full raw text of the current branch'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.getCodeExtraInformation()
@@ -466,7 +509,6 @@ module.exports = {
_('Get dialogue state value'),
_('Get dialogue state value'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('string', _('Variable Name'), '', false)
@@ -591,9 +633,9 @@ module.exports = {
extension
.addCondition(
'WasBranchVisited',
_('Branch title has been visited before'),
_('Check if the current branch has been visited before'),
_('Branch title _PARAM0_ has been visited before'),
_('Branch title has been visited'),
_('Check if a branch has been visited'),
_('Branch title _PARAM0_ has been visited'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
@@ -604,12 +646,12 @@ module.exports = {
extension
.addCondition(
'CompareDialogueStateVariable',
_('Compare dialogue state variable'),
'CompareDialogueStateStringVariable',
_('Compare dialogue state string variable'),
_(
'Compare dialogue state variable. Use this to trigger game events via dialogue variables.'
'Compare dialogue state string variable. Use this to trigger game events via dialogue variables.'
),
_('Dialogue state variable _PARAM0_ is equal to _PARAM1_'),
_('Dialogue state string variable _PARAM0_ is equal to _PARAM1_'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
@@ -619,6 +661,40 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('gdjs.dialogueTree.compareVariable');
extension
.addCondition(
'CompareDialogueStateNumberVariable',
_('Compare dialogue state number variable'),
_(
'Compare dialogue state number variable. Use this to trigger game events via dialogue variables.'
),
_('Dialogue state number variable _PARAM0_ is equal to _PARAM1_'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('string', _('State variable'), '', false)
.addParameter('expression', _('Equal to'), '', false)
.getCodeExtraInformation()
.setFunctionName('gdjs.dialogueTree.compareVariable');
extension
.addCondition(
'CompareDialogueStateBooleanVariable',
_('Compare dialogue state boolean variable'),
_(
'Compare dialogue state variable. Use this to trigger game events via dialogue variables.'
),
_('Dialogue state boolean variable _PARAM0_ is equal to _PARAM1_'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('string', _('State variable'), '', false)
.addParameter('trueorfalse', _('Equal to'), '', false)
.getCodeExtraInformation()
.setFunctionName('gdjs.dialogueTree.compareVariable');
extension
.addCondition(
'HasClippedTextScrollingCompleted',
@@ -636,7 +712,7 @@ module.exports = {
return extension;
},
runExtensionSanityTests: function(gd, extension) {
runExtensionSanityTests: function(gd /*: libGDevelop */, extension /*: gdPlatformExtension*/) {
return [];
},
};

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017 j hayley
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,66 @@
# bondage.js [![Build Status](https://travis-ci.org/jhayley/bondage.js.svg?branch=master)](https://travis-ci.org/jhayley/bondage.js)
[Yarn](https://github.com/InfiniteAmmoInc/Yarn) parser for Javascript, in the same vein as [YarnSpinner](https://github.com/thesecretlab/YarnSpinner).
# Usage
#### As a Web Tool
To run through your yarn files in your browser, go to http://hayley.zone/bondage.js, paste your yarn data in the field, then hit "compile".
#### As a Command Line Tool
Installation: `npm install -g bondage`
Now you can use the `bondage` command to run through Yarn files from the command line. You can load one or multiple files at a time. If you load multiple files and a two nodes are encountered with the same name, the node will be overwritten.
**Examples**
* Running a single file from the default start node (named "Start"): `bondage run yarnfile.json`
* Running a single file from the specified node name: `bondage run -s StartNode yarnfile.json`
* Running multiple files from the specified node name: `bondage run -s StartNode yarnfile1.json yarnfile2.json ...`
* See the compiled ast: `bondage compile --ast yarnfile.json`
* See the tokenized input: `bondage compile --tokens yarnfile.json`
#### As a Library
**Web**
Include [dist/bondage.min.js](https://github.com/jhayley/bondage.js/blob/master/dist/bondage.min.js) somewhere in your html, and the `bondage` variable will be added to the global scope. You can then access everything in the example below (such as `bondage.Runner`) through that variable.
**Node**
Installation: `npm install bondage`
```javascript
const fs = require('fs');
const bondage = require('bondage');
const runner = new bondage.Runner();
const yarnData = JSON.parse(fs.readFileSync('yarnFile.json'));
runner.load(yarnData);
// Loop over the dialogue from the node titled 'Start'
for (const result of runner.run('Start')) {
// Do something else with the result
if (result instanceof bondage.TextResult) {
console.log(result.text);
} else if (result instanceof bondage.OptionsResult) {
// This works for both links between nodes and shortcut options
console.log(result.options);
// Select based on the option's index in the array (if you don't select an option, the dialog will continue past them)
result.select(1);
} else if (result instanceof bondage.CommandResult) {
// If the text was inside <<here>>, it will get returned as a CommandResult string, which you can use in any way you want
console.log(result.text);
}
}
// Advance the dialogue manually from the node titled 'Start'
const d = runner.run('Start')
let result = d.next().value;
let nextResult = d.next().value;
// And so on
```
For usage of the yarn format itself, please see the [YarnSpinner Documentation](https://github.com/thesecretlab/YarnSpinner/tree/master/Documentation), everything there should carry here too (if something does not match up, please open an issue).

File diff suppressed because one or more lines are too long

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