Compare commits

...

180 Commits

Author SHA1 Message Date
Florian Rival
c6c586459c Update the subscriptions plans to reflect the new ones and their updated benefits (#4290)
* Read [the blog post](https://gdevelop.io/blog/new-premium-subscriptions-online-services) for a full description of the updates and online services unlocked by the updated (and the existing) plans.
2022-09-14 11:33:37 +02:00
AlexandreS
a930011d8d Bump newIDE version 2022-09-14 10:24:54 +02:00
github-actions[bot]
51d723bd3d Update translations [skip ci] (#4284) 2022-09-14 10:21:23 +02:00
D8H
b63f968011 Fix resource refactoring for child-objects (#4289)
* Don't show in changelogs.
2022-09-14 09:41:07 +02:00
Florian Rival
3387c553d8 Fix previews not loading audio/font/json resources uploaded with the web-app (#4285)
Don't show in changelog
2022-09-13 16:41:33 +02:00
D8H
441cd20846 Fix a crash when renaming a child-object (#4281)
* Add tests for object renaming in events.
* Don't show in changelogs.
2022-09-13 12:46:20 +02:00
AlexandreS
f9871bd63d Add supported formats mimtypes to resource selector input accept attributes (#4283)
[skip-ci]
2022-09-13 11:51:22 +02:00
github-actions[bot]
bac11b3818 Update translations [skip ci] (#4230)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2022-09-13 10:37:01 +02:00
D8H
3e32cb8cea Fix the events-based objects editor that were never showing up in dev mode (#4279)
* Don't show in changelogs
2022-09-12 10:48:22 +02:00
Florian Rival
db74a59730 Add support for markdown in announcements (#4280)
Don't show in changelog
2022-09-12 10:28:32 +02:00
D8H
e7d09531b7 Fix event-based behavior properties default values that were ignored (#4276)
* Don't show in changelogs
2022-09-09 17:56:27 +02:00
Florian Rival
97cf19180b Rename Behaviors/Functions to Extensions in the project manager (#4272)
Don't show in changelog
2022-09-09 14:08:13 +02:00
Florian Rival
5cc999c0a3 Add announcements and news in the homepage community tab (#4273)
* Also display "urgent" announcements at the top of the home page (which can be dismissed).
2022-09-09 10:50:49 +02:00
D8H
5eb0aa9e14 Add an instance render for custom objects (#4251)
* Don't show in changelogs
2022-09-06 12:41:38 +02:00
D8H
7f528649d7 Revert the RendererInstance parameter for the tile map extension (#4260)
* Don't show in changelogs
2022-09-05 19:38:47 +02:00
D8H
c4f44daa8c Expose a gdObject constructor for the asset script (#4268)
* Don't show in changelogs.
2022-09-05 16:14:54 +02:00
AlexandreS
7d00e78628 Change the name of exports to be based on the name and version of the game 2022-09-05 12:12:39 +02:00
Aurélien Vivet
887ced270a Add the possibility to receive the GDevelop newsletter from the Profile and on Signup (#4256) 2022-09-05 10:32:30 +02:00
D8H
b8e9bc801a Add a properties editor for custom objects (#4227)
* Don't show in changelogs
2022-09-02 14:13:41 +02:00
D8H
7f023e1a58 Remove useless SetIncludeFile call. (#4255)
- Most of them has a wrong path anyway.
- Don't show in changelogs.
2022-09-01 14:30:24 +02:00
AlexandreS
6606ddb260 Improve SVG display in Resource Store for dark themes 2022-09-01 09:31:04 +02:00
Clément Pasteau
a682c1baa8 Update "Submit New Extension" link with new format (#4254) 2022-08-31 14:47:32 +02:00
Clément Pasteau
d581af20e1 Improve Signup and Edit profile to show when a username is not available 2022-08-31 13:59:14 +02:00
Florian Rival
2abf636283 Fix tests on Windows
Don't show in changelog
2022-08-30 18:15:08 +02:00
D8H
7d09853c12 Fix tile maps layer filtering (#4249) 2022-08-30 14:31:28 +02:00
AlexandreS
bb88f3ae4d Add button to release notes in about dialog
Do not show in changelog
2022-08-30 13:52:10 +02:00
D8H
44b06039e1 Upgrade the Pixi tile map extension to 3.2.2 (#4212)
* It also lifts the 16,000 tiles limit.
2022-08-30 13:11:59 +02:00
Clément Pasteau
9c7f2e4293 Remove user public profile search type (#4243)
Do not show in changelog
2022-08-30 11:26:12 +02:00
AlexandreS
facbbe614d Add button in changelog dialog to read on Github to benefit from browser translator 2022-08-30 11:09:15 +02:00
AlexandreS
d5cadadf82 Fix browser translator crashing the app 2022-08-29 11:30:52 +02:00
D8H
aed4b76a3f Refactor behavior configuration model (#4217)
* Merge BehaviorContent into Behavior and add CustomBehavior
* Don't show in changelogs
2022-08-29 09:21:21 +02:00
Florian Rival
b1e03f4555 Add support for uploading your own files from your device for cloud project on the web-app (#4225)
* You can now upload your own files when working on the web-app, when your project is saved as a Cloud project.
* This means the web-app can be used without limits to build any game you could build on the desktop app.
* Support for Cloud projects on the desktop app will be available soon. You will also be able to save an existing project on your computer as a cloud project, or vice versa.
2022-08-28 22:30:58 +02:00
D8H
93be3153b5 Fix useless "Change" prefix in some actions name (#4238) 2022-08-28 21:44:23 +02:00
Aurélien Vivet
d0c9ff6754 Fix the action to tween the number of a scene variable (#4235) 2022-08-28 16:53:16 +02:00
AlexandreS
a5cf0896bc Fix the wording of the layer field when the layer is not optional (though it has a default value: the base layer) (#4232) 2022-08-26 17:12:40 +02:00
Clément Pasteau
7f6ce26c43 Handle players logging in to GDevelop and becoming creators (#4231)
Do not show in changelog
2022-08-26 13:51:45 +02:00
AlexandreS
eda9db6b40 Fix points coordinates inputs not losing focus when moving points on the preview 2022-08-26 09:55:37 +02:00
github-actions[bot]
b9405f5e7d Update translations [skip ci] (#4220)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2022-08-26 09:26:08 +02:00
Clément Pasteau
ca591f60d6 Improve game templates visibility
* Change "Create a new project" action from the command palette to directly open a blank project
* Add 2 new actions in the Desktop menu "Create an empty project" and "Create a project from a template"
* Templates are now displayed at the top of the Build section
* The button "Create a project" in the Build section now directly opens a blank project
2022-08-25 16:49:37 +02:00
Peter Anderson
214e012ec4 Rename object variables expression names to differentiate number and text variables. 2022-08-25 15:32:39 +02:00
Aurélien Vivet
9cc0172a60 Add Educational tag for games on Liluo.io (#4222) 2022-08-25 10:20:34 +02:00
Florian Rival
6e01228ae6 Fix Safari/iOS unable to load some images in the app (#4148) 2022-08-24 12:25:33 +02:00
github-actions[bot]
e22611625e Update translations [skip ci] (#4205)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2022-08-22 14:58:20 +02:00
Clément Pasteau
28ccb55a06 Improve onboarding banner (#4216)
Do not show in changelog
2022-08-22 14:41:07 +02:00
D8H
7893b892a3 Add an events-based object editor prototype (#4208)
* don't show in change logs
2022-08-22 14:05:58 +02:00
Arthur Pacaud
10b3c50a42 Fix parameter to specify the P2P port not being an expression (#4215) 2022-08-22 12:00:09 +02:00
D8H
8c5fbc6e34 Add missing translations for some messages shown when renaming an object (#4213) 2022-08-21 19:00:10 +02:00
Aurélien Vivet
a40382333b Fix the name of the "End Opacity" condition of the particle emitters (#4214) 2022-08-21 16:47:43 +02:00
Florian Rival
fb95f26fbb Update artifacts download script to include arm64 build artifacts [skip ci] [ci skip]
Don't show in changelog
2022-08-18 10:14:08 +02:00
Florian Rival
48a90ae86d Display a super thin or invisible scrollbars for the toolbar and tabs, according to the browser 2022-08-18 09:16:49 +02:00
Florian Rival
6303a50a9d Enable macOS build for Apple Silicon and arm64 builds for Linux (#4031) 2022-08-17 16:02:25 +02:00
D8H
a47ec5199e Limit the number of autocompletion elements displayed for extensions search tags. (#4207)
Don't show in changelog
2022-08-17 11:43:24 +02:00
D8H
a6921c2de3 Fix the extensions search bar that was only using the first 30 tags alphabetically (#4206) 2022-08-17 10:17:57 +02:00
Florian Rival
b21b6f0dfb Bump newIDE version 2022-08-16 18:01:34 +02:00
Florian Rival
c0d4480099 Update AdMob to declare AD_ID permission on Android, as required for Android 13 2022-08-16 17:50:53 +02:00
github-actions[bot]
56277ff5d3 Update translations [skip ci] (#4204)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2022-08-16 17:04:22 +02:00
Florian Rival
4fa1fbd5e2 Remove useless files being scanned for translations
Don't show in changelog
2022-08-16 16:51:30 +02:00
Florian Rival
f61ef1be2e Add monetization tab in game dashboard
* Allow to enable or disable ads on the game page if published on Liluo.io
* In the future, games that generate enough revenue will be able to opt-in into "revenue share", so that as a creator you can start earning from your game sessions.
* This also this allows to maintain free publishing on Liluo.io for all.
2022-08-16 16:40:52 +02:00
github-actions[bot]
bf387631ec Update translations [skip ci] (#4173)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2022-08-16 14:18:32 +02:00
Florian Rival
981752af26 Make compile-translations script more robust
Don't show in changelog
2022-08-16 14:09:52 +02:00
Florian Rival
58e5933c75 Update GDevelop logo in the about dialog
Don't show in changelog
2022-08-12 22:47:23 +02:00
Florian Rival
237ad8ce39 Show the full version number in the About dialog, and the update status for the web-app (#4202) 2022-08-12 20:41:23 +02:00
Florian Rival
02225cb0ec Move the preferences button in the home page (#4201)
* Also display the full GDevelop version number in the "About GDevelop" button in the home page - useful to check if you're on the latest version when using the web-app
2022-08-12 19:26:09 +02:00
Florian Rival
b34426e084 Add support for Android 12 splashscreen icon (#4200) 2022-08-12 18:48:10 +02:00
Florian Rival
23c09f3472 Fix buttons to download exported games not shown as primary buttons 2022-08-12 17:01:59 +02:00
D8H
59a7690748 Fix the "move parameter" refactor for expressions in the extension editor (#3968) 2022-08-12 14:04:12 +02:00
Aurélien Vivet
3e97d4b878 Clarify the name of the actions to resume a paused sound/music (#4199) 2022-08-12 12:20:27 +02:00
Florian Rival
d710dd0335 Fix sourcemap of Box2D wasm source wrongly included when exporting
Don't show in changelog
2022-08-11 21:53:13 +02:00
Aurélien Vivet
78695b6b17 Fix wrong description of Firebase "Check for a document's existence" action (#4198) 2022-08-11 21:48:24 +02:00
Florian Rival
4e3dec4356 Upgrade Admob so that it works with the latest Android SDK, required to publish apps on the Play Store (#4197) 2022-08-11 17:33:40 +02:00
D8H
f373e3b8d1 Fix the export of game using Box2d WASM library (#4195)
Don't show in changelog
2022-08-11 15:42:47 +02:00
Clément Pasteau
3e71c3a63f Fix saving project after creation (#4194)
Do not show in changelog
2022-08-10 11:31:49 +02:00
Clément Pasteau
86cad044d4 Add a test button to display staging assets in dev (#4170)
Do not show in changelog
2022-08-10 11:18:03 +02:00
Florian Rival
21b525ab98 Fix raycast condition not working properly on objects with multiple hitboxes (#4186) 2022-08-09 11:21:57 +02:00
Clément Pasteau
fb328fd0f5 Install fixes (#4190)
Do not show in changelog
2022-08-09 10:06:49 +02:00
Aurélien Vivet
afdb934a8a Fix typo (#4191) 2022-08-08 17:56:41 +02:00
AlexandreS
530f756e47 Add possibility to seal an instance (impossible to select it on the canvas) 2022-08-08 14:20:11 +02:00
Sebastian Krzyszkowiak
b1fb207a08 Minimize in game/real cursor flickering when showing/hiding the cursor (#4184) 2022-08-05 23:17:35 +02:00
Florian Rival
5f87213ccd Improve messages when reaching the maximum count of cloud projects 2022-08-05 22:56:21 +02:00
Florian Rival
9065454bfe Add more cloud projects for GDevelop online subscribers (#4183)
Don't show in changelog
2022-08-05 18:33:14 +02:00
Florian Rival
801fbb4b10 Fix orange outline sometimes appearing around the scene editor canvas 2022-08-05 18:29:22 +02:00
D8H
cfa538ec3d Fix the collision mask of rotated tiles that were sometimes misplaced (#4181) 2022-08-05 18:10:06 +02:00
D8H
504443dea4 Fix a game analytics test (#4182)
It was building data with fixed dates that were processed using the real today date.
Don't show in change logs.
2022-08-05 16:56:39 +02:00
Florian Rival
bdbc665d2e Fix exported WebManifest file having a syntax error when the game description has line breaks
Fix #4180
2022-08-05 09:13:25 +02:00
D8H
1d77f2da23 Replace the Box2D library with a WebAssembly one (#4153)
* It fixes a crash of the old Box2D library when a lot of objects with the Physics2 behavior were created.
* The same version of Box2d (2.3.1) is still used so there should not be any behavior change.
2022-08-04 18:11:00 +02:00
AlexandreS
7b6aa78aeb Fix memory leak at the end of a cloud project save (#4178)
Do not show in changelog
2022-08-04 16:19:09 +02:00
AlexandreS
e9aaed9d41 Fix json resource removed from project resources although it is used in event 2022-08-04 14:05:42 +02:00
Florian Rival
982c9e38c1 Add support for subscribing to GDevelop premium accounts with PayPal (#4166)
* You can now get a subscription, support GDevelop development and get more one-click online exports every day, using PayPal (or using credit cards as done previously).
2022-08-03 23:00:08 +02:00
Arthur Pacaud
c86388018c Add tween actions for camera zoom and camera rotation (#4174) 2022-08-03 22:21:45 +02:00
AlexandreS
6ae1b62df7 Add possibility to remove a project from the recent project list
Do not show in changelog
2022-08-03 17:42:33 +02:00
AlexandreS
ea745a49d7 Set storage provider before opening file metadata (#4175)
Do not show in changelog
2022-08-03 17:28:16 +02:00
AlexandreS
48fc2f640b Fix google drive project display in build section
Do not show in changelog
2022-08-03 16:31:15 +02:00
github-actions[bot]
a86ee8c338 Update translations [skip ci] (#4139)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2022-08-03 15:52:37 +02:00
AlexandreS
1787b3c5c8 Improve communication around cloud projects
Do not show in changelog
2022-08-03 15:42:20 +02:00
D8H
3e246e3cf0 Fix the loading of tile map atlases that was aborted when the image contains unused pixels at the right or bottom. (#4167) 2022-08-02 10:53:04 +02:00
AlexandreS
5035d16bd4 Improve game dashboard naming
Do not show in changelog
2022-08-01 17:04:41 +02:00
AlexandreS
2f6109a21c Display a custom error message when user has too may cloud projects
Do not show in changelog
2022-08-01 14:42:21 +02:00
D8H
0792fdadc7 Fix the tile map collision mask debug rendering that wasn't refreshed when there was no collision condition nor bahavior (#4162) 2022-08-01 10:21:17 +02:00
Clément Pasteau
0ca596e287 Remove scrolling on liluo iframe (#4159) 2022-07-29 18:13:27 +02:00
Florian Rival
899a252ddd Fix starters shown at the bottom of the example list on Firefox 2022-07-29 17:32:50 +02:00
AlexandreS
d92bf23e58 Fix double opening of project
Do not show in changelog
2022-07-29 15:11:20 +02:00
AlexandreS
37ae451178 Improve Homepage project list with more context actions and better display for local projects 2022-07-29 14:30:36 +02:00
Clément Pasteau
9c47a92ea6 Move asset store actions to be at the bottom of the dialog 2022-07-29 13:22:34 +02:00
Aurélien Vivet
1afd4b94be Fix a typo: Remove a double from (#4154)
Don't show in the changelog
2022-07-29 10:47:07 +02:00
Clément Pasteau
4d5a3f499f Rework play section to display Liluo games (#4151)
* Rework play section to display Liluo games

* ensure message origin
2022-07-29 10:12:02 +02:00
AlexandreS
13da1c56fd Add GDevelop own Cloud storage for web-app project
In order to make the life easier for our users on the web-app, we created GDevelop's cloud storage.
With a GDevelop account on the web-app, you can now save your project online and retrieve it from any device.
2022-07-28 15:26:41 +02:00
Clément Pasteau
8131ffcdb5 Fix Asset cards text color to be visible on light theme (#4152) 2022-07-28 14:55:39 +02:00
AlexandreS
77f948bfbf Improve search and replace in event sheet
- Fix a bug that hangs GDevelop when replacing with an empty search text
- Allow to replace with an empty string to mimic a "Delete search text" feature
2022-07-27 15:33:28 +02:00
D8H
c6abfc5433 Add type definitions on the Physics2 extension (#4147) 2022-07-27 09:47:32 +02:00
Florian Rival
2777e458ae Fix Add condition/action buttons overflowing outside of their column on small screens 2022-07-26 23:13:19 +02:00
Florian Rival
1d0695d722 Improve again rendering of the examples list on small screens
Don't show in changelog
2022-07-26 23:00:33 +02:00
Florian Rival
1820575f52 Fix display of the examples/starters on small screens (#4146) 2022-07-26 18:16:41 +02:00
Arthur Pacaud
f62236788d Add various improvements to the P2P extension (#4145)
- Updated PeerJS.
- Fixes for Safari.
- Improved typings.
- New default TURN server.
- Add a JavaScript API to get access to the raw connection.
  This allows to send custom messages from JavaScript. This allows to use a binary protocol from JavaScript.
- Use Map instead of JavaScript objects in places where it makes sense (more performant and less error prone).
- Avoid making a redundant get for every connection on the map containing the connections.

Only show in developer changelog
2022-07-26 14:25:08 +02:00
D8H
247e2f39e0 Add actions to change the tile map dimensions (#4141) 2022-07-26 09:20:27 +02:00
D8H
30898058a4 Fix layer names in drop-down lists were translated even though they are defined by users (#4130) 2022-07-25 18:53:30 +02:00
D8H
4e5d268f63 Handle tile maps with invalid resources (#4140)
* Fix an uncatched exceptions when a tile map resource is not set.
* Show place-holders for tile map with invalid resources in the instances editor.
* Give a better default name to tile map collision mask objects.
* Add a border around the tile map collision mask objects in the instance editor.
2022-07-25 17:33:08 +02:00
github-actions[bot]
fc4072b055 Update translations [skip ci] (#4132)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2022-07-25 11:18:38 +02:00
Clément Pasteau
9adec3ac72 Fix manual export URLs crashing the app on web (#4138) 2022-07-25 11:17:35 +02:00
D8H
95c2efbe07 Fix tilemaps object boxes to keep the empty tiles margins (#4133)
* It makes the same boxes as the tilemaps collision mask object to ease positioning.
* If the extra margin is not intended the right size can be set with Tiled.
2022-07-25 10:51:20 +02:00
Florian Rival
5a71b3a05f Add the unit (milliseconds) in the Tween behavior action parameters (#4137) 2022-07-24 22:23:35 +02:00
Florian Rival
fe87150cd4 Fix rendering of the home page on Safari (#4136) 2022-07-24 20:14:10 +02:00
Florian Rival
ddd3dc095a Fix wrong colors on the progress bar of the leaderboard creation dialog (#4135)
Don't show in changelog
2022-07-24 18:49:19 +02:00
Florian Rival
43bd02f99f Fix groups being redlined in the events sheet (#4134)
Do not show in changelog
2022-07-24 16:05:47 +02:00
github-actions[bot]
7ebf3c559b Update translations [skip ci] (#4122)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2022-07-22 14:04:30 +02:00
D8H
a5dca5fcb7 Fix: tilemaps were making the webapp crash due to a broken link. (#4131) 2022-07-22 14:03:19 +02:00
VegeTato
179a130d30 Update AboutDialog.js (#4127)
Added my twitter link beside my name :)
2022-07-22 11:00:50 +02:00
Peter Anderson
9953d33764 Issue #4119: Fix colours of expanded/collapsed arrows on event sheet. (#4129) 2022-07-22 10:58:58 +02:00
Clément Pasteau
5cb8603b56 Reduce max size of get started tiles (#4126)
Do not show in changelog
2022-07-22 10:10:04 +02:00
D8H
5278628480 Show typing errors of object parameters directly on the event sheet (#4121) 2022-07-21 09:23:40 +02:00
github-actions[bot]
99b615c573 Update translations [skip ci] (#4117)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2022-07-19 11:34:30 +02:00
Clément Pasteau
0ffc88a470 Small fixes (#4116)
Do not show in changelog
2022-07-18 18:25:27 +02:00
Clément Pasteau
b389b3cc90 Fix onboarding flow for web (#4115) 2022-07-18 16:22:50 +02:00
Clément Pasteau
41a70ec1e7 Bump IDE version to 139 (#4113) 2022-07-18 12:26:07 +02:00
D8H
1844d826f9 [PathFinding] Add a warn for too long searches (#4112)
* Don't show in changelogs
2022-07-18 12:25:54 +02:00
github-actions[bot]
e7e45e9c9b Update translations [skip ci] (#4102)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2022-07-18 12:14:34 +02:00
Clément Pasteau
7f7dc0e07f Final fixes release 139 (#4111)
* Fix MultiAutoComplete resetting after each input
* Always open a scene when opening a project
2022-07-18 12:13:43 +02:00
D8H
7af0153ceb [Platformer] Fix: platformer characters can now jump when moving against a wall that is part of the same object as the floor. (#4106)
* This bug could happen when using a tilemap collision mask object and not sustaining the jump.
2022-07-18 12:07:15 +02:00
D8H
9aaabbcc1d Fix the box of collision masks in the editor (#4105)
* Don't show in changelogs
2022-07-18 10:14:56 +02:00
Florian Rival
55cc75e990 Update wording of games not visible on Liluo on the games dashboard
Don't show in changelog
2022-07-13 18:47:19 +02:00
AlexandreS
d3d6c50790 Fix custom tooltip crashing when payload is undefined (#4101)
Don't show in changelog
2022-07-13 18:04:05 +02:00
github-actions[bot]
c7f2e4312c Update translations [skip ci] (#4058)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2022-07-13 15:49:36 +02:00
Peter Anderson
38cff7bbce Fix typos: replace 'Musics' with 'Music' (#4099) 2022-07-13 15:36:27 +02:00
AlexandreS
761de213ac Fix tabs and links colors
Do not show in changelog
2022-07-13 15:14:05 +02:00
D8H
f871b64011 [TileMap] Collision mask object (#3313)
* The collision mask is read from the tile maps exported by Tiled 1.9+.
* Several collision masks can be used for instance to have platforms and ladders.
* Take a look to the wiki for more details https://wiki.gdevelop.io/gdevelop5/objects/tilemap
2022-07-13 15:12:12 +02:00
AlexandreS
9441d3a2d2 Adapt themes' colors for better contrast across the app 2022-07-13 11:31:36 +02:00
Florian Rival
e86348727e Add a button, in the Profile, to manage online the subscription to GDevelop services (#4096)
This allows to easily update a payment method or switch to another plan/cancel (though this can already be done from the interface)
2022-07-13 10:59:41 +02:00
Peter Anderson
754845e5cd Fix grammar for the description of the Platform behavior (#4098) 2022-07-13 10:49:50 +02:00
Fannie Yan
1b86c23b92 Replace leaderboards when a user opens a game template (#4094)
* Replace leaderboards when a user opens a game template
2022-07-12 15:33:55 +02:00
AlexandreS
3c44602486 Fix Physics2 behaviors (#4074)
* Make it possible to activate and reactivate physics 2 behaviour
* Fix behaviour for objects modified or destroyed during events life cycle
* Make Physics2 Collision condition valid in any step of behaviour life cycles
2022-07-12 14:46:49 +02:00
D8H
b0f1e962a4 Automatically select and rename new behaviors or functions in the extension editor (#4092) 2022-07-11 16:27:22 +02:00
D8H
c48c86a51f Make radian or degree explicit in descriptions for angles (#4091) 2022-07-11 14:47:21 +02:00
Florian Rival
2b83ec9871 Revert color changes in themes (#4089)
* Primary color is the one that is displaying well, with good contrast, on the background.
* Secondary is the "accent" one that works well for raised button, selected buttons, etc...

Don't show in changelog
2022-07-11 10:36:15 +02:00
Florian Rival
c340f8ad06 Fix display of games showcase
Don't show in changelog
2022-07-08 17:53:41 +02:00
Clément Pasteau
07341f1e00 Improve the new Homepage Learn section by categorising tutorials
* Tutorials are now organised into Full Games, Game Mechanics, and official videos from Beginner to Advanced!
2022-07-08 16:06:57 +02:00
Sebastian Krzyszkowiak
7402d4f29f Add an option in the Resources editor to preload audio files in cache without decoding (#4010)
* This is helpful to load the audio files at the loading of the game (so even if the internet connection is lost, they will be available in the "browser cache") but without decoding them in memory (which could make too much work for low end devices, resulting in crashes)
2022-07-07 12:56:32 +02:00
AlexandreS
8599a1cfa7 Allow to display up to 50 leaderboard entries in Liluo/in-game 2022-07-06 15:39:59 +02:00
Clément Pasteau
98bfc7a4e0 Revamp GDevelop Homepage
* New "Get Started" section, to guide newcomers on where to start with GDevelop
* New "Build" section, the entry point for your projects
* New "Learn" section, the entry point to tutorials and future help tools
* New "Play" section, the entry point for all games created with GDevelop
* New "Community" section, the entry point to stay informed with the GDevelop world
2022-07-06 14:00:46 +02:00
D8H
cef352276d Add a duplicate action in the functions lists contextual menu. (#4085) 2022-07-06 12:33:52 +02:00
Fannie Yan
49ea27fd54 Slightly rework games dashboard (#4084)
Don't show in changelog
2022-07-06 12:12:24 +02:00
D8H
23b5b16bdf Select copied element on behaviors and functions lists (#4083) 2022-07-06 11:06:12 +02:00
Arthur Pacaud
2124133b4a Add an option to wait for a network request action to end before running other actions (#4023)
* In the future, there will be other actions where you can optionally wait for their tasks to be finished before running the rest of the actions. It makes logic easier and more straightforward to express in events.
* This is similar to the Wait action, except that it's optional.
2022-07-05 23:58:08 +02:00
Florian Rival
905344f396 Fix contrast of expressions in Rosé Pine theme 2022-07-05 15:08:43 +02:00
Florian Rival
84b78dfe0f Order extensions according to what is specified in the extensions repository (#4080)
Don't show in changelog
2022-07-03 22:47:18 +02:00
Ehan
1d8086b2f4 Add a new "Rosé Pine" theme (Code Editor & UI Theme) (#4079)
* Based on https://rosepinetheme.com/ and adapted by @EhanAhamed for GDevelop.
2022-07-03 18:20:19 +02:00
Florian Rival
22d5d46601 Add a toggle to display community extensions (#4078)
* Community extensions are extensions made by a community member, but which are not reviewed by the GDevelop extension team.
  They can be useful, but also need to be carefully reviewed if you use some (inspect them or reach out to their author in case of doubt).
* If you want to submit an extension, see the [GitHub repository of community extensions](https://github.com/gdevelopapp/gdevelop-extensions).
2022-07-02 13:36:37 +02:00
Fannie Yan
a5d56c37c9 Allow user to manage builds (#4075)
* In build tab:
  - Allow users to edit build names
  - Allow users to delete builds
* In feedback tab:
  - Display build name if a feedback is linked to one and allow users to filter feedbacks on builds
2022-07-01 10:44:29 +02:00
Florian Rival
5025ad9fb9 Avoid bad expression warnings in the console when using force actions without changing the force type (#4073) 2022-06-30 19:20:32 +02:00
D8H
daae78e802 Add version locks for rechart. (#4076)
Don't show in changelogs.
2022-06-30 16:28:02 +02:00
Florian Rival
9ee4b704da Clean more deprecated include files in extensions (#4072)
Don't show in changelog
2022-06-30 12:09:17 +02:00
D8H
a8991b7c9b Add game analytics charts (#4046)
The game dash board shows new charts to understand how well a game is doing on several aspects:
* the popularity (number of players)
* the player engagement (how long the game is played)

Note that players data are anonymized.
2022-06-30 12:06:03 +02:00
Florian Rival
cf061638b8 Avoid warnings in the console during preview/export by cleaning old C++ include files (#4070)
Only show in developer changelog
2022-06-28 19:26:25 +02:00
Arthur Pacaud
0686e02e27 Don't show objects already in a group in the selector to add a new object to this group (#4069) 2022-06-28 10:52:46 +02:00
Arthur Pacaud
e65b576e4b Adding actions to tween the value of a scene variable or a layer camera position (#4022)
* Like tweens added on objects, these tweens can be manipulated: paused, resumed or stopped.
2022-06-27 23:56:16 +02:00
Florian Rival
aacfed02a1 Allow the web-app to use relative resources if found when the project is opened from a public URL (#4066)
* For example, this can be useful to open a desktop project stored on a public space like GitHub (using the "raw" raw.githubusercontent.com/... urls given by GitHub)

Only show in developer changelog
2022-06-27 15:59:13 +02:00
Fannie Yan
6a25a9ad77 Allow user to open their games for feedbacks (#4045)
* Rework slighlty the game dashboard to allow users to make their game discoverable on Liluo.io, add a banner asking for feedback on their game pages on Liluo.io and add a banner asking for feedback on their build pages
* Add a tab Feedback when managing games, accessible through the games dashboard that allows users to see and process the feedbacks given to their game.
2022-06-27 15:23:43 +02:00
Clément Pasteau
e1140609d0 Add a button to start (or redo) the onboarding on the homepage
* Also add new languages FR, PT & ES
2022-06-27 15:18:15 +02:00
AlexandreS
81ef11163d Bump newIDE version 2022-06-21 16:41:38 +02:00
AlexandreS
fcc19a6dcf Fix collision bug introduced when fixing a collision bug 2022-06-21 16:41:18 +02:00
github-actions[bot]
bcad2d5667 Update translations [skip ci] (#4042)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2022-06-21 16:01:54 +02:00
D8H
3c83e5d24a No longer count pauses (when the tab is hidden) for the players session duration statistics (#4054) 2022-06-21 15:04:41 +02:00
853 changed files with 55564 additions and 17172 deletions

View File

@@ -68,7 +68,7 @@ jobs:
- run:
name: Clean dist folder to keep only installers/binaries.
command: rm -rf "newIDE/electron-app/dist/mac/GDevelop 5.app"
command: rm -rf "newIDE/electron-app/dist/mac/GDevelop 5.app" && rm -rf "newIDE/electron-app/dist/mac-arm64/GDevelop 5.app"
# Upload artifacts (CircleCI)
- store_artifacts:
@@ -143,11 +143,11 @@ jobs:
# 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 -- --linux AppImage zip deb --publish=never
command: export NODE_OPTIONS="--max-old-space-size=7168" && cd newIDE/electron-app && npm run build -- --linux --publish=never
- run:
name: Clean dist folder to keep only installers/binaries.
command: rm -rf newIDE/electron-app/dist/linux-unpacked
command: rm -rf newIDE/electron-app/dist/linux-unpacked && rm -rf newIDE/electron-app/dist/linux-arm64-unpacked
# Upload artifacts (CircleCI)
- store_artifacts:

View File

@@ -468,6 +468,14 @@ gd::String EventsCodeGenerator::GenerateActionCode(
action, *this, context);
}
// Get the correct function name depending on whether it should be async or
// not.
const gd::String& functionCallName =
instrInfos.IsAsync() &&
(!instrInfos.IsOptionallyAsync() || action.IsAwaited())
? instrInfos.codeExtraInformation.asyncFunctionCallName
: instrInfos.codeExtraInformation.functionCallName;
// Be sure there is no lack of parameter.
while (action.GetParameters().size() < instrInfos.parameters.size()) {
vector<gd::Expression> parameters = action.GetParameters();
@@ -522,6 +530,7 @@ gd::String EventsCodeGenerator::GenerateActionCode(
action.GetParameters(), instrInfos.parameters, context);
actionCode += GenerateObjectAction(realObjects[i],
objInfo,
functionCallName,
arguments,
instrInfos,
context,
@@ -556,6 +565,7 @@ gd::String EventsCodeGenerator::GenerateActionCode(
GenerateBehaviorAction(realObjects[i],
action.GetParameter(1).GetPlainString(),
autoInfo,
functionCallName,
arguments,
instrInfos,
context,
@@ -567,8 +577,11 @@ gd::String EventsCodeGenerator::GenerateActionCode(
} else {
vector<gd::String> arguments = GenerateParametersCodes(
action.GetParameters(), instrInfos.parameters, context);
actionCode +=
GenerateFreeAction(arguments, instrInfos, context, optionalAsyncCallbackName);
actionCode += GenerateFreeAction(functionCallName,
arguments,
instrInfos,
context,
optionalAsyncCallbackName);
}
return actionCode;
@@ -678,7 +691,8 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
} else if (ParameterMetadata::IsObject(metadata.type)) {
// It would be possible to run a gd::ExpressionCodeGenerator if later
// objects can have nested objects, or function returning objects.
argOutput = GenerateObject(parameter.GetPlainString(), metadata.type, context);
argOutput =
GenerateObject(parameter.GetPlainString(), metadata.type, context);
} else if (metadata.type == "relationalOperator") {
auto parameterString = parameter.GetPlainString();
argOutput += parameterString == "=" ? "==" : parameterString;
@@ -716,13 +730,15 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
} else if (metadata.type == "yesorno") {
auto parameterString = parameter.GetPlainString();
argOutput += (parameterString == "yes" || parameterString == "oui") ? GenerateTrue()
: GenerateFalse();
argOutput += (parameterString == "yes" || parameterString == "oui")
? GenerateTrue()
: GenerateFalse();
} else if (metadata.type == "trueorfalse") {
auto parameterString = parameter.GetPlainString();
// This is duplicated in AdvancedExtension.cpp for GDJS
argOutput += (parameterString == "True" || parameterString == "Vrai") ? GenerateTrue()
: GenerateFalse();
argOutput += (parameterString == "True" || parameterString == "Vrai")
? GenerateTrue()
: GenerateFalse();
}
// Code only parameter type
else if (metadata.type == "inlineCode") {
@@ -1082,6 +1098,7 @@ gd::String EventsCodeGenerator::GenerateBehaviorCondition(
}
gd::String EventsCodeGenerator::GenerateFreeAction(
const gd::String& functionCallName,
const std::vector<gd::String>& arguments,
const gd::InstructionMetadata& instrInfos,
gd::EventsCodeGenerationContext& context,
@@ -1095,21 +1112,21 @@ gd::String EventsCodeGenerator::GenerateFreeAction(
call = GenerateOperatorCall(
instrInfos,
arguments,
instrInfos.codeExtraInformation.functionCallName,
functionCallName,
instrInfos.codeExtraInformation.optionalAssociatedInstruction);
else if (instrInfos.codeExtraInformation.accessType ==
gd::InstructionMetadata::ExtraInformation::Mutators)
call =
GenerateMutatorCall(instrInfos,
arguments,
instrInfos.codeExtraInformation.functionCallName);
functionCallName);
else
call = GenerateCompoundOperatorCall(
instrInfos,
arguments,
instrInfos.codeExtraInformation.functionCallName);
functionCallName);
} else {
call = instrInfos.codeExtraInformation.functionCallName + "(" +
call = functionCallName + "(" +
GenerateArgumentsList(arguments) + ")";
}
@@ -1123,6 +1140,7 @@ gd::String EventsCodeGenerator::GenerateFreeAction(
gd::String EventsCodeGenerator::GenerateObjectAction(
const gd::String& objectName,
const gd::ObjectMetadata& objInfo,
const gd::String& functionCallName,
const std::vector<gd::String>& arguments,
const gd::InstructionMetadata& instrInfos,
gd::EventsCodeGenerationContext& context,
@@ -1136,27 +1154,25 @@ gd::String EventsCodeGenerator::GenerateObjectAction(
call = GenerateOperatorCall(
instrInfos,
arguments,
instrInfos.codeExtraInformation.functionCallName,
functionCallName,
instrInfos.codeExtraInformation.optionalAssociatedInstruction,
2);
else
call = GenerateCompoundOperatorCall(
instrInfos,
arguments,
instrInfos.codeExtraInformation.functionCallName,
2);
instrInfos, arguments, functionCallName, 2);
return "For each picked object \"" + objectName + "\", call " + call +
".\n";
} else {
gd::String argumentsStr = GenerateArgumentsList(arguments, 1);
call = instrInfos.codeExtraInformation.functionCallName + "(" +
argumentsStr + ")";
call = functionCallName + "(" + argumentsStr + ")";
return "For each picked object \"" + objectName + "\", call " + call + "(" +
argumentsStr + ")" +
(optionalAsyncCallbackName.empty() ? "" : (", then call" + optionalAsyncCallbackName)) +
(optionalAsyncCallbackName.empty()
? ""
: (", then call" + optionalAsyncCallbackName)) +
".\n";
}
}
@@ -1165,6 +1181,7 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
const gd::String& objectName,
const gd::String& behaviorName,
const gd::BehaviorMetadata& autoInfo,
const gd::String& functionCallName,
const std::vector<gd::String>& arguments,
const gd::InstructionMetadata& instrInfos,
gd::EventsCodeGenerationContext& context,
@@ -1178,26 +1195,28 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
call = GenerateOperatorCall(
instrInfos,
arguments,
instrInfos.codeExtraInformation.functionCallName,
functionCallName,
instrInfos.codeExtraInformation.optionalAssociatedInstruction,
2);
else
call = GenerateCompoundOperatorCall(
instrInfos,
arguments,
instrInfos.codeExtraInformation.functionCallName,
functionCallName,
2);
return "For each picked object \"" + objectName + "\", call " + call +
" for behavior \"" + behaviorName + "\".\n";
} else {
gd::String argumentsStr = GenerateArgumentsList(arguments, 2);
call = instrInfos.codeExtraInformation.functionCallName + "(" +
call = functionCallName + "(" +
argumentsStr + ")";
return "For each picked object \"" + objectName + "\", call " + call + "(" +
argumentsStr + ")" + " for behavior \"" + behaviorName + "\"" +
(optionalAsyncCallbackName.empty() ? "" : (", then call" + optionalAsyncCallbackName)) +
(optionalAsyncCallbackName.empty()
? ""
: (", then call" + optionalAsyncCallbackName)) +
".\n";
}
}

View File

@@ -154,9 +154,10 @@ class GD_CORE_API EventsCodeGenerator {
* \param context Context used for generation
* \return Code
*/
gd::String GenerateActionCode(gd::Instruction& action,
EventsCodeGenerationContext& context,
const gd::String& optionalAsyncCallbackName = "");
gd::String GenerateActionCode(
gd::Instruction& action,
EventsCodeGenerationContext& context,
const gd::String& optionalAsyncCallbackName = "");
struct CallbackDescriptor {
CallbackDescriptor(const gd::String functionName_,
@@ -174,7 +175,8 @@ class GD_CORE_API EventsCodeGenerator {
*/
const gd::String argumentsList;
/**
* A set of all objects that need to be backed up to be passed to the callback code.
* A set of all objects that need to be backed up to be passed to the
* callback code.
*/
const std::set<gd::String> requiredObjects;
};
@@ -507,10 +509,10 @@ class GD_CORE_API EventsCodeGenerator {
* - currentScene: Reference to the current runtime scene.
* - objectList : a map containing lists of objects which are specified by the
object name in another parameter.
* - objectListOrEmptyIfJustDeclared : Same as `objectList` but do not pick object if
they are not already picked.
* - objectPtr: Return a reference to the object specified by the object name in
another parameter. Example:
* - objectListOrEmptyIfJustDeclared : Same as `objectList` but do not pick
object if they are not already picked.
* - objectPtr: Return a reference to the object specified by the object name
in another parameter. Example:
* \code
.AddParameter("object", _("Object"))
.AddParameter("objectPtr", _("Target object"))
@@ -700,6 +702,7 @@ class GD_CORE_API EventsCodeGenerator {
gd::EventsCodeGenerationContext& context);
virtual gd::String GenerateFreeAction(
const gd::String& functionCallName,
const std::vector<gd::String>& arguments,
const gd::InstructionMetadata& instrInfos,
gd::EventsCodeGenerationContext& context,
@@ -708,6 +711,7 @@ class GD_CORE_API EventsCodeGenerator {
virtual gd::String GenerateObjectAction(
const gd::String& objectName,
const gd::ObjectMetadata& objInfo,
const gd::String& functionCallName,
const std::vector<gd::String>& arguments,
const gd::InstructionMetadata& instrInfos,
gd::EventsCodeGenerationContext& context,
@@ -717,6 +721,7 @@ class GD_CORE_API EventsCodeGenerator {
const gd::String& objectName,
const gd::String& behaviorName,
const gd::BehaviorMetadata& autoInfo,
const gd::String& functionCallName,
const std::vector<gd::String>& arguments,
const gd::InstructionMetadata& instrInfos,
gd::EventsCodeGenerationContext& context,
@@ -775,8 +780,8 @@ class GD_CORE_API EventsCodeGenerator {
bool hasProjectAndLayout; ///< true only if project and layout are valid
///< references. If false, they should not be used.
const gd::Project* project; ///< The project being used.
const gd::Layout* scene; ///< The scene being generated.
const gd::Project* project; ///< The project being used.
const gd::Layout* scene; ///< The scene being generated.
bool errorOccurred; ///< Must be set to true if an error occured.
bool compilationForRuntime; ///< Is set to true if the code generation is

View File

@@ -75,7 +75,8 @@ void BaseEvent::PreprocessAsyncActions(const gd::Platform& platform) {
const auto& action = actionsList->at(aId);
const gd::InstructionMetadata& actionMetadata =
gd::MetadataProvider::GetActionMetadata(platform, action.GetType());
if (actionMetadata.IsAsync()) {
if (actionMetadata.IsAsync() &&
(!actionMetadata.IsOptionallyAsync() || action.IsAwaited())) {
gd::InstructionsList remainingActions;
remainingActions.InsertInstructions(
*actionsList, aId + 1, actionsList->size() - 1);

View File

@@ -72,6 +72,22 @@ class GD_CORE_API Instruction {
*/
void SetInverted(bool inverted_) { inverted = inverted_; }
/**
* \brief Return true if the async instruction should be awaited.
* This is not relevant if the instruction is not optionally asynchronous.
*
* \return true if the instruction is to be awaited
*/
bool IsAwaited() const { return awaitAsync; }
/**
* \brief Set if the async instruction is to be awaited or not.
* This is not relevant if the instruction is not optionally asynchronous.
*
* \param inverted true if the instruction must be awaited
*/
void SetAwaited(bool awaited) { awaitAsync = awaited; }
/**
* \brief Return the number of parameters of the instruction.
*/
@@ -139,7 +155,9 @@ class GD_CORE_API Instruction {
* Useful to get reference to the original instruction in memory during code
* generation, to ensure stable unique identifiers.
*/
std::weak_ptr<Instruction> GetOriginalInstruction() { return originalInstruction; };
std::weak_ptr<Instruction> GetOriginalInstruction() {
return originalInstruction;
};
friend std::shared_ptr<Instruction> CloneRememberingOriginalElement(
std::shared_ptr<Instruction> instruction);
@@ -148,6 +166,9 @@ class GD_CORE_API Instruction {
gd::String type; ///< Instruction type
bool inverted; ///< True if the instruction if inverted. Only applicable for
///< instruction used as conditions by events
bool awaitAsync =
false; ///< Tells the code generator whether the optionally asynchronous
///< instruction should be generated as asynchronous (awaited) or not.
mutable std::vector<gd::Expression>
parameters; ///< Vector containing the parameters
gd::InstructionsList subInstructions; ///< Sub instructions, if applicable.

View File

@@ -269,6 +269,9 @@ void gd::EventsListSerialization::UnserializeInstructionsFrom(
instrElement.GetChild("type", 0, "Type")
.GetBoolAttribute("inverted", false, "Contraire"));
instruction.SetAwaited(
instrElement.GetChild("type", 0, "Type").GetBoolAttribute("await"));
// Read parameters
vector<gd::Expression> parameters;
@@ -346,6 +349,8 @@ void gd::EventsListSerialization::SerializeInstructionsTo(
if (list[k].IsInverted())
instruction.GetChild("type").SetAttribute("inverted", true);
if (list[k].IsAwaited())
instruction.GetChild("type").SetAttribute("await", true);
// Parameters
SerializerElement& parameters = instruction.AddChild("parameters");

View File

@@ -14,14 +14,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
extension
.SetExtensionInformation(
"BuiltinAudio",
_("Sounds and musics"),
_("Sounds and music"),
_("GDevelop provides several conditions and actions to play audio "
"files. They can be either long musics or short sound effects."),
"files. They can be either long music or short sound effects."),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/all-features/audio")
.SetCategory("Audio");
extension.AddInstructionOrExpressionGroupMetadata(_("Sounds and musics"))
extension.AddInstructionOrExpressionGroupMetadata(_("Sounds and music"))
.SetIcon("res/actions/music24.png");
extension
@@ -73,9 +73,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
extension
.AddAction("RePlaySoundCanal",
_("Play the sound of a channel"),
_("Play the sound of the channel."),
_("Play the sound of channel _PARAM1_"),
_("Resume playing a sound on a channel"),
_("Resume playing a sound on a channel that was paused."),
_("Resume the sound of channel _PARAM1_"),
_("Sounds on channels"),
"res/actions/son24.png",
"res/actions/son.png")
@@ -132,9 +132,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
extension
.AddAction("RePlayMusicCanal",
_("Play the music of a channel"),
_("Play the music of the channel."),
_("Play the music of channel _PARAM1_"),
_("Resume playing a music on a channel"),
_("Resume playing a music on a channel that was paused."),
_("Resume the music of channel _PARAM1_"),
_("Music on channels"),
"res/actions/music24.png",
"res/actions/music.png")

View File

@@ -28,7 +28,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
extension.AddInstructionOrExpressionGroupMetadata(_("Movement using forces"))
.SetIcon("res/actions/force24.png");
gd::ObjectMetadata& obj = extension.AddObject<gd::Object>(
gd::ObjectMetadata& obj = extension.AddObject<gd::ObjectConfiguration>(
"", _("Base object"), _("Base object"), "res/objeticon24.png");
obj.AddCondition("PosX",
@@ -219,7 +219,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction("SetAngle",
_("Angle"),
_("Change the angle of rotation of an object."),
_("Change the angle of rotation of an object (in degrees)."),
_("the angle"),
_("Angle"),
"res/actions/direction24.png",
@@ -289,7 +289,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Speed on X axis (in pixels per second)"))
.AddParameter("expression", _("Speed on Y axis (in pixels per second)"))
.AddParameter("forceMultiplier", _("Force multiplier"));
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
.SetDefaultValue("0");
obj.AddAction("AddForceAL",
_("Add a force (angle)"),
@@ -305,7 +306,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angle"))
.AddParameter("expression", _("Speed (in pixels per second)"))
.AddParameter("forceMultiplier", _("Force multiplier"))
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
.SetDefaultValue("0")
.MarkAsAdvanced();
obj.AddAction(
@@ -323,7 +325,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression", _("X position"))
.AddParameter("expression", _("Y position"))
.AddParameter("expression", _("Speed (in pixels per second)"))
.AddParameter("forceMultiplier", _("Force multiplier"))
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
.SetDefaultValue("0")
.MarkAsAdvanced();
obj.AddAction(
@@ -390,7 +393,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/layer.png")
.AddParameter("object", _("Object"))
.AddParameter("layer", _("Move it to this layer (base layer if empty)"))
.AddParameter("layer", _("Move it to this layer"))
.SetDefaultValue("\"\"")
.MarkAsAdvanced();
@@ -756,7 +759,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectPtr", _("Target Object"))
.AddParameter("expression", _("Speed (in pixels per second)"))
.AddParameter("forceMultiplier", _("Force multiplier"))
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
.SetDefaultValue("0")
.MarkAsAdvanced();
obj.AddAction(
@@ -776,7 +780,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectPtr", _("Rotate around this object"))
.AddParameter("expression", _("Speed (in degrees per second)"))
.AddParameter("expression", _("Distance (in pixels)"))
.AddParameter("forceMultiplier", _("Force multiplier"))
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
.SetDefaultValue("0")
.MarkAsAdvanced();
obj.AddAction("MettreAutour",
@@ -993,7 +998,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddExpression("ForceAngle",
_("Angle of the sum of forces"),
_("Angle of the sum of forces"),
_("Angle of the sum of forces (in degrees)"),
_("Movement using forces"),
"res/actions/force.png")
.AddParameter("object", _("Object"));
@@ -1093,7 +1098,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression", _("Target Y position"));
obj.AddExpression("Variable",
_("Object variable"),
_("Value of an object variable"),
_("Value of an object variable"),
_("Variables"),
"res/actions/var.png")
@@ -1109,7 +1114,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectvar", _("Variable"));
obj.AddStrExpression("VariableString",
_("Object variable"),
_("Text of an object variable"),
_("Text of an object variable"),
_("Variables"),
"res/actions/var.png")
@@ -1126,8 +1131,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddExpression("AngleToObject",
_("Angle between two objects"),
_("Compute the angle between two objects. If you need the "
"angle to an arbitrary position, use AngleToPosition."),
_("Compute the angle between two objects (in degrees). "
"If you need the angle to an arbitrary position, "
"use AngleToPosition."),
_("Angle"),
"res/actions/position.png")
.AddParameter("object", _("Object"))
@@ -1160,8 +1166,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddExpression("AngleToPosition",
_("Angle between an object and a position"),
_("Compute the angle between the object center and a "
"\"target\" position. If you need the angle between two "
"objects, use AngleToObject."),
"\"target\" position (in degrees). If you need the angle "
"between two objects, use AngleToObject."),
_("Angle"),
"res/actions/position.png")
.AddParameter("object", _("Object"))
@@ -1523,7 +1529,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"object will become the only one taken into account.\nIf "
"the condition is inverted, the object to be intersected "
"will be the farthest one within the ray radius."),
_("Cast a ray from from _PARAM1_;_PARAM2_ to _PARAM3_;_PARAM4_ "
_("Cast a ray from _PARAM1_;_PARAM2_ to _PARAM3_;_PARAM4_ "
"against _PARAM0_, and save the "
"result in _PARAM5_, _PARAM6_"),
"",

View File

@@ -195,7 +195,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"number",
"CameraAngle",
_("Angle of a camera of a layer"),
_("the angle of rotation of a camera"),
_("the angle of rotation of a camera (in degrees)"),
_("the angle of camera (layer: _PARAM3_, camera: _PARAM4_)"),
"",
"res/conditions/camera24.png")
@@ -221,7 +221,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"res/actions/camera24.png",
"res/actions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"))
.AddParameter("layer", _("Layer"))
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Width"), "", true)
.AddParameter("expression", _("Height"), "", true)
@@ -256,7 +256,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"res/actions/camera24.png",
"res/actions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"))
.AddParameter("layer", _("Layer"))
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number"))
.MarkAsComplex();
@@ -272,7 +272,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"res/actions/camera24.png",
"res/actions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"))
.AddParameter("layer", _("Layer"))
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number"))
.AddParameter("expression", _("Width"))
@@ -290,7 +290,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"res/actions/camera24.png",
"res/actions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"))
.AddParameter("layer", _("Layer"))
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number"))
.AddParameter(
@@ -309,7 +309,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
extension
.AddAction("ZoomCamera",
_("Change camera zoom"),
_("Camera zoom"),
_("Change camera zoom."),
_("Change camera zoom to _PARAM1_ (layer: _PARAM2_, camera: "
"_PARAM3_)"),
@@ -413,7 +413,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"res/actions/layer24.png",
"res/actions/layer.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"))
.AddParameter("layer", _("Layer"))
.SetDefaultValue("\"\"")
.MarkAsAdvanced();
@@ -426,7 +426,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"res/actions/layer24.png",
"res/actions/layer.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"))
.AddParameter("layer", _("Layer"))
.SetDefaultValue("\"\"")
.MarkAsAdvanced();
@@ -439,7 +439,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"res/conditions/layer24.png",
"res/conditions/layer.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"))
.AddParameter("layer", _("Layer"))
.SetDefaultValue("\"\"")
.MarkAsAdvanced();
@@ -576,7 +576,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
extension
.AddAction("SetLayerDefaultZOrder",
_("Change layer default Z order"),
_("Layer default Z order"),
_("Change the default Z order set to objects when they are "
"created on a layer."),
_("Set the default Z order of objects created on _PARAM1_ to "

View File

@@ -96,13 +96,13 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
_("Difference between two angles"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("First angle"))
.AddParameter("expression", _("Second angle"));
.AddParameter("expression", _("First angle, in degrees"))
.AddParameter("expression", _("Second angle, in degrees"));
extension
.AddExpression("AngleBetweenPositions",
_("Angle between two positions"),
_("Compute the angle between two positions."),
_("Compute the angle between two positions (in degrees)."),
"",
"res/mathfunction.png")
.AddParameter("expression", _("First point X position"))
@@ -159,7 +159,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("acos",
_("Arccosine"),
_("Arccosine"),
_("Arccosine, return an angle (in radian). "
"`ToDeg` allows to convert it to degrees."),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
@@ -175,7 +176,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("asin",
_("Arcsine"),
_("Arcsine"),
_("Arcsine, return an angle (in radian). "
"`ToDeg` allows to convert it to degrees."),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
@@ -191,7 +193,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("atan",
_("Arctangent"),
_("Arctangent"),
_("Arctangent, return an angle (in radian). "
"`ToDeg` allows to convert it to degrees."),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
@@ -258,7 +261,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("cos",
_("Cosine"),
_("Cosine of a number"),
_("Cosine of an angle (in radian). "
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
@@ -400,7 +404,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("sin",
_("Sine"),
_("Sine of a number"),
_("Sine of an angle (in radian). "
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
@@ -424,7 +429,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("tan",
_("Tangent"),
_("Tangent of a number"),
_("Tangent of an angle (in radian). "
"If you want to use degrees, use`ToRad`: `tan(ToRad(45))`."),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));

View File

@@ -112,7 +112,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
extension
.AddAction("SceneBackground",
_("Change background color"),
_("Background color"),
_("Change the background color of the scene."),
_("Set background color to _PARAM1_"),
"",

View File

@@ -33,7 +33,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.SetCategoryFullName(_("General"));
obj.AddAction("Opacity",
_("Change sprite opacity"),
_("Sprite opacity"),
_("Change the opacity of a Sprite. 0 is fully transparent, 255 "
"is opaque (default)."),
_("the opacity"),

View File

@@ -25,8 +25,7 @@ namespace gd {
Animation SpriteObject::badAnimation;
SpriteObject::SpriteObject(gd::String name_)
: Object(name_), updateIfNotVisible(false) {}
SpriteObject::SpriteObject() : updateIfNotVisible(false) {}
SpriteObject::~SpriteObject(){};

View File

@@ -36,11 +36,11 @@ namespace gd {
* \see gd::BuiltinExtensionsImplementer::ImplementsSpriteExtension
* \ingroup SpriteObjectExtension
*/
class GD_CORE_API SpriteObject : public gd::Object {
class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
public:
SpriteObject(gd::String name_);
SpriteObject();
virtual ~SpriteObject();
std::unique_ptr<gd::Object> Clone() const override {
std::unique_ptr<gd::ObjectConfiguration> Clone() const override {
return gd::make_unique<SpriteObject>(*this);
}

View File

@@ -21,9 +21,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/all-features/timers-and-time");
extension.AddInstructionOrExpressionGroupMetadata(
_("Timers and time")
)
extension.AddInstructionOrExpressionGroupMetadata(_("Timers and time"))
.SetIcon("res/conditions/timer24.png");
// Deprecated and replaced by CompareTimer
@@ -138,7 +136,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
extension
.AddAction("ChangeTimeScale",
_("Change time scale"),
_("Time scale"),
_("Change the time scale of the scene."),
_("Set the time scale of the scene to _PARAM1_"),
"",
@@ -158,8 +156,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
"res/timer.svg",
"res/timer.svg")
.AddParameter("expression", "Time to wait in seconds")
.SetHelpPath("/all-features/timers-and-time/wait-action")
.SetAsync();
.SetHelpPath("/all-features/timers-and-time/wait-action");
extension
.AddExpression("TimeDelta",

View File

@@ -55,7 +55,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
extension
.AddAction("SetWindowMargins",
_("Change the window's margins"),
_("Window's margins"),
_("This action changes the margins, in pixels, between the "
"game frame and the window borders."),
_("Set margins of game window to "
@@ -71,7 +71,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
extension
.AddAction("SetGameResolutionSize",
_("Change the resolution of the game"),
_("Game resolution"),
_("Changes the resolution of the game, effectively changing "
"the game area size. This won't change the size of the "
"window in which the game is running."),
@@ -117,7 +117,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
extension
.AddAction("SetGameResolutionResizeMode",
_("Change the game resolution resize mode"),
_("Game resolution resize mode"),
_("Set if the width or the height of the game resolution "
"should be changed to fit the game window - or if the game "
"resolution should not be updated automatically."),
@@ -153,7 +153,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
extension
.AddAction("SetWindowIcon",
_("Change the window's icon"),
_("Window's icon"),
_("This action changes the icon of the game's window."),
_("Use _PARAM1_ as the icon for the game's window."),
"",
@@ -164,7 +164,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
extension
.AddAction("SetWindowTitle",
_("Change the window's title"),
_("Window's title"),
_("This action changes the title of the game's window."),
_("Change window title to _PARAM1_"),
"",

View File

@@ -14,6 +14,8 @@
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/BehaviorsSharedData.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/MakeUnique.h"
#include "GDCore/Tools/Log.h"
namespace gd {
@@ -29,21 +31,50 @@ BehaviorMetadata::BehaviorMetadata(
std::shared_ptr<gd::Behavior> instance_,
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance_)
: extensionNamespace(extensionNamespace_),
className(className_),
iconFilename(icon24x24),
instance(instance_),
sharedDatasInstance(sharedDatasInstance_) {
#if defined(GD_IDE_ONLY)
sharedDatasInstance(sharedDatasInstance_),
isEventBased(false) {
SetFullName(gd::String(fullname_));
SetDescription(gd::String(description_));
SetDefaultName(gd::String(defaultName_));
SetGroup(group_);
className = className_;
iconFilename = icon24x24;
#endif
if (!instance) {
gd::LogFatalError(
"Trying to create a BehaviorMetadata that has no "
"behavior. This will crash - please double check that the "
"BehaviorMetadata is valid for: " + name_);
}
if (instance) instance->SetTypeName(name_);
if (sharedDatasInstance) sharedDatasInstance->SetTypeName(name_);
}
BehaviorMetadata::BehaviorMetadata(
const gd::String& extensionNamespace,
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& group_,
const gd::String& icon24x24_): BehaviorMetadata(
extensionNamespace,
name_,
fullname_,
// Default name is the name
name_,
description_,
group_,
icon24x24_,
// Class name is the name, actually unused
name_,
// It is only used to get the name for GetName.
gd::make_unique<gd::Behavior>("", name_),
nullptr){
isEventBased = true;
};
gd::InstructionMetadata& BehaviorMetadata::AddCondition(
const gd::String& name,
const gd::String& fullname,
@@ -52,7 +83,6 @@ gd::InstructionMetadata& BehaviorMetadata::AddCondition(
const gd::String& group,
const gd::String& icon,
const gd::String& smallicon) {
#if defined(GD_IDE_ONLY)
gd::String nameWithNamespace =
extensionNamespace.empty() ? name : extensionNamespace + name;
conditionsInfos[nameWithNamespace] = InstructionMetadata(extensionNamespace,
@@ -66,7 +96,6 @@ gd::InstructionMetadata& BehaviorMetadata::AddCondition(
.SetHelpPath(GetHelpPath())
.SetIsBehaviorInstruction();
return conditionsInfos[nameWithNamespace];
#endif
}
gd::InstructionMetadata& BehaviorMetadata::AddAction(
@@ -77,7 +106,6 @@ gd::InstructionMetadata& BehaviorMetadata::AddAction(
const gd::String& group,
const gd::String& icon,
const gd::String& smallicon) {
#if defined(GD_IDE_ONLY)
gd::String nameWithNamespace =
extensionNamespace.empty() ? name : extensionNamespace + name;
actionsInfos[nameWithNamespace] = InstructionMetadata(extensionNamespace,
@@ -91,7 +119,6 @@ gd::InstructionMetadata& BehaviorMetadata::AddAction(
.SetHelpPath(GetHelpPath())
.SetIsBehaviorInstruction();
return actionsInfos[nameWithNamespace];
#endif
}
gd::InstructionMetadata& BehaviorMetadata::AddScopedCondition(
@@ -102,7 +129,6 @@ gd::InstructionMetadata& BehaviorMetadata::AddScopedCondition(
const gd::String& group,
const gd::String& icon,
const gd::String& smallicon) {
#if defined(GD_IDE_ONLY)
gd::String nameWithNamespace =
GetName() + gd::PlatformExtension::GetNamespaceSeparator() + name;
conditionsInfos[nameWithNamespace] = InstructionMetadata(extensionNamespace,
@@ -116,7 +142,6 @@ gd::InstructionMetadata& BehaviorMetadata::AddScopedCondition(
.SetHelpPath(GetHelpPath())
.SetIsBehaviorInstruction();
return conditionsInfos[nameWithNamespace];
#endif
}
gd::InstructionMetadata& BehaviorMetadata::AddScopedAction(
@@ -127,7 +152,6 @@ gd::InstructionMetadata& BehaviorMetadata::AddScopedAction(
const gd::String& group,
const gd::String& icon,
const gd::String& smallicon) {
#if defined(GD_IDE_ONLY)
gd::String nameWithNamespace =
GetName() + gd::PlatformExtension::GetNamespaceSeparator() + name;
actionsInfos[nameWithNamespace] = InstructionMetadata(extensionNamespace,
@@ -141,7 +165,6 @@ gd::InstructionMetadata& BehaviorMetadata::AddScopedAction(
.SetHelpPath(GetHelpPath())
.SetIsBehaviorInstruction();
return actionsInfos[nameWithNamespace];
#endif
}
gd::ExpressionMetadata& BehaviorMetadata::AddExpression(
@@ -150,7 +173,6 @@ gd::ExpressionMetadata& BehaviorMetadata::AddExpression(
const gd::String& description,
const gd::String& group,
const gd::String& smallicon) {
#if defined(GD_IDE_ONLY)
// Be careful, behaviors expression do not have namespace (not necessary as
// we refer to the behavior name in the expression).
expressionsInfos[name] = ExpressionMetadata("number",
@@ -162,7 +184,6 @@ gd::ExpressionMetadata& BehaviorMetadata::AddExpression(
smallicon)
.SetHelpPath(GetHelpPath());
return expressionsInfos[name];
#endif
}
gd::ExpressionMetadata& BehaviorMetadata::AddStrExpression(
@@ -171,7 +192,6 @@ gd::ExpressionMetadata& BehaviorMetadata::AddStrExpression(
const gd::String& description,
const gd::String& group,
const gd::String& smallicon) {
#if defined(GD_IDE_ONLY)
// Be careful, behaviors expression do not have namespace (not necessary as
// we refer to the behavior name in the expression).
strExpressionsInfos[name] = ExpressionMetadata("string",
@@ -183,7 +203,6 @@ gd::ExpressionMetadata& BehaviorMetadata::AddStrExpression(
smallicon)
.SetHelpPath(GetHelpPath());
return strExpressionsInfos[name];
#endif
}
gd::MultipleInstructionMetadata BehaviorMetadata::AddExpressionAndCondition(
@@ -288,7 +307,6 @@ 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;
@@ -356,49 +374,44 @@ gd::ExpressionMetadata& BehaviorMetadata::AddDuplicatedStrExpression(
return strExpressionsInfos[newNameWithNamespace];
}
#endif
BehaviorMetadata& BehaviorMetadata::SetFullName(const gd::String& fullname_) {
#if defined(GD_IDE_ONLY)
fullname = fullname_;
#endif
return *this;
}
BehaviorMetadata& BehaviorMetadata::SetDefaultName(
const gd::String& defaultName_) {
#if defined(GD_IDE_ONLY)
defaultName = defaultName_;
#endif
return *this;
}
BehaviorMetadata& BehaviorMetadata::SetDescription(
const gd::String& description_) {
#if defined(GD_IDE_ONLY)
description = description_;
#endif
return *this;
}
BehaviorMetadata& BehaviorMetadata::SetGroup(const gd::String& group_) {
#if defined(GD_IDE_ONLY)
group = group_;
#endif
return *this;
}
BehaviorMetadata& BehaviorMetadata::SetIncludeFile(
const gd::String& includeFile) {
#if defined(GD_IDE_ONLY)
includeFiles.clear();
includeFiles.push_back(includeFile);
#endif
return *this;
}
BehaviorMetadata& BehaviorMetadata::AddIncludeFile(
const gd::String& includeFile) {
#if defined(GD_IDE_ONLY)
if (std::find(includeFiles.begin(), includeFiles.end(), includeFile) ==
includeFiles.end())
includeFiles.push_back(includeFile);
#endif
return *this;
}
BehaviorMetadata& BehaviorMetadata::AddRequiredFile(
const gd::String& requiredFile) {
if (std::find(requiredFiles.begin(), requiredFiles.end(), requiredFile) ==
requiredFiles.end())
requiredFiles.push_back(requiredFile);
return *this;
}
@@ -407,13 +420,25 @@ const gd::String& BehaviorMetadata::GetName() const {
}
gd::Behavior& BehaviorMetadata::Get() const {
if (!instance)
if (isEventBased) {
gd::LogFatalError("Error: Event-based behaviors don't have blueprint. "
"This method should not never be called.");
}
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.");
"BehaviorMetadata is valid for: " + className);
}
return *instance;
}
gd::BehaviorsSharedData* BehaviorMetadata::GetSharedDataInstance() const {
if (isEventBased) {
gd::LogFatalError("Error: Event-based behaviors don't have blueprint. "
"This method should not never be called.");
}
return sharedDatasInstance.get();
}
} // namespace gd

View File

@@ -38,6 +38,20 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& className_,
std::shared_ptr<gd::Behavior> instance,
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance);
/**
* \brief Construct a behavior metadata, without "blueprint" behavior.
*
* \note This is used by events based behaviors.
*/
BehaviorMetadata(
const gd::String& extensionNamespace,
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& group_,
const gd::String& icon24x24_);
BehaviorMetadata(){};
virtual ~BehaviorMetadata(){};
@@ -195,6 +209,13 @@ class GD_CORE_API BehaviorMetadata {
*/
BehaviorMetadata& AddIncludeFile(const gd::String& includeFile);
/**
* \brief Add a file to the already existing required files.
* \note These files are required for the behavior to work,
* but they are not executable.
*/
BehaviorMetadata& AddRequiredFile(const gd::String& requiredFile);
/**
* Get the help path of the behavior, relative to the GDevelop documentation
* root.
@@ -239,16 +260,20 @@ class GD_CORE_API BehaviorMetadata {
/**
* \brief Return the associated gd::Behavior, handling behavior contents.
*
* \note Returns a dumb Behavior for events based behaviors as CustomBehavior
* are using EventBasedBehavior.
*/
gd::Behavior& Get() const;
/**
* \brief Return the associated gd::BehaviorsSharedData, handling behavior
* shared data, if any (nullptr if none).
*
* \note Returns nullptr for events based behaviors as they don't declare
* shared data yet.
*/
gd::BehaviorsSharedData* GetSharedDataInstance() const {
return sharedDatasInstance.get();
}
gd::BehaviorsSharedData* GetSharedDataInstance() const;
/**
* \brief Return a reference to a map containing the names of the actions
@@ -271,30 +296,29 @@ class GD_CORE_API BehaviorMetadata {
*/
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressions() { return strExpressionsInfos; };
#if defined(GD_IDE_ONLY)
std::map<gd::String, gd::InstructionMetadata> conditionsInfos;
std::map<gd::String, gd::InstructionMetadata> actionsInfos;
std::map<gd::String, gd::ExpressionMetadata> expressionsInfos;
std::map<gd::String, gd::ExpressionMetadata> strExpressionsInfos;
std::vector<gd::String> includeFiles;
std::vector<gd::String> requiredFiles;
gd::String className;
#endif
private:
gd::String extensionNamespace;
gd::String helpPath;
#if defined(GD_IDE_ONLY)
gd::String fullname;
gd::String defaultName;
gd::String description;
gd::String group;
gd::String iconFilename;
gd::String objectType;
#endif
// TODO: Nitpicking: convert these to std::unique_ptr to clarify ownership.
std::shared_ptr<gd::Behavior> instance;
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance;
bool isEventBased;
};
} // namespace gd

View File

@@ -22,7 +22,6 @@ InstructionMetadata::InstructionMetadata()
canHaveSubInstructions(false),
hidden(true),
usageComplexity(5),
isAsync(false),
isPrivate(false),
isObjectInstruction(false),
isBehaviorInstruction(false) {}
@@ -46,7 +45,6 @@ InstructionMetadata::InstructionMetadata(const gd::String& extensionNamespace_,
extensionNamespace(extensionNamespace_),
hidden(false),
usageComplexity(5),
isAsync(false),
isPrivate(false),
isObjectInstruction(false),
isBehaviorInstruction(false) {}

View File

@@ -6,10 +6,10 @@
#ifndef INSTRUCTIONMETADATA_H
#define INSTRUCTIONMETADATA_H
#include <algorithm>
#include <functional>
#include <map>
#include <memory>
#include <algorithm>
#include "GDCore/Events/Instruction.h"
#include "GDCore/String.h"
@@ -104,16 +104,16 @@ class GD_CORE_API InstructionMetadata {
* background, executing the instructions following it before the frame after
* it resolved.
*/
bool IsAsync() const { return isAsync; }
bool IsAsync() const {
return !codeExtraInformation.asyncFunctionCallName.empty();
}
/**
* Set that the instruction is asynchronous - it will be running in the
* background, executing the instructions following it before the frame after
* it resolved.
* Check if the instruction asynchronicity is optional. If it is, it can either
* be used synchronously or asynchronously, with one function for each.
*/
InstructionMetadata &SetAsync() {
isAsync = true;
return *this;
bool IsOptionallyAsync() const {
return IsAsync() && !codeExtraInformation.functionCallName.empty();
}
/**
@@ -319,14 +319,26 @@ class GD_CORE_API InstructionMetadata {
virtual ~ExtraInformation(){};
/**
* Set the function name which will be used when generating the code.
* \param functionName the name of the function to call
* Set the name of the function which will be called in the generated code.
* \param functionName the name of the function to call.
*/
ExtraInformation &SetFunctionName(const gd::String &functionName_) {
functionCallName = functionName_;
return *this;
}
/**
* Set the name of the function, doing asynchronous work, which will be called in
* the generated code. This function should return an asynchronous task
* (i.e: `gdjs.AsyncTask` in the JavaScript runtime).
*
* \param functionName the name of the function doing asynchronous work to call.
*/
ExtraInformation &SetAsyncFunctionName(const gd::String &functionName_) {
asyncFunctionCallName = functionName_;
return *this;
}
/**
* Declare if the instruction being declared is somewhat manipulating in a
* standard way.
@@ -354,7 +366,7 @@ class GD_CORE_API InstructionMetadata {
* .AddParameter("object", _("Object"), "Text", false)
* .AddParameter("operator", _("Modification operator"), "string")
* .AddParameter("string", _("String"))
* .SetFunctionName("SetString").SetManipulatedType("string").SetGetter("GetString").SetIncludeFile("MyExtension/TextObject.h");
* .SetFunctionName("SetString").SetManipulatedType("string").SetGetter("GetString");
*
* DECLARE_END_OBJECT_ACTION()
* \endcode
@@ -422,6 +434,7 @@ class GD_CORE_API InstructionMetadata {
bool HasCustomCodeGenerator() const { return hasCustomCodeGenerator; }
gd::String functionCallName;
gd::String asyncFunctionCallName;
gd::String type;
AccessType accessType;
gd::String optionalAssociatedInstruction;
@@ -454,15 +467,26 @@ class GD_CORE_API InstructionMetadata {
}
/**
* \brief Set the function that should be called when generating the source
* code from events.
* \param functionName the name of the function to call
* Set the name of the function which will be called in the generated code.
* \param functionName the name of the function to call.
* \note Shortcut for `codeExtraInformation.SetFunctionName`.
*/
ExtraInformation &SetFunctionName(const gd::String &functionName) {
return codeExtraInformation.SetFunctionName(functionName);
}
/**
* Set the name of the function, doing asynchronous work, which will be called in
* the generated code. This function should return an asynchronous task
* (i.e: `gdjs.AsyncTask` in the JavaScript runtime).
*
* \param functionName the name of the function doing asynchronous work to call.
* \note Shortcut for `codeExtraInformation.SetAsyncFunctionName`.
*/
ExtraInformation &SetAsyncFunctionName(const gd::String &functionName) {
return codeExtraInformation.SetAsyncFunctionName(functionName);
}
std::vector<ParameterMetadata> parameters;
private:
@@ -479,7 +503,6 @@ class GD_CORE_API InstructionMetadata {
int usageComplexity; ///< Evaluate the instruction from 0 (simple&easy to
///< use) to 10 (complex to understand)
bool isPrivate;
bool isAsync;
bool isObjectInstruction;
bool isBehaviorInstruction;
gd::String requiredBaseObjectCapability;

View File

@@ -14,6 +14,7 @@
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/Log.h"
namespace gd {
@@ -22,45 +23,53 @@ ObjectMetadata::ObjectMetadata(const gd::String& extensionNamespace_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon24x24,
std::shared_ptr<gd::Object> blueprintObject_)
: extensionNamespace(extensionNamespace_),
blueprintObject(blueprintObject_) {
name = name_;
#if defined(GD_IDE_ONLY)
SetFullName(gd::String(fullname_));
SetDescription(gd::String(description_));
iconFilename = icon24x24;
#endif
createFunPtr =
[blueprintObject_](gd::String name) -> std::unique_ptr<gd::Object> {
if (blueprintObject_ == std::shared_ptr<gd::Object>()) {
std::cout
<< "Error: Unable to create object. Have you declared an extension "
"(or ObjectMetadata) without specifying an object as blueprint?"
<< std::endl;
std::shared_ptr<gd::ObjectConfiguration> blueprintObject_)
: ObjectMetadata(extensionNamespace_,
name_,
fullname_,
description_,
icon24x24,
[blueprintObject_]() -> std::unique_ptr<gd::ObjectConfiguration> {
if (blueprintObject_ == std::shared_ptr<gd::ObjectConfiguration>()) {
gd::LogFatalError(
"Error: Unable to create object. Have you declared an extension "
"(or ObjectMetadata) without specifying an object as blueprint?");
return nullptr;
}
std::unique_ptr<gd::Object> newObject = blueprintObject_->Clone();
newObject->SetName(name);
return newObject;
};
return blueprintObject_->Clone();
}) {
blueprintObject = blueprintObject_;
}
ObjectMetadata::ObjectMetadata(const gd::String& extensionNamespace_,
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon24x24)
: ObjectMetadata(extensionNamespace_,
name_,
fullname_,
description_,
icon24x24,
[]() -> std::unique_ptr<gd::ObjectConfiguration> {
gd::LogFatalError(
"Error: Event-based objects don't have blueprint. "
"This method should not never be called.");
return nullptr;
}) {}
ObjectMetadata::ObjectMetadata(const gd::String& extensionNamespace_,
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon24x24,
CreateFunPtr createFunPtrP)
: extensionNamespace(extensionNamespace_) {
name = name_;
#if defined(GD_IDE_ONLY)
: name(name_),
iconFilename(icon24x24),
createFunPtr(createFunPtrP),
extensionNamespace(extensionNamespace_) {
SetFullName(gd::String(fullname_));
SetDescription(gd::String(description_));
iconFilename = icon24x24;
#endif
createFunPtr = createFunPtrP;
}
gd::InstructionMetadata& ObjectMetadata::AddCondition(

View File

@@ -13,6 +13,7 @@
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectConfiguration.h"
#include "GDCore/String.h"
namespace gd {
class InstructionMetadata;
@@ -20,7 +21,7 @@ class MultipleInstructionMetadata;
class ExpressionMetadata;
} // namespace gd
typedef std::function<std::unique_ptr<gd::Object>(gd::String name)>
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()>
CreateFunPtr;
namespace gd {
@@ -42,7 +43,17 @@ class GD_CORE_API ObjectMetadata {
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon24x24_,
std::shared_ptr<gd::Object> blueprintObject_);
std::shared_ptr<gd::ObjectConfiguration> blueprintObject_);
/**
* \brief Construct an object metadata, without "blueprint" object
*
* \note This is used by events based objects.
*/
ObjectMetadata(const gd::String& extensionNamespace_,
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon24x24_);
/**
* \brief Construct an object metadata, with a function that will be called
@@ -304,10 +315,12 @@ class GD_CORE_API ObjectMetadata {
gd::String categoryFullName;
std::set<gd::String> unsupportedBaseObjectCapabilities;
std::shared_ptr<gd::Object>
std::shared_ptr<gd::ObjectConfiguration>
blueprintObject; ///< The "blueprint" object to be copied when a new
///< object is asked. Can be null in case a creation
///< function is passed.
///< function is passed or for events based objects
///< (CustomObject are using EventBasedObject, they
///< don't need blueprints).
};
} // namespace gd

View File

@@ -7,7 +7,9 @@
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectConfiguration.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
using namespace std;
@@ -91,24 +93,22 @@ std::shared_ptr<gd::PlatformExtension> Platform::GetExtension(
return std::shared_ptr<gd::PlatformExtension>();
}
std::unique_ptr<gd::Object> Platform::CreateObject(
gd::String type, const gd::String& name) const {
std::unique_ptr<gd::ObjectConfiguration> Platform::CreateObjectConfiguration(
gd::String type) const {
if (creationFunctionTable.find(type) == creationFunctionTable.end()) {
std::cout << "Tried to create an object with an unknown type: " << type
<< " for platform " << GetName() << "!" << std::endl;
gd::LogWarning("Tried to create an object with an unknown type: " + type
+ " for platform " + GetName() + "!");
type = "";
if (creationFunctionTable.find("") == creationFunctionTable.end()) {
std::cout << "Unable to create a Base object!" << std::endl;
gd::LogError("Unable to create a Base object!");
return nullptr;
}
}
// Create a new object with the type we want.
std::unique_ptr<gd::Object> object =
(creationFunctionTable.find(type)->second)(name);
object->SetType(type);
return std::unique_ptr<gd::Object>(std::move(object));
auto objectConfiguration = (creationFunctionTable.find(type)->second)();
objectConfiguration->SetType(type);
return objectConfiguration;
}
#if defined(GD_IDE_ONLY)

View File

@@ -16,6 +16,7 @@ namespace gd {
class InstructionsMetadataHolder;
class Project;
class Object;
class ObjectConfiguration;
class Behavior;
class BehaviorMetadata;
class ObjectMetadata;
@@ -26,7 +27,7 @@ class LayoutEditorCanvas;
class ProjectExporter;
} // namespace gd
typedef std::function<std::unique_ptr<gd::Object>(gd::String name)>
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()>
CreateFunPtr;
#undef CreateEvent
@@ -146,8 +147,8 @@ class GD_CORE_API Platform {
/**
* \brief Create an object of given type with the specified name.
*/
std::unique_ptr<gd::Object> CreateObject(gd::String type,
const gd::String& name) const;
std::unique_ptr<gd::ObjectConfiguration> CreateObjectConfiguration(
gd::String type) const;
/**
* \brief Create an event of given type

View File

@@ -18,6 +18,7 @@
#include "GDCore/Extensions/Platform.h"
#include "GDCore/IDE/PlatformManager.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/ObjectConfiguration.h"
#include "GDCore/Project/BehaviorsSharedData.h"
#include "GDCore/Tools/Localization.h"
@@ -231,7 +232,7 @@ gd::ObjectMetadata& PlatformExtension::AddObject(
const gd::String& fullname,
const gd::String& description,
const gd::String& icon24x24,
std::shared_ptr<gd::Object> instance) {
std::shared_ptr<gd::ObjectConfiguration> instance) {
gd::String nameWithNamespace = GetNameSpace() + name;
objectsInfos[nameWithNamespace] = ObjectMetadata(GetNameSpace(),
nameWithNamespace,
@@ -244,6 +245,21 @@ gd::ObjectMetadata& PlatformExtension::AddObject(
return objectsInfos[nameWithNamespace];
}
gd::ObjectMetadata& PlatformExtension::AddEventsBasedObject(
const gd::String& name,
const gd::String& fullname,
const gd::String& description,
const gd::String& icon24x24) {
gd::String nameWithNamespace = GetNameSpace() + name;
objectsInfos[nameWithNamespace] = ObjectMetadata(GetNameSpace(),
nameWithNamespace,
fullname,
description,
icon24x24)
.SetHelpPath(GetHelpPath());
return objectsInfos[nameWithNamespace];
}
gd::BehaviorMetadata& PlatformExtension::AddBehavior(
const gd::String& name,
const gd::String& fullname,
@@ -269,6 +285,23 @@ gd::BehaviorMetadata& PlatformExtension::AddBehavior(
return behaviorsInfo[nameWithNamespace];
}
gd::BehaviorMetadata& PlatformExtension::AddEventsBasedBehavior(
const gd::String& name,
const gd::String& fullname,
const gd::String& description,
const gd::String& group,
const gd::String& icon24x24) {
gd::String nameWithNamespace = GetNameSpace() + name;
behaviorsInfo[nameWithNamespace] = BehaviorMetadata(GetNameSpace(),
nameWithNamespace,
fullname,
description,
group,
icon24x24)
.SetHelpPath(GetHelpPath());
return behaviorsInfo[nameWithNamespace];
}
gd::EffectMetadata& PlatformExtension::AddEffect(const gd::String& name) {
gd::String nameWithNamespace = GetNameSpace() + name;
effectsMetadata[nameWithNamespace] = EffectMetadata(nameWithNamespace);

View File

@@ -37,9 +37,10 @@ class ArbitraryResourceWorker;
class BehaviorsSharedData;
class Behavior;
class Object;
class ObjectConfiguration;
} // namespace gd
typedef std::function<std::unique_ptr<gd::Object>(gd::String name)>
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()>
CreateFunPtr;
namespace gd {
@@ -242,7 +243,21 @@ class GD_CORE_API PlatformExtension {
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon_,
std::shared_ptr<gd::Object> instance);
std::shared_ptr<gd::ObjectConfiguration> instance);
/**
* \brief Declare a new events based object as being part of the extension.
*
* \param name The name of the object
* \param fullname The user friendly name of the object
* \param description The user friendly description of the object
* \param icon The icon of the object.
*/
gd::ObjectMetadata& AddEventsBasedObject(
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon_);
/**
* \brief Declare a new behavior as being part of the extension.
@@ -267,6 +282,21 @@ class GD_CORE_API PlatformExtension {
std::shared_ptr<gd::Behavior> instance,
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance);
/**
* \brief Declare a new events based behavior as being part of the extension.
*
* \param name The name of the behavior
* \param fullname The user friendly name of the behavior
* \param description The user friendly description of the behavior
* \param icon The icon of the behavior.
*/
gd::BehaviorMetadata& AddEventsBasedBehavior(
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& group_,
const gd::String& icon_);
/**
* \brief Declare a new effect as being part of the extension.
* \param name The internal name of the effect (also called effect type).

View File

@@ -25,8 +25,8 @@ gd::ObjectMetadata& PlatformExtension::AddObject(const gd::String& name,
fullname,
description,
icon24x24,
[](gd::String name) -> std::unique_ptr<gd::Object> {
return gd::make_unique<T>(name);
[]() -> std::unique_ptr<gd::ObjectConfiguration> {
return gd::make_unique<T>();
})
.SetHelpPath(GetHelpPath());

View File

@@ -0,0 +1,25 @@
#include "BehaviorTypeRenamer.h"
#include "GDCore/Events/Instruction.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/WholeProjectRefactorer.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
namespace gd {
void BehaviorTypeRenamer::DoVisitObject(gd::Object& object) {
};
void BehaviorTypeRenamer::DoVisitBehavior(gd::Behavior& behavior) {
if (behavior.GetTypeName() == oldType) {
behavior.SetTypeName(newType);
}
};
BehaviorTypeRenamer::~BehaviorTypeRenamer() {}
} // namespace gd

View File

@@ -0,0 +1,43 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_BEHAVIORTYPERENAMER_H
#define GDCORE_BEHAVIORTYPERENAMER_H
#include <set>
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/String.h"
namespace gd {
class Project;
class Object;
class Behavior;
} // namespace gd
namespace gd {
class GD_CORE_API BehaviorTypeRenamer : public ArbitraryObjectsWorker {
public:
BehaviorTypeRenamer(const gd::Project& project_,
const gd::String& oldType_,
const gd::String& newType_)
: project(project_), oldType(oldType_), newType(newType_){};
virtual ~BehaviorTypeRenamer();
private:
void DoVisitObject(gd::Object& object) override;
void DoVisitBehavior(gd::Behavior& behavior) override;
const gd::Project& project;
gd::String oldType;
gd::String newType;
};
}; // namespace gd
#endif // GDCORE_BEHAVIORTYPERENAMER_H

View File

@@ -0,0 +1,24 @@
#include "CustomObjectTypeRenamer.h"
#include "GDCore/Events/Instruction.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/WholeProjectRefactorer.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
namespace gd {
void CustomObjectTypeRenamer::DoVisitObject(gd::Object& object) {
if (object.GetType() == oldType) {
object.SetType(newType);
}
};
void CustomObjectTypeRenamer::DoVisitBehavior(gd::Behavior& behavior) {};
CustomObjectTypeRenamer::~CustomObjectTypeRenamer() {}
} // namespace gd

View File

@@ -0,0 +1,43 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_CUSTOMOBJECTTYPERENAMER_H
#define GDCORE_CUSTOMOBJECTTYPERENAMER_H
#include <set>
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/String.h"
namespace gd {
class Project;
class Object;
class Behavior;
} // namespace gd
namespace gd {
class GD_CORE_API CustomObjectTypeRenamer : public ArbitraryObjectsWorker {
public:
CustomObjectTypeRenamer(const gd::Project& project_,
const gd::String& oldType_,
const gd::String& newType_)
: project(project_), oldType(oldType_), newType(newType_){};
virtual ~CustomObjectTypeRenamer();
private:
void DoVisitObject(gd::Object& object) override;
void DoVisitBehavior(gd::Behavior& behavior) override;
const gd::Project& project;
gd::String oldType;
gd::String newType;
};
}; // namespace gd
#endif // GDCORE_CUSTOMOBJECTTYPERENAMER_H

View File

@@ -0,0 +1,41 @@
/*
* 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/EventsLeaderboardsLister.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
namespace gd {
bool EventsLeaderboardsLister::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
const gd::InstructionMetadata& instrInfo =
isCondition ? MetadataProvider::GetConditionMetadata(
project.GetCurrentPlatform(), instruction.GetType())
: MetadataProvider::GetActionMetadata(
project.GetCurrentPlatform(), instruction.GetType());
for (int i = 0; i < instruction.GetParametersCount() &&
i < instrInfo.GetParametersCount();
++i)
if (instrInfo.GetParameter(i).type == "leaderboardId") {
leaderboardIds.insert(instruction.GetParameter(i).GetPlainString());
}
return false;
}
EventsLeaderboardsLister::~EventsLeaderboardsLister() {}
} // namespace gd

View File

@@ -0,0 +1,48 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef EventsLeaderboardsLister_H
#define EventsLeaderboardsLister_H
#include <map>
#include <memory>
#include <set>
#include <vector>
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class BaseEvent;
class Project;
class EventsList;
}
namespace gd {
/**
* \brief List the leaderboard ids in the instructions.
*
* \ingroup IDE
*/
class GD_CORE_API EventsLeaderboardsLister : public ArbitraryEventsWorker {
public:
EventsLeaderboardsLister(gd::Project& project_) : project(project_){};
virtual ~EventsLeaderboardsLister();
/**
* Return the values of all leaderboardIds found in the events.
*/
const std::set<gd::String>& GetLeaderboardIds() { return leaderboardIds; }
private:
virtual bool DoVisitInstruction(gd::Instruction& instruction,
bool isCondition);
std::set<gd::String> leaderboardIds;
gd::Project& project;
};
} // namespace gd
#endif // EventsLeaderboardsLister_H

View File

@@ -0,0 +1,49 @@
/*
* 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/EventsLeaderboardsRenamer.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
namespace gd {
bool EventsLeaderboardsRenamer::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
const gd::InstructionMetadata& instrInfo =
isCondition ? MetadataProvider::GetConditionMetadata(
project.GetCurrentPlatform(), instruction.GetType())
: MetadataProvider::GetActionMetadata(
project.GetCurrentPlatform(), instruction.GetType());
for (int i = 0; i < instruction.GetParametersCount() &&
i < instrInfo.GetParametersCount();
++i) {
const gd::ParameterMetadata parameter = instrInfo.GetParameter(i);
if (parameter.type == "leaderboardId") {
const gd::String leaderboardId =
instruction.GetParameter(i).GetPlainString();
if (leaderboardIdMap.find(leaderboardId) != leaderboardIdMap.end()) {
instruction.SetParameter(i, leaderboardIdMap[leaderboardId]);
}
}
}
return false;
}
EventsLeaderboardsRenamer::~EventsLeaderboardsRenamer() {}
} // namespace gd

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.
*/
#ifndef EventsLeaderboardsRenamer_H
#define EventsLeaderboardsRenamer_H
#include <map>
#include <memory>
#include <set>
#include <vector>
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class BaseEvent;
class Project;
class EventsList;
}
namespace gd {
/**
* \brief Replace the leaderboard ids in the instructions.
*
* \ingroup IDE
*/
class GD_CORE_API EventsLeaderboardsRenamer : public ArbitraryEventsWorker {
public:
EventsLeaderboardsRenamer(
gd::Project& project_,
const std::map<gd::String, gd::String>& leaderboardIdMap_)
: project(project_), leaderboardIdMap(leaderboardIdMap_){};
virtual ~EventsLeaderboardsRenamer();
private:
virtual bool DoVisitInstruction(gd::Instruction& instruction,
bool isCondition);
std::map<gd::String, gd::String> leaderboardIdMap;
gd::Project& project;
};
} // namespace gd
#endif // EventsLeaderboardsRenamer_H

View File

@@ -19,6 +19,7 @@
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/IDE/Events/InstructionSentenceFormatter.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
using namespace std;
@@ -121,7 +122,7 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
bool hasDoneRenaming;
const gd::String& objectName;
const gd::String& objectNewName;
const gd::Platform &platform;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
@@ -216,7 +217,7 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
private:
bool hasObject;
const gd::String& objectName;
const gd::Platform &platform;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
@@ -411,8 +412,8 @@ void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
}
bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
gd::InstructionsList& actions,
gd::String name) {
bool somethingModified = false;
@@ -434,7 +435,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
"number", instrInfos.parameters[pNb].type)) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, project, layout, "number", *node, name)) {
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "number", *node, name)) {
deleteMe = true;
break;
}
@@ -444,7 +445,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
"string", instrInfos.parameters[pNb].type)) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, project, layout, "string", *node, name)) {
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "string", *node, name)) {
deleteMe = true;
break;
}
@@ -458,8 +459,8 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
} else if (!actions[aId].GetSubInstructions().empty())
somethingModified =
RemoveObjectInActions(platform,
project,
layout,
globalObjectsContainer,
objectsContainer,
actions[aId].GetSubInstructions(),
name) ||
somethingModified;
@@ -470,8 +471,8 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
bool EventsRefactorer::RemoveObjectInConditions(
const gd::Platform& platform,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
gd::InstructionsList& conditions,
gd::String name) {
bool somethingModified = false;
@@ -494,7 +495,7 @@ bool EventsRefactorer::RemoveObjectInConditions(
"number", instrInfos.parameters[pNb].type)) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, project, layout, "number", *node, name)) {
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "number", *node, name)) {
deleteMe = true;
break;
}
@@ -504,7 +505,7 @@ bool EventsRefactorer::RemoveObjectInConditions(
"string", instrInfos.parameters[pNb].type)) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, project, layout, "string", *node, name)) {
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "string", *node, name)) {
deleteMe = true;
break;
}
@@ -518,8 +519,8 @@ bool EventsRefactorer::RemoveObjectInConditions(
} else if (!conditions[cId].GetSubInstructions().empty())
somethingModified =
RemoveObjectInConditions(platform,
project,
layout,
globalObjectsContainer,
objectsContainer,
conditions[cId].GetSubInstructions(),
name) ||
somethingModified;
@@ -529,8 +530,8 @@ bool EventsRefactorer::RemoveObjectInConditions(
}
void EventsRefactorer::RemoveObjectInEvents(const gd::Platform& platform,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
gd::EventsList& events,
gd::String name) {
for (std::size_t i = 0; i < events.size(); ++i) {
@@ -538,19 +539,19 @@ void EventsRefactorer::RemoveObjectInEvents(const gd::Platform& platform,
events[i].GetAllConditionsVectors();
for (std::size_t j = 0; j < conditionsVectors.size(); ++j) {
bool conditionsModified = RemoveObjectInConditions(
platform, project, layout, *conditionsVectors[j], name);
platform, globalObjectsContainer, objectsContainer, *conditionsVectors[j], name);
}
vector<gd::InstructionsList*> actionsVectors =
events[i].GetAllActionsVectors();
for (std::size_t j = 0; j < actionsVectors.size(); ++j) {
bool actionsModified = RemoveObjectInActions(
platform, project, layout, *actionsVectors[j], name);
platform, globalObjectsContainer, objectsContainer, *actionsVectors[j], name);
}
if (events[i].CanHaveSubEvents())
RemoveObjectInEvents(
platform, project, layout, events[i].GetSubEvents(), name);
platform, globalObjectsContainer, objectsContainer, events[i].GetSubEvents(), name);
}
}
@@ -565,6 +566,8 @@ std::vector<EventsSearchResult> EventsRefactorer::ReplaceStringInEvents(
bool inActions,
bool inEventStrings) {
vector<EventsSearchResult> modifiedEvents;
if (toReplace.empty()) return modifiedEvents;
for (std::size_t i = 0; i < events.size(); ++i) {
bool eventModified = false;
if (inConditions) {

View File

@@ -78,13 +78,16 @@ class GD_CORE_API ExpressionParameterMover
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
auto moveParameter =
[this](std::vector<std::unique_ptr<gd::ExpressionNode>>& parameters) {
if (oldIndex >= parameters.size() || newIndex >= parameters.size())
[this](std::vector<std::unique_ptr<gd::ExpressionNode>>& parameters, int firstWrittenParameterIndex) {
size_t newExpressionIndex = newIndex - firstWrittenParameterIndex;
size_t oldExpressionIndex = oldIndex - firstWrittenParameterIndex;
if (oldExpressionIndex >= parameters.size() || newExpressionIndex >= parameters.size())
return;
auto movedParameterNode = std::move(parameters[oldIndex]);
parameters.erase(parameters.begin() + oldIndex);
parameters.insert(parameters.begin() + newIndex,
auto movedParameterNode = std::move(parameters[oldExpressionIndex]);
parameters.erase(parameters.begin() + oldExpressionIndex);
parameters.insert(parameters.begin() + newExpressionIndex,
std::move(movedParameterNode));
};
@@ -92,10 +95,13 @@ class GD_CORE_API ExpressionParameterMover
if (behaviorType.empty() && !objectType.empty() &&
!node.objectName.empty()) {
// Move parameter of an object function
// This refactor only applies on events object functions
// and events object functions doesn't exist yet.
// This is a dead code.
const gd::String& thisObjectType = gd::GetTypeOfObject(
globalObjectsContainer, objectsContainer, node.objectName);
if (thisObjectType == objectType) {
moveParameter(node.parameters);
moveParameter(node.parameters, 1);
hasDoneMoving = true;
}
} else if (!behaviorType.empty() && !node.behaviorName.empty()) {
@@ -103,12 +109,12 @@ class GD_CORE_API ExpressionParameterMover
const gd::String& thisBehaviorType = gd::GetTypeOfBehavior(
globalObjectsContainer, objectsContainer, node.behaviorName);
if (thisBehaviorType == behaviorType) {
moveParameter(node.parameters);
moveParameter(node.parameters, 2);
hasDoneMoving = true;
}
} else if (behaviorType.empty() && objectType.empty()) {
// Move parameter of a free function
moveParameter(node.parameters);
moveParameter(node.parameters, 1);
hasDoneMoving = true;
}
}

View File

@@ -5,7 +5,7 @@
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/WholeProjectRefactorer.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/Project/BehaviorContent.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
@@ -29,7 +29,7 @@ void UsedExtensionsFinder::DoVisitObject(gd::Object& object) {
// Behaviors scanner
void UsedExtensionsFinder::DoVisitBehavior(gd::BehaviorContent& behavior) {
void UsedExtensionsFinder::DoVisitBehavior(gd::Behavior& behavior) {
usedExtensions.insert(
gd::MetadataProvider::GetExtensionAndBehaviorMetadata(
project.GetCurrentPlatform(), behavior.GetTypeName())

View File

@@ -16,7 +16,7 @@
namespace gd {
class Project;
class Object;
class BehaviorContent;
class Behavior;
} // namespace gd
namespace gd {
@@ -38,7 +38,7 @@ class GD_CORE_API UsedExtensionsFinder
void DoVisitObject(gd::Object& object) override;
// Behavior Visitor
void DoVisitBehavior(gd::BehaviorContent& behavior) override;
void DoVisitBehavior(gd::Behavior& behavior) override;
// Instructions Visitor
bool DoVisitInstruction(gd::Instruction& instruction,

View File

@@ -8,9 +8,10 @@
#include "GDCore/Events/Expression.h"
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/EventsBasedObject.h"
//#include "GDCore/Project/ObjectsContainer.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"
@@ -72,4 +73,39 @@ void EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
}
}
void EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
const gd::Project& project,
const gd::EventsBasedObject& eventsBasedObject,
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);
// TODO EBO Use a constant instead a hard coded value "Object".
// ...and has an "Object" by convention...
if (!outputObjectsContainer.HasObjectNamed("Object")) {
gd::LogWarning("No \"Object\" in a function of an events based object: " +
eventsFunction.GetName() +
". This means this function is likely misconfigured (check "
"its parameters).");
return;
}
if (eventsBasedObject.HasObjectNamed("Object")) {
gd::LogWarning("Child-objects can't be named Object because it's reserved"
"for the parent. ");
return;
}
// ...and its children.
auto &children = eventsBasedObject.GetObjects();
for (auto &childObject : children) {
auto child = childObject.get();
outputObjectsContainer.InsertObject(*child, children.size());
}
}
} // namespace gd

View File

@@ -14,6 +14,7 @@ class ObjectsContainer;
class ParameterMetadata;
class EventsFunction;
class EventsBasedBehavior;
class EventsBasedObject;
class Expression;
} // namespace gd
@@ -51,6 +52,21 @@ class GD_CORE_API EventsFunctionTools {
const gd::EventsFunction& eventsFunction,
gd::ObjectsContainer& outputGlobalObjectsContainer,
gd::ObjectsContainer& outputObjectsContainer);
/**
* \brief Given a parent-object events function, initialize the given objects container
* with objects described in the events function parameters, in
* the events function groups and in the parent-object properties for
* child-objects.
*
* This is useful to create the "context" of a function, before code
* generation for example.
*/
static void ObjectEventsFunctionToObjectsContainer(
const gd::Project& project,
const gd::EventsBasedObject& eventsBasedObject,
const gd::EventsFunction& eventsFunction,
gd::ObjectsContainer& outputGlobalObjectsContainer,
gd::ObjectsContainer& outputObjectsContainer);
};
} // namespace gd

View File

@@ -10,7 +10,7 @@
#include <memory>
#include <vector>
#include "GDCore/Project/BehaviorContent.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/String.h"
@@ -36,7 +36,7 @@ void ArbitraryObjectsWorker::VisitObject(gd::Object& object) {
VisitBehavior(object.GetBehavior(behaviorName));
}
void ArbitraryObjectsWorker::VisitBehavior(gd::BehaviorContent& behavior) {
void ArbitraryObjectsWorker::VisitBehavior(gd::Behavior& behavior) {
DoVisitBehavior(behavior);
}

View File

@@ -15,7 +15,7 @@
namespace gd {
class Object;
class ObjectsContainer;
class BehaviorContent;
class Behavior;
} // namespace gd
namespace gd {
@@ -40,7 +40,7 @@ class GD_CORE_API ArbitraryObjectsWorker {
private:
void VisitObjectContainer(gd::ObjectsContainer& objects);
void VisitObject(gd::Object& object);
void VisitBehavior(gd::BehaviorContent& instruction);
void VisitBehavior(gd::Behavior& behavior);
/**
* Called to do some work on an object container.
@@ -55,7 +55,7 @@ class GD_CORE_API ArbitraryObjectsWorker {
/**
* Called to do some work on a behavior.
*/
virtual void DoVisitBehavior(gd::BehaviorContent& instruction){};
virtual void DoVisitBehavior(gd::Behavior& behavior){};
};
} // namespace gd

View File

@@ -111,7 +111,7 @@ class ResourceWorkerInEventsWorker : public ArbitraryEventsWorker {
ResourceWorkerInEventsWorker(const gd::Project& project_,
gd::ArbitraryResourceWorker& worker_)
: project(project_), worker(worker_){};
virtual ~ResourceWorkerInEventsWorker() {};
virtual ~ResourceWorkerInEventsWorker(){};
private:
bool DoVisitInstruction(gd::Instruction& instruction, bool isCondition) {
@@ -131,7 +131,8 @@ class ResourceWorkerInEventsWorker : public ArbitraryEventsWorker {
const gd::String& lastObjectName) {
const String& parameterValue = parameterExpression.GetPlainString();
if (parameterMetadata.GetType() ==
"police") { // Should be renamed fontResource
"police" || // Should be renamed fontResource
parameterMetadata.GetType() == "fontResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeFont(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
@@ -149,6 +150,10 @@ class ResourceWorkerInEventsWorker : public ArbitraryEventsWorker {
gd::String updatedParameterValue = parameterValue;
worker.ExposeImage(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
} else if (parameterMetadata.GetType() == "jsonResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeJson(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
}
});

View File

@@ -11,7 +11,7 @@
namespace gd {
class Project;
class Object;
class BehaviorContent;
class Behavior;
} // namespace gd
namespace gd {
@@ -24,12 +24,12 @@ class GD_CORE_API UnfilledRequiredBehaviorPropertyProblem {
UnfilledRequiredBehaviorPropertyProblem(
const gd::Project& sourceProject_,
gd::Object& sourceObject_,
gd::BehaviorContent& sourceBehaviorContent_,
gd::Behavior& sourceBehavior_,
const gd::String& sourcePropertyName_,
const gd::String& expectedBehaviorTypeName_)
: sourceProject(sourceProject_),
sourceObject(sourceObject_),
sourceBehaviorContent(sourceBehaviorContent_),
sourceBehavior(sourceBehavior_),
sourcePropertyName(sourcePropertyName_),
expectedBehaviorTypeName(expectedBehaviorTypeName_){};
virtual ~UnfilledRequiredBehaviorPropertyProblem();
@@ -47,8 +47,8 @@ class GD_CORE_API UnfilledRequiredBehaviorPropertyProblem {
/**
* \brief Return the behavior where the problem appears.
*/
virtual gd::BehaviorContent& GetSourceBehaviorContent() const {
return sourceBehaviorContent;
virtual gd::Behavior& GetSourceBehaviorContent() const {
return sourceBehavior;
}
/**
@@ -69,7 +69,7 @@ class GD_CORE_API UnfilledRequiredBehaviorPropertyProblem {
private:
const gd::Project& sourceProject;
gd::Object& sourceObject;
gd::BehaviorContent& sourceBehaviorContent;
gd::Behavior& sourceBehavior;
const gd::String sourcePropertyName;
const gd::String expectedBehaviorTypeName;

View File

@@ -11,6 +11,8 @@
#include "GDCore/IDE/DependenciesAnalyzer.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
#include "GDCore/IDE/Events/CustomObjectTypeRenamer.h"
#include "GDCore/IDE/Events/BehaviorTypeRenamer.h"
#include "GDCore/IDE/Events/EventsRefactorer.h"
#include "GDCore/IDE/Events/ExpressionsParameterMover.h"
#include "GDCore/IDE/Events/ExpressionsRenamer.h"
@@ -20,8 +22,9 @@
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/IDE/UnfilledRequiredBehaviorPropertyProblem.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/BehaviorContent.h"
#include "GDCore/Project/BehaviorConfigurationContainer.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/Project/ExternalLayout.h"
@@ -53,6 +56,17 @@ gd::String GetBehaviorFullType(const gd::String& extensionName,
const auto& separator = gd::PlatformExtension::GetNamespaceSeparator();
return extensionName + separator + behaviorName;
}
gd::String GetObjectEventsFunctionFullType(const gd::String& extensionName,
const gd::String& objectName,
const gd::String& functionName) {
const auto& separator = gd::PlatformExtension::GetNamespaceSeparator();
return extensionName + separator + objectName + separator + functionName;
}
gd::String GetObjectFullType(const gd::String& extensionName,
const gd::String& objectName) {
const auto& separator = gd::PlatformExtension::GetNamespaceSeparator();
return extensionName + separator + objectName;
}
} // namespace
namespace gd {
@@ -60,6 +74,9 @@ namespace gd {
// By convention, the first parameter of an events based behavior method is
// always called "Object".
const gd::String WholeProjectRefactorer::behaviorObjectParameterName = "Object";
// By convention, the first parameter of an events based object method is
// always called "Object".
const gd::String WholeProjectRefactorer::parentObjectParameterName = "Object";
void WholeProjectRefactorer::ExposeProjectEvents(
gd::Project& project, gd::ArbitraryEventsWorker& worker) {
@@ -93,6 +110,17 @@ void WholeProjectRefactorer::ExposeProjectEvents(
worker.Launch(eventsFunction->GetEvents());
}
}
// Add (object) events functions
for (auto&& eventsBasedObject :
eventsFunctionsExtension.GetEventsBasedObjects()
.GetInternalVector()) {
auto& objectEventsFunctions = eventsBasedObject->GetEventsFunctions();
for (auto&& eventsFunction :
objectEventsFunctions.GetInternalVector()) {
worker.Launch(eventsFunction->GetEvents());
}
}
}
}
@@ -139,6 +167,13 @@ void WholeProjectRefactorer::ExposeProjectEvents(
.GetInternalVector()) {
ExposeEventsBasedBehaviorEvents(project, *eventsBasedBehavior, worker);
}
// Add (object) events functions
for (auto&& eventsBasedObject :
eventsFunctionsExtension.GetEventsBasedObjects()
.GetInternalVector()) {
ExposeEventsBasedObjectEvents(project, *eventsBasedObject, worker);
}
}
}
@@ -162,11 +197,49 @@ void WholeProjectRefactorer::ExposeEventsBasedBehaviorEvents(
}
}
void WholeProjectRefactorer::ExposeEventsBasedObjectEvents(
gd::Project& project,
const gd::EventsBasedObject& eventsBasedObject,
gd::ArbitraryEventsWorkerWithContext& worker) {
auto& objectEventsFunctions = eventsBasedObject.GetEventsFunctions();
for (auto&& eventsFunction : objectEventsFunctions.GetInternalVector()) {
gd::ObjectsContainer globalObjectsAndGroups;
gd::ObjectsContainer objectsAndGroups;
gd::EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
project,
eventsBasedObject,
*eventsFunction,
globalObjectsAndGroups,
objectsAndGroups);
worker.Launch(
eventsFunction->GetEvents(), globalObjectsAndGroups, objectsAndGroups);
}
}
void WholeProjectRefactorer::ExposeProjectObjects(
gd::Project& project, gd::ArbitraryObjectsWorker& worker) {
// Global objects
worker.Launch(project);
for (size_t i = 0; i < project.GetLayoutsCount(); i++)
// Layers objects
for (size_t i = 0; i < project.GetLayoutsCount(); i++) {
worker.Launch(project.GetLayout(i));
}
// Event based objects children
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
e++) {
auto& eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
for (auto&& eventsBasedObjectUniquePtr :
eventsFunctionsExtension.GetEventsBasedObjects()
.GetInternalVector()) {
auto eventsBasedObject = eventsBasedObjectUniquePtr.get();
worker.Launch(*eventsBasedObject);
}
}
};
std::set<gd::String>
@@ -181,8 +254,8 @@ WholeProjectRefactorer::GetAllObjectTypesUsingEventsBasedBehavior(
auto addTypesOfObjectsIn =
[&allTypes, &behaviorType](const gd::ObjectsContainer& objectsContainer) {
for (auto& object : objectsContainer.GetObjects()) {
for (auto& behaviorContent : object->GetAllBehaviorContents()) {
if (behaviorContent.second->GetTypeName() == behaviorType) {
for (auto& behavior : object->GetAllBehaviorContents()) {
if (behavior.second->GetTypeName() == behaviorType) {
allTypes.insert(object->GetType());
}
}
@@ -223,6 +296,26 @@ void WholeProjectRefactorer::EnsureBehaviorEventsFunctionsProperParameters(
}
}
void WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::EventsBasedObject& eventsBasedObject) {
for (auto& eventsFunction :
eventsBasedObject.GetEventsFunctions().GetInternalVector()) {
auto& parameters = eventsFunction->GetParameters();
while (parameters.size() < 1) {
gd::ParameterMetadata newParameter;
parameters.push_back(newParameter);
}
parameters[0]
.SetType("object")
.SetName(parentObjectParameterName)
.SetDescription("Object")
.SetExtraInfo(GetObjectFullType(eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName()));
}
}
void WholeProjectRefactorer::RenameEventsFunctionsExtension(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
@@ -297,6 +390,66 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
// extension name
};
auto renameObjectEventsFunction =
[&project, &oldName, &newName](
const gd::EventsBasedObject& eventsBasedObject,
const gd::EventsFunction& eventsFunction) {
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(oldName,
eventsBasedObject.GetName(),
eventsFunction.GetName()),
GetObjectEventsFunctionFullType(newName,
eventsBasedObject.GetName(),
eventsFunction.GetName()));
ExposeProjectEvents(project, renamer);
} else if (eventsFunction.GetFunctionType() ==
gd::EventsFunction::Expression ||
eventsFunction.GetFunctionType() ==
gd::EventsFunction::StringExpression) {
// Nothing to do, expressions are not including the extension name
}
};
auto renameObjectPropertyFunctions =
[&project, &oldName, &newName](
const gd::EventsBasedObject& eventsBasedObject,
const gd::NamedPropertyDescriptor& property) {
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(
oldName,
eventsBasedObject.GetName(),
gd::EventsBasedObject::GetPropertyActionName(
property.GetName())),
GetObjectEventsFunctionFullType(
newName,
eventsBasedObject.GetName(),
gd::EventsBasedObject::GetPropertyActionName(
property.GetName())));
ExposeProjectEvents(project, actionRenamer);
gd::InstructionsTypeRenamer conditionRenamer =
gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(
oldName,
eventsBasedObject.GetName(),
gd::EventsBasedObject::GetPropertyConditionName(
property.GetName())),
GetObjectEventsFunctionFullType(
newName,
eventsBasedObject.GetName(),
gd::EventsBasedObject::GetPropertyConditionName(
property.GetName())));
ExposeProjectEvents(project, conditionRenamer);
// Nothing to do for expressions, expressions are not including the
// extension name
};
// 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.
@@ -352,6 +505,28 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
}
}
// Object instructions
for (auto&& eventsBasedObject :
eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) {
auto& objectEventsFunctions = eventsBasedObject->GetEventsFunctions();
for (auto&& eventsFunction : objectEventsFunctions.GetInternalVector()) {
if (eventsFunction->GetFunctionType() == gd::EventsFunction::Action ||
eventsFunction->GetFunctionType() == gd::EventsFunction::Condition) {
renameObjectEventsFunction(*eventsBasedObject, *eventsFunction);
}
}
}
// Object properties
for (auto&& eventsBasedObject :
eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) {
auto& objectProperties = eventsBasedObject->GetPropertyDescriptors();
for (auto&& propertyDescriptor : objectProperties.GetInternalVector()) {
renameObjectPropertyFunctions(*eventsBasedObject,
*propertyDescriptor);
}
}
// Finally, rename behaviors used in objects
for (auto&& eventsBasedBehavior :
eventsFunctionsExtension.GetEventsBasedBehaviors().GetInternalVector()) {
@@ -360,6 +535,15 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
GetBehaviorFullType(oldName, eventsBasedBehavior->GetName()),
GetBehaviorFullType(newName, eventsBasedBehavior->GetName()));
}
// Finally, rename custom objects type
for (auto&& eventsBasedObject :
eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) {
DoRenameObject(
project,
GetObjectFullType(oldName, eventsBasedObject->GetName()),
GetObjectFullType(newName, eventsBasedObject->GetName()));
}
}
void WholeProjectRefactorer::RenameEventsFunction(
@@ -419,6 +603,44 @@ void WholeProjectRefactorer::RenameBehaviorEventsFunction(
}
}
void WholeProjectRefactorer::RenameObjectEventsFunction(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::EventsBasedObject& eventsBasedObject,
const gd::String& oldFunctionName,
const gd::String& newFunctionName) {
auto& eventsFunctions = eventsBasedObject.GetEventsFunctions();
if (!eventsFunctions.HasEventsFunctionNamed(oldFunctionName)) return;
const gd::EventsFunction& eventsFunction =
eventsFunctions.GetEventsFunction(oldFunctionName);
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName(),
oldFunctionName),
GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName(),
newFunctionName));
ExposeProjectEvents(project, renamer);
} else if (eventsFunction.GetFunctionType() ==
gd::EventsFunction::Expression ||
eventsFunction.GetFunctionType() ==
gd::EventsFunction::StringExpression) {
gd::ExpressionsRenamer renamer =
gd::ExpressionsRenamer(project.GetCurrentPlatform());
renamer.SetReplacedObjectExpression(
GetObjectFullType(eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName()),
oldFunctionName,
newFunctionName);
ExposeProjectEvents(project, renamer);
}
}
void WholeProjectRefactorer::MoveEventsFunctionParameter(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
@@ -489,6 +711,45 @@ void WholeProjectRefactorer::MoveBehaviorEventsFunctionParameter(
}
}
void WholeProjectRefactorer::MoveObjectEventsFunctionParameter(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::EventsBasedObject& eventsBasedObject,
const gd::String& functionName,
std::size_t oldIndex,
std::size_t newIndex) {
auto& eventsFunctions = eventsBasedObject.GetEventsFunctions();
if (!eventsFunctions.HasEventsFunctionNamed(functionName)) return;
const gd::EventsFunction& eventsFunction =
eventsFunctions.GetEventsFunction(functionName);
const gd::String& eventsFunctionType =
GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName(),
functionName);
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
gd::InstructionsParameterMover mover = gd::InstructionsParameterMover(
project, eventsFunctionType, oldIndex, newIndex);
ExposeProjectEvents(project, mover);
} else if (eventsFunction.GetFunctionType() ==
gd::EventsFunction::Expression ||
eventsFunction.GetFunctionType() ==
gd::EventsFunction::StringExpression) {
gd::ExpressionsParameterMover mover =
gd::ExpressionsParameterMover(project.GetCurrentPlatform());
mover.SetObjectExpressionMovedParameter(
GetObjectFullType(eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName()),
functionName,
oldIndex,
newIndex);
ExposeProjectEvents(project, mover);
}
}
void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
@@ -555,6 +816,55 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
}
}
void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::EventsBasedObject& eventsBasedObject,
const gd::String& oldPropertyName,
const gd::String& newPropertyName) {
auto& properties = eventsBasedObject.GetPropertyDescriptors();
if (!properties.Has(oldPropertyName)) return;
// 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.SetReplacedObjectExpression(
GetObjectFullType(eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName()),
EventsBasedObject::GetPropertyExpressionName(oldPropertyName),
EventsBasedObject::GetPropertyExpressionName(newPropertyName));
ExposeProjectEvents(project, expressionRenamer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName(),
EventsBasedObject::GetPropertyActionName(oldPropertyName)),
GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName(),
EventsBasedObject::GetPropertyActionName(newPropertyName)));
ExposeProjectEvents(project, actionRenamer);
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName(),
EventsBasedObject::GetPropertyConditionName(oldPropertyName)),
GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName(),
EventsBasedObject::GetPropertyConditionName(newPropertyName)));
ExposeProjectEvents(project, conditionRenamer);
}
void WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
gd::Project& project,
gd::Object& object,
@@ -575,10 +885,8 @@ void WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
return;
}
gd::Behavior& behavior = behaviorMetadata.Get();
gd::BehaviorContent& behaviorContent = object.GetBehavior(behaviorName);
for (auto const& keyValue :
behavior.GetProperties(behaviorContent.GetContent())) {
gd::Behavior& behavior = object.GetBehavior(behaviorName);
for (auto const& keyValue : behavior.GetProperties()) {
const gd::String& propertyName = keyValue.first;
const gd::PropertyDescriptor& property = keyValue.second;
if (property.GetType().LowerCase() == "behavior") {
@@ -588,11 +896,11 @@ void WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
continue;
}
const gd::String& requiredBehaviorType = extraInfo.at(0);
const auto behaviorContents =
const auto behaviorNames =
WholeProjectRefactorer::GetBehaviorsWithType(object,
requiredBehaviorType);
const gd::String* defaultBehaviorName = nullptr;
if (behaviorContents.size() == 0) {
if (behaviorNames.size() == 0) {
const gd::BehaviorMetadata& requiredBehaviorMetadata =
MetadataProvider::GetBehaviorMetadata(platform,
requiredBehaviorType);
@@ -602,10 +910,9 @@ void WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
project, object, requiredBehaviorType, requiredBehaviorName);
defaultBehaviorName = &requiredBehaviorName;
} else {
defaultBehaviorName = &behaviorContents.at(0);
defaultBehaviorName = &behaviorNames.at(0);
}
behavior.UpdateProperty(
behaviorContent.GetContent(), propertyName, *defaultBehaviorName);
behavior.UpdateProperty(propertyName, *defaultBehaviorName);
}
}
}
@@ -614,9 +921,8 @@ 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) {
const gd::Behavior& behavior = object.GetBehavior(behaviorName);
if (behavior.GetTypeName() == type) {
behaviors.push_back(behaviorName);
}
}
@@ -644,18 +950,15 @@ void WholeProjectRefactorer::FindDependentBehaviorNames(
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 gd::Behavior& behavior = object.GetBehavior(objectBehaviorName);
const auto& behaviorMetadata = MetadataProvider::GetBehaviorMetadata(
platform, behaviorContent.GetTypeName());
platform, behavior.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())) {
for (auto const& keyValue : behavior.GetProperties()) {
const gd::String& propertyName = keyValue.first;
const gd::PropertyDescriptor& property = keyValue.second;
if (property.GetType().LowerCase() == "behavior" &&
@@ -679,25 +982,11 @@ WholeProjectRefactorer::FindInvalidRequiredBehaviorProperties(
[&project, &invalidRequiredBehaviorProperties](
const std::vector<std::unique_ptr<gd::Object> >& objectsList) {
for (auto& object : objectsList) {
for (auto& behaviorContentKeyValuePair :
for (auto& behaviorKeyValuePair :
object->GetAllBehaviorContents()) {
gd::BehaviorContent& behaviorContent =
*behaviorContentKeyValuePair.second;
gd::Behavior& behavior = *behaviorKeyValuePair.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())) {
for (auto const& keyValue : behavior.GetProperties()) {
const gd::String& propertyName = keyValue.first;
const gd::PropertyDescriptor& property = keyValue.second;
if (property.GetType().LowerCase() != "behavior") {
@@ -719,7 +1008,7 @@ WholeProjectRefactorer::FindInvalidRequiredBehaviorProperties(
auto problem = UnfilledRequiredBehaviorPropertyProblem(
project,
*object,
behaviorContent,
behavior,
propertyName,
requiredBehaviorType);
invalidRequiredBehaviorProperties.push_back(problem);
@@ -748,21 +1037,15 @@ bool WholeProjectRefactorer::FixInvalidRequiredBehaviorProperties(
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 = problem.GetSourceBehaviorContent();
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)) {
if (MetadataProvider::IsBadBehaviorMetadata(expectedBehaviorMetadata)) {
continue;
}
@@ -772,13 +1055,11 @@ bool WholeProjectRefactorer::FixInvalidRequiredBehaviorProperties(
object,
problem.GetExpectedBehaviorTypeName(),
newBehaviorName);
behavior.UpdateProperty(behaviorContent.GetContent(),
problem.GetSourcePropertyName(),
behavior.UpdateProperty(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]);
@@ -897,6 +1178,115 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
GetBehaviorFullType(eventsFunctionsExtension.GetName(), newBehaviorName));
}
void WholeProjectRefactorer::RenameEventsBasedObject(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::String& oldObjectName,
const gd::String& newObjectName) {
auto& eventsBasedObjects =
eventsFunctionsExtension.GetEventsBasedObjects();
if (!eventsBasedObjects.Has(oldObjectName)) {
gd::LogWarning("Warning, " + oldObjectName +
" was not found when calling RenameEventsBasedObject.");
return;
}
auto& eventsBasedObject = eventsBasedObjects.Get(oldObjectName);
auto renameObjectEventsFunction =
[&project,
&eventsFunctionsExtension,
&oldObjectName,
&newObjectName](const gd::EventsFunction& eventsFunction) {
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
oldObjectName,
eventsFunction.GetName()),
GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
newObjectName,
eventsFunction.GetName()));
ExposeProjectEvents(project, renamer);
} else if (eventsFunction.GetFunctionType() ==
gd::EventsFunction::Expression ||
eventsFunction.GetFunctionType() ==
gd::EventsFunction::StringExpression) {
// Nothing to do, expressions are not including the name of the
// object
}
};
auto renameObjectProperty = [&project,
&eventsFunctionsExtension,
&oldObjectName,
&newObjectName](
const gd::NamedPropertyDescriptor&
property) {
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
oldObjectName,
EventsBasedObject::GetPropertyActionName(property.GetName())),
GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
newObjectName,
EventsBasedObject::GetPropertyActionName(property.GetName())));
ExposeProjectEvents(project, actionRenamer);
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
oldObjectName,
EventsBasedObject::GetPropertyConditionName(property.GetName())),
GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
newObjectName,
EventsBasedObject::GetPropertyConditionName(property.GetName())));
ExposeProjectEvents(project, conditionRenamer);
// Nothing to do for expression, expressions are not including the name of
// the object
};
// 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.
auto& objectEventsFunctions = eventsBasedObject.GetEventsFunctions();
// Object expressions
for (auto&& eventsFunction : objectEventsFunctions.GetInternalVector()) {
if (eventsFunction->GetFunctionType() == gd::EventsFunction::Expression ||
eventsFunction->GetFunctionType() ==
gd::EventsFunction::StringExpression) {
renameObjectEventsFunction(*eventsFunction);
}
}
// Object instructions
for (auto&& eventsFunction : objectEventsFunctions.GetInternalVector()) {
if (eventsFunction->GetFunctionType() == gd::EventsFunction::Action ||
eventsFunction->GetFunctionType() == gd::EventsFunction::Condition) {
renameObjectEventsFunction(*eventsFunction);
}
}
// Object properties
auto& properties = eventsBasedObject.GetPropertyDescriptors();
for (auto&& property : properties.GetInternalVector()) {
renameObjectProperty(*property);
}
DoRenameObject(
project,
GetObjectFullType(eventsFunctionsExtension.GetName(), oldObjectName),
GetObjectFullType(eventsFunctionsExtension.GetName(), newObjectName));
}
void WholeProjectRefactorer::DoRenameEventsFunction(
gd::Project& project,
const gd::EventsFunction& eventsFunction,
@@ -924,18 +1314,9 @@ void WholeProjectRefactorer::DoRenameBehavior(
const gd::String& newBehaviorType) {
auto renameBehaviorTypeInBehaviorContent =
[&oldBehaviorType,
&newBehaviorType](gd::BehaviorContent& behaviorContent) {
if (behaviorContent.GetTypeName() == oldBehaviorType) {
behaviorContent.SetTypeName(newBehaviorType);
}
};
auto renameBehaviorTypeInObjects =
[&renameBehaviorTypeInBehaviorContent](
std::vector<std::unique_ptr<gd::Object> >& objectsList) {
for (auto& object : objectsList) {
for (auto& behaviorContent : object->GetAllBehaviorContents()) {
renameBehaviorTypeInBehaviorContent(*behaviorContent.second);
}
&newBehaviorType](gd::BehaviorConfigurationContainer& behavior) {
if (behavior.GetTypeName() == oldBehaviorType) {
behavior.SetTypeName(newBehaviorType);
}
};
auto renameBehaviorTypeInParameters =
@@ -972,15 +1353,18 @@ void WholeProjectRefactorer::DoRenameBehavior(
}
}
}
// Rename behavior in objects lists.
auto behaviorTypeRenamer = gd::BehaviorTypeRenamer(
project,
oldBehaviorType,
newBehaviorType);
ExposeProjectObjects(project, behaviorTypeRenamer);
// Rename behavior in global objects
renameBehaviorTypeInObjects(project.GetObjects());
// Rename behavior in layout objects and layout behavior shared data.
// Rename behavior in layout behavior shared data.
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
gd::Layout& layout = project.GetLayout(i);
renameBehaviorTypeInObjects(layout.GetObjects());
for (auto& behaviorSharedDataContent : layout.GetAllBehaviorSharedData()) {
renameBehaviorTypeInBehaviorContent(*behaviorSharedDataContent.second);
}
@@ -1003,6 +1387,76 @@ void WholeProjectRefactorer::DoRenameBehavior(
renameBehaviorTypeInParameters(*eventsFunction);
}
}
for (auto&& eventsBasedObject :
eventsFunctionsExtension.GetEventsBasedObjects()
.GetInternalVector()) {
auto& behaviorEventsFunctions = eventsBasedObject->GetEventsFunctions();
for (auto&& eventsFunction :
behaviorEventsFunctions.GetInternalVector()) {
renameBehaviorTypeInParameters(*eventsFunction);
}
}
}
}
void WholeProjectRefactorer::DoRenameObject(
gd::Project& project,
const gd::String& oldObjectType,
const gd::String& newObjectType) {
auto customObjectTypeRenamer = gd::CustomObjectTypeRenamer(
project,
oldObjectType,
newObjectType);
ExposeProjectObjects(project, customObjectTypeRenamer);
auto renameObjectTypeInParameters =
[&oldObjectType, &newObjectType](gd::EventsFunction& eventsFunction) {
for (auto& parameter : eventsFunction.GetParameters()) {
if (gd::ParameterMetadata::IsObject(parameter.GetType()) &&
parameter.GetExtraInfo() == oldObjectType) {
parameter.SetExtraInfo(newObjectType);
}
}
};
// Rename in parameters of (free/behavior) events function
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
e++) {
auto& eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
// Behavior object types
for (auto&& eventsBasedBehavior :
eventsFunctionsExtension.GetEventsBasedBehaviors().GetInternalVector()) {
if (eventsBasedBehavior->GetObjectType() == oldObjectType) {
eventsBasedBehavior->SetObjectType(newObjectType);
}
}
for (auto&& eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
renameObjectTypeInParameters(*eventsFunction);
}
for (auto&& eventsBasedBehavior :
eventsFunctionsExtension.GetEventsBasedBehaviors()
.GetInternalVector()) {
auto& behaviorEventsFunctions = eventsBasedBehavior->GetEventsFunctions();
for (auto&& eventsFunction :
behaviorEventsFunctions.GetInternalVector()) {
renameObjectTypeInParameters(*eventsFunction);
}
}
for (auto&& eventsBasedObject :
eventsFunctionsExtension.GetEventsBasedObjects()
.GetInternalVector()) {
auto& behaviorEventsFunctions = eventsBasedObject->GetEventsFunctions();
for (auto&& eventsFunction :
behaviorEventsFunctions.GetInternalVector()) {
renameObjectTypeInParameters(*eventsFunction);
}
}
}
}
@@ -1123,6 +1577,28 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
}
}
}
void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsBasedObject(
gd::Project& project,
gd::EventsBasedObject& eventsBasedObject,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
const gd::String& objectName,
bool isObjectGroup,
bool removeEventsAndGroups) {
for (auto &functionUniquePtr : eventsBasedObject.GetEventsFunctions().GetInternalVector()) {
auto function = functionUniquePtr.get();
WholeProjectRefactorer::ObjectOrGroupRemovedInEventsFunction(
project,
*function,
globalObjectsContainer,
objectsContainer,
objectName,
isObjectGroup,
isObjectGroup);
}
}
void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsFunction(
gd::Project& project,
gd::EventsFunction& eventsFunction,
@@ -1150,6 +1626,26 @@ void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsFunction(
}
}
void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
gd::Project& project,
gd::ObjectsContainer& globalObjectsContainer,
gd::EventsBasedObject& eventsBasedObject,
const gd::String& oldName,
const gd::String& newName,
bool isObjectGroup) {
for (auto &functionUniquePtr : eventsBasedObject.GetEventsFunctions().GetInternalVector()) {
auto *function = functionUniquePtr.get();
WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
project,
*function,
globalObjectsContainer,
eventsBasedObject,
oldName,
newName,
isObjectGroup);
}
}
void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
gd::Project& project,
gd::EventsFunction& eventsFunction,

View File

@@ -18,11 +18,11 @@ class EventsFunctionsExtension;
class EventsFunction;
class ObjectsContainer;
class EventsBasedBehavior;
class EventsBasedObject;
class ArbitraryEventsWorker;
class ArbitraryObjectsWorker;
class ArbitraryEventsWorkerWithContext;
class Behavior;
class BehaviorContent;
class BehaviorMetadata;
class UnfilledRequiredBehaviorPropertyProblem;
} // namespace gd
@@ -61,13 +61,24 @@ class GD_CORE_API WholeProjectRefactorer {
* \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
* based behavior.
*/
static void ExposeEventsBasedBehaviorEvents(
gd::Project& project,
const gd::EventsBasedBehavior& eventsBasedBehavior,
gd::ArbitraryEventsWorkerWithContext& worker);
/**
* \brief Call the specified worker on all events of the events based object
*
* This should be the preferred way to traverse all the events of an events
* based object.
*/
static void ExposeEventsBasedObjectEvents(
gd::Project& project,
const gd::EventsBasedObject& eventsBasedObject,
gd::ArbitraryEventsWorkerWithContext& worker);
/**
* \brief Call the specified worker on all ObjectContainers of the project
* (global, layouts...)
@@ -119,6 +130,21 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& oldFunctionName,
const gd::String& newFunctionName);
/**
* \brief Refactor the project **before** an events function of an object is
* renamed.
*
* \warning Do the renaming of the specified function after calling this.
* This is because the function is expected to have its old name for the
* refactoring.
*/
static void RenameObjectEventsFunction(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::EventsBasedObject& eventsBasedObject,
const gd::String& oldFunctionName,
const gd::String& newFunctionName);
/**
* \brief Refactor the project **before** an events function parameter
* is moved.
@@ -150,6 +176,22 @@ class GD_CORE_API WholeProjectRefactorer {
std::size_t oldIndex,
std::size_t newIndex);
/**
* \brief Refactor the project **before** the parameter of an events function
* of an object is moved.
*
* \warning Do the move of the specified function parameters after calling
* this. This is because the function is expected to be in its old state for
* the refactoring.
*/
static void MoveObjectEventsFunctionParameter(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::EventsBasedObject& eventsBasedObject,
const gd::String& functionName,
std::size_t oldIndex,
std::size_t newIndex);
/**
* \brief Refactor the project **before** a property of a behavior is
* renamed.
@@ -165,6 +207,21 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& oldPropertyName,
const gd::String& newPropertyName);
/**
* \brief Refactor the project **before** a property of an object is
* renamed.
*
* \warning Do the renaming of the specified property after calling this.
* This is because the property is expected to have its old name for the
* refactoring.
*/
static void RenameEventsBasedObjectProperty(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::EventsBasedObject& eventsBasedObject,
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.
@@ -217,6 +274,19 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& oldBehaviorName,
const gd::String& newBehaviorName);
/**
* \brief Refactor the project **before** an object is renamed.
*
* \warning Do the renaming of the specified object after calling this.
* This is because the object is expected to have its old name for the
* refactoring.
*/
static void RenameEventsBasedObject(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::String& oldObjectName,
const gd::String& newObjectName);
/**
* \brief Refactor the project after an object is renamed in a layout
*
@@ -241,6 +311,34 @@ class GD_CORE_API WholeProjectRefactorer {
bool isObjectGroup,
bool removeEventsAndGroups = true);
/**
* \brief Refactor the project after an object is removed in an events-based
* object.
*
* This will update the events of the function and groups.
*/
static void ObjectOrGroupRemovedInEventsBasedObject(
gd::Project& project,
gd::EventsBasedObject& eventsBasedObject,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
const gd::String& objectName,
bool isObjectGroup,
bool removeEventsAndGroups);
/**
* \brief Refactor the events function after an object or group is renamed
*
* This will update the events of the function and groups.
*/
static void ObjectOrGroupRenamedInEventsBasedObject(
gd::Project& project,
gd::ObjectsContainer& globalObjectsContainer,
gd::EventsBasedObject& eventsBasedObject,
const gd::String& oldName,
const gd::String& newName,
bool isObjectGroup);
/**
* \brief Refactor the events function after an object or group is renamed
*
@@ -309,6 +407,14 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::EventsBasedBehavior& eventsBasedBehavior);
/**
* \brief Ensure (adding if necessary) that the functions of the given
* object have the proper mandatory parameters (the "Object").
*/
static void EnsureObjectEventsFunctionsProperParameters(
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::EventsBasedObject& eventsBasedObject);
virtual ~WholeProjectRefactorer(){};
private:
@@ -324,6 +430,10 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& oldBehaviorType,
const gd::String& newBehaviorType);
static void DoRenameObject(gd::Project& project,
const gd::String& oldObjectType,
const gd::String& newObjectType);
static void FindDependentBehaviorNames(
const gd::Project& project,
const gd::Object& object,
@@ -331,6 +441,7 @@ class GD_CORE_API WholeProjectRefactorer {
std::unordered_set<gd::String>& dependentBehaviorNames);
static const gd::String behaviorObjectParameterName;
static const gd::String parentObjectParameterName;
WholeProjectRefactorer(){};
};

View File

@@ -0,0 +1,42 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "AbstractEventsBasedEntity.h"
#include "EventsFunctionsContainer.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/MakeUnique.h"
namespace gd {
AbstractEventsBasedEntity::AbstractEventsBasedEntity(const gd::String& _name)
: name(_name), fullName("") {}
void AbstractEventsBasedEntity::SerializeTo(SerializerElement& element) const {
element.SetAttribute("description", description);
element.SetAttribute("name", name);
element.SetAttribute("fullName", fullName);
gd::SerializerElement& eventsFunctionsElement =
element.AddChild("eventsFunctions");
eventsFunctionsContainer.SerializeEventsFunctionsTo(eventsFunctionsElement);
propertyDescriptors.SerializeElementsTo(
"propertyDescriptor", element.AddChild("propertyDescriptors"));
}
void AbstractEventsBasedEntity::UnserializeFrom(gd::Project& project,
const SerializerElement& element) {
description = element.GetStringAttribute("description");
name = element.GetStringAttribute("name");
fullName = element.GetStringAttribute("fullName");
const gd::SerializerElement& eventsFunctionsElement =
element.GetChild("eventsFunctions");
eventsFunctionsContainer.UnserializeEventsFunctionsFrom(
project, eventsFunctionsElement);
propertyDescriptors.UnserializeElementsFrom(
"propertyDescriptor", element.GetChild("propertyDescriptors"));
}
} // namespace gd

View File

@@ -0,0 +1,151 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_ABSTRACTEVENTSBASEDENTITY_H
#define GDCORE_ABSTRACTEVENTSBASEDENTITY_H
#include <vector>
#include "GDCore/Project/NamedPropertyDescriptor.h"
#include "GDCore/Tools/SerializableWithNameList.h"
#include "GDCore/Project/EventsFunctionsContainer.h"
#include "GDCore/String.h"
namespace gd {
class SerializerElement;
class Project;
} // namespace gd
namespace gd {
/**
* \brief Represents a behavior or an object that is implemented with events.
*
* It's the responsibility of the IDE to run the logic to transform this into a
* real behavior or object, by declaring an extension and running code generation.
* See `EventsFunctionsExtensionsLoader`.
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API AbstractEventsBasedEntity {
public:
AbstractEventsBasedEntity(const gd::String& _name);
virtual ~AbstractEventsBasedEntity(){};
/**
* \brief Return a pointer to a new AbstractEventsBasedEntity constructed from
* this one.
*/
AbstractEventsBasedEntity* Clone() const { return new AbstractEventsBasedEntity(*this); };
/**
* \brief Get the description of the behavior or object, that is displayed in the
* editor.
*/
const gd::String& GetDescription() const { return description; };
/**
* \brief Set the description of the behavior or object, to be displayed in the editor.
*/
virtual AbstractEventsBasedEntity& SetDescription(const gd::String& description_) {
description = description_;
return *this;
}
/**
* \brief Get the internal name of the behavior or object.
*/
const gd::String& GetName() const { return name; };
/**
* \brief Set the internal name of the behavior or object.
*/
AbstractEventsBasedEntity& SetName(const gd::String& name_) {
name = name_;
return *this;
}
/**
* \brief Get the name of the behavior or object, that is displayed in the editor.
*/
const gd::String& GetFullName() const { return fullName; };
/**
* \brief Set the name of the behavior or object, to be displayed in the editor.
*/
AbstractEventsBasedEntity& SetFullName(const gd::String& fullName_) {
fullName = fullName_;
return *this;
}
/**
* \brief Return a reference to the functions of the events based behavior or object.
*/
EventsFunctionsContainer& GetEventsFunctions() {
return eventsFunctionsContainer;
}
/**
* \brief Return a const reference to the functions of the events based
* behavior or object.
*/
const EventsFunctionsContainer& GetEventsFunctions() const {
return eventsFunctionsContainer;
}
/**
* \brief Return a reference to the list of the properties.
*/
SerializableWithNameList<NamedPropertyDescriptor>& GetPropertyDescriptors() {
return propertyDescriptors;
}
/**
* \brief Return a const reference to the list of the properties.
*/
const SerializableWithNameList<NamedPropertyDescriptor>& GetPropertyDescriptors()
const {
return propertyDescriptors;
}
/**
* \brief Get the name of the action to change a property.
*/
static gd::String GetPropertyActionName(const gd::String& propertyName) { return "SetProperty" + propertyName; };
/**
* \brief Get the name of the condition to compare a property.
*/
static gd::String GetPropertyConditionName(const gd::String& propertyName) { return "Property" + propertyName; };
/**
* \brief Get the name of the expression to get a property.
*/
static gd::String GetPropertyExpressionName(const gd::String& propertyName) { return "Property" + propertyName; };
/** \name Serialization
*/
///@{
/**
* \brief Serialize the AbstractEventsBasedEntity to the specified element
*/
virtual void SerializeTo(gd::SerializerElement& element) const;
/**
* \brief Load the AbstractEventsBasedEntity from the specified element
*/
virtual void UnserializeFrom(gd::Project& project,
const gd::SerializerElement& element);
///@}
private:
gd::String name;
gd::String fullName;
gd::String description;
gd::EventsFunctionsContainer eventsFunctionsContainer;
SerializableWithNameList<NamedPropertyDescriptor> propertyDescriptors;
};
} // namespace gd
#endif // GDCORE_ABSTRACTEVENTSBASEDENTITY_H

View File

@@ -5,20 +5,10 @@
*/
#include "GDCore/Project/Behavior.h"
#include <iostream>
#if defined(GD_IDE_ONLY)
#include "GDCore/Project/PropertyDescriptor.h"
#endif
namespace gd {
Behavior::~Behavior(){};
#if defined(GD_IDE_ONLY)
std::map<gd::String, gd::PropertyDescriptor> Behavior::GetProperties(
const gd::SerializerElement& behaviorContent) const {
std::map<gd::String, gd::PropertyDescriptor> nothing;
return nothing;
}
#endif
} // namespace gd

View File

@@ -5,86 +5,28 @@
*/
#ifndef GDCORE_BEHAVIOR_H
#define GDCORE_BEHAVIOR_H
#include <map>
#include "GDCore/String.h"
#if defined(GD_IDE_ONLY)
namespace gd {
class PropertyDescriptor;
}
#endif
namespace gd {
class SerializerElement;
class Project;
class Layout;
} // namespace gd
#include "GDCore/Project/BehaviorConfigurationContainer.h"
namespace gd {
/**
* \brief Base class used to represents a behavior that can be applied to an
* object
* object. It stores the content (i.e: the properties) of a behavior of an object.
*
* \see gd::BehaviorContent
* \see gd::BehaviorsSharedData
* \see gd::Object
* \ingroup PlatformDefinition
*/
class GD_CORE_API Behavior {
class GD_CORE_API Behavior: public BehaviorConfigurationContainer {
public:
Behavior(){};
Behavior(): BehaviorConfigurationContainer() {};
Behavior(const gd::String& name_, const gd::String& type_)
: BehaviorConfigurationContainer(name_, type_) {};
virtual ~Behavior();
virtual Behavior* Clone() const { return new Behavior(*this); }
/**
* \brief Return the type of the behavior
*/
const gd::String& GetTypeName() const { return type; }
/**
* \brief Set the type of the behavior.
*/
void SetTypeName(const gd::String& type_) { type = type_; };
#if defined(GD_IDE_ONLY)
/**
* \brief Called when the IDE wants to know about the custom properties of the
* behavior.
*
* Implementation example:
\code
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[_("Initial speed")].SetValue(gd::String::From(initialSpeed));
return properties;
\endcode
*
* \return a std::map with properties names as key.
* \see gd::PropertyDescriptor
*/
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
const gd::SerializerElement& behaviorContent) const;
/**
* \brief Called when the IDE wants to update a custom property of the
* behavior
*
* \return false if the new value cannot be set
* \see gd::InitialInstance
*/
virtual bool UpdateProperty(gd::SerializerElement& behaviorContent,
const gd::String& name,
const gd::String& value) {
return false;
};
#endif
/**
* \brief Called to initialize the content with the default properties
* for the behavior.
*/
virtual void InitializeContent(gd::SerializerElement& behaviorContent){};
private:
gd::String type;
virtual Behavior* Clone() const override { return new Behavior(*this); }
};
} // namespace gd

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.
*/
#include "GDCore/Project/BehaviorConfigurationContainer.h"
#include <iostream>
#include "GDCore/Project/PropertyDescriptor.h"
namespace gd {
BehaviorConfigurationContainer::~BehaviorConfigurationContainer(){};
std::map<gd::String, gd::PropertyDescriptor> BehaviorConfigurationContainer::GetProperties() const {
return GetProperties(content);
};
std::map<gd::String, gd::PropertyDescriptor> BehaviorConfigurationContainer::GetProperties(
const gd::SerializerElement& behaviorContent) const {
std::map<gd::String, gd::PropertyDescriptor> nothing;
return nothing;
}
} // namespace gd

View File

@@ -0,0 +1,155 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_BEHAVIORCONFIGURATIONCONTAINER_H
#define GDCORE_BEHAVIORCONFIGURATIONCONTAINER_H
#include <map>
#include <memory>
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/String.h"
namespace gd {
class PropertyDescriptor;
class SerializerElement;
class Project;
class Layout;
} // namespace gd
namespace gd {
/**
* \brief Base class for containers of behavior configuration.
* They can be attached to objects (Behavior) or layouts (BehaviorsSharedData).
* It stores the content (i.e: the properties) of a behavior of an object.
*
* \see gd::Behavior
* \see gd::BehaviorsSharedData
* \ingroup PlatformDefinition
*/
class GD_CORE_API BehaviorConfigurationContainer {
public:
BehaviorConfigurationContainer(){};
BehaviorConfigurationContainer(const gd::String& name_, const gd::String& type_)
: name(name_), type(type_){};
virtual ~BehaviorConfigurationContainer();
virtual BehaviorConfigurationContainer* Clone() const { return new BehaviorConfigurationContainer(*this); }
/**
* \brief Return the name identifying the behavior
*/
const gd::String& GetName() const { return name; }
/**
* \brief Change the name identifying the behavior
*/
void SetName(const gd::String& name_) { name = name_; }
/**
* \brief Return the type of the behavior
*/
const gd::String& GetTypeName() const { return type; }
/**
* \brief Set the type of the behavior.
*/
void SetTypeName(const gd::String& type_) { type = type_; };
/**
* \brief Called when the IDE wants to know about the custom properties of the
* behavior.
*
* \return a std::map with properties names as key.
* \see gd::PropertyDescriptor
*/
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
/**
* \brief Called when the IDE wants to update a custom property of the
* behavior
*
* \return false if the new value cannot be set
* \see gd::InitialInstance
*/
bool UpdateProperty(const gd::String& name, const gd::String& value) {
return UpdateProperty(content, name, value);
};
/**
* \brief Called to initialize the content with the default properties
* for the behavior.
*/
virtual void InitializeContent() {
InitializeContent(content);
};
/**
* \brief Serialize the behavior content.
*/
virtual void SerializeTo(gd::SerializerElement& element) const {
element = content;
};
/**
* \brief Unserialize the behavior content.
*/
virtual void UnserializeFrom(const gd::SerializerElement& element) {
content = element;
};
const gd::SerializerElement& GetContent() const { return content; };
gd::SerializerElement& GetContent() { return content; };
protected:
/**
* \brief Called when the IDE wants to know about the custom properties of the
* behavior.
*
* Implementation example:
\code
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[_("Initial speed")].SetValue(gd::String::From(initialSpeed));
return properties;
\endcode
*
* \return a std::map with properties names as key.
* \see gd::PropertyDescriptor
*/
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
const gd::SerializerElement& behaviorContent) const;
/**
* \brief Called when the IDE wants to update a custom property of the
* behavior
*
* \return false if the new value cannot be set
* \see gd::InitialInstance
*/
virtual bool UpdateProperty(gd::SerializerElement& behaviorContent,
const gd::String& name,
const gd::String& value) {
return false;
};
/**
* \brief Called to initialize the content with the default properties
* for the behavior.
*/
virtual void InitializeContent(gd::SerializerElement& behaviorContent){};
private:
gd::String name; ///< Name of the behavior
gd::String type; ///< The type of the behavior that is represented. Usually
///< in the form "ExtensionName::BehaviorTypeName"
gd::SerializerElement content; // Storage for the behavior properties
};
} // namespace gd
#endif // GDCORE_BEHAVIORCONFIGURATIONCONTAINER_H

View File

@@ -1,12 +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/BehaviorContent.h"
namespace gd {
BehaviorContent::~BehaviorContent(){};
} // namespace gd

View File

@@ -1,88 +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 GDCORE_BEHAVIORCONTENT_H
#define GDCORE_BEHAVIORCONTENT_H
#include <map>
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/String.h"
#if defined(GD_IDE_ONLY)
namespace gd {
class PropertyDescriptor;
}
#endif
namespace gd {
class SerializerElement;
class Project;
class Layout;
} // namespace gd
namespace gd {
/**
* \brief Store the content (i.e: the properties) of a behavior of an object.
*
* \see gd::Behavior
* \see gd::BehaviorsSharedData
* \see gd::Object
* \ingroup PlatformDefinition
*/
class GD_CORE_API BehaviorContent {
public:
BehaviorContent(const gd::String& name_, const gd::String& type_)
: name(name_), type(type_){};
virtual ~BehaviorContent();
virtual BehaviorContent* Clone() const { return new BehaviorContent(*this); }
/**
* \brief Return the name identifying the behavior
*/
virtual const gd::String& GetName() const { return name; }
/**
* \brief Change the name identifying the behavior
*/
virtual void SetName(const gd::String& name_) { name = name_; }
/**
* \brief Get the type of the behavior.
*/
virtual const gd::String& GetTypeName() const { return type; }
/**
* \brief Change the type of the behavior
*/
virtual void SetTypeName(const gd::String& type_) { type = type_; }
#if defined(GD_IDE_ONLY)
/**
* \brief Serialize the behavior content.
*/
virtual void SerializeTo(gd::SerializerElement& element) const {
element = content;
};
#endif
/**
* \brief Unserialize the behavior content.
*/
virtual void UnserializeFrom(const gd::SerializerElement& element) {
content = element;
};
const gd::SerializerElement& GetContent() const { return content; };
gd::SerializerElement& GetContent() { return content; };
protected:
gd::String name; ///< Name of the behavior
gd::String type; ///< The type of the behavior that is represented. Usually
///< in the form "ExtensionName::BehaviorTypeName"
gd::SerializerElement content; // Storage for the behavior properties
};
} // namespace gd
#endif // GDCORE_BEHAVIORCONTENT_H

View File

@@ -5,21 +5,11 @@
*/
#include "GDCore/Project/BehaviorsSharedData.h"
#if defined(GD_IDE_ONLY)
#include <map>
#include "GDCore/Project/PropertyDescriptor.h"
#endif
namespace gd {
BehaviorsSharedData::~BehaviorsSharedData(){};
#if defined(GD_IDE_ONLY)
std::map<gd::String, gd::PropertyDescriptor> BehaviorsSharedData::GetProperties(
const gd::SerializerElement& behaviorSharedDataContent) const {
std::map<gd::String, gd::PropertyDescriptor> nothing;
return nothing;
}
#endif
} // namespace gd

View File

@@ -4,19 +4,11 @@
* reserved. This project is released under the MIT License.
*/
#ifndef BEHAVIORSSHAREDDATA_H
#define BEHAVIORSSHAREDDATA_H
#ifndef GDCORE_BEHAVIORSSHAREDDATA_H
#define GDCORE_BEHAVIORSSHAREDDATA_H
#include <map>
#include <memory>
#include "GDCore/String.h"
class BehaviorsRuntimeSharedData;
namespace gd {
class SerializerElement;
class PropertyDescriptor;
class Project;
class Layout;
} // namespace gd
#include "GDCore/Project/BehaviorConfigurationContainer.h"
namespace gd {
@@ -29,63 +21,15 @@ namespace gd {
*
* \ingroup GameEngine
*/
class GD_CORE_API BehaviorsSharedData {
class GD_CORE_API BehaviorsSharedData: public BehaviorConfigurationContainer {
public:
BehaviorsSharedData(){};
BehaviorsSharedData(): BehaviorConfigurationContainer() {};
BehaviorsSharedData(const gd::String& name_, const gd::String& type_)
: BehaviorConfigurationContainer(name_, type_) {};
virtual ~BehaviorsSharedData();
virtual gd::BehaviorsSharedData* Clone() const {
return new BehaviorsSharedData(*this);
}
/**
* \brief Return the name identifying the type of the behavior
*/
gd::String GetTypeName() { return type; }
/**
* \brief Change name identifying the type of the behavior.
*/
void SetTypeName(const gd::String& type_) { type = type_; };
#if defined(GD_IDE_ONLY)
/**
* \brief Called when the IDE wants to know about the properties of the shared
data.
*
* Usage example:
\code
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[_("Initial speed")].SetValue(gd::String::From(initialSpeed));
return properties;
\endcode
*
* \return a std::map with properties names as key.
* \see gd::PropertyDescriptor
*/
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
const gd::SerializerElement& behaviorSharedDataContent) const;
/**
* \brief Called when the IDE wants to update a property of the shared data
*
* \return false if the new value cannot be set
* \see gd::InitialInstance
*/
virtual bool UpdateProperty(gd::SerializerElement& behaviorSharedDataContent,
const gd::String& name,
const gd::String& value) {
return false;
};
#endif
virtual void InitializeContent(
gd::SerializerElement& behaviorSharedDataContent){};
private:
gd::String type; ///< The type indicate of which type is the behavior.
virtual BehaviorsSharedData* Clone() const override { return new BehaviorsSharedData(*this); }
};
} // namespace gd
#endif // BEHAVIORSSHAREDDATA_H
#endif // GDCORE_BEHAVIORSSHAREDDATA_H

View File

@@ -0,0 +1,119 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "CustomBehavior.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Serialization/SerializerElement.h"
#include <map>
using namespace gd;
CustomBehavior *CustomBehavior::Clone() const {
CustomBehavior *clone = new CustomBehavior(*this);
return clone;
}
std::map<gd::String, gd::PropertyDescriptor> CustomBehavior::GetProperties(
const gd::SerializerElement &behaviorContent) const {
auto behaviorProperties = std::map<gd::String, gd::PropertyDescriptor>();
if (!project.HasEventsBasedBehavior(GetTypeName())) {
return behaviorProperties;
}
const auto &eventsBasedBehavior = project.GetEventsBasedBehavior(GetTypeName());
const auto &properties = eventsBasedBehavior.GetPropertyDescriptors();
for (auto &property : properties.GetInternalVector()) {
const auto &propertyName = property->GetName();
const auto &propertyType = property->GetType();
// TODO Move this into a PropertyDescriptor copy method.
auto &newProperty = behaviorProperties[propertyName]
.SetType(property->GetType())
.SetDescription(property->GetDescription())
.SetGroup(property->GetGroup())
.SetLabel(property->GetLabel())
.SetValue(property->GetValue())
.SetHidden(property->IsHidden());
for (auto &extraInfo : property->GetExtraInfo()) {
newProperty.AddExtraInfo(extraInfo);
}
if (behaviorContent.HasChild(propertyName)) {
if (propertyType == "String" || propertyType == "Choice" ||
propertyType == "Color" || propertyType == "Behavior") {
newProperty.SetValue(
behaviorContent.GetChild(propertyName).GetStringValue());
} else if (propertyType == "Number") {
newProperty.SetValue(gd::String::From(
behaviorContent.GetChild(propertyName).GetDoubleValue()));
} else if (propertyType == "Boolean") {
newProperty.SetValue(
behaviorContent.GetChild(propertyName).GetBoolValue() ? "true"
: "false");
}
} else {
// No value was serialized for this property. `newProperty`
// will have the default value coming from `enumeratedProperty`.
}
}
return behaviorProperties;
}
bool CustomBehavior::UpdateProperty(gd::SerializerElement &behaviorContent,
const gd::String &propertyName,
const gd::String &newValue) {
if (!project.HasEventsBasedBehavior(GetTypeName())) {
return false;
}
const auto &eventsBasedBehavior = project.GetEventsBasedBehavior(GetTypeName());
const auto &properties = eventsBasedBehavior.GetPropertyDescriptors();
if (!properties.Has(propertyName)) {
return false;
}
const auto &property = properties.Get(propertyName);
auto &element = behaviorContent.AddChild(propertyName);
const gd::String &propertyType = property.GetType();
if (propertyType == "String" || propertyType == "Choice" ||
propertyType == "Color" || propertyType == "Behavior") {
element.SetStringValue(newValue);
} else if (propertyType == "Number") {
element.SetDoubleValue(newValue.To<double>());
} else if (propertyType == "Boolean") {
element.SetBoolValue(newValue == "1");
}
return true;
}
void CustomBehavior::InitializeContent(gd::SerializerElement &behaviorContent) {
if (!project.HasEventsBasedBehavior(GetTypeName())) {
return;
}
const auto &eventsBasedBehavior = project.GetEventsBasedBehavior(GetTypeName());
const auto &properties = eventsBasedBehavior.GetPropertyDescriptors();
for (auto &&property : properties.GetInternalVector()) {
auto &element = behaviorContent.AddChild(property->GetName());
auto propertyType = property->GetType();
if (propertyType == "String" || propertyType == "Choice" ||
propertyType == "Color" || propertyType == "Behavior") {
element.SetStringValue(property->GetValue());
} else if (propertyType == "Number") {
element.SetDoubleValue(property->GetValue().To<double>());
} else if (propertyType == "Boolean") {
element.SetBoolValue(property->GetValue() == "true");
}
}
}

View File

@@ -0,0 +1,51 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_CUSTOMBEHAVIOR_H
#define GDCORE_CUSTOMBEHAVIOR_H
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Serialization/SerializerElement.h"
using namespace gd;
namespace gd {
/**
* \brief A gd::Behavior that stores its content in JSON and forward the
* properties related functions to Javascript with Emscripten.
*/
class CustomBehavior : public gd::Behavior {
public:
CustomBehavior(const gd::String &name,
const Project &project_,
const gd::String &fullType)
: Behavior(name, fullType),
project(project_) {}
CustomBehavior *Clone() const override;
using Behavior::GetProperties;
using Behavior::InitializeContent;
using Behavior::UpdateProperty;
protected:
virtual std::map<gd::String, gd::PropertyDescriptor>
GetProperties(const gd::SerializerElement &behaviorContent) const override;
virtual bool UpdateProperty(gd::SerializerElement &behaviorContent,
const gd::String &name,
const gd::String &value) override;
virtual void
InitializeContent(gd::SerializerElement &behaviorContent) override;
private:
const Project &project; ///< The project is used to get the
///< EventBasedBehavior from the fullType.
};
} // namespace gd
#endif // GDCORE_CUSTOMBEHAVIOR_H

View File

@@ -0,0 +1,230 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "CustomObjectConfiguration.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/Log.h"
using namespace gd;
void CustomObjectConfiguration::Init(const gd::CustomObjectConfiguration& objectConfiguration) {
project = objectConfiguration.project;
objectContent = objectConfiguration.objectContent;
// There is no default copy for a map of unique_ptr like childObjectConfigurations.
childObjectConfigurations.clear();
for (auto& it : objectConfiguration.childObjectConfigurations) {
childObjectConfigurations[it.first] =
gd::make_unique<gd::ObjectConfiguration>(*it.second);
}
}
gd::ObjectConfiguration CustomObjectConfiguration::badObjectConfiguration;
std::unique_ptr<gd::ObjectConfiguration> CustomObjectConfiguration::Clone() const {
CustomObjectConfiguration* clone = new CustomObjectConfiguration(*this);
return std::unique_ptr<gd::ObjectConfiguration>(clone);
}
gd::ObjectConfiguration &CustomObjectConfiguration::GetChildObjectConfiguration(const gd::String &objectName) {
if (!project->HasEventsBasedObject(GetType())) {
return badObjectConfiguration;
}
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
if (!eventsBasedObject.HasObjectNamed(objectName)) {
gd::LogError("Tried to get the configuration of a child-object:" + objectName
+ " that doesn't exist in the event-based object: " + GetType());
return badObjectConfiguration;
}
auto &childObject = eventsBasedObject.GetObject(objectName);
auto configurationPosition = childObjectConfigurations.find(objectName);
if (configurationPosition == childObjectConfigurations.end()) {
childObjectConfigurations.insert(std::make_pair(
objectName,
project->CreateObjectConfiguration(childObject.GetType())));
return *(childObjectConfigurations[objectName]);
}
else {
auto &pair = *configurationPosition;
auto &configuration = pair.second;
return *configuration;
}
}
std::map<gd::String, gd::PropertyDescriptor> CustomObjectConfiguration::GetProperties() const {
auto objectProperties = std::map<gd::String, gd::PropertyDescriptor>();
if (!project->HasEventsBasedObject(GetType())) {
return objectProperties;
}
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
const auto &properties = eventsBasedObject.GetPropertyDescriptors();
for (auto &property : properties.GetInternalVector()) {
const auto &propertyName = property->GetName();
const auto &propertyType = property->GetType();
// TODO Move this into a PropertyDescriptor copy method.
auto &newProperty = objectProperties[propertyName]
.SetType(property->GetType())
.SetDescription(property->GetDescription())
.SetGroup(property->GetGroup())
.SetLabel(property->GetLabel())
.SetValue(property->GetValue())
.SetHidden(property->IsHidden());
for (auto &extraInfo : property->GetExtraInfo()) {
newProperty.AddExtraInfo(extraInfo);
}
if (objectContent.HasChild(propertyName)) {
if (
propertyType == "String" ||
propertyType == "Choice" ||
propertyType == "Color"
) {
newProperty.SetValue(
objectContent.GetChild(propertyName).GetStringValue()
);
} else if (propertyType == "Number") {
newProperty.SetValue(
gd::String::From(objectContent.GetChild(propertyName).GetDoubleValue())
);
} else if (propertyType == "Boolean") {
newProperty.SetValue(
objectContent.GetChild(propertyName).GetBoolValue()
? "true"
: "false"
);
}
} else {
// No value was serialized for this property. `newProperty`
// will have the default value coming from `enumeratedProperty`.
}
}
return objectProperties;
}
bool CustomObjectConfiguration::UpdateProperty(const gd::String& propertyName,
const gd::String& newValue) {
if (!project->HasEventsBasedObject(GetType())) {
return false;
}
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
const auto &properties = eventsBasedObject.GetPropertyDescriptors();
if (!properties.Has(propertyName)) {
return false;
}
const auto &property = properties.Get(propertyName);
auto &element = objectContent.AddChild(propertyName);
const gd::String &propertyType = property.GetType();
if (
propertyType == "String" ||
propertyType == "Choice" ||
propertyType == "Color"
) {
element.SetStringValue(newValue);
} else if (propertyType == "Number") {
element.SetDoubleValue(newValue.To<double>());
} else if (propertyType == "Boolean") {
element.SetBoolValue(newValue == "1");
}
return true;
}
std::map<gd::String, gd::PropertyDescriptor>
CustomObjectConfiguration::GetInitialInstanceProperties(
const gd::InitialInstance& instance,
gd::Project& project,
gd::Layout& scene) {
return std::map<gd::String, gd::PropertyDescriptor>();
}
bool CustomObjectConfiguration::UpdateInitialInstanceProperty(
gd::InitialInstance& instance,
const gd::String& name,
const gd::String& value,
gd::Project& project,
gd::Layout& scene) {
return false;
}
void CustomObjectConfiguration::DoSerializeTo(SerializerElement& element) const {
element.AddChild("content") = objectContent;
auto &childrenContentElement = element.AddChild("childrenContent");
for (auto &pair : childObjectConfigurations) {
auto &childName = pair.first;
auto &childConfiguration = pair.second;
auto &childElement = childrenContentElement.AddChild(childName);
childConfiguration->SerializeTo(childElement);
}
}
void CustomObjectConfiguration::DoUnserializeFrom(Project& project,
const SerializerElement& element) {
objectContent = element.GetChild("content");
auto &childrenContentElement = element.GetChild("childrenContent");
for (auto &pair : childrenContentElement.GetAllChildren()) {
auto &childName = pair.first;
auto &childElement = pair.second;
auto &childConfiguration = GetChildObjectConfiguration(childName);
childConfiguration.UnserializeFrom(project, *childElement);
}
}
void CustomObjectConfiguration::ExposeResources(
gd::ArbitraryResourceWorker& worker) {
std::map<gd::String, gd::PropertyDescriptor> properties = GetProperties();
for (auto& property : properties) {
const String& propertyName = property.first;
const gd::PropertyDescriptor& propertyDescriptor = property.second;
if (propertyDescriptor.GetType() == "resource") {
auto& extraInfo = propertyDescriptor.GetExtraInfo();
const gd::String& resourceType = extraInfo.empty() ? "" : extraInfo[0];
const gd::String& oldPropertyValue = propertyDescriptor.GetValue();
gd::String newPropertyValue = oldPropertyValue;
if (resourceType == "image") {
worker.ExposeImage(newPropertyValue);
} else if (resourceType == "audio") {
worker.ExposeAudio(newPropertyValue);
} else if (resourceType == "font") {
worker.ExposeFont(newPropertyValue);
} else if (resourceType == "video") {
worker.ExposeVideo(newPropertyValue);
} else if (resourceType == "json") {
worker.ExposeJson(newPropertyValue);
} else if (resourceType == "bitmapFont") {
worker.ExposeBitmapFont(newPropertyValue);
}
if (newPropertyValue != oldPropertyValue) {
UpdateProperty(propertyName, newPropertyValue);
}
}
}
auto objectProperties = std::map<gd::String, gd::PropertyDescriptor>();
if (!project->HasEventsBasedObject(GetType())) {
return;
}
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
for (auto& childObject : eventsBasedObject.GetObjects()) {
auto &configuration = GetChildObjectConfiguration(childObject->GetName());
configuration.ExposeResources(worker);
}
}

View File

@@ -0,0 +1,100 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_CUSTOMOBJECTCONFIGURATION_H
#define GDCORE_CUSTOMOBJECTCONFIGURATION_H
#include "GDCore/Project/ObjectConfiguration.h"
#include <map>
#include <memory>
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Serialization/SerializerElement.h"
using namespace gd;
namespace gd {
/**
* \brief A gd::ObjectConfiguration that stores its content in JSON and is
* composed of other configuration according to it's object children.
*
* It also implements "ExposeResources" to expose the properties of type
* "resource".
*/
class CustomObjectConfiguration : public gd::ObjectConfiguration {
public:
CustomObjectConfiguration(const Project& project_, const String& type_)
: project(&project_) {
SetType(type_);
}
std::unique_ptr<gd::ObjectConfiguration> Clone() const override;
/**
* Copy constructor. Calls Init().
*/
CustomObjectConfiguration(const gd::CustomObjectConfiguration& object)
: ObjectConfiguration(object) {
Init(object);
};
/**
* Assignment operator. Calls Init().
*/
CustomObjectConfiguration& operator=(const gd::CustomObjectConfiguration& object){
if ((this) != &object) {
ObjectConfiguration::operator=(object);
Init(object);
}
return *this;
}
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
bool UpdateProperty(const gd::String& name, const gd::String& value) override;
std::map<gd::String, gd::PropertyDescriptor> GetInitialInstanceProperties(
const gd::InitialInstance& instance,
gd::Project& project,
gd::Layout& scene) override;
bool UpdateInitialInstanceProperty(gd::InitialInstance& instance,
const gd::String& name,
const gd::String& value,
gd::Project& project,
gd::Layout& scene) override;
void ExposeResources(gd::ArbitraryResourceWorker& worker) override;
gd::ObjectConfiguration &GetChildObjectConfiguration(const gd::String& objectName);
protected:
void DoSerializeTo(SerializerElement& element) const override;
void DoUnserializeFrom(Project& project, const SerializerElement& element) override;
private:
const Project* project; ///< The project is used to get the
///< EventBasedObject from the fullType.
gd::SerializerElement objectContent;
std::map<gd::String, std::unique_ptr<gd::ObjectConfiguration>> childObjectConfigurations;
static gd::ObjectConfiguration badObjectConfiguration;
/**
* Initialize configuration using another configuration. Used by copy-ctor
* and assign-op.
*
* Don't forget to update me if members were changed!
*
* It's needed because there is no default copy for childObjectConfigurations
* and it must be a deep copy.
*/
void Init(const gd::CustomObjectConfiguration& object);
};
} // namespace gd
#endif // GDCORE_CUSTOMOBJECTCONFIGURATION_H

View File

@@ -3,7 +3,6 @@
* 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 "EventsBasedBehavior.h"
#include "EventsFunctionsContainer.h"
#include "GDCore/Serialization/SerializerElement.h"
@@ -12,36 +11,17 @@
namespace gd {
EventsBasedBehavior::EventsBasedBehavior()
: name("MyBehavior"), fullName("") {}
: AbstractEventsBasedEntity("MyBehavior") {}
void EventsBasedBehavior::SerializeTo(SerializerElement& element) const {
element.SetAttribute("description", description);
element.SetAttribute("name", name);
element.SetAttribute("fullName", fullName);
AbstractEventsBasedEntity::SerializeTo(element);
element.SetAttribute("objectType", objectType);
gd::SerializerElement& eventsFunctionsElement =
element.AddChild("eventsFunctions");
eventsFunctionsContainer.SerializeEventsFunctionsTo(eventsFunctionsElement);
propertyDescriptors.SerializeElementsTo(
"propertyDescriptor", element.AddChild("propertyDescriptors"));
}
void EventsBasedBehavior::UnserializeFrom(gd::Project& project,
const SerializerElement& element) {
description = element.GetStringAttribute("description");
name = element.GetStringAttribute("name");
fullName = element.GetStringAttribute("fullName");
AbstractEventsBasedEntity::UnserializeFrom(project, element);
objectType = element.GetStringAttribute("objectType");
const gd::SerializerElement& eventsFunctionsElement =
element.GetChild("eventsFunctions");
eventsFunctionsContainer.UnserializeEventsFunctionsFrom(
project, eventsFunctionsElement);
propertyDescriptors.UnserializeElementsFrom(
"propertyDescriptor", element.GetChild("propertyDescriptors"));
}
} // namespace gd
#endif

View File

@@ -3,11 +3,11 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#ifndef GDCORE_EVENTSBASEDBEHAVIOR_H
#define GDCORE_EVENTSBASEDBEHAVIOR_H
#include <vector>
#include "GDCore/Project/AbstractEventsBasedEntity.h"
#include "GDCore/Project/NamedPropertyDescriptor.h"
#include "GDCore/Tools/SerializableWithNameList.h"
#include "GDCore/Project/EventsFunctionsContainer.h"
@@ -28,7 +28,7 @@ namespace gd {
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API EventsBasedBehavior {
class GD_CORE_API EventsBasedBehavior: public AbstractEventsBasedEntity {
public:
EventsBasedBehavior();
virtual ~EventsBasedBehavior(){};
@@ -39,43 +39,24 @@ class GD_CORE_API EventsBasedBehavior {
*/
EventsBasedBehavior* Clone() const { return new EventsBasedBehavior(*this); };
/**
* \brief Get the description of the behavior, that is displayed in the
* editor.
*/
const gd::String& GetDescription() const { return description; };
/**
* \brief Set the description of the behavior, to be displayed in the editor.
*/
EventsBasedBehavior& SetDescription(const gd::String& description_) {
description = description_;
EventsBasedBehavior& SetDescription(const gd::String& description_) override {
AbstractEventsBasedEntity::SetDescription(description_);
return *this;
}
/**
* \brief Get the internal name of the behavior.
*/
const gd::String& GetName() const { return name; };
/**
* \brief Set the internal name of the behavior.
*/
EventsBasedBehavior& SetName(const gd::String& name_) {
name = name_;
AbstractEventsBasedEntity::SetName(name_);
return *this;
}
/**
* \brief Get the name of the behavior, that is displayed in the editor.
*/
const gd::String& GetFullName() const { return fullName; };
/**
* \brief Set the name of the behavior, to be displayed in the editor.
*/
EventsBasedBehavior& SetFullName(const gd::String& fullName_) {
fullName = fullName_;
AbstractEventsBasedEntity::SetFullName(fullName_);
return *this;
}
@@ -92,76 +73,15 @@ class GD_CORE_API EventsBasedBehavior {
return *this;
}
/**
* \brief Return a reference to the functions of the events based behavior.
*/
EventsFunctionsContainer& GetEventsFunctions() {
return eventsFunctionsContainer;
}
void SerializeTo(SerializerElement& element) const override;
/**
* \brief Return a const reference to the functions of the events based
* behavior.
*/
const EventsFunctionsContainer& GetEventsFunctions() const {
return eventsFunctionsContainer;
}
/**
* \brief Return a reference to the list of the properties.
*/
SerializableWithNameList<NamedPropertyDescriptor>& GetPropertyDescriptors() {
return propertyDescriptors;
}
/**
* \brief Return a const reference to the list of the properties.
*/
const SerializableWithNameList<NamedPropertyDescriptor>& GetPropertyDescriptors()
const {
return propertyDescriptors;
}
/**
* \brief Get the name of the action to change a property.
*/
static gd::String GetPropertyActionName(const gd::String& propertyName) { return "SetProperty" + propertyName; };
/**
* \brief Get the name of the condition to compare a property.
*/
static gd::String GetPropertyConditionName(const gd::String& propertyName) { return "Property" + propertyName; };
/**
* \brief Get the name of the expression to get a property.
*/
static gd::String GetPropertyExpressionName(const gd::String& propertyName) { return "Property" + propertyName; };
/** \name Serialization
*/
///@{
/**
* \brief Serialize the EventsBasedBehavior to the specified element
*/
void SerializeTo(gd::SerializerElement& element) const;
/**
* \brief Load the EventsBasedBehavior from the specified element
*/
void UnserializeFrom(gd::Project& project,
const gd::SerializerElement& element);
///@}
const SerializerElement& element) override;
private:
gd::String name;
gd::String fullName;
gd::String description;
gd::String objectType;
gd::EventsFunctionsContainer eventsFunctionsContainer;
SerializableWithNameList<NamedPropertyDescriptor> propertyDescriptors;
};
} // namespace gd
#endif // GDCORE_EVENTSBASEDBEHAVIOR_H
#endif

View File

@@ -0,0 +1,36 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "EventsBasedObject.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Serialization/SerializerElement.h"
namespace gd {
EventsBasedObject::EventsBasedObject()
: AbstractEventsBasedEntity("MyObject"), ObjectsContainer() {
}
EventsBasedObject::~EventsBasedObject() {}
EventsBasedObject::EventsBasedObject(const gd::EventsBasedObject &_eventBasedObject)
: AbstractEventsBasedEntity(_eventBasedObject) {
// TODO Add a copy constructor in ObjectsContainer.
initialObjects = gd::Clone(_eventBasedObject.initialObjects);
objectGroups = _eventBasedObject.objectGroups;
}
void EventsBasedObject::SerializeTo(SerializerElement& element) const {
AbstractEventsBasedEntity::SerializeTo(element);
SerializeObjectsTo(element.AddChild("objects"));
}
void EventsBasedObject::UnserializeFrom(gd::Project& project,
const SerializerElement& element) {
AbstractEventsBasedEntity::UnserializeFrom(project, element);
UnserializeObjectsFrom(project, element.GetChild("objects"));
}
} // namespace gd

View File

@@ -0,0 +1,72 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EVENTSBASEDOBJECT_H
#define GDCORE_EVENTSBASEDOBJECT_H
#include <vector>
#include "GDCore/Project/AbstractEventsBasedEntity.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/String.h"
namespace gd {
class SerializerElement;
class Project;
} // namespace gd
namespace gd {
// TODO EBO Add a way to mark some parts of children configuration as readonly.
/**
* \brief Represents an object that is implemented with events.
*
* It's the responsibility of the IDE to run the logic to transform this into a
* real object, by declaring an extension and running code generation.
* See `EventsFunctionsExtensionsLoader`.
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public ObjectsContainer {
public:
EventsBasedObject();
virtual ~EventsBasedObject();
EventsBasedObject(const gd::EventsBasedObject &_eventBasedObject);
/**
* \brief Return a pointer to a new EventsBasedObject constructed from
* this one.
*/
EventsBasedObject* Clone() const { return new EventsBasedObject(*this); };
EventsBasedObject& SetDescription(const gd::String& description_) override {
AbstractEventsBasedEntity::SetDescription(description_);
return *this;
}
/**
* \brief Set the internal name of the object.
*/
EventsBasedObject& SetName(const gd::String& name_) {
AbstractEventsBasedEntity::SetName(name_);
return *this;
}
/**
* \brief Set the name of the object, to be displayed in the editor.
*/
EventsBasedObject& SetFullName(const gd::String& fullName_) {
AbstractEventsBasedEntity::SetFullName(fullName_);
return *this;
}
void SerializeTo(SerializerElement& element) const override;
void UnserializeFrom(gd::Project& project,
const SerializerElement& element) override;
private:
};
} // namespace gd
#endif // GDCORE_EVENTSBASEDOBJECT_H

View File

@@ -6,6 +6,7 @@
#include "EventsFunctionsExtension.h"
#include "EventsBasedBehavior.h"
#include "EventsBasedObject.h"
#include "EventsFunction.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/MakeUnique.h"
@@ -42,6 +43,7 @@ void EventsFunctionsExtension::Init(const gd::EventsFunctionsExtension& other) {
helpPath = other.helpPath;
EventsFunctionsContainer::Init(other);
eventsBasedBehaviors = other.eventsBasedBehaviors;
eventsBasedObjects = other.eventsBasedObjects;
}
void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
@@ -79,9 +81,17 @@ void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
SerializeEventsFunctionsTo(element.AddChild("eventsFunctions"));
eventsBasedBehaviors.SerializeElementsTo(
"eventsBasedBehavior", element.AddChild("eventsBasedBehaviors"));
eventsBasedObjects.SerializeElementsTo(
"eventsBasedObject", element.AddChild("eventsBasedObjects"));
}
void EventsFunctionsExtension::UnserializeFrom(
gd::Project& project, const SerializerElement& element) {
UnserializeExtensionDeclarationFrom(project, element);
UnserializeExtensionImplementationFrom(project, element);
}
void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
gd::Project& project, const SerializerElement& element) {
version = element.GetStringAttribute("version");
extensionNamespace = element.GetStringAttribute("extensionNamespace");
@@ -134,9 +144,48 @@ void EventsFunctionsExtension::UnserializeFrom(
dependencies.push_back(
UnserializeDependencyFrom(dependenciesElement.GetChild(i)));
// Only unserialize behaviors and objects names.
// As event based objects can contains objects using CustomBehavior and/or
// CustomObject, this allows them to reference EventBasedBehavior and
// EventBasedObject respectively.
auto &behaviorsElement = element.GetChild("eventsBasedBehaviors");
behaviorsElement.ConsiderAsArrayOf("eventsBasedBehavior");
for (std::size_t i = 0; i < behaviorsElement.GetChildrenCount(); ++i) {
const gd::String &behaviorName =
behaviorsElement.GetChild(i).GetStringAttribute("name");
eventsBasedBehaviors.InsertNew(behaviorName, eventsBasedBehaviors.GetCount());
}
auto &objectsElement = element.GetChild("eventsBasedObjects");
objectsElement.ConsiderAsArrayOf("eventsBasedObject");
for (std::size_t i = 0; i < objectsElement.GetChildrenCount(); ++i) {
const gd::String &objectName =
objectsElement.GetChild(i).GetStringAttribute("name");
eventsBasedObjects.InsertNew(objectName, eventsBasedObjects.GetCount());
}
}
void EventsFunctionsExtension::UnserializeExtensionImplementationFrom(
gd::Project& project,
const SerializerElement& element) {
UnserializeEventsFunctionsFrom(project, element.GetChild("eventsFunctions"));
eventsBasedBehaviors.UnserializeElementsFrom(
"eventsBasedBehavior", project, element.GetChild("eventsBasedBehaviors"));
auto &behaviorsElement = element.GetChild("eventsBasedBehaviors");
behaviorsElement.ConsiderAsArrayOf("eventsBasedBehavior");
for (std::size_t i = 0; i < behaviorsElement.GetChildrenCount(); ++i) {
const gd::String &behaviorName =
behaviorsElement.GetChild(i).GetStringAttribute("name");
if (eventsBasedBehaviors.Has(behaviorName)) {
eventsBasedBehaviors.Get(behaviorName).UnserializeFrom(project, behaviorsElement.GetChild(i));
}
}
auto &objectsElement = element.GetChild("eventsBasedObjects");
objectsElement.ConsiderAsArrayOf("eventsBasedObject");
for (std::size_t i = 0; i < objectsElement.GetChildrenCount(); ++i) {
const gd::String &objectName =
objectsElement.GetChild(i).GetStringAttribute("name");
if (eventsBasedObjects.Has(objectName)) {
eventsBasedObjects.Get(objectName).UnserializeFrom(project, objectsElement.GetChild(i));
}
}
}
bool EventsFunctionsExtension::IsExtensionLifecycleEventsFunction(

View File

@@ -10,6 +10,7 @@
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/EventsFunctionsContainer.h"
#include "GDCore/String.h"
#include "GDCore/Tools/SerializableWithNameList.h"
@@ -145,6 +146,21 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
return eventsBasedBehaviors;
}
/**
* \brief Return a reference to the list of the events based objects.
*/
gd::SerializableWithNameList<EventsBasedObject>& GetEventsBasedObjects() {
return eventsBasedObjects;
}
/**
* \brief Return a const reference to the list of the events based objects.
*/
const gd::SerializableWithNameList<EventsBasedObject>&
GetEventsBasedObjects() const {
return eventsBasedObjects;
}
/**
* \brief Sets an extension origin. This method is not present since the
* beginning so the projects created before that will have extensions
@@ -200,10 +216,26 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
void SerializeTo(gd::SerializerElement& element) const;
/**
* \brief Load the EventsFunctionsExtension from the specified element
* \brief Load the EventsFunctionsExtension from the specified element.
*/
void UnserializeFrom(gd::Project& project,
const gd::SerializerElement& element);
/**
* \brief Load the extension without free functions, behaviors and objects
* implementation.
*/
void UnserializeExtensionDeclarationFrom(
gd::Project& project,
const gd::SerializerElement& element);
/**
* \brief Load free functions, behaviors and objects implementation
* (in opposition to load just their "declaration" by reading their name).
*/
void UnserializeExtensionImplementationFrom(
gd::Project& project,
const gd::SerializerElement& element);
///@}
/** \name Lifecycle event functions
@@ -255,6 +287,7 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
gd::String helpPath; ///< The relative path to the help for this extension in
///< the documentation (or an absolute URL).
gd::SerializableWithNameList<EventsBasedBehavior> eventsBasedBehaviors;
gd::SerializableWithNameList<EventsBasedObject> eventsBasedObjects;
std::vector<gd::DependencyMetadata> dependencies;
};

View File

@@ -11,9 +11,7 @@
#include "GDCore/Project/Project.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/UUID/UUID.h"
#if defined(GD_IDE_ONLY)
#include "GDCore/Project/PropertyDescriptor.h"
#endif
namespace gd {
@@ -30,6 +28,7 @@ InitialInstance::InitialInstance()
width(0),
height(0),
locked(false),
sealed(false),
persistentUuid(UUID::MakeUuid4()) {}
void InitialInstance::UnserializeFrom(const SerializerElement& element) {
@@ -44,6 +43,7 @@ void InitialInstance::UnserializeFrom(const SerializerElement& element) {
SetZOrder(element.GetIntAttribute("zOrder", 0, "plan"));
SetLayer(element.GetStringAttribute("layer"));
SetLocked(element.GetBoolAttribute("locked", false));
SetSealed(element.GetBoolAttribute("sealed", false));
persistentUuid = element.GetStringAttribute("persistentUuid");
if (persistentUuid.empty()) ResetPersistentUuid();
@@ -83,7 +83,8 @@ void InitialInstance::SerializeTo(SerializerElement& element) const {
element.SetAttribute("customSize", HasCustomSize());
element.SetAttribute("width", GetCustomWidth());
element.SetAttribute("height", GetCustomHeight());
element.SetAttribute("locked", IsLocked());
if (IsLocked()) element.SetAttribute("locked", IsLocked());
if (IsSealed()) element.SetAttribute("sealed", IsSealed());
if (persistentUuid.empty()) persistentUuid = UUID::MakeUuid4();
element.SetStringAttribute("persistentUuid", persistentUuid);
@@ -112,15 +113,14 @@ InitialInstance& InitialInstance::ResetPersistentUuid() {
return *this;
}
#if defined(GD_IDE_ONLY)
std::map<gd::String, gd::PropertyDescriptor>
InitialInstance::GetCustomProperties(gd::Project& project, gd::Layout& layout) {
// Find an object
if (layout.HasObjectNamed(GetObjectName()))
return layout.GetObject(GetObjectName())
return layout.GetObject(GetObjectName()).GetConfiguration()
.GetInitialInstanceProperties(*this, project, layout);
else if (project.HasObjectNamed(GetObjectName()))
return project.GetObject(GetObjectName())
return project.GetObject(GetObjectName()).GetConfiguration()
.GetInitialInstanceProperties(*this, project, layout);
std::map<gd::String, gd::PropertyDescriptor> nothing;
@@ -132,15 +132,14 @@ bool InitialInstance::UpdateCustomProperty(const gd::String& name,
gd::Project& project,
gd::Layout& layout) {
if (layout.HasObjectNamed(GetObjectName()))
return layout.GetObject(GetObjectName())
return layout.GetObject(GetObjectName()).GetConfiguration()
.UpdateInitialInstanceProperty(*this, name, value, project, layout);
else if (project.HasObjectNamed(GetObjectName()))
return project.GetObject(GetObjectName())
return project.GetObject(GetObjectName()).GetConfiguration()
.UpdateInitialInstanceProperty(*this, name, value, project, layout);
return false;
}
#endif
double InitialInstance::GetRawDoubleProperty(const gd::String& name) const {
const auto& it = numberProperties.find(name);

View File

@@ -127,19 +127,31 @@ class GD_CORE_API InitialInstance {
void SetCustomHeight(double height_) { height = height_; }
/**
* \brief Return true if the instance is locked and cannot be selected by
* clicking on it in the IDE.
* \brief Return true if the instance is locked and cannot be moved in the IDE.
*/
bool IsLocked() const { return locked; };
/**
* \brief (Un)lock the initial instance.
*
* An instance which is locked cannot be selected by clicking on it in a
* layout editor canvas.
* An instance which is locked cannot be moved with actions in the IDE.
*/
void SetLocked(bool enable = true) { locked = enable; }
/**
* \brief Return true if the instance cannot be selected by clicking on it
* in the IDE (only applies if instance is also locked).
*/
bool IsSealed() const { return sealed; };
/**
* \brief (Un)seal the initial instance.
*
* An instance which is sealed cannot be selected by clicking on it in a
* layout editor canvas.
*/
void SetSealed(bool enable = true) { sealed = enable; }
///@}
/** \name Variable management
@@ -270,6 +282,7 @@ class GD_CORE_API InitialInstance {
double height; ///< Object custom height
gd::VariablesContainer initialVariables; ///< Instance specific variables
bool locked; ///< True if the instance is locked
bool sealed; ///< True if the instance is sealed
mutable gd::String persistentUuid; ///< A persistent random version 4 UUID, useful for hot reloading.
static gd::String*

View File

@@ -16,7 +16,6 @@
#include "GDCore/Extensions/Platform.h"
#include "GDCore/IDE/SceneNameMangler.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/BehaviorContent.h"
#include "GDCore/Project/BehaviorsSharedData.h"
#include "GDCore/Project/InitialInstance.h"
#include "GDCore/Project/Layer.h"
@@ -33,7 +32,7 @@ using namespace std;
namespace gd {
gd::Layer Layout::badLayer;
gd::BehaviorContent Layout::badBehaviorContent("", "");
gd::BehaviorsSharedData Layout::badBehaviorSharedData("", "");
Layout::Layout(const Layout& other) { Init(other); }
@@ -51,9 +50,6 @@ Layout::Layout()
backgroundColorB(209),
stopSoundsOnStartup(true),
standardSortMethod(true),
oglFOV(90.0f),
oglZNear(1.0f),
oglZFar(500.0f),
disableInputWhenNotFocused(true),
profiler(NULL)
{
@@ -79,23 +75,23 @@ std::vector<gd::String> Layout::GetAllBehaviorSharedDataNames() const {
return allNames;
}
const gd::BehaviorContent& Layout::GetBehaviorSharedData(
const gd::BehaviorsSharedData& Layout::GetBehaviorSharedData(
const gd::String& behaviorName) const {
auto it = behaviorsSharedData.find(behaviorName);
if (it != behaviorsSharedData.end()) return *it->second;
return badBehaviorContent;
return badBehaviorSharedData;
}
gd::BehaviorContent& Layout::GetBehaviorSharedData(
gd::BehaviorsSharedData& Layout::GetBehaviorSharedData(
const gd::String& behaviorName) {
auto it = behaviorsSharedData.find(behaviorName);
if (it != behaviorsSharedData.end()) return *it->second;
return badBehaviorContent;
return badBehaviorSharedData;
}
const std::map<gd::String, std::unique_ptr<gd::BehaviorContent> >&
const std::map<gd::String, std::unique_ptr<gd::BehaviorsSharedData> >&
Layout::GetAllBehaviorSharedData() const {
return behaviorsSharedData;
}
@@ -197,20 +193,20 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
std::vector<gd::String> objectBehaviors =
initialObjects[i]->GetAllBehaviorNames();
for (unsigned int j = 0; j < objectBehaviors.size(); ++j) {
auto& behaviorContent =
auto& behavior =
initialObjects[i]->GetBehavior(objectBehaviors[j]);
allBehaviorsTypes.push_back(behaviorContent.GetTypeName());
allBehaviorsNames.push_back(behaviorContent.GetName());
allBehaviorsTypes.push_back(behavior.GetTypeName());
allBehaviorsNames.push_back(behavior.GetName());
}
}
for (std::size_t i = 0; i < project.GetObjectsCount(); ++i) {
std::vector<gd::String> objectBehaviors =
project.GetObject(i).GetAllBehaviorNames();
for (std::size_t j = 0; j < objectBehaviors.size(); ++j) {
auto& behaviorContent =
auto& behavior =
project.GetObject(i).GetBehavior(objectBehaviors[j]);
allBehaviorsTypes.push_back(behaviorContent.GetTypeName());
allBehaviorsNames.push_back(behaviorContent.GetName());
allBehaviorsTypes.push_back(behavior.GetTypeName());
allBehaviorsNames.push_back(behavior.GetName());
}
}
@@ -222,19 +218,34 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
if (behaviorsSharedData.find(name) != behaviorsSharedData.end()) continue;
const gd::BehaviorMetadata& behaviorMetadata =
gd::MetadataProvider::GetBehaviorMetadata(project.GetCurrentPlatform(),
allBehaviorsTypes[i]);
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) continue;
if (project.HasEventsBasedBehavior(allBehaviorsTypes[i])) {
// Events based behaviors don't have shared data yet.
auto sharedData =
gd::make_unique<gd::BehaviorsSharedData>(name, allBehaviorsTypes[i]);
sharedData->InitializeContent();
behaviorsSharedData[name] = std::move(sharedData);
}
else {
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;
gd::BehaviorsSharedData* behaviorsSharedDataBluePrint =
behaviorMetadata.GetSharedDataInstance();
if (!behaviorsSharedDataBluePrint) continue;
auto behaviorContent =
gd::make_unique<gd::BehaviorContent>(name, allBehaviorsTypes[i]);
behaviorSharedData->InitializeContent(behaviorContent->GetContent());
behaviorsSharedData[name] = std::move(behaviorContent);
auto sharedData =
gd::make_unique<gd::BehaviorsSharedData>(
*behaviorsSharedDataBluePrint);
sharedData->SetName(name);
sharedData->SetTypeName(allBehaviorsTypes[i]);
sharedData->InitializeContent();
behaviorsSharedData[name] = std::move(sharedData);
}
}
// Remove useless shared data:
@@ -260,17 +271,12 @@ void Layout::SerializeTo(SerializerElement& element) const {
element.SetAttribute("v", (int)GetBackgroundColorGreen());
element.SetAttribute("b", (int)GetBackgroundColorBlue());
element.SetAttribute("title", GetWindowDefaultTitle());
element.SetAttribute("oglFOV", oglFOV);
element.SetAttribute("oglZNear", oglZNear);
element.SetAttribute("oglZFar", oglZFar);
element.SetAttribute("standardSortMethod", standardSortMethod);
element.SetAttribute("stopSoundsOnStartup", stopSoundsOnStartup);
element.SetAttribute("disableInputWhenNotFocused",
disableInputWhenNotFocused);
#if defined(GD_IDE_ONLY)
editorSettings.SerializeTo(element.AddChild("uiSettings"));
#endif
GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
GetVariables().SerializeTo(element.AddChild("variables"));
@@ -321,9 +327,6 @@ void Layout::UnserializeFrom(gd::Project& project,
element.GetIntAttribute("b"));
SetWindowDefaultTitle(
element.GetStringAttribute("title", "(No title)", "titre"));
oglFOV = element.GetDoubleAttribute("oglFOV");
oglZNear = element.GetDoubleAttribute("oglZNear");
oglZFar = element.GetDoubleAttribute("oglZFar");
standardSortMethod = element.GetBoolAttribute("standardSortMethod");
stopSoundsOnStartup = element.GetBoolAttribute("stopSoundsOnStartup");
disableInputWhenNotFocused =
@@ -364,20 +367,20 @@ void Layout::UnserializeFrom(gd::Project& project,
"Behavior"); // Compatibility with GD <= 4
gd::String name = sharedDataElement.GetStringAttribute("name", "", "Name");
auto behaviorContent = gd::make_unique<gd::BehaviorContent>(name, type);
auto behavior = gd::make_unique<gd::BehaviorsSharedData>(name, type);
// Compatibility with GD <= 4.0.98
// If there is only one child called "content" (in addition to "type" and
// "name"), it's the content of a JavaScript behavior. Move the content
// out of the "content" object (to put it directly at the root of the
// behavior shared data element).
if (sharedDataElement.HasChild("content")) {
behaviorContent->UnserializeFrom(sharedDataElement.GetChild("content"));
behavior->UnserializeFrom(sharedDataElement.GetChild("content"));
}
// end of compatibility code
else {
behaviorContent->UnserializeFrom(sharedDataElement);
behavior->UnserializeFrom(sharedDataElement);
}
behaviorsSharedData[name] = std::move(behaviorContent);
behaviorsSharedData[name] = std::move(behavior);
}
}
@@ -388,9 +391,6 @@ void Layout::Init(const Layout& other) {
backgroundColorB = other.backgroundColorB;
standardSortMethod = other.standardSortMethod;
title = other.title;
oglFOV = other.oglFOV;
oglZNear = other.oglZNear;
oglZFar = other.oglZFar;
stopSoundsOnStartup = other.stopSoundsOnStartup;
disableInputWhenNotFocused = other.disableInputWhenNotFocused;
initialInstances = other.initialInstances;
@@ -402,7 +402,7 @@ void Layout::Init(const Layout& other) {
behaviorsSharedData.clear();
for (const auto& it : other.behaviorsSharedData) {
behaviorsSharedData[it.first] =
std::unique_ptr<gd::BehaviorContent>(it.second->Clone());
gd::make_unique<gd::BehaviorsSharedData>(*(it.second->Clone()));
}
events = other.events;

View File

@@ -17,14 +17,12 @@
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/VariablesContainer.h"
#include "GDCore/String.h"
#if defined(GD_IDE_ONLY)
#include "GDCore/IDE/Dialogs/LayoutEditorCanvas/EditorSettings.h"
#endif
namespace gd {
class BaseEvent;
class Object;
class Project;
class BehaviorContent;
class InitialInstancesContainer;
} // namespace gd
class TiXmlElement;
@@ -131,7 +129,6 @@ class GD_CORE_API Layout : public ObjectsContainer {
*/
///@{
#if defined(GD_IDE_ONLY)
/**
* Get the events of the layout
*/
@@ -141,7 +138,7 @@ class GD_CORE_API Layout : public ObjectsContainer {
* Get the events of the layout
*/
gd::EventsList& GetEvents() { return events; }
#endif
///@}
/** \name Variable management
@@ -238,12 +235,10 @@ class GD_CORE_API Layout : public ObjectsContainer {
*/
void MoveLayer(std::size_t oldIndex, std::size_t newIndex);
#if defined(GD_IDE_ONLY)
/**
* \brief Serialize the layers.
*/
void SerializeLayersTo(SerializerElement& element) const;
#endif
/**
* \brief Unserialize the layers.
@@ -274,21 +269,21 @@ class GD_CORE_API Layout : public ObjectsContainer {
/**
* \brief Get the shared data stored for a behavior
*/
const gd::BehaviorContent& GetBehaviorSharedData(
const gd::BehaviorsSharedData& GetBehaviorSharedData(
const gd::String& behaviorName) const;
/**
* \brief Get the shared data stored for a behavior
*/
gd::BehaviorContent& GetBehaviorSharedData(const gd::String& behaviorName);
gd::BehaviorsSharedData& GetBehaviorSharedData(const gd::String& behaviorName);
/**
* \brief Get a map of all shared data stored for behaviors
*/
const std::map<gd::String, std::unique_ptr<gd::BehaviorContent>>&
const std::map<gd::String, std::unique_ptr<gd::BehaviorsSharedData>>&
GetAllBehaviorSharedData() const;
#if defined(GD_IDE_ONLY)
/**
* Return the settings associated to the layout.
* \see gd::EditorSettings
@@ -304,7 +299,6 @@ class GD_CORE_API Layout : public ObjectsContainer {
gd::EditorSettings& GetAssociatedEditorSettings() {
return editorSettings;
}
#endif
/** \name Other properties
*/
@@ -345,48 +339,16 @@ class GD_CORE_API Layout : public ObjectsContainer {
* launched
*/
bool StopSoundsOnStartup() const { return stopSoundsOnStartup; }
/**
* Set OpenGL default field of view
*/
void SetOpenGLFOV(float oglFOV_) { oglFOV = oglFOV_; }
/**
* Get OpenGL default field of view
*/
float GetOpenGLFOV() const { return oglFOV; }
/**
* Set OpenGL near clipping plan
*/
void SetOpenGLZNear(float oglZNear_) { oglZNear = oglZNear_; }
/**
* Get OpenGL near clipping plan
*/
float GetOpenGLZNear() const { return oglZNear; }
/**
* Set OpenGL far clipping plan
*/
void SetOpenGLZFar(float oglZFar_) { oglZFar = oglZFar_; }
/**
* Get OpenGL far clipping plan
*/
float GetOpenGLZFar() const { return oglZFar; }
///@}
/** \name Saving and loading
* Members functions related to saving and loading the object.
*/
///@{
#if defined(GD_IDE_ONLY)
/**
* \brief Serialize the layout.
*/
void SerializeTo(SerializerElement& element) const;
#endif
/**
* \brief Unserialize the layout.
@@ -395,7 +357,6 @@ class GD_CORE_API Layout : public ObjectsContainer {
///@}
// TODO: GD C++ Platform specific code below
#if defined(GD_IDE_ONLY)
/**
* Get the profiler associated with the scene. Can be NULL.
*/
@@ -405,7 +366,6 @@ class GD_CORE_API Layout : public ObjectsContainer {
* Set the profiler associated with the scene. Can be NULL.
*/
void SetProfiler(BaseProfiler* profiler_) { profiler = profiler_; };
#endif
private:
gd::String name; ///< Scene name
@@ -417,32 +377,27 @@ class GD_CORE_API Layout : public ObjectsContainer {
gd::VariablesContainer variables; ///< Variables list
gd::InitialInstancesContainer initialInstances; ///< Initial instances
std::vector<gd::Layer> initialLayers; ///< Initial layers
std::map<gd::String, std::unique_ptr<gd::BehaviorContent>>
std::map<gd::String, std::unique_ptr<gd::BehaviorsSharedData>>
behaviorsSharedData; ///< Initial shared datas of behaviors
bool stopSoundsOnStartup; ///< True to make the scene stop all sounds at
///< startup.
bool standardSortMethod; ///< True to sort objects using standard sort.
float oglFOV; ///< OpenGL Field Of View value
float oglZNear; ///< OpenGL Near Z position
float oglZFar; ///< OpenGL Far Z position
bool disableInputWhenNotFocused; /// If set to true, the input must be
/// disabled when the window do not have the
/// focus.
static gd::Layer badLayer; ///< Null object, returned when GetLayer can not
///< find an appropriate layer.
static gd::BehaviorContent
badBehaviorContent; ///< Null object, returned when
static gd::BehaviorsSharedData
badBehaviorSharedData; ///< Null object, returned when
///< GetBehaviorSharedData can not find the
///< specified behavior shared data.
#if defined(GD_IDE_ONLY)
EventsList events; ///< Scene events
gd::EditorSettings editorSettings;
#endif
// TODO: GD C++ Platform specific code below
#if defined(GD_IDE_ONLY)
BaseProfiler* profiler; ///< Pointer to the profiler. Can be NULL.
#endif
/**
* Initialize from another layout. Used by copy-ctor and assign-op.

View File

@@ -9,29 +9,52 @@
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/CustomBehavior.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Tools/Log.h"
namespace gd {
Object::~Object() {}
Object::Object(const gd::String& name_) : name(name_) {}
Object::Object(const gd::String& name_,
const gd::String& type_,
std::unique_ptr<gd::ObjectConfiguration> configuration_)
: name(name_), configuration(std::move(configuration_)) {
SetType(type_);
}
Object::Object(const gd::String& name_,
const gd::String& type_,
gd::ObjectConfiguration* configuration_)
: name(name_), configuration(configuration_) {
SetType(type_);
}
void Object::Init(const gd::Object& object) {
name = object.name;
assetStoreId = object.assetStoreId;
type = object.type;
objectVariables = object.objectVariables;
tags = object.tags;
effectsContainer = object.effectsContainer;
behaviors.clear();
for (auto& it : object.behaviors) {
behaviors[it.first] = gd::make_unique<gd::BehaviorContent>(*it.second);
behaviors[it.first] = gd::make_unique<gd::Behavior>(*it.second);
}
configuration = object.configuration->Clone();
}
gd::ObjectConfiguration& Object::GetConfiguration() {
return *configuration;
}
const gd::ObjectConfiguration& Object::GetConfiguration() const {
return *configuration;
}
std::vector<gd::String> Object::GetAllBehaviorNames() const {
@@ -49,7 +72,7 @@ bool Object::RenameBehavior(const gd::String& name, const gd::String& newName) {
behaviors.find(newName) != behaviors.end())
return false;
std::unique_ptr<BehaviorContent> aut =
std::unique_ptr<Behavior> aut =
std::move(behaviors.find(name)->second);
behaviors.erase(name);
behaviors[newName] = std::move(aut);
@@ -58,11 +81,11 @@ bool Object::RenameBehavior(const gd::String& name, const gd::String& newName) {
return true;
}
gd::BehaviorContent& Object::GetBehavior(const gd::String& name) {
gd::Behavior& Object::GetBehavior(const gd::String& name) {
return *behaviors.find(name)->second;
}
const gd::BehaviorContent& Object::GetBehavior(const gd::String& name) const {
const gd::Behavior& Object::GetBehavior(const gd::String& name) const {
return *behaviors.find(name)->second;
}
@@ -70,47 +93,41 @@ bool Object::HasBehaviorNamed(const gd::String& name) const {
return behaviors.find(name) != behaviors.end();
}
gd::BehaviorContent& Object::AddBehavior(
const gd::BehaviorContent& behaviorContent) {
const gd::String& behaviorName = behaviorContent.GetName();
auto newBehaviorContent =
gd::make_unique<gd::BehaviorContent>(behaviorContent);
behaviors[behaviorName] = std::move(newBehaviorContent);
return *behaviors[behaviorName];
}
std::map<gd::String, gd::PropertyDescriptor> Object::GetProperties() const {
std::map<gd::String, gd::PropertyDescriptor> nothing;
return nothing;
}
gd::BehaviorContent* Object::AddNewBehavior(const gd::Project& project,
gd::Behavior* Object::AddNewBehavior(const gd::Project& project,
const gd::String& type,
const gd::String& name) {
const gd::BehaviorMetadata& behaviorMetadata =
gd::MetadataProvider::GetBehaviorMetadata(project.GetCurrentPlatform(),
type);
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
return nullptr;
auto initializeAndAdd =
[this, &name](std::unique_ptr<gd::Behavior> behavior) {
behavior->InitializeContent();
this->behaviors[name] = std::move(behavior);
return this->behaviors[name].get();
};
if (project.HasEventsBasedBehavior(type)) {
return initializeAndAdd(
gd::make_unique<CustomBehavior>(name, project, type));
}
else {
const gd::BehaviorMetadata& behaviorMetadata =
gd::MetadataProvider::GetBehaviorMetadata(project.GetCurrentPlatform(),
type);
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
gd::LogWarning("Tried to create a behavior with an unknown type: " + type
+ " on object " + GetName() + "!");
// It's probably an events-based object that was removed.
// Create a custom behavior to preserve the properties values.
return initializeAndAdd(
gd::make_unique<CustomBehavior>(name, project, type));
}
std::unique_ptr<gd::Behavior> behavior(behaviorMetadata.Get().Clone());
behavior->SetName(name);
return initializeAndAdd(std::move(behavior));
}
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>
Object::GetInitialInstanceProperties(const gd::InitialInstance& instance,
gd::Project& project,
gd::Layout& layout) {
std::map<gd::String, gd::PropertyDescriptor> nothing;
return nothing;
}
void Object::UnserializeFrom(gd::Project& project,
const SerializerElement& element) {
type = element.GetStringAttribute("type");
SetType(element.GetStringAttribute("type"));
assetStoreId = element.GetStringAttribute("assetStoreId");
name = element.GetStringAttribute("name", name, "nom");
tags = element.GetStringAttribute("tags");
@@ -133,9 +150,8 @@ void Object::UnserializeFrom(gd::Project& project,
.FindAndReplace("Automatism", "Behavior");
gd::String name = behaviorElement.GetStringAttribute("name", "", "Name");
auto behaviorContent = gd::make_unique<gd::BehaviorContent>(name, type);
behaviorContent->UnserializeFrom(behaviorElement);
behaviors[name] = std::move(behaviorContent);
auto behavior = gd::Object::AddNewBehavior(project, type, name);
behavior->UnserializeFrom(behaviorElement);
}
}
// End of compatibility code
@@ -151,7 +167,7 @@ void Object::UnserializeFrom(gd::Project& project,
"Automatism", "Behavior"); // Compatibility with GD <= 4
gd::String name = behaviorElement.GetStringAttribute("name");
auto behaviorContent = gd::make_unique<gd::BehaviorContent>(name, type);
auto behavior = gd::Object::AddNewBehavior(project, type, name);
// Compatibility with GD <= 4.0.98
// If there is only one child called "content" (in addition to "type" and
// "name"), it's the content of a JavaScript behavior. Move the content
@@ -169,17 +185,16 @@ void Object::UnserializeFrom(gd::Project& project,
contentElement.RemoveChild("type");
}
behaviorContent->UnserializeFrom(contentElement);
behavior->UnserializeFrom(contentElement);
}
// end of compatibility code
else {
behaviorContent->UnserializeFrom(behaviorElement);
behavior->UnserializeFrom(behaviorElement);
}
behaviors[name] = std::move(behaviorContent);
}
}
DoUnserializeFrom(project, element);
configuration->UnserializeFrom(project, element);
}
void Object::SerializeTo(SerializerElement& element) const {
@@ -194,18 +209,18 @@ void Object::SerializeTo(SerializerElement& element) const {
behaviorsElement.ConsiderAsArrayOf("behavior");
std::vector<gd::String> allBehaviors = GetAllBehaviorNames();
for (std::size_t i = 0; i < allBehaviors.size(); ++i) {
const gd::BehaviorContent& behaviorContent = GetBehavior(allBehaviors[i]);
const gd::Behavior& behavior = GetBehavior(allBehaviors[i]);
SerializerElement& behaviorElement = behaviorsElement.AddChild("behavior");
behaviorContent.SerializeTo(behaviorElement);
behavior.SerializeTo(behaviorElement);
behaviorElement.RemoveChild("type"); // The content can contain type or
// name properties, remove them.
behaviorElement.RemoveChild("name");
behaviorElement.SetAttribute("type", behaviorContent.GetTypeName());
behaviorElement.SetAttribute("name", behaviorContent.GetName());
behaviorElement.SetAttribute("type", behavior.GetTypeName());
behaviorElement.SetAttribute("name", behavior.GetName());
}
DoSerializeTo(element);
configuration->SerializeTo(element);
}
} // namespace gd

View File

@@ -10,11 +10,13 @@
#include <memory>
#include <vector>
#include "GDCore/Project/BehaviorContent.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/ObjectConfiguration.h"
#include "GDCore/Project/EffectsContainer.h"
#include "GDCore/Project/VariablesContainer.h"
#include "GDCore/String.h"
#include "GDCore/Tools/MakeUnique.h"
namespace gd {
class PropertyDescriptor;
class Project;
@@ -28,7 +30,7 @@ class EffectsContainer;
namespace gd {
/**
* \brief Base class used to represent an object of a platform
* \brief Represent an object of a platform
*
* \ingroup PlatformDefinition
*/
@@ -36,9 +38,19 @@ class GD_CORE_API Object {
public:
/**
* Create a new object with the name passed as argument.
* \param name Object's name
*/
Object(const gd::String& name);
Object(const gd::String& name,
const gd::String& type,
std::unique_ptr<gd::ObjectConfiguration> configuration);
/**
* Create a new object with the name passed as argument.
*
* Object takes the ownership of the configuration.
*/
Object(const gd::String& name,
const gd::String& type,
gd::ObjectConfiguration* configuration);
/**
* Copy constructor. Calls Init().
@@ -70,6 +82,13 @@ class GD_CORE_API Object {
return gd::make_unique<gd::Object>(*this);
}
/**
* \brief Return the object configuration.
*/
gd::ObjectConfiguration& GetConfiguration();
const gd::ObjectConfiguration& GetConfiguration() const;
/** \name Common properties
* Members functions related to common properties
*/
@@ -93,11 +112,15 @@ class GD_CORE_API Object {
/** \brief Change the type of the object.
*/
void SetType(const gd::String& type_) { type = type_; }
void SetType(const gd::String& type_) {
configuration->SetType(type_);
}
/** \brief Return the type of the object.
*/
const gd::String& GetType() const { return type; }
const gd::String& GetType() const {
return configuration->GetType();
}
/** \brief Change the tags of the object.
*/
@@ -108,92 +131,6 @@ class GD_CORE_API Object {
const gd::String& GetTags() const { return tags; }
///@}
/** \name Resources management
* Members functions related to managing resources used by the object
*/
///@{
/**
* \brief Called ( e.g. during compilation ) so as to inventory internal
* resources and sometimes update their filename. Implementation example:
* \code
* worker.ExposeImage(myImage);
* worker.ExposeFile(myResourceFile);
* \endcode
*
* \see ArbitraryResourceWorker
*/
virtual void ExposeResources(gd::ArbitraryResourceWorker& worker) { return; };
/**
* Redefine this function to return true if your object can use shaders.
*/
virtual bool SupportShaders() { return false; }
///@}
/** \name Object properties
* Reading and updating object properties
*/
///@{
/**
* \brief Called when the IDE wants to know about the custom properties of the
object.
*
* Usage example:
\code
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[ToString(_("Text"))].SetValue("Hello world!");
return properties;
\endcode
*
* \return a std::map with properties names as key.
* \see gd::PropertyDescriptor
*/
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
/**
* \brief Called when the IDE wants to update a custom property of the object
*
* \return false if the new value cannot be set
*/
virtual bool UpdateProperty(const gd::String& name, const gd::String& value) {
return false;
};
///@}
/** \name Drawing and editing initial instances
* Members functions related to drawing and editing initial instances of this
* object
*/
///@{
/**
* \brief Called when the IDE wants to know about the custom properties of an
* initial instance of this object.
*
* \return a std::map with properties names as key and values.
* \see gd::InitialInstance
*/
virtual std::map<gd::String, gd::PropertyDescriptor>
GetInitialInstanceProperties(const gd::InitialInstance& instance,
gd::Project& project,
gd::Layout& layout);
/**
* \brief Called when the IDE wants to update a custom property of an initial
* instance of this object.
*
* \return false if the new value cannot be set
* \see gd::InitialInstance
*/
virtual bool UpdateInitialInstanceProperty(gd::InitialInstance& instance,
const gd::String& name,
const gd::String& value,
gd::Project& project,
gd::Layout& layout) {
return false;
};
///@}
/** \name Behaviors management
* Members functions related to behaviors management.
*/
@@ -208,12 +145,12 @@ class GD_CORE_API Object {
/**
* \brief Return a reference to the content of the behavior called \a name.
*/
BehaviorContent& GetBehavior(const gd::String& name);
Behavior& GetBehavior(const gd::String& name);
/**
* \brief Return a reference to the content of the behavior called \a name.
*/
const BehaviorContent& GetBehavior(const gd::String& name) const;
const Behavior& GetBehavior(const gd::String& name) const;
/**
* \brief Return true if object has a behavior called \a name.
@@ -231,13 +168,6 @@ class GD_CORE_API Object {
*/
bool RenameBehavior(const gd::String& name, const gd::String& newName);
/**
* \brief Add the specified behavior content to the object
*
* \return A reference to the newly added behavior content.
*/
gd::BehaviorContent& AddBehavior(const gd::BehaviorContent& behavior);
/**
* \brief Add the behavior of the specified \a type with the specified \a
* name.
@@ -247,15 +177,15 @@ class GD_CORE_API Object {
* \return A pointer to the newly added behavior content. NULL if the creation
* failed.
*/
gd::BehaviorContent* AddNewBehavior(const gd::Project& project,
const gd::String& type,
const gd::String& name);
gd::Behavior* AddNewBehavior(const gd::Project& project,
const gd::String& type,
const gd::String& name);
/**
* \brief Get a read-only access to the map containing the behaviors with
* their properties.
*/
const std::map<gd::String, std::unique_ptr<gd::BehaviorContent>>&
const std::map<gd::String, std::unique_ptr<gd::Behavior>>&
GetAllBehaviorContents() const {
return behaviors;
};
@@ -316,9 +246,8 @@ class GD_CORE_API Object {
protected:
gd::String name; ///< The full name of the object
gd::String assetStoreId; ///< The ID of the asset if the object comes from the store.
gd::String type; ///< Which type is the object. ( To test if we can do
///< something reserved to some objects with it )
std::map<gd::String, std::unique_ptr<gd::BehaviorContent>>
std::unique_ptr<gd::ObjectConfiguration> configuration;
std::map<gd::String, std::unique_ptr<gd::Behavior>>
behaviors; ///< Contains all behaviors and their properties for the
///< object. Behavior contents are the ownership of the
///< object.
@@ -328,20 +257,12 @@ class GD_CORE_API Object {
gd::EffectsContainer
effectsContainer; ///< The effects container for the object.
/**
* \brief Derived objects can redefine this method to load custom attributes.
*/
virtual void DoUnserializeFrom(gd::Project& project,
const SerializerElement& element){};
/**
* \brief Derived objects can redefine this method to save custom attributes.
*/
virtual void DoSerializeTo(SerializerElement& element) const {};
/**
* Initialize object using another object. Used by copy-ctor and assign-op.
* Don't forget to update me if members were changed!
*
* It's needed because there is no default copy for a map of unique_ptr like
* behaviors and it must be a deep copy.
*/
void Init(const gd::Object& object);
};

View File

@@ -0,0 +1,47 @@
/*
* 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/ObjectConfiguration.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/CustomBehavior.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Tools/Log.h"
namespace gd {
ObjectConfiguration::~ObjectConfiguration() {}
ObjectConfiguration::ObjectConfiguration() {}
std::map<gd::String, gd::PropertyDescriptor> ObjectConfiguration::GetProperties() const {
std::map<gd::String, gd::PropertyDescriptor> nothing;
return nothing;
}
std::map<gd::String, gd::PropertyDescriptor>
ObjectConfiguration::GetInitialInstanceProperties(const gd::InitialInstance& instance,
gd::Project& project,
gd::Layout& layout) {
std::map<gd::String, gd::PropertyDescriptor> nothing;
return nothing;
}
void ObjectConfiguration::UnserializeFrom(gd::Project& project,
const SerializerElement& element) {
DoUnserializeFrom(project, element);
}
void ObjectConfiguration::SerializeTo(SerializerElement& element) const {
DoSerializeTo(element);
}
} // namespace gd

View File

@@ -0,0 +1,194 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_OBJECTCONFIGURATION_H
#define GDCORE_OBJECTCONFIGURATION_H
#include "GDCore/Vector2.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/EffectsContainer.h"
#include "GDCore/Project/VariablesContainer.h"
#include "GDCore/String.h"
#include "GDCore/Tools/MakeUnique.h"
namespace gd {
class PropertyDescriptor;
class Project;
class Layout;
class ArbitraryResourceWorker;
class InitialInstance;
class SerializerElement;
class EffectsContainer;
} // namespace gd
namespace gd {
/**
* \brief Base class used to represent an object configuration.
* For example, this can be the animations in a sprite, the text, its font,
* its color in a Text object, etc...
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API ObjectConfiguration {
public:
/**
* Create a new object configuration.
*/
ObjectConfiguration();
/**
* Destructor.
*/
virtual ~ObjectConfiguration();
/**
* Must return a pointer to a copy of the configuration. This method is
* needed to do polymorphic copies. Just redefine this method in your derived
* object class like this:
* \code
* return gd::make_unique<MyObjectConfiguration>(*this);
* \endcode
*/
virtual std::unique_ptr<gd::ObjectConfiguration> Clone() const {
return gd::make_unique<gd::ObjectConfiguration>(*this);
}
/** \brief Change the type of the object.
*/
void SetType(const gd::String& type_) { type = type_; }
/** \brief Return the type of the object.
*/
const gd::String& GetType() const { return type; }
/** \name Object properties
* Reading and updating object configuration properties
*/
///@{
/**
* \brief Called when the IDE wants to know about the custom properties of the
object configuration.
*
* Usage example:
\code
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[ToString(_("Text"))].SetValue("Hello world!");
return properties;
\endcode
*
* \return a std::map with properties names as key.
* \see gd::PropertyDescriptor
*/
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
/**
* \brief Called when the IDE wants to update a custom property of the object
* configuration.
*
* \return false if the new value cannot be set
*/
virtual bool UpdateProperty(const gd::String& name, const gd::String& value) {
return false;
};
///@}
/** \name Drawing and editing initial instances
* Members functions related to drawing and editing initial instances of this
* object configuration
*/
///@{
/**
* \brief Called when the IDE wants to know about the custom properties of an
* initial instance of this object configuration.
*
* \return a std::map with properties names as key and values.
* \see gd::InitialInstance
*/
virtual std::map<gd::String, gd::PropertyDescriptor>
GetInitialInstanceProperties(const gd::InitialInstance& instance,
gd::Project& project,
gd::Layout& layout);
/**
* \brief Called when the IDE wants to update a custom property of an initial
* instance of this object configuration.
*
* \return false if the new value cannot be set
* \see gd::InitialInstance
*/
virtual bool UpdateInitialInstanceProperty(gd::InitialInstance& instance,
const gd::String& name,
const gd::String& value,
gd::Project& project,
gd::Layout& layout) {
return false;
};
///@}
/** \name Resources management
* Members functions related to managing resources used by the object configuration
*/
///@{
/**
* \brief Called ( e.g. during compilation ) so as to inventory internal
* resources and sometimes update their filename. Implementation example:
* \code
* worker.ExposeImage(myImage);
* worker.ExposeFile(myResourceFile);
* \endcode
*
* \see ArbitraryResourceWorker
*/
virtual void ExposeResources(gd::ArbitraryResourceWorker& worker) { return; };
///@}
/** \name Serialization
* Members functions related to serialization of the object configuration
*/
///@{
/**
* \brief Serialize the object configuration.
* \see DoSerializeTo
*/
void SerializeTo(SerializerElement& element) const;
/**
* \brief Unserialize the object configuration.
* \see DoUnserializeFrom
*/
void UnserializeFrom(gd::Project& project, const SerializerElement& element);
///@}
protected:
gd::String type; ///< Which type of object is represented by this
///< configuration.
/**
* \brief Derived object configuration can redefine this method to load
* custom attributes.
*/
virtual void DoUnserializeFrom(gd::Project& project,
const SerializerElement& element){};
/**
* \brief Derived object configuration can redefine this method to save
* custom attributes.
*/
virtual void DoSerializeTo(SerializerElement& element) const {};
};
} // namespace gd
/**
* Object configurations are usually managed thanks to (smart) pointers.
*/
using ObjConfSPtr = std::unique_ptr<gd::ObjectConfiguration>;
#endif // GDCORE_OBJECT_H

View File

@@ -83,7 +83,7 @@ gd::Object& ObjectsContainer::InsertNewObject(const gd::Project& project,
gd::Object& newlyCreatedObject = *(*(initialObjects.insert(
position < initialObjects.size() ? initialObjects.begin() + position
: initialObjects.end(),
project.GetCurrentPlatform().CreateObject(objectType, name))));
project.CreateObject(objectType, name))));
return newlyCreatedObject;
}

View File

@@ -23,10 +23,12 @@
#include "GDCore/IDE/PlatformManager.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/CustomObjectConfiguration.h"
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/Project/ExternalLayout.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectConfiguration.h"
#include "GDCore/Project/ObjectGroupsContainer.h"
#include "GDCore/Project/ResourcesManager.h"
#include "GDCore/Project/SourceFile.h"
@@ -79,22 +81,84 @@ Project::~Project() {}
void Project::ResetProjectUuid() { projectUuid = UUID::MakeUuid4(); }
std::unique_ptr<gd::Object> Project::CreateObject(
const gd::String& type,
const gd::String& name,
const gd::String& platformName) {
for (std::size_t i = 0; i < platforms.size(); ++i) {
if (!platformName.empty() && platforms[i]->GetName() != platformName)
continue;
const gd::String& type,
const gd::String& name) const {
return gd::make_unique<Object>(name, type, CreateObjectConfiguration(type));
}
std::unique_ptr<gd::Object> object = platforms[i]->CreateObject(
type, name); // Create a base object if the type can't be found in the
// platform
if (object && object->GetType() == type)
return object; // If the object is valid and has the good type (not a
// base object), return it
std::unique_ptr<gd::ObjectConfiguration> Project::CreateObjectConfiguration(
const gd::String& type) const {
if (Project::HasEventsBasedObject(type)) {
return gd::make_unique<CustomObjectConfiguration>(*this, type);
}
else {
// Create a base object if the type can't be found in the platform.
return currentPlatform->CreateObjectConfiguration(type);
}
}
return nullptr;
bool Project::HasEventsBasedObject(const gd::String& type) const {
const auto separatorIndex = type.find(PlatformExtension::GetNamespaceSeparator());
if (separatorIndex == std::string::npos) {
return false;
}
gd::String extensionName = type.substr(0, separatorIndex);
if (!Project::HasEventsFunctionsExtensionNamed(extensionName)) {
return false;
}
auto &extension = Project::GetEventsFunctionsExtension(extensionName);
gd::String objectTypeName = type.substr(separatorIndex + 2);
return extension.GetEventsBasedObjects().Has(objectTypeName);
}
gd::EventsBasedObject& Project::GetEventsBasedObject(const gd::String& type) {
const auto separatorIndex = type.find(PlatformExtension::GetNamespaceSeparator());
gd::String extensionName = type.substr(0, separatorIndex);
gd::String objectTypeName = type.substr(separatorIndex + 2);
auto &extension = Project::GetEventsFunctionsExtension(extensionName);
return extension.GetEventsBasedObjects().Get(objectTypeName);
}
const gd::EventsBasedObject& Project::GetEventsBasedObject(const gd::String& type) const {
const auto separatorIndex = type.find(PlatformExtension::GetNamespaceSeparator());
gd::String extensionName = type.substr(0, separatorIndex);
gd::String objectTypeName = type.substr(separatorIndex + 2);
const auto &extension = Project::GetEventsFunctionsExtension(extensionName);
return extension.GetEventsBasedObjects().Get(objectTypeName);
}
bool Project::HasEventsBasedBehavior(const gd::String& type) const {
const auto separatorIndex = type.find(PlatformExtension::GetNamespaceSeparator());
if (separatorIndex == std::string::npos) {
return false;
}
gd::String extensionName = type.substr(0, separatorIndex);
if (!Project::HasEventsFunctionsExtensionNamed(extensionName)) {
return false;
}
auto &extension = Project::GetEventsFunctionsExtension(extensionName);
gd::String behaviorTypeName = type.substr(separatorIndex + 2);
return extension.GetEventsBasedBehaviors().Has(behaviorTypeName);
}
gd::EventsBasedBehavior& Project::GetEventsBasedBehavior(const gd::String& type) {
const auto separatorIndex = type.find(PlatformExtension::GetNamespaceSeparator());
gd::String extensionName = type.substr(0, separatorIndex);
gd::String behaviorTypeName = type.substr(separatorIndex + 2);
auto &extension = Project::GetEventsFunctionsExtension(extensionName);
return extension.GetEventsBasedBehaviors().Get(behaviorTypeName);
}
const gd::EventsBasedBehavior& Project::GetEventsBasedBehavior(const gd::String& type) const {
const auto separatorIndex = type.find(PlatformExtension::GetNamespaceSeparator());
gd::String extensionName = type.substr(0, separatorIndex);
gd::String behaviorTypeName = type.substr(separatorIndex + 2);
auto &extension = Project::GetEventsFunctionsExtension(extensionName);
return extension.GetEventsBasedBehaviors().Get(behaviorTypeName);
}
std::shared_ptr<gd::BaseEvent> Project::CreateEvent(
@@ -642,6 +706,38 @@ void Project::UnserializeFrom(const SerializerElement& element) {
if (currentPlatform == NULL && !platforms.empty())
currentPlatform = platforms.back();
eventsFunctionsExtensions.clear();
const SerializerElement& eventsFunctionsExtensionsElement =
element.GetChild("eventsFunctionsExtensions");
eventsFunctionsExtensionsElement.ConsiderAsArrayOf(
"eventsFunctionsExtension");
// First, only unserialize behaviors and objects names.
// As event based objects can contains CustomObject and Custom Object,
// this allows them to reference EventBasedBehavior and EventBasedObject
// respectively.
for (std::size_t i = 0;
i < eventsFunctionsExtensionsElement.GetChildrenCount();
++i) {
const SerializerElement& eventsFunctionsExtensionElement =
eventsFunctionsExtensionsElement.GetChild(i);
gd::EventsFunctionsExtension& newEventsFunctionsExtension =
InsertNewEventsFunctionsExtension("",
GetEventsFunctionsExtensionsCount());
newEventsFunctionsExtension.UnserializeExtensionDeclarationFrom(
*this, eventsFunctionsExtensionElement);
}
// Then unserialize functions, behaviors and objects content.
for (std::size_t i = 0;
i < eventsFunctionsExtensionsElement.GetChildrenCount();
++i) {
const SerializerElement& eventsFunctionsExtensionElement =
eventsFunctionsExtensionsElement.GetChild(i);
eventsFunctionsExtensions.at(i)->UnserializeExtensionImplementationFrom(
*this, eventsFunctionsExtensionElement);
}
GetObjectGroups().UnserializeFrom(
element.GetChild("objectsGroups", 0, "ObjectGroups"));
resourcesManager.UnserializeFrom(
@@ -676,24 +772,6 @@ void Project::UnserializeFrom(const SerializerElement& element) {
externalEvents.UnserializeFrom(*this, externalEventElement);
}
eventsFunctionsExtensions.clear();
const SerializerElement& eventsFunctionsExtensionsElement =
element.GetChild("eventsFunctionsExtensions");
eventsFunctionsExtensionsElement.ConsiderAsArrayOf(
"eventsFunctionsExtension");
for (std::size_t i = 0;
i < eventsFunctionsExtensionsElement.GetChildrenCount();
++i) {
const SerializerElement& eventsFunctionsExtensionElement =
eventsFunctionsExtensionsElement.GetChild(i);
gd::EventsFunctionsExtension& newEventsFunctionsExtension =
InsertNewEventsFunctionsExtension("",
GetEventsFunctionsExtensionsCount());
newEventsFunctionsExtension.UnserializeFrom(
*this, eventsFunctionsExtensionElement);
}
externalLayouts.clear();
const SerializerElement& externalLayoutsElement =
element.GetChild("externalLayouts", 0, "ExternalLayouts");
@@ -868,8 +946,9 @@ void Project::ExposeResources(gd::ArbitraryResourceWorker& worker) {
// Add layouts resources
for (std::size_t s = 0; s < GetLayoutsCount(); s++) {
for (std::size_t j = 0; j < GetLayout(s).GetObjectsCount();
++j) // Add objects resources
GetLayout(s).GetObject(j).ExposeResources(worker);
++j) { // Add objects resources
GetLayout(s).GetObject(j).GetConfiguration().ExposeResources(worker);
}
LaunchResourceWorkerOnEvents(*this, GetLayout(s).GetEvents(), worker);
}
@@ -888,7 +967,7 @@ void Project::ExposeResources(gd::ArbitraryResourceWorker& worker) {
// Add global objects resources
for (std::size_t j = 0; j < GetObjectsCount(); ++j) {
GetObject(j).ExposeResources(worker);
GetObject(j).GetConfiguration().ExposeResources(worker);
}
// Add loading screen background image if present

View File

@@ -24,7 +24,10 @@ class ExternalEvents;
class ResourcesManager;
class ExternalLayout;
class EventsFunctionsExtension;
class EventsBasedObject;
class EventsBasedBehavior;
class Object;
class ObjectConfiguration;
class VariablesContainer;
class ArbitraryResourceWorker;
class SourceFile;
@@ -455,20 +458,20 @@ class GD_CORE_API Project : public ObjectsContainer {
/**
* Create an object of the given type with the specified name.
*
* \note A project can use more than one platform. In this case, the first
* platform supporting the object is used, unless \a platformName argument is
* not empty.<br> It is assumed that each platform provides an equivalent
* object.
*
*
* \param type The type of the object
* \param name The name of the object
* \param platformName The name of the platform to be used. If empty, the
* first platform supporting the object is used.
*/
std::unique_ptr<gd::Object> CreateObject(const gd::String& type,
const gd::String& name,
const gd::String& platformName = "");
const gd::String& name) const;
/**
* Create an object configuration of the given type.
*
* \param type The type of the object
*/
std::unique_ptr<gd::ObjectConfiguration> CreateObjectConfiguration(
const gd::String& type) const;
/**
* Create an event of the given type.
@@ -827,6 +830,37 @@ class GD_CORE_API Project : public ObjectsContainer {
* \brief Remove all the events functions extensions.
*/
void ClearEventsFunctionsExtensions();
/**
* \brief Check if events based object with a given type exists.
*/
bool HasEventsBasedObject(const gd::String& type) const;
/**
* \brief Return the events based object with a given type.
*/
gd::EventsBasedObject& GetEventsBasedObject(const gd::String& type);
/**
* \brief Return the events based object with a given type.
*/
const gd::EventsBasedObject& GetEventsBasedObject(const gd::String& type) const;
/**
* \brief Check if events based behavior with a given type exists.
*/
bool HasEventsBasedBehavior(const gd::String& type) const;
/**
* \brief Return the events based behavior with a given type.
*/
gd::EventsBasedBehavior& GetEventsBasedBehavior(const gd::String& type);
/**
* \brief Return the events based behavior with a given type.
*/
const gd::EventsBasedBehavior& GetEventsBasedBehavior(const gd::String& type) const;
///@}
/** \name Resources management

View File

@@ -184,11 +184,17 @@ std::map<gd::String, gd::PropertyDescriptor> AudioResource::GetProperties()
const {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[_("Preload as sound")]
.SetDescription(_("Loads the fully decoded file into cache, so it can be played right away as Sound with no further delays."))
.SetValue(preloadAsSound ? "true" : "false")
.SetType("Boolean");
properties[_("Preload as music")]
.SetDescription(_("Prepares the file for immediate streaming as Music (does not wait for complete download)."))
.SetValue(preloadAsMusic ? "true" : "false")
.SetType("Boolean");
properties[_("Preload in cache")]
.SetDescription(_("Loads the complete file into cache, but does not decode it into memory until requested."))
.SetValue(preloadInCache ? "true" : "false")
.SetType("Boolean");
return properties;
}
@@ -199,6 +205,8 @@ bool AudioResource::UpdateProperty(const gd::String& name,
preloadAsSound = value == "1";
else if (name == _("Preload as music"))
preloadAsMusic = value == "1";
else if (name == _("Preload in cache"))
preloadInCache = value == "1";
return true;
}
@@ -569,6 +577,7 @@ void AudioResource::UnserializeFrom(const SerializerElement& element) {
SetFile(element.GetStringAttribute("file"));
SetPreloadAsMusic(element.GetBoolAttribute("preloadAsMusic"));
SetPreloadAsSound(element.GetBoolAttribute("preloadAsSound"));
SetPreloadInCache(element.GetBoolAttribute("preloadInCache"));
}
void AudioResource::SerializeTo(SerializerElement& element) const {
@@ -576,6 +585,7 @@ void AudioResource::SerializeTo(SerializerElement& element) const {
element.SetAttribute("file", GetFile());
element.SetAttribute("preloadAsMusic", PreloadAsMusic());
element.SetAttribute("preloadAsSound", PreloadAsSound());
element.SetAttribute("preloadInCache", PreloadInCache());
}
void FontResource::SetFile(const gd::String& newFile) {

View File

@@ -223,7 +223,7 @@ class GD_CORE_API ImageResource : public Resource {
*/
class GD_CORE_API AudioResource : public Resource {
public:
AudioResource() : Resource(), preloadAsMusic(false), preloadAsSound(false) {
AudioResource() : Resource(), preloadAsMusic(false), preloadAsSound(false), preloadInCache(false) {
SetKind("audio");
};
virtual ~AudioResource(){};
@@ -263,10 +263,21 @@ class GD_CORE_API AudioResource : public Resource {
*/
void SetPreloadAsSound(bool enable = true) { preloadAsSound = enable; }
/**
* \brief Return true if the audio resource should be preloaded in cache (without decoding into memory).
*/
bool PreloadInCache() const { return preloadInCache; }
/**
* \brief Set if the audio resource should be preloaded in cache (without decoding into memory).
*/
void SetPreloadInCache(bool enable = true) { preloadInCache = enable; }
private:
gd::String file;
bool preloadAsSound;
bool preloadAsMusic;
bool preloadInCache;
};
/**

View File

@@ -22,7 +22,7 @@ namespace gd {
* properties).
*
* It is used for serialization (to JSON or XML), or as a generic
* container for properties of objects (see for example gd::BehaviorContent).
* container for properties of objects (see for example gd::Behavior).
*
* It also has specialized methods in GDevelop.js (see postjs.js) to be
* converted to a JavaScript object.

View File

@@ -13,12 +13,14 @@
#include "GDCore/IDE/Project/ProjectResourcesAdder.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Events/Builtin/StandardEvent.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Tools/SystemStats.h"
#include "GDCore/Tools/VersionWrapper.h"
#include "DummyPlatform.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
#include "catch.hpp"
class ArbitraryResourceWorkerTest : public gd::ArbitraryResourceWorker {
@@ -63,14 +65,15 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
"path/to/file4.png") != worker.files.end());
SECTION("Object using a resource") {
gd::SpriteObject obj("myObject");
gd::SpriteObject spriteConfiguration;
gd::Animation anim;
gd::Sprite sprite;
sprite.SetImageName("res1");
anim.SetDirectionsCount(1);
anim.GetDirection(0).AddSprite(sprite);
obj.AddAnimation(anim);
spriteConfiguration.AddAnimation(anim);
gd::Object obj("myObject", "", spriteConfiguration.Clone());
project.InsertObject(obj, 0);
worker.files.clear();

View File

@@ -0,0 +1,209 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
/**
* @file Tests covering serialization to JSON.
*/
#include "DummyPlatform.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Builtin/StandardEvent.h"
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Serialization.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/Variable.h"
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Tools/SystemStats.h"
#include "GDCore/Tools/VersionWrapper.h"
#include "catch.hpp"
using namespace gd;
namespace {
void AddEventsBasedExtension(gd::Project &project) {
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &eventsBasedBehavior =
eventsExtension.GetEventsBasedBehaviors().InsertNew(
"MyEventsBasedBehavior", 0);
eventsBasedBehavior.SetFullName("My events based behavior");
eventsBasedBehavior.SetDescription("An events based behavior for test");
eventsBasedBehavior.SetObjectType("");
eventsBasedBehavior.GetPropertyDescriptors()
.InsertNew("MyProperty", 0)
.SetType("Number");
};
void AddAnotherEventsBasedExtensionWithDependency(gd::Project &project) {
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyOtherEventsExtension", 0);
auto &eventsBasedObject = eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
eventsBasedObject.SetFullName("My events based object");
eventsBasedObject.SetDescription("An events based object for test");
gd::Object &object = eventsBasedObject.InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
gd::Behavior *behavior =
object.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior",
"MyEventsBasedBehavior");
behavior->UpdateProperty("MyProperty", "481516");
};
void SetupProject(gd::Project &project, gd::Platform &platform) {
SetupProjectWithDummyPlatform(project, platform);
AddEventsBasedExtension(project);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
gd::Behavior *behavior =
object.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior",
"MyEventsBasedBehavior");
behavior->UpdateProperty("MyProperty", "481516");
};
void CheckBehaviorPropertyInObjectContainerElement(
SerializerElement &objectContainerElement) {
REQUIRE(objectContainerElement.HasChild("objects"));
auto &objectsElement = objectContainerElement.GetChild("objects");
objectsElement.ConsiderAsArrayOf("object");
REQUIRE(objectsElement.GetChildrenCount() == 1);
auto &objectElement = objectsElement.GetChild(0);
REQUIRE(objectElement.GetStringAttribute("name") == "MyObject");
REQUIRE(objectElement.GetStringAttribute("type") == "MyExtension::Sprite");
REQUIRE(objectElement.HasChild("behaviors"));
auto &behaviorsElement = objectElement.GetChild("behaviors");
behaviorsElement.ConsiderAsArrayOf("behavior");
REQUIRE(behaviorsElement.GetChildrenCount() == 1);
auto &behaviorElement = behaviorsElement.GetChild(0);
REQUIRE(behaviorElement.GetStringAttribute("name") ==
"MyEventsBasedBehavior");
REQUIRE(behaviorElement.GetStringAttribute("type") ==
"MyEventsExtension::MyEventsBasedBehavior");
REQUIRE(behaviorElement.GetStringAttribute("MyProperty") == "481516");
};
void CheckBehaviorPropertyInElement(SerializerElement &projectElement) {
auto &layoutsElement = projectElement.GetChild("layouts");
layoutsElement.ConsiderAsArrayOf("layout");
REQUIRE(layoutsElement.GetChildrenCount() == 1);
auto &layoutElement = layoutsElement.GetChild(0);
REQUIRE(layoutElement.GetStringAttribute("name") == "Scene");
CheckBehaviorPropertyInObjectContainerElement(layoutElement);
};
void CheckBehaviorProperty(ObjectsContainer &container) {
auto &object = container.GetObject("MyObject");
REQUIRE(object.GetType() == "MyExtension::Sprite");
REQUIRE(object.HasBehaviorNamed("MyEventsBasedBehavior"));
auto &behavior = object.GetBehavior("MyEventsBasedBehavior");
REQUIRE(behavior.GetTypeName() == "MyEventsExtension::MyEventsBasedBehavior");
REQUIRE(behavior.GetProperties().size() == 1);
REQUIRE(behavior.GetProperties().at("MyProperty").GetValue() == "481516");
};
} // namespace
// TODO EBO Add similar test cases for events-based objects.
TEST_CASE("BehaviorSerialization", "[common]") {
SECTION("Save and load a project with a custom behavior property value") {
gd::Platform platform;
gd::Project writtenProject;
SetupProject(writtenProject, platform);
CheckBehaviorProperty(writtenProject.GetLayout("Scene"));
SerializerElement projectElement;
writtenProject.SerializeTo(projectElement);
CheckBehaviorPropertyInElement(projectElement);
gd::Project readProject;
readProject.AddPlatform(platform);
readProject.UnserializeFrom(projectElement);
CheckBehaviorProperty(readProject.GetLayout("Scene"));
}
SECTION("Load a project with a property value on a custom behavior that no longer exists") {
gd::Platform platform;
gd::Project writtenProject;
SetupProject(writtenProject, platform);
// Remove the events-based behavior
writtenProject.RemoveEventsFunctionsExtension("MyEventsExtension");
SerializerElement projectElement;
writtenProject.SerializeTo(projectElement);
CheckBehaviorPropertyInElement(projectElement);
gd::Project readProject;
readProject.AddPlatform(platform);
readProject.UnserializeFrom(projectElement);
// Add the events-based behavior back
AddEventsBasedExtension(readProject);
CheckBehaviorProperty(readProject.GetLayout("Scene"));
}
SECTION("Save and load a project with an event based extension dependency") {
gd::Platform platform;
gd::Project writtenProject;
SetupProject(writtenProject, platform);
AddAnotherEventsBasedExtensionWithDependency(writtenProject);
// It's important that the extension with the dependency is the first one.
REQUIRE(writtenProject.GetEventsFunctionsExtension(0).GetName() ==
"MyOtherEventsExtension");
REQUIRE(writtenProject.GetEventsFunctionsExtension(1).GetName() ==
"MyEventsExtension");
SerializerElement projectElement;
writtenProject.SerializeTo(projectElement);
auto &extensionsElement =
projectElement.GetChild("eventsFunctionsExtensions");
extensionsElement.ConsiderAsArrayOf("eventsFunctionsExtension");
REQUIRE(extensionsElement.GetChildrenCount() == 2);
auto &firstExtensionElement = extensionsElement.GetChild(0);
REQUIRE(firstExtensionElement.GetStringAttribute("name") ==
"MyOtherEventsExtension");
auto &eventsBasedObjectsElement =
firstExtensionElement.GetChild("eventsBasedObjects");
eventsBasedObjectsElement.ConsiderAsArrayOf("eventsBasedObject");
auto &eventsBasedObjectElement =
eventsBasedObjectsElement.GetChild(0);
CheckBehaviorPropertyInObjectContainerElement(eventsBasedObjectElement);
auto &secondExtensionElement = extensionsElement.GetChild(1);
REQUIRE(secondExtensionElement.GetStringAttribute("name") ==
"MyEventsExtension");
gd::Project readProject;
readProject.AddPlatform(platform);
readProject.UnserializeFrom(projectElement);
// The custom behavior is unserialized even though it depends on the other
// extension.
REQUIRE(readProject.HasEventsBasedObject(
"MyOtherEventsExtension::MyEventsBasedObject"));
CheckBehaviorProperty(readProject.GetEventsBasedObject(
"MyOtherEventsExtension::MyEventsBasedObject"));
}
}

View File

@@ -19,6 +19,8 @@
#include "GDCore/Tools/VersionWrapper.h"
#include "catch.hpp"
// TODO: Add some tests on layouts and behavior shared data.
TEST_CASE("Project", "[common]") {
SECTION("Basics") {
gd::Project project;

View File

@@ -7,14 +7,19 @@
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/ObjectConfiguration.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Tools/Localization.h"
#include "catch.hpp"
// TODO Remove these 2 classes and write the test with events based behaviors.
class BehaviorWithRequiredBehaviorProperty : public gd::Behavior {
public:
BehaviorWithRequiredBehaviorProperty(){};
BehaviorWithRequiredBehaviorProperty(
const gd::String& name, const gd::String& type)
: Behavior(name, type) {};
virtual ~BehaviorWithRequiredBehaviorProperty(){};
virtual Behavior* Clone() const override {
return new BehaviorWithRequiredBehaviorProperty(*this);
@@ -49,7 +54,9 @@ class BehaviorWithRequiredBehaviorProperty : public gd::Behavior {
class BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior
: public gd::Behavior {
public:
BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior(){};
BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior(
const gd::String& name, const gd::String& type)
: Behavior(name, type) {};
virtual ~BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior(){};
virtual Behavior* Clone() const override {
return new BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior(
@@ -93,7 +100,7 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
// Create the base object. All objects "inherits" from it.
baseObjectExtension->SetExtensionInformation(
"BuiltinObject", "Base Object dummy extension", "", "", "");
auto& baseObject = baseObjectExtension->AddObject<gd::Object>(
auto& baseObject = baseObjectExtension->AddObject<gd::ObjectConfiguration>(
"", "Dummy Base Object", "Dummy Base Object", "");
// Add this expression for all objects. But it requires a "capability".
@@ -125,6 +132,18 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
.AddParameter("expression", "Parameter 1 (a number)")
.SetFunctionName("doSomething");
extension
->AddAction("DoSomethingWithObjects",
"Do something",
"This does something",
"Do something please",
"",
"",
"")
.AddParameter("object", _("Object 1 parameter"))
.AddParameter("object", _("Object 2 parameter"))
.SetFunctionName("doSomethingWithObjects");
extension
->AddAction("DoSomethingWithResources",
"Do something with resources",
@@ -209,7 +228,7 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
.AddParameter("objectvar", _("Variable for object 2"))
.SetFunctionName("getStringWith1ObjectParamAnd2ObjectVarParam");
auto& object = extension->AddObject<gd::Object>(
auto& object = extension->AddObject<gd::SpriteObject>(
"Sprite", "Dummy Sprite", "Dummy sprite object", "");
object
.AddExpression("GetObjectVariableAsNumber",
@@ -260,10 +279,11 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
"Dummy behavior",
"MyBehavior",
"A dummy behavior for tests",
"",
"",
"",
gd::make_unique<gd::Behavior>(),
"Group",
"Icon.png",
"MyBehavior",
gd::make_unique<gd::Behavior>(
"Behavior", "MyExtension::MyBehavior"),
gd::make_unique<gd::BehaviorsSharedData>());
behavior
.AddAction("BehaviorDoSomething",
@@ -304,10 +324,11 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
"Another Dummy behavior",
"MyOtherBehavior",
"Another dummy behavior for tests",
"",
"",
"",
gd::make_unique<gd::Behavior>(),
"Group",
"Icon.png",
"MyOtherBehavior",
gd::make_unique<gd::Behavior>(
"Behavior", "MyExtension::MyOtherBehavior"),
gd::make_unique<gd::BehaviorsSharedData>());
}
@@ -317,10 +338,11 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
"BehaviorWithRequiredBehaviorProperty",
"BehaviorWithRequiredBehaviorProperty",
"A dummy behavior requiring another behavior (MyBehavior)",
"",
"",
"",
gd::make_unique<BehaviorWithRequiredBehaviorProperty>(),
"Group",
"Icon.png",
"BehaviorWithRequiredBehaviorProperty",
gd::make_unique<BehaviorWithRequiredBehaviorProperty>(
"Behavior", "MyExtension::BehaviorWithRequiredBehaviorProperty"),
gd::make_unique<gd::BehaviorsSharedData>());
}
{
@@ -331,17 +353,19 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
"A dummy behavior requiring another behavior "
"(BehaviorWithRequiredBehaviorProperty) that itself requires another "
"behavior (MyBehavior)",
"",
"",
"",
"Group",
"Icon.png",
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior",
gd::make_unique<
BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior>(),
BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior>(
"Behavior",
"MyExtension::BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior"),
gd::make_unique<gd::BehaviorsSharedData>());
}
{
auto& object = extension
->AddObject<gd::Object>(
->AddObject<gd::ObjectConfiguration>(
"FakeObjectWithUnsupportedCapability",
"FakeObjectWithUnsupportedCapability",
"This is FakeObjectWithUnsupportedCapability",

View File

@@ -0,0 +1,76 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
/**
* @file Tests covering events-based extensions
*/
#include "GDCore/IDE/WholeProjectRefactorer.h"
#include <algorithm>
#include <stdexcept>
#include "DummyPlatform.h"
#include "GDCore/Events/Builtin/LinkEvent.h"
#include "GDCore/Events/Builtin/StandardEvent.h"
#include "GDCore/Events/Event.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/UnfilledRequiredBehaviorPropertyProblem.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/Project/ExternalLayout.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/Variable.h"
#include "catch.hpp"
namespace {
gd::EventsFunctionsExtension &
SetupProjectWithEventsFunctionExtension(gd::Project &project) {
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
// Add an events-based behavior
{
auto &eventsBasedBehavior =
eventsExtension.GetEventsBasedBehaviors().InsertNew(
"MyEventsBasedBehavior", 0);
eventsBasedBehavior.SetFullName("My events based behavior");
eventsBasedBehavior.SetDescription("An events based behavior for test");
// Add a property
eventsBasedBehavior.GetPropertyDescriptors()
.InsertNew("MyProperty", 0)
.SetValue("123")
.SetType("Number");
}
return eventsExtension;
}
} // namespace
TEST_CASE("Events-based extension", "[common]") {
SECTION("Behavior property default value") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
auto &layout1 = project.InsertNewLayout("Layout1", 0);
auto &object = layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
// Attach a behavior to an object.
auto *behavior = object.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior", "MyEventsBasedBehavior");
behavior->InitializeContent();
// The behavior has the default value.
REQUIRE(behavior->GetProperties().size() == 1);
REQUIRE(behavior->GetProperties().at("MyProperty").GetValue() == "123");
}
}

View File

@@ -0,0 +1,111 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
/**
* @file Tests covering serialization to JSON.
*/
#include "DummyPlatform.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Builtin/StandardEvent.h"
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Serialization.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/Variable.h"
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Tools/SystemStats.h"
#include "GDCore/Tools/VersionWrapper.h"
#include "catch.hpp"
using namespace gd;
namespace {
void SetupProject(gd::Project &project, gd::Platform &platform) {
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto &configuration = object.GetConfiguration();
auto *spriteConfiguration = dynamic_cast<gd::SpriteObject *>(&configuration);
REQUIRE(spriteConfiguration != nullptr);
gd::Animation animation;
animation.SetName("Idle");
spriteConfiguration->AddAnimation(animation);
};
void CheckSpriteConfiguration(
SerializerElement &objectContainerElement) {
};
void CheckSpriteConfigurationInElement(SerializerElement &projectElement) {
auto &layoutsElement = projectElement.GetChild("layouts");
layoutsElement.ConsiderAsArrayOf("layout");
REQUIRE(layoutsElement.GetChildrenCount() == 1);
auto &layoutElement = layoutsElement.GetChild(0);
REQUIRE(layoutElement.GetStringAttribute("name") == "Scene");
REQUIRE(layoutElement.HasChild("objects"));
auto &objectsElement = layoutElement.GetChild("objects");
objectsElement.ConsiderAsArrayOf("object");
REQUIRE(objectsElement.GetChildrenCount() == 1);
auto &objectElement = objectsElement.GetChild(0);
REQUIRE(objectElement.GetStringAttribute("name") == "MyObject");
REQUIRE(objectElement.GetStringAttribute("type") == "MyExtension::Sprite");
REQUIRE(objectElement.HasChild("animations"));
auto &animationsElement = objectElement.GetChild("animations");
animationsElement.ConsiderAsArrayOf("animation");
REQUIRE(animationsElement.GetChildrenCount() == 1);
auto &animationElement = animationsElement.GetChild(0);
REQUIRE(animationElement.GetStringAttribute("name") ==
"Idle");
};
void CheckSpriteConfiguration(gd::Project &project) {
auto &layout = project.GetLayout("Scene");
auto &object = layout.GetObject("MyObject");
REQUIRE(object.GetName() == "MyObject");
REQUIRE(object.GetType() == "MyExtension::Sprite");
auto &configuration = object.GetConfiguration();
auto *spriteConfiguration = dynamic_cast<gd::SpriteObject *>(&configuration);
REQUIRE(spriteConfiguration);
REQUIRE(spriteConfiguration->GetAnimationsCount() == 1);
auto &animation = spriteConfiguration->GetAnimation(0);
REQUIRE(animation.GetName() == "Idle");
};
} // namespace
TEST_CASE("ObjectSerialization", "[common]") {
SECTION("Save and load a project with a sprite configuration") {
gd::Platform platform;
gd::Project writtenProject;
SetupProject(writtenProject, platform);
CheckSpriteConfiguration(writtenProject);
SerializerElement projectElement;
writtenProject.SerializeTo(projectElement);
CheckSpriteConfigurationInElement(projectElement);
gd::Project readProject;
readProject.AddPlatform(platform);
readProject.UnserializeFrom(projectElement);
CheckSpriteConfiguration(readProject);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -58,7 +58,7 @@ module.exports = {
.setName('AdMob Cordova plugin')
.setDependencyType('cordova')
.setExportName('gdevelop-cordova-admob-plus')
.setVersion('0.43.0')
.setVersion('0.45.0')
.setExtraSetting(
'APP_ID_ANDROID',
new gd.PropertyDescriptor('AdMobAppIdAndroid').setType(

View File

@@ -454,7 +454,7 @@ module.exports = {
project,
layout,
instance,
associatedObject,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
) {
@@ -463,7 +463,7 @@ module.exports = {
project,
layout,
instance,
associatedObject,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
@@ -507,7 +507,8 @@ module.exports = {
* This is called to update the PIXI object on the scene editor
*/
RenderedBBTextInstance.prototype.update = function () {
const properties = this._associatedObject.getProperties();
const properties = this._associatedObjectConfiguration
.getProperties();
const rawText = properties.get('text').getValue();
if (rawText !== this._pixiObject.text) {

View File

@@ -589,7 +589,7 @@ module.exports = {
project,
layout,
instance,
associatedObject,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
) {
@@ -598,7 +598,7 @@ module.exports = {
project,
layout,
instance,
associatedObject,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
@@ -634,7 +634,8 @@ module.exports = {
// This is called to update the PIXI object on the scene editor
RenderedBitmapTextInstance.prototype.update = function () {
const properties = this._associatedObject.getProperties();
const properties = this._associatedObjectConfiguration
.getProperties();
// Update the rendered text properties (note: Pixi is only
// applying changes if there were changed).

View File

@@ -34,7 +34,6 @@ void DeclareDestroyOutsideBehaviorExtension(gd::PlatformExtension& extension) {
std::make_shared<DestroyOutsideBehavior>(),
std::shared_ptr<gd::BehaviorsSharedData>());
#if defined(GD_IDE_ONLY)
aut.AddCondition("ExtraBorder",
_("Additional border"),
_("Compare the additional border that the object must cross "
@@ -47,8 +46,7 @@ void DeclareDestroyOutsideBehaviorExtension(gd::PlatformExtension& extension) {
.AddParameter("behavior", _("Behavior"), "DestroyOutside")
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced()
.SetFunctionName("GetExtraBorder")
.SetIncludeFile("DestroyOutsideBehavior/DestroyOutsideRuntimeBehavior.h");
.SetFunctionName("GetExtraBorder");
aut.AddAction("ExtraBorder",
_("Additional border"),
@@ -63,7 +61,5 @@ void DeclareDestroyOutsideBehaviorExtension(gd::PlatformExtension& extension) {
.UseStandardOperatorParameters("number")
.MarkAsAdvanced()
.SetFunctionName("SetExtraBorder")
.SetGetter("GetExtraBorder")
.SetIncludeFile("DestroyOutsideBehavior/DestroyOutsideRuntimeBehavior.h");
#endif
.SetGetter("GetExtraBorder");
}

View File

@@ -506,7 +506,7 @@ module.exports = {
project,
layout,
instance,
associatedObject,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
) {
@@ -515,7 +515,7 @@ module.exports = {
project,
layout,
instance,
associatedObject,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
@@ -549,7 +549,7 @@ module.exports = {
*/
RenderedDummyObjectInstance.prototype.update = function () {
// Read a property from the object
const property1Value = this._associatedObject
const property1Value = this._associatedObjectConfiguration
.getProperties()
.get('My first property')
.getValue();

View File

@@ -1786,7 +1786,7 @@ module.exports = {
'FirestoreHasDocument',
_("Check for a document's existence"),
_(
'Checks for the existence of a document. Sets the result variable to 1 if it exists else to 2.'
'Checks for the existence of a document. Sets the result variable to true if it exists else to false.'
),
_(
'Check for existence of _PARAM1_ in collection _PARAM0_ and store result in _PARAM2_ (store result state in _PARAM3_)'

View File

@@ -24,7 +24,6 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
.AddInstructionOrExpressionGroupMetadata(_("Inventories"))
.SetIcon("CppPlatform/Extensions/Inventoryicon.png");
#if defined(GD_IDE_ONLY)
extension
.AddAction("Add",
_("Add an item"),
@@ -37,8 +36,7 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("string", _("Inventory name"))
.AddParameter("string", _("Item name"))
.SetFunctionName("InventoryTools::Add")
.SetIncludeFile("Inventory/InventoryTools.h");
.SetFunctionName("InventoryTools::Add");
extension
.AddAction("Remove",
@@ -52,8 +50,7 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("string", _("Inventory name"))
.AddParameter("string", _("Item name"))
.SetFunctionName("InventoryTools::Remove")
.SetIncludeFile("Inventory/InventoryTools.h");
.SetFunctionName("InventoryTools::Remove");
extension
.AddCondition("Count",
@@ -68,8 +65,7 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
.AddParameter("string", _("Inventory name"))
.AddParameter("string", _("Item name"))
.UseStandardRelationalOperatorParameters("number")
.SetFunctionName("InventoryTools::Count")
.SetIncludeFile("Inventory/InventoryTools.h");
.SetFunctionName("InventoryTools::Count");
extension
.AddCondition("Has",
@@ -84,8 +80,7 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("string", _("Inventory name"))
.AddParameter("string", _("Item name"))
.SetFunctionName("InventoryTools::Has")
.SetIncludeFile("Inventory/InventoryTools.h");
.SetFunctionName("InventoryTools::Has");
extension
.AddAction("SetMaximum",
@@ -103,8 +98,7 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
.AddParameter("string", _("Inventory name"))
.AddParameter("string", _("Item name"))
.AddParameter("expression", _("Maximum count"))
.SetFunctionName("InventoryTools::SetMaximum")
.SetIncludeFile("Inventory/InventoryTools.h");
.SetFunctionName("InventoryTools::SetMaximum");
extension
.AddAction("SetUnlimited",
@@ -121,8 +115,7 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
.AddParameter("string", _("Inventory name"))
.AddParameter("string", _("Item name"))
.AddParameter("yesorno", _("Allow an unlimited amount?"))
.SetFunctionName("InventoryTools::SetUnlimited")
.SetIncludeFile("Inventory/InventoryTools.h");
.SetFunctionName("InventoryTools::SetUnlimited");
extension
.AddCondition("IsFull",
@@ -137,8 +130,7 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("string", _("Inventory name"))
.AddParameter("string", _("Item name"))
.SetFunctionName("InventoryTools::Has")
.SetIncludeFile("Inventory/InventoryTools.h");
.SetFunctionName("InventoryTools::Has");
extension
.AddAction("Equip",
@@ -154,8 +146,7 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
.AddParameter("string", _("Inventory name"))
.AddParameter("string", _("Item name"))
.AddParameter("yesorno", _("Equip?"))
.SetFunctionName("InventoryTools::Equip")
.SetIncludeFile("Inventory/InventoryTools.h");
.SetFunctionName("InventoryTools::Equip");
extension
.AddCondition("IsEquipped",
@@ -169,8 +160,7 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("string", _("Inventory name"))
.AddParameter("string", _("Item name"))
.SetFunctionName("InventoryTools::IsEquipped")
.SetIncludeFile("Inventory/InventoryTools.h");
.SetFunctionName("InventoryTools::IsEquipped");
extension
.AddAction("SerializeToVariable",
@@ -185,8 +175,7 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("string", _("Inventory name"))
.AddParameter("scenevar", _("Scene variable"))
.SetFunctionName("InventoryTools::SerializeToVariable")
.SetIncludeFile("Inventory/InventoryTools.h");
.SetFunctionName("InventoryTools::SerializeToVariable");
extension
.AddAction("UnserializeFromVariable",
@@ -200,8 +189,7 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("string", _("Inventory name"))
.AddParameter("scenevar", _("Scene variable"))
.SetFunctionName("InventoryTools::UnserializeFromVariable")
.SetIncludeFile("Inventory/InventoryTools.h");
.SetFunctionName("InventoryTools::UnserializeFromVariable");
extension
.AddExpression("Count",
@@ -212,7 +200,5 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("string", _("Inventory name"))
.AddParameter("string", _("Item name"))
.SetFunctionName("InventoryTools::Count")
.SetIncludeFile("Inventory/InventoryTools.h");
#endif
.SetFunctionName("InventoryTools::Count");
}

View File

@@ -44,7 +44,7 @@ module.exports = {
_('Save player score'),
_("Save the player's score to the given leaderboard."),
_(
'Send to leaderboard _PARAM1_ the score _PARAM2_ with player name: _PARAM3_.'
'Send to leaderboard _PARAM1_ the score _PARAM2_ with player name: _PARAM3_'
),
_('Save score'),
'JsPlatform/Extensions/leaderboard.svg',

View File

@@ -269,7 +269,7 @@ module.exports = {
project,
layout,
instance,
associatedObject,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
) {
@@ -278,19 +278,19 @@ module.exports = {
project,
layout,
instance,
associatedObject,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
this._radius = parseFloat(
this._associatedObject
this._associatedObjectConfiguration
.getProperties(this.project)
.get('radius')
.getValue()
);
if (this._radius <= 0) this._radius = 1;
const colorHex = objectsRenderingService.rgbOrHexToHexNumber(
this._associatedObject
this._associatedObjectConfiguration
.getProperties(this.project)
.get('color')
.getValue()

View File

@@ -28,8 +28,6 @@ void DeclareLinkedObjectsExtension(gd::PlatformExtension& extension) {
extension.AddInstructionOrExpressionGroupMetadata(_("Linked objects"))
.SetIcon("CppPlatform/Extensions/LinkedObjectsicon24.png");
#if defined(GD_IDE_ONLY)
extension
.AddAction("LinkObjects",
_("Link two objects"),
@@ -44,8 +42,7 @@ void DeclareLinkedObjectsExtension(gd::PlatformExtension& extension) {
.AddParameter("objectPtr", _("Object 1"))
.AddParameter("objectPtr", _("Object 2"))
.SetFunctionName("GDpriv::LinkedObjects::LinkObjects")
.SetIncludeFile("LinkedObjects/LinkedObjectsTools.h");
.SetFunctionName("GDpriv::LinkedObjects::LinkObjects");
extension
.AddAction("RemoveLinkBetween",
@@ -60,8 +57,7 @@ void DeclareLinkedObjectsExtension(gd::PlatformExtension& extension) {
.AddParameter("objectPtr", _("Object 1"))
.AddParameter("objectPtr", _("Object 2"))
.SetFunctionName("GDpriv::LinkedObjects::RemoveLinkBetween")
.SetIncludeFile("LinkedObjects/LinkedObjectsTools.h");
.SetFunctionName("GDpriv::LinkedObjects::RemoveLinkBetween");
extension
.AddAction("RemoveAllLinksOf",
@@ -75,8 +71,7 @@ void DeclareLinkedObjectsExtension(gd::PlatformExtension& extension) {
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("objectPtr", _("Object"))
.SetFunctionName("GDpriv::LinkedObjects::RemoveAllLinksOf")
.SetIncludeFile("LinkedObjects/LinkedObjectsTools.h");
.SetFunctionName("GDpriv::LinkedObjects::RemoveAllLinksOf");
extension
.AddCondition("PickObjectsLinkedTo",
@@ -94,8 +89,7 @@ void DeclareLinkedObjectsExtension(gd::PlatformExtension& extension) {
.AddParameter("objectPtr", _("...if they are linked to this object"))
.AddCodeOnlyParameter("eventsFunctionContext", "")
.SetFunctionName("GDpriv::LinkedObjects::PickObjectsLinkedTo")
.SetIncludeFile("LinkedObjects/LinkedObjectsTools.h");
.SetFunctionName("GDpriv::LinkedObjects::PickObjectsLinkedTo");
extension
.AddAction(
@@ -112,8 +106,5 @@ void DeclareLinkedObjectsExtension(gd::PlatformExtension& extension) {
.AddParameter("objectPtr", _("...if they are linked to this object"))
.AddCodeOnlyParameter("eventsFunctionContext", "")
.SetFunctionName("GDpriv::LinkedObjects::PickObjectsLinkedTo")
.SetIncludeFile("LinkedObjects/LinkedObjectsTools.h");
#endif
.SetFunctionName("GDpriv::LinkedObjects::PickObjectsLinkedTo");
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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