Compare commits

...

144 Commits

Author SHA1 Message Date
Florian Rival
d5f73bea0d Address some review comment 2022-10-04 22:46:55 +02:00
Florian Rival
32c69ab78a Fix typing 2022-10-04 22:46:55 +02:00
Florian Rival
3dd5e2c242 Refactor to have resourceManagementProps everywhere 2022-10-04 22:46:55 +02:00
Florian Rival
fbfcd3da5d [WIP] Allow to choose resources from the asset store in the desktop app 2022-10-04 22:42:15 +02:00
Florian Rival
0db30f02c9 Add support for opening onboarding directly on the web-app
https://editor.gdevelop.io/?initial-dialog=onboarding

Don't show in changelog
2022-10-04 16:03:12 +02:00
D8H
a852e91690 Add missing expression group icons (#4353) 2022-10-04 14:56:59 +02:00
AlexandreS
79d6281061 Add expression and condition to get highest z order of a layer (#4346) 2022-10-04 14:31:49 +02:00
AlexandreS
eba6b2540c Add price to assets home private asset packs thumbnails and display them in their dialog (#4350)
Don't show in changelog
2022-10-04 12:13:25 +02:00
D8H
0706a54305 Reorganize extensions categories (#4345) 2022-10-04 10:37:27 +02:00
D8H
d929fd6e48 Add a test on sprite hit-boxes after a camera displacement (#4349)
* Don't show in changelog
2022-10-03 14:17:01 +02:00
Florian Rival
4dbabab052 Bump newIDE version 2022-09-30 15:43:18 +02:00
D8H
827c5d6442 Add an extension category filter (#4341) 2022-09-30 15:14:23 +02:00
Florian Rival
46be0e0ffc Change previews so that they use the development environment for GDevelop APIs if running GDevelop development version (#4343)
Only show in developer changelog
2022-09-30 14:55:50 +02:00
github-actions[bot]
72e3cf5b99 Update translations (#4313) 2022-09-30 10:12:34 +02:00
D8H
54f32a2542 Add new categories for extensions (#4331) 2022-09-29 18:24:06 +02:00
D8H
b826f66455 Make the custom object renderer works better with 9-patch and text child-objects (#4335)
* Don't show in changelogs.
2022-09-29 17:16:41 +02:00
D8H
6fc03cccc6 Add help buttons in the expression editor and the extension details dialog (#4337) 2022-09-29 15:44:16 +02:00
AlexandreS
ed7313a330 Add invert condition shortcut (J key by default - configurable in your preferences) (#4334) 2022-09-29 11:18:33 +02:00
D8H
7390f7cd6a Ensure required behavior properties can't be hidden (#4336) 2022-09-29 09:54:01 +02:00
D8H
4619ae824b Allow event-based objects to define a default name for created objects (#4329)
* Don't show in changelogs
2022-09-28 17:43:51 +02:00
D8H
0f69ee435f Add tests on behavior properties initialization and unserialization (#4314)
* Don't show in changelogs
2022-09-28 17:43:18 +02:00
AlexandreS
f46241d5a2 Fix bug that prevented converting a variable to JSON when one previously tried to access an out-of-index child in a variable array (#4333) 2022-09-28 17:39:53 +02:00
D8H
4c8ec48004 Add subsections for extensions categories in the Wiki (#4332)
* Add a warning message on pages for extensions from the community list.
2022-09-28 15:34:03 +02:00
AlexandreS
3ac121be4c Add asset packs that can be purchased in the Asset store home (#4328)
Do not show in changelog
2022-09-28 15:29:45 +02:00
D8H
3aa636861c Custom objects take the icon of one of their sprite child (#4316)
* Don't show in changelogs.
2022-09-27 16:19:12 +02:00
D8H
6d4b422be6 Fix extension description links on the Wiki (#4325) 2022-09-27 16:18:18 +02:00
Clément Pasteau
b8ee27f62c Improve player authentication
* Improve player authentication by indicating when the game is not registered
* Show a link to open the window if blocked

Do not show in changelog
2022-09-27 15:19:06 +02:00
AlexandreS
6996ff452d Fix various memory leaks when using the app (#4323) 2022-09-23 18:34:34 +02:00
AlexandreS
da7934c6ac Add context menu items to manipulate the view on the scene editor (#4307)
- Return to initial position (view matches the game resolution)
- Fit zoom to selected instances
- Fit zoom to the whole scene
- Select all instances of an object on the scene (in the context menu of an object)
2022-09-23 13:27:40 +02:00
Clément Pasteau
90bebcb404 Create GDevelop Authentication extension
* This is an experimental extension!
* It allows you to provide a login/register form to your players, with 1 action
* It connects the player automatically when they launch your game again
* It also provides a new action to submit a leaderboard entry without having to enter a username
* This is the beginning of Player Authentication and more features will come allowing creators to interact with their players
2022-09-23 10:44:58 +02:00
D8H
a29e7aae44 Bump newIDE version (#4317) 2022-09-22 12:22:11 +02:00
D8H
52201e2a36 Fix tiles rotation that was no longer applied in tile maps (#4315) 2022-09-22 10:25:38 +02:00
Florian Rival
50465badd7 Bump newIDE version 2022-09-21 10:01:17 +02:00
D8H
6e1bfb0190 Fix properties on the scene of the Physics behavior not working ("shared data" of behaviors not handled properly) (#4310) 2022-09-21 09:56:38 +02:00
Aurélien Vivet
40c7c57670 Add issue template for Asset Store Submission [skip ci] (#4309)
Don't show in changelog
2022-09-20 21:43:43 +02:00
github-actions[bot]
e51c73b293 Update translations [skip ci] (#4306)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2022-09-19 11:16:17 +02:00
Florian Rival
29d5d5fe75 Bump newIDE version 2022-09-19 10:23:17 +02:00
AlexandreS
6e1f2c4eee Fix parameter fields being reset to their old value after being changed (#4308) 2022-09-19 09:28:50 +02:00
Florian Rival
2f2a89faf6 Use a purple heart instead of a red one to look less like an error
Don't show in changelog
2022-09-16 12:23:15 +02:00
AlexandreS
4100b24dfd Improve display of black icons on dark themes (#4302) 2022-09-16 12:22:11 +02:00
AlexandreS
c616abe1c5 Bump newIDE version 2022-09-16 10:45:10 +02:00
Aurélien Vivet
35084de4f6 Add a new expression: Pi number (3.1415...) (#4304) 2022-09-16 10:30:46 +02:00
github-actions[bot]
6ecb5e9d8c Update translations [skip ci] (#4291)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2022-09-16 10:09:03 +02:00
D8H
9532a8f6de Fix extension upgrades that was leaving duplicated behaviors. (#4301)
- Don't show in changelogs (the regression is between the 140 and the 141)
2022-09-15 15:43:28 +02:00
D8H
00a5b0b402 Fix events-based behavior default name. (#4300)
* Don't show in changelogs (the regression is between the 140 and the 141)
2022-09-15 11:57:28 +02:00
D8H
629567ad21 Fix tile maps with rectangular tiles (#4299) 2022-09-14 19:04:42 +02:00
D8H
5f21229ccc Remove a file commited by mistake (#4296) 2022-09-14 18:40:48 +02:00
Florian Rival
27cf2ef596 Remove shadow on home page menu buttons
Don't show in changelog
2022-09-14 16:44:47 +02:00
AlexandreS
2bc9a6d19d Fix previews on private navigation for cloud projects
Do not show in changelog
2022-09-14 16:29:15 +02:00
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
722 changed files with 30447 additions and 14318 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

@@ -0,0 +1,19 @@
---
name: "📦 Asset Store submission"
about: Submit a free asset pack for the GDevelop Asset Store.
title: ''
labels: "📦 Asset Store submission"
assignees: ''
---
BEFORE opening a new submission, please make sure that you:
- You have packaged the asset pack according [these rules](https://wiki.gdevelop.io/gdevelop5/community/contribute-to-the-assets-store). Otherwise, your package may be rejected or we will ask you to do the changes.
## Description
- License:
- Author:
- Link to the original website:
- Zip file:

View File

@@ -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",
@@ -36,8 +36,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Compare the X position of the object."),
_("the X position"),
_("Position"),
"res/conditions/position24.png",
"res/conditions/position.png")
"res/conditions/position24_black.png",
"res/conditions/position_black.png")
.AddParameter("object", _("Object"))
.UseStandardRelationalOperatorParameters("number")
@@ -48,8 +48,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Change the X position of an object."),
_("the X position"),
_("Position"),
"res/actions/position24.png",
"res/actions/position.png")
"res/actions/position24_black.png",
"res/actions/position_black.png")
.AddParameter("object", _("Object"))
.UseStandardOperatorParameters("number")
@@ -60,8 +60,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Compare the Y position of an object."),
_("the Y position"),
_("Position"),
"res/conditions/position24.png",
"res/conditions/position.png")
"res/conditions/position24_black.png",
"res/conditions/position_black.png")
.AddParameter("object", _("Object"))
.UseStandardRelationalOperatorParameters("number")
@@ -72,8 +72,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Change the Y position of an object."),
_("the Y position"),
_("Position"),
"res/actions/position24.png",
"res/actions/position.png")
"res/actions/position24_black.png",
"res/actions/position_black.png")
.AddParameter("object", _("Object"))
.UseStandardOperatorParameters("number")
@@ -85,8 +85,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Change the position of _PARAM0_: _PARAM1_ _PARAM2_ (x "
"axis), _PARAM3_ _PARAM4_ (y axis)"),
_("Position"),
"res/actions/position24.png",
"res/actions/position.png")
"res/actions/position24_black.png",
"res/actions/position_black.png")
.AddParameter("object", _("Object"))
.AddParameter("operator", _("Modification's sign"), "number")
@@ -102,8 +102,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"_PARAM2_ (x "
"axis), _PARAM3_ _PARAM4_ (y axis)"),
_("Position/Center"),
"res/actions/position24.png",
"res/actions/position.png")
"res/actions/position24_black.png",
"res/actions/position_black.png")
.AddParameter("object", _("Object"))
.AddParameter("operator", _("Modification's sign"), "number")
.AddParameter("expression", _("X position"))
@@ -118,7 +118,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the X position of the center of rotation"),
_("the X position of the center"),
_("Position/Center"),
"res/actions/position24.png")
"res/actions/position24_black.png")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -129,7 +129,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the Y position of the center of rotation"),
_("the Y position of the center"),
_("Position/Center"),
"res/actions/position24.png")
"res/actions/position24_black.png")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -140,7 +140,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"the object) left position"),
_("the bounding box left position"),
_("Position/Bounding Box"),
"res/conditions/bounding-box-left.svg")
"res/conditions/bounding-box-left_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -151,7 +151,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the bounding box (the area encapsulating the object) top position"),
_("the bounding box top position"),
_("Position/Bounding Box"),
"res/conditions/bounding-box-top.svg")
"res/conditions/bounding-box-top_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -162,7 +162,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"the object) right position"),
_("the bounding box right position"),
_("Position/Bounding Box"),
"res/conditions/bounding-box-right.svg")
"res/conditions/bounding-box-right_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -173,7 +173,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"the object) bottom position"),
_("the bounding box bottom position"),
_("Position/Bounding Box"),
"res/conditions/bounding-box-bottom.svg")
"res/conditions/bounding-box-bottom_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -184,7 +184,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"the object) center X position"),
_("the bounding box center X position"),
_("Position/Bounding Box"),
"res/conditions/bounding-box-center.svg")
"res/conditions/bounding-box-center_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -195,7 +195,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"the object) center Y position"),
_("the bounding box center Y position"),
_("Position/Bounding Box"),
"res/conditions/bounding-box-center.svg")
"res/conditions/bounding-box-center_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -222,8 +222,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Change the angle of rotation of an object (in degrees)."),
_("the angle"),
_("Angle"),
"res/actions/direction24.png",
"res/actions/direction.png")
"res/actions/direction24_black.png",
"res/actions/direction_black.png")
.AddParameter("object", _("Object"))
.UseStandardOperatorParameters("number");
@@ -234,8 +234,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"counterclockwise otherwise."),
_("Rotate _PARAM0_ at speed _PARAM1_ deg/second"),
_("Angle"),
"res/actions/direction24.png",
"res/actions/direction.png")
"res/actions/rotate24_black.png",
"res/actions/rotate_black.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angular speed (in degrees per second)"))
@@ -248,8 +248,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Rotate an object towards an angle with the specified speed."),
_("Rotate _PARAM0_ towards _PARAM1_ at speed _PARAM2_ deg/second"),
_("Angle"),
"res/actions/direction24.png",
"res/actions/direction.png")
"res/actions/rotate24_black.png",
"res/actions/rotate_black.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angle to rotate towards (in degrees)"))
@@ -264,8 +264,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Rotate _PARAM0_ towards _PARAM1_;_PARAM2_ at speed "
"_PARAM3_ deg/second"),
_("Angle"),
"res/actions/direction24.png",
"res/actions/direction.png")
"res/actions/rotate24_black.png",
"res/actions/rotate_black.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("X position"))
@@ -393,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();
@@ -512,8 +512,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Compare the angle of the specified object."),
_("the angle (in degrees)"),
_("Angle"),
"res/conditions/direction24.png",
"res/conditions/direction.png")
"res/conditions/direction24_black.png",
"res/conditions/direction_black.png")
.AddParameter("object", _("Object"))
.UseStandardRelationalOperatorParameters("number")
@@ -965,21 +965,21 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("X position"),
_("X position of the object"),
_("Position"),
"res/actions/position.png")
"res/actions/position_black.png")
.AddParameter("object", _("Object"));
obj.AddExpression("Y",
_("Y position"),
_("Y position of the object"),
_("Position"),
"res/actions/position.png")
"res/actions/position_black.png")
.AddParameter("object", _("Object"));
obj.AddExpression("Angle",
_("Angle"),
_("Current angle, in degrees, of the object"),
_("Angle"),
"res/actions/direction.png")
"res/actions/direction_black.png")
.AddParameter("object", _("Object"));
obj.AddExpression("ForceX",
@@ -1022,14 +1022,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Width"),
_("Width of the object"),
_("Size"),
"res/actions/scaleWidth.png")
"res/actions/scaleWidth_black.png")
.AddParameter("object", _("Object"));
obj.AddExpression("Largeur",
_("Width"),
_("Width of the object"),
_("Size"),
"res/actions/scaleWidth.png")
"res/actions/scaleWidth_black.png")
.AddParameter("object", _("Object"))
.SetHidden();
@@ -1037,14 +1037,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Height"),
_("Height of the object"),
_("Size"),
"res/actions/scaleHeight.png")
"res/actions/scaleHeight_black.png")
.AddParameter("object", _("Object"));
obj.AddExpression("Hauteur",
_("Height"),
_("Height of the object"),
_("Size"),
"res/actions/scaleHeight.png")
"res/actions/scaleHeight_black.png")
.AddParameter("object", _("Object"))
.SetHidden();
@@ -1098,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")
@@ -1114,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")
@@ -1135,7 +1135,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"If you need the angle to an arbitrary position, "
"use AngleToPosition."),
_("Angle"),
"res/actions/position.png")
"res/actions/position_black.png")
.AddParameter("object", _("Object"))
.AddParameter("objectPtr", _("Object"));
@@ -1146,7 +1146,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"getting the cartesian coordinates of a 2D vector, using "
"its polar coordinates."),
_("Position"),
"res/actions/position.png")
"res/actions/position_black.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angle, in degrees"))
.AddParameter("expression", _("Distance"));
@@ -1158,7 +1158,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"getting the cartesian coordinates of a 2D vector, using "
"its polar coordinates."),
_("Position"),
"res/actions/position.png")
"res/actions/position_black.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angle, in degrees"))
.AddParameter("expression", _("Distance"));
@@ -1169,7 +1169,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"\"target\" position (in degrees). If you need the angle "
"between two objects, use AngleToObject."),
_("Angle"),
"res/actions/position.png")
"res/actions/position_black.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Target X position"))
.AddParameter("expression", _("Target Y position"));
@@ -1565,7 +1565,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Object name"),
_("Return the name of the object"),
"",
"res/conditions/text.png")
"res/conditions/text_black.png")
.AddParameter("object", _("Object"));
obj.AddStrExpression("Layer",

View File

@@ -22,6 +22,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"object or a position.",
"Florian Rival",
"Open source (MIT License)")
.SetCategory("Camera")
.SetExtensionHelpPath("/interface/scene-editor/layers-and-cameras");
extension.AddInstructionOrExpressionGroupMetadata(_("Layers and cameras"))
.SetIcon("res/conditions/camera24.png");
@@ -221,7 +222,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 +257,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 +273,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 +291,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 +310,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 +414,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 +427,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 +440,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 +577,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 "
@@ -589,6 +590,19 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.SetDefaultValue("\"\"")
.AddParameter("expression", _("New default Z order"));
extension
.AddExpressionAndCondition("number",
"LayerHighestZOrder",
_("Layer highest Z order"),
_("the highest Z order of objects in a layer"),
_("the highest Z order of objects in the layer _PARAM1_"),
"",
"res/conditions/layer.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.UseStandardParameters("number");
extension
.AddAction(
"SetLayerAmbientLightColor",

View File

@@ -21,14 +21,14 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
"Open source (MIT License)")
.SetExtensionHelpPath("/all-features/common-conversions");
extension.AddInstructionOrExpressionGroupMetadata(_("Conversion"))
.SetIcon("res/conditions/toujours24.png");
.SetIcon("res/conditions/toujours24_black.png");
extension
.AddExpression("ToNumber",
_("Text > Number"),
_("Convert the text to a number"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("string", _("Text to convert to a number"));
extension
@@ -36,7 +36,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
_("Number > Text"),
_("Convert the result of the expression to text"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("expression", _("Expression to be converted to text"));
extension
@@ -45,7 +45,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
_("Convert the result of the expression to text, "
"without using the scientific notation"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("expression", _("Expression to be converted to text"));
extension
@@ -54,7 +54,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
_("Degrees > Radians"),
_("Converts the angle, expressed in degrees, into radians"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("expression", _("Angle, in degrees"));
extension
@@ -63,7 +63,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
_("Radians > Degrees"),
_("Converts the angle, expressed in radians, into degrees"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("expression", _("Angle, in radians"));
extension
@@ -71,7 +71,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
_("Convert scene variable to JSON"),
_("Convert a scene variable to JSON"),
_("JSON"),
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("scenevar", _("Scene variable to be stringified"));
extension
@@ -79,7 +79,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
_("Convert global variable to JSON"),
_("Convert a global variable to JSON"),
_("JSON"),
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("globalvar", _("The global variable to be stringified"));
extension
@@ -87,7 +87,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
_("Convert object variable to JSON"),
_("Convert an object variable to JSON"),
_("JSON"),
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("objectPtr", _("The object with the variable"))
.AddParameter("objectvar", _("The object variable to be stringified"));

View File

@@ -33,7 +33,7 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
.SetExtensionHelpPath("/all-features/advanced-conditions");
extension
.AddInstructionOrExpressionGroupMetadata(_("Events and control flow"))
.SetIcon("res/conditions/toujours24.png");
.SetIcon("res/conditions/toujours24_black.png");
extension
.AddCondition("Always",
@@ -42,8 +42,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
"the condition is inverted)."),
_("Always"),
"",
"res/conditions/toujours24.png",
"res/conditions/toujours.png")
"res/conditions/toujours24_black.png",
"res/conditions/toujours_black.png")
.SetHelpPath("/all-features/advanced-conditions")
.AddCodeOnlyParameter("conditionInverted", "")
.MarkAsAdvanced();
@@ -61,8 +61,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
_("Check if one of the sub conditions is true"),
_("If one of these conditions is true:"),
"",
"res/conditions/or24.png",
"res/conditions/or.png")
"res/conditions/or24_black.png",
"res/conditions/or_black.png")
.SetCanHaveSubInstructions()
.MarkAsAdvanced();
@@ -72,8 +72,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
_("Check if all sub conditions are true"),
_("If all of these conditions are true:"),
"",
"res/conditions/and24.png",
"res/conditions/and.png")
"res/conditions/and24_black.png",
"res/conditions/and_black.png")
.SetCanHaveSubInstructions()
.MarkAsAdvanced();
@@ -84,8 +84,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
_("Return the contrary of the result of the sub conditions"),
_("Invert the logical result of these conditions:"),
"",
"res/conditions/not24.png",
"res/conditions/not.png")
"res/conditions/not24_black.png",
"res/conditions/not_black.png")
.SetCanHaveSubInstructions()
.MarkAsAdvanced();
@@ -104,8 +104,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
_("Compare the two numbers."),
_("_PARAM0_ _PARAM1_ _PARAM2_"),
"",
"res/conditions/egal24.png",
"res/conditions/egal.png")
"res/conditions/egal24_black.png",
"res/conditions/egal_black.png")
.SetHelpPath("/all-features/advanced-conditions")
.AddParameter("expression", _("First expression"))
.AddParameter("relationalOperator", _("Sign of the test"), "number")
@@ -125,8 +125,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
_("Compare the two strings."),
_("_PARAM0_ _PARAM1_ _PARAM2_"),
"",
"res/conditions/egal24.png",
"res/conditions/egal.png")
"res/conditions/egal24_black.png",
"res/conditions/egal_black.png")
.SetHelpPath("/all-features/advanced-conditions")
.AddParameter("string", _("First string expression"))
.AddParameter("relationalOperator", _("Sign of the test"), "string")

View File

@@ -21,7 +21,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/all-features/storage")
.SetCategory("Device");
.SetCategory("Advanced");
extension.AddInstructionOrExpressionGroupMetadata(_("Storage"))
.SetIcon("res/conditions/fichier24.png");

View File

@@ -485,6 +485,13 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
.AddParameter("expression", _("Angle, in degrees"))
.AddParameter("expression", _("Distance"));
extension
.AddExpression("Pi",
_("Number Pi (3.1415...)"),
_("The number Pi (3.1415...)"),
"",
"res/mathfunction.png")
.SetHelpPath("/all-features/expressions");
}
} // namespace gd

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

@@ -22,6 +22,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/objects/sprite");
extension.AddInstructionOrExpressionGroupMetadata(_("Sprite"))
.SetIcon("CppPlatform/Extensions/spriteicon.png");
gd::ObjectMetadata& obj =
extension
@@ -33,7 +35,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"),
@@ -79,8 +81,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"is in 8 directions mode, the valid directions are 0..7"),
_("the direction"),
_("Direction"),
"res/actions/direction24.png",
"res/actions/direction.png")
"res/actions/direction24_black.png",
"res/actions/direction_black.png")
.SetHidden() // Hide as 8 direction is not supported officially in the
// interface.
.AddParameter("object", _("Object"), "Sprite")
@@ -140,8 +142,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"Rotate an object towards a position.",
"Rotate _PARAM0_ towards _PARAM1_;_PARAM2_",
_("Direction"),
"res/actions/direction24.png",
"res/actions/direction.png")
"res/actions/rotate24_black.png",
"res/actions/rotate_black.png")
.AddParameter("object", _("Object to be rotated"), "Sprite")
.AddParameter("expression", _("X position"))
@@ -156,8 +158,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Modify the scale of the specified object."),
_("the scale"),
_("Size"),
"res/actions/scale24.png",
"res/actions/scale.png")
"res/actions/scale24_black.png",
"res/actions/scale_black.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
@@ -168,8 +170,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Modify the scale of the width of an object."),
_("the width's scale"),
_("Size"),
"res/actions/scale24.png",
"res/actions/scale.png")
"res/actions/scaleWidth24_black.png",
"res/actions/scaleWidth_black.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
@@ -180,8 +182,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Modify the scale of the height of an object."),
_("the height's scale"),
_("Size"),
"res/actions/scale24.png",
"res/actions/scale.png")
"res/actions/scaleHeight24_black.png",
"res/actions/scaleHeight_black.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
@@ -192,8 +194,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Change the width of a Sprite object."),
_("the width"),
_("Size"),
"res/actions/scale24.png",
"res/actions/scale.png")
"res/actions/scaleWidth24_black.png",
"res/actions/scaleWidth_black.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
@@ -204,8 +206,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Compare the width of a Sprite object."),
_("the width"),
_("Size"),
"res/conditions/scaleWidth24.png",
"res/conditions/scaleWidth.png")
"res/conditions/scaleWidth24_black.png",
"res/conditions/scaleWidth_black.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters("number")
@@ -216,8 +218,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Change the height of a Sprite object."),
_("the height"),
_("Size"),
"res/actions/scale24.png",
"res/actions/scale.png")
"res/actions/scaleHeight24_black.png",
"res/actions/scaleHeight_black.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
@@ -228,8 +230,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Compare the height of a Sprite object."),
_("the height"),
_("Size"),
"res/conditions/scaleHeight24.png",
"res/conditions/scaleHeight.png")
"res/conditions/scaleHeight24_black.png",
"res/conditions/scaleHeight_black.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters("number")
@@ -240,8 +242,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Change the size of an object."),
_("Change the size of _PARAM0_: set to _PARAM1_x_PARAM2_"),
_("Size"),
"res/actions/scale24.png",
"res/actions/scale.png")
"res/actions/scale24_black.png",
"res/actions/scale_black.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Width"))
@@ -281,8 +283,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"from 0 to 7. Otherwise, the direction is in degrees."),
_("the direction"),
_("Direction"),
"res/conditions/direction24.png",
"res/conditions/direction.png")
"res/conditions/direction24_black.png",
"res/conditions/direction_black.png")
.SetHidden() // Hide as 8 direction is not supported officially in the
// interface.
.AddParameter("object", _("Object"), "Sprite")
@@ -330,8 +332,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Compare the scale of the width of an object."),
_("the width's scale"),
_("Size"),
"res/conditions/scaleWidth24.png",
"res/conditions/scaleWidth.png")
"res/conditions/scaleWidth24_black.png",
"res/conditions/scaleWidth_black.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters("number")
@@ -342,8 +344,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Compare the scale of the height of an object."),
_("the height's scale"),
_("Size"),
"res/conditions/scaleHeight24.png",
"res/conditions/scaleHeight.png")
"res/conditions/scaleHeight24_black.png",
"res/conditions/scaleHeight_black.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters("number")
@@ -449,8 +451,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"Rotate an object towards another.",
"Rotate _PARAM0_ towards _PARAM1_",
_("Direction"),
"res/actions/direction24.png",
"res/actions/direction.png")
"res/actions/rotate24_black.png",
"res/actions/rotate_black.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectPtr", "Rotate toward this object")
@@ -461,7 +463,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("X position of a point"),
_("X position of a point"),
_("Position"),
"res/actions/position.png")
"res/actions/position_black.png")
.SetHidden()
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectPointName", _("Name of the point"), "", true);
@@ -470,7 +472,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Y position of a point"),
_("Y position of a point"),
_("Position"),
"res/actions/position.png")
"res/actions/position_black.png")
.SetHidden()
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectPointName", _("Name of the point"), "", true);
@@ -479,7 +481,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("X position of a point"),
_("X position of a point"),
_("Position"),
"res/actions/position.png")
"res/actions/position_black.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectPointName", _("Name of the point"));
@@ -488,7 +490,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Y position of a point"),
_("Y position of a point"),
_("Position"),
"res/actions/position.png")
"res/actions/position_black.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectPointName", _("Name of the point"));
@@ -497,7 +499,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Direction"),
_("Direction of the object"),
_("Direction"),
"res/actions/direction.png")
"res/actions/direction_black.png")
.SetHidden()
.AddParameter("object", _("Object"), "Sprite");
@@ -505,7 +507,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Direction"),
_("Direction of the object"),
_("Direction"),
"res/actions/direction.png")
"res/actions/direction_black.png")
.SetHidden() // Hide as 8 direction is not supported officially in the
// interface.
.AddParameter("object", _("Object"), "Sprite");
@@ -550,14 +552,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Scale of the width of an object"),
_("Scale of the width of an object"),
_("Size"),
"res/actions/scaleWidth.png")
"res/actions/scaleWidth_black.png")
.AddParameter("object", _("Object"), "Sprite");
obj.AddExpression("ScaleY",
_("Scale of the height of an object"),
_("Scale of the height of an object"),
_("Size"),
"res/actions/scaleHeight.png")
"res/actions/scaleHeight_black.png")
.AddParameter("object", _("Object"), "Sprite");
obj.AddExpression("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,20 +21,20 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
"Open source (MIT License)")
.SetExtensionHelpPath("" /*TODO: Add a documentation page for this */);
extension.AddInstructionOrExpressionGroupMetadata(_("Text manipulation"))
.SetIcon("res/actions/text24.png");
.SetIcon("res/actions/text24_black.png");
extension.AddStrExpression("NewLine",
_("Insert a new line"),
_("Insert a new line"),
"",
"res/conditions/toujours24.png");
"res/conditions/toujours24_black.png");
extension
.AddStrExpression("FromCodePoint",
_("Get character from code point"),
_("Get character from code point"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("expression", _("Code point"));
@@ -43,7 +43,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Uppercase a text"),
_("Uppercase a text"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("string", _("Text"));
@@ -52,7 +52,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Lowercase a text"),
_("Lowercase a text"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("string", _("Text"));
@@ -61,7 +61,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Get a portion of a text"),
_("Get a portion of a text"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("string", _("Text"))
.AddParameter("expression",
@@ -74,7 +74,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Get a character from a text"),
_("Get a character from a text"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("string", _("Text"))
.AddParameter(
@@ -86,7 +86,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Repeat a text"),
_("Repeat a text"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("string", _("Text to repeat"))
.AddParameter("expression", _("Repetition count"));
@@ -96,7 +96,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Length of a text"),
_("Length of a text"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("string", _("Text"));
@@ -106,7 +106,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Search in a text (return the position of the result or "
"-1 if not found)"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"));
@@ -117,7 +117,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
"Search in a text from the end (return the position of "
"the result or -1 if not found)",
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"))
@@ -131,7 +131,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
"the result, from the beginning of the string, or -1 if not "
"found)"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"));
@@ -142,7 +142,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Search in a text, starting from a position (return the "
"position of the result or -1 if not found)"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"))
@@ -157,7 +157,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
"Search in a text from the end, starting from a position (return "
"the position of the result or -1 if not found)",
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"))
@@ -175,7 +175,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
" the position of the result, from the beginning of the string, or "
"-1 if not found)"),
"",
"res/conditions/toujours24.png")
"res/conditions/toujours24_black.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"))

View File

@@ -136,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_"),
"",
@@ -153,8 +153,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
"the next actions (and sub-events)."),
_("Wait _PARAM0_ seconds"),
"",
"res/timer.svg",
"res/timer.svg")
"res/timer_black.svg",
"res/timer_black.svg")
.AddParameter("expression", "Time to wait in seconds")
.SetHelpPath("/all-features/timers-and-time/wait-action");

View File

@@ -20,6 +20,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
"these features can be applied.",
"Florian Rival",
"Open source (MIT License)")
.SetCategory("User interface")
.SetExtensionHelpPath("/all-features/window");
extension
.AddInstructionOrExpressionGroupMetadata(
@@ -55,7 +56,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 +72,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 +118,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 +154,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 +165,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,12 +14,14 @@
#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 {
BehaviorMetadata::BehaviorMetadata(
const gd::String& extensionNamespace_,
const gd::String& name_,
const gd::String& nameWithNamespace,
const gd::String& fullname_,
const gd::String& defaultName_,
const gd::String& description_,
@@ -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) instance->SetTypeName(name_);
if (sharedDatasInstance) sharedDatasInstance->SetTypeName(name_);
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: " + nameWithNamespace);
}
if (instance) instance->SetTypeName(nameWithNamespace);
if (sharedDatasInstance) sharedDatasInstance->SetTypeName(nameWithNamespace);
}
BehaviorMetadata::BehaviorMetadata(
const gd::String& extensionNamespace,
const gd::String& nameWithNamespace,
const gd::String& fullname_,
const gd::String& defaultName_,
const gd::String& description_,
const gd::String& group_,
const gd::String& icon24x24_): BehaviorMetadata(
extensionNamespace,
nameWithNamespace,
fullname_,
defaultName_,
description_,
group_,
icon24x24_,
// Class name is the name, actually unused
defaultName_,
// It is only used to get the name for GetName.
gd::make_unique<gd::Behavior>("", nameWithNamespace),
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

@@ -29,7 +29,7 @@ class GD_CORE_API BehaviorMetadata {
public:
BehaviorMetadata(
const gd::String& extensionNamespace,
const gd::String& name_,
const gd::String& nameWithNamespace,
const gd::String& fullname_,
const gd::String& defaultName_,
const gd::String& description_,
@@ -38,6 +38,21 @@ 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& nameWithNamespace,
const gd::String& fullname_,
const gd::String& defaultName_,
const gd::String& description_,
const gd::String& group_,
const gd::String& icon24x24_);
BehaviorMetadata(){};
virtual ~BehaviorMetadata(){};
@@ -195,6 +210,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 +261,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 +297,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

@@ -361,7 +361,7 @@ class GD_CORE_API InstructionMetadata {
* _("the string"),
* _("Text"),
* "CppPlatform/Extensions/text24.png",
* "CppPlatform/Extensions/text.png");
* "CppPlatform/Extensions/text_black.png");
*
* .AddParameter("object", _("Object"), "Text", false)
* .AddParameter("operator", _("Modification operator"), "string")

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,25 @@ 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,
// Default name is the name
name,
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

@@ -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;
@@ -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);
}
}

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,40 @@
/*
* 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 {
element.SetAttribute("defaultName", defaultName);
AbstractEventsBasedEntity::SerializeTo(element);
SerializeObjectsTo(element.AddChild("objects"));
}
void EventsBasedObject::UnserializeFrom(gd::Project& project,
const SerializerElement& element) {
defaultName = element.GetStringAttribute("defaultName");
AbstractEventsBasedEntity::UnserializeFrom(project, element);
UnserializeObjectsFrom(project, element.GetChild("objects"));
}
} // namespace gd

View File

@@ -0,0 +1,86 @@
/*
* 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); };
/**
* \brief Get the default name for created objects.
*/
const gd::String& GetDefaultName() const { return defaultName; };
/**
* \brief Set the default name for created objects.
*/
EventsBasedObject& SetDefaultName(const gd::String& defaultName_) {
defaultName = defaultName_;
return *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:
gd::String defaultName;
};
} // 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,34 @@ 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"));
eventsBasedObjects.UnserializeElementsFrom(
"eventsBasedObject", project, element.GetChild("eventsBasedObjects"));
}
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,10 @@ 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;
gd::BehaviorsSharedData* behaviorSharedData =
behaviorMetadata.GetSharedDataInstance();
if (!behaviorSharedData) continue;
auto behaviorContent =
gd::make_unique<gd::BehaviorContent>(name, allBehaviorsTypes[i]);
behaviorSharedData->InitializeContent(behaviorContent->GetContent());
behaviorsSharedData[name] = std::move(behaviorContent);
auto sharedData = CreateBehaviorsSharedData(project, name, allBehaviorsTypes[i]);
if (sharedData) {
behaviorsSharedData[name] = std::move(sharedData);
}
}
// Remove useless shared data:
@@ -253,6 +240,33 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
}
}
std::unique_ptr<gd::BehaviorsSharedData> Layout::CreateBehaviorsSharedData(gd::Project& project, const gd::String& name, const gd::String& behaviorsType) {
if (project.HasEventsBasedBehavior(behaviorsType)) {
// Events based behaviors don't have shared data yet.
auto sharedData =
gd::make_unique<gd::BehaviorsSharedData>(name, behaviorsType);
sharedData->InitializeContent();
return std::move(sharedData);
}
const gd::BehaviorMetadata& behaviorMetadata =
gd::MetadataProvider::GetBehaviorMetadata(
project.GetCurrentPlatform(),
behaviorsType);
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
return nullptr;
}
gd::BehaviorsSharedData* behaviorsSharedDataBluePrint =
behaviorMetadata.GetSharedDataInstance();
if (!behaviorsSharedDataBluePrint) return nullptr;
auto sharedData = behaviorsSharedDataBluePrint->Clone();
sharedData->SetName(name);
sharedData->SetTypeName(behaviorsType);
sharedData->InitializeContent();
return std::unique_ptr<gd::BehaviorsSharedData>(sharedData);
}
void Layout::SerializeTo(SerializerElement& element) const {
element.SetAttribute("name", GetName());
element.SetAttribute("mangledName", GetMangledName());
@@ -260,17 +274,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 +330,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 +370,23 @@ 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);
// 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"));
auto sharedData = CreateBehaviorsSharedData(project, name, type);
if (sharedData) {
// 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")) {
sharedData->UnserializeFrom(sharedDataElement.GetChild("content"));
}
// end of compatibility code
else {
sharedData->UnserializeFrom(sharedDataElement);
}
behaviorsSharedData[name] = std::move(sharedData);
}
// end of compatibility code
else {
behaviorContent->UnserializeFrom(sharedDataElement);
}
behaviorsSharedData[name] = std::move(behaviorContent);
}
}
@@ -388,9 +397,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 +408,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());
std::unique_ptr<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,38 +377,38 @@ 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.
* Don't forget to update me if members were changed!
*/
void Init(const gd::Layout& other);
std::unique_ptr<gd::BehaviorsSharedData> CreateBehaviorsSharedData(
gd::Project& project,
const gd::String& name,
const gd::String& behaviorsType);
};
/**

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

@@ -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

@@ -28,7 +28,7 @@ module.exports = {
'Arthur Pacaud (arthuro555)',
'MIT'
)
.setCategory('Device');
.setCategory('User interface');
extension
.addInstructionOrExpressionGroupMetadata(_('Advanced window management'))
.setIcon('res/actions/window24.png');

View File

@@ -17,6 +17,7 @@ void DeclareAnchorBehaviorExtension(gd::PlatformExtension& extension) {
_("Anchor objects to the window's bounds."),
"Victor Levasseur",
"Open source (MIT License)")
.SetCategory("User interface")
.SetExtensionHelpPath("/behaviors/anchor");
gd::BehaviorMetadata& aut = extension.AddBehavior(

View File

@@ -33,7 +33,10 @@ module.exports = {
'Todor Imreorov',
'Open source (MIT License)'
)
.setExtensionHelpPath('/objects/bbtext');
.setExtensionHelpPath('/objects/bbtext')
.setCategory('User interface');
extension.addInstructionOrExpressionGroupMetadata(_("BBCode Text Object"))
.setIcon("JsPlatform/Extensions/bbcode32.png");
var objectBBText = new gd.ObjectJsImplementation();
// $FlowExpectedError
@@ -168,7 +171,7 @@ module.exports = {
.addIncludeFile(
'Extensions/BBText/pixi-multistyle-text/dist/pixi-multistyle-text.umd.js'
)
.setCategoryFullName(_('Texts'));
.setCategoryFullName(_('User interface'));
/**
* Utility function to add both a setter and a getter to a property from a list.
@@ -289,7 +292,7 @@ module.exports = {
const setterAndGetterProperties = [
{
functionName: 'BBText',
iconPath: 'res/actions/text24.png',
iconPath: 'res/actions/text24_black.png',
type: 'string',
paramLabel: _('BBCode text'),
conditionDescription: _('Compare the value of the BBCode text.'),
@@ -364,7 +367,7 @@ module.exports = {
},
{
functionName: 'WordWrap',
iconPath: 'res/actions/scaleWidth24.png',
iconPath: 'res/actions/scaleWidth24_black.png',
type: 'boolean',
paramLabel: _('Word wrap'),
conditionDescription: _('Check if word wrap is enabled.'),
@@ -376,7 +379,7 @@ module.exports = {
},
{
functionName: 'WrappingWidth',
iconPath: 'res/actions/scaleWidth24.png',
iconPath: 'res/actions/scaleWidth24_black.png',
type: 'number',
paramLabel: _('Wrapping width'),
conditionDescription: _(
@@ -454,7 +457,7 @@ module.exports = {
project,
layout,
instance,
associatedObject,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
) {
@@ -463,7 +466,7 @@ module.exports = {
project,
layout,
instance,
associatedObject,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
@@ -498,7 +501,7 @@ module.exports = {
RenderedBBTextInstance.getThumbnail = function (
project,
resourcesLoader,
object
objectConfiguration
) {
return 'JsPlatform/Extensions/bbcode24.png';
};
@@ -507,7 +510,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

@@ -35,7 +35,10 @@ module.exports = {
'Aurélien Vivet',
'Open source (MIT License)'
)
.setExtensionHelpPath('/objects/bitmap_text');
.setExtensionHelpPath('/objects/bitmap_text')
.setCategory('User interface');
extension.addInstructionOrExpressionGroupMetadata(_("Bitmap Text"))
.setIcon("JsPlatform/Extensions/bitmapfont32.png");
const bitmapTextObject = new gd.ObjectJsImplementation();
// $FlowExpectedError
@@ -171,7 +174,7 @@ module.exports = {
.addIncludeFile(
'Extensions/BitmapText/bitmaptextruntimeobject-pixi-renderer.js'
)
.setCategoryFullName(_('Texts'));
.setCategoryFullName(_('User interface'));
object
.addExpressionAndConditionAndAction(
@@ -181,7 +184,7 @@ module.exports = {
_('the text'),
_('the text'),
'',
'res/conditions/text24.png'
'res/conditions/text24_black.png'
)
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
.useStandardParameters('string')
@@ -225,7 +228,7 @@ module.exports = {
_('the scale (1 by default)'),
_('the scale'),
'',
'res/actions/scale24.png'
'res/actions/scale24_black.png'
)
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
.useStandardParameters('number')
@@ -331,8 +334,8 @@ module.exports = {
_('Check if word wrap is enabled.'),
_('_PARAM0_ word wrap is enabled'),
'',
'res/conditions/wordWrap24.png',
'res/conditions/wordWrap.png'
'res/conditions/wordWrap24_black.png',
'res/conditions/wordWrap_black.png'
)
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
.getCodeExtraInformation()
@@ -345,8 +348,8 @@ module.exports = {
_('De/activate word wrapping.'),
_('Activate word wrap of _PARAM0_: _PARAM1_'),
'',
'res/actions/wordWrap24.png',
'res/actions/wordWrap.png'
'res/actions/wordWrap24_black.png',
'res/actions/wordWrap_black.png'
)
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
.addParameter('yesorno', _('Activate word wrap'), '', false)
@@ -361,7 +364,7 @@ module.exports = {
_('the width, in pixels, after which the text is wrapped on next line'),
_('the wrapping width'),
'',
'res/actions/scaleWidth24.png'
'res/actions/scaleWidth24_black.png'
)
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
.useStandardParameters('number')
@@ -589,7 +592,7 @@ module.exports = {
project,
layout,
instance,
associatedObject,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
) {
@@ -598,7 +601,7 @@ module.exports = {
project,
layout,
instance,
associatedObject,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
@@ -627,14 +630,15 @@ module.exports = {
RenderedBitmapTextInstance.getThumbnail = function (
project,
resourcesLoader,
object
objectConfiguration
) {
return 'JsPlatform/Extensions/bitmapfont24.png';
};
// 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

@@ -20,6 +20,7 @@ void DeclareDestroyOutsideBehaviorExtension(gd::PlatformExtension& extension) {
"or other short-lived objects."),
"Florian Rival",
"Open source (MIT License)")
.SetCategory("Game mechanic")
.SetExtensionHelpPath("/behaviors/destroyoutside");
gd::BehaviorMetadata& aut =

View File

@@ -31,7 +31,7 @@ module.exports = {
"Matthias Meike",
"Open source (MIT License)"
).setExtensionHelpPath("/all-features/device-sensors")
.setCategory('Device');
.setCategory('Input');
extension.addInstructionOrExpressionGroupMetadata(_("Device sensors"))
.setIcon("JsPlatform/Extensions/orientation_active32.png");

View File

@@ -35,7 +35,7 @@ module.exports = {
'Open source (MIT License)'
)
.setExtensionHelpPath('/all-features/device-vibration')
.setCategory('Device');
.setCategory('User interface');
extension.addInstructionOrExpressionGroupMetadata(_("Device vibration"))
.setIcon("JsPlatform/Extensions/vibration_start32.png");

View File

@@ -34,7 +34,7 @@ module.exports = {
'Open source (MIT License)'
)
.setExtensionHelpPath('/all-features/dialogue-tree')
.setCategory('Advanced');
.setCategory('Game mechanic');
extension
.addInstructionOrExpressionGroupMetadata(_('Dialogue Tree (experimental)'))
.setIcon('JsPlatform/Extensions/yarn32.png');

View File

@@ -20,6 +20,7 @@ void DeclareDraggableBehaviorExtension(gd::PlatformExtension& extension) {
"or disable the behavior when needed."),
"Florian Rival",
"Open source (MIT License)")
.SetCategory("User interface")
.SetExtensionHelpPath("/behaviors/draggable");
gd::BehaviorMetadata& aut = extension.AddBehavior(

View File

@@ -31,7 +31,9 @@ module.exports = {
'Lots of different effects to be used in your game.',
'Various contributors from PixiJS, PixiJS filters and GDevelop',
'MIT'
).setExtensionHelpPath('/interface/scene-editor/layer-effects');
)
.setCategory('Visual effect')
.setExtensionHelpPath('/interface/scene-editor/layer-effects');
// You can declare an effect here. Please order the effects by alphabetical order.
// This file is for common effects that are well-known/"battle-tested". If you have an

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
);
@@ -539,7 +539,7 @@ module.exports = {
RenderedDummyObjectInstance.getThumbnail = function (
project,
resourcesLoader,
object
objectConfiguration
) {
return 'CppPlatform/Extensions/texticon24.png';
};
@@ -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

@@ -34,7 +34,7 @@ module.exports = {
'Open source (MIT License)'
)
.setExtensionHelpPath('/all-features/filesystem')
.setCategory('Device');
.setCategory('Advanced');
extension
.addInstructionOrExpressionGroupMetadata(_('File system'))
.setIcon('JsPlatform/Extensions/filesystem_create_folder32.png');

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

@@ -19,7 +19,7 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/all-features/inventory")
.SetCategory("Advanced");
.SetCategory("Game mechanic");
extension
.AddInstructionOrExpressionGroupMetadata(_("Inventories"))
.SetIcon("CppPlatform/Extensions/Inventoryicon.png");

View File

@@ -20,7 +20,7 @@ export type ObjectsRenderingService = {
RenderedInstance: any,
registerInstanceRenderer: (objectType: string, renderer: any) => void,
requireModule: (dirname: string, moduleName: string) => any,
getThumbnail: (project: gdProject, object: gdObject) => string,
getThumbnail: (project: gdProject, objectConfiguration: gdObjectConfiguration) => string,
rgbOrHexToHexNumber: (value: string) => number,
};
export type ObjectsEditorService = {

View File

@@ -34,7 +34,7 @@ module.exports = {
'Open source (MIT License)'
)
.setExtensionHelpPath('/all-features/leaderboards')
.setCategory('Leaderboards')
.setCategory('Players')
.addInstructionOrExpressionGroupMetadata(_('Leaderboards (experimental)'))
.setIcon('JsPlatform/Extensions/leaderboard.svg');
@@ -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',
@@ -65,6 +65,32 @@ module.exports = {
.addIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
.setFunctionName('gdjs.evtTools.leaderboards.savePlayerScore');
extension
.addAction(
'SaveConnectedPlayerScore',
_('Save connected player score'),
_("Save the connected player's score to the given leaderboard."),
_(
'Send to leaderboard _PARAM1_ the score _PARAM2_ for the connected player'
),
_('Save score'),
'JsPlatform/Extensions/leaderboard.svg',
'JsPlatform/Extensions/leaderboard.svg'
)
.addCodeOnlyParameter('currentScene', '')
.addParameter('leaderboardId', _('Leaderboard'), '', false)
.addParameter(
'expression',
_('Score to register for the player'),
'',
false
)
.setHelpPath('/all-features/leaderboards')
.getCodeExtraInformation()
.setIncludeFile('Extensions/Leaderboards/sha256.js')
.addIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
.setFunctionName('gdjs.evtTools.leaderboards.saveConnectedPlayerScore');
extension
.addCondition(
'HasLastSaveErrored',

View File

@@ -16,8 +16,10 @@ namespace gdjs {
lastScoreSavingSucceededAt: number | null;
currentlySavingScore: number | null;
currentlySavingPlayerName: string | null;
currentlySavingPlayerId: string | null;
lastSavedScore: number | null;
lastSavedPlayerName: string | null;
lastSavedPlayerId: string | null;
lastSaveError: string | null;
isScoreSaving: boolean;
hasScoreBeenSaved: boolean;
@@ -28,25 +30,45 @@ namespace gdjs {
this.lastScoreSavingSucceededAt = null;
this.currentlySavingScore = null;
this.currentlySavingPlayerName = null;
this.currentlySavingPlayerId = null;
this.lastSavedScore = null;
this.lastSavedPlayerName = null;
this.lastSavedPlayerId = null;
this.lastSaveError = null;
this.isScoreSaving = false;
this.hasScoreBeenSaved = false;
this.hasScoreSavingErrored = false;
}
isSameAsLastScore(playerName: string, score: number): boolean {
isSameAsLastScore({
playerName,
playerId,
score,
}: {
playerName?: string;
playerId?: string;
score: number;
}): boolean {
return (
this.lastSavedPlayerName === playerName &&
((!!playerName && this.lastSavedPlayerName === playerName) ||
(!!playerId && this.lastSavedPlayerId === playerId)) &&
this.lastSavedScore === score
);
}
isAlreadySavingThisScore(playerName: string, score: number): boolean {
isAlreadySavingThisScore({
playerName,
playerId,
score,
}: {
playerName?: string;
playerId?: string;
score: number;
}): boolean {
return (
((!!playerName && this.currentlySavingPlayerName === playerName) ||
(!!playerId && this.currentlySavingPlayerId === playerId)) &&
this.isScoreSaving &&
this.currentlySavingPlayerName === playerName &&
this.currentlySavingScore === score
);
}
@@ -58,19 +80,29 @@ namespace gdjs {
);
}
startSaving(playerName: string, score: number): void {
startSaving({
playerName,
playerId,
score,
}: {
playerName?: string;
playerId?: string;
score: number;
}): void {
this.lastScoreSavingStartedAt = Date.now();
this.isScoreSaving = true;
this.hasScoreBeenSaved = false;
this.hasScoreSavingErrored = false;
this.currentlySavingScore = score;
this.currentlySavingPlayerName = playerName;
if (playerName) this.currentlySavingPlayerName = playerName;
if (playerId) this.currentlySavingPlayerId = playerId;
}
closeSaving(): void {
this.lastScoreSavingSucceededAt = Date.now();
this.lastSavedScore = this.currentlySavingScore;
this.lastSavedPlayerName = this.currentlySavingPlayerName;
this.lastSavedPlayerId = this.currentlySavingPlayerId;
this.isScoreSaving = false;
this.hasScoreBeenSaved = true;
}
@@ -155,50 +187,31 @@ namespace gdjs {
return lastScoreSavingState;
};
export const savePlayerScore = function (
runtimeScene: gdjs.RuntimeScene,
leaderboardId: string,
score: float,
playerName: string
) {
let scoreSavingState: ScoreSavingState;
if (_scoreSavingStateByLeaderboard[leaderboardId]) {
scoreSavingState = _scoreSavingStateByLeaderboard[leaderboardId];
if (scoreSavingState.isAlreadySavingThisScore(playerName, score)) {
logger.warn(
'There is already a request to save with this player name and this score. Ignoring this one.'
);
return;
}
if (scoreSavingState.isSameAsLastScore(playerName, score)) {
logger.warn(
'The player and score to be sent are the same as previous one. Ignoring this one.'
);
const errorCode = 'SAME_AS_PREVIOUS';
scoreSavingState.setError(errorCode);
return;
}
if (scoreSavingState.isTooSoonToSaveAnotherScore()) {
logger.warn(
'Last entry was sent too little time ago. Ignoring this one.'
);
const errorCode = 'TOO_FAST';
scoreSavingState.setError(errorCode);
return;
}
} else {
scoreSavingState = new ScoreSavingState();
_scoreSavingStateByLeaderboard[leaderboardId] = scoreSavingState;
}
scoreSavingState.startSaving(playerName, score);
const baseUrl = 'https://api.gdevelop-app.com/play';
const saveScore = function ({
leaderboardId,
playerName,
playerId,
playerToken,
score,
scoreSavingState,
runtimeScene,
}: {
leaderboardId: string;
playerName?: string;
playerId?: string;
playerToken?: string;
score: number;
scoreSavingState: ScoreSavingState;
runtimeScene: gdjs.RuntimeScene;
}) {
const rootApi = runtimeScene
.getGame()
.isUsingGDevelopDevelopmentEnvironment()
? 'https://api-dev.gdevelop.io'
: 'https://api.gdevelop.io';
const baseUrl = `${rootApi}/play`;
const game = runtimeScene.getGame();
const payload = JSON.stringify({
playerName: formatPlayerName(playerName),
const payloadObject = {
score: score,
sessionId: game.getSessionId(),
clientPlayerId: game.getPlayerId(),
@@ -206,18 +219,25 @@ namespace gdjs {
typeof window !== 'undefined' && (window as any).location
? (window as any).location.href
: '',
});
fetch(
`${baseUrl}/game/${gdjs.projectData.properties.projectUuid}/leaderboard/${leaderboardId}/entry`,
{
body: payload,
method: 'POST',
headers: {
'Content-Type': 'application/json',
Digest: computeDigest(payload),
},
}
).then(
};
if (playerName)
payloadObject['playerName'] = formatPlayerName(playerName);
const payload = JSON.stringify(payloadObject);
const headers = {
'Content-Type': 'application/json',
Digest: computeDigest(payload),
};
if (playerToken)
headers['Authorization'] = `player-game-token ${playerToken}`;
let leaderboardEntryCreationUrl = `${baseUrl}/game/${gdjs.projectData.properties.projectUuid}/leaderboard/${leaderboardId}/entry`;
if (playerId) {
leaderboardEntryCreationUrl += `?playerId=${playerId}`;
}
fetch(leaderboardEntryCreationUrl, {
body: payload,
method: 'POST',
headers: headers,
}).then(
(response) => {
if (!response.ok) {
const errorCode = response.status.toString();
@@ -250,6 +270,114 @@ namespace gdjs {
);
};
export const savePlayerScore = function (
runtimeScene: gdjs.RuntimeScene,
leaderboardId: string,
score: float,
playerName: string
) {
let scoreSavingState: ScoreSavingState;
if (_scoreSavingStateByLeaderboard[leaderboardId]) {
scoreSavingState = _scoreSavingStateByLeaderboard[leaderboardId];
if (
scoreSavingState.isAlreadySavingThisScore({ playerName, score })
) {
logger.warn(
'There is already a request to save with this player name and this score. Ignoring this one.'
);
return;
}
if (scoreSavingState.isSameAsLastScore({ playerName, score })) {
logger.warn(
'The player and score to be sent are the same as previous one. Ignoring this one.'
);
const errorCode = 'SAME_AS_PREVIOUS';
scoreSavingState.setError(errorCode);
return;
}
if (scoreSavingState.isTooSoonToSaveAnotherScore()) {
logger.warn(
'Last entry was sent too little time ago. Ignoring this one.'
);
const errorCode = 'TOO_FAST';
scoreSavingState.setError(errorCode);
return;
}
} else {
scoreSavingState = new ScoreSavingState();
_scoreSavingStateByLeaderboard[leaderboardId] = scoreSavingState;
}
scoreSavingState.startSaving({ playerName, score });
saveScore({
leaderboardId,
playerName,
score,
scoreSavingState,
runtimeScene,
});
};
export const saveConnectedPlayerScore = function (
runtimeScene: gdjs.RuntimeScene,
leaderboardId: string,
score: float
) {
let scoreSavingState: ScoreSavingState;
const playerId = gdjs.playerAuthentication.getUserId();
const playerToken = gdjs.playerAuthentication.getUserToken();
if (!playerId || !playerToken) {
logger.warn(
'Cannot save a score for a connected player if the player is not connected.'
);
return;
}
if (_scoreSavingStateByLeaderboard[leaderboardId]) {
scoreSavingState = _scoreSavingStateByLeaderboard[leaderboardId];
if (scoreSavingState.isAlreadySavingThisScore({ playerId, score })) {
logger.warn(
'There is already a request to save with this player ID and this score. Ignoring this one.'
);
return;
}
if (scoreSavingState.isSameAsLastScore({ playerId, score })) {
logger.warn(
'The player and score to be sent are the same as previous one. Ignoring this one.'
);
const errorCode = 'SAME_AS_PREVIOUS';
scoreSavingState.setError(errorCode);
return;
}
if (scoreSavingState.isTooSoonToSaveAnotherScore()) {
logger.warn(
'Last entry was sent too little time ago. Ignoring this one.'
);
const errorCode = 'TOO_FAST';
scoreSavingState.setError(errorCode);
return;
}
} else {
scoreSavingState = new ScoreSavingState();
_scoreSavingStateByLeaderboard[leaderboardId] = scoreSavingState;
}
scoreSavingState.startSaving({ playerId, score });
saveScore({
leaderboardId,
playerId,
playerToken,
score,
scoreSavingState,
runtimeScene,
});
};
export const isSaving = function (leaderboardId?: string): boolean {
if (leaderboardId) {
return _scoreSavingStateByLeaderboard[leaderboardId]
@@ -512,7 +640,12 @@ namespace gdjs {
}
const gameId = gdjs.projectData.properties.projectUuid;
const targetUrl = `https://liluo.io/games/${gameId}/leaderboard/${leaderboardId}?inGameEmbedded=true`;
const isDev = runtimeScene
.getGame()
.isUsingGDevelopDevelopmentEnvironment();
const targetUrl = `https://liluo.io/games/${gameId}/leaderboard/${leaderboardId}?inGameEmbedded=true${
isDev ? '&dev=true' : ''
}`;
checkLeaderboardAvailability(targetUrl).then(
(isAvailable) => {
if (leaderboardId !== _requestedLeaderboardId) {

View File

@@ -32,7 +32,8 @@ module.exports = {
'This provides a light object, and a behavior to mark other objects as being obstacles for the lights. This is a great way to create a special atmosphere to your game, along with effects, make it more realistic or to create gameplays based on lights.',
'Harsimran Virk',
'MIT'
);
)
.setCategory('Visual effect');
const lightObstacleBehavior = new gd.BehaviorJsImplementation();
// $FlowExpectedError - ignore Flow warning as we're creating a behavior
@@ -195,7 +196,7 @@ module.exports = {
.setIncludeFile('Extensions/Lighting/lightruntimeobject.js')
.addIncludeFile('Extensions/Lighting/lightruntimeobject-pixi-renderer.js')
.addIncludeFile('Extensions/Lighting/lightobstacleruntimebehavior.js')
.setCategoryFullName(_('Lights'));
.setCategoryFullName(_('Visual effect'));
object
.addAction(
@@ -269,7 +270,7 @@ module.exports = {
project,
layout,
instance,
associatedObject,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
) {
@@ -278,19 +279,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()
@@ -370,7 +371,7 @@ module.exports = {
RenderedLightObjectInstance.getThumbnail = function (
project,
resourcesLoader,
object
objectConfiguration
) {
return 'CppPlatform/Extensions/lightIcon32.png';
};

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