Compare commits

...

173 Commits

Author SHA1 Message Date
Florian Rival
25acb603b4 Bump newIDE version 2021-09-07 19:29:02 +01:00
Florian Rival
27d4ead51e Update translations 2021-09-07 19:22:13 +01:00
Florian Rival
1704d196f9 Add script to easily download artifacts (useful when deploying a new release)
Don't show in changelog
2021-09-07 19:19:04 +01:00
D8H
d40e360b8a Add support for behaviors based on other behaviors ("behavior composition") (#2781)
* This allows [custom behaviors](http://wiki.compilgames.net/doku.php/gdevelop5/behaviors/events-based-behaviors), that you can create in your project or get from extensions, to require the presence of one or multiple other behaviors on an object.
  * This is an advanced feature that is helpful to create behaviors that are based on other. For example, a behavior "Platformer enemy" using the "Platformer object" behavior and adding specific actions, conditions and logic to make an enemy chase the player.
  * If you create a behavior and want to use this, just go to the properties of this behavior and add a new property. Choose the type "Required Behavior" for this property. You can then use this new behavior in the events of the behavior you just edited.
* To use a behavior based on another, you don't need to do anything special! Just add it to your object as usual: any missing behavior will be added to your object, so you can start using it immediately.
2021-09-06 19:51:42 +01:00
ClementPasteau
183a0bd08e Increase shader precision, allowing lights to be displayed correctly on iOS (#3017) 2021-09-06 17:43:45 +01:00
D8H
8780f2f415 Add tests for platformer objects on slope junctions (#3016)
Only show in developer changelog
2021-09-06 10:57:56 +01:00
Aurélien Vivet
5adb3c92ee Add "object" term in timer action for object (#3002)
* Add "object" term in timer action for object

* Change for other actions and conditions
2021-09-03 08:04:18 +00:00
D8H
a54ee812bd Improve performance of conditions of "Linked Objects" (#2995) 2021-08-31 21:29:11 +02:00
Aurélien Vivet
f8db01706d Increase the extension description text field height (#2997)
Don't show in changelog
2021-08-31 13:51:01 +02:00
Florian Rival
d9368921af Clean old examples JSON files (#2996)
Not used anymore (the web-app uses examples from resources.gdevelop-app.com)

Don't show in changelog
2021-08-30 16:17:20 +02:00
Florian Rival
12743f6f7e Prevent instances to have a negative width or height in the instances editor
* Note that this does not affect existing games that would use this incorrect behavior (which can create bugs)
2021-08-30 13:20:41 +02:00
Florian Rival
3d3048906e Fix crash when instances were resized on the scene editor after being set to a size of 0
Fix #2983, fix #2829
2021-08-30 12:16:47 +02:00
Ulises Freitas
413fbc529e Updated URL in credits (#2985)
Don't show in changelog
2021-08-28 16:48:28 +02:00
ClementPasteau
287ebd4244 Allow colors to be used for Behavior properties (#2980) 2021-08-27 15:45:46 +02:00
Florian Rival
f2199c8ab4 Clean unused exports/functions (#2978)
Don't show in changelog
2021-08-27 11:17:01 +02:00
ClementPasteau
64b63d4efa Rework the color fields to allow to enter colors as R;G;B directly in the field (#2972) 2021-08-27 10:34:55 +02:00
ClementPasteau
3820c2613a Allow behaviors to have a "string list" property like functions (#2968) 2021-08-25 10:05:30 +02:00
Arthur Pacaud
c42603bb29 Add multiple contributors to the credits (#2967) 2021-08-25 07:47:13 +02:00
ClementPasteau
b879d3043f Increase Flow hash table to avoid memory limitations (#2966)
Only show in developer changelog
2021-08-24 11:21:32 +02:00
ClementPasteau
8be448fd0e Allow rounding pixels when rendering on a project level (#2965) 2021-08-24 10:44:06 +02:00
Florian Rival
9535fbca0f Fix S3 upload on CircleCI (#2960)
aws cli was not properly installed even with the last fix. Now using the "official" commandline: https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-mac.html

Don't show in changelog
2021-08-23 14:03:01 +02:00
Harsimran Singh Virk
6667a0005c Remove deprecated/unmaintained Cocos2d-JS renderer files (#2956)
Only show in developer changelog
2021-08-23 12:27:47 +02:00
ClementPasteau
860faae853 Update newIDE deployment docs (#2900)
Don't show in changelog
2021-08-23 09:57:43 +02:00
Florian Rival
dd47c7f6c4 Fix installation of awscli on macOS on CircleCI for automatic builds (#2955)
Don't show in changelog
2021-08-20 16:42:48 +02:00
Aurélien Vivet
c4f76efbcd Fix some missing translations (#2953) 2021-08-20 16:23:02 +02:00
Florian Rival
56d9dc05f1 Add command to open the extension search in the command palette 2021-08-20 16:15:37 +02:00
Harsimran Singh Virk
599ccb677f Add support for visual effects ("shaders") on objects. (#2901)
* This allows to generate interesting visual effects, which can be controlled by events. For example, you can use an outline on an object to highlight, make the player glow when launching a spell, blur objects, etc...
* A new "effects" tab is now present in the objects editor. From there, you can add visual effects, that were already available for layers, customize them from this editor.
* Actions and conditions are available to manipulate effects and change their parameters during the game.
* Learn more on the wiki: http://wiki.compilgames.net/doku.php/gdevelop5/objects/effects

Co-authored-by: Florian Rival <Florian.Rival@gmail.com>
2021-08-20 15:01:06 +02:00
Florian Rival
b97f716c09 Improve events sheet wording for object boolean variables 2021-08-19 14:58:22 +02:00
Florian Rival
58917aec02 Improve typing of TestRuntimeObject (#2943)
Only show in developer changelog
2021-08-19 10:11:16 +02:00
Florian Rival
fdaba4a6d5 Auto cancel Semaphore builds on newer commits, even when running, for faster tests [skip ci]
Don't show in changelog
2021-08-19 10:01:09 +02:00
Florian Rival
d1f49cd1f7 Update Semaphore links [skip ci] 2021-08-18 15:39:32 +02:00
Florian Rival
71a9a3f1d0 Use Semaphore 2 to run the fast tests for each commit/PR (#2935)
Only show in developer changelog
2021-08-18 12:05:00 +02:00
Arthur Pacaud
9173e704be Move variable event tools to their own file (#2870)
Only show in developer changelog
2021-08-17 21:17:58 +02:00
Florian Rival
1a27f689e0 Remove deprecated/unused/unmaintained GDCpp code (#2930)
* This also includes extensions code.

Only show in developer changelog
2021-08-17 14:34:58 +02:00
Aurélien Vivet
ef198b2c64 Fix missing translations in the main menu bar (#2933) 2021-08-17 14:09:02 +02:00
Arthur Pacaud
d5039b5b51 Prevent variable value to be set to an invalid number ("NaN" ) in the variables editor 2021-08-17 12:19:08 +02:00
Florian Rival
4b19696523 Add missing extensions on the web-app (Screenshot, AdvancedWindow)
Don't show in changelog
2021-08-16 20:43:06 +02:00
Florian Rival
32978c22e8 Fix games crashing when an unknown action/condition was used (could come from a deleted extension) 2021-08-16 19:36:52 +02:00
Florian Rival
1f6f2701ff Fix variable dropdown not updated in the action/condition editor after editing variables 2021-08-16 16:42:43 +02:00
Florian Rival
fbf2340f00 Fix a crash when drag'n'dropping actions/conditions in custom behaviors 2021-08-16 16:37:59 +02:00
Florian Rival
4ff208b39f Allow again to choose the opacity of the grid in the scene editor
* Also fix an issue where a grid with the black color was not persisted properly.

Fix #2922 and fix #2918
2021-08-16 11:33:56 +02:00
Florian Rival
3d0a893c1c Autoclose beta 114 upgrade issue [skip ci] 2021-08-13 15:03:59 +02:00
Clément Pasteau
2581021a57 Ensure the deployment script stops on error 2021-08-13 10:39:23 +02:00
Clément Pasteau
e4fc065dc1 Bump newIDE Version 2021-08-12 17:27:30 +02:00
Florian Rival
d1f4d26e49 Fix color of grids in scene editor not properly persisted
* Also make the update real time (any change in the settings are shown directly in the editor)

Don't show the rest in the changelog:

* Add various Flow typings where missing (SetupGridDialog and various InstancesEditor files)
* Serialize the settings into a generic "EditorSetting" (so that the Project is agnostic of any editor related stuff)
* Rename uiSettings/options/LayoutEditorCanvasOptions to InstancesEditorSettings
  * Handle everything inside the IDE (so that the Project remains agnostic of any editor related stuff)

Note that in the future, this kind of EditorSetting that is stored inside the project could be moved to its own structure (living outside of the project file).
2021-08-12 17:05:32 +02:00
ClementPasteau
a1b840a4fa Add Release Ladder action to Platformer Object Behavior (#2892)
Allow a Platformer Object to simulate a "Release Ladder" action
2021-08-12 15:54:19 +02:00
Florian Rival
465629b688 Add a way to set the "extra info" of a parameter without automatic namespace addition for objects/behaviors
Don't show in changelog
2021-08-12 10:28:01 +02:00
ClementPasteau
38758c62c6 Improve Actions and Conditions search allowing typing mistakes (fuzzy) (#2891) 2021-08-11 17:40:20 +02:00
Aurélien Vivet
26f6e95e46 Show previews of image resources properly pixelated when smoothing is deactivated (#2882) 2021-08-09 17:09:58 +02:00
Aurélien Vivet
34abf8290e Bump newIDE version (#2880) 2021-08-07 14:33:54 +02:00
Aurélien Vivet
52677f5512 Show pixel art assets in the asset store as pixelated and larger (#2838) 2021-08-05 20:27:47 +02:00
ClementPasteau
df2b51bb1b Increase the NewIDE tests jest timeout (#2878)
Don't show in changelog
2021-08-05 15:12:52 +02:00
ClementPasteau
6b0ff984f2 Fix Panel Sprite initial opacity not being correctly applied (#2873)
Fix Panel Sprite initial opacity not being correctly applied
2021-08-05 14:25:43 +02:00
D8H
f4512242e4 Add an action to clear the shapes of a Shape Painter object on demand (#2868) 2021-08-04 13:10:29 +02:00
D8H
8beabbadef Add an action to forbid to jump again while in the air to the Platformer behavior. (#2872)
* This is useful if you want to allow to jump again in the air for a bit of time, and then forbid to jump again later (for example, to implement a "Coyote Time" feature to your player character)
2021-08-04 12:29:38 +02:00
Todor Imreorov
9491a8ed45 Fix buttons to save/load/change the file in Piskel sometimes not displayed properly (#2844) 2021-08-04 11:29:35 +02:00
D8H
f945dfd987 Fix an error log when the new instruction dialog opens (#2869)
Don't show in changelog
2021-08-04 09:35:04 +02:00
Florian Rival
ff42591354 Increase the GDJS tests Karma timeout (#2861)
Semaphore CI tests were sometimes timing out, notably the ones involving PixiJS and real resources to load.

Don't show in changelog
2021-08-03 16:20:35 +02:00
D8H
21fb93c66a Improve TypeScript types for the Shape Painter object (#2860)
Only show in developer changelog
2021-08-03 16:17:11 +02:00
Arthur Pacaud
068fbe653a Add new lines between functions back in TS files (#2859)
Only show in developer changelog
2021-08-03 14:35:07 +02:00
Florian Rival
80891dcc59 Fix readme link
[skip ci]
Don't show in changelog
2021-08-02 19:57:24 +02:00
ClementPasteau
34155d65f1 Fix color picker not shown for the action setting the color of a light object (#2857) 2021-08-02 19:01:16 +02:00
Florian Rival
18f22470ca Fix wrong icon shown intermittently in the extensions store 2021-08-01 20:22:24 +02:00
Florian Rival
92a8ebc58b Fix extra scrollbar on small screens when selecting an object or an action/condition in the events sheet 2021-08-01 19:11:29 +02:00
Florian Rival
565384e270 Fix unability to scroll when a lot of parameters were shown for an action or a condition 2021-08-01 19:11:29 +02:00
Florian Rival
8335b2edf9 Add continuous delivery: automatic macOS and Windows builds (#2854)
* This automatically builds the signed macOS app, the Windows exe and AppX, the Linux AppImage.
* This is only for master and any "experimental-build/xxx" branches.
* Only Travis CI and Semaphore CI are running tests, for all branches.
2021-07-31 18:12:19 +02:00
Aurélien Vivet
12c77d0455 Add thumbnails in the resources list (#2842) 2021-07-27 15:59:06 +02:00
Florian Rival
13b62a06eb Add option to allow building Android App Bundles that can be uploaded if you already published APKs with Play App Signing enabled for your game
* If you already opted in for "Play App Signing" in the Play Developer Console and published some APKs like this, you need to enable the new "Old upload key" option, in the Signing Option, before *each* packaging for Android.
* Read this [page to learn more](http://wiki.compilgames.net/doku.php/gdevelop5/publishing/android_and_ios/play-store/upgrading-from-apk-to-aab#done_you_can_now_upload_your_aab) and have step by step details of what to do to update your game.
* If you publish a new game with Android App Bundles, there is nothing to do!
2021-07-22 15:09:58 +01:00
Florian Rival
d27119d8ea Remove deprecated examples upload script from web-app deployment
Don't show in changelog
2021-07-21 17:25:40 +01:00
Florian Rival
dd3ff554d5 Upgrade AppVeyor CI to Node.js 14 (#2826)
[ci skip] [skip ci]
2021-07-20 23:36:56 +01:00
Florian Rival
287a17b634 Add a maximum size for the GDevelop logo so that it's not too big on large resolutions 2021-07-20 18:13:42 +01:00
Florian Rival
7dc477e29e Bump newIDE version 2021-07-20 15:53:20 +01:00
Florian Rival
8174bca3b1 Fix progress bar not shown if GDevelop logo was hidden
Don't show in changelog
2021-07-19 21:41:24 +01:00
Florian Rival
7f6388c6f5 Make the loading screen customizable (#2814)
* Allow to choose the style of the GDevelop logo (light, dark, colored or plain)
* Allow to choose the background color and an optional background image
* Allow to choose the size of the progress bar (with a minimum and maximum size)
* Allow to choose the duration of the fade in animations and the minimum time the loading screen is shown
* Use the **new preview button in the game properties** dialog to run a preview with the loading screen shown
2021-07-19 19:52:25 +01:00
Florian Rival
da3a099ff2 Fix increasing size of the project file whenever changes on a layer were cancelled
* This was because of a duplication of the "cameras" stored in the layer.
* Also add a check to clean project files with the problem.

Fix #2812
2021-07-17 11:56:04 +01:00
Florian Rival
7b2c7b4a00 Bump newIDE version 2021-07-15 18:06:49 +01:00
Florian Rival
f750a356c3 Add missing Flow annotations
Don't show in changelog
2021-07-15 14:50:02 +01:00
Florian Rival
611a72aee1 Fix focus not set when editing a mouse button field in the events sheet
* Also fix various missing Flow annotations
2021-07-14 22:46:18 +01:00
Florian Rival
1b965b65a4 Fix variables not shown properly in the debugger
* This removes toJSON method on gdjs.Variable. This was just introduced in beta 111, if you're using it, please use toJSObject instead and JSON.stringify.
2021-07-14 22:08:00 +01:00
Florian Rival
c077628eb4 Bump newIDE version 2021-07-14 18:12:06 +01:00
Leo_Red
f1a6da0cb2 Remove example issues auto close workflow (#2806)
Don't show in changelog
2021-07-14 14:42:35 +01:00
Aurélien Vivet
df4a780311 Give more consistency to the order of the buttons in the behaviors editor (#2803) 2021-07-13 22:48:58 +01:00
Florian Rival
8c955cf77a Remove useless "Behavior" text in the behaviors editor
Don't show in changelog
2021-07-13 16:15:51 +01:00
Florian Rival
17efae037c Fix crash when analyzing unused variables when a scene is depending on another scene 2021-07-13 16:09:01 +01:00
Florian Rival
f1120238ec Slightly improve rendering scheduling for games 2021-07-13 13:51:32 +01:00
Florian Rival
5d6a2bb3a0 Fix GDJS tests (regression since rework of GDJS build in the editor)
Don't show in changelog
2021-07-13 13:46:32 +01:00
Florian Rival
f3a49ad2cf Speed up GDJS build (including at editor startup) in development
This reduces the number of copied files (let esbuild build directly in the proper output folder).
Also avoid copying the source files after every change (avoiding ~3-4 seconds of copy).

Overall, a change in GDJS/Extensions results in 1-3 seconds of build, instead of almost 10 sometimes due to the large number of file copies.

Only show in developer changelog
2021-07-12 18:11:17 +01:00
Florian Rival
aac3379f59 Remove more deprecated strings from translations
Don't show in changelog
2021-07-12 14:30:28 +01:00
Florian Rival
49949189cf Remove deprecated strings from translations
Don't show in changelog
2021-07-12 11:50:29 +01:00
Florian Rival
977daa50fa Remove gcc from Travis CI matrix as too costly in build minutes
Don't show in changelog
2021-07-11 18:21:48 +01:00
Florian Rival
fd8a7df868 Fix wording 2021-07-11 17:16:04 +01:00
Florian Rival
303110ade5 Fix long description not shown for Yes/No and True/False parameter fields
Fix #2794
2021-07-11 17:16:04 +01:00
Florian Rival
cb15111d03 Display behavior icons in the behaviors editor
* Also better align some icons
* Show button to open the help page for all behaviors
2021-07-11 17:16:04 +01:00
Florian Rival
9db4d603a0 Refactor access to behavior/behavior shared data in the editor
Avoid having getters in the gd::Platform or the gd::Project, as they should not be responsible for this.
Instead, use gd::MetadataProvider to fetch the BehaviorMetadata.

Don't show in changelog
2021-07-11 17:16:04 +01:00
Florian Rival
6c7db9a948 Display extension icons in the project manager 2021-07-11 14:26:57 +01:00
Florian Rival
6b9a8f14e3 Center images in extension generated documentation pages
Don't show in changelog
2021-07-10 18:51:31 +01:00
Florian Rival
2f3a18046a Fix rendering of lists and author names in extensions generated documentation
Don't show in changelog
2021-07-10 18:46:17 +01:00
Florian Rival
812ff43905 Automatically generate pages on the wiki for the community extensions 2021-07-10 18:19:02 +01:00
Florian Rival
1a113004be Update extensions registry loading to use the GDevelop asset API instead of using GitHub directly
Don't show in changelog
2021-07-10 14:18:26 +01:00
Florian Rival
0dd10a7955 Improve extract changelog script
Don't show in changelog
2021-07-09 23:05:27 +01:00
Florian Rival
00b25461ed Fix "X" and "Y" expression for sprite objects (regression)
The default point being passed was incorrectly set as 0 instead of "" (empty string), which was misunderstood by the game engine as the origin point (which would be flipped)

Don't show in changelog
2021-07-09 15:32:48 +01:00
Florian Rival
9e28068e4f Fix Debugger Tools extension not available in the web-app 2021-07-08 20:01:07 +01:00
D8H
6b231f3eb6 Fix: instances editor no longer give unnecessary floating positions (#2790)
* Fix: Moving instances and resizing one instance no longer give floating positions or dimensions on 0° rotated instances.
Don't show in changelog
2021-07-07 20:12:14 +02:00
Florian Rival
2dd2c85f12 Update translations 2021-07-06 17:20:43 +01:00
Florian Rival
c61faa7e05 Clean up some dead code
Don't show in changelog
2021-07-06 17:13:00 +01:00
Florian Rival
1840f6f45a Save a bit of time at startup by avoiding to pre-fetch resources
Don't show in changelog
2021-07-06 15:54:12 +01:00
Florian Rival
b11eccfa22 Clarify in the list of effects that Kawase blur should be preferred over the classic Gaussian blur for performance 2021-07-06 15:53:37 +01:00
Florian Rival
9236608502 Fix broken sortable list of animations (regression)
Fix #2784

Don't show in changelog
2021-07-06 15:32:35 +01:00
Florian Rival
12a6bc23c3 Add an option to package games as Android App Bundles, to publish them on Google Play
* Starting from August, it will be mandatory to upload Android App Bundles to Google Play - APK files won't be accepted anymore.
2021-07-04 19:29:13 +01:00
Florian Rival
23c2b84707 Fix animation scrolling in the Sprite object editor on small screens 2021-07-03 13:00:32 +01:00
Florian Rival
adb4f2a6cf Fix animation editor preview speed being too fast on monitors with high refresh rate
* Also fix scrolling/zooming in the preview

Fix #2779
2021-07-03 12:03:18 +01:00
D8H
aa3ed78eda Improve selection in the scene editor so that multiple instances can be properly rotated and resized (#2751)
* When resizing or rotating multiple instances, they will keep their relative positions.
* When resizing rotated instances, their aspect ratio will be kept to avoid an unintuitive resize effect 
* This makes it easier to edit chunks of levels, scale them, resize them and rotate them.
2021-07-01 23:26:26 +01:00
Aurélien Vivet
efb8668077 Allow popups in the events sheet to be validated after a change using Ctrl+Enter (or Cmd+Enter on macOS) (#2569)
* Also add a preference to choose if Escape should cancel any changes made (like in a dialog) or not (like previously).
2021-06-30 22:03:19 +01:00
Florian Rival
8d763d4600 Put the button to restore the default collision mask in a split menu
This is because its usage is less frequent, so it does not eat the bottom space.
We can also now delete all polygons to restore the default masks, so its usage will decrease.
2021-06-25 14:11:30 +02:00
Aurélien Vivet
0cc1e57450 Put the button "add a behavior to the object" at the bottom of the list of behaviors (#2760)
* Also restore the default collision mask if all polygons are removed in the custom mask
2021-06-25 13:47:01 +02:00
Florian Rival
24c13e1022 Make the buttons at the bottom of the list of animations always visible in the Sprite editor 2021-06-22 11:52:52 +02:00
Florian Rival
965f7aab32 Fix getting the length of an object array always returning 0 2021-06-22 10:16:43 +02:00
Florian Rival
23c1f2423d Update badge to use travis-ci.com
Don't show in changelog
2021-06-17 09:30:49 +02:00
Arthur Pacaud
1d5eb8e529 Move JSON and JS variable conversions to gdjs.Variable (#2740)
Only show in developer changelog
2021-06-16 16:59:12 +01:00
D8H
8968ef34e2 Add Flow typing to the instances editor (#2745)
Only show in developer changelog
2021-06-16 16:50:51 +01:00
Arthur Pacaud
736ba023ff Add various DX improvements (#2741)
Only show in developer changelog
2021-06-16 16:22:30 +01:00
D8H
ade075f076 Reorganize pathfinding behavior actions and conditions in 2 groups (#2738) 2021-06-16 14:58:47 +01:00
Florian Rival
049c36b081 Fix tests 2021-06-16 08:44:46 +02:00
Florian Rival
3977e2b6f2 Fix formatting 2021-06-14 15:12:11 +01:00
Aurélien Vivet
f08f38bc3b Fix "NAN" shown for the cursor position when opening the scene editor (#2743) 2021-06-14 15:10:53 +01:00
D8H
127a881416 Add a condition and expression to check the movement angle for the pathfinding behavior (#2737) 2021-06-12 18:39:31 +01:00
Florian Rival
606143ff36 Fix typings 2021-06-12 15:53:17 +01:00
Florian Rival
05a68cb17f Fix behavior not always set correctly when editing parameters using the inline popover in the events sheet 2021-06-12 15:52:01 +01:00
Florian Rival
280377cc98 Fix RGB colors with a component at 0 not applied to the ambient light color
Fix #2734
2021-06-12 15:02:49 +01:00
Florian Rival
3c88c150d5 Fix effects container of an object not copied properly (and so erased when previewing)
This is a good example of why custom assignment ctor/copy operator should be avoided. In the case of gd::Object, it would have been better to encapsulate the behaviors in a "gd::BehaviorContentContainer", that would have custom assignement ctor/copy operator, so that we could then avoid specifying those for gd::Object.

Don't show in changelog
2021-06-12 02:08:34 +01:00
D8H
13471ad40a Add actions/conditions/expressions to specify an offset for the virtual grid used by the Pathfinding behavior (#2730) 2021-06-12 00:14:24 +01:00
Florian Rival
0d7d574f1b Fix action and condition to change the movement angle offset of the Top Down Movement behavior 2021-06-12 00:05:02 +01:00
D8H
19a10d7dab Add autocompletions for animation and points of Sprite objects (#2722)
* Both for the parameters of actions and inside expressions.
2021-06-11 23:27:44 +01:00
Arthur Pacaud
84e096f85d Update the IDE to Firebase v9 (to reduce the size of the Firebase module) (#2724)
Only show in developer changelog
2021-06-11 23:13:50 +01:00
Aurélien Vivet
40f5eb3e23 Remove unused argument (#2731)
Don't show in changelog
2021-06-11 11:17:00 +01:00
Arthur Pacaud
4948e16dd5 Add disconnection actions to the p2p extension (#2723) 2021-06-09 22:45:20 +01:00
D8H
2b38325d96 Ensure variables referenced in external events are shown in the autocompletions in the variables editor (#2717) 2021-06-09 21:29:20 +01:00
D8H
9a10caeeac Add autocompletion for variable names in expressions (#2692) 2021-06-07 09:16:12 +01:00
Florian Rival
a4be56a24b Add links when creating issues 2021-06-06 17:47:57 +01:00
Arthur Pacaud
fc8b724e3c Export extension dependencies exported when the extension is used (#2671)
* This for example allow to export the vibration extension only if it's used in events.

Only show in developer changelog
2021-06-06 16:45:47 +01:00
Aurélien Vivet
7e61419a36 Clean the examples folder (#2713)
Only show in developer changelog
2021-06-06 15:37:47 +01:00
Florian Rival
473661b8a2 Fix typings 2021-06-06 15:36:01 +01:00
Florian Rival
350fea08bf Enable serialization of effects in gd::Object
Don't show in changelog
2021-06-05 16:55:28 +01:00
D8H
4f9154549b Add autocompletion in expressions for scene names, layer names and parameters with choices (#2702) 2021-06-05 14:27:28 +01:00
Florian Rival
d9172ded36 Replace the list of examples by an "Example Library" (#2697)
* You can contribute to the examples library by submitting your new (or improved) examples on https://github.com/GDevelopApp/GDevelop-examples
2021-06-05 00:57:23 +01:00
Aurélien Vivet
aef8271a4e Specify type of variables in the events sheet sentences (#2701) 2021-06-02 21:33:29 +01:00
Harsimran Singh Virk
83db8ce272 Added Effects Container in gd::Object (#2683)
Only show in developer changelog
2021-05-31 22:22:08 +01:00
Florian Rival
e26c1470c1 Upgrade to Flow 0.131 (#2695)
Don't show in changelog
2021-05-31 22:19:13 +01:00
Florian Rival
4b382cb191 Allow to pass the path to GDJS to the extensions loader (#2694)
Useful for third party/external tools.

Don't show in changelog
2021-05-30 19:21:42 +01:00
Aurélien Vivet
6c631410f2 Fix the opacity value for BBText and Bitmap Text object, value is now clamped between 0 and 255 (#2693) 2021-05-30 18:44:04 +02:00
D8H
516b1d978c Fix platformer objects so that they can always grab a platform ledge even when multiple platforms are overlapping (#2686) 2021-05-28 22:09:50 +01:00
Arthur Pacaud
822146e5f1 Add an action to add a document in Firestore without having to specify a name (#2687) 2021-05-27 21:58:26 +01:00
Florian Rival
7b3987bae4 Upgrade TypeScript to version 4.3.2 for GDJS game engine (#2688)
Only show in developer changelog
2021-05-27 12:37:54 +01:00
Aurélien Vivet
506c029690 Fix events sheet showing "unknown instruction" when the action/condition editor is dismissed with a backdrop click (#2684) 2021-05-27 09:36:09 +01:00
Aurélien Vivet
b28e4e1230 Hide preferences in the web-app when they are not applicable for it (#2681) 2021-05-26 15:44:36 +01:00
Arthur Pacaud
c1edcbfa19 Add support for running queries in Firebase (#2610) 2021-05-26 09:48:16 +01:00
D8H
3125956dfc In the variables editor, add autocompletion for variables that are used in events but not yet defined in the list (#2665)
* This means that if you use a scene, global or object variable in your events, it will be suggested the next time you open the variables editor of the scene, project or of an object, when you enter the name of a new variable.
* Note that this works only for now for variables that are not arrays or structures.
2021-05-25 23:37:25 +01:00
Florian Rival
633c7bbd9d Fix color field warning
Don't show in changelog
2021-05-25 20:51:03 +01:00
Florian Rival
df92ea1ac9 Add a warning when trying to enter a color text with an extra quote
* See as an example: #2675
2021-05-25 20:41:04 +01:00
Aurélien Vivet
3eb571a03a Fix AABB and the positioning of the bitmap text object. 2021-05-25 20:57:41 +02:00
Aurélien Vivet
98303f7f50 Fix BitmapText height when the text is finishing with new lines (#2670) 2021-05-25 08:44:40 +01:00
Arthur Pacaud
34dfbbc294 Remove misleading descriptions of subscriptions (#2544)
Don't show in changelog
2021-05-24 21:49:32 +02:00
Harsimran Singh Virk
afbb316bd2 Refactor gd::Layer to use a gd::EffectsContainer (#2645)
Only show in developer changelog
2021-05-22 00:22:58 +01:00
Arthur Pacaud
b75945869c Add autocompletions for scene, layers and some parameter fields (#2663)
* Both display the scene names (or layer names, or valid choices, according to the field) and the autocompletions like a usual text expression - making it more obvious that you can use an expression here.
2021-05-22 00:07:34 +01:00
Aurélien Vivet
efb3f55885 Add a preference to display the preview window always on top of other windows (#2667) 2021-05-20 23:14:42 +02:00
Aurélien Vivet
82d2a4b5e4 Add padding option for effects on layers (#2658) 2021-05-18 16:25:01 +01:00
aphoenixholland
7748f3c48e Add support for tweening object color using Hue/Saturation/Lightness (HSL) (#2571)
* This is useful to make some effects or have a more natural color change.
2021-05-17 23:23:03 +01:00
D8H
80ddc9c1b7 Fix grid snapping at the object creation when the grid position is not an integer (#2648) 2021-05-15 20:22:50 +01:00
Arthur Pacaud
5d50c31e55 Add code snippets for Visual Studio Code (#2647)
Only show in developer changelog
2021-05-15 19:05:56 +01:00
Florian Rival
61a969fdb1 Bump newIDE version 2021-05-13 19:42:05 +01:00
Florian Rival
a14b8e8bcd Merge branch 'master' of github.com:4ian/GDevelop 2021-05-13 19:41:51 +01:00
D8H
faa37a4fd2 Update Link Tools examples to use the new link action (#2646) 2021-05-13 19:21:00 +01:00
Florian Rival
176efafe43 Increase the size before warning in the service worker
Don't show in changelog
2021-05-12 23:30:49 +01:00
3820 changed files with 31478 additions and 1195351 deletions

View File

@@ -1,9 +1,79 @@
# CircleCI 2.0 configuration file to build GDevelop app running
# on the Electron runtime (newIDE/electron-app).
# CircleCI configuration to build GDevelop app running
# on the Electron runtime (newIDE/electron-app) for macOS and Linux.
# For Windows, see the appveyor.yml file.
version: 2
version: 2.1
jobs:
build:
build-macos:
macos:
xcode: 12.5.1
steps:
- checkout
# System dependencies (for Emscripten and upload)
- run:
name: Install dependencies for Emscripten
command: brew install cmake
- run:
name: Install dependencies for AWS S3 upload
command: curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg" && sudo installer -pkg AWSCLIV2.pkg -target /
- run:
name: Install Emscripten (for GDevelop.js)
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 1.39.6 && ./emsdk activate 1.39.6 && cd ..
# GDevelop.js dependencies
- restore_cache:
keys:
- gd-macos-nodejs-dependencies-{{ checksum "newIDE/app/package.json" }}-{{ checksum "newIDE/electron-app/package.json" }}-{{ checksum "GDevelop.js/package.json" }}
# fallback to using the latest cache if no exact match is found
- gd-macos-nodejs-dependencies---
- run:
name: Install GDevelop.js dependencies and build it
command: cd GDevelop.js && npm install && cd ..
# Build GDevelop.js (and run tests to ensure it works)
- run:
name: Build GDevelop.js
command: cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build && npm test && cd ..
# GDevelop IDE dependencies (after building GDevelop.js to avoid downloading a pre-built version)
- run:
name: Install GDevelop IDE dependencies
command: cd newIDE/app && npm install && cd ../electron-app && npm install
- save_cache:
paths:
- newIDE/electron-app/node_modules
- newIDE/app/node_modules
- GDevelop.js/node_modules
key: gd-macos-nodejs-dependencies-{{ checksum "newIDE/app/package.json" }}-{{ checksum "newIDE/electron-app/package.json" }}-{{ checksum "GDevelop.js/package.json" }}
# Build GDevelop IDE (seems like we need to allow Node.js to use more space than usual)
# Note: Code signing is done using CSC_LINK (see https://www.electron.build/code-signing).
- run:
name: Build GDevelop IDE
command: export NODE_OPTIONS="--max-old-space-size=7168" && cd newIDE/electron-app && npm run build -- --mac --publish=never
- run:
name: Clean dist folder to keep only installers/binaries.
command: rm -rf "newIDE/electron-app/dist/mac/GDevelop 5.app"
# Upload artifacts (CircleCI)
- store_artifacts:
path: newIDE/electron-app/dist
# Upload artifacts (AWS)
- run:
name: Deploy to S3 (specific commit)
command: export PATH=~/.local/bin:$PATH && aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/commit/$(git rev-parse HEAD)/
- run:
name: Deploy to S3 (latest)
command: export PATH=~/.local/bin:$PATH && aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/latest/
build-linux:
# CircleCI docker workers are failing if they don't have enough memory (no swap)
resource_class: xlarge
docker:
@@ -23,10 +93,6 @@ jobs:
name: Install Emscripten (for GDevelop.js)
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 1.39.6 && ./emsdk activate 1.39.6 && cd ..
- run:
name: Install Wine for Electron builder
command: sudo dpkg --add-architecture i386 && sudo apt-get update && sudo apt install wine32
- run:
name: Install system dependencies for Electron builder
command: sudo apt install icnsutils && sudo apt install graphicsmagick && sudo apt install rsync
@@ -34,15 +100,15 @@ jobs:
# GDevelop.js dependencies
- restore_cache:
keys:
- gd-nodejs-dependencies-{{ checksum "newIDE/app/package.json" }}-{{ checksum "newIDE/electron-app/package.json" }}-{{ checksum "GDevelop.js/package.json" }}
- gd-linux-nodejs-dependencies-{{ checksum "newIDE/app/package.json" }}-{{ checksum "newIDE/electron-app/package.json" }}-{{ checksum "GDevelop.js/package.json" }}
# fallback to using the latest cache if no exact match is found
- gd-nodejs-dependencies---
- gd-linux-nodejs-dependencies---
- run:
name: Install GDevelop.js dependencies and build it
command: cd GDevelop.js && sudo npm install -g grunt-cli && npm install && cd ..
command: cd GDevelop.js && npm install && cd ..
# Build GDevelop.js
# Build GDevelop.js (and run tests to ensure it works)
- run:
name: Build GDevelop.js
command: cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build && npm test && cd ..
@@ -57,16 +123,16 @@ jobs:
- newIDE/electron-app/node_modules
- newIDE/app/node_modules
- GDevelop.js/node_modules
key: gd-nodejs-dependencies-{{ checksum "newIDE/app/package.json" }}-{{ checksum "newIDE/electron-app/package.json" }}
key: gd-linux-nodejs-dependencies-{{ checksum "newIDE/app/package.json" }}-{{ checksum "newIDE/electron-app/package.json" }}-{{ checksum "GDevelop.js/package.json" }}
# Build GDevelop IDE (seems like we need to allow Node.js to use more space than usual)
- run:
name: Build GDevelop IDE
command: export NODE_OPTIONS="--max-old-space-size=7168" && 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 -- --linux AppImage --publish=never
- run:
name: Clean dist folder to keep only installers/binaries.
command: rm -rf newIDE/electron-app/dist/linux-unpacked && rm -rf newIDE/electron-app/dist/win-unpacked && rm -rf newIDE/electron-app/dist/mac
command: rm -rf newIDE/electron-app/dist/linux-unpacked
# Upload artifacts (CircleCI)
- store_artifacts:
@@ -79,3 +145,20 @@ jobs:
- run:
name: Deploy to S3 (latest)
command: aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/latest/
workflows:
builds:
jobs:
- build-macos:
filters:
branches:
only:
- master
- /experimental-build.*/
- build-linux:
filters:
branches:
only:
- master
- /experimental-build.*/

View File

@@ -13,6 +13,5 @@
-fPIC
-I./ExtLibs/SFML/include
-I./Core
-I./GDCpp/.
-I./GDJS/.
-F./ExtLibs/SFML/extlibs/libs-osx/Frameworks

1
.gitattributes vendored
View File

@@ -1,6 +1,5 @@
Core/GDCore/Serialization/rapidjson/rapidjson.h/* linguist-vendored
Core/GDCore/TinyXml/* linguist-vendored
GDCpp/GDCpp/Runtime/TinyXml/* linguist-vendored
Extensions/ParticleSystem/SPARK/* linguist-vendored
Extensions/PhysicsBehavior/Box2D/* linguist-vendored
Extensions/PhysicsBehavior/box2djs/* linguist-vendored

17
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
blank_issues_enabled: false
contact_links:
- name: GDevelop Discord
url: https://discord.gg/rjdYHvj
about: Discuss on the forum or on the Discord to get help creating a game or identifying a bug.
- name: GDevelop Forums
url: https://forum.gdevelop-app.com
about: You can also discuss game creation, new feature requests and bugs on the forum.
- name: GDevelop Roadmap
url: https://trello.com/b/qf0lM7k8/gdevelop-roadmap
about: Look at the roadmap and vote on features that you want to see in GDevelop.
- name: Submit a new game example that you created
url: https://github.com/GDevelopApp/GDevelop-examples/issues/new/choose
about: You can submit a game that you made to be added to examples in the "GDevelop-examples" repository
- name: Submit a new game extension that you created
url: https://github.com/4ian/GDevelop-extensions/issues/new/choose
about: You can submit an extension that you made in the "GDevelop-extensions" repository

View File

@@ -4,13 +4,6 @@ jobs:
autoclose:
runs-on: ubuntu-latest
steps:
- name: Autoclose issues about adding a new example without providing anything
uses: arkon/issue-closer-action@v1.1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
type: "body"
regex: ".*INSERT the link to your game here, or add it as an attachment.*"
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed because it seems that you have not included any example.\n\nGitHub is a place for the technical development of GDevelop itself - you may want to go on the [forum](https://forum.gdevelop-app.com/), the Discord chat or [read the documentation](http://wiki.compilgames.net/doku.php/gdevelop5/start) to learn more about GDevelop. Thanks!"
- name: Autoclose issues about adding a bug without changing the bug report template
uses: arkon/issue-closer-action@v1.1
with:
@@ -25,3 +18,11 @@ jobs:
type: "body"
regex: ".*_instance.getRawFloatProperty is not a function.*"
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed as this seems to be a known bug. It can be solved by **closing entirely the web-app and opening it again**. This will allow the web-app to auto-update and the problem should be gone."
- name: Autoclose known beta 114 web-app update bug
uses: arkon/issue-closer-action@v1.1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
type: "body"
regex: ".*getAssociatedSettings is not a function.*"
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed as this seems to be a known bug. It can be solved by **closing entirely the web-app and opening it again**. This will allow the web-app to auto-update and the problem should be gone."

2
.gitignore vendored
View File

@@ -1,4 +1,3 @@
/Core/GDCore/Tools/VersionPriv.h
/docs
/docs-wiki
/ExtLibs/SFML
@@ -16,7 +15,6 @@
*.bc
/Binaries/Output
*.autosave
!/GDCpp/scripts/bcp.exe
!/scripts/libgettextlib-0-17.dll
!/scripts/libgettextsrc-0-17.dll
!/xgettext.exe

105
.semaphore/semaphore.yml Normal file
View File

@@ -0,0 +1,105 @@
version: v1.0
name: Fast tests (not building GDevelop.js - can have false negatives)
agent:
machine:
type: e1-standard-2
os_image: ubuntu2004
auto_cancel:
running:
when: "true"
blocks:
- name: Install
task:
jobs:
- name: Install node_modules and cache them
commands:
- checkout
- node -v
- |-
if ! cache has_key newIDE-app-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum newIDE/app/package-lock.json); then
cd newIDE/app
npm i
cd ../..
cache store newIDE-app-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum newIDE/app/package-lock.json) newIDE/app/node_modules
fi
- |-
if ! cache has_key GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json); then
cd GDJS
npm i
cd ..
cache store GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json) GDJS/node_modules
fi
- |-
if ! cache has_key GDJS-tests-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/tests/package-lock.json); then
cd GDJS/tests
npm i
cd ../..
cache store GDJS-tests-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/tests/package-lock.json) GDJS/tests/node_modules
fi
dependencies: []
- name: Type checks
dependencies:
- Install
task:
jobs:
- name: newIDE typing
commands:
- checkout
- cache restore newIDE-app-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum newIDE/app/package-lock.json)
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
- cd newIDE/app
- npm run postinstall
- npm run flow
- cd ../..
- name: GDJS typing and documentation generation
commands:
- checkout
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
- cache restore GDJS-tests-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/tests/package-lock.json)
- cd GDJS
- npm run check-types
- npm run generate-doc
- name: Auto formatting
dependencies:
- Install
task:
jobs:
- name: newIDE auto-formatting
commands:
- checkout
- cache restore newIDE-app-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum newIDE/app/package-lock.json)
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
- cd newIDE/app
- npm run postinstall
- npm run check-format
- cd ../..
- name: GDJS auto-formatting
commands:
- checkout
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
- cd GDJS
- npm run check-format
- cd ..
- name: Tests
dependencies:
- Install
task:
jobs:
- name: newIDE tests
commands:
- checkout
- cache restore newIDE-app-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum newIDE/app/package-lock.json)
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
- cd newIDE/app
- npm run postinstall
- npm run analyze-test-coverage
- cd ../..
- name: GDJS tests
commands:
- checkout
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
- cache restore GDJS-tests-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/tests/package-lock.json)
- cd GDJS
- npm run build
- npm run test
- cd ../..

View File

@@ -1,7 +1,15 @@
# Travis CI configuration to build and run all tests
# (and typing/formatting) for the Core, newIDE, GDJS.
#
# This builds GDevelop.js and store it on a S3 so it can be used to run
# GDevelop without building it.
#
# See also Semaphore CI for quick tests (not building GDevelop.js, so
# faster but not always reliable).
language: cpp
sudo: false
compiler:
- gcc
- clang
# Cache .npm folder for faster npm install
@@ -54,7 +62,7 @@ before_install:
install:
#Get the correct version of gcc/g++
- if [ "$CXX" = "g++" ]; then export CXX="g++-${GCC_VERSION}" CC="gcc-${GCC_VERSION}"; fi
#Compile the tests only for GDCore and GDCpp
#Compile the tests only for GDCore
- mkdir .build-tests
- cd .build-tests
- cmake -DBUILD_GDJS=FALSE -DBUILD_TESTS=TRUE -DCMAKE_CXX_COMPILER=$(which $CXX) -DCMAKE_C_COMPILER=$(which $CC) ..
@@ -81,12 +89,9 @@ install:
- cd ../..
script:
# GDCore and GDCpp game engine tests:
# GDCore tests:
- cd .build-tests
- Core/GDCore_tests
- GDCpp/GDCpp_tests
- Extensions/PathfindingBehavior/PathfindingBehavior_Runtime_tests
- Extensions/LinkedObjects/LinkedObjects_Runtime_tests
- cd ..
# GDevelop.js tests
- cd GDevelop.js
@@ -103,6 +108,6 @@ script:
- npm run check-format
- cd ..
# GDJS game engine tests, disabled on Travis CI because ChromeHeadless can't be started.
# See them running on Semaphore-CI instead: https://semaphoreci.com/4ian/gd
# See them running on Semaphore-CI instead: https://gdevelop.semaphoreci.com/projects/GDevelop
# - cd GDJS/tests && npm test
# - cd ../..

129
.vscode/GDevelopExtensions.code-snippets vendored Normal file
View File

@@ -0,0 +1,129 @@
{
"Define extension": {
"scope": "javascript",
"description": "Adds the boilerplate code of a GDevelop extension definition.",
"prefix": "gdext",
"body": [
"// @flow",
"/**",
" * This is a declaration of an extension for GDevelop 5.",
" *",
" * Changes in this file are watched and automatically imported if the editor",
" * is running. You can also manually run `node import-GDJS-Runtime.js` (in newIDE/app/scripts).",
" *",
" * The file must be named \"JsExtension.js\", otherwise GDevelop won't load it.",
" * ⚠️ If you make a change and the extension is not loaded, open the developer console",
" * and search for any errors.",
" *",
" * More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md",
" */",
"",
"/*::",
"// Import types to allow Flow to do static type checking on this file.",
"// Extensions declaration are typed using Flow (like the editor), but the files",
"// for the game engine are checked with TypeScript annotations.",
"import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'",
"*/",
"",
"module.exports = {",
"\tcreateExtension: function (",
"\t\t/*: (string) => string */,",
"\t\tgd /*: libGDevelop */",
"\t) {",
"\t\tconst extension = new gd.PlatformExtension();",
"\t\textension",
"\t\t\t.setExtensionInformation(",
"\t\t\t\t'${1:${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/$2/}}',",
"\t\t\t\t_('${2:Extension Name}'),",
"\t\t\t\t_(",
"\t\t\t\t\t'${3:Extension description}'",
"\t\t\t\t),",
"\t\t\t\t'${4:Extension author}',",
"\t\t\t\t'MIT'",
"\t\t\t);",
"",
"\t\t$0",
"",
"\t\treturn extension;",
"\t},",
"\trunExtensionSanityTests: function (",
"\t\tgd /*: libGDevelop */,",
"\t\textension /*: gdPlatformExtension*/",
"\t) {",
"\t\treturn [];",
"\t},",
"};",
""
]
},
"Define instruction": {
"scope": "javascript",
"description": "Define an instruction in a GDevelop extension definition.",
"prefix": "gdinstr",
"body": [
"extension",
"\t.add${1|Condition,Action|}(",
"\t\t'${2:InstructionInternalName}',",
"\t\t_('${3:Instruction full name}'),",
"\t\t_(",
"\t\t\t'${4:Instruction description}'",
"\t\t),",
"\t\t_('${5:Event sheet sentence}'),",
"\t\t_('${6:Events group}'),",
"\t\t'JsPlatform/Extensions/${8:icon}.png',",
"\t\t'JsPlatform/Extensions/${8:icon}.png'",
"\t)",
"\t.getCodeExtraInformation()",
"\t.setIncludeFile('Extensions/${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/$2/}/${9:${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/${2:/downcase}/}tools}.js')",
"\t.setFunctionName('gdjs.evtTools.${7:${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/${2:/downcase}/}.}');",
"",
"$0"
]
},
"Define expression": {
"scope": "javascript",
"description": "Define an expression in a GDevelop extension definition.",
"prefix": "gdexp",
"body": [
"extension",
"\t.add${1|Expression,StrExpression|}(",
"\t\t'${2:ExpressionsInternalName}',",
"\t\t_('${3:Expression full name}'),",
"\t\t_(",
"\t\t\t'${4:Expression description}'",
"\t\t),",
"\t\t_('${5:Events group}'),",
"\t\t'JsPlatform/Extensions/${7:icon}.png'",
"\t)",
"\t.getCodeExtraInformation()",
"\t.setIncludeFile('Extensions/${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/$2/}/${8:${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/${2:/downcase}/}tools}.js')",
"\t.setFunctionName('gdjs.evtTools.${6:${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/${2:/downcase}/}.}');",
"",
"$0"
]
},
"Add parameter": {
"scope": "javascript",
"description": "Define a parameter in a GDevelop extension definition.",
"prefix": "gdparam",
"body": [
".addParameter('${1|string,expression,object,behavior,yesorno,stringWithSelector,scenevar,globalvar,objectvar,objectList,objectListWithoutPicking,color,key,sceneName,file,layer,relationalOperator,operator,trueorfalse,musicfile,soundfile,police,mouse,passwordjoyaxis,camera,objectPtr,forceMultiplier|}', '${2:Parameter description}', '${3:Optional parameter data}', /*parameterIsOptional=*/${4|false,true|})"
]
},
"Add code only parameter": {
"scope": "javascript",
"description": "Define a parameter in a GDevelop extension definition.",
"prefix": "gdcoparam",
"body": [
".addCodeOnlyParameter('${1|inlineCode,currentScene,objectsContext,eventsFunctionContext,conditionInverted|}', '${2:Inline code (for inlineCode parameter)}')"
]
},
"Add include": {
"scope": "javascript",
"description": "Define an include file in a GDevelop extension definition.",
"prefix": "gdincl",
"body": [
".addIncludeFile('Extensions/${TM_DIRECTORY/(.*)[\\\\\\/](.*)[\\\\\\/]?$/$2/}/${1:include}.js')"
]
}
}

View File

@@ -4,7 +4,6 @@
"name": "Mac",
"includePath": [
"${workspaceRoot}",
"${workspaceRoot}/GDCpp",
"${workspaceRoot}/GDJS",
"${workspaceRoot}/Extensions",
"${workspaceRoot}/Core",
@@ -16,6 +15,7 @@
"${workspaceRoot}"
],
"defines": [
"EMSCRIPTEN",
"GD_IDE_ONLY",
"GD_CORE_API=/* Macro used to export classes on Windows, please ignore */",
"GD_API=/* Macro used to export classes on Windows, please ignore */",
@@ -45,7 +45,6 @@
"name": "Linux",
"includePath": [
"${workspaceRoot}",
"${workspaceRoot}/GDCpp",
"${workspaceRoot}/GDJS",
"${workspaceRoot}/Extensions",
"${workspaceRoot}/Core",
@@ -55,6 +54,7 @@
"${workspaceRoot}"
],
"defines": [
"EMSCRIPTEN",
"GD_IDE_ONLY",
"GD_CORE_API=/* Macro used to export classes on Windows, please ignore */",
"GD_API=/* Macro used to export classes on Windows, please ignore */",
@@ -75,18 +75,16 @@
"name": "Win32",
"includePath": [
"${workspaceRoot}",
"${workspaceRoot}/IDE",
"${workspaceRoot}/GDCpp",
"${workspaceRoot}/GDJS",
"${workspaceRoot}/Extensions",
"${workspaceRoot}/Core",
"${workspaceRoot}/ExtLibs/SFML/include",
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include",
"${workspaceRoot}"
],
"defines": [
"_DEBUG",
"UNICODE",
"EMSCRIPTEN",
"GD_IDE_ONLY",
"GD_CORE_API=/* Macro used to export classes on Windows, please ignore */",
"GD_API=/* Macro used to export classes on Windows, please ignore */",
@@ -95,7 +93,6 @@
"intelliSenseMode": "msvc-x64",
"browse": {
"path": [
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include/*",
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
@@ -104,4 +101,4 @@
}
],
"version": 4
}
}

View File

@@ -1,8 +1,8 @@
{
"recommendations": [
"esbenp.prettier-vscode",
"xaver.clang-format",
"ms-vscode.cpptools",
"flowtype.flow-for-vscode"
]
}
"recommendations": [
"esbenp.prettier-vscode",
"xaver.clang-format",
"ms-vscode.cpptools",
"flowtype.flow-for-vscode"
]
}

29
.vscode/launch.json vendored
View File

@@ -1,15 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "pwa-chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}"
}
]
}
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "pwa-chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}",
"preLaunchTask": "Start development server"
}
]
}

View File

@@ -106,12 +106,16 @@
"xstring": "cpp",
"xtr1common": "cpp",
"xtree": "cpp",
"xutility": "cpp"
"xutility": "cpp",
"xlocbuf": "cpp",
"xlocmes": "cpp",
"xmemory0": "cpp"
},
"files.exclude": {
"Binaries/*build*": true,
"Binaries/Output": true,
"ExtLibs/SFML": true,
"GDJS/Runtime-dist": true,
"docs": true,
"newIDE/electron-app/dist": true,
"newIDE/app/build": true,

158
.vscode/tasks.json vendored
View File

@@ -1,66 +1,100 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "start",
"path": "newIDE/app/",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [],
"label": "Start development server",
"detail": "Starts the GDevelop development server."
},
{
"type": "npm",
"script": "build",
"path": "GDevelop.js/",
"group": "build",
"problemMatcher": [],
"label": "Build GDevelop.js",
"detail": "Builds GDCore for newIDE."
},
{
"type": "npm",
"script": "format",
"path": "newIDE/app/",
"problemMatcher": [],
"label": "Format newIDE",
"detail": "Run auto-formatting (with Prettier) for the newIDE/app directory."
},
{
"type": "npm",
"script": "test",
"path": "newIDE/app/",
"group": {
"kind": "test",
"isDefault": true
},
"problemMatcher": [],
"label": "Run newIDE tests",
"detail": "Run tests for newIDE."
},
{
"type": "typescript",
"tsconfig": "GDJS/tsconfig.json",
"option": "watch",
"problemMatcher": [
"$tsc-watch"
],
"group": "test",
"label": "GDJS TS Check",
"detail": "Runs a types check on the GDJS Runtime."
},
{
"type": "npm",
"script": "test",
"path": "GDJS/",
"group": "test",
"problemMatcher": [],
"label": "Run GDJS tests",
"detail": "Run tests for GDJS."
}
]
{
"type": "npm",
"script": "start",
"path": "newIDE/app/",
"group": "build",
"label": "Start development server",
"detail": "Starts the GDevelop development server.",
"problemMatcher": [
{
"owner": "cra",
"fileLocation": ["relative", "${workspaceFolder}/newIDE/app"],
"source": "create-react-app",
"applyTo": "allDocuments",
"pattern": [
{
"regexp": "^([^\\s].*?)$",
"file": 1
},
{
"regexp": "^ Line\\s+(\\d+):\\s+(.*)\\s\\s+(.*)$",
"line": 1,
"message": 2,
"code": 3,
"loop": true
}
],
"background": {
"activeOnStart": true,
"beginsPattern": "^(?:Compiled with warnings\\.|Compiled successfully!)$",
"endsPattern": "^(?:Search for the keywords to learn more about each warning\\.|Note that the development build is not optimized\\.)$"
}
}
],
"presentation": {
"reveal": "silent"
},
"isBackground": true,
"runOptions": { "instanceLimit": 1, "runOn": "folderOpen" }
},
{
"type": "npm",
"script": "start",
"path": "newIDE/electron-app/",
"group": "build",
"problemMatcher": [],
"label": "Start electron app",
"detail": "Starts the development local version of GDevelop."
},
{
"type": "npm",
"script": "build",
"path": "GDevelop.js/",
"group": "build",
"problemMatcher": [],
"label": "Build GDevelop.js",
"detail": "Builds GDCore for newIDE."
},
{
"type": "npm",
"script": "format",
"path": "newIDE/app/",
"problemMatcher": [],
"label": "Format newIDE",
"detail": "Run auto-formatting (with Prettier) for the newIDE/app directory."
},
{
"type": "npm",
"script": "test",
"path": "newIDE/app/",
"group": {
"kind": "test",
"isDefault": true
},
"problemMatcher": [],
"label": "Run newIDE tests",
"detail": "Run tests for newIDE."
},
{
"type": "typescript",
"tsconfig": "GDJS/tsconfig.json",
"option": "watch",
"problemMatcher": ["$tsc-watch"],
"group": "test",
"label": "GDJS TS Check",
"detail": "Runs a types check on the GDJS Runtime."
},
{
"type": "npm",
"script": "test",
"path": "GDJS/",
"group": "test",
"problemMatcher": [],
"label": "Run GDJS tests",
"detail": "Run tests for GDJS."
}
]
}

View File

@@ -1,3 +1,3 @@
This is the directory where native or WebAssembly binaries of the C++ code of GDCore, GDCpp and GDJS are produced.
This is the directory where native or WebAssembly binaries of the C++ code of GDCore and GDJS are produced.
See GDevelop.js README for the instructions to compile after a change in the C++ source code.

View File

@@ -14,12 +14,10 @@ macro(gd_set_option var default type docstring)
endif()
set(${var} ${${var}} CACHE ${type} ${docstring} FORCE)
endmacro()
gd_set_option(BUILD_CORE TRUE BOOL "TRUE to build GDevelop Core library, FALSE to use the already compiled binaries")
gd_set_option(BUILD_GDCPP TRUE BOOL "TRUE to build GDevelop C++ Platform")
gd_set_option(BUILD_CORE TRUE BOOL "TRUE to build GDevelop Core library")
gd_set_option(BUILD_GDJS TRUE BOOL "TRUE to build GDevelop JS Platform")
gd_set_option(BUILD_EXTENSIONS TRUE BOOL "TRUE to build the extensions")
gd_set_option(BUILD_TESTS FALSE BOOL "TRUE to build the tests")
gd_set_option(FULL_VERSION_NUMBER TRUE BOOL "TRUE to build GDevelop with its full version number (lastest tag + commit hash), FALSE to only use the lastest tag (avoid rebulding many source file when developping)")
# Disable deprecated code
set(NO_GUI TRUE CACHE BOOL "" FORCE) #Force disable old GUI related code.
@@ -55,9 +53,6 @@ IF ("${CMAKE_BUILD_TYPE}" STREQUAL "")
message( "CMAKE_BUILD_TYPE is empty, assuming build type is Release" )
set(CMAKE_BUILD_TYPE Release)
ENDIF()
IF (EMSCRIPTEN)
set(BUILD_GDCPP FALSE CACHE BOOL "" FORCE) #Force disable GDC++ when compiling with emscripten.
ENDIF()
IF("${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND NOT WIN32 AND CMAKE_COMPILER_IS_GNUCXX)
SET(CMAKE_SHARED_LINKER_FLAGS "-s") #Force stripping to avoid errors when packaging for linux.
@@ -84,7 +79,6 @@ endif()
set(GD_base_dir ${CMAKE_CURRENT_SOURCE_DIR})
#Add all the CMakeLists:
ADD_SUBDIRECTORY(Version)
ADD_SUBDIRECTORY(ExtLibs)
IF(BUILD_CORE)
ADD_SUBDIRECTORY(Core)
@@ -92,10 +86,7 @@ ENDIF()
IF(BUILD_GDJS)
ADD_SUBDIRECTORY(GDJS)
ENDIF()
IF(BUILD_GDCPP)
ADD_SUBDIRECTORY(GDCpp)
ENDIF()
IF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/GDevelop.js/CMakeLists.txt" AND EMSCRIPTEN)
IF(EMSCRIPTEN)
ADD_SUBDIRECTORY(GDevelop.js)
ENDIF()
IF(BUILD_EXTENSIONS)

View File

@@ -57,7 +57,6 @@ IF(EMSCRIPTEN)
ELSE()
add_library(GDCore SHARED ${source_files})
ENDIF()
add_dependencies(GDCore GDVersion)
IF(EMSCRIPTEN)
set_target_properties(GDCore PROPERTIES SUFFIX ".bc")
ELSEIF(WIN32)

View File

@@ -14,9 +14,8 @@
*
* \section other Other documentations
*
* GDevelop is architectured around a `Core` (this library), platforms (`GDJS`, `GDCpp`) and extensions (`Extensions` folder). The editor (`newIDE` folder) is using all of these libraries.
* GDevelop is architectured around a `Core` (this library), a game engine (`GDJS`) and extensions (`Extensions` folder). The editor (`newIDE` folder) is using all of these libraries.
*
* - [Open GDevelop C++ Platform documentation](../GDCpp Documentation/index.html)
* - [Open GDevelop JS Platform documentation](../GDJS Documentation/index.html)
* - <a href="https://github.com/4ian/GDevelop/blob/master/newIDE/README.md">Getting started with the editor</a>
* - <a href="https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md">Getting started with the extensions</a>

View File

@@ -3,13 +3,17 @@
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include <iostream>
#include "EffectsCodeGenerator.h"
#include <iostream>
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Project/Effect.h"
#include "GDCore/Project/EffectsContainer.h"
#include "GDCore/Project/Layer.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
namespace gd {
@@ -26,13 +30,30 @@ void ExposeProjectEffects(
auto& layout = project.GetLayout(s);
for (std::size_t l = 0; l < layout.GetLayersCount(); ++l) {
auto& layer = layout.GetLayer(l);
for (std::size_t e = 0; e < layer.GetEffectsCount(); ++e) {
auto& effect = layer.GetEffect(e);
auto& effects = layout.GetLayer(l).GetEffects();
for (std::size_t e = 0; e < effects.GetEffectsCount(); ++e) {
auto& effect = effects.GetEffect(e);
worker(effect);
}
}
for (std::size_t i; i < layout.GetObjectsCount(); i++) {
auto& object = layout.GetObject(i);
auto& effects = object.GetEffects();
for (std::size_t e = 0; e < effects.GetEffectsCount(); e++) {
auto& effect = effects.GetEffect(e);
worker(effect);
}
}
}
// Add global object effects
for (std::size_t s = 0; s < project.GetObjectsCount(); s++) {
auto& effects = project.GetObject(s).GetEffects();
for (std::size_t e = 0; e < effects.GetEffectsCount(); e++) {
auto& effect = effects.GetEffect(e);
worker(effect);
}
}
}

View File

@@ -261,8 +261,11 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
EventsCodeGenerationContext& context) {
gd::String conditionCode;
gd::InstructionMetadata instrInfos =
const gd::InstructionMetadata& instrInfos =
MetadataProvider::GetConditionMetadata(platform, condition.GetType());
if (MetadataProvider::IsBadInstructionMetadata(instrInfos)) {
return "/* Unknown instruction - skipped. */";
}
AddIncludeFiles(instrInfos.codeExtraInformation.GetIncludeFiles());
maxConditionsListsSize =
@@ -299,15 +302,13 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
!GetObjectsAndGroups().GetObjectGroups().Has(objectInParameter) &&
!GetGlobalObjectsAndGroups().GetObjectGroups().Has(
objectInParameter)) {
condition.SetParameter(pNb, gd::Expression(""));
condition.SetType("");
return "/* Unknown object - skipped. */";
} else if (!instrInfos.parameters[pNb].supplementaryInformation.empty() &&
gd::GetTypeOfObject(GetGlobalObjectsAndGroups(),
GetObjectsAndGroups(),
objectInParameter) !=
instrInfos.parameters[pNb].supplementaryInformation) {
condition.SetParameter(pNb, gd::Expression(""));
condition.SetType("");
return "/* Mismatched object type - skipped. */";
}
}
}
@@ -425,6 +426,11 @@ gd::String EventsCodeGenerator::GenerateConditionsListCode(
outputCode += "{\n";
outputCode += conditionCode;
outputCode += "}";
} else {
// Deprecated way to cancel code generation - but still honor it.
// Can be removed once condition is passed by const reference to
// GenerateConditionCode.
outputCode += "/* Skipped condition (empty type) */";
}
}
@@ -440,8 +446,11 @@ gd::String EventsCodeGenerator::GenerateActionCode(
gd::Instruction& action, EventsCodeGenerationContext& context) {
gd::String actionCode;
gd::InstructionMetadata instrInfos =
const gd::InstructionMetadata& instrInfos =
MetadataProvider::GetActionMetadata(platform, action.GetType());
if (MetadataProvider::IsBadInstructionMetadata(instrInfos)) {
return "/* Unknown instruction - skipped. */";
}
AddIncludeFiles(instrInfos.codeExtraInformation.GetIncludeFiles());
@@ -466,15 +475,13 @@ gd::String EventsCodeGenerator::GenerateActionCode(
!GetObjectsAndGroups().GetObjectGroups().Has(objectInParameter) &&
!GetGlobalObjectsAndGroups().GetObjectGroups().Has(
objectInParameter)) {
action.SetParameter(pNb, gd::Expression(""));
action.SetType("");
return "/* Unknown object - skipped. */";
} else if (!instrInfos.parameters[pNb].supplementaryInformation.empty() &&
gd::GetTypeOfObject(GetGlobalObjectsAndGroups(),
GetObjectsAndGroups(),
objectInParameter) !=
instrInfos.parameters[pNb].supplementaryInformation) {
action.SetParameter(pNb, gd::Expression(""));
action.SetType("");
return "/* Mismatched object type - skipped. */";
}
}
}
@@ -556,7 +563,14 @@ gd::String EventsCodeGenerator::GenerateActionsListCode(
gd::String actionCode = GenerateActionCode(actions[aId], context);
outputCode += "{";
if (!actions[aId].GetType().empty()) outputCode += actionCode;
if (actions[aId].GetType().empty()) {
// Deprecated way to cancel code generation - but still honor it.
// Can be removed once action is passed by const reference to
// GenerateActionCode.
outputCode += "/* Skipped action (empty type) */";
} else {
outputCode += actionCode;
}
outputCode += "}";
}

View File

@@ -462,24 +462,21 @@ class GD_CORE_API EventsCodeGenerator {
* Other standard parameters type that should be implemented by platforms:
* - currentScene: Reference to the current runtime scene.
* - objectList : a map containing lists of objects which are specified by the
object name in another parameter. (C++: std::map <gd::String,
std::vector<RuntimeObject*> *>). Example:
object name in another parameter. Example:
* \code
AddExpression("Count", _("Object count"), _("Count the number of picked
objects"), _("Objects"), "res/conditions/nbObjet.png")
.AddParameter("objectList", _("Object"))
.SetFunctionName("PickedObjectsCount").SetIncludeFile("GDCpp/Extensions/Builtin/ObjectTools.h");
.SetFunctionName("getPickedObjectsCount");
* \endcode
* - objectListWithoutPicking : Same as objectList but do not pick object if
they are not already picked.
* - objectPtr : Return a pointer to object specified by the object name in
another parameter ( C++: RuntimeObject* ). Example:
* - objectPtr : Return a reference to the object specified by the object name in
another parameter. Example:
* \code
.AddParameter("object", _("Object"))
.AddParameter("objectPtr", _("Target object"))
//The called function will be called with this signature on the C++ platform:
Function(gd::String, RuntimeObject*)
* \endcode
*/
virtual gd::String GenerateParameterCodes(

View File

@@ -360,8 +360,11 @@ gd::String ExpressionCodeGenerator::GenerateDefaultValue(
if (gd::ParameterMetadata::IsObject(type)) {
return codeGenerator.GenerateBadObject();
}
if (gd::ParameterMetadata::IsExpression("string", type)) {
return "\"\"";
}
return (type == "string") ? "\"\"" : "0";
return "0";
}
void ExpressionCodeGenerator::OnVisitEmptyNode(EmptyNode& node) {

View File

@@ -16,7 +16,6 @@
#include "GDCore/String.h"
namespace gd {
class EventsList;
class MainFrameWrapper;
class Project;
class Layout;
class EventsCodeGenerator;

View File

@@ -66,6 +66,22 @@ class GD_CORE_API ExpressionParser2 {
return Start(type, objectName);
}
/**
* Given an object name (or empty if none) and a behavior name (or empty if none),
* return the index of the first parameter that is inside the parenthesis:
* 0, 1 or 2.
*
* For example, in an expression like `Object.MyBehavior::Method("hello")`, the
* parameter "hello" is the second parameter (the first being by convention Object,
* and the second MyBehavior, also by convention).
*/
static size_t WrittenParametersFirstIndex(const gd::String &objectName,
const gd::String &behaviorName) {
// By convention, object is always the first parameter, and behavior the
// second one.
return !behaviorName.empty() ? 2 : (!objectName.empty() ? 1 : 0);
}
private:
/** \name Grammar
* Each method is a part of the grammar.
@@ -999,13 +1015,6 @@ class GD_CORE_API ExpressionParser2 {
}
///@}
static size_t WrittenParametersFirstIndex(const gd::String &objectName,
const gd::String &behaviorName) {
// By convention, object is always the first parameter, and behavior the
// second one.
return !behaviorName.empty() ? 2 : (!objectName.empty() ? 1 : 0);
}
gd::String expression;
std::size_t currentPosition;

View File

@@ -32,7 +32,6 @@ class GD_CORE_API BuiltinExtensionsImplementer {
static void ImplementsExternalLayoutsExtension(
gd::PlatformExtension& extension);
static void ImplementsFileExtension(gd::PlatformExtension& extension);
static void ImplementsJoystickExtension(gd::PlatformExtension& extension);
static void ImplementsKeyboardExtension(gd::PlatformExtension& extension);
static void ImplementsMathematicalToolsExtension(
gd::PlatformExtension& extension);

View File

@@ -206,7 +206,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"all of the forces it has."),
_("Add to _PARAM0_ _PARAM3_ force of _PARAM1_ p/s on X axis and "
"_PARAM2_ p/s on Y axis"),
_("Movement"),
_("Movement using forces"),
"res/actions/force24.png",
"res/actions/force.png")
@@ -222,7 +222,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"using the specified angle and length."),
_("Add to _PARAM0_ _PARAM3_ force, angle: _PARAM1_ degrees and "
"length: _PARAM2_ pixels"),
_("Movement"),
_("Movement using forces"),
"res/actions/force24.png",
"res/actions/force.png")
@@ -238,7 +238,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Add a force to an object to make it move toward a position."),
_("Move _PARAM0_ toward _PARAM1_;_PARAM2_ with _PARAM4_ force of _PARAM3_ "
"pixels"),
_("Movement"),
_("Movement using forces"),
"res/actions/force24.png",
"res/actions/force.png")
@@ -251,30 +251,30 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction(
"AddForceTournePos",
_("Add a force to move around a position"),
_("Add a force to an object to make it rotate around a "
"Add a force to move around a position",
"Add a force to an object to make it rotate around a "
"position.\nNote that the movement is not precise, especially if "
"the speed is high.\nTo position an object around a position more "
"precisely, use the actions in the category \"Position\"."),
_("Rotate _PARAM0_ around _PARAM1_;_PARAM2_ at _PARAM3_ deg/sec and "
"_PARAM4_ pixels away"),
_("Movement"),
"precisely, use the actions in the category \"Position\".",
"Rotate _PARAM0_ around _PARAM1_;_PARAM2_ at _PARAM3_ deg/sec and "
"_PARAM4_ pixels away",
_("Movement using forces"),
"res/actions/forceTourne24.png",
"res/actions/forceTourne.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("X position of the center"))
.AddParameter("expression", _("Y position of the center"))
.AddParameter("expression", _("Speed (in Degrees per seconds)"))
.AddParameter("expression", _("Distance (in pixels)"))
.AddParameter("forceMultiplier", _("Force multiplier"))
.AddParameter("expression", "X position of the center")
.AddParameter("expression", "Y position of the center")
.AddParameter("expression", "Speed (in Degrees per seconds)")
.AddParameter("expression", "Distance (in pixels)")
.AddParameter("forceMultiplier", "Force multiplier")
.SetHidden();
obj.AddAction("Arreter",
_("Stop the object"),
_("Stop the object by deleting all of its forces."),
_("Stop _PARAM0_ (remove all forces)"),
_("Movement"),
_("Movement using forces"),
"res/actions/arreter24.png",
"res/actions/arreter.png")
@@ -344,7 +344,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction("SetObjectVariableAsBoolean",
_("Boolean value of an object variable"),
_("Change the boolean value of an object variable."),
_("Set the boolean value of the variable _PARAM1_ of object "
_("Set the boolean value of variable _PARAM1_ of "
"_PARAM0_ to _PARAM2_"),
_("Variables"),
"res/actions/var24.png",
@@ -360,7 +360,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Toggles the boolean value of an object variable.") + "\n" +
_("If it was true, it will become false, and if it was false "
"it will become true."),
_("Toggle the boolean value of the variable _PARAM1_ of object "
_("Toggle the boolean value of variable _PARAM1_ of "
"_PARAM0_"),
_("Variables"),
"res/actions/var24.png",
@@ -475,9 +475,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.MarkAsSimple();
obj.AddCondition("Invisible",
_("Invisibility of an object"),
_("Check if an object is hidden."),
_("_PARAM0_ is hidden"),
"Invisibility of an object",
"Check if an object is hidden.",
"_PARAM0_ is hidden",
_("Visibility"),
"res/conditions/visibilite24.png",
"res/conditions/visibilite.png")
@@ -486,10 +486,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.SetHidden(); // Inverted "Visible" condition does the same thing.
obj.AddCondition("Arret",
_("Object is stopped"),
_("Object is stopped (no forces applied on it)"),
_("Check if an object is not moving"),
_("_PARAM0_ is stopped"),
_("Movement"),
_("Movement using forces"),
"res/conditions/arret24.png",
"res/conditions/arret.png")
@@ -497,10 +497,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.MarkAsAdvanced();
obj.AddCondition("Vitesse",
_("Speed"),
_("Speed (from forces)"),
_("Compare the overall speed of an object"),
_("the overall speed"),
_("Movement"),
_("Movement using forces"),
"res/conditions/vitesse24.png",
"res/conditions/vitesse.png")
@@ -509,17 +509,17 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.MarkAsAdvanced();
obj.AddCondition("AngleOfDisplacement",
_("Angle of movement"),
_("Compare the angle of displacement of an object"),
_("Angle of displacement of _PARAM0_ is _PARAM1_ (tolerance "
_("Angle of movement (using forces)"),
_("Compare the angle of movement of an object according to the forces applied on it."),
_("Angle of movement of _PARAM0_ is _PARAM1_ (tolerance"
": _PARAM2_ degrees)"),
_("Movement"),
_("Movement using forces"),
"res/conditions/vitesse24.png",
"res/conditions/vitesse.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angle, in degrees"))
.AddParameter("expression", _("Tolerance"))
.AddParameter("expression", _("Tolerance, in degrees"))
.MarkAsAdvanced();
obj.AddCondition("VarObjet",
@@ -560,9 +560,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.SetDefaultValue("true");
obj.AddCondition("VarObjetDef",
_("Variable defined"),
_("Check if the variable is defined."),
_("Variable _PARAM1 of _PARAM0_ is defined"),
"Variable defined",
"Check if the variable is defined.",
"Variable _PARAM1 of _PARAM0_ is defined",
_("Variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
@@ -632,7 +632,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Removes a variable at the specified index of an object array "
"variable."),
_("Remove variable at index _PARAM2_ from array variable _PARAM1_ of "
"object _PARAM0_"),
"_PARAM0_"),
_("Variables/Collections/Arrays"),
"res/actions/var24.png",
"res/actions/var.png")
@@ -671,7 +671,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Add a force to move toward an object"),
_("Add a force to an object to make it move toward another."),
_("Move _PARAM0_ toward _PARAM1_ with _PARAM3_ force of _PARAM2_ pixels"),
_("Movement"),
_("Movement using forces"),
"res/actions/forceVers24.png",
"res/actions/forceVers.png")
@@ -690,7 +690,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"the actions in category \"Position\"."),
_("Rotate _PARAM0_ around _PARAM1_ at _PARAM2_ deg/sec and _PARAM3_ "
"pixels away"),
_("Movement"),
_("Movement using forces"),
"res/actions/forceTourne24.png",
"res/actions/forceTourne.png")
@@ -720,29 +720,29 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
// Deprecated action
obj.AddAction("Rebondir",
_("Move an object away from another"),
_("Move an object away from another, using forces."),
_("Move _PARAM0_ away from _PARAM1_ (only _PARAM0_ will move)"),
_("Movement"),
"Move an object away from another",
"Move an object away from another, using forces.",
"Move _PARAM0_ away from _PARAM1_ (only _PARAM0_ will move)",
_("Movement using forces"),
"res/actions/ecarter24.png",
"res/actions/ecarter.png")
.SetHidden()
.AddParameter("object", _("Object"))
.AddParameter("objectList", _("Object 2 (won't move)"));
.AddParameter("objectList", "Object 2 (won't move)");
// Deprecated action
obj.AddAction("Ecarter",
_("Move an object away from another"),
_("Move an object away from another without using forces."),
_("Move _PARAM0_ away from _PARAM2_ (only _PARAM0_ will move)"),
"Move an object away from another",
"Move an object away from another without using forces.",
"Move _PARAM0_ away from _PARAM2_ (only _PARAM0_ will move)",
_("Position"),
"res/actions/ecarter24.png",
"res/actions/ecarter.png")
.SetHidden()
.AddParameter("object", _("Object"))
.AddParameter("objectList", _("Object 2 (won't move)"));
.AddParameter("objectList", "Object 2 (won't move)");
obj.AddAction("SeparateFromObjects",
_("Separate objects"),
@@ -795,8 +795,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddCondition(
"ObjectTimer",
_("Value of a timer"),
_("Test the elapsed time of a timer."),
_("Value of an object timer"),
_("Test the elapsed time of an object timer."),
_("The timer _PARAM1_ of _PARAM0_ is greater than _PARAM2_ seconds"),
_("Timers"),
"res/conditions/timer24.png",
@@ -806,8 +806,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression", _("Time in seconds"));
obj.AddCondition("ObjectTimerPaused",
_("Timer paused"),
_("Test if specified timer is paused."),
_("Object timer paused"),
_("Test if specified object timer is paused."),
_("The timer _PARAM1_ of _PARAM0_ is paused"),
_("Timers"),
"res/conditions/timerPaused24.png",
@@ -817,8 +817,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.MarkAsAdvanced();
obj.AddAction("ResetObjectTimer",
_("Start (or reset) a timer"),
_("Reset the specified timer, if the timer doesn't exist "
_("Start (or reset) an object timer"),
_("Reset the specified object timer, if the timer doesn't exist "
"it's created and started."),
_("Reset the timer _PARAM1_ of _PARAM0_"),
_("Timers"),
@@ -828,8 +828,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("string", _("Timer's name"));
obj.AddAction("PauseObjectTimer",
_("Pause a timer"),
_("Pause a timer."),
_("Pause an object timer"),
_("Pause an object timer."),
_("Pause timer _PARAM1_ of _PARAM0_"),
_("Timers"),
"res/actions/pauseTimer24.png",
@@ -839,8 +839,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.MarkAsAdvanced();
obj.AddAction("UnPauseObjectTimer",
_("Unpause a timer"),
_("Unpause a timer."),
_("Unpause an object timer"),
_("Unpause an object timer."),
_("Unpause timer _PARAM1_ of _PARAM0_"),
_("Timers"),
"res/actions/unPauseTimer24.png",
@@ -850,8 +850,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.MarkAsAdvanced();
obj.AddAction("RemoveObjectTimer",
_("Delete a timer"),
_("Delete a timer from memory."),
_("Delete an object timer"),
_("Delete an object timer from memory."),
_("Delete timer _PARAM1_ of _PARAM0_ from memory"),
_("Timers"),
"res/actions/timer24.png",
@@ -882,37 +882,37 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"));
obj.AddExpression("ForceX",
_("Average X coordinates of forces"),
_("Average X coordinates of forces"),
_("Movement"),
_("X coordinate of the sum of forces"),
_("X coordinate of the sum of forces"),
_("Movement using forces"),
"res/actions/force.png")
.AddParameter("object", _("Object"));
obj.AddExpression("ForceY",
_("Average Y coordinates of forces"),
_("Average Y coordinates of forces"),
_("Movement"),
_("Y coordinate of the sum of forces"),
_("Y coordinate of the sum of forces"),
_("Movement using forces"),
"res/actions/force.png")
.AddParameter("object", _("Object"));
obj.AddExpression("ForceAngle",
_("Average angle of the forces"),
_("Average angle of the forces"),
_("Movement"),
_("Angle of the sum of forces"),
_("Angle of the sum of forces"),
_("Movement using forces"),
"res/actions/force.png")
.AddParameter("object", _("Object"));
obj.AddExpression("ForceLength",
_("Average length of the forces"),
_("Average length of the forces"),
_("Movement"),
_("Length of the sum of forces"),
_("Length of the sum of forces"),
_("Movement using forces"),
"res/actions/force.png")
.AddParameter("object", _("Object"));
obj.AddExpression("Longueur",
_("Average length of the forces"),
_("Average length of the forces"),
_("Movement"),
_("Length of the sum of forces"),
_("Length of the sum of forces"),
_("Movement using forces"),
"res/actions/force.png")
.AddParameter("object", _("Object"))
.SetHidden();
@@ -1021,9 +1021,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectvar", _("Variable"));
obj.AddExpression("ObjectTimerElapsedTime",
_("Timer value"),
_("Value of a timer"),
_("Timers"),
_("Object timer value"),
_("Value of an object timer"),
_("Object timers"),
"res/actions/time.png")
.AddParameter("object", _("Object"))
.AddParameter("string", _("Timer's name"));
@@ -1072,6 +1072,74 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression", _("Target X position"))
.AddParameter("expression", _("Target Y position"));
obj.AddAction("EnableEffect",
_("Enable an object effect"),
_("Enable an effect on the object"),
_("Enable effect _PARAM1_ on _PARAM0_: _PARAM2_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("string", _("Effect Name"))
.AddParameter("yesorno", _("Enable?"))
.MarkAsSimple();
obj.AddAction("SetEffectDoubleParameter",
_("Effect parameter (number)"),
_("Change the value of a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("string", _("Effect Name"))
.AddParameter("string", _("Parameter name"))
.AddParameter("expression", _("New value"))
.MarkAsSimple();
obj.AddAction("SetEffectStringParameter",
_("Effect parameter (string)"),
_("Change the value (string) of a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("string", _("Effect Name"))
.AddParameter("string", _("Parameter name"))
.AddParameter("string", _("New value"))
.MarkAsSimple();
obj.AddAction("SetEffectBooleanParameter",
_("Effect parameter (enable or disable)"),
_("Enable or disable a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Enable _PARAM2_ for effect _PARAM1_ of _PARAM0_: _PARAM3_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("string", _("Effect Name"))
.AddParameter("string", _("Parameter Name"))
.AddParameter("yesorno", _("Enable?"))
.MarkAsSimple();
obj.AddCondition("IsEffectEnabled",
_("Effect is enabled"),
_("Check if the effect on an object is enabled."),
_("Effect _PARAM1_ of _PARAM0_ is enabled"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("string", _("Effect Name"))
.MarkAsSimple();
extension
.AddAction("Create",
_("Create an object"),
@@ -1149,7 +1217,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Moves all objects according to the forces they have. GDevelop "
"calls this action at the end of the events by default."),
_("Apply movement to all objects"),
_("Movement"),
_("Movement using forces"),
"res/actions/doMove24.png",
"res/actions/doMove.png")
.AddCodeOnlyParameter("currentScene", "")
@@ -1157,16 +1225,16 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
extension
.AddCondition("SeDirige",
_("An object is moving toward another"),
_("An object is moving toward another (using forces)"),
_("Check if an object moves toward another.\nThe first "
"object must move."),
_("_PARAM0_ is moving toward _PARAM1_"),
_("Movement"),
_("Movement using forces"),
"res/conditions/sedirige24.png",
"res/conditions/sedirige.png")
.AddParameter("objectList", _("Object"))
.AddParameter("objectList", _("Object 2"))
.AddParameter("expression", _("Angle of tolerance"))
.AddParameter("expression", _("Tolerance, in degrees"))
.AddCodeOnlyParameter("conditionInverted", "")
.MarkAsAdvanced();

View File

@@ -1,77 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "AllBuiltinExtensions.h"
#include "GDCore/Tools/Localization.h"
using namespace std;
namespace gd {
void GD_CORE_API BuiltinExtensionsImplementer::ImplementsJoystickExtension(
gd::PlatformExtension& extension) {
extension
.SetExtensionInformation(
"BuiltinJoystick",
_("Joysticks features"),
"Built-in extension that enables the use of joysticks.",
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("" /*TODO: Add a documentation page for this */);
#if defined(GD_IDE_ONLY)
extension
.AddCondition("JoystickButtonDown",
_("A button on a joystick is pressed"),
_("Test if a button on a joystick is pressed."),
_("The button _PARAM2_ of joystick _PARAM1_ is pressed"),
_("Joystick"),
"res/conditions/joystick24.png",
"res/conditions/joystick.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Joystick number (first joystick: 0)"))
.AddParameter("expression", _("Button"));
extension
.AddCondition("JoystickAxis",
_("Value of an axis of a joystick"),
_("Test the value of an axis of a joystick."),
_("the value of the axis _PARAM2_ of joystick _PARAM1_"),
_("Joystick"),
"res/conditions/joystick24.png",
"res/conditions/joystick.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Joystick number (first joystick: 0)"))
.AddParameter("joyaxis", _("Axis"))
.UseStandardRelationalOperatorParameters("number");
extension
.AddAction(
"GetJoystickAxis",
_("Get the value of the axis of a joystick"),
_("Save the value of the axis of the joystick (from -100 to 100)."),
_("Save in _PARAM3_ the value of axis _PARAM2_ of joystick _PARAM1_"),
_("Joystick"),
"res/actions/joystick24.png",
"res/actions/joystick.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Joystick number (first joystick: 0)"))
.AddParameter("joyaxis", _("Axis"))
.AddParameter("scenevar", _("Save the result to the scene variable"))
.SetManipulatedType("number");
extension
.AddExpression("GetJoystickAxis",
_("Joystick axis"),
_("Value of an axis of a joystick"),
_("Joystick"),
"res/conditions/joystick.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Joystick number (first joystick: 0)"))
.AddParameter("joyaxis", _("Axis"));
#endif
}
} // namespace gd

View File

@@ -15,7 +15,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
.SetExtensionInformation(
"BuiltinNetwork",
_("Basic internet features"),
_("Features to send web requests, communicate with external \"APIs\" and other network related tasks."),
_("Features to send web requests, communicate with external \"APIs\" "
"and other network related tasks."),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/all-features/network");
@@ -24,33 +25,33 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
extension
.AddAction(
"SendRequest",
_("Send a request to a web page"),
_("Send a request to the specified web page.\n\nPlease note that for "
"the web games, the game must be hosted on the same host "
"as specified below, except if the server is configured to answer "
"to all requests (cross-domain requests)."),
_("Send _PARAM3_ request to _PARAM0__PARAM1_ with body: _PARAM2_"),
"Send a request to a web page",
"Send a request to the specified web page.\n\nPlease note that for "
"the web games, the game must be hosted on the same host "
"as specified below, except if the server is configured to answer "
"to all requests (cross-domain requests).",
"Send _PARAM3_ request to _PARAM0__PARAM1_ with body: _PARAM2_",
_("Network"),
"res/actions/net24.png",
"res/actions/net.png")
.AddParameter("string", _("Host, with protocol"))
.SetParameterLongDescription(_("Example: \"http://example.com/\"."))
.AddParameter("string", _("Path"))
.AddParameter("string", "Host, with protocol")
.SetParameterLongDescription("Example: \"http://example.com/\".")
.AddParameter("string", "Path")
.SetParameterLongDescription(
_("Example: \"/user/123\" or \"/some-page.php\"."))
.AddParameter("string", _("Request body content"))
.AddParameter("string", _("Method: \"POST\" or \"GET\""), "", true)
.SetParameterLongDescription(_("If empty, \"GET\" will be used."))
"Example: \"/user/123\" or \"/some-page.php\".")
.AddParameter("string", "Request body content")
.AddParameter("string", "Method: \"POST\" or \"GET\"", "", true)
.SetParameterLongDescription("If empty, \"GET\" will be used.")
.SetDefaultValue("\"GET\"")
.AddParameter("string", _("Content type"), "", true)
.AddParameter("string", "Content type", "", true)
.SetParameterLongDescription(
_("If empty, \"application/x-www-form-urlencoded\" will be used."))
.AddParameter("scenevar", _("Reponse scene variable"), "", true)
"If empty, \"application/x-www-form-urlencoded\" will be used.")
.AddParameter("scenevar", "Reponse scene variable", "", true)
.SetParameterLongDescription(
_("The response of the server will be stored, as a string, in this "
"variable. If the server returns *JSON*, you may want to use the "
"action \"Convert JSON to a scene variable\" afterwards, to "
"explore the results with a *structure variable*."))
"The response of the server will be stored, as a string, in this "
"variable. If the server returns *JSON*, you may want to use the "
"action \"Convert JSON to a scene variable\" afterwards, to "
"explore the results with a *structure variable*.")
.MarkAsComplex()
.SetHidden();
@@ -74,7 +75,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
"highly recommended."))
.AddParameter("string", _("Request body content"))
.AddParameter("stringWithSelector",
_("Resize mode"),
_("Request method"),
"[\"GET\", \"POST\", \"PUT\", \"HEAD\", \"DELETE\", "
"\"PATCH\", \"OPTIONS\"]",
false)

View File

@@ -7,7 +7,6 @@
#include <SFML/Graphics/Sprite.hpp>
#include <iostream>
#include "GDCore/Extensions/Builtin/SpriteExtension/Polygon2d.h"
#include "GDCore/Project/ImageManager.h"
using namespace std;
@@ -16,11 +15,7 @@ namespace gd {
Point Sprite::badPoint("");
Sprite::Sprite()
:
#if !defined(EMSCRIPTEN)
hasItsOwnImage(false),
#endif
automaticCollisionMask(true),
: automaticCollisionMask(true),
origine("origine"),
centre("centre"),
automaticCentre(true) {
@@ -73,36 +68,10 @@ Point& Sprite::GetPoint(const gd::String& name) {
bool Sprite::SetDefaultCenterPoint(bool enabled) {
automaticCentre = enabled;
#if !defined(EMSCRIPTEN)
if (automaticCentre)
centre.SetXY(sfmlSprite.getLocalBounds().width / 2,
sfmlSprite.getLocalBounds().height / 2);
#endif
return true;
}
std::vector<Polygon2d> Sprite::GetCollisionMask() const {
// TODO(perf): Cache to avoid re-creating a mask at every call
#if !defined(EMSCRIPTEN)
if (automaticCollisionMask) {
std::vector<Polygon2d> mask;
Polygon2d rectangle;
rectangle.vertices.push_back(sf::Vector2f(0, 0));
rectangle.vertices.push_back(
sf::Vector2f(sfmlSprite.getLocalBounds().width, 0));
rectangle.vertices.push_back(sf::Vector2f(
sfmlSprite.getLocalBounds().width, sfmlSprite.getLocalBounds().height));
rectangle.vertices.push_back(
sf::Vector2f(0, sfmlSprite.getLocalBounds().height));
mask.push_back(rectangle);
return mask;
}
#endif
return customCollisionMask;
}
@@ -111,25 +80,4 @@ void Sprite::SetCustomCollisionMask(
customCollisionMask = collisionMask;
}
#if !defined(EMSCRIPTEN)
void Sprite::LoadImage(std::shared_ptr<SFMLTextureWrapper> image_) {
sfmlImage = image_;
sfmlSprite.setTexture(sfmlImage->texture, true);
hasItsOwnImage = false;
if (automaticCentre)
centre.SetXY(sfmlSprite.getLocalBounds().width / 2,
sfmlSprite.getLocalBounds().height / 2);
}
void Sprite::MakeSpriteOwnsItsImage() {
if (!hasItsOwnImage || sfmlImage == std::shared_ptr<SFMLTextureWrapper>()) {
sfmlImage = std::make_shared<SFMLTextureWrapper>(
sfmlImage->texture); // Copy the texture.
sfmlSprite.setTexture(sfmlImage->texture);
hasItsOwnImage = true;
}
}
#endif
} // namespace gd

View File

@@ -11,7 +11,6 @@
#include "GDCore/Extensions/Builtin/SpriteExtension/Point.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Polygon2d.h"
#include "GDCore/String.h"
class SFMLTextureWrapper;
#undef LoadImage // prevent windows.h to be polluting everything
namespace gd {
@@ -19,9 +18,6 @@ namespace gd {
/**
* \brief Represents a sprite to be displayed on the screen.
*
* A sprite contains a SFML sprite to be displayed, some points,
* and can also have its own texture (rather than a texture from ImageManager).
*
* \see Direction
* \see SpriteObject
* \ingroup SpriteObjectExtension
@@ -163,53 +159,7 @@ class GD_CORE_API Sprite {
*/
bool SetDefaultCenterPoint(bool enabled);
#if !defined(EMSCRIPTEN)
/** \name Sprite runtime management
* Functions used by the C++ game engine.
*/
///@{
/**
* \brief Get the SFML sprite associated with the sprite
*/
inline const sf::Sprite& GetSFMLSprite() const { return sfmlSprite; }
/**
* \brief Get the SFML sprite associated with the sprite
*/
inline sf::Sprite& GetSFMLSprite() { return sfmlSprite; }
/**
* \brief Set the SFML texture of the sprite
*/
void LoadImage(std::shared_ptr<SFMLTextureWrapper> image);
/**
* \brief Get SFML texture used by the sprite
*/
std::shared_ptr<SFMLTextureWrapper> GetSFMLTexture() { return sfmlImage; };
/**
* \brief Get SFML texture used by the sprite
*/
const std::shared_ptr<SFMLTextureWrapper> GetSFMLTexture() const {
return sfmlImage;
};
/**
* \brief Make the sprite, if it uses a texture from ImageManager,
* copy this texture and take ownership of it.
*/
void MakeSpriteOwnsItsImage();
///@}
#endif
private:
#if !defined(EMSCRIPTEN)
sf::Sprite sfmlSprite; ///< Displayed SFML sprite
std::shared_ptr<SFMLTextureWrapper>
sfmlImage; ///< Pointer to the image displayed by the sprite.
bool hasItsOwnImage; ///< True if sfmlImage is only owned by this Sprite.
#endif
gd::String image; ///< Name of the image to be loaded in Image Manager.
bool automaticCollisionMask; ///< True to use the custom collision mask.

View File

@@ -66,7 +66,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"res/actions/animation.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("string", _("Animation name"))
.AddParameter("objectAnimationName", _("Animation name"))
.MarkAsAdvanced();
obj.AddAction(
@@ -133,9 +133,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.MarkAsSimple();
obj.AddAction("TourneVersPos",
_("Rotate an object toward a position"),
_("Rotate an object towards a position."),
_("Rotate _PARAM0_ towards _PARAM1_;_PARAM2_"),
"Rotate an object toward a position",
"Rotate an object towards a position.",
"Rotate _PARAM0_ towards _PARAM1_;_PARAM2_",
_("Direction"),
"res/actions/direction24.png",
"res/actions/direction.png")
@@ -230,7 +230,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"res/conditions/animation.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("string", _("Animation name"))
.AddParameter("objectAnimationName", _("Animation name"))
.MarkAsAdvanced();
obj.AddCondition(
@@ -249,7 +249,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
obj.AddCondition("Sprite",
_("Current frame"),
_("Compare the index of the current frame in the animation displayed by the specified object. The first frame in an animation starts at index 0."),
_("Compare the index of the current frame in the animation "
"displayed by the specified object. The first frame in an "
"animation starts at index 0."),
_("the animation frame"),
_("Animations and images"),
"res/conditions/sprite24.png",
@@ -332,47 +334,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
obj.AddAction("CopyImageOnImageOfSprite",
_("Copy an image on the current one of an object"),
_("Copy an image on the current image of an object.\nNote that "
"the source image must be preferably kept loaded in memory."),
_("Copy image _PARAM2_ on the current of _PARAM0_ at "
"_PARAM3_;_PARAM4_"),
obj.AddAction("ChangeColor",
_("Tint color"),
_("Change the tint of an object. The default color is white."),
_("Change tint of _PARAM0_ to _PARAM1_"),
_("Effects"),
"res/copy24.png",
"res/copyicon.png")
.AddParameter("object", _("Object"), "Sprite")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("string", _("Name of the source image"))
.AddParameter("expression", _("X position"))
.AddParameter("expression", _("Y position"))
.AddParameter(
"yesorno",
_("Should the copy take in account the source transparency\?"));
obj.AddAction(
"CreateMaskFromColorOnActualImage", // Actual is indeed a mistake :
// Current should have been
// chosen.
_("Make a color of the image of an object transparent"),
_("Make a color of the image of an object transparent."),
_("Make color _PARAM1_ of the current image of _PARAM0_ transparent"),
_("Effects"),
"res/actions/opacity24.png",
"res/actions/opacity.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("color", _("Color to make transparent"));
obj.AddAction(
"ChangeColor",
_("Tint color"),
_("Change the tint of an object. The default color is white."),
_("Change tint of _PARAM0_ to _PARAM1_"),
_("Effects"),
"res/actions/color24.png",
"res/actions/color.png")
"res/actions/color24.png",
"res/actions/color.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("color", _("Tint"));
@@ -436,15 +404,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.AddParameter("object", _("Object"), "Sprite");
obj.AddAction("TourneVers",
_("Rotate an object toward another"),
_("Rotate an object towards another."),
_("Rotate _PARAM0_ towards _PARAM1_"),
"Rotate an object toward another",
"Rotate an object towards another.",
"Rotate _PARAM0_ towards _PARAM1_",
_("Direction"),
"res/actions/direction24.png",
"res/actions/direction.png")
.AddParameter("object", _("Object to be rotated"), "Sprite")
.AddParameter("objectPtr", _("Rotate toward this object"))
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectPtr", "Rotate toward this object")
.AddCodeOnlyParameter("currentScene", "")
.SetHidden(); // Deprecated
@@ -455,7 +423,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"res/actions/position.png")
.SetHidden()
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("string", _("Name of the point"), "", true);
.AddParameter("objectPointName", _("Name of the point"), "", true);
obj.AddExpression("Y",
_("Y position of a point"),
@@ -464,7 +432,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"res/actions/position.png")
.SetHidden()
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("string", _("Name of the point"), "", true);
.AddParameter("objectPointName", _("Name of the point"), "", true);
obj.AddExpression("PointX",
_("X position of a point"),
@@ -473,7 +441,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"res/actions/position.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("string", _("Name of the point"));
.AddParameter("objectPointName", _("Name of the point"));
obj.AddExpression("PointY",
_("Y position of a point"),
@@ -482,7 +450,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"res/actions/position.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("string", _("Name of the point"));
.AddParameter("objectPointName", _("Name of the point"));
obj.AddExpression("Direc",
_("Direction"),

View File

@@ -10,7 +10,6 @@
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
#include "GDCore/Project/ImageManager.h"
#include "GDCore/Project/InitialInstance.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"

View File

@@ -16,7 +16,6 @@ class Object;
class Layout;
class Sprite;
class Animation;
class MainFrameWrapper;
class SerializerElement;
class PropertyDescriptor;
} // namespace gd

View File

@@ -112,9 +112,9 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
extension
.AddExpression("StrRFind",
_("Search in a text from the end"),
_("Search in a text from the end (return the position of "
"the result or -1 if not found)"),
"Search in a text from the end",
"Search in a text from the end (return the position of "
"the result or -1 if not found)",
_("Manipulation of text"),
"res/conditions/toujours24.png")
@@ -152,17 +152,17 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
extension
.AddExpression(
"StrRFindFrom",
_("Search in a text from the end, starting from a position"),
_("Search in a text from the end, starting from a position (return "
"the position of the result or -1 if not found)"),
"Search in a text from the end, starting from a position",
"Search in a text from the end, starting from a position (return "
"the position of the result or -1 if not found)",
_("Manipulation of text"),
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"))
.AddParameter("expression",
_("Position of the last character in the string to be "
"considered in the search"))
"Position of the last character in the string to be "
"considered in the search")
.SetHidden(); // Deprecated, see StrFindLastFrom instead.
extension

View File

@@ -87,9 +87,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddCondition("VarSceneDef",
_("Test if a scene variable is defined"),
_("Test if the scene variable exists."),
_("Scene variable _PARAM0_ is defined"),
"Test if a scene variable is defined",
"Test if the scene variable exists.",
"Scene variable _PARAM0_ is defined",
_("Variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
@@ -136,9 +136,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddCondition("VarGlobalDef",
_("Test if a global variable is defined"),
_("Test if a global variable exists"),
_("Global variable _PARAM0_ is defined"),
"Test if a global variable is defined",
"Test if a global variable exists",
"Global variable _PARAM0_ is defined",
_("Variables/Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
@@ -341,7 +341,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"SceneVariableRemoveAt",
_("Remove variable from a scene array (by index)"),
_("Removes a variable at the specified index of a scene array variable."),
_("Remove variable at index _PARAM1_ from array variable _PARAM0_"),
_("Remove variable at index _PARAM1_ from scene array variable _PARAM0_"),
_("Variables/Collections/Arrays"),
"res/actions/var24.png",
"res/actions/var.png")
@@ -367,7 +367,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"GlobalVariableRemoveAt",
_("Remove variable from a global array (by index)"),
_("Removes a variable at the specified index of a global array variable."),
_("Remove variable at index _PARAM1_ from array variable _PARAM0_"),
_("Remove variable at index _PARAM1_ from global array variable _PARAM0_"),
_("Variables/Global variables/Collections/Arrays"),
"res/actions/var24.png",
"res/actions/var.png")

View File

@@ -275,6 +275,76 @@ BehaviorMetadata::AddExpressionAndConditionAndAction(
expression, condition, action);
}
#if defined(GD_IDE_ONLY)
gd::InstructionMetadata& BehaviorMetadata::AddDuplicatedAction(
const gd::String& newActionName, const gd::String& copiedActionName) {
gd::String newNameWithNamespace = extensionNamespace + newActionName;
gd::String copiedNameWithNamespace = extensionNamespace + copiedActionName;
auto copiedAction = actionsInfos.find(copiedNameWithNamespace);
if (copiedAction == actionsInfos.end()) {
gd::LogWarning("Could not find an action with name " +
copiedNameWithNamespace + " to copy.");
} else {
actionsInfos[newNameWithNamespace] = copiedAction->second;
}
return actionsInfos[newNameWithNamespace];
}
gd::InstructionMetadata& BehaviorMetadata::AddDuplicatedCondition(
const gd::String& newConditionName, const gd::String& copiedConditionName) {
gd::String newNameWithNamespace = extensionNamespace + newConditionName;
gd::String copiedNameWithNamespace = extensionNamespace + copiedConditionName;
auto copiedCondition = conditionsInfos.find(copiedNameWithNamespace);
if (copiedCondition == conditionsInfos.end()) {
gd::LogWarning("Could not find a condition with name " +
copiedNameWithNamespace + " to copy.");
} else {
conditionsInfos[newNameWithNamespace] = copiedCondition->second;
}
return conditionsInfos[newNameWithNamespace];
}
gd::ExpressionMetadata& BehaviorMetadata::AddDuplicatedExpression(
const gd::String& newExpressionName,
const gd::String& copiedExpressionName) {
gd::String newNameWithNamespace = extensionNamespace + newExpressionName;
gd::String copiedNameWithNamespace =
extensionNamespace + copiedExpressionName;
auto copiedExpression = expressionsInfos.find(copiedNameWithNamespace);
if (copiedExpression == expressionsInfos.end()) {
gd::LogWarning("Could not find an expression with name " +
copiedNameWithNamespace + " to copy.");
} else {
expressionsInfos[newNameWithNamespace] = copiedExpression->second;
}
return expressionsInfos[newNameWithNamespace];
}
gd::ExpressionMetadata& BehaviorMetadata::AddDuplicatedStrExpression(
const gd::String& newExpressionName,
const gd::String& copiedExpressionName) {
gd::String newNameWithNamespace = extensionNamespace + newExpressionName;
gd::String copiedNameWithNamespace =
extensionNamespace + copiedExpressionName;
auto copiedExpression = strExpressionsInfos.find(copiedNameWithNamespace);
if (copiedExpression == strExpressionsInfos.end()) {
gd::LogWarning("Could not find a string expression with name " +
copiedNameWithNamespace + " to copy.");
} else {
strExpressionsInfos[newNameWithNamespace] = copiedExpression->second;
}
return strExpressionsInfos[newNameWithNamespace];
}
#endif
BehaviorMetadata& BehaviorMetadata::SetFullName(const gd::String& fullname_) {
#if defined(GD_IDE_ONLY)
fullname = fullname_;
@@ -323,4 +393,14 @@ const gd::String& BehaviorMetadata::GetName() const {
return instance->GetTypeName();
}
gd::Behavior& BehaviorMetadata::Get() const {
if (!instance)
gd::LogFatalError(
"Trying to get a behavior from a BehaviorMetadata that has no "
"behavior. This will crash - please double check that the "
"BehaviorMetadata is valid.");
return *instance;
}
} // namespace gd

View File

@@ -138,6 +138,46 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& group,
const gd::String& icon);
/**
* \brief Create a new action which is the duplicate of the specified one.
*
* Useful for handling a deprecated action that is just a "copy" of the new
* one.
*/
gd::InstructionMetadata& AddDuplicatedAction(
const gd::String& newActionName, const gd::String& copiedActionName);
/**
* \brief Create a new condition which is the duplicate of the specified one.
*
* Useful for handling a deprecated condition that is just a "copy" of the new
* one.
*/
gd::InstructionMetadata& AddDuplicatedCondition(
const gd::String& newConditionName,
const gd::String& copiedConditionName);
/**
* \brief Create a new expression which is the duplicate of the specified one.
*
* Useful for handling a deprecated expression that is just a "copy" of the
* new one.
*/
gd::ExpressionMetadata& AddDuplicatedExpression(
const gd::String& newExpressionName,
const gd::String& copiedExpressionName);
/**
* \brief Create a new string expression which is the duplicate of the
* specified one.
*
* Useful for handling a deprecated string expression that is just a "copy" of
* the new one.
*/
gd::ExpressionMetadata& AddDuplicatedStrExpression(
const gd::String& newExpressionName,
const gd::String& copiedExpressionName);
BehaviorMetadata& SetFullName(const gd::String& fullname_);
BehaviorMetadata& SetDefaultName(const gd::String& defaultName_);
BehaviorMetadata& SetDescription(const gd::String& description_);
@@ -200,7 +240,7 @@ class GD_CORE_API BehaviorMetadata {
/**
* \brief Return the associated gd::Behavior, handling behavior contents.
*/
gd::Behavior& Get() const { return *instance; }
gd::Behavior& Get() const;
/**
* \brief Return the associated gd::BehaviorsSharedData, handling behavior

View File

@@ -7,7 +7,8 @@
namespace gd {
EffectMetadata::EffectMetadata(const gd::String& type_) : type(type_) {}
EffectMetadata::EffectMetadata(const gd::String& type_)
: type(type_), isMarkedAsNotWorkingForObjects(false) {}
EffectMetadata& EffectMetadata::SetIncludeFile(const gd::String& includeFile) {
includeFiles.clear();
@@ -22,4 +23,9 @@ EffectMetadata& EffectMetadata::AddIncludeFile(const gd::String& includeFile) {
return *this;
}
EffectMetadata& EffectMetadata::MarkAsNotWorkingForObjects() {
isMarkedAsNotWorkingForObjects = true;
return *this;
}
} // namespace gd

View File

@@ -8,6 +8,7 @@
#include <functional>
#include <map>
#include <memory>
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/String.h"
@@ -49,7 +50,8 @@ class GD_CORE_API EffectMetadata {
};
/**
* Set the help path of the effect, relative to the GDevelop documentation root.
* Set the help path of the effect, relative to the GDevelop documentation
* root.
*/
EffectMetadata& SetHelpPath(const gd::String& path) {
helpPath = path;
@@ -66,6 +68,11 @@ class GD_CORE_API EffectMetadata {
*/
EffectMetadata& AddIncludeFile(const gd::String& includeFile);
/**
* \brief Mark the effect as not working as an object effect.
*/
EffectMetadata& MarkAsNotWorkingForObjects();
/**
* \brief Return a reference to the properties of this effect.
*/
@@ -81,12 +88,14 @@ class GD_CORE_API EffectMetadata {
}
/**
* \brief Get the help path of the effect, relative to the GDevelop documentation root.
* \brief Get the help path of the effect, relative to the GDevelop
* documentation root.
*/
const gd::String& GetHelpPath() const { return helpPath; }
/**
* \brief Get the type of the effect (its internal name, like "BlackAndWhite").
* \brief Get the type of the effect (its internal name, like
* "BlackAndWhite").
*/
const gd::String& GetType() const { return type; }
@@ -107,6 +116,11 @@ class GD_CORE_API EffectMetadata {
return includeFiles;
}
/**
* \brief Check if the effect is marked as not working as an object effect.
*/
bool IsMarkedAsNotWorkingForObjects() const { return isMarkedAsNotWorkingForObjects; };
private:
gd::String extensionNamespace;
gd::String type;
@@ -114,6 +128,7 @@ class GD_CORE_API EffectMetadata {
gd::String fullname;
gd::String description;
std::vector<gd::String> includeFiles;
bool isMarkedAsNotWorkingForObjects;
std::map<gd::String, gd::PropertyDescriptor> properties;
};

View File

@@ -187,6 +187,19 @@ class GD_CORE_API InstructionMetadata {
return *this;
};
/**
* \brief Set the additional information, used for some parameters
* with special type (for example, it can contains the type of object accepted
* by the parameter), for the last added parameter.
*
* \see AddParameter
*/
InstructionMetadata &SetParameterExtraInfo(const gd::String &extraInfo) {
if (!parameters.empty())
parameters.back().SetExtraInfo(extraInfo);
return *this;
};
/**
* \brief Add the default parameters for an instruction manipulating the
* specified type ("string", "number") with the default operators.
@@ -221,14 +234,14 @@ class GD_CORE_API InstructionMetadata {
/**
* \brief Check if the instruction is an object instruction.
*/
bool IsObjectInstruction() {
bool IsObjectInstruction() const {
return isObjectInstruction;
}
/**
* \brief Check if the instruction is a behavior instruction.
*/
bool IsBehaviorInstruction() {
bool IsBehaviorInstruction() const {
return isBehaviorInstruction;
}

View File

@@ -19,7 +19,7 @@ using namespace std;
namespace gd {
gd::BehaviorMetadata MetadataProvider::badBehaviorInfo;
gd::BehaviorMetadata MetadataProvider::badBehaviorMetadata;
gd::ObjectMetadata MetadataProvider::badObjectInfo;
gd::EffectMetadata MetadataProvider::badEffectMetadata;
gd::InstructionMetadata MetadataProvider::badInstructionMetadata;
@@ -38,7 +38,7 @@ MetadataProvider::GetExtensionAndBehaviorMetadata(const gd::Platform& platform,
}
}
return ExtensionAndMetadata<BehaviorMetadata>(badExtension, badBehaviorInfo);
return ExtensionAndMetadata<BehaviorMetadata>(badExtension, badBehaviorMetadata);
}
const BehaviorMetadata& MetadataProvider::GetBehaviorMetadata(

View File

@@ -245,13 +245,21 @@ class GD_CORE_API MetadataProvider {
return &metadata == &badExpressionMetadata;
}
static bool IsBadInstructionMetadata(const gd::InstructionMetadata& metadata) {
return &metadata == &badInstructionMetadata;
}
static bool IsBadBehaviorMetadata(const gd::BehaviorMetadata& metadata) {
return &metadata == &badBehaviorMetadata;
}
virtual ~MetadataProvider();
private:
MetadataProvider();
static PlatformExtension badExtension;
static BehaviorMetadata badBehaviorInfo;
static BehaviorMetadata badBehaviorMetadata;
static ObjectMetadata badObjectInfo;
static EffectMetadata badEffectMetadata;
static gd::InstructionMetadata badInstructionMetadata;

View File

@@ -68,14 +68,14 @@ class GD_CORE_API ParameterMetadata {
/**
* \brief Return an optional additional information, used for some parameters
* with special type (For example, it can contains the type of object accepted
* with special type (for example, it can contains the type of object accepted
* by the parameter).
*/
const gd::String &GetExtraInfo() const { return supplementaryInformation; }
/**
* \brief Set an optional additional information, used for some parameters
* with special type (For example, it can contains the type of object accepted
* with special type (for example, it can contains the type of object accepted
* by the parameter).
*/
ParameterMetadata &SetExtraInfo(const gd::String &supplementaryInformation_) {
@@ -175,7 +175,8 @@ class GD_CORE_API ParameterMetadata {
* \brief Return true if the type of the parameter is an expression of the
* given type.
* \note If you had a new type of parameter, also add it in the IDE (
* see EventsFunctionParametersEditor) and in the EventsCodeGenerator.
* see EventsFunctionParametersEditor, ParameterRenderingService
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
*/
static bool IsExpression(const gd::String &type,
const gd::String &parameterType) {
@@ -187,7 +188,9 @@ class GD_CORE_API ParameterMetadata {
parameterType == "color" || parameterType == "file" ||
parameterType == "joyaxis" ||
parameterType == "stringWithSelector" ||
parameterType == "sceneName";
parameterType == "sceneName" ||
parameterType == "objectPointName" ||
parameterType == "objectAnimationName";
} else if (type == "variable") {
return parameterType == "objectvar" || parameterType == "globalvar" ||
parameterType == "scenevar";

View File

@@ -4,6 +4,7 @@
* reserved. This project is released under the MIT License.
*/
#include "ParameterMetadataTools.h"
#include "GDCore/Events/Expression.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
@@ -60,6 +61,24 @@ void ParameterMetadataTools::IterateOverParameters(
std::function<void(const gd::ParameterMetadata& parameterMetadata,
const gd::String& parameterValue,
const gd::String& lastObjectName)> fn) {
IterateOverParametersWithIndex(
parameters,
parametersMetadata,
[&fn](const gd::ParameterMetadata& parameterMetadata,
const gd::String& parameterValue,
size_t parameterIndex,
const gd::String& lastObjectName) {
fn(parameterMetadata, parameterValue, lastObjectName);
});
}
void ParameterMetadataTools::IterateOverParametersWithIndex(
const std::vector<gd::Expression>& parameters,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
std::function<void(const gd::ParameterMetadata& parameterMetadata,
const gd::String& parameterValue,
size_t parameterIndex,
const gd::String& lastObjectName)> fn) {
gd::String lastObjectName = "";
for (std::size_t pNb = 0; pNb < parametersMetadata.size(); ++pNb) {
const gd::ParameterMetadata& parameterMetadata = parametersMetadata[pNb];
@@ -70,7 +89,7 @@ void ParameterMetadataTools::IterateOverParameters(
? parameterMetadata.GetDefaultValue()
: parameterValue;
fn(parameterMetadata, parameterValueOrDefault, lastObjectName);
fn(parameterMetadata, parameterValueOrDefault, pNb, lastObjectName);
// Memorize the last object name. By convention, parameters that require
// an object (mainly, "objectvar" and "behavior") should be placed after

View File

@@ -35,6 +35,19 @@ class GD_CORE_API ParameterMetadataTools {
const gd::String& parameterValue,
const gd::String& lastObjectName)> fn);
/**
* Iterate over a list of parameters and their values.
* Callback function is called with the parameter metadata, its value
* and if applicable the name of the object it's linked to.
*/
static void IterateOverParametersWithIndex(
const std::vector<gd::Expression>& parameters,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
std::function<void(const gd::ParameterMetadata& parameterMetadata,
const gd::String& parameterValue,
size_t parameterIndex,
const gd::String& lastObjectName)> fn);
/**
* Given a parameter, return, if applicable, the index of the object parameter
* it's linked to.

View File

@@ -100,26 +100,6 @@ std::unique_ptr<gd::Object> Platform::CreateObject(
return std::unique_ptr<gd::Object>(std::move(object));
}
gd::Behavior* Platform::GetBehavior(const gd::String& behaviorType) const {
for (std::size_t i = 0; i < extensionsLoaded.size(); ++i) {
gd::Behavior* behavior = extensionsLoaded[i]->GetBehavior(behaviorType);
if (behavior) return behavior;
}
return nullptr;
}
gd::BehaviorsSharedData* Platform::GetBehaviorSharedDatas(
const gd::String& behaviorType) const {
for (std::size_t i = 0; i < extensionsLoaded.size(); ++i) {
gd::BehaviorsSharedData* behaviorSharedData =
extensionsLoaded[i]->GetBehaviorSharedDatas(behaviorType);
if (behaviorSharedData) return behaviorSharedData;
}
return nullptr;
}
#if defined(GD_IDE_ONLY)
std::shared_ptr<gd::BaseEvent> Platform::CreateEvent(
const gd::String& eventType) const {

View File

@@ -126,7 +126,8 @@ class GD_CORE_API Platform {
///@}
/** \name Factory method
* Member functions used to create the platforms objects
* Member functions used to create the platform objects.
* TODO: This could be moved to gd::MetadataProvider.
*/
///@{
@@ -136,18 +137,6 @@ class GD_CORE_API Platform {
std::unique_ptr<gd::Object> CreateObject(gd::String type,
const gd::String& name) const;
/**
* \brief Get the class handling the behavior with the given type, or
* `nullptr` if no behavior with the given type is found.
*/
gd::Behavior* GetBehavior(const gd::String& type) const;
/**
* \brief Get the class handling the behavior shared data with the given type,
* or `nullptr` if no behavior with the given type is found.
*/
gd::BehaviorsSharedData* GetBehaviorSharedDatas(const gd::String& type) const;
#if defined(GD_IDE_ONLY)
/**
* \brief Create an event of given type
@@ -165,11 +154,13 @@ class GD_CORE_API Platform {
/**
* \brief Called when the IDE is about to shut down: Take this opportunity for
* erasing for example any temporary file.
* @deprecated This should be removed.
*/
virtual void OnIDEClosed(){};
/**
* \brief Called when the IDE is initialized and ready to be used.
* @deprecated This should be removed.
*/
virtual void OnIDEInitialized(){};

View File

@@ -512,7 +512,7 @@ PlatformExtension::GetAllStrExpressionsForBehavior(gd::String autoType) {
return badExpressionsMetadata;
}
gd::BaseEventSPtr PlatformExtension::CreateEvent(gd::String eventType) const {
gd::BaseEventSPtr PlatformExtension::CreateEvent(const gd::String& eventType) const {
if (eventsInfos.find(eventType) != eventsInfos.end()) {
if (eventsInfos.find(eventType)->second.instance ==
std::shared_ptr<BaseEvent>()) {
@@ -531,14 +531,14 @@ gd::BaseEventSPtr PlatformExtension::CreateEvent(gd::String eventType) const {
#endif
CreateFunPtr PlatformExtension::GetObjectCreationFunctionPtr(
gd::String objectType) const {
const gd::String& objectType) const {
if (objectsInfos.find(objectType) != objectsInfos.end())
return objectsInfos.find(objectType)->second.createFunPtr;
return NULL;
}
gd::Behavior* PlatformExtension::GetBehavior(gd::String type) const {
gd::Behavior* PlatformExtension::GetBehavior(const gd::String& type) const {
if (behaviorsInfo.find(type) != behaviorsInfo.end())
return &behaviorsInfo.find(type)->second.Get();
@@ -546,7 +546,7 @@ gd::Behavior* PlatformExtension::GetBehavior(gd::String type) const {
}
gd::BehaviorsSharedData* PlatformExtension::GetBehaviorSharedDatas(
gd::String type) const {
const gd::String& type) const {
if (behaviorsInfo.find(type) != behaviorsInfo.end() &&
behaviorsInfo.find(type)->second.GetSharedDataInstance())
return behaviorsInfo.find(type)->second.GetSharedDataInstance();

View File

@@ -400,7 +400,7 @@ class GD_CORE_API PlatformExtension {
* \brief Return a function to create the object if the type is handled by the
* extension
*/
CreateFunPtr GetObjectCreationFunctionPtr(gd::String objectType) const;
CreateFunPtr GetObjectCreationFunctionPtr(const gd::String& objectType) const;
/**
* \brief Return a vector containing all the effect types provided by the
@@ -413,13 +413,13 @@ class GD_CORE_API PlatformExtension {
*
* Return an empty pointer if \a eventType is not provided by the extension.
*/
std::shared_ptr<gd::BaseEvent> CreateEvent(gd::String eventType) const;
std::shared_ptr<gd::BaseEvent> CreateEvent(const gd::String& eventType) const;
/**
* \brief Get the gd::Behavior handling the given behavior type.
*
* Return nullptr if \a behaviorType is not provided by the extension.
*/
gd::Behavior* GetBehavior(gd::String behaviorType) const;
gd::Behavior* GetBehavior(const gd::String& behaviorType) const;
/**
* \brief Get the gd::BehaviorsSharedData handling the given behavior shared
@@ -428,7 +428,7 @@ class GD_CORE_API PlatformExtension {
* Return nullptr if \a behaviorType is not provided by the extension.
*/
gd::BehaviorsSharedData* GetBehaviorSharedDatas(
gd::String behaviorType) const;
const gd::String& behaviorType) const;
/**
* \brief Return a reference to the ObjectMetadata object associated to \a

View File

@@ -15,25 +15,18 @@
#include "GDCore/Project/Project.h"
#include "GDCore/Project/SourceFile.h"
DependenciesAnalyzer::DependenciesAnalyzer(gd::Project& project_,
gd::Layout& layout_)
DependenciesAnalyzer::DependenciesAnalyzer(const gd::Project& project_,
const gd::Layout& layout_)
: project(project_), layout(&layout_), externalEvents(NULL) {
parentScenes.push_back(layout->GetName());
}
DependenciesAnalyzer::DependenciesAnalyzer(gd::Project& project_,
gd::ExternalEvents& externalEvents_)
DependenciesAnalyzer::DependenciesAnalyzer(const gd::Project& project_,
const gd::ExternalEvents& externalEvents_)
: project(project_), layout(NULL), externalEvents(&externalEvents_) {
parentExternalEvents.push_back(externalEvents->GetName());
}
DependenciesAnalyzer::DependenciesAnalyzer(const DependenciesAnalyzer& parent)
: parentScenes(parent.parentScenes),
parentExternalEvents(parent.parentExternalEvents),
project(parent.project),
layout(NULL),
externalEvents(NULL) {}
bool DependenciesAnalyzer::Analyze() {
if (layout)
return Analyze(layout->GetEvents(), true);
@@ -47,9 +40,9 @@ bool DependenciesAnalyzer::Analyze() {
DependenciesAnalyzer::~DependenciesAnalyzer() {}
bool DependenciesAnalyzer::Analyze(gd::EventsList& events, bool isOnTopLevel) {
bool DependenciesAnalyzer::Analyze(const gd::EventsList& events, bool isOnTopLevel) {
for (unsigned int i = 0; i < events.size(); ++i) {
gd::LinkEvent* linkEvent = dynamic_cast<gd::LinkEvent*>(&events[i]);
const gd::LinkEvent* linkEvent = dynamic_cast<const gd::LinkEvent*>(&events[i]);
if (linkEvent) {
DependenciesAnalyzer analyzer(*this);
@@ -113,7 +106,7 @@ bool DependenciesAnalyzer::Analyze(gd::EventsList& events, bool isOnTopLevel) {
sourceFilesDependencies.insert(dependencies.begin(), dependencies.end());
const gd::String& associatedSourceFile =
events[i].GetAssociatedGDManagedSourceFile(project);
events[i].GetAssociatedGDManagedSourceFile(const_cast<gd::Project&>(project));
if (!associatedSourceFile.empty())
sourceFilesDependencies.insert(associatedSourceFile);

View File

@@ -35,7 +35,7 @@ class GD_CORE_API DependenciesAnalyzer {
/**
* \brief Constructor for analyzing the dependencies of a layout
*/
DependenciesAnalyzer(gd::Project& project_, gd::Layout& layout_);
DependenciesAnalyzer(const gd::Project& project_, const gd::Layout& layout_);
/**
* \brief Constructor for analyzing the dependencies of external events.
@@ -45,8 +45,8 @@ class GD_CORE_API DependenciesAnalyzer {
* external events can be compiled separatly and called by a scene. \see
* DependenciesAnalyzer::ExternalEventsCanBeCompiledForAScene
*/
DependenciesAnalyzer(gd::Project& project_,
gd::ExternalEvents& externalEvents);
DependenciesAnalyzer(const gd::Project& project_,
const gd::ExternalEvents& externalEvents);
virtual ~DependenciesAnalyzer();
@@ -124,13 +124,7 @@ class GD_CORE_API DependenciesAnalyzer {
* (they have no parents). \return false if a circular dependency exists, true
* otherwise.
*/
bool Analyze(gd::EventsList& events, bool isOnTopLevel);
/**
* \brief Internal constructor used when analyzing a linked layout/external
* events.
*/
DependenciesAnalyzer(const DependenciesAnalyzer& parent);
bool Analyze(const gd::EventsList& events, bool isOnTopLevel);
void AddParentScene(gd::String parentScene) {
parentScenes.push_back(parentScene);
@@ -161,9 +155,9 @@ class GD_CORE_API DependenciesAnalyzer {
std::vector<gd::String>
parentExternalEvents; ///< Used to check for circular dependencies.
gd::Project& project;
gd::Layout* layout;
gd::ExternalEvents* externalEvents;
const gd::Project& project;
const gd::Layout* layout;
const gd::ExternalEvents* externalEvents;
};
#endif // DEPENDENCIESANALYZER_H

View File

@@ -0,0 +1,25 @@
/*
* 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)
#include "GDCore/CommonTools.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "EditorSettings.h"
namespace gd {
EditorSettings::EditorSettings() {}
void EditorSettings::SerializeTo(SerializerElement& element) const {
element = content;
}
void EditorSettings::UnserializeFrom(
const SerializerElement& element) {
content = element;
}
} // namespace gd
#endif

View File

@@ -0,0 +1,46 @@
/*
* 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 SCENECANVASSETTINGS_H
#define SCENECANVASSETTINGS_H
#include "GDCore/String.h"
#include "GDCore/Serialization/SerializerElement.h"
namespace gd {
/**
* \brief Container for arbitrary serialized data to be used by the editor
* to store settings.
*
* \see Scene
*/
class GD_CORE_API EditorSettings {
public:
EditorSettings();
virtual ~EditorSettings(){};
/** \name Serialization
*/
///@{
/**
* \brief Serialize the settings.
*/
void SerializeTo(SerializerElement& element) const;
/**
* \brief Unserialize the settings.
*/
void UnserializeFrom(const SerializerElement& element);
///@}
private:
gd::SerializerElement content; ///< Arbitrary content, depending on the editor.
};
} // namespace gd
#endif // SCENECANVASSETTINGS_H
#endif

View File

@@ -1,59 +0,0 @@
/*
* 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)
#include "LayoutEditorCanvasOptions.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Serialization/SerializerElement.h"
namespace gd {
LayoutEditorCanvasOptions::LayoutEditorCanvasOptions()
: grid(false),
snap(true),
gridWidth(32),
gridHeight(32),
gridOffsetX(0),
gridOffsetY(0),
gridType("rectangular"),
gridR(158),
gridG(180),
gridB(255),
zoomFactor(1),
windowMask(false) {}
void LayoutEditorCanvasOptions::SerializeTo(SerializerElement& element) const {
element.SetAttribute("grid", grid);
element.SetAttribute("snap", snap);
element.SetAttribute("gridWidth", gridWidth);
element.SetAttribute("gridHeight", gridHeight);
element.SetAttribute("gridOffsetX", gridOffsetX);
element.SetAttribute("gridOffsetY", gridOffsetY);
element.SetAttribute("gridType", gridType);
element.SetAttribute("gridR", gridR);
element.SetAttribute("gridG", gridG);
element.SetAttribute("gridB", gridB);
element.SetAttribute("zoomFactor", zoomFactor);
element.SetAttribute("windowMask", windowMask);
}
void LayoutEditorCanvasOptions::UnserializeFrom(
const SerializerElement& element) {
grid = element.GetBoolAttribute("grid");
snap = element.GetBoolAttribute("snap");
windowMask = element.GetBoolAttribute("windowMask");
gridWidth = element.GetDoubleAttribute("gridWidth", 32);
gridHeight = element.GetDoubleAttribute("gridHeight", 32);
gridOffsetX = element.GetDoubleAttribute("gridOffsetX", 0);
gridOffsetY = element.GetDoubleAttribute("gridOffsetY", 0);
gridType = element.GetStringAttribute("gridType", "rectangular");
gridR = element.GetIntAttribute("gridR", 158);
gridG = element.GetIntAttribute("gridG", 180);
gridB = element.GetIntAttribute("gridB", 255);
zoomFactor = element.GetDoubleAttribute("zoomFactor", 1.0);
}
} // namespace gd
#endif

View File

@@ -1,58 +0,0 @@
/*
* 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 SCENECANVASSETTINGS_H
#define SCENECANVASSETTINGS_H
#include "GDCore/String.h"
namespace gd {
class SerializerElement;
}
namespace gd {
/**
* \brief Tool class used to store settings of a LayoutEditorCanvas.
*
* \see Scene
*/
class GD_CORE_API LayoutEditorCanvasOptions {
public:
LayoutEditorCanvasOptions();
virtual ~LayoutEditorCanvasOptions(){};
/** \name Serialization
*/
///@{
/**
* \brief Serialize instances container.
*/
void SerializeTo(SerializerElement& element) const;
/**
* \brief Unserialize the instances container.
*/
void UnserializeFrom(const SerializerElement& element);
///@}
bool grid; ///< True if grid activated in editor
bool snap; ///< True if snap to grid activated in editor
double gridWidth; ///< Grid width in editor
double gridHeight; ///< Grid height in editor
double gridOffsetX; ///< Grid X offset
double gridOffsetY; ///< Grid Y offset
gd::String gridType; ///< Grid type: rectangular or isometric
int gridR; ///< Grid red color in editor
int gridG; ///< Grid green color in editor
int gridB; ///< Grid blue color in editor
double zoomFactor; ///< Stores the zoom factor
bool windowMask; ///< True if window mask displayed in editor
};
} // namespace gd
#endif // SCENECANVASSETTINGS_H
#endif

View File

@@ -0,0 +1,164 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
namespace gd {
/**
* \brief Go through the nodes and rename any reference to an object behavior.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionBehaviorRenamer
: public ExpressionParser2NodeWorker {
public:
ExpressionBehaviorRenamer(const gd::ObjectsContainer& globalObjectsContainer_,
const gd::ObjectsContainer& objectsContainer_,
const gd::String& objectName_,
const gd::String& oldBehaviorName_,
const gd::String& newBehaviorName_)
: hasDoneRenaming(false),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
objectName(objectName_),
oldBehaviorName(oldBehaviorName_),
newBehaviorName(newBehaviorName_){};
virtual ~ExpressionBehaviorRenamer(){};
bool HasDoneRenaming() const { return hasDoneRenaming; }
protected:
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
node.expression->Visit(*this);
}
void OnVisitOperatorNode(OperatorNode& node) override {
node.leftHandSide->Visit(*this);
node.rightHandSide->Visit(*this);
}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
node.factor->Visit(*this);
}
void OnVisitNumberNode(NumberNode& node) override {}
void OnVisitTextNode(TextNode& node) override {}
void OnVisitVariableNode(VariableNode& node) override {
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
node.expression->Visit(*this);
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
if (!node.behaviorFunctionName.empty()) {
// Behavior function name
if (node.objectName == objectName && node.objectFunctionOrBehaviorName == oldBehaviorName) {
node.objectFunctionOrBehaviorName = newBehaviorName;
hasDoneRenaming = true;
}
}
}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
if (!node.behaviorName.empty()) {
// Behavior function call
if (node.objectName == objectName && node.behaviorName == oldBehaviorName) {
node.behaviorName = newBehaviorName;
hasDoneRenaming = true;
}
}
for (auto& parameter : node.parameters) {
parameter->Visit(*this);
}
}
void OnVisitEmptyNode(EmptyNode& node) override {}
private:
bool hasDoneRenaming;
const gd::ObjectsContainer& globalObjectsContainer;
const gd::ObjectsContainer& objectsContainer;
const gd::String& objectName; // The object name for which the behavior
// must be replaced.
const gd::String& oldBehaviorName;
const gd::String& newBehaviorName;
};
bool EventsBehaviorRenamer::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
const auto& metadata = isCondition
? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
instruction.GetParameters(),
metadata.GetParameters(),
[&](const gd::ParameterMetadata& parameterMetadata,
const gd::String& parameterValue,
size_t parameterIndex,
const gd::String& lastObjectName) {
const gd::String& type = parameterMetadata.type;
if (gd::ParameterMetadata::IsBehavior(type)) {
if (lastObjectName == objectName) {
if (parameterValue == oldBehaviorName) {
instruction.SetParameter(parameterIndex,
gd::Expression(newBehaviorName));
}
}
} else {
gd::ExpressionParser2 parser(
platform, GetGlobalObjectsContainer(), GetObjectsContainer());
auto node =
gd::ParameterMetadata::IsExpression("number", type)
? parser.ParseExpression("number", parameterValue)
: (gd::ParameterMetadata::IsExpression("string", type)
? parser.ParseExpression("string", parameterValue)
: std::unique_ptr<gd::ExpressionNode>());
if (node) {
ExpressionBehaviorRenamer renamer(GetGlobalObjectsContainer(),
GetObjectsContainer(),
objectName,
oldBehaviorName,
newBehaviorName);
node->Visit(renamer);
if (renamer.HasDoneRenaming()) {
instruction.SetParameter(
parameterIndex,
ExpressionParser2NodePrinter::PrintNode(*node));
}
}
}
});
return false;
}
EventsBehaviorRenamer::~EventsBehaviorRenamer() {}
} // namespace gd

View File

@@ -0,0 +1,52 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef EventsBehaviorRenamer_H
#define EventsBehaviorRenamer_H
#include <map>
#include <memory>
#include <vector>
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class BaseEvent;
class Platform;
class EventsList;
} // namespace gd
namespace gd {
/**
* \brief Replace in expressions and in parameters of actions or conditions, references
* to the name of a behavior of an object by another name.
*
* \ingroup IDE
*/
class GD_CORE_API EventsBehaviorRenamer : public ArbitraryEventsWorkerWithContext {
public:
EventsBehaviorRenamer(const gd::Platform &platform_,
const gd::String& objectName_,
const gd::String& oldBehaviorName_,
const gd::String& newBehaviorName_) :
platform(platform_),
objectName(objectName_),
oldBehaviorName(oldBehaviorName_),
newBehaviorName(newBehaviorName_)
{};
virtual ~EventsBehaviorRenamer();
private:
bool DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) override;
const gd::Platform &platform;
gd::String objectName;
gd::String oldBehaviorName;
gd::String newBehaviorName;
};
} // namespace gd
#endif // EventsBehaviorRenamer_H

View File

@@ -5,17 +5,19 @@
*/
#include "GDCore/IDE/Events/EventsRefactorer.h"
#include <memory>
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/Project/ObjectsContainer.h"
using namespace std;
@@ -31,10 +33,14 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
public:
ExpressionObjectRenamer(const gd::String& objectName_,
const gd::String& objectNewName_)
: hasDoneRenaming(false), objectName(objectName_), objectNewName(objectNewName_){};
: hasDoneRenaming(false),
objectName(objectName_),
objectNewName(objectNewName_){};
virtual ~ExpressionObjectRenamer(){};
static bool Rename(gd::ExpressionNode & node, const gd::String& objectName, const gd::String& objectNewName) {
static bool Rename(gd::ExpressionNode& node,
const gd::String& objectName,
const gd::String& objectNewName) {
if (ExpressionValidator::HasNoErrors(node)) {
ExpressionObjectRenamer renamer(objectName, objectNewName);
node.Visit(renamer);
@@ -72,7 +78,8 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
if (gd::ParameterMetadata::IsObject(node.type) && node.identifierName == objectName) {
if (gd::ParameterMetadata::IsObject(node.type) &&
node.identifierName == objectName) {
hasDoneRenaming = true;
node.identifierName = objectNewName;
}
@@ -109,10 +116,11 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
public:
ExpressionObjectFinder(const gd::String& objectName_)
: hasObject(false), objectName(objectName_) {};
: hasObject(false), objectName(objectName_){};
virtual ~ExpressionObjectFinder(){};
static bool CheckIfHasObject(gd::ExpressionNode & node, const gd::String & objectName) {
static bool CheckIfHasObject(gd::ExpressionNode& node,
const gd::String& objectName) {
if (ExpressionValidator::HasNoErrors(node)) {
ExpressionObjectFinder finder(objectName);
node.Visit(finder);
@@ -150,7 +158,8 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
if (gd::ParameterMetadata::IsObject(node.type) && node.identifierName == objectName) {
if (gd::ParameterMetadata::IsObject(node.type) &&
node.identifierName == objectName) {
hasObject = true;
}
}
@@ -183,7 +192,7 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
bool somethingModified = false;
for (std::size_t aId = 0; aId < actions.size(); ++aId) {
gd::InstructionMetadata instrInfos =
const gd::InstructionMetadata& instrInfos =
MetadataProvider::GetActionMetadata(platform, actions[aId].GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
// Replace object's name in parameters
@@ -194,20 +203,24 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("number", actions[aId].GetParameter(pNb).GetPlainString());
auto node = parser.ParseExpression(
"number", actions[aId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
actions[aId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
actions[aId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("string", actions[aId].GetParameter(pNb).GetPlainString());
auto node = parser.ParseExpression(
"string", actions[aId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
actions[aId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
actions[aId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
}
}
@@ -236,8 +249,9 @@ bool EventsRefactorer::RenameObjectInConditions(
bool somethingModified = false;
for (std::size_t cId = 0; cId < conditions.size(); ++cId) {
gd::InstructionMetadata instrInfos = MetadataProvider::GetConditionMetadata(
platform, conditions[cId].GetType());
const gd::InstructionMetadata& instrInfos =
MetadataProvider::GetConditionMetadata(platform,
conditions[cId].GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
// Replace object's name in parameters
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].type) &&
@@ -247,20 +261,24 @@ bool EventsRefactorer::RenameObjectInConditions(
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("number", conditions[cId].GetParameter(pNb).GetPlainString());
auto node = parser.ParseExpression(
"number", conditions[cId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
conditions[cId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
conditions[cId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("string", conditions[cId].GetParameter(pNb).GetPlainString());
auto node = parser.ParseExpression(
"string", conditions[cId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
conditions[cId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
conditions[cId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
}
}
@@ -293,8 +311,8 @@ bool EventsRefactorer::RenameObjectInEventParameters(
expression.GetPlainString() == oldName)
expression = gd::Expression(newName);
// Replace object's name in expressions
else if (ParameterMetadata::IsExpression(
"number", parameterMetadata.GetType())) {
else if (ParameterMetadata::IsExpression("number",
parameterMetadata.GetType())) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("number", expression.GetPlainString());
@@ -303,8 +321,8 @@ bool EventsRefactorer::RenameObjectInEventParameters(
}
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", parameterMetadata.GetType())) {
else if (ParameterMetadata::IsExpression("string",
parameterMetadata.GetType())) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("string", expression.GetPlainString());
@@ -337,13 +355,19 @@ void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
platform, project, layout, *actionsVectors[j], oldName, newName);
}
vector<pair<gd::Expression*, gd::ParameterMetadata>> expressionsWithMetadata =
events[i].GetAllExpressionsWithMetadata();
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);
gd::ParameterMetadata parameterMetadata =
expressionsWithMetadata[j].second;
bool somethingModified = RenameObjectInEventParameters(platform,
project,
layout,
*expression,
parameterMetadata,
oldName,
newName);
}
if (events[i].CanHaveSubEvents())
@@ -366,7 +390,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
for (std::size_t aId = 0; aId < actions.size(); ++aId) {
bool deleteMe = false;
gd::InstructionMetadata instrInfos =
const gd::InstructionMetadata& instrInfos =
MetadataProvider::GetActionMetadata(platform, actions[aId].GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
// Find object's name in parameters
@@ -379,7 +403,8 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("number", actions[aId].GetParameter(pNb).GetPlainString());
auto node = parser.ParseExpression(
"number", actions[aId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
deleteMe = true;
@@ -390,7 +415,8 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("string", actions[aId].GetParameter(pNb).GetPlainString());
auto node = parser.ParseExpression(
"string", actions[aId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
deleteMe = true;
@@ -427,8 +453,9 @@ bool EventsRefactorer::RemoveObjectInConditions(
for (std::size_t cId = 0; cId < conditions.size(); ++cId) {
bool deleteMe = false;
gd::InstructionMetadata instrInfos = MetadataProvider::GetConditionMetadata(
platform, conditions[cId].GetType());
const gd::InstructionMetadata& instrInfos =
MetadataProvider::GetConditionMetadata(platform,
conditions[cId].GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
// Find object's name in parameters
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].type) &&
@@ -440,7 +467,8 @@ bool EventsRefactorer::RemoveObjectInConditions(
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("number", conditions[cId].GetParameter(pNb).GetPlainString());
auto node = parser.ParseExpression(
"number", conditions[cId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
deleteMe = true;
@@ -451,7 +479,8 @@ bool EventsRefactorer::RemoveObjectInConditions(
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("string", conditions[cId].GetParameter(pNb).GetPlainString());
auto node = parser.ParseExpression(
"string", conditions[cId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
deleteMe = true;
@@ -781,10 +810,10 @@ bool EventsRefactorer::SearchStringInConditions(
}
bool EventsRefactorer::SearchStringInEvent(gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::BaseEvent& event,
gd::String search,
bool matchCase) {
gd::ObjectsContainer& layout,
gd::BaseEvent& event,
gd::String search,
bool matchCase) {
for (gd::String str : event.GetAllSearchableStrings()) {
if (matchCase) {
if (str.find(search) != gd::String::npos) return true;

View File

@@ -17,6 +17,8 @@
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/IDE/DependenciesAnalyzer.h"
using namespace std;
@@ -95,11 +97,11 @@ std::set<gd::String> EventsVariablesFinder::FindAllGlobalVariables(
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
std::set<gd::String> results2 =
FindArgumentsInEvents(platform,
project,
project.GetLayout(i),
project.GetLayout(i).GetEvents(),
"globalvar");
FindArgumentsInEventsAndDependencies(
platform,
project,
project.GetLayout(i),
"globalvar");
results.insert(results2.begin(), results2.end());
}
@@ -112,8 +114,8 @@ std::set<gd::String> EventsVariablesFinder::FindAllLayoutVariables(
const gd::Layout& layout) {
std::set<gd::String> results;
std::set<gd::String> results2 = FindArgumentsInEvents(
platform, project, layout, layout.GetEvents(), "scenevar");
std::set<gd::String> results2 = FindArgumentsInEventsAndDependencies(
platform, project, layout, "scenevar");
results.insert(results2.begin(), results2.end());
return results;
@@ -126,12 +128,12 @@ std::set<gd::String> EventsVariablesFinder::FindAllObjectVariables(
const gd::Object& object) {
std::set<gd::String> results;
std::set<gd::String> results2 = FindArgumentsInEvents(platform,
project,
layout,
layout.GetEvents(),
"objectvar",
object.GetName());
std::set<gd::String> results2 = FindArgumentsInEventsAndDependencies(
platform,
project,
layout,
"objectvar",
object.GetName());
results.insert(results2.begin(), results2.end());
return results;
@@ -149,7 +151,7 @@ std::set<gd::String> EventsVariablesFinder::FindArgumentsInInstructions(
for (std::size_t aId = 0; aId < instructions.size(); ++aId) {
gd::String lastObjectParameter = "";
gd::InstructionMetadata instrInfos =
const gd::InstructionMetadata& instrInfos =
instructionsAreConditions ? MetadataProvider::GetConditionMetadata(
platform, instructions[aId].GetType())
: MetadataProvider::GetActionMetadata(
@@ -203,6 +205,38 @@ std::set<gd::String> EventsVariablesFinder::FindArgumentsInInstructions(
return results;
}
std::set<gd::String> EventsVariablesFinder::FindArgumentsInEventsAndDependencies(
const gd::Platform& platform,
const gd::Project& project,
const gd::Layout& layout,
const gd::String& parameterType,
const gd::String& objectName) {
std::set<gd::String> results;
std::set<gd::String> results2 = FindArgumentsInEvents(
platform, project, layout, layout.GetEvents(), parameterType, objectName);
results.insert(results2.begin(), results2.end());
DependenciesAnalyzer dependenciesAnalyzer = DependenciesAnalyzer(project, layout);
dependenciesAnalyzer.Analyze();
for (const gd::String& externalEventName : dependenciesAnalyzer.GetExternalEventsDependencies()) {
const gd::ExternalEvents& externalEvents = project.GetExternalEvents(externalEventName);
std::set<gd::String> results3 = FindArgumentsInEvents(
platform, project, layout, externalEvents.GetEvents(), parameterType, objectName);
results.insert(results3.begin(), results3.end());
}
for (const gd::String& sceneName : dependenciesAnalyzer.GetScenesDependencies()) {
const gd::Layout& dependencyLayout = project.GetLayout(sceneName);
std::set<gd::String> results3 = FindArgumentsInEvents(
platform, project, dependencyLayout, dependencyLayout.GetEvents(), parameterType, objectName);
results.insert(results3.begin(), results3.end());
}
return results;
}
std::set<gd::String> EventsVariablesFinder::FindArgumentsInEvents(
const gd::Platform& platform,
const gd::Project& project,

View File

@@ -24,11 +24,17 @@ namespace gd {
* global or object variables.
*
* \todo Refactor this class using ArbitraryEventsWorker
* \todo Rework this class to return the shapes (maybe even types?) of the
* variables (in particular for structures and arrays), so we can use this
* for better autocompletions in the variables dialogs in the IDE.
*
* \ingroup IDE
*/
class EventsVariablesFinder {
public:
EventsVariablesFinder(){};
virtual ~EventsVariablesFinder(){};
/**
* Construct a list containing the name of all global variables used in the
* project.
@@ -94,10 +100,34 @@ class EventsVariablesFinder {
/**
* Construct a list of the value of the arguments for parameters of type @
* parameterType
* parameterType. It searchs in events dependencies.
*
* \param platform The platform of the project
* \param project The project used
* \param project The layout used
* \param layout The layout used
* \param events The events to be analyzed
* \param parameterType The parameters type to be analyzed
* \param objectName If not empty, parameters will be taken into account
* only if the last object parameter is filled with
* this value.
*
* \return A std::set filled with the values used for all parameters of the
* specified type
*/
static std::set<gd::String> FindArgumentsInEventsAndDependencies(
const gd::Platform& platform,
const gd::Project& project,
const gd::Layout& layout,
const gd::String& parameterType,
const gd::String& objectName = "");
/**
* Construct a list of the value of the arguments for parameters of type @
* parameterType. It doesn't search in events dependencies.
*
* \param platform The platform of the project
* \param project The project used
* \param layout The layout used
* \param events The events to be analyzed
* \param parameterType The parameters type to be analyzed
* \param objectName If not empty, parameters will be taken into account
@@ -113,10 +143,7 @@ class EventsVariablesFinder {
const gd::Layout& layout,
const gd::EventsList& events,
const gd::String& parameterType,
const gd::String& objectName = "");
EventsVariablesFinder(){};
virtual ~EventsVariablesFinder(){};
const gd::String& objectName);
};
} // namespace gd

View File

@@ -0,0 +1,31 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "ExpressionCompletionFinder.h"
namespace gd {
const gd::ParameterMetadata
ExpressionCompletionDescription::badParameterMetadata;
/**
* \brief Turn an ExpressionCompletionDescription to a string.
*/
std::ostream& operator<<(std::ostream& os,
ExpressionCompletionDescription const& value) {
os << "{ " << value.GetCompletionKind() << ", " << value.GetType() << ", "
<< value.GetPrefix() << ", " << value.GetObjectName() << ", "
<< value.GetBehaviorName() << ", "
<< (value.IsExact() ? "exact" : "non-exact") << ", "
<< (value.IsLastParameter() ? "last parameter" : "not last parameter")
<< ", "
<< (value.HasParameterMetadata()
? gd::String::From(&value.GetParameterMetadata())
: "no parameter metadata")
<< " }";
return os;
}
} // namespace gd

View File

@@ -8,10 +8,14 @@
#include <memory>
#include <vector>
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/IDE/Events/ExpressionNodeLocationFinder.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
namespace gd {
class Expression;
class ObjectsContainer;
@@ -33,19 +37,21 @@ struct ExpressionCompletionDescription {
/**
* The different kind of completions that can be described.
*/
enum CompletionKind {
Object,
Behavior,
Expression,
Variable,
};
enum CompletionKind { Object, Behavior, Expression, Variable, Text };
/**
* \brief Create a completion for an object with the given prefix
*/
static ExpressionCompletionDescription ForObject(const gd::String& type_,
const gd::String& prefix_) {
return ExpressionCompletionDescription(Object, type_, prefix_);
static ExpressionCompletionDescription ForObject(
const gd::String& type_,
const gd::String& prefix_,
size_t replacementStartPosition_,
size_t replacementEndPosition_) {
return ExpressionCompletionDescription(Object,
type_,
prefix_,
replacementStartPosition_,
replacementEndPosition_);
}
/**
@@ -53,17 +59,58 @@ struct ExpressionCompletionDescription {
* the specified object
*/
static ExpressionCompletionDescription ForBehavior(
const gd::String& prefix_, const gd::String& objectName_) {
return ExpressionCompletionDescription(Behavior, "", prefix_, objectName_);
const gd::String& prefix_,
size_t replacementStartPosition_,
size_t replacementEndPosition_,
const gd::String& objectName_) {
return ExpressionCompletionDescription(Behavior,
"",
prefix_,
replacementStartPosition_,
replacementEndPosition_,
objectName_);
}
/**
* \brief Create a completion for a variable with the given prefix
*/
static ExpressionCompletionDescription ForVariable(
const gd::String& type_, const gd::String& prefix_) {
return ExpressionCompletionDescription(Variable, type_, prefix_);
const gd::String& type_,
const gd::String& prefix_,
size_t replacementStartPosition_,
size_t replacementEndPosition_,
const gd::String& objectName_ = "") {
return ExpressionCompletionDescription(Variable,
type_,
prefix_,
replacementStartPosition_,
replacementEndPosition_,
objectName_);
}
/**
* \brief Create a completion for a text with the given prefix
*/
static ExpressionCompletionDescription ForText(
const gd::String& type_,
const gd::ParameterMetadata& parameterMetadata_,
const gd::String& prefix_,
size_t replacementStartPosition_,
size_t replacementEndPosition_,
const bool isLastParameter_,
const gd::String& objectName_ = "") {
auto description =
ExpressionCompletionDescription(Text,
type_,
prefix_,
replacementStartPosition_,
replacementEndPosition_,
objectName_);
description.SetIsLastParameter(isLastParameter_);
description.SetParameterMetadata(parameterMetadata_);
return description;
}
/**
* \brief Create a completion for an expression (free, object or behavior
* expression) with the given prefix
@@ -71,10 +118,17 @@ struct ExpressionCompletionDescription {
static ExpressionCompletionDescription ForExpression(
const gd::String& type_,
const gd::String& prefix_,
size_t replacementStartPosition_,
size_t replacementEndPosition_,
const gd::String& objectName_ = "",
const gd::String& behaviorName_ = "") {
return ExpressionCompletionDescription(
Expression, type_, prefix_, objectName_, behaviorName_);
return ExpressionCompletionDescription(Expression,
type_,
prefix_,
replacementStartPosition_,
replacementEndPosition_,
objectName_,
behaviorName_);
}
/** Check if two description of completions are equal */
@@ -131,6 +185,56 @@ struct ExpressionCompletionDescription {
*/
bool IsExact() const { return isExact; }
/**
* \brief Return the first character index of the autocompleted part.
*/
size_t GetReplacementStartPosition() const {
return replacementStartPosition;
}
/**
* \brief Return the first character index after the autocompleted part.
*/
size_t GetReplacementEndPosition() const { return replacementEndPosition; }
/**
* \brief Set if the expression is the last child of a function call.
*/
ExpressionCompletionDescription& SetIsLastParameter(bool isLastParameter_) {
isLastParameter = isLastParameter_;
return *this;
}
/**
* \brief Check if the expression is the last child of a function call.
*/
bool IsLastParameter() const { return isLastParameter; }
/**
* \brief Set the parameter metadata, in the case the completion is about
* a parameter of a function call.
*/
ExpressionCompletionDescription& SetParameterMetadata(
const gd::ParameterMetadata& parameterMetadata_) {
parameterMetadata = &parameterMetadata_;
return *this;
}
/**
* \brief Check if the completion is about a parameter of a function call.
*/
bool HasParameterMetadata() const {
return parameterMetadata != &badParameterMetadata;
}
/**
* \brief Return the parameter metadata, if the completion is about a
* parameter of a function call. Returns an empty metadata otherwise.
*/
const gd::ParameterMetadata& GetParameterMetadata() const {
return *parameterMetadata;
}
/** Default constructor, only to be used by Emscripten bindings. */
ExpressionCompletionDescription() : completionKind(Object){};
@@ -138,34 +242,40 @@ struct ExpressionCompletionDescription {
ExpressionCompletionDescription(CompletionKind completionKind_,
const gd::String& type_,
const gd::String& prefix_,
size_t replacementStartPosition_,
size_t replacementEndPosition_,
const gd::String& objectName_ = "",
const gd::String& behaviorName_ = "")
: completionKind(completionKind_),
type(type_),
prefix(prefix_),
replacementStartPosition(replacementStartPosition_),
replacementEndPosition(replacementEndPosition_),
objectName(objectName_),
behaviorName(behaviorName_),
isExact(false) {}
isExact(false),
isLastParameter(false),
parameterMetadata(&badParameterMetadata) {}
CompletionKind completionKind;
gd::String type;
gd::String prefix;
size_t replacementStartPosition;
size_t replacementEndPosition;
gd::String objectName;
gd::String behaviorName;
bool isExact;
bool isLastParameter;
const gd::ParameterMetadata* parameterMetadata;
static const gd::ParameterMetadata badParameterMetadata;
};
/**
* \brief Turn an ExpressionCompletionDescription to a string.
*/
std::ostream& operator<<(std::ostream& os,
ExpressionCompletionDescription const& value) {
os << "{ " << value.GetCompletionKind() << ", " << value.GetType() << ", "
<< value.GetPrefix() << ", " << value.GetObjectName() << ", "
<< value.GetBehaviorName() << ", "
<< (value.IsExact() ? "exact" : "non-exact") << " }";
return os;
}
ExpressionCompletionDescription const& value);
/**
* \brief Returns the list of completion descriptions for an expression node.
@@ -182,16 +292,18 @@ class GD_CORE_API ExpressionCompletionFinder
static std::vector<ExpressionCompletionDescription>
GetCompletionDescriptionsFor(gd::ExpressionNode& node,
size_t searchedPosition) {
gd::ExpressionNode* nodeAtLocation =
gd::ExpressionNodeLocationFinder::GetNodeAtPosition(node,
searchedPosition);
gd::ExpressionNodeLocationFinder finder(searchedPosition);
node.Visit(finder);
gd::ExpressionNode* nodeAtLocation = finder.GetNode();
if (nodeAtLocation == nullptr) {
std::vector<ExpressionCompletionDescription> emptyCompletions;
return emptyCompletions;
}
gd::ExpressionCompletionFinder autocompletionProvider(searchedPosition);
gd::ExpressionNode* maybeParentNodeAtLocation = finder.GetParentNode();
gd::ExpressionCompletionFinder autocompletionProvider(
searchedPosition, maybeParentNodeAtLocation);
nodeAtLocation->Visit(autocompletionProvider);
return autocompletionProvider.GetCompletionDescriptions();
}
@@ -208,32 +320,92 @@ class GD_CORE_API ExpressionCompletionFinder
protected:
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
completions.push_back(
ExpressionCompletionDescription::ForObject(node.type, ""));
completions.push_back(
ExpressionCompletionDescription::ForExpression(node.type, ""));
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type, "", searchedPosition + 1, searchedPosition + 1));
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type, "", searchedPosition + 1, searchedPosition + 1));
}
void OnVisitOperatorNode(OperatorNode& node) override {
completions.push_back(
ExpressionCompletionDescription::ForObject(node.type, ""));
completions.push_back(
ExpressionCompletionDescription::ForExpression(node.type, ""));
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type, "", searchedPosition + 1, searchedPosition + 1));
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type, "", searchedPosition + 1, searchedPosition + 1));
}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
completions.push_back(
ExpressionCompletionDescription::ForObject(node.type, ""));
completions.push_back(
ExpressionCompletionDescription::ForExpression(node.type, ""));
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type, "", searchedPosition + 1, searchedPosition + 1));
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type, "", searchedPosition + 1, searchedPosition + 1));
}
void OnVisitNumberNode(NumberNode& node) override {
// No completions
}
void OnVisitTextNode(TextNode& node) override {
// No completions
// Completions are searched in the case the text node is a parameter of a
// function call.
FunctionCallNode* functionCall =
dynamic_cast<FunctionCallNode*>(maybeParentNodeAtLocation);
if (functionCall != nullptr) {
int parameterIndex = -1;
for (int i = 0; i < functionCall->parameters.size(); i++) {
if (functionCall->parameters.at(i).get() == &node) {
parameterIndex = i;
break;
}
}
if (parameterIndex < 0) {
return;
}
// Search the parameter metadata index skipping invisible ones.
size_t visibleParameterIndex = 0;
size_t metadataParameterIndex = ExpressionParser2::WrittenParametersFirstIndex(
functionCall->objectName, functionCall->behaviorName);
const gd::ParameterMetadata* parameterMetadata = nullptr;
while (metadataParameterIndex <
functionCall->expressionMetadata.parameters.size()) {
if (!functionCall->expressionMetadata.parameters[metadataParameterIndex]
.IsCodeOnly()) {
if (visibleParameterIndex == parameterIndex) {
parameterMetadata = &functionCall->expressionMetadata
.parameters[metadataParameterIndex];
}
visibleParameterIndex++;
}
metadataParameterIndex++;
}
const int visibleParameterCount = visibleParameterIndex;
if (parameterMetadata == nullptr) {
// There are too many parameters in the expression, this text node is
// not actually linked to a parameter expected by the function call.
return;
}
const gd::String& type = parameterMetadata->GetType();
if (type == "string") {
// No completions for an arbitrary string.
return;
}
bool isLastParameter = parameterIndex == visibleParameterCount - 1;
completions.push_back(ExpressionCompletionDescription::ForText(
type,
*parameterMetadata,
node.text,
node.location.GetStartPosition(),
node.location.GetEndPosition(),
isLastParameter,
functionCall->objectName));
}
}
void OnVisitVariableNode(VariableNode& node) override {
completions.push_back(
ExpressionCompletionDescription::ForVariable(node.type, node.name));
completions.push_back(ExpressionCompletionDescription::ForVariable(
node.type,
node.name,
node.location.GetStartPosition(),
node.location.GetEndPosition(),
node.objectName));
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
// No completions
@@ -246,13 +418,22 @@ class GD_CORE_API ExpressionCompletionFinder
if (gd::ParameterMetadata::IsObject(node.type)) {
// Only show completions of objects if an object is required
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type, node.identifierName));
node.type,
node.identifierName,
node.location.GetStartPosition(),
node.location.GetEndPosition()));
} else {
// Show completions for expressions and objects otherwise.
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type, node.identifierName));
node.type,
node.identifierName,
node.location.GetStartPosition(),
node.location.GetEndPosition()));
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type, node.identifierName));
node.type,
node.identifierName,
node.location.GetStartPosition(),
node.location.GetEndPosition()));
}
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
@@ -262,16 +443,24 @@ class GD_CORE_API ExpressionCompletionFinder
// function name missing)
if (IsCaretOn(node.objectNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type, node.objectName));
node.type,
node.objectName,
node.objectNameLocation.GetStartPosition(),
node.objectNameLocation.GetEndPosition()));
} else if (IsCaretOn(node.objectNameDotLocation) ||
IsCaretOn(node.objectFunctionOrBehaviorNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForBehavior(
node.objectFunctionOrBehaviorName, node.objectName));
node.objectFunctionOrBehaviorName,
node.objectFunctionOrBehaviorNameLocation.GetStartPosition(),
node.objectFunctionOrBehaviorNameLocation.GetEndPosition(),
node.objectName));
} else if (IsCaretOn(node.behaviorNameNamespaceSeparatorLocation) ||
IsCaretOn(node.behaviorFunctionNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type,
node.behaviorFunctionName,
node.behaviorFunctionNameLocation.GetStartPosition(),
node.behaviorFunctionNameLocation.GetEndPosition(),
node.objectName,
node.objectFunctionOrBehaviorName));
}
@@ -279,13 +468,23 @@ class GD_CORE_API ExpressionCompletionFinder
// Object function or behavior name
if (IsCaretOn(node.objectNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type, node.objectName));
node.type,
node.objectName,
node.objectNameLocation.GetStartPosition(),
node.objectNameLocation.GetEndPosition()));
} else if (IsCaretOn(node.objectNameDotLocation) ||
IsCaretOn(node.objectFunctionOrBehaviorNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForBehavior(
node.objectFunctionOrBehaviorName, node.objectName));
node.objectFunctionOrBehaviorName,
node.objectFunctionOrBehaviorNameLocation.GetStartPosition(),
node.objectFunctionOrBehaviorNameLocation.GetEndPosition(),
node.objectName));
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type, node.objectFunctionOrBehaviorName, node.objectName));
node.type,
node.objectFunctionOrBehaviorName,
node.objectFunctionOrBehaviorNameLocation.GetStartPosition(),
node.objectFunctionOrBehaviorNameLocation.GetEndPosition(),
node.objectName));
}
}
}
@@ -297,24 +496,35 @@ class GD_CORE_API ExpressionCompletionFinder
// Behavior function
if (IsCaretOn(node.objectNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type, node.objectName));
node.type,
node.objectName,
node.objectNameLocation.GetStartPosition(),
node.objectNameLocation.GetEndPosition()));
} else if (IsCaretOn(node.objectNameDotLocation) ||
IsCaretOn(node.behaviorNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForBehavior(
node.behaviorName, node.objectName));
node.behaviorName,
node.behaviorNameLocation.GetStartPosition(),
node.behaviorNameLocation.GetEndPosition(),
node.objectName));
} else {
completions.push_back(
ExpressionCompletionDescription::ForExpression(node.type,
node.functionName,
node.objectName,
node.behaviorName)
.SetIsExact(isCaretOnParenthesis));
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type,
node.functionName,
node.functionNameLocation.GetStartPosition(),
node.functionNameLocation.GetEndPosition(),
node.objectName,
node.behaviorName)
.SetIsExact(isCaretOnParenthesis));
}
} else if (!node.objectName.empty()) {
// Object function
if (IsCaretOn(node.objectNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type, node.objectName));
node.type,
node.objectName,
node.objectNameLocation.GetStartPosition(),
node.objectNameLocation.GetEndPosition()));
} else {
// Add completions for behaviors, because we could imagine that the user
// wants to move from an object function to a behavior function, and so
@@ -323,25 +533,41 @@ class GD_CORE_API ExpressionCompletionFinder
// function).
if (!isCaretOnParenthesis) {
completions.push_back(ExpressionCompletionDescription::ForBehavior(
node.functionName, node.objectName));
node.functionName,
node.objectNameLocation.GetStartPosition(),
node.objectNameLocation.GetEndPosition(),
node.objectName));
}
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type, node.functionName, node.objectName)
node.type,
node.functionName,
node.functionNameLocation.GetStartPosition(),
node.functionNameLocation.GetEndPosition(),
node.objectName)
.SetIsExact(isCaretOnParenthesis));
}
} else {
// Free function
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type, node.functionName)
node.type,
node.functionName,
node.functionNameLocation.GetStartPosition(),
node.functionNameLocation.GetEndPosition())
.SetIsExact(isCaretOnParenthesis));
}
}
void OnVisitEmptyNode(EmptyNode& node) override {
completions.push_back(
ExpressionCompletionDescription::ForObject(node.type, node.text));
completions.push_back(
ExpressionCompletionDescription::ForExpression(node.type, node.text));
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type,
node.text,
node.location.GetStartPosition(),
node.location.GetEndPosition()));
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type,
node.text,
node.location.GetStartPosition(),
node.location.GetEndPosition()));
}
private:
@@ -354,11 +580,14 @@ class GD_CORE_API ExpressionCompletionFinder
(inclusive && searchedPosition <= location.GetEndPosition())));
}
ExpressionCompletionFinder(size_t searchedPosition_)
: searchedPosition(searchedPosition_){};
ExpressionCompletionFinder(size_t searchedPosition_,
gd::ExpressionNode* maybeParentNodeAtLocation_)
: searchedPosition(searchedPosition_),
maybeParentNodeAtLocation(maybeParentNodeAtLocation_){};
std::vector<ExpressionCompletionDescription> completions;
size_t searchedPosition;
gd::ExpressionNode* maybeParentNodeAtLocation;
};
} // namespace gd

View File

@@ -8,6 +8,7 @@
#include <memory>
#include <vector>
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
namespace gd {
@@ -46,11 +47,30 @@ class GD_CORE_API ExpressionNodeLocationFinder
return finder.GetNode();
}
/**
* \brief Helper function to find the parent of the deepest node at the search
* position, if any.
*
* \warning Useful for tests. In other cases, prefer using `GetParentNode`.
*/
static ExpressionNode* GetParentNodeAtPosition(gd::ExpressionNode& node,
size_t searchedPosition) {
gd::ExpressionNodeLocationFinder finder(searchedPosition);
node.Visit(finder);
return finder.GetParentNode();
}
/**
* \brief Return the deepest node found at the search position, if any.
*/
ExpressionNode* GetNode() { return foundNode; };
/**
* \brief Return the parent of deepest node found at the search position, if
* any.
*/
ExpressionNode* GetParentNode() { return parentNode; };
protected:
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
CheckSearchPositionInNode(node);
@@ -110,6 +130,7 @@ class GD_CORE_API ExpressionNodeLocationFinder
if (node.location.GetStartPosition() <= searchedPosition &&
((!inclusive && searchedPosition < node.location.GetEndPosition()) ||
(inclusive && searchedPosition <= node.location.GetEndPosition()))) {
parentNode = foundNode;
foundNode = &node;
return true;
}
@@ -119,6 +140,7 @@ class GD_CORE_API ExpressionNodeLocationFinder
size_t searchedPosition;
ExpressionNode* foundNode;
ExpressionNode* parentNode;
};
} // namespace gd

View File

@@ -4,9 +4,11 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/ExpressionsParameterMover.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
@@ -134,10 +136,11 @@ class GD_CORE_API ExpressionParameterMover
bool ExpressionsParameterMover::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
auto& metadata = isCondition ? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
const auto& metadata = isCondition
? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
for (std::size_t pNb = 0; pNb < metadata.parameters.size() &&
pNb < instruction.GetParametersCount();

View File

@@ -4,9 +4,11 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/ExpressionsRenamer.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
@@ -145,10 +147,11 @@ class GD_CORE_API ExpressionFunctionRenamer
bool ExpressionsRenamer::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
auto& metadata = isCondition ? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
const auto& metadata = isCondition
? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
for (std::size_t pNb = 0; pNb < metadata.parameters.size() &&
pNb < instruction.GetParametersCount();

View File

@@ -24,24 +24,6 @@ namespace gd {
InstructionSentenceFormatter *InstructionSentenceFormatter::_singleton = NULL;
gd::String InstructionSentenceFormatter::Translate(
const gd::Instruction &instr, const gd::InstructionMetadata &metadata) {
gd::String out = metadata.GetSentence();
if (out.empty())
out = " "; // Prevent empty sentences that could trigger graphical
// glitches.
// Replace _PARAMx_ placeholders by their values
for (std::size_t i = 0; i < metadata.parameters.size(); ++i) {
gd::String placeholder = "_PARAM" + gd::String::From(i) + "_";
gd::String parameter = instr.GetParameter(i).GetPlainString();
out = out.FindAndReplace(placeholder, parameter);
}
out = out.FindAndReplace("\n", " ");
return out;
}
std::vector<std::pair<gd::String, gd::TextFormatting> >
InstructionSentenceFormatter::GetAsFormattedText(
const Instruction &instr, const gd::InstructionMetadata &metadata) {
@@ -83,8 +65,7 @@ InstructionSentenceFormatter::GetAsFormattedText(
}
// Add the parameter
TextFormatting format =
GetFormattingFromType(metadata.parameters[firstParamIndex].type);
TextFormatting format;
format.userData = firstParamIndex;
gd::String text = instr.GetParameter(firstParamIndex).GetPlainString();
@@ -109,74 +90,6 @@ InstructionSentenceFormatter::GetAsFormattedText(
return formattedStr;
}
TextFormatting InstructionSentenceFormatter::GetFormattingFromType(
const gd::String &type) {
if (gd::ParameterMetadata::IsObject(type)) return typesFormatting["object"];
return typesFormatting[type];
}
gd::String InstructionSentenceFormatter::LabelFromType(const gd::String &type) {
if (type.empty())
return "";
else if (type == "expression")
return _("Expression");
else if (gd::ParameterMetadata::IsObject(type))
return _("Object");
else if (type == "behavior")
return _("Behavior");
else if (type == "operator")
return _("Operator");
else if (type == "relationalOperator")
return _("Relational operator");
else if (type == "file")
return _("File");
else if (type == "key")
return _("Key");
else if (type == "mouse")
return _("Mouse button");
else if (type == "yesorno")
return _("Yes or No");
else if (type == "police")
return _("Font");
else if (type == "color")
return _("Color");
else if (type == "trueorfalse")
return _("True or False");
else if (type == "string")
return _("String");
else if (type == "musicfile")
return _("Music");
else if (type == "soundfile")
return _("Sound");
else if (type == "password")
return _("Password");
else if (type == "layer")
return _("Layer");
else if (type == "joyaxis")
return _("Joystick axis");
else if (type == "objectvar")
return _("Variable of the object");
else if (type == "scenevar")
return _("Scene variable");
else if (type == "globalvar")
return _("Global variable");
return _("Unknown");
}
void InstructionSentenceFormatter::LoadTypesFormattingFromConfig() {
// Load default configuration
typesFormatting.clear();
typesFormatting["expression"].SetColor(27, 143, 1).SetBold();
typesFormatting["object"].SetColor(182, 97, 10).SetBold();
typesFormatting["behavior"].SetColor(119, 119, 119).SetBold();
typesFormatting["operator"].SetColor(55, 131, 211).SetBold();
typesFormatting["objectvar"].SetColor(131, 55, 162).SetBold();
typesFormatting["scenevar"].SetColor(131, 55, 162).SetBold();
typesFormatting["globalvar"].SetColor(131, 55, 162).SetBold();
}
} // namespace gd
#endif

View File

@@ -25,39 +25,12 @@ namespace gd {
*/
class GD_CORE_API InstructionSentenceFormatter {
public:
/**
* \brief Create a sentence from an instruction and its metadata.
*
* Sentence is provided in the gd::InstructionMetadata passed as parameter.
* Parameters placeholders ("_PARAMx_", x being the parameter index) are
* replaced by their values stored in the isntruction passed as parameter.
*/
gd::String Translate(const gd::Instruction &instr,
const gd::InstructionMetadata &metadata);
/**
* \brief Create a formatted sentence from an instruction and its metadata.
*/
std::vector<std::pair<gd::String, gd::TextFormatting> > GetAsFormattedText(
const gd::Instruction &instr, const gd::InstructionMetadata &metadata);
/**
* \brief Return the TextFormatting object associated to the \a type.
*/
TextFormatting GetFormattingFromType(const gd::String &type);
/**
* \brief Return the label of a parameter type
*/
gd::String LabelFromType(const gd::String &type);
/**
* \brief Load the configuration from the default configuration.
*/
void LoadTypesFormattingFromConfig();
std::map<gd::String, gd::TextFormatting> typesFormatting;
static InstructionSentenceFormatter *Get() {
if (NULL == _singleton) {
_singleton = new InstructionSentenceFormatter;

View File

@@ -13,85 +13,20 @@ namespace gd {
/**
* \brief Represents the style of a text displayed in the events editor.
*
* Notably used by EventsRenderingHelper to render Instruction.
*
* \see EventsRenderingHelper
* \ingroup IDEDialogsEventsEditor
*/
class GD_CORE_API TextFormatting {
public:
TextFormatting()
: colorRed(0),
colorGreen(0),
colorBlue(0),
bold(false),
italic(false),
userData(gd::String::npos) {}
TextFormatting() : userData(gd::String::npos) {}
~TextFormatting() {}
/**
* \brief Return true if the bold style must be applied.
*/
bool IsBold() const { return bold; }
/**
* \brief Return true if the italic style must be applied.
*/
bool IsItalic() const { return italic; }
/**
* \brief Return the red component of the color that must be applied to the
* text.
*/
unsigned int GetColorRed() const { return colorRed; }
/**
* \brief Return the green component of the color that must be applied to the
* text.
*/
unsigned int GetColorGreen() const { return colorGreen; }
/**
* \brief Return the blue component of the color that must be applied to the
* text.
*/
unsigned int GetColorBlue() const { return colorBlue; }
/**
* Change the color of the text.
*/
TextFormatting& SetColor(unsigned int r, unsigned int g, unsigned int b) {
colorRed = r;
colorGreen = g;
colorBlue = b;
return *this;
}
/**
* \brief Set if the bold style must be applied.
*/
TextFormatting& SetBold(bool enable = true) {
bold = enable;
return *this;
}
/**
* \brief Set if the italic style must be applied.
*/
TextFormatting& SetItalic(bool enable = true) {
italic = enable;
return *this;
}
/**
* Return the data (an integer) associated with the text formatting.
* Used to store the parameter when rendering instructions.
*/
size_t GetUserData() const { return userData; }
unsigned int colorRed;
unsigned int colorGreen;
unsigned int colorBlue;
bool bold;
bool italic;
size_t userData;
};

View File

@@ -4,16 +4,20 @@
* reserved. This project is released under the MIT License.
*/
#include "EventsFunctionTools.h"
#include "GDCore/Events/Expression.h"
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/EventsFunction.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
namespace gd {
void EventsFunctionTools::EventsFunctionToObjectsContainer(
void EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
gd::Project& project,
const gd::EventsFunction& eventsFunction,
gd::ObjectsContainer& outputGlobalObjectsContainer,
@@ -31,4 +35,41 @@ void EventsFunctionTools::EventsFunctionToObjectsContainer(
outputObjectsContainer.GetObjectGroups() = eventsFunction.GetObjectGroups();
}
void EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
gd::Project& project,
const gd::EventsBasedBehavior& eventsBasedBehavior,
const gd::EventsFunction& eventsFunction,
gd::ObjectsContainer& outputGlobalObjectsContainer,
gd::ObjectsContainer& outputObjectsContainer) {
// The context is build the same way as free function...
FreeEventsFunctionToObjectsContainer(project,
eventsFunction,
outputGlobalObjectsContainer,
outputObjectsContainer);
// ...and has an "Object" by convention...
if (!outputObjectsContainer.HasObjectNamed("Object")) {
gd::LogWarning("No \"Object\" in a function of an events based behavior: " +
eventsFunction.GetName() +
". This means this function is likely misconfigured (check "
"its parameters).");
return;
}
// ...with behaviors from properties.
gd::Object& thisObject = outputObjectsContainer.GetObject("Object");
for (size_t i = 0;
i < eventsBasedBehavior.GetPropertyDescriptors().GetCount();
i++) {
const NamedPropertyDescriptor& propertyDescriptor =
eventsBasedBehavior.GetPropertyDescriptors().Get(i);
const std::vector<gd::String>& extraInfo =
propertyDescriptor.GetExtraInfo();
if (propertyDescriptor.GetType() == "Behavior" && extraInfo.size() > 0) {
gd::String behaviorName = propertyDescriptor.GetName();
thisObject.AddNewBehavior(project, extraInfo.at(0), behaviorName);
}
}
}
} // namespace gd

View File

@@ -13,6 +13,7 @@ class Project;
class ObjectsContainer;
class ParameterMetadata;
class EventsFunction;
class EventsBasedBehavior;
class Expression;
} // namespace gd
@@ -23,18 +24,33 @@ namespace gd {
class GD_CORE_API EventsFunctionTools {
public:
/**
* \brief Given an events function, initialize the given objects container
* \brief Given a free events function, initialize the given objects container
* with objects described in the events function parameters and in
* the events function groups.
*
* This is useful to create the "context" of a function, before code
* generation for example.
*/
static void EventsFunctionToObjectsContainer(
static void FreeEventsFunctionToObjectsContainer(
gd::Project& project,
const gd::EventsFunction& eventsFunction,
gd::ObjectsContainer& outputGlobalObjectsContainer,
gd::ObjectsContainer& outputObjectsContainer);
/**
* \brief Given a behavior events function, initialize the given objects container
* with objects described in the events function parameters, in
* the events function groups and in the behavior properties (for additional
* required behaviors on the object).
*
* This is useful to create the "context" of a function, before code
* generation for example.
*/
static void BehaviorEventsFunctionToObjectsContainer(
gd::Project& project,
const gd::EventsBasedBehavior& eventsBasedBehavior,
const gd::EventsFunction& eventsFunction,
gd::ObjectsContainer& outputGlobalObjectsContainer,
gd::ObjectsContainer& outputObjectsContainer);
};
} // namespace gd

View File

@@ -14,16 +14,16 @@ namespace gd {
* \note Both objects must be kept alive, as this is keeping a pointer to them.
*/
struct DependencyMetadataAndExtension {
DependencyMetadataAndExtension(gd::DependencyMetadata& dependency_,
gd::PlatformExtension& extension_)
DependencyMetadataAndExtension(gd::DependencyMetadata &dependency_,
gd::PlatformExtension &extension_)
: dependency(&dependency_), extension(&extension_){};
gd::DependencyMetadata& GetDependency() const { return *dependency; };
gd::PlatformExtension& GetExtension() const { return *extension; };
gd::DependencyMetadata &GetDependency() const { return *dependency; };
gd::PlatformExtension &GetExtension() const { return *extension; };
private:
gd::DependencyMetadata* dependency;
gd::PlatformExtension* extension;
gd::DependencyMetadata *dependency;
gd::PlatformExtension *extension;
};
/**
@@ -33,8 +33,8 @@ struct DependencyMetadataAndExtension {
class ExportedDependencyResolver {
public:
/**
* \brief Return the list of dependencies to be exported for the given project
* and dependency type.
* \brief Return the list of dependencies to be exported for the given
* project, used extensions list and dependency type.
*
* Not all dependencies declared by extensions must be exported: some are only
* exported when some settings are filled. Then, some others are only exported
@@ -42,11 +42,13 @@ class ExportedDependencyResolver {
* one level though).
*/
static std::vector<DependencyMetadataAndExtension> GetDependenciesFor(
const gd::Project& project, const gd::String& dependencyType) {
const gd::Project &project,
std::set<gd::String> usedExtensions,
const gd::String &dependencyType) {
std::vector<DependencyMetadataAndExtension> dependenciesWithProperType;
for (std::shared_ptr<gd::PlatformExtension> extension :
project.GetCurrentPlatform().GetAllPlatformExtensions()) {
for (gd::DependencyMetadata& dependency :
for (const gd::String &extensionName : usedExtensions) {
auto extension = project.GetCurrentPlatform().GetExtension(extensionName);
for (gd::DependencyMetadata &dependency :
extension->GetAllDependencies()) {
if (dependency.GetDependencyType() == dependencyType) {
DependencyMetadataAndExtension dependencyMetadataAndExtension(
@@ -60,7 +62,7 @@ class ExportedDependencyResolver {
// and those that don't require extra settings to be filled.
std::vector<DependencyMetadataAndExtension> dependenciesWithFilledSettings;
for (auto dependencyAndExtension : dependenciesWithProperType) {
auto& dependency = dependencyAndExtension.GetDependency();
auto &dependency = dependencyAndExtension.GetDependency();
auto extraSettingValues = GetExtensionDependencyExtraSettingValues(
project, dependencyAndExtension);
@@ -73,15 +75,15 @@ class ExportedDependencyResolver {
// exported (or dependencies that don't require another dependency).
std::vector<DependencyMetadataAndExtension> exportedDependencies;
for (auto dependencyAndExtension : dependenciesWithFilledSettings) {
auto& dependency = dependencyAndExtension.GetDependency();
auto& otherDependencyName =
auto &dependency = dependencyAndExtension.GetDependency();
auto &otherDependencyName =
dependency.GetOtherDependencyThatMustBeExported();
if (otherDependencyName.empty() ||
std::find_if(
dependenciesWithFilledSettings.begin(),
dependenciesWithFilledSettings.end(),
[&otherDependencyName](
DependencyMetadataAndExtension& otherDependencyAndExtension) {
DependencyMetadataAndExtension &otherDependencyAndExtension) {
return otherDependencyAndExtension.GetDependency().GetName() ==
otherDependencyName;
}) != dependenciesWithFilledSettings.end()) {
@@ -98,15 +100,15 @@ class ExportedDependencyResolver {
*/
static std::map<gd::String, gd::String>
GetExtensionDependencyExtraSettingValues(
const gd::Project& project,
const gd::DependencyMetadataAndExtension& dependencyAndExtension) {
const gd::Project &project,
const gd::DependencyMetadataAndExtension &dependencyAndExtension) {
std::map<gd::String, gd::String> values;
auto& dependency = dependencyAndExtension.GetDependency();
const gd::String& extensionName =
auto &dependency = dependencyAndExtension.GetDependency();
const gd::String &extensionName =
dependencyAndExtension.GetExtension().GetName();
for (const auto& extraSetting : dependency.GetAllExtraSettings()) {
const gd::String& type = extraSetting.second.GetType();
for (const auto &extraSetting : dependency.GetAllExtraSettings()) {
const gd::String &type = extraSetting.second.GetType();
const gd::String extraSettingValue =
type == "ExtensionProperty"
? project.GetExtensionProperties().GetValue(

View File

@@ -27,50 +27,6 @@ namespace gd {
PlatformLoader::PlatformLoader() {}
void PlatformLoader::LoadAllPlatformsInManager(gd::String dir) {
{
#if defined(WINDOWS)
std::shared_ptr<gd::Platform> platform = LoadPlatformInManager("GDCpp.dll");
#elif defined(LINUX)
std::shared_ptr<gd::Platform> platform =
LoadPlatformInManager("libGDCpp.so");
#elif defined(MACOS)
std::shared_ptr<gd::Platform> platform =
LoadPlatformInManager("libGDCpp.dylib");
#else
#warning Add the appropriate filename here for the C++ Platform!
std::shared_ptr<gd::Platform> platform;
#endif
if (platform)
gd::ExtensionsLoader::LoadAllExtensions("./CppPlatform/Extensions/",
*platform);
}
{
#if defined(WINDOWS)
std::shared_ptr<gd::Platform> platform =
LoadPlatformInManager("./JsPlatform/GDJS.dll");
#elif defined(LINUX)
std::shared_ptr<gd::Platform> platform =
LoadPlatformInManager("./JsPlatform/libGDJS.so");
#elif defined(MACOS)
std::shared_ptr<gd::Platform> platform =
LoadPlatformInManager("./JsPlatform/libGDJS.dylib");
#else
#warning Add the appropriate filename here for the Js Platform!
std::shared_ptr<gd::Platform> platform;
#endif
if (platform)
gd::ExtensionsLoader::LoadAllExtensions("./JsPlatform/Extensions/",
*platform);
if (platform)
gd::ExtensionsLoader::LoadAllExtensions(
"./CppPlatform/Extensions/", *platform, true);
}
gd::ExtensionsLoader::ExtensionsLoadingDone("./CppPlatform/Extensions/");
}
std::shared_ptr<gd::Platform> PlatformLoader::LoadPlatformInManager(
gd::String fullpath) {
std::cout << "Loading platform " << fullpath << "..." << std::endl;

View File

@@ -30,15 +30,6 @@ passing
*/
class GD_CORE_API PlatformLoader {
public:
/**
* Load all the platforms available in a directory.
*
* \param dir The directory where platforms must be searched for.
*
* \todo For now, only GDCpp.dll and GDJS.dll are loaded.
*/
static void LoadAllPlatformsInManager(gd::String dir);
/**
* Load a specific platform.
*

View File

@@ -0,0 +1,12 @@
/*
* GDevelop Core
* Copyright 2008-2021 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "UnfilledRequiredBehaviorPropertyProblem.h"
namespace gd {
UnfilledRequiredBehaviorPropertyProblem::~UnfilledRequiredBehaviorPropertyProblem(){};
} // namespace gd

View File

@@ -0,0 +1,80 @@
/*
* GDevelop Core
* Copyright 2008-2021 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_UNFILLEDREQUIREDBEHAVIORPROPERTYPROBLEM_H
#define GDCORE_UNFILLEDREQUIREDBEHAVIORPROPERTYPROBLEM_H
#include "GDCore/String.h"
namespace gd {
class Project;
class Object;
class BehaviorContent;
} // namespace gd
namespace gd {
/**
* \brief A problem when a required behavior property is not fill correctly.
*/
class GD_CORE_API UnfilledRequiredBehaviorPropertyProblem {
public:
UnfilledRequiredBehaviorPropertyProblem(
const gd::Project& sourceProject_,
gd::Object& sourceObject_,
gd::BehaviorContent& sourceBehaviorContent_,
const gd::String& sourcePropertyName_,
const gd::String& expectedBehaviorTypeName_)
: sourceProject(sourceProject_),
sourceObject(sourceObject_),
sourceBehaviorContent(sourceBehaviorContent_),
sourcePropertyName(sourcePropertyName_),
expectedBehaviorTypeName(expectedBehaviorTypeName_){};
virtual ~UnfilledRequiredBehaviorPropertyProblem();
/**
* \brief Return the project where the problem appears
*/
virtual const gd::Project& GetSourceProject() const { return sourceProject; }
/**
* \brief Return the object where the problem appears.
*/
virtual gd::Object& GetSourceObject() const { return sourceObject; }
/**
* \brief Return the behavior where the problem appears.
*/
virtual gd::BehaviorContent& GetSourceBehaviorContent() const {
return sourceBehaviorContent;
}
/**
* \brief Return the property where the problem appears.
*/
virtual const gd::String& GetSourcePropertyName() const {
return sourcePropertyName;
}
/**
* \brief Return the behavior type name that is expected for the required
* behavior property.
*/
virtual const gd::String& GetExpectedBehaviorTypeName() const {
return expectedBehaviorTypeName;
}
private:
const gd::Project& sourceProject;
gd::Object& sourceObject;
gd::BehaviorContent& sourceBehaviorContent;
const gd::String sourcePropertyName;
const gd::String expectedBehaviorTypeName;
};
} // namespace gd
#endif // GDCORE_UNFILLEDREQUIREDBEHAVIORPROPERTYPROBLEM_H

View File

@@ -5,9 +5,12 @@
*/
#include "WholeProjectRefactorer.h"
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/DependenciesAnalyzer.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
#include "GDCore/IDE/Events/EventsRefactorer.h"
#include "GDCore/IDE/Events/ExpressionsParameterMover.h"
#include "GDCore/IDE/Events/ExpressionsRenamer.h"
@@ -15,6 +18,9 @@
#include "GDCore/IDE/Events/InstructionsTypeRenamer.h"
#include "GDCore/IDE/EventsFunctionTools.h"
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/IDE/UnfilledRequiredBehaviorPropertyProblem.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/BehaviorContent.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/ExternalEvents.h"
@@ -51,6 +57,10 @@ gd::String GetBehaviorFullType(const gd::String& extensionName,
namespace gd {
// By convention, the first parameter of an events based behavior method is
// always called "Object".
const gd::String WholeProjectRefactorer::behaviorObjectParameterName = "Object";
void WholeProjectRefactorer::ExposeProjectEvents(
gd::Project& project, gd::ArbitraryEventsWorker& worker) {
// See also gd::Project::ExposeResources for a method that traverse the whole
@@ -115,7 +125,7 @@ void WholeProjectRefactorer::ExposeProjectEvents(
for (auto&& eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
gd::ObjectsContainer globalObjectsAndGroups;
gd::ObjectsContainer objectsAndGroups;
gd::EventsFunctionTools::EventsFunctionToObjectsContainer(
gd::EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
project, *eventsFunction, globalObjectsAndGroups, objectsAndGroups);
worker.Launch(eventsFunction->GetEvents(),
@@ -127,22 +137,31 @@ void WholeProjectRefactorer::ExposeProjectEvents(
for (auto&& eventsBasedBehavior :
eventsFunctionsExtension.GetEventsBasedBehaviors()
.GetInternalVector()) {
auto& behaviorEventsFunctions = eventsBasedBehavior->GetEventsFunctions();
for (auto&& eventsFunction :
behaviorEventsFunctions.GetInternalVector()) {
gd::ObjectsContainer globalObjectsAndGroups;
gd::ObjectsContainer objectsAndGroups;
gd::EventsFunctionTools::EventsFunctionToObjectsContainer(
project, *eventsFunction, globalObjectsAndGroups, objectsAndGroups);
worker.Launch(eventsFunction->GetEvents(),
globalObjectsAndGroups,
objectsAndGroups);
}
ExposeEventsBasedBehaviorEvents(project, *eventsBasedBehavior, worker);
}
}
}
void WholeProjectRefactorer::ExposeEventsBasedBehaviorEvents(
gd::Project& project,
const gd::EventsBasedBehavior& eventsBasedBehavior,
gd::ArbitraryEventsWorkerWithContext& worker) {
auto& behaviorEventsFunctions = eventsBasedBehavior.GetEventsFunctions();
for (auto&& eventsFunction : behaviorEventsFunctions.GetInternalVector()) {
gd::ObjectsContainer globalObjectsAndGroups;
gd::ObjectsContainer objectsAndGroups;
gd::EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
project,
eventsBasedBehavior,
*eventsFunction,
globalObjectsAndGroups,
objectsAndGroups);
worker.Launch(
eventsFunction->GetEvents(), globalObjectsAndGroups, objectsAndGroups);
}
}
void WholeProjectRefactorer::ExposeProjectObjects(
gd::Project& project, gd::ArbitraryObjectsWorker& worker) {
worker.Launch(project);
@@ -192,7 +211,7 @@ void WholeProjectRefactorer::EnsureBehaviorEventsFunctionsProperParameters(
parameters[0]
.SetType("object")
.SetName("Object")
.SetName(behaviorObjectParameterName)
.SetDescription("Object")
.SetExtraInfo(eventsBasedBehavior.GetObjectType());
parameters[1]
@@ -470,7 +489,7 @@ void WholeProjectRefactorer::MoveBehaviorEventsFunctionParameter(
}
}
void WholeProjectRefactorer::RenameBehaviorProperty(
void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::EventsBasedBehavior& eventsBasedBehavior,
@@ -479,41 +498,294 @@ void WholeProjectRefactorer::RenameBehaviorProperty(
auto& properties = eventsBasedBehavior.GetPropertyDescriptors();
if (!properties.Has(oldPropertyName)) return;
// Order is important: we first rename the expressions then the instructions,
// to avoid being unable to fetch the metadata (the types of parameters) of
// instructions after they are renamed.
gd::ExpressionsRenamer expressionRenamer =
gd::ExpressionsRenamer(project.GetCurrentPlatform());
expressionRenamer.SetReplacedBehaviorExpression(
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName()),
EventsBasedBehavior::GetPropertyExpressionName(oldPropertyName),
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
ExposeProjectEvents(project, expressionRenamer);
if (properties.Get(oldPropertyName).GetType() == "Behavior") {
// This is a property representing another behavior that must exist on the
// object.
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetPropertyActionName(oldPropertyName)),
GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetPropertyActionName(newPropertyName)));
ExposeProjectEvents(project, actionRenamer);
// This other "required behavior" uses the property name, that is about to
// change, as its name.
// So we must change all reference to this name in the events of the
// behavior functions.
gd::EventsBehaviorRenamer behaviorRenamer(project.GetCurrentPlatform(),
behaviorObjectParameterName,
oldPropertyName,
newPropertyName);
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetPropertyConditionName(oldPropertyName)),
GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetPropertyConditionName(newPropertyName)));
ExposeProjectEvents(project, conditionRenamer);
ExposeEventsBasedBehaviorEvents(
project, eventsBasedBehavior, behaviorRenamer);
} else {
// Properties that represent primitive values will be used through
// their related actions/conditions/expressions. Rename these.
// Order is important: we first rename the expressions then the
// instructions, to avoid being unable to fetch the metadata (the types of
// parameters) of instructions after they are renamed.
gd::ExpressionsRenamer expressionRenamer =
gd::ExpressionsRenamer(project.GetCurrentPlatform());
expressionRenamer.SetReplacedBehaviorExpression(
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName()),
EventsBasedBehavior::GetPropertyExpressionName(oldPropertyName),
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
ExposeProjectEvents(project, expressionRenamer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetPropertyActionName(oldPropertyName)),
GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetPropertyActionName(newPropertyName)));
ExposeProjectEvents(project, actionRenamer);
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetPropertyConditionName(oldPropertyName)),
GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetPropertyConditionName(newPropertyName)));
ExposeProjectEvents(project, conditionRenamer);
}
}
void WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
gd::Project& project,
gd::Object& object,
const gd::String& behaviorType,
const gd::String& behaviorName) {
if (object.AddNewBehavior(project, behaviorType, behaviorName) == nullptr) {
// The behavior type/metadata can't be found.
return;
};
const gd::Platform& platform = project.GetCurrentPlatform();
const gd::BehaviorMetadata& behaviorMetadata =
MetadataProvider::GetBehaviorMetadata(platform, behaviorType);
if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
// Should not happen because the behavior was added successfully (so its
// metadata are valid) - but double check anyway and bail out if the
// behavior metadata are invalid.
return;
}
gd::Behavior& behavior = behaviorMetadata.Get();
gd::BehaviorContent& behaviorContent = object.GetBehavior(behaviorName);
for (auto const& keyValue :
behavior.GetProperties(behaviorContent.GetContent())) {
const gd::String& propertyName = keyValue.first;
const gd::PropertyDescriptor& property = keyValue.second;
if (property.GetType().LowerCase() == "behavior") {
const std::vector<gd::String>& extraInfo = property.GetExtraInfo();
if (extraInfo.size() == 0) {
// very unlikely
continue;
}
const gd::String& requiredBehaviorType = extraInfo.at(0);
const auto behaviorContents =
WholeProjectRefactorer::GetBehaviorsWithType(object,
requiredBehaviorType);
const gd::String* defaultBehaviorName = nullptr;
if (behaviorContents.size() == 0) {
const gd::BehaviorMetadata& requiredBehaviorMetadata =
MetadataProvider::GetBehaviorMetadata(platform,
requiredBehaviorType);
const gd::String& requiredBehaviorName =
requiredBehaviorMetadata.GetDefaultName();
WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
project, object, requiredBehaviorType, requiredBehaviorName);
defaultBehaviorName = &requiredBehaviorName;
} else {
defaultBehaviorName = &behaviorContents.at(0);
}
behavior.UpdateProperty(
behaviorContent.GetContent(), propertyName, *defaultBehaviorName);
}
}
}
std::vector<gd::String> WholeProjectRefactorer::GetBehaviorsWithType(
const gd::Object& object, const gd::String& type) {
std::vector<gd::String> behaviors;
for (auto& behaviorName : object.GetAllBehaviorNames()) {
const gd::BehaviorContent& behaviorContent =
object.GetBehavior(behaviorName);
if (behaviorContent.GetTypeName() == type) {
behaviors.push_back(behaviorName);
}
}
return behaviors;
}
std::vector<gd::String> WholeProjectRefactorer::FindDependentBehaviorNames(
const gd::Project& project,
const gd::Object& object,
const gd::String& behaviorName) {
std::unordered_set<gd::String> dependentBehaviorNames;
WholeProjectRefactorer::FindDependentBehaviorNames(
project, object, behaviorName, dependentBehaviorNames);
std::vector<gd::String> results;
results.insert(results.end(),
dependentBehaviorNames.begin(),
dependentBehaviorNames.end());
return results;
}
void WholeProjectRefactorer::FindDependentBehaviorNames(
const gd::Project& project,
const gd::Object& object,
const gd::String& behaviorName,
std::unordered_set<gd::String>& dependentBehaviorNames) {
const gd::Platform& platform = project.GetCurrentPlatform();
for (auto const& objectBehaviorName : object.GetAllBehaviorNames()) {
const gd::BehaviorContent& behaviorContent =
object.GetBehavior(objectBehaviorName);
const auto& behaviorMetadata = MetadataProvider::GetBehaviorMetadata(
platform, behaviorContent.GetTypeName());
if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
// Ignore this behavior as it's unknown.
continue;
}
gd::Behavior& behavior = behaviorMetadata.Get();
for (auto const& keyValue :
behavior.GetProperties(behaviorContent.GetContent())) {
const gd::String& propertyName = keyValue.first;
const gd::PropertyDescriptor& property = keyValue.second;
if (property.GetType().LowerCase() == "behavior" &&
property.GetValue() == behaviorName &&
dependentBehaviorNames.find(objectBehaviorName) ==
dependentBehaviorNames.end()) {
dependentBehaviorNames.insert(objectBehaviorName);
WholeProjectRefactorer::FindDependentBehaviorNames(
project, object, objectBehaviorName, dependentBehaviorNames);
}
}
}
};
std::vector<gd::UnfilledRequiredBehaviorPropertyProblem>
WholeProjectRefactorer::FindInvalidRequiredBehaviorProperties(
const gd::Project& project) {
std::vector<gd::UnfilledRequiredBehaviorPropertyProblem>
invalidRequiredBehaviorProperties;
auto findInvalidRequiredBehaviorPropertiesInObjects =
[&project, &invalidRequiredBehaviorProperties](
const std::vector<std::unique_ptr<gd::Object> >& objectsList) {
for (auto& object : objectsList) {
for (auto& behaviorContentKeyValuePair :
object->GetAllBehaviorContents()) {
gd::BehaviorContent& behaviorContent =
*behaviorContentKeyValuePair.second;
const auto& behaviorMetadata =
gd::MetadataProvider::GetBehaviorMetadata(
project.GetCurrentPlatform(),
behaviorContent.GetTypeName());
if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
std::cout << "Could not find metadata for behavior with type \""
<< behaviorContent.GetTypeName() << "\"" << std::endl;
continue;
}
const auto& behavior = behaviorMetadata.Get();
for (auto const& keyValue :
behavior.GetProperties(behaviorContent.GetContent())) {
const gd::String& propertyName = keyValue.first;
const gd::PropertyDescriptor& property = keyValue.second;
if (property.GetType().LowerCase() != "behavior") {
continue;
}
const gd::String& requiredBehaviorName = property.GetValue();
const std::vector<gd::String>& extraInfo =
property.GetExtraInfo();
if (extraInfo.size() == 0) {
// very unlikely
continue;
}
const gd::String& requiredBehaviorType = extraInfo.at(0);
if (requiredBehaviorName == "" ||
!object->HasBehaviorNamed(requiredBehaviorName) ||
object->GetBehavior(requiredBehaviorName).GetTypeName() !=
requiredBehaviorType) {
auto problem = UnfilledRequiredBehaviorPropertyProblem(
project,
*object,
behaviorContent,
propertyName,
requiredBehaviorType);
invalidRequiredBehaviorProperties.push_back(problem);
}
}
}
}
};
// Find in global objects
findInvalidRequiredBehaviorPropertiesInObjects(project.GetObjects());
// Find in layout objects.
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
const gd::Layout& layout = project.GetLayout(i);
findInvalidRequiredBehaviorPropertiesInObjects(layout.GetObjects());
}
return invalidRequiredBehaviorProperties;
}
bool WholeProjectRefactorer::FixInvalidRequiredBehaviorProperties(
gd::Project& project) {
const auto& invalidRequiredBehaviorProblems =
FindInvalidRequiredBehaviorProperties(project);
for (const auto& problem : invalidRequiredBehaviorProblems) {
auto& object = problem.GetSourceObject();
auto suggestedBehaviorNames =
GetBehaviorsWithType(object, problem.GetExpectedBehaviorTypeName());
auto& behaviorContent = problem.GetSourceBehaviorContent();
auto& behaviorMetadata = MetadataProvider::GetBehaviorMetadata(
project.GetCurrentPlatform(), behaviorContent.GetTypeName());
if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
continue;
}
auto& behavior = behaviorMetadata.Get();
if (suggestedBehaviorNames.empty()) {
// No matching behavior on the object.
// Add required behaviors on the object.
auto& expectedBehaviorMetadata = MetadataProvider::GetBehaviorMetadata(
project.GetCurrentPlatform(), problem.GetExpectedBehaviorTypeName());
if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
continue;
}
const gd::String& newBehaviorName =
expectedBehaviorMetadata.GetDefaultName();
AddBehaviorAndRequiredBehaviors(project,
object,
problem.GetExpectedBehaviorTypeName(),
newBehaviorName);
behavior.UpdateProperty(behaviorContent.GetContent(),
problem.GetSourcePropertyName(),
newBehaviorName);
} else {
// There is a matching behavior on the object use it by default.
behavior.UpdateProperty(
behaviorContent.GetContent(),
problem.GetSourcePropertyName(),
// It's unlikely the object has 2 behaviors of the same type.
suggestedBehaviorNames[0]);
}
}
return !invalidRequiredBehaviorProblems.empty();
}
void WholeProjectRefactorer::RenameEventsBasedBehavior(
@@ -678,6 +950,31 @@ void WholeProjectRefactorer::DoRenameBehavior(
}
};
// Rename behavior in required behavior properties
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
e++) {
auto& eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
for (auto&& eventsBasedBehavior :
eventsFunctionsExtension.GetEventsBasedBehaviors()
.GetInternalVector()) {
for (size_t i = 0;
i < eventsBasedBehavior->GetPropertyDescriptors().GetCount();
i++) {
NamedPropertyDescriptor& propertyDescriptor =
eventsBasedBehavior->GetPropertyDescriptors().Get(i);
std::vector<gd::String>& extraInfo = propertyDescriptor.GetExtraInfo();
if (propertyDescriptor.GetType() == "Behavior" &&
extraInfo.size() > 0) {
const gd::String& requiredBehaviorType = extraInfo[0];
if (requiredBehaviorType == oldBehaviorType) {
extraInfo[0] = newBehaviorType;
}
}
}
}
}
// Rename behavior in global objects
renameBehaviorTypeInObjects(project.GetObjects());

View File

@@ -6,10 +6,13 @@
#ifndef GDCORE_WHOLEPROJECTREFACTORER_H
#define GDCORE_WHOLEPROJECTREFACTORER_H
#include <set>
#include <unordered_set>
#include <vector>
namespace gd {
class Platform;
class Project;
class Layout;
class Object;
class String;
class EventsFunctionsExtension;
class EventsFunction;
@@ -18,6 +21,10 @@ class EventsBasedBehavior;
class ArbitraryEventsWorker;
class ArbitraryObjectsWorker;
class ArbitraryEventsWorkerWithContext;
class Behavior;
class BehaviorContent;
class BehaviorMetadata;
class UnfilledRequiredBehaviorPropertyProblem;
} // namespace gd
namespace gd {
@@ -51,13 +58,24 @@ class GD_CORE_API WholeProjectRefactorer {
gd::ArbitraryEventsWorkerWithContext& worker);
/**
* \brief Call the specified worker on all ObjectContainers of the project (global,
* layouts...)
* \brief Call the specified worker on all events of the events based behavior
*
* This should be the preferred way to traverse all the events of an events
* based behavior
*/
static void ExposeEventsBasedBehaviorEvents(
gd::Project& project,
const gd::EventsBasedBehavior& eventsBasedBehavior,
gd::ArbitraryEventsWorkerWithContext& worker);
/**
* \brief Call the specified worker on all ObjectContainers of the project
* (global, layouts...)
*
* This should be the preferred way to traverse all the objects of a project.
*/
static void ExposeProjectObjects(
gd::Project& project, gd::ArbitraryObjectsWorker& worker);
static void ExposeProjectObjects(gd::Project& project,
gd::ArbitraryObjectsWorker& worker);
/**
* \brief Refactor the project **before** an events function extension is
@@ -140,13 +158,52 @@ class GD_CORE_API WholeProjectRefactorer {
* This is because the property is expected to have its old name for the
* refactoring.
*/
static void RenameBehaviorProperty(
static void RenameEventsBasedBehaviorProperty(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::EventsBasedBehavior& eventsBasedBehavior,
const gd::String& oldPropertyName,
const gd::String& newPropertyName);
/**
* \brief Add a behavior to an object and add required behaviors if necessary
* to fill every behavior properties of the added behaviors.
*/
static void AddBehaviorAndRequiredBehaviors(gd::Project& project,
gd::Object& object,
const gd::String& behaviorType,
const gd::String& behaviorName);
/**
* \brief Find every behavior of the object that needs the given behaviors
* directly or indirectly (because of "required behavior" properties).
*/
static std::vector<gd::String> FindDependentBehaviorNames(
const gd::Project& project,
const gd::Object& object,
const gd::String& behaviorName);
/**
* \brief Find the names of the behaviors with the specified type on the object.
*/
static std::vector<gd::String> GetBehaviorsWithType(const gd::Object& object,
const gd::String& type);
/**
* \brief Find in the project objects having behaviors with "behavior" properties that
* don't have a valid value (i.e: pointing to a non existing behavior, or of a wrong type).
*/
static std::vector<gd::UnfilledRequiredBehaviorPropertyProblem>
FindInvalidRequiredBehaviorProperties(const gd::Project& project);
/**
* \brief Fix in the project objects having behaviors with "behavior" properties that
* don't have a valid value (i.e: pointing to a non existing behavior, or of a wrong type),
* by setting a proper behavior, or adding missing behaviors to these objects.
*/
static bool
FixInvalidRequiredBehaviorProperties(gd::Project& project);
/**
* \brief Refactor the project **before** a behavior is renamed.
*
@@ -267,6 +324,14 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& oldBehaviorType,
const gd::String& newBehaviorType);
static void FindDependentBehaviorNames(
const gd::Project& project,
const gd::Object& object,
const gd::String& behaviorName,
std::unordered_set<gd::String>& dependentBehaviorNames);
static const gd::String behaviorObjectParameterName;
WholeProjectRefactorer(){};
};

View File

@@ -9,7 +9,6 @@
namespace gd {
#if defined(GD_IDE_ONLY)
void Effect::SerializeTo(SerializerElement& element) const {
element.SetAttribute("name", GetName());
element.SetAttribute("effectType", GetEffectType());
@@ -32,7 +31,6 @@ void Effect::SerializeTo(SerializerElement& element) const {
booleanParametersElement.AddChild(parameter.first)
.SetValue(parameter.second);
}
#endif
void Effect::UnserializeFrom(const SerializerElement& element) {
SetName(element.GetStringAttribute("name"));

View File

@@ -74,12 +74,10 @@ class GD_CORE_API Effect {
booleanParameters.clear();
}
#if defined(GD_IDE_ONLY)
/**
* \brief Serialize layer.
*/
void SerializeTo(SerializerElement& element) const;
#endif
/**
* \brief Unserialize the layer.

View File

@@ -0,0 +1,140 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "EffectsContainer.h"
#include "Effect.h"
#include "GDCore/Serialization/SerializerElement.h"
namespace gd {
Effect EffectsContainer::badEffect;
EffectsContainer::EffectsContainer() {}
EffectsContainer::EffectsContainer(const EffectsContainer& other) {
Init(other);
}
EffectsContainer& EffectsContainer::operator=(const EffectsContainer& rhs) {
if (this != &rhs) Init(rhs);
return *this;
}
void EffectsContainer::Init(const EffectsContainer& other) {
effects.clear();
for (auto& it : other.effects) {
effects.push_back(std::make_shared<Effect>(*it));
}
}
bool EffectsContainer::HasEffectNamed(const gd::String& name) const {
return (find_if(effects.begin(),
effects.end(),
[&name](const std::shared_ptr<gd::Effect>& effect) {
return effect->GetName() == name;
}) != effects.end());
}
gd::Effect& EffectsContainer::GetEffect(const gd::String& name) {
auto effect = find_if(effects.begin(),
effects.end(),
[&name](std::shared_ptr<gd::Effect>& effect) {
return effect->GetName() == name;
});
if (effect != effects.end()) return **effect;
return badEffect;
}
const gd::Effect& EffectsContainer::GetEffect(const gd::String& name) const {
auto effect = find_if(effects.begin(),
effects.end(),
[&name](const std::shared_ptr<gd::Effect>& effect) {
return effect->GetName() == name;
});
if (effect != effects.end()) return **effect;
return badEffect;
}
gd::Effect& EffectsContainer::GetEffect(std::size_t index) {
return *effects[index];
}
const gd::Effect& EffectsContainer::GetEffect(std::size_t index) const {
return *effects[index];
}
std::size_t EffectsContainer::GetEffectsCount() const { return effects.size(); }
std::size_t EffectsContainer::GetEffectPosition(const gd::String& name) const {
for (std::size_t i = 0; i < effects.size(); ++i) {
if (effects[i]->GetName() == name) return i;
}
return gd::String::npos;
}
gd::Effect& EffectsContainer::InsertNewEffect(const gd::String& name,
std::size_t position) {
auto newEffect = std::make_shared<Effect>();
newEffect->SetName(name);
if (position < effects.size())
effects.insert(effects.begin() + position, newEffect);
else
effects.push_back(newEffect);
return *newEffect;
}
void EffectsContainer::InsertEffect(const gd::Effect& effect,
std::size_t position) {
auto newEffect = std::make_shared<gd::Effect>(effect);
if (position < effects.size())
effects.insert(effects.begin() + position, newEffect);
else
effects.push_back(newEffect);
}
void EffectsContainer::RemoveEffect(const gd::String& name) {
auto effect = find_if(effects.begin(),
effects.end(),
[&name](const std::shared_ptr<gd::Effect>& effect) {
return effect->GetName() == name;
});
if (effect == effects.end()) return;
effects.erase(effect);
}
void EffectsContainer::SwapEffects(std::size_t firstEffectIndex,
std::size_t secondEffectIndex) {
if (firstEffectIndex >= effects.size() || secondEffectIndex >= effects.size())
return;
auto temp = effects[firstEffectIndex];
effects[firstEffectIndex] = effects[secondEffectIndex];
effects[secondEffectIndex] = temp;
}
void EffectsContainer::SerializeTo(SerializerElement& element) const {
element.ConsiderAsArrayOf("effect");
for (std::size_t i = 0; i < GetEffectsCount(); ++i) {
SerializerElement& effectElement = element.AddChild("effect");
GetEffect(i).SerializeTo(effectElement);
}
}
void EffectsContainer::UnserializeFrom(const SerializerElement& element) {
effects.clear();
element.ConsiderAsArrayOf("effect");
for (std::size_t i = 0; i < element.GetChildrenCount(); ++i) {
const SerializerElement& effectElement = element.GetChild(i);
auto effect = std::make_shared<Effect>();
effect->UnserializeFrom(effectElement);
effects.push_back(effect);
}
}
} // namespace gd

View File

@@ -0,0 +1,114 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EFFECTS_CONTAINER_H
#define GDCORE_EFFECTS_CONTAINER_H
#include <memory>
#include <vector>
#include "GDCore/String.h"
namespace gd {
class Effect;
}
namespace gd {
class SerializerElement;
}
namespace gd {
/**
* \brief Contains effects applied to an entity on screen (i.e: a Layer or an
* Object).
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API EffectsContainer {
public:
EffectsContainer();
EffectsContainer(const EffectsContainer& other);
virtual ~EffectsContainer(){};
EffectsContainer& operator=(const EffectsContainer& rhs);
/**
* \brief Return true if the effect called "name" exists.
*/
bool HasEffectNamed(const gd::String& name) const;
/**
* \brief Return a reference to the effect called "name".
*/
Effect& GetEffect(const gd::String& name);
/**
* \brief Return a reference to the effect called "name".
*/
const Effect& GetEffect(const gd::String& name) const;
/**
* Return a reference to the effect at position "index" in the effects list
*/
Effect& GetEffect(std::size_t index);
/**
* Return a reference to the effect at position "index" in the effects list
*/
const Effect& GetEffect(std::size_t index) const;
/**
* Return the position of the effect called "name" in the effects list
*/
std::size_t GetEffectPosition(const gd::String& name) const;
/**
* Return the number of effecst.
*/
std::size_t GetEffectsCount() const;
/**
* Add a new effect at the specified position in the effects list.
*/
gd::Effect& InsertNewEffect(const gd::String& name, std::size_t position);
/**
* \brief Add a copy of the specified effect in the effects list.
*
* \note No pointer or reference must be kept on the effect passed as
* parameter.
*
* \param theEffect The effect that must be copied and inserted
* into the effects list
* \param position Insertion position.
*/
void InsertEffect(const Effect& theEffect, std::size_t position);
/**
* Remove the specified effect.
*/
void RemoveEffect(const gd::String& name);
/**
* Swap the position of two effects.
*/
void SwapEffects(std::size_t firstEffectIndex, std::size_t secondEffectIndex);
/**
* \brief Serialize the effects container.
*/
void SerializeTo(SerializerElement& element) const;
/**
* \brief Unserialize the effects container.
*/
void UnserializeFrom(const SerializerElement& element);
private:
std::vector<std::shared_ptr<gd::Effect>> effects;
static Effect badEffect;
void Init(const EffectsContainer& other);
};
} // namespace gd
#endif

View File

@@ -5,7 +5,7 @@
*/
#include "GDCore/Project/ExternalLayout.h"
#include "GDCore/IDE/Dialogs/LayoutEditorCanvas/LayoutEditorCanvasOptions.h"
#include "GDCore/IDE/Dialogs/LayoutEditorCanvas/EditorSettings.h"
#include "GDCore/Project/InitialInstancesContainer.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/TinyXml/tinyxml.h"
@@ -16,7 +16,7 @@ void ExternalLayout::UnserializeFrom(const SerializerElement& element) {
name = element.GetStringAttribute("name", "", "Name");
instances.UnserializeFrom(element.GetChild("instances", 0, "Instances"));
#if defined(GD_IDE_ONLY)
editionSettings.UnserializeFrom(element.GetChild("editionSettings"));
editorSettings.UnserializeFrom(element.GetChild("editionSettings"));
#endif
associatedLayout = element.GetStringAttribute("associatedLayout");
}
@@ -25,7 +25,7 @@ void ExternalLayout::UnserializeFrom(const SerializerElement& element) {
void ExternalLayout::SerializeTo(SerializerElement& element) const {
element.SetAttribute("name", name);
instances.SerializeTo(element.AddChild("instances"));
editionSettings.SerializeTo(element.AddChild("editionSettings"));
editorSettings.SerializeTo(element.AddChild("editionSettings"));
element.SetAttribute("associatedLayout", associatedLayout);
}
#endif

View File

@@ -13,7 +13,7 @@ namespace gd {
class SerializerElement;
}
#if defined(GD_IDE_ONLY)
#include "GDCore/IDE/Dialogs/LayoutEditorCanvas/LayoutEditorCanvasOptions.h"
#include "GDCore/IDE/Dialogs/LayoutEditorCanvas/EditorSettings.h"
#endif
namespace gd {
@@ -58,15 +58,15 @@ class GD_CORE_API ExternalLayout {
/**
* \brief Get the user settings for the IDE.
*/
const gd::LayoutEditorCanvasOptions& GetAssociatedSettings() const {
return editionSettings;
const gd::EditorSettings& GetAssociatedEditorSettings() const {
return editorSettings;
}
/**
* \brief Get the user settings for the IDE.
*/
gd::LayoutEditorCanvasOptions& GetAssociatedSettings() {
return editionSettings;
gd::EditorSettings& GetAssociatedEditorSettings() {
return editorSettings;
}
#endif
@@ -100,7 +100,7 @@ class GD_CORE_API ExternalLayout {
gd::String name;
gd::InitialInstancesContainer instances;
#if defined(GD_IDE_ONLY)
gd::LayoutEditorCanvasOptions editionSettings;
gd::EditorSettings editorSettings;
#endif
gd::String associatedLayout;
};

View File

@@ -1,213 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Project/ImageManager.h"
#include <SFML/OpenGL.hpp>
#include "GDCore/Project/ResourcesLoader.h"
#include "GDCore/Project/ResourcesManager.h"
#include "GDCore/Tools/InvalidImage.h"
#if !defined(ANDROID) && !defined(MACOS)
#include <GL/glu.h>
#endif
#undef LoadImage // thx windows.h
namespace gd {
ImageManager::ImageManager() : resourcesManager(NULL) {
#if !defined(EMSCRIPTEN)
badTexture = std::make_shared<SFMLTextureWrapper>();
badTexture->texture.loadFromMemory(gd::InvalidImageData,
sizeof(gd::InvalidImageData));
badTexture->texture.setSmooth(false);
badTexture->image = badTexture->texture.copyToImage();
#endif
}
std::shared_ptr<SFMLTextureWrapper> ImageManager::GetSFMLTexture(
const gd::String& name) const {
if (!resourcesManager) {
std::cout << "ImageManager has no ResourcesManager associated with.";
return badTexture;
}
if (alreadyLoadedImages.find(name) != alreadyLoadedImages.end() &&
!alreadyLoadedImages.find(name)->second.expired())
return alreadyLoadedImages.find(name)->second.lock();
std::cout << "ImageManager: Loading " << name << ".";
// Load only an image when necessary
try {
ImageResource& image =
dynamic_cast<ImageResource&>(resourcesManager->GetResource(name));
auto texture = std::make_shared<SFMLTextureWrapper>();
ResourcesLoader::Get()->LoadSFMLImage(image.GetFile(), texture->image);
texture->texture.loadFromImage(texture->image);
texture->texture.setSmooth(image.smooth);
alreadyLoadedImages[name] = texture;
#if defined(GD_IDE_ONLY)
if (preventUnloading)
unloadingPreventer.push_back(
texture); // If unload prevention is activated, add the image to the
// list dedicated to prevent images from being unloaded.
#endif
return texture;
} catch (...) {
}
std::cout << " Resource not found." << std::endl;
return badTexture;
}
bool ImageManager::HasLoadedSFMLTexture(const gd::String& name) const {
if (alreadyLoadedImages.find(name) != alreadyLoadedImages.end() &&
!alreadyLoadedImages.find(name)->second.expired())
return true;
return false;
}
void ImageManager::SetSFMLTextureAsPermanentlyLoaded(
const gd::String& name,
std::shared_ptr<SFMLTextureWrapper>& texture) const {
if (alreadyLoadedImages.find(name) == alreadyLoadedImages.end() ||
alreadyLoadedImages.find(name)->second.expired())
alreadyLoadedImages[name] = texture;
if (permanentlyLoadedImages.find(name) == permanentlyLoadedImages.end())
permanentlyLoadedImages[name] = texture;
}
void ImageManager::ReloadImage(const gd::String& name) const {
if (!resourcesManager) {
std::cout << "ImageManager has no ResourcesManager associated with.";
return;
}
// Verify if image is in memory. If not, it will be automatically reloaded
// when necessary.
if (alreadyLoadedImages.find(name) == alreadyLoadedImages.end() ||
alreadyLoadedImages.find(name)->second.expired())
return;
// Image still in memory, get it and update it.
std::shared_ptr<SFMLTextureWrapper> oldTexture =
alreadyLoadedImages.find(name)->second.lock();
try {
ImageResource& image =
dynamic_cast<ImageResource&>(resourcesManager->GetResource(name));
std::cout << "ImageManager: Reload " << name << std::endl;
ResourcesLoader::Get()->LoadSFMLImage(image.GetFile(), oldTexture->image);
oldTexture->texture.loadFromImage(oldTexture->image);
oldTexture->texture.setSmooth(image.smooth);
return;
} catch (...) { /*The ressource is not an image*/
}
// Image not present anymore in image list.
std::cout << "ImageManager: " << name << " is not available anymore."
<< std::endl;
*oldTexture = *badTexture;
}
std::shared_ptr<OpenGLTextureWrapper> ImageManager::GetOpenGLTexture(
const gd::String& name) const {
if (alreadyLoadedOpenGLTextures.find(name) !=
alreadyLoadedOpenGLTextures.end() &&
!alreadyLoadedOpenGLTextures.find(name)->second.expired())
return alreadyLoadedOpenGLTextures.find(name)->second.lock();
std::cout << "Load OpenGL Texture" << name << std::endl;
std::shared_ptr<OpenGLTextureWrapper> texture =
std::make_shared<OpenGLTextureWrapper>(GetSFMLTexture(name));
alreadyLoadedOpenGLTextures[name] = texture;
return texture;
}
void ImageManager::LoadPermanentImages() {
if (!resourcesManager) {
std::cout << "ImageManager has no ResourcesManager associated with.";
return;
}
// Create a new list of permanently loaded images but do not delete now the
// old list so as not to unload images that could be still present.
std::map<gd::String, std::shared_ptr<SFMLTextureWrapper> >
newPermanentlyLoadedImages;
std::vector<gd::String> resources = resourcesManager->GetAllResourceNames();
for (std::size_t i = 0; i < resources.size(); i++) {
try {
ImageResource& image = dynamic_cast<ImageResource&>(
resourcesManager->GetResource(resources[i]));
if (image.alwaysLoaded)
newPermanentlyLoadedImages[image.GetName()] =
GetSFMLTexture(image.GetName());
} catch (...) { /*The resource is not an image, we don't care about it.*/
}
}
permanentlyLoadedImages = newPermanentlyLoadedImages;
}
#if defined(GD_IDE_ONLY)
void ImageManager::PreventImagesUnloading() {
preventUnloading = true;
for (auto it = alreadyLoadedImages.begin(); it != alreadyLoadedImages.end();
++it) {
std::shared_ptr<SFMLTextureWrapper> image = (it->second).lock();
if (image != std::shared_ptr<SFMLTextureWrapper>())
unloadingPreventer.push_back(image);
}
}
void ImageManager::EnableImagesUnloading() {
preventUnloading = false;
unloadingPreventer
.clear(); // Images which are not used anymore will thus be destroyed (As
// no shared pointer will be pointing to them).
}
#endif
} // namespace gd
SFMLTextureWrapper::SFMLTextureWrapper(const sf::Texture& texture_)
: texture(texture_), image(texture.copyToImage()) {}
SFMLTextureWrapper::SFMLTextureWrapper() {}
SFMLTextureWrapper::~SFMLTextureWrapper() {}
OpenGLTextureWrapper::OpenGLTextureWrapper(
std::shared_ptr<SFMLTextureWrapper> sfmlTexture_) {
sfmlTexture = sfmlTexture_;
#if !defined(ANDROID) // TODO: OpenGL
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sfmlTexture->image.getSize().x,
// sfmlTexture->image.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE,
// sfmlTexture->image.getPixelsPtr()); glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(
GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
#endif
}
OpenGLTextureWrapper::~OpenGLTextureWrapper() {
#if !defined(ANDROID) // TODO: OpenGL
glDeleteTextures(1, &texture);
#endif
};

View File

@@ -1,185 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef ImageManager_H
#define ImageManager_H
#include <SFML/Graphics.hpp>
#include <SFML/OpenGL.hpp>
#include <SFML/System.hpp>
#include <iostream>
#include <memory>
#include <vector>
#include "GDCore/String.h"
namespace gd {
class ResourcesManager;
}
class OpenGLTextureWrapper;
class SFMLTextureWrapper;
#undef LoadImage // thx windows.h
namespace gd {
/**
* \brief Manage images for the IDE as well as at runtime for GD C++ Platform,
* providing an easy way to get SFML images or OpenGL textures.
*
* Image manager is used by objects to obtain their images from the image name.
*
* Images are loaded dynamically when necessary, and are unloaded if there is no
* more shared_ptr pointing on an image.
*
* You should in particular be interested by gd::ImageManager::GetOpenGLTexture
* and gd::ImageManager::GetSFMLTexture.
*
* \see SFMLTextureWrapper
* \see OpenGLTextureWrapper
*
* \ingroup ResourcesManagement
*/
class GD_CORE_API ImageManager {
public:
ImageManager();
virtual ~ImageManager(){};
/**
* \brief Get a shared pointer to an OpenGL texture. The shared pointer must
* be kept alive as long as the texture is used.
*/
std::shared_ptr<OpenGLTextureWrapper> GetOpenGLTexture(
const gd::String& name) const;
/**
* \brief Get a shared pointer to a SFML texture. The shared pointer must be
* kept alive as long as the texture is used.
*
* For example, if the texture is used in an object, you should store the
* shared pointer in a member to make sure the texture is available as long as
* the object is alive.
*/
std::shared_ptr<SFMLTextureWrapper> GetSFMLTexture(
const gd::String& name) const;
/**
* \brief Set the gd::ResourcesManager used by the ImageManager.
*/
void SetResourcesManager(gd::ResourcesManager* resourcesManager_) {
resourcesManager = resourcesManager_;
}
/**
* \brief Load all images of the project which are flagged as alwaysLoaded.
* \see ImageResource
*/
void LoadPermanentImages();
/**
* \brief Check if a SFML texture with the specified name is available and
* loaded in memory. \return true if the texture called \a name if available
* and loaded in memory.
*/
bool HasLoadedSFMLTexture(const gd::String& name) const;
/**
* \brief Add the SFMLTextureWrapper to loaded images ( so that it can be
* accessed thanks to ImageManager::GetSFMLTexture ) with the specified name
* and mark it as permanently loaded ( so that is is unloaded only when the
* layout is unloaded ).
*/
void SetSFMLTextureAsPermanentlyLoaded(
const gd::String& name,
std::shared_ptr<SFMLTextureWrapper>& texture) const;
/**
* \brief Reload a single image from the game resources
*/
void ReloadImage(const gd::String& name) const;
#if defined(GD_IDE_ONLY)
/**
* \brief When called, images won't be unloaded from memory until
* EnableImagesUnloading is called. Can be used when reloading a layout so as
* to prevent images from being unloaded and then immediately reloaded.
*/
void PreventImagesUnloading();
/**
* \brief Enable again unused images to be unloaded from memory.
*/
void EnableImagesUnloading();
#endif
private:
mutable std::map<gd::String, std::weak_ptr<SFMLTextureWrapper> >
alreadyLoadedImages; ///< Reference all images loaded in memory.
mutable std::map<gd::String, std::shared_ptr<SFMLTextureWrapper> >
permanentlyLoadedImages; ///< Contains (smart) pointers to images which
///< should stay loaded even if they are not
///< (currently) used.
#if defined(GD_IDE_ONLY)
/** This list is filled, when PreventImagesUnloading is called, with images
* already loaded in memory ( and any image loaded after the call to
* PreventImagesUnloading ). It will thus prevent these images from being
* unloaded. This list is destroyed when EnableImagesUnloading is called.
*
* \see PreventImagesUnloading
* \see EnableImagesUnloading
*/
mutable std::vector<std::shared_ptr<SFMLTextureWrapper> > unloadingPreventer;
bool preventUnloading; ///< True if no images must be currently unloaded.
#endif
mutable std::map<gd::String, std::weak_ptr<OpenGLTextureWrapper> >
alreadyLoadedOpenGLTextures; ///< Reference all OpenGL textures loaded in
///< memory.
mutable std::shared_ptr<SFMLTextureWrapper> badTexture;
mutable std::shared_ptr<OpenGLTextureWrapper> badOpenGLTexture;
gd::ResourcesManager* resourcesManager;
};
} // namespace gd
/**
* \brief Class wrapping an SFML texture.
*
* \see gd::ImageManager
* \ingroup ResourcesManagement
*/
class GD_CORE_API SFMLTextureWrapper {
public:
SFMLTextureWrapper(const sf::Texture& texture);
SFMLTextureWrapper();
~SFMLTextureWrapper();
sf::Texture texture;
sf::Image image; ///< Associated sfml image, used for pixel perfect collision
///< for example. If you update the image, call
///< LoadFromImage on texture to update it also.
};
/**
* \brief Class wrapping an OpenGL texture.
*
* \see gd::ImageManager
* \ingroup ResourcesManagement
*/
class GD_CORE_API OpenGLTextureWrapper {
public:
OpenGLTextureWrapper(std::shared_ptr<SFMLTextureWrapper> sfmlTexture_);
OpenGLTextureWrapper() : texture(0){};
~OpenGLTextureWrapper();
inline GLuint GetOpenGLTexture() const { return texture; }
private:
std::shared_ptr<SFMLTextureWrapper> sfmlTexture;
GLuint texture;
};
#endif // ImageManager_H

View File

@@ -4,6 +4,7 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Project/Layer.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Project/Effect.h"
#include "GDCore/Serialization/SerializerElement.h"
@@ -11,9 +12,9 @@
namespace gd {
Camera Layer::badCamera;
Effect Layer::badEffect;
Layer::Layer() : isVisible(true), isLightingLayer(false), followBaseLayerCamera(false) {}
Layer::Layer()
: isVisible(true), isLightingLayer(false), followBaseLayerCamera(false) {}
/**
* Change cameras count, automatically adding/removing them.
@@ -52,11 +53,7 @@ void Layer::SerializeTo(SerializerElement& element) const {
}
SerializerElement& effectsElement = element.AddChild("effects");
effectsElement.ConsiderAsArrayOf("effect");
for (std::size_t i = 0; i < GetEffectsCount(); ++i) {
SerializerElement& effectElement = effectsElement.AddChild("effect");
GetEffect(i).SerializeTo(effectElement);
}
effectsContainer.SerializeTo(effectsElement);
}
#endif
@@ -67,155 +64,53 @@ void Layer::UnserializeFrom(const SerializerElement& element) {
SetName(element.GetStringAttribute("name", "", "Name"));
SetVisibility(element.GetBoolAttribute("visibility", true, "Visibility"));
SetLightingLayer(element.GetBoolAttribute("isLightingLayer", false));
SetFollowBaseLayerCamera(element.GetBoolAttribute("followBaseLayerCamera", false));
SetAmbientLightColor(element.GetIntAttribute("ambientLightColorR", 200),
SetFollowBaseLayerCamera(
element.GetBoolAttribute("followBaseLayerCamera", false));
SetAmbientLightColor(element.GetIntAttribute("ambientLightColorR", 200),
element.GetIntAttribute("ambientLightColorG", 200),
element.GetIntAttribute("ambientLightColorB", 200));
// Compatibility with GD <= 3.3
if (element.HasChild("Camera")) {
for (std::size_t i = 0; i < element.GetChildrenCount("Camera"); ++i) {
const SerializerElement& cameraElement = element.GetChild("Camera", i);
SetCameraCount(GetCameraCount() + 1);
Camera& camera = GetCamera(GetCameraCount() - 1);
cameras.clear();
SerializerElement& camerasElement = element.GetChild("cameras");
camerasElement.ConsiderAsArrayOf("camera");
for (std::size_t i = 0; i < camerasElement.GetChildrenCount(); ++i) {
const SerializerElement& cameraElement = camerasElement.GetChild(i);
camera.SetUseDefaultSize(
cameraElement.GetBoolAttribute("DefaultSize", true));
camera.SetSize(cameraElement.GetDoubleAttribute("Width"),
cameraElement.GetDoubleAttribute("Height"));
Camera camera;
camera.SetUseDefaultSize(
cameraElement.GetBoolAttribute("defaultSize", true));
camera.SetSize(cameraElement.GetDoubleAttribute("width"),
cameraElement.GetDoubleAttribute("height"));
camera.SetUseDefaultViewport(
cameraElement.GetBoolAttribute("defaultViewport", true));
camera.SetViewport(
cameraElement.GetDoubleAttribute("viewportLeft"),
cameraElement.GetDoubleAttribute("viewportTop"),
cameraElement.GetDoubleAttribute("viewportRight"),
cameraElement.GetDoubleAttribute(
"viewportBottom"));
camera.SetUseDefaultViewport(
cameraElement.GetBoolAttribute("DefaultViewport", true));
camera.SetViewport(
cameraElement.GetDoubleAttribute("ViewportLeft"),
cameraElement.GetDoubleAttribute("ViewportTop"),
cameraElement.GetDoubleAttribute("ViewportRight"),
cameraElement.GetDoubleAttribute(
"ViewportBottom")); // (sf::Rect used Right and Bottom instead of
// Width and Height before)
}
}
// End of compatibility code
else {
SerializerElement& camerasElement = element.GetChild("cameras");
camerasElement.ConsiderAsArrayOf("camera");
for (std::size_t i = 0; i < camerasElement.GetChildrenCount(); ++i) {
const SerializerElement& cameraElement = camerasElement.GetChild(i);
SetCameraCount(GetCameraCount() + 1);
Camera& camera = GetCamera(GetCameraCount() - 1);
camera.SetUseDefaultSize(
cameraElement.GetBoolAttribute("defaultSize", true));
camera.SetSize(cameraElement.GetDoubleAttribute("width"),
cameraElement.GetDoubleAttribute("height"));
camera.SetUseDefaultViewport(
cameraElement.GetBoolAttribute("defaultViewport", true));
camera.SetViewport(
cameraElement.GetDoubleAttribute("viewportLeft"),
cameraElement.GetDoubleAttribute("viewportTop"),
cameraElement.GetDoubleAttribute("viewportRight"),
cameraElement.GetDoubleAttribute(
"viewportBottom")); // (sf::Rect used Right and Bottom instead of
// Width and Height before)
}
cameras.push_back(camera);
}
effects.clear();
SerializerElement& effectsElement = element.GetChild("effects");
effectsElement.ConsiderAsArrayOf("effect");
for (std::size_t i = 0; i < effectsElement.GetChildrenCount(); ++i) {
const SerializerElement& effectElement = effectsElement.GetChild(i);
auto effect = std::make_shared<Effect>();
effect->UnserializeFrom(effectElement);
effects.push_back(effect);
if (camerasElement.GetChildrenCount() > 50) {
// Highly unlikely that we want as many cameras, as they were not even exposed in
// the editor nor used in the game engine. Must be because of a bug in the editor that
// duplicated cameras when cancelling changes on a layer.
// Reset to one camera.
SetCameraCount(1);
}
const SerializerElement& effectsElement = element.GetChild("effects");
effectsContainer.UnserializeFrom(effectsElement);
}
gd::Effect& Layer::GetEffect(const gd::String& name) {
auto effect = find_if(effects.begin(),
effects.end(),
[&name](std::shared_ptr<gd::Effect>& effect) {
return effect->GetName() == name;
});
if (effect != effects.end()) return **effect;
return badEffect;
}
const gd::Effect& Layer::GetEffect(const gd::String& name) const {
auto effect = find_if(effects.begin(),
effects.end(),
[&name](const std::shared_ptr<gd::Effect>& effect) {
return effect->GetName() == name;
});
if (effect != effects.end()) return **effect;
return badEffect;
}
gd::Effect& Layer::GetEffect(std::size_t index) { return *effects[index]; }
const gd::Effect& Layer::GetEffect(std::size_t index) const {
return *effects[index];
}
std::size_t Layer::GetEffectsCount() const { return effects.size(); }
bool Layer::HasEffectNamed(const gd::String& name) const {
return (find_if(effects.begin(),
effects.end(),
[&name](const std::shared_ptr<gd::Effect>& effect) {
return effect->GetName() == name;
}) != effects.end());
}
std::size_t Layer::GetEffectPosition(const gd::String& name) const {
for (std::size_t i = 0; i < effects.size(); ++i) {
if (effects[i]->GetName() == name) return i;
}
return gd::String::npos;
gd::EffectsContainer& Layer::GetEffects() {
return effectsContainer;
}
gd::Effect& Layer::InsertNewEffect(const gd::String& name,
std::size_t position) {
auto newEffect = std::make_shared<Effect>();
newEffect->SetName(name);
if (position < effects.size())
effects.insert(effects.begin() + position, newEffect);
else
effects.push_back(newEffect);
return *newEffect;
}
void Layer::InsertEffect(const gd::Effect& effect, std::size_t position) {
auto newEffect = std::make_shared<gd::Effect>(effect);
if (position < effects.size())
effects.insert(effects.begin() + position, newEffect);
else
effects.push_back(newEffect);
}
void Layer::RemoveEffect(const gd::String& name) {
auto effect = find_if(effects.begin(),
effects.end(),
[&name](const std::shared_ptr<gd::Effect>& effect) {
return effect->GetName() == name;
});
if (effect == effects.end()) return;
effects.erase(effect);
}
void Layer::SwapEffects(std::size_t firstEffectIndex,
std::size_t secondEffectIndex) {
if (firstEffectIndex >= effects.size() || secondEffectIndex >= effects.size())
return;
auto temp = effects[firstEffectIndex];
effects[firstEffectIndex] = effects[secondEffectIndex];
effects[secondEffectIndex] = temp;
const gd::EffectsContainer& Layer::GetEffects() const {
return effectsContainer;
}
Camera::Camera()

View File

@@ -7,7 +7,10 @@
#define GDCORE_LAYER_H
#include <memory>
#include <vector>
#include "EffectsContainer.h"
#include "GDCore/String.h"
namespace gd {
class Effect;
}
@@ -17,6 +20,9 @@ class Camera;
namespace gd {
class SerializerElement;
}
namespace gd {
class EffectsContainer;
}
namespace gd {
@@ -54,7 +60,9 @@ class GD_CORE_API Layer {
/**
* \brief Set if the layer is a lightining layer or not.
*/
void SetLightingLayer(bool isLightingLayer_) { isLightingLayer = isLightingLayer_; }
void SetLightingLayer(bool isLightingLayer_) {
isLightingLayer = isLightingLayer_;
}
/**
* \brief Return true if the layer is a lighting layer.
@@ -64,7 +72,9 @@ class GD_CORE_API Layer {
/**
* \brief Set if the layer automatically follows the base layer or not.
*/
void SetFollowBaseLayerCamera(bool followBaseLayerCamera_) { followBaseLayerCamera = followBaseLayerCamera_; }
void SetFollowBaseLayerCamera(bool followBaseLayerCamera_) {
followBaseLayerCamera = followBaseLayerCamera_;
}
/**
* \brief Return true if the layer follows the base layer.
@@ -144,66 +154,14 @@ class GD_CORE_API Layer {
*/
///@{
/**
* \brief Return true if the effect called "name" exists.
* \brief Return the effects container.
*/
bool HasEffectNamed(const gd::String& name) const;
EffectsContainer& GetEffects();
/**
* \brief Return a reference to the effect called "name".
* \brief Return a const reference to the effects container.
*/
Effect& GetEffect(const gd::String& name);
/**
* \brief Return a reference to the effect called "name".
*/
const Effect& GetEffect(const gd::String& name) const;
/**
* Return a reference to the effect at position "index" in the effects list
*/
Effect& GetEffect(std::size_t index);
/**
* Return a reference to the effect at position "index" in the effects list
*/
const Effect& GetEffect(std::size_t index) const;
/**
* Return the position of the effect called "name" in the effects list
*/
std::size_t GetEffectPosition(const gd::String& name) const;
/**
* Return the number of effecst.
*/
std::size_t GetEffectsCount() const;
/**
* Add a new effect at the specified position in the effects list.
*/
gd::Effect& InsertNewEffect(const gd::String& name, std::size_t position);
/**
* \brief Add a copy of the specified effect in the effects list.
*
* \note No pointer or reference must be kept on the layer passed as
* parameter.
*
* \param theEffect The effect that must be copied and inserted
* into the effects list
* \param position Insertion position.
*/
void InsertEffect(const Effect& theEffect, std::size_t position);
/**
* Remove the specified effect.
*/
void RemoveEffect(const gd::String& name);
/**
* Swap the position of two effects.
*/
void SwapEffects(std::size_t firstEffectIndex, std::size_t secondEffectIndex);
const EffectsContainer& GetEffects() const;
///@}
#if defined(GD_IDE_ONLY)
@@ -219,19 +177,19 @@ class GD_CORE_API Layer {
void UnserializeFrom(const SerializerElement& element);
private:
gd::String name; ///< The name of the layer
bool isVisible; ///< True if the layer is visible
bool isLightingLayer; ///< True if the layer is used to display lights and renders an ambient light.
bool followBaseLayerCamera; ///< True if the layer automatically follows the base layer
unsigned int ambientLightColorR; ///< Ambient light color Red component
unsigned int ambientLightColorG; ///< Ambient light color Green component
unsigned int ambientLightColorB; ///< Ambient light color Blue component
gd::String name; ///< The name of the layer
bool isVisible; ///< True if the layer is visible
bool isLightingLayer; ///< True if the layer is used to display lights and
///< renders an ambient light.
bool followBaseLayerCamera; ///< True if the layer automatically follows the
///< base layer
unsigned int ambientLightColorR; ///< Ambient light color Red component
unsigned int ambientLightColorG; ///< Ambient light color Green component
unsigned int ambientLightColorB; ///< Ambient light color Blue component
std::vector<gd::Camera> cameras; ///< The camera displayed by the layer
std::vector<std::shared_ptr<gd::Effect>>
effects; ///< The effects applied to the layer.
gd::EffectsContainer effectsContainer; ///< The effects applied to the layer.
static gd::Camera badCamera;
static gd::Effect badEffect;
};
/**

View File

@@ -5,10 +5,14 @@
*/
#include "Layout.h"
#include <algorithm>
#include <vector>
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Serialization.h"
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/IDE/SceneNameMangler.h"
#include "GDCore/Project/Behavior.h"
@@ -219,16 +223,21 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
++i) {
const gd::String& name = allBehaviorsNames[i];
if (behaviorsSharedData.find(name) == behaviorsSharedData.end()) {
gd::BehaviorsSharedData* behaviorSharedData =
project.GetBehaviorSharedDatas(allBehaviorsTypes[i]);
if (behaviorSharedData) {
auto behaviorContent =
gd::make_unique<gd::BehaviorContent>(name, allBehaviorsTypes[i]);
behaviorSharedData->InitializeContent(behaviorContent->GetContent());
behaviorsSharedData[name] = std::move(behaviorContent);
}
}
if (behaviorsSharedData.find(name) != behaviorsSharedData.end()) continue;
const gd::BehaviorMetadata& behaviorMetadata =
gd::MetadataProvider::GetBehaviorMetadata(project.GetCurrentPlatform(),
allBehaviorsTypes[i]);
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) continue;
gd::BehaviorsSharedData* behaviorSharedData =
behaviorMetadata.GetSharedDataInstance();
if (!behaviorSharedData) continue;
auto behaviorContent =
gd::make_unique<gd::BehaviorContent>(name, allBehaviorsTypes[i]);
behaviorSharedData->InitializeContent(behaviorContent->GetContent());
behaviorsSharedData[name] = std::move(behaviorContent);
}
// Remove useless shared data:
@@ -263,7 +272,7 @@ void Layout::SerializeTo(SerializerElement& element) const {
disableInputWhenNotFocused);
#if defined(GD_IDE_ONLY)
GetAssociatedSettings().SerializeTo(element.AddChild("uiSettings"));
editorSettings.SerializeTo(element.AddChild("uiSettings"));
#endif
GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
@@ -324,7 +333,7 @@ void Layout::UnserializeFrom(gd::Project& project,
element.GetBoolAttribute("disableInputWhenNotFocused");
#if defined(GD_IDE_ONLY)
associatedSettings.UnserializeFrom(
editorSettings.UnserializeFrom(
element.GetChild("uiSettings", 0, "UISettings"));
GetObjectGroups().UnserializeFrom(
@@ -403,7 +412,7 @@ void Layout::Init(const Layout& other) {
#if defined(GD_IDE_ONLY)
events = other.events;
associatedSettings = other.associatedSettings;
editorSettings = other.editorSettings;
objectGroups = other.objectGroups;
profiler = other.profiler;

View File

@@ -18,7 +18,7 @@
#include "GDCore/Project/VariablesContainer.h"
#include "GDCore/String.h"
#if defined(GD_IDE_ONLY)
#include "GDCore/IDE/Dialogs/LayoutEditorCanvas/LayoutEditorCanvasOptions.h"
#include "GDCore/IDE/Dialogs/LayoutEditorCanvas/EditorSettings.h"
#endif
namespace gd {
class BaseEvent;
@@ -291,18 +291,18 @@ class GD_CORE_API Layout : public ObjectsContainer {
#if defined(GD_IDE_ONLY)
/**
* Return the settings associated to the layout.
* \see gd::LayoutEditorCanvasOptions
* \see gd::EditorSettings
*/
const gd::LayoutEditorCanvasOptions& GetAssociatedSettings() const {
return associatedSettings;
const gd::EditorSettings& GetAssociatedEditorSettings() const {
return editorSettings;
}
/**
* Return the settings associated to the layout.
* \see gd::LayoutEditorCanvasOptions
* \see gd::EditorSettings
*/
gd::LayoutEditorCanvasOptions& GetAssociatedSettings() {
return associatedSettings;
gd::EditorSettings& GetAssociatedEditorSettings() {
return editorSettings;
}
#endif
@@ -436,7 +436,7 @@ class GD_CORE_API Layout : public ObjectsContainer {
///< specified behavior shared data.
#if defined(GD_IDE_ONLY)
EventsList events; ///< Scene events
gd::LayoutEditorCanvasOptions associatedSettings;
gd::EditorSettings editorSettings;
#endif
// TODO: GD C++ Platform specific code below

View File

@@ -5,15 +5,63 @@
*/
#include "LoadingScreen.h"
#include "GDCore/Serialization/SerializerElement.h"
namespace gd {
LoadingScreen::LoadingScreen()
: showGDevelopSplash(true),
gdevelopLogoStyle("light"),
backgroundImageResourceName(""),
backgroundColor(0),
backgroundFadeInDuration(0.2),
minDuration(1.5),
logoAndProgressFadeInDuration(0.2),
logoAndProgressLogoFadeInDelay(0.2),
showProgressBar(true),
progressBarMinWidth(40),
progressBarMaxWidth(200),
progressBarWidthPercent(30),
progressBarHeight(20),
progressBarColor(0xFFFFFF){};
void LoadingScreen::SerializeTo(SerializerElement& element) const {
element.SetAttribute("showGDevelopSplash", showGDevelopSplash);
element.SetAttribute("gdevelopLogoStyle",
gdevelopLogoStyle);
element.SetAttribute("backgroundImageResourceName",
backgroundImageResourceName);
element.SetAttribute("backgroundColor", backgroundColor);
element.SetAttribute("backgroundFadeInDuration", backgroundFadeInDuration);
element.SetAttribute("minDuration", minDuration);
element.SetAttribute("logoAndProgressFadeInDuration", logoAndProgressFadeInDuration);
element.SetAttribute("logoAndProgressLogoFadeInDelay", logoAndProgressLogoFadeInDelay);
element.SetAttribute("showProgressBar", showProgressBar);
element.SetAttribute("progressBarMinWidth", progressBarMinWidth);
element.SetAttribute("progressBarMaxWidth", progressBarMaxWidth);
element.SetAttribute("progressBarWidthPercent", progressBarWidthPercent);
element.SetAttribute("progressBarHeight", progressBarHeight);
element.SetAttribute("progressBarColor", progressBarColor);
}
void LoadingScreen::UnserializeFrom(const SerializerElement& element) {
showGDevelopSplash = element.GetBoolAttribute("showGDevelopSplash", true);
gdevelopLogoStyle =
element.GetStringAttribute("gdevelopLogoStyle", "light");
backgroundImageResourceName =
element.GetStringAttribute("backgroundImageResourceName");
backgroundColor = element.GetIntAttribute("backgroundColor", 0);
backgroundFadeInDuration =
element.GetDoubleAttribute("backgroundFadeInDuration", 0.2);
minDuration = element.GetDoubleAttribute("minDuration", 1.5);
logoAndProgressFadeInDuration = element.GetDoubleAttribute("logoAndProgressFadeInDuration", 0.2);
logoAndProgressLogoFadeInDelay = element.GetDoubleAttribute("logoAndProgressLogoFadeInDelay", 0.2);
showProgressBar = element.GetBoolAttribute("showProgressBar", true);
progressBarMinWidth = element.GetDoubleAttribute("progressBarMinWidth", 40);
progressBarMaxWidth = element.GetDoubleAttribute("progressBarMaxWidth", 200);
progressBarWidthPercent = element.GetDoubleAttribute("progressBarWidthPercent", 30);
progressBarHeight = element.GetDoubleAttribute("progressBarHeight", 20);
progressBarColor = element.GetIntAttribute("progressBarColor", 0xFFFFFF);
}
} // namespace gd

View File

@@ -22,36 +22,151 @@ namespace gd {
*/
class GD_CORE_API LoadingScreen {
public:
LoadingScreen(){};
LoadingScreen();
virtual ~LoadingScreen(){};
/**
* \brief Set if the GDevelop splash should be shown while loading assets.
*/
void ShowGDevelopSplash(bool show) { showGDevelopSplash = show; };
/**
* \brief Return true if the GDevelop splash should be shown while loading
* \brief Return true if the GDevelop logo should be shown while loading
* assets.
*/
bool IsGDevelopSplashShown() const { return showGDevelopSplash; };
/**
* \brief Set if the GDevelop logo should be shown while loading assets.
*/
LoadingScreen& ShowGDevelopSplash(bool show) {
showGDevelopSplash = show;
return *this;
};
const gd::String& GetGDevelopLogoStyle() const { return gdevelopLogoStyle; };
LoadingScreen& SetGDevelopLogoStyle(const gd::String& value) {
gdevelopLogoStyle = value;
return *this;
}
const gd::String& GetBackgroundImageResourceName() const {
return backgroundImageResourceName;
};
LoadingScreen& SetBackgroundImageResourceName(const gd::String& value) {
backgroundImageResourceName = value;
return *this;
}
int GetBackgroundColor() const { return backgroundColor; };
LoadingScreen& SetBackgroundColor(int value) {
backgroundColor = value;
return *this;
}
double GetBackgroundFadeInDuration() const {
return backgroundFadeInDuration;
};
LoadingScreen& SetBackgroundFadeInDuration(double value) {
backgroundFadeInDuration = value;
return *this;
}
double GetMinDuration() const { return minDuration; };
LoadingScreen& SetMinDuration(double value) {
minDuration = value;
return *this;
}
double GetLogoAndProgressFadeInDuration() const {
return logoAndProgressFadeInDuration;
}
LoadingScreen& SetLogoAndProgressFadeInDuration(double value) {
logoAndProgressFadeInDuration = value;
return *this;
}
double GetLogoAndProgressLogoFadeInDelay() const {
return logoAndProgressLogoFadeInDelay;
}
LoadingScreen& SetLogoAndProgressLogoFadeInDelay(double value) {
logoAndProgressLogoFadeInDelay = value;
return *this;
}
bool GetShowProgressBar() const { return showProgressBar; }
LoadingScreen& SetShowProgressBar(bool value) {
showProgressBar = value;
return *this;
}
double GetProgressBarMinWidth() const { return progressBarMinWidth; }
LoadingScreen& SetProgressBarMinWidth(double value) {
progressBarMinWidth = value;
return *this;
}
double GetProgressBarMaxWidth() const { return progressBarMaxWidth; }
LoadingScreen& SetProgressBarMaxWidth(double value) {
progressBarMaxWidth = value;
return *this;
}
double GetProgressBarWidthPercent() const { return progressBarWidthPercent; }
LoadingScreen& SetProgressBarWidthPercent(double value) {
progressBarWidthPercent = value;
return *this;
}
double GetProgressBarHeight() const { return progressBarHeight; }
LoadingScreen& SetProgressBarHeight(double value) {
progressBarHeight = value;
return *this;
}
int GetProgressBarColor() const { return progressBarColor; }
LoadingScreen& SetProgressBarColor(int value) {
progressBarColor = value;
return *this;
}
/** \name Saving and loading
*/
///@{
/**
* \brief Serialize objects groups container.
* \brief Serialize the loading screen setup.
*/
void SerializeTo(SerializerElement& element) const;
/**
* \brief Unserialize the objects groups container.
* \brief Unserialize the loading screen setup.
*/
void UnserializeFrom(const SerializerElement& element);
///@}
private:
bool showGDevelopSplash;
gd::String gdevelopLogoStyle;
gd::String backgroundImageResourceName;
int backgroundColor;
double backgroundFadeInDuration; // In seconds.
double minDuration; // In seconds.
double logoAndProgressFadeInDuration; // In seconds.
double logoAndProgressLogoFadeInDelay; // In seconds.
bool showProgressBar;
double progressBarMinWidth; // In pixels.
double progressBarMaxWidth; // In pixels.
double progressBarWidthPercent;
double progressBarHeight; // In pixels.
int progressBarColor;
};
} // namespace gd

View File

@@ -70,12 +70,6 @@ class GD_CORE_API NamedPropertyDescriptor : public PropertyDescriptor {
virtual void UnserializeValuesFrom(const SerializerElement& element);
///@}
/**
* Return a PropertyDescriptor from this NamedPropertyDescriptor,
* slicing the name.
*/
PropertyDescriptor ToPropertyDescriptor() { return PropertyDescriptor(*this); }
private:
gd::String name; ///< The name of the property.
};

View File

@@ -4,6 +4,9 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Project/Object.h"
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/Layout.h"
@@ -24,6 +27,7 @@ void Object::Init(const gd::Object& object) {
type = object.type;
objectVariables = object.objectVariables;
tags = object.tags;
effectsContainer = object.effectsContainer;
behaviors.clear();
for (auto& it : object.behaviors) {
@@ -85,16 +89,17 @@ std::map<gd::String, gd::PropertyDescriptor> Object::GetProperties() const {
gd::BehaviorContent* Object::AddNewBehavior(gd::Project& project,
const gd::String& type,
const gd::String& name) {
gd::Behavior* behavior = project.GetCurrentPlatform().GetBehavior(type);
if (behavior) {
auto behaviorContent = gd::make_unique<gd::BehaviorContent>(name, type);
behavior->InitializeContent(behaviorContent->GetContent());
behaviors[name] = std::move(behaviorContent);
return behaviors[name].get();
} else {
const gd::BehaviorMetadata& behaviorMetadata =
gd::MetadataProvider::GetBehaviorMetadata(project.GetCurrentPlatform(),
type);
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
return nullptr;
}
auto behaviorContent = gd::make_unique<gd::BehaviorContent>(name, type);
behaviorMetadata.Get().InitializeContent(behaviorContent->GetContent());
behaviors[name] = std::move(behaviorContent);
return behaviors[name].get();
}
std::map<gd::String, gd::PropertyDescriptor>
@@ -116,6 +121,11 @@ void Object::UnserializeFrom(gd::Project& project,
element.GetChild("variables", 0, "Variables"));
behaviors.clear();
if (element.HasChild("effects")) {
const SerializerElement& effectsElement = element.GetChild("effects");
effectsContainer.UnserializeFrom(effectsElement);
}
// Compatibility with GD <= 3.3
if (element.HasChild("Automatism")) {
for (std::size_t i = 0; i < element.GetChildrenCount("Automatism"); ++i) {
@@ -180,6 +190,7 @@ void Object::SerializeTo(SerializerElement& element) const {
element.SetAttribute("type", GetType());
element.SetAttribute("tags", GetTags());
objectVariables.SerializeTo(element.AddChild("variables"));
effectsContainer.SerializeTo(element.AddChild("effects"));
SerializerElement& behaviorsElement = element.AddChild("behaviors");
behaviorsElement.ConsiderAsArrayOf("behavior");

View File

@@ -9,7 +9,9 @@
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Project/BehaviorContent.h"
#include "GDCore/Project/EffectsContainer.h"
#include "GDCore/Project/VariablesContainer.h"
#include "GDCore/String.h"
#include "GDCore/Tools/MakeUnique.h"
@@ -20,6 +22,7 @@ class Layout;
class ArbitraryResourceWorker;
class InitialInstance;
class SerializerElement;
class EffectsContainer;
} // namespace gd
namespace gd {
@@ -146,8 +149,7 @@ class GD_CORE_API Object {
*
* \return false if the new value cannot be set
*/
virtual bool UpdateProperty(const gd::String& name,
const gd::String& value) {
virtual bool UpdateProperty(const gd::String& name, const gd::String& value) {
return false;
};
///@}
@@ -198,12 +200,12 @@ class GD_CORE_API Object {
std::vector<gd::String> GetAllBehaviorNames() const;
/**
* \brief Return a reference to the behavior called \a name.
* \brief Return a reference to the content of the behavior called \a name.
*/
BehaviorContent& GetBehavior(const gd::String& name);
/**
* \brief Return a reference to the behavior called \a name.
* \brief Return a reference to the content of the behavior called \a name.
*/
const BehaviorContent& GetBehavior(const gd::String& name) const;
@@ -270,6 +272,24 @@ class GD_CORE_API Object {
* object variables
*/
gd::VariablesContainer& GetVariables() { return objectVariables; }
///@}
/**
* \name Effects management
* Member functions related to effects management.
*/
///@{
/**
* \brief Provide access to the gd::EffectsContainer member containing the
* effects.
*/
const gd::EffectsContainer& GetEffects() const { return effectsContainer; }
/**
* \brief Provide access to the gd::EffectsContainer member containing the
* effects.
*/
gd::EffectsContainer& GetEffects() { return effectsContainer; }
///@}
/** \name Serialization
@@ -301,7 +321,9 @@ class GD_CORE_API Object {
///< object.
gd::VariablesContainer
objectVariables; ///< List of the variables of the object
gd::String tags; ///< Comma-separated list of tags
gd::String tags; ///< Comma-separated list of tags
gd::EffectsContainer
effectsContainer; ///< The effects container for the object.
/**
* \brief Derived objects can redefine this method to load custom attributes.

View File

@@ -26,7 +26,6 @@
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/Project/ExternalLayout.h"
#include "GDCore/Project/ImageManager.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectGroupsContainer.h"
@@ -64,26 +63,20 @@ Project::Project()
minFPS(20),
verticalSync(false),
scaleMode("linear"),
pixelsRounding(false),
adaptGameResolutionAtRuntime(true),
sizeOnStartupMode("adaptWidth"),
projectUuid(""),
useDeprecatedZeroAsDefaultZOrder(false),
imageManager(std::make_shared<ImageManager>())
useDeprecatedZeroAsDefaultZOrder(false)
#if defined(GD_IDE_ONLY)
,
useExternalSourceFiles(false),
currentPlatform(NULL),
gdMajorVersion(gd::VersionWrapper::Major()),
gdMinorVersion(gd::VersionWrapper::Minor()),
gdBuildVersion(gd::VersionWrapper::Build()),
dirty(false)
gdBuildVersion(gd::VersionWrapper::Build())
#endif
{
imageManager->SetResourcesManager(&resourcesManager);
#if !defined(GD_IDE_ONLY)
platforms.push_back(&CppPlatform::Get());
#endif
}
Project::~Project() {}
@@ -109,33 +102,6 @@ std::unique_ptr<gd::Object> Project::CreateObject(
return nullptr;
}
gd::Behavior* Project::GetBehavior(const gd::String& type,
const gd::String& platformName) {
for (std::size_t i = 0; i < platforms.size(); ++i) {
if (!platformName.empty() && platforms[i]->GetName() != platformName)
continue;
gd::Behavior* behavior = platforms[i]->GetBehavior(type);
if (behavior) return behavior;
}
return nullptr;
}
gd::BehaviorsSharedData* Project::GetBehaviorSharedDatas(
const gd::String& type, const gd::String& platformName) {
for (std::size_t i = 0; i < platforms.size(); ++i) {
if (!platformName.empty() && platforms[i]->GetName() != platformName)
continue;
gd::BehaviorsSharedData* behaviorSharedData =
platforms[i]->GetBehaviorSharedDatas(type);
if (behaviorSharedData) return behaviorSharedData;
}
return nullptr;
}
#if defined(GD_IDE_ONLY)
std::shared_ptr<gd::BaseEvent> Project::CreateEvent(
const gd::String& type, const gd::String& platformName) {
@@ -515,8 +481,6 @@ void Project::ClearEventsFunctionsExtensions() {
void Project::UnserializeFrom(const SerializerElement& element) {
// Checking version
#if defined(GD_IDE_ONLY)
gd::String updateText;
const SerializerElement& gdVersionElement =
element.GetChild("gdVersion", 0, "GDVersion");
gdMajorVersion =
@@ -528,10 +492,10 @@ void Project::UnserializeFrom(const SerializerElement& element) {
if (gdMajorVersion > gd::VersionWrapper::Major())
gd::LogWarning(
_("The version of GDevelop used to create this game seems to be a new "
"version.\nGDevelop may fail to open the game, or data may be "
"missing.\nYou should check if a new version of GDevelop is "
"available."));
"The version of GDevelop used to create this game seems to be a new "
"version.\nGDevelop may fail to open the game, or data may be "
"missing.\nYou should check if a new version of GDevelop is "
"available.");
else {
if ((gdMajorVersion == gd::VersionWrapper::Major() &&
gdMinorVersion > gd::VersionWrapper::Minor()) ||
@@ -543,22 +507,12 @@ void Project::UnserializeFrom(const SerializerElement& element) {
gdBuildVersion == gd::VersionWrapper::Build() &&
revision > gd::VersionWrapper::Revision())) {
gd::LogWarning(
_("The version of GDevelop used to create this game seems to be "
"greater.\nGDevelop may fail to open the game, or data may be "
"missing.\nYou should check if a new version of GDevelop is "
"available."));
"The version of GDevelop used to create this game seems to be "
"greater.\nGDevelop may fail to open the game, or data may be "
"missing.\nYou should check if a new version of GDevelop is "
"available.");
}
}
// Compatibility code
if (gdMajorVersion <= 1) {
gd::LogError(_(
"The game was saved with version of GDevelop which is too old. Please "
"open and save the game with one of the first version of GDevelop 2. "
"You will then be able to open your game with this GDevelop version."));
return;
}
// End of Compatibility code
#endif
const SerializerElement& propElement =
@@ -575,6 +529,7 @@ void Project::UnserializeFrom(const SerializerElement& element) {
SetVerticalSyncActivatedByDefault(
propElement.GetChild("verticalSync").GetValue().GetBool());
SetScaleMode(propElement.GetStringAttribute("scaleMode", "linear"));
SetPixelsRounding(propElement.GetBoolAttribute("pixelsRounding", false));
SetAdaptGameResolutionAtRuntime(
propElement.GetBoolAttribute("adaptGameResolutionAtRuntime", false));
SetSizeOnStartupMode(propElement.GetStringAttribute("sizeOnStartupMode", ""));
@@ -682,21 +637,6 @@ void Project::UnserializeFrom(const SerializerElement& element) {
currentPlatform = platforms.back();
#endif
// Compatibility code
#if defined(GD_IDE_ONLY)
if (VersionWrapper::IsOlder(gdMajorVersion, 0, 0, 0, 3, 0, 0, 0)) {
updateText +=
_("Sprite scaling has changed since GD 2: The resizing is made so that "
"the origin point of the object won't move whatever the scale of the "
"object.\n");
updateText +=
_("You may have to slightly change the position of some objects if you "
"have changed their size.\n\n");
updateText += _("Thank you for your understanding.\n");
}
#endif
// End of Compatibility code
#if defined(GD_IDE_ONLY)
GetObjectGroups().UnserializeFrom(
element.GetChild("objectsGroups", 0, "ObjectGroups"));
@@ -802,6 +742,7 @@ void Project::SerializeTo(SerializerElement& element) const {
propElement.AddChild("verticalSync")
.SetValue(IsVerticalSynchronizationEnabledByDefault());
propElement.SetAttribute("scaleMode", scaleMode);
propElement.SetAttribute("pixelsRounding", pixelsRounding);
propElement.SetAttribute("adaptGameResolutionAtRuntime",
adaptGameResolutionAtRuntime);
propElement.SetAttribute("sizeOnStartupMode", sizeOnStartupMode);
@@ -877,10 +818,6 @@ void Project::SerializeTo(SerializerElement& element) const {
for (std::size_t i = 0; i < externalSourceFiles.size(); ++i)
externalSourceFiles[i]->SerializeTo(
externalSourceFilesElement.AddChild("sourceFile"));
#if defined(GD_IDE_ONLY)
dirty = false;
#endif
}
bool Project::ValidateName(const gd::String& name) {
@@ -997,6 +934,7 @@ void Project::Init(const gd::Project& game) {
minFPS = game.minFPS;
verticalSync = game.verticalSync;
scaleMode = game.scaleMode;
pixelsRounding = game.pixelsRounding;
adaptGameResolutionAtRuntime = game.adaptGameResolutionAtRuntime;
sizeOnStartupMode = game.sizeOnStartupMode;
projectUuid = game.projectUuid;
@@ -1023,9 +961,7 @@ void Project::Init(const gd::Project& game) {
platforms = game.platforms;
resourcesManager = game.resourcesManager;
imageManager = std::make_shared<ImageManager>(*game.imageManager);
imageManager->SetResourcesManager(&resourcesManager);
initialObjects = gd::Clone(game.initialObjects);
scenes = gd::Clone(game.scenes);
@@ -1047,7 +983,6 @@ void Project::Init(const gd::Project& game) {
#if defined(GD_IDE_ONLY)
projectFile = game.GetProjectFile();
imagesChanged = game.imagesChanged;
#endif
}

View File

@@ -28,7 +28,6 @@ class Object;
class VariablesContainer;
class ArbitraryResourceWorker;
class SourceFile;
class ImageManager;
class Behavior;
class BehaviorsSharedData;
class BaseEvent;
@@ -277,6 +276,19 @@ class GD_CORE_API Project : public ObjectsContainer {
*/
void SetScaleMode(const gd::String& scaleMode_) { scaleMode = scaleMode_; }
/**
* Return true if pixels rounding option is enabled.
*/
bool GetPixelsRounding() const {
return pixelsRounding;
}
/**
* Set pixels rounding option to true or false.
*/
void SetPixelsRounding(bool enable) { pixelsRounding = enable; }
/**
* \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
@@ -390,37 +402,6 @@ class GD_CORE_API Project : public ObjectsContainer {
const gd::String& name,
const gd::String& platformName = "");
/**
* Get the behavior of the given type.
*
* \note A project can use more than one platform. In this case, the first
* platform supporting the behavior is used, unless \a platformName argument
* is not empty.
* It is assumed that each platform provides an equivalent
* behavior.
*
* \param type The type of the behavior
* \param platformName The name of the platform to be used. If empty, the
* first platform supporting the object is used.
*/
gd::Behavior* GetBehavior(const gd::String& type,
const gd::String& platformName = "");
/**
* Get the behavior shared data of the given type.
*
* \note A project can use more than one platform. In this case, the first
* platform supporting the behavior shared data is used, unless \a
* platformName argument is not empty.
* It is assumed that each platform provides equivalent behavior shared data.
*
* \param type The type of behavior
* \param platformName The name of the platform to be used. If empty, the
* first platform supporting the object is used.
*/
gd::BehaviorsSharedData* GetBehaviorSharedDatas(
const gd::String& type, const gd::String& platformName = "");
#if defined(GD_IDE_ONLY)
/**
* Create an event of the given type.
@@ -529,19 +510,6 @@ class GD_CORE_API Project : public ObjectsContainer {
*/
void SerializeTo(SerializerElement& element) const;
/**
* \brief Return true if the project is marked as being modified (The IDE or
* application using the project should ask to save the project if the project
* is closed).
*/
bool IsDirty() { return dirty; }
/**
* \brief Mark the project as being modified (The IDE or application
* using the project should ask to save the project if the project is closed).
*/
void SetDirty(bool enable = true) { dirty = enable; }
/**
* Get the major version of GDevelop used to save the project.
*/
@@ -823,28 +791,6 @@ class GD_CORE_API Project : public ObjectsContainer {
*/
ResourcesManager& GetResourcesManager() { return resourcesManager; }
/**
* \brief Provide access to the ImageManager allowing to load SFML or OpenGL
* textures for the IDE ( or at runtime for the GD C++ Platform ).
*/
const std::shared_ptr<gd::ImageManager>& GetImageManager() const {
return imageManager;
}
/**
* \brief Provide access to the ImageManager allowing to load SFML or OpenGL
* textures for the IDE ( or at runtime for the GD C++ Platform ).
*/
std::shared_ptr<gd::ImageManager>& GetImageManager() { return imageManager; }
/**
* \brief Provide access to the ImageManager allowing to load SFML or OpenGL
* textures for the IDE ( or at runtime for the GD C++ Platform ).
*/
void SetImageManager(std::shared_ptr<gd::ImageManager> imageManager_) {
imageManager = imageManager_;
}
/**
* \brief Called ( e.g. during compilation ) so as to inventory internal
* resources, sometimes update their filename or any other work or resources.
@@ -941,12 +887,6 @@ class GD_CORE_API Project : public ObjectsContainer {
#endif
///@}
// TODO: Put this in private part
#if defined(GD_IDE_ONLY)
std::vector<gd::String> imagesChanged; ///< Images that have been changed and
///< which have to be reloaded
#endif
private:
/**
* Initialize from another game. Used by copy-ctor and assign-op.
@@ -963,6 +903,8 @@ class GD_CORE_API Project : public ObjectsContainer {
///< are below this number )
bool verticalSync; ///< If true, must activate vertical synchronization.
gd::String scaleMode;
bool pixelsRounding; ///< If true, the rendering should stop pixel interpolation
///< of rendered objects.
bool adaptGameResolutionAtRuntime; ///< Should the game resolution be adapted
///< to the window size at runtime
gd::String
@@ -985,9 +927,6 @@ class GD_CORE_API Project : public ObjectsContainer {
#endif
gd::ResourcesManager
resourcesManager; ///< Contains all resources used by the project
std::shared_ptr<gd::ImageManager>
imageManager; ///< Image manager is accessed thanks to a (smart) ptr as
///< it can be shared with GD C++ Platform projects.
std::vector<gd::Platform*>
platforms; ///< Pointers to the platforms this project supports.
gd::String firstLayout;
@@ -1018,7 +957,6 @@ class GD_CORE_API Project : public ObjectsContainer {
///< time the project was saved.
mutable unsigned int gdBuildVersion; ///< The GD build version used the last
///< time the project was saved.
mutable bool dirty; ///< True to flag the project as being modified.
#endif
};

View File

@@ -76,6 +76,14 @@ class GD_CORE_API PropertyDescriptor {
return *this;
}
/**
* \brief Set and replace the additional information for the property.
*/
PropertyDescriptor& SetExtraInfo(const std::vector<gd::String>& info) {
extraInformation = info;
return *this;
}
/**
* \brief Add an information about the property.
* \note The information are arbitrary and are interpreted by the class
@@ -92,9 +100,14 @@ class GD_CORE_API PropertyDescriptor {
const gd::String& GetType() const { return type; }
const gd::String& GetLabel() const { return label; }
const gd::String& GetDescription() const { return description; }
const std::vector<gd::String>& GetExtraInfo() const {
return extraInformation;
}
std::vector<gd::String>& GetExtraInfo() {
return extraInformation;
}
/**
* \brief Set if the property should be shown or hidden in the editor.

View File

@@ -1,108 +0,0 @@
#include "GDCore/Project/ResourcesLoader.h"
#include <SFML/Audio.hpp>
#include <SFML/Graphics.hpp>
#include <cstring>
#include <fstream>
#include <iostream>
#include <utility>
#include "GDCore/String.h"
#include "GDCore/Tools/FileStream.h"
#undef LoadImage // Undef a macro from windows.h
using namespace std;
namespace gd {
ResourcesLoader *ResourcesLoader::_singleton = NULL;
void ResourcesLoader::LoadSFMLImage(const gd::String &filename,
sf::Image &image) {
gd::SFMLFileStream stream;
if (!stream.open(filename) || !image.loadFromStream(stream))
cout << "Failed to load a SFML image: " << filename << endl;
}
sf::Texture ResourcesLoader::LoadSFMLTexture(const gd::String &filename) {
sf::Texture texture;
LoadSFMLTexture(filename, texture);
return texture;
}
void ResourcesLoader::LoadSFMLTexture(const gd::String &filename,
sf::Texture &texture) {
gd::SFMLFileStream stream;
if (!stream.open(filename) || !texture.loadFromStream(stream))
cout << "Failed to load a SFML texture: " << filename << endl;
}
std::pair<sf::Font *, StreamHolder *> ResourcesLoader::LoadFont(
const gd::String &filename) {
sf::Font *font = new sf::Font();
StreamHolder *streamHolder = new StreamHolder();
if (!streamHolder->stream.open(filename) ||
!font->loadFromStream(streamHolder->stream)) {
cout << "Failed to load a font from a file: " << filename << endl;
delete font;
delete streamHolder;
return std::make_pair((sf::Font *)nullptr, (StreamHolder *)nullptr);
}
return std::make_pair(font, streamHolder);
}
sf::SoundBuffer ResourcesLoader::LoadSoundBuffer(const gd::String &filename) {
sf::SoundBuffer sbuffer;
gd::SFMLFileStream stream;
if (!stream.open(filename) || !sbuffer.loadFromStream(stream))
cout << "Failed to load a sound buffer: " << filename << endl;
return sbuffer;
}
gd::String ResourcesLoader::LoadPlainText(const gd::String &filename) {
gd::String text;
gd::FileStream file(filename, ios::in);
if (!file.fail()) {
std::string ligne;
while (getline(file, ligne)) text += gd::String::FromUTF8(ligne) + "\n";
file.close();
} else
cout << "Failed to read a file: " << filename << endl;
return text;
}
/**
* Load a binary text file
*/
char *ResourcesLoader::LoadBinaryFile(const gd::String &filename) {
gd::FileStream file(filename, ios::in | ios::binary | ios::ate);
if (file.is_open()) {
iostream::pos_type size = file.tellg();
char *memblock = new char[size];
file.seekg(0, ios::beg);
file.read(memblock, size);
file.close();
return memblock;
}
cout << "Binary file " << filename << " can't be loaded into memory " << endl;
return NULL;
}
long int ResourcesLoader::GetBinaryFileSize(const gd::String &filename) {
gd::FileStream file(filename, ios::in | ios::binary | ios::ate);
if (file.is_open()) {
return file.tellg();
}
std::cout << "Binary file " << filename << " cannot be read. " << std::endl;
return 0;
}
} // namespace gd

View File

@@ -1,106 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef RESSOURCESLOADER_H
#define RESSOURCESLOADER_H
#include <SFML/Audio.hpp>
#include <SFML/Graphics.hpp>
#include "GDCore/String.h"
#include "GDCore/Tools/FileStream.h"
#undef LoadImage // Undef macro from windows.h
namespace gd {
/**
* \brief A class holding a buffer and/or a file stream (useful for SFML classes
* that needs their buffer/stream continuously opened)
*/
struct StreamHolder {
StreamHolder() : buffer(nullptr), stream() {}
~StreamHolder() {
if (buffer) delete buffer;
}
char *buffer;
gd::SFMLFileStream stream;
};
/**
* \brief Class used by games to load resources from files: this is purely an
* abstraction to most SFML loadFrom* functions.
*
* This class is replaced in GDCpp by an equivalent that can load also from
* memory.
*
* \ingroup ResourcesManagement
*/
class GD_CORE_API ResourcesLoader {
public:
void LoadSFMLImage(const gd::String &filename, sf::Image &image);
/**
* Load a SFML texture.
*/
sf::Texture LoadSFMLTexture(const gd::String &filename);
void LoadSFMLTexture(const gd::String &filename, sf::Texture &texture);
/**
* Load a SFML Font.
* \warning The function calling LoadFont is the owner of the returned font
* and buffer (if any): Don't forget to delete them after use.
*
* \return A pair containing the loaded font, or NULL if loading failed, and
* the buffer that need to be kept alive while the font is used (can be NULL
* if the font was loaded from a file).
*/
std::pair<sf::Font *, StreamHolder *> LoadFont(const gd::String &filename);
/**
* Load a SFML Sound Buffer
*/
sf::SoundBuffer LoadSoundBuffer(const gd::String &filename);
/**
* Load a plain text file
*/
gd::String LoadPlainText(const gd::String &filename);
/**
* Get a buffer for file.
* Be careful, the buffer will be invalided by any subsequent call to
* Load[Something]. Make a copy of the buffer if you want it to stay alive
* longer.
*/
char *LoadBinaryFile(const gd::String &filename);
/**
* Get the size of a file
*/
long int GetBinaryFileSize(const gd::String &filename);
static ResourcesLoader *Get() {
if (NULL == _singleton) {
_singleton = new ResourcesLoader;
}
return (static_cast<ResourcesLoader *>(_singleton));
}
static void DestroySingleton() {
if (NULL != _singleton) {
delete _singleton;
_singleton = NULL;
}
}
private:
ResourcesLoader(){};
virtual ~ResourcesLoader(){};
static ResourcesLoader *_singleton;
};
} // namespace gd
#endif // RESSOURCESLOADER_H

View File

@@ -7,7 +7,6 @@
#include "GDCore/Project/Variable.h"
#include <sstream>
#include <cmath>
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
@@ -92,7 +91,7 @@ double Variable::GetValue() const {
if (type == Type::Number) {
return value;
} else if (type == Type::String) {
double retVal = str.To<double>();
double retVal = str.empty() ? 0.0 : str.To<double>();
if(std::isnan(retVal)) retVal = 0.0;
return retVal;
} else if (type == Type::Boolean) {

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