Compare commits

...

154 Commits

Author SHA1 Message Date
Florian Rival
aa6aada8be Add a condition (and expression) to check if an external layout is being previewed (and which one) 2023-09-20 09:20:02 +02:00
D8H
dfe84fbe2b Fix an issue in the frame rate synchronization of the Physics behavior (#5649)
* It should avoid jittery cameras that was happening from time to time.
2023-09-19 15:11:57 +02:00
Aurélien Vivet
cd896c399d Fix typo (#5668)
- Fix the width word used in the getHeight() method for the objects.
- Fix the purial of the window in an action.
2023-09-19 13:32:34 +01:00
Clément Pasteau
d8126ead34 Prevent triggering layout change when the virtual keyboard appears. (#5666)
* It fixes a bug on mobile where starting typing would show the virtual keyboard, triggering a resize of the window, which would change the layout and make the input disappear.
2023-09-18 18:15:22 +02:00
AlexandreS
bdbbe1f409 Fix Health bar and Joystick guided lessons in web app (#5665) 2023-09-18 10:38:36 +02:00
D8H
3a241d03f1 Allow sprite animations to play backward with a negative speed scale (#5662) 2023-09-18 09:24:51 +02:00
Florian Rival
e4cf92e949 Improve documentation of expressions by showing parameter in a human readable way 2023-09-16 16:35:24 +02:00
Florian Rival
0dc513317c Revert "Update createObjectsFrom and createObjectsFromExternalLayout to return a list of objects that it creates. (#5658)" (#5660)
This reverts commit 3e85242165.
2023-09-15 14:46:33 +02:00
Dawid Fatyga
3e85242165 Update createObjectsFrom and createObjectsFromExternalLayout to return a list of objects that it creates. (#5658)
Only show in developer changelog
2023-09-15 14:45:25 +02:00
D8H
ca9fe51d99 Fix scaling actions icons (#5647) 2023-09-13 12:54:22 +02:00
Florian Rival
2e9a5ee287 Fix ExpressionParser2 tests (#5654)
Don't show in changelog
2023-09-13 12:54:09 +02:00
Clément Pasteau
b57e944da5 Fix opening a custom object after having opened a pack in the store (#5651) 2023-09-11 14:30:36 +02:00
Florian Rival
06cdeb763d Fix user questionnaire sometimes shown even when already filled (#5648) 2023-09-08 14:15:00 +02:00
Clément Pasteau
5809a02a26 Add more events about premium game templates opening (#5644)
Do not show in changelog
2023-09-07 19:24:23 +02:00
Florian Rival
3a2878c737 Add more restricted characters in internationalized names (#5643)
Only show in developer changelog
2023-09-07 14:54:56 +02:00
Clément Pasteau
2cbfb806e2 Fix speed of adding an asset (#5642)
Do not show in changelog
2023-09-07 14:36:26 +02:00
AlexandreS
18211d197a Remember collapsed state of object behaviors configuration panels (#5641) 2023-09-07 14:30:23 +02:00
Clément Pasteau
128657c876 Prevent throwing when leaderboards cannot be fetched (#5639)
Do not show in changelog
2023-09-07 11:26:42 +02:00
github-actions[bot]
930d4d394f Update translations [skip ci] (#5629)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2023-09-07 09:53:55 +02:00
D8H
cc460657e5 Upgrade Storybook to 7.4.0 (#5625)
Only show in developer changelog 

Co-authored-by: Clément Pasteau <4895034+ClementPasteau@users.noreply.github.com>
Co-authored-by: Florian Rival <Florian.Rival@gmail.com>
2023-09-06 20:04:01 +02:00
AlexandreS
d9f2cb51a3 Add view of team and its groups (classrooms) for education plan holders (#5603) 2023-09-06 17:00:19 +02:00
AlexandreS
d736afe4a0 Fix events search crashing the events sheet when a parameter contains more than 5 spaces (#5628) 2023-09-06 16:53:35 +02:00
Clément Pasteau
10825c0a8c Allow using Premium game templates, high quality games (#5611)
* Those templates are ready-made games, which can be used for as many games as you want
* They directly work on mobile, web and desktop for a seamless experience
* They contain everything for a full game, start menu, options, leaderboards, and even character selection
* They can easily be modified to integrate your assets, or your custom logic to make this game yours
2023-09-06 15:26:45 +02:00
Clément Pasteau
a75a8e1bfe Add steamworks extension (#5440) 2023-09-06 09:31:27 +02:00
D8H
9a02905fb6 Refactor resources loading in Runtime (#5632)
* Only for dev
2023-09-06 00:12:07 +02:00
AlexandreS
414292812f Fix context menu actions disappearing when opening a project and Resources tab is restored (#5630) 2023-09-05 16:29:28 +02:00
AlexandreS
4d9035ad07 Display the navigation bar of the homepage at the bottom on mobile (#5627) 2023-09-05 14:10:01 +02:00
github-actions[bot]
bcf0184fdd Update translations [skip ci] (#5622)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2023-09-05 10:28:24 +02:00
Florian Rival
817f2cf758 Display a message if a subscription is valid but will expire in the future (#5626) 2023-09-04 12:35:00 +02:00
Aurélien Vivet
3c5e10f5c3 Fix typo in theme template (theme.json) (#5623)
Thanks to @Entr0py404 for finding this!
Only show in developer changelog

Co-authored-by: Tristan Rhodes <tristan.rhodes@gmail.com>
2023-09-02 18:38:34 +02:00
Clément Pasteau
7d19b811e4 Fix creating a local project in the right folder (#5621) 2023-09-01 17:46:47 +02:00
Clément Pasteau
17b3579e5b Bump to 5.2.172 (#5620) 2023-09-01 14:32:32 +02:00
github-actions[bot]
afa8d4f7f6 Update translations [skip ci] (#5614)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2023-09-01 14:30:07 +02:00
Florian Rival
b262cb4c3e Fix link in disabled events still processed internally (#5619)
* This could generate infinite loop crashs even when a link is included as
a sub event of a disabled event.
2023-09-01 13:58:51 +02:00
Clément Pasteau
1c69302c02 Fix using correct parameter for size capability behavior (#5618)
Do not show in changelog
2023-09-01 09:57:51 +02:00
AlexandreS
5ba36916c6 Display a nicer refresh icon in the UI and fields (#5617) 2023-09-01 09:15:21 +02:00
D8H
7f3e2b210a Fix missing effect tab on some objects (#5616) 2023-08-31 20:41:06 +02:00
D8H
f83df15817 Fix a performance regression on scenes with a lot of sprites (#5615) 2023-08-31 18:19:50 +02:00
Gleb Volkov
40639f5578 Add clearCanvas flag to RuntimeScene for multi-scene rendering support (#5525)
* Add `clearCanvas` field to `RuntimeScene` class and pass it to `PIXI.Renderer.render` as `clear` option to support multi-scene rendering.

* Show in developer changelog
2023-08-31 10:10:15 +02:00
Florian Rival
f07e3bfe19 Reduce "layout shifts" in Events Sheet when adding events or modifying them (#5612)
* Browsing the events sheet and editing events should be a bit more comfortable now.
2023-08-31 10:09:47 +02:00
D8H
ef9a82ee33 Fix scene editor window rectangle color (#5613) 2023-08-30 21:44:01 +02:00
D8H
e916662ad4 Fix behavior list placeholder for object with default behaviors (#5610) 2023-08-29 17:32:50 +02:00
AlexandreS
d7ca46455e Abstract project caching (#5609)
Don't show in changelog
2023-08-29 16:52:41 +02:00
AlexandreS
d193b9375e Small improvements in tabs opening (#5608)
Don't show in changelog
2023-08-29 16:22:03 +02:00
Clément Pasteau
90b830853a Bump version to 5.2.171 (#5607) 2023-08-29 14:12:27 +02:00
github-actions[bot]
f6b4cab966 Update translations (#5605)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2023-08-29 14:09:52 +02:00
D8H
0ebec6fa02 Fix regression in some expressions of Sprite objects (#5606) 2023-08-29 13:31:31 +02:00
Florian Rival
ab2b46adad Add a shortcut (Cmd/Ctrl+G) to move selected events in a new group (#5604) 2023-08-28 12:56:33 +02:00
Clément Pasteau
29fedf2efb Bump version to 5.2.170 (#5602)
Do not show in changelog
2023-08-25 11:33:29 +02:00
github-actions[bot]
c0cd196a74 Update translations [skip ci] (#5600)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2023-08-25 11:24:23 +02:00
D8H
18e8020bf5 Simplify the list of actions/conditions by removing duplicated actions/conditions that are common between objects (#5494)
* Actions, conditions and expressions related to opacity, size (width/height), scale, animations and other common features are now visible only once when you search for them in actions/conditions (instead of being shown once for every type of object supporting them). This reduces the risk of confusion for new or existing users, notably when multiple versions of the same action were returned by the search and was making it difficult to choose the proper one.
* Internally, this works thanks to default, built-in behaviors that are supported by the objects.
2023-08-25 11:11:55 +02:00
AlexandreS
2ac85dff02 At project opening, reopen the tabs that were opened when it was closed (#5486) 2023-08-25 09:00:46 +02:00
AlexandreS
5919c4ae20 Add possibility to import and export extensions when using GDevelop online editor (#5490) 2023-08-24 18:09:09 +02:00
github-actions[bot]
de12838b3f Update translations [skip ci] (#5594)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2023-08-24 16:48:16 +02:00
Clément Pasteau
b55f56dbd6 Fix special characters in files crashing cloud projects (#5599)
* This fixes preview and download of a cloud project with special characters in files
2023-08-24 16:47:21 +02:00
D8H
c8eed6e472 Fix project file name when creating a new project (#5598) 2023-08-24 12:57:22 +02:00
Aurélien Vivet
7a360b07f6 Simplify confirmation of deletion of leaderboards by asking to type "delete" instead of the full leaderboard name (#5596) 2023-08-23 16:03:29 +02:00
D8H
f86fcf4190 Fix effects on custom objects child-objects that weren't displayed at runtime (#5585) 2023-08-23 15:53:42 +02:00
D8H
e4cbdd4f45 No longer automatically fill the behavior parameter from "activate behavior" actions when there are multiple choices (#5514) 2023-08-23 15:52:50 +02:00
Florian Rival
4b5448cf00 When resizing a 3D object with Shift pressed (or when resizing multiple objects), the depth of the object is also scaled proportionally (#5595)
* This will make the authoring of 3D levels easier.
2023-08-23 12:56:56 +02:00
github-actions[bot]
72e7949faf Update translations [skip ci] (#5591)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2023-08-23 11:21:44 +02:00
Clément Pasteau
63f9f40e3d Fix layout shop (#5593)
Do not show in changelog
2023-08-23 11:21:16 +02:00
Clément Pasteau
dfbb3515cb Fix shop layout on small screens (#5592)
Don't show in changelog
2023-08-23 10:53:19 +02:00
Florian Rival
7985be10cd Simplify the context menus in the Events Sheet (#5590)
* Also display shortcuts for the most used commands, both in the menus and in the toolbar.
2023-08-22 14:56:40 +02:00
github-actions[bot]
6de8324943 Update translations [skip ci] (#5575)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2023-08-22 13:59:16 +02:00
Florian Rival
79a14e220d Create a devcontainer to do some basic development task via GitHub codespaces. (#5589)
Only show in developer changelog
2023-08-22 12:42:52 +02:00
D8H
4575935a42 Fix 3D filters making 2D games crash (#5588) 2023-08-22 11:54:22 +02:00
D8H
134886eedc Add a default 3D light on any new layer (#5576)
* This won't affect efficiency for 2D games.
2023-08-18 22:39:40 +02:00
Clément Pasteau
da308bb104 Fix displaying placeholder when provided (#5574)
Do not show in changelog
2023-08-18 09:49:52 +02:00
github-actions[bot]
5087526066 Update translations [skip ci] (#5573)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2023-08-18 09:27:52 +02:00
Florian Rival
b6f98ad667 Fix actions disappearing when wrongly translated with the same name in a non english language translation (#5566) 2023-08-17 18:23:07 +02:00
github-actions[bot]
b4a6b73146 Update translations [skip ci] (#5570)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2023-08-17 14:00:15 +02:00
Clément Pasteau
2ccdc1aad8 Improve asset store with pack search, filters and navigation (#5546) 2023-08-17 12:29:52 +02:00
supertree-wook
68f13297ef Fix "Share your extension" not redirecting to the proper page on the documentation (#5568) 2023-08-17 10:27:16 +02:00
D8H
6a26e2cf32 Fix unused resources clean up to keep resources used in effects (#5560) 2023-08-16 14:30:08 +02:00
Clément Pasteau
9532a42558 Better text select mouse button (#5569)
Do not show in changelog
2023-08-16 12:31:04 +02:00
github-actions[bot]
f23bc5dfd9 Update translations [skip ci] (#5552)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2023-08-16 11:28:56 +02:00
Florian Rival
4a4bf6d761 Add support for unicode names (any character, including emojis) for object/group/behavior/extension/function names (#5564)
* In other words: this allows to use emojis, accented characters, CJK languages and any word from any language to name anything in GDevelop. This should be very useful for non english speaking users.
* This must be activated in the preferences of GDevelop. This will be activated by default once this is proven to work without bugs.
2023-08-14 21:46:10 +02:00
Florian Rival
68968b603a Automatically fix object/group/function/behavior/object/property names when an incorrect one is entered (#5561)
* Instead of displaying an error message (for example, if a space is used in an object name), the name entered is automatically fixed. This is easier to understand and avoids breaking the creative workflow.
* Same for scenes, external events, external layouts and extension names in the project manager.
2023-08-14 00:05:53 +02:00
D8H
eb723b2a0e Fix missing tags for installed extensions in the behavior list (#5553) 2023-08-13 13:14:27 +02:00
Florian Rival
c51e6fa04e Fix warning
Don't show in changelog
2023-08-12 13:12:11 +02:00
D8H
a0ad9200cf Deprecate actions that uses an expression for resources (#5558) 2023-08-11 20:22:21 +02:00
D8H
99804f366a Allow JavaScript extensions to use resource parameters. (#5559) 2023-08-11 20:21:51 +02:00
D8H
71fead702d Make EventsFunctionParametersEditor a function component (#5554)
Don't show in changelog
2023-08-11 20:21:19 +02:00
D8H
54c9177b03 Filter autocompleted tags according to community visibility setting (#5555)
* It avoids to show tags that gives no results.
2023-08-11 10:50:09 +02:00
D8H
8157d3c9db Fix layers deletion when instances are in several external layouts (#5548) 2023-08-10 15:53:40 +02:00
github-actions[bot]
03e0da8619 Update translations [skip ci] (#5533)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-08-10 14:12:39 +02:00
D8H
be84b2153f Move some Tween actions in "Size" and "Visibility" groups (#5551) 2023-08-10 12:22:09 +02:00
AlexandreS
10591a41e6 Fix React callback dependency array (#5547)
Don't show in changelog
2023-08-09 16:28:12 +02:00
D8H
d41cc18be2 Fix the "Select instances on scene" menu action in external layouts (#5543) 2023-08-09 14:51:12 +02:00
AlexandreS
fb6e09d0e3 Add autosave feature for Cloud projects (#5545)
- Cloud projects are now autosaved on each game preview. Should the editor crash, it will help recover your project.
- The saved project is stored on the device for performance reasons.
- Warning: if you're using GDevelop online on a public computer, this feature saves a copy of your project in the browser storage. To make sure no one can access it, make sure to log out the editor when you leave the computer.
2023-08-08 15:55:06 +02:00
Clément Pasteau
8766f73333 Show warning and revert to automatic collision mask if deleting the last frame of a sprite object (#5542) 2023-08-08 14:26:59 +02:00
D8H
b32a9006c6 Fix the information icon color in the new behavior dialog (#5537) 2023-08-04 10:49:06 +02:00
D8H
2d613e7281 Autocomplete behavior functions on object in expressions (#5534)
* Use behavior icons in expression autocompletion.
* Fix icon colors in expression autocompletion.
2023-08-03 10:59:48 +02:00
Clément Pasteau
ca220d8fe5 Fix copying points & masks when editing sprite too (#5532)
Do not show in changeloc
2023-08-02 16:58:49 +02:00
github-actions[bot]
9971702ec9 Update translations (#5529) 2023-08-02 14:21:57 +02:00
Clément Pasteau
e48f14b753 Bump IDE version to 169 (#5530)
Do not show in changelog
2023-08-02 14:21:20 +02:00
Clément Pasteau
ce046c0b99 Fix setting up points & collision masks according to object animation settings (#5527)
* Adding a new sprite in a new animation will now correctly copy points and collision masks defined in others if "sharing with all animations" is toggled
2023-08-02 14:10:37 +02:00
Florian Rival
e29cb462e1 Add mention to using git for projects in the project properties dialog (#5528) 2023-08-02 14:02:20 +02:00
github-actions[bot]
aee05affd0 Update translations [skip ci] (#5526)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2023-08-02 12:03:59 +02:00
Clément Pasteau
f95d197634 Fix a bug where renaming project elements wouldn't work when an action is using the default layer (#5524) 2023-08-02 11:27:39 +02:00
github-actions[bot]
075cc5a7aa Update translations [skip ci] (#5513)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2023-07-31 17:18:10 +02:00
Clément Pasteau
56c2aa0dc6 Fix collision mask when adding new sprites with default, full image mask (#5523) 2023-07-31 17:17:39 +02:00
Clément Pasteau
fa003374ba Fix automatic collision mask on multiple sprites addition (#5521)
And on piskel edition
2023-07-31 11:29:11 +02:00
github-actions[bot]
ca27a946a1 Update translations [skip ci] (#5509)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2023-07-28 17:57:49 +02:00
Clément Pasteau
2845c403f9 Prevent saving in the same folder as GDevelop's executable (#5510)
* Some users have mentioned their project disappear after a GDevelop's update. This is a safe-guard to avoid projects from being saved in the executable folder, as it gets deleted on every update.
2023-07-28 17:57:22 +02:00
Clément Pasteau
9cc2e2987e Allow navigating to packs and bundles directly from banners (#5512) 2023-07-28 17:07:12 +02:00
Clément Pasteau
b9d6336dc7 Rework the asset store to show bundles and owned packs first (#5504)
* Also slightly improve the size of dialogs on large screens
2023-07-28 10:39:11 +02:00
D8H
c2ad00ed6c No longer show a tooltip when a behavior has no author (#5507)
Don't show in changelog
2023-07-28 08:58:07 +02:00
Clément Pasteau
2d1845f0b8 run actions only on push, not on new tags (#5508)
Do not show in changelog
2023-07-27 16:55:54 +02:00
D8H
b5f0758f4d Add an information button on behaviors (#5505)
* Show authors on hovering
* Open extension details on click
2023-07-27 14:51:41 +02:00
Clément Pasteau
1e2ffe5d15 Allow downloading artefacts from a commit hash (#5506)
Do not show in changelog
2023-07-27 14:20:01 +02:00
github-actions[bot]
c887769c0a Update translations (#5474)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2023-07-27 14:14:51 +02:00
Clément Pasteau
dc1ac1e094 Bump to 5.2.168 (#5502) 2023-07-27 11:53:24 +02:00
Clément Pasteau
4b1ceeb642 Fix adapting collision mask to new sprites (#5500) 2023-07-27 09:20:31 +02:00
supertree-wook
e5d92fbf43 Upgrade missing cmake (#5450)
Only show in developer changelog
2023-07-26 22:54:40 +02:00
Florian Rival
c323fea5bd Simplify display of leaderboard entries (#5501)
Don't show in the changelog
2023-07-26 22:14:52 +02:00
D8H
32f0fe9051 Fix some typos in the new behavior dialog (#5503) 2023-07-26 22:14:35 +02:00
Clément Pasteau
be74d3efa6 Prevent installing too many assets at a time (#5495)
* Installing more than 100 assets from a pack can cause failures on some low connections
2023-07-25 09:09:23 +02:00
D8H
8969c9af8c Show extensions from the store at the end of the behavior list (#5476) 2023-07-24 17:50:39 +02:00
D8H
15cac278d6 Separate 2D and 3D effects in 2 lists (#5484) 2023-07-24 11:02:06 +02:00
Florian Rival
9e8a15547d Improve leaderboard score handling (#5481)
* Leaderboards will now display the score of the player, if a score was just sent before displaying the leaderboard.
* If the score is being sent, the leaderboard will wait for it to be sent before showing the leaderboard.
* Important change: a player name can now be empty when a score is sent. In this case, the leaderboard will auto-generate a name.
* Leaderboard administration was improved to allow to customise the prefix used to generate automatically player names (when no name is entered by the player). You can also now choose to disallow any custom player name to prevent abuse (in this case, all non-connected player names will be auto-generated)
* Allow to use custom CSS to fully customize the leaderboard - only for business users (reach out if you need this).

Co-authored-by: AlexandreS <32449369+AlexandreSi@users.noreply.github.com>
2023-07-18 16:20:45 +02:00
supertree-wook
ed74a49aa3 Remove unnecessary dependencies in the Editor and GDJS (#5469)
Only show in developer changelog
2023-07-18 14:29:19 +02:00
D8H
6ef5d0c326 Add an action to insert a function parameter (#5483) 2023-07-18 12:29:14 +02:00
AlexandreS
5f871e2643 Fix Safari not being able to open .glb files on iPad/iPhone (#5479) 2023-07-18 09:24:18 +02:00
AlexandreS
4f65fa0d82 Fix: Avoid purchasing twice the same asset pack (#5482) 2023-07-17 17:28:56 +02:00
AlexandreS
4d1d763bd9 Fix keyboard undesired openings on mobile (#5478) 2023-07-13 17:16:37 +02:00
AlexandreS
3286722b6a Enable search and replace in For each object events and Javascript events (#5477) 2023-07-13 17:09:00 +02:00
AlexandreS
656255a662 Bump newIDE version (#5475) 2023-07-12 11:56:23 +02:00
AlexandreS
ea7b7a778e Improve messages visibility in collision masks dialog (#5473)
Don't show in changelog
2023-07-12 10:00:37 +02:00
AlexandreS
9b6de5affd Add possibility to subscribe to a startup plan from the profile (#5472) 2023-07-11 16:31:25 +02:00
Clément Pasteau
0c03659314 Fix Node.js 18 compatibility, upgrade to create-react-app v5 and make mac build universal (#5270)
* only show in developer changelog
2023-07-11 15:03:33 +02:00
github-actions[bot]
6b08c0f033 Update translations [skip ci] (#5466)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-07-11 14:10:20 +02:00
AlexandreS
a1dcf03a5b Fix the editor hanging when opening a scene with hundreds of instances of 3D model objects (#5470) 2023-07-10 17:31:29 +02:00
D8H
556d13c881 Fix the community warning that wasn't showing up in documentation (#5468)
Don't show in changelog
2023-07-09 19:31:28 +02:00
D8H
0d6c42a9bf Filter private actions and conditions from the reference page (#5467)
* Don't show in changelog
2023-07-07 14:09:53 +02:00
D8H
690ce16ab4 Add a listing of actions and conditions in community extension reference pages (#5464) 2023-07-07 10:50:47 +02:00
github-actions[bot]
5f51a5e465 Update translations [skip ci] (#5465)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-07-06 09:51:54 +02:00
AlexandreS
b7521de138 Add startup plan support in user profile components (#5462) 2023-07-05 09:39:40 +02:00
AlexandreS
acea6fc595 Fix SetPosition action that was missing parenthesis creating math errors (#5458) 2023-07-03 12:07:10 +02:00
github-actions[bot]
d8107fe3d5 Update translations [skip ci] (#5457)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2023-07-03 11:31:55 +02:00
Clément Pasteau
b40b95be99 Remove jimp, use Canvas for image manipulation (#5454)
Do not show in changelog
2023-07-03 11:21:28 +02:00
AlexandreS
6644525dd0 Remove former fix that triggered a bug where values were not persisted after editing expression in event sheet (#5455) 2023-07-03 10:28:43 +02:00
github-actions[bot]
56e66d1c5a Update translations [skip ci] (#5452)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2023-06-30 15:51:19 +02:00
Clément Pasteau
90d8afb5a0 Calculate Sprite collision masks automatically (#5447)
* Sprites now have an option to calculate their collision mask automatically, based on the first image of their first animation
* The generated collision mask consists of the biggest rectangle possible, encapsulating the image and avoiding transparent pixels
* This option is enabled by default for all new sprites, and can be disabled to create a custom collision mask like before
* When enabled, the mask will adapt automatically when the first image is updated
2023-06-30 15:33:50 +02:00
AlexandreS
d4db61a595 Fix autofocus of searchbar on tablets in landscape (#5451) 2023-06-29 22:40:06 +02:00
D8H
90413b842d Move event-based extension metadata generation from newIDE to GDJS (#5255) 2023-06-29 20:18:51 +02:00
github-actions[bot]
43c788acbf Update translations [skip ci] (#5444)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2023-06-29 11:29:17 +02:00
supertree-wook
ee22b2e4b1 Upgrade CMake minimum version and improve CMake code (#5446)
Only show in developer changelog
2023-06-28 12:01:05 +02:00
AlexandreS
007d56e946 Display the scene editors more conveniently on mobile (#5441) 2023-06-26 18:07:23 +02:00
AlexandreS
577c4adb14 Fix images selectors not updating on Box 3D editor after an image has been created with Piskel (#5442) 2023-06-26 17:53:23 +02:00
AlexandreS
7f17720ff3 Fix: Do not close popover when releasing text selection click outside of popover (#5443) 2023-06-23 16:51:24 +02:00
github-actions[bot]
288db1c941 Update translations [skip ci] (#5434)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2023-06-23 16:32:13 +02:00
Florian Rival
2496fc3eef Revert "Add extension to support Steamworks integration of games made with GDevelop (#5401)" (#5438)
This reverts commit 3c43f28966.
2023-06-22 12:58:00 +02:00
727 changed files with 69955 additions and 73171 deletions

View File

@@ -15,7 +15,7 @@ jobs:
# Build the **entire** app for macOS.
build-macos:
macos:
xcode: 12.5.1
xcode: 14.2.0
steps:
- checkout
@@ -62,13 +62,14 @@ jobs:
# Build GDevelop IDE (seems like we need to allow Node.js to use more space than usual)
# Note: Code signing is done using CSC_LINK (see https://www.electron.build/code-signing).
# To test signing the code in the CI, add "export CSC_FOR_PULL_REQUEST=true && " before the command.
- run:
name: Build GDevelop IDE
command: export NODE_OPTIONS="--max-old-space-size=7168" && cd newIDE/electron-app && npm run build -- --mac --publish=never
command: export NODE_OPTIONS="--max-old-space-size=7168" && cd newIDE/electron-app && CI=false npm run build -- --mac --publish=never
- run:
name: Clean dist folder to keep only installers/binaries.
command: rm -rf "newIDE/electron-app/dist/mac/GDevelop 5.app" && rm -rf "newIDE/electron-app/dist/mac-arm64/GDevelop 5.app"
command: rm -rf "newIDE/electron-app/dist/mac-universal/GDevelop 5.app"
# Upload artifacts (CircleCI)
- store_artifacts:
@@ -101,8 +102,8 @@ jobs:
command: sudo apt-get update && sudo apt install cmake
- run:
name: Install Python3 dependencies for Emscripten
command: sudo apt install python-is-python3 python3-distutils -y
name: Install Python3 dependencies for Emscripten
command: sudo apt install python-is-python3 python3-distutils -y
- run:
name: Install Emscripten (for GDevelop.js)
@@ -178,8 +179,8 @@ jobs:
command: sudo apt-get update && sudo apt install cmake
- run:
name: Install Python3 dependencies for Emscripten
command: sudo apt install python-is-python3 python3-distutils -y
name: Install Python3 dependencies for Emscripten
command: sudo apt install python-is-python3 python3-distutils -y
- run:
name: Install Emscripten (for GDevelop.js)

View File

@@ -0,0 +1,14 @@
{
"image": "mcr.microsoft.com/devcontainers/universal:2",
"onCreateCommand": "cd newIDE/app && npm install && cd ../electron-app && npm install",
"forwardPorts": [3000],
"customizations": {
"vscode": {
"extensions": [
"esbenp.prettier-vscode",
"ms-vscode.cpptools",
"flowtype.flow-for-vscode"
]
}
}
}

View File

@@ -9,6 +9,10 @@ name: Build Storybook
on:
# Launch on all commits.
push:
branches:
- "**"
tags-ignore:
- "**" # Don't run on new tags
# Allows to run this workflow manually from the Actions tab,
# to publish on Chromatic (not done by default).
workflow_dispatch:
@@ -24,8 +28,8 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 16
cache: 'npm'
cache-dependency-path: 'newIDE/app/package-lock.json'
cache: "npm"
cache-dependency-path: "newIDE/app/package-lock.json"
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v2

View File

@@ -4,6 +4,10 @@ name: Extract translations
on:
# Execute for all commits (to ensure translations extraction works)
push:
branches:
- "**"
tags-ignore:
- "**" # Don't run on new tags
# Allows to run this workflow manually from the Actions tab.
workflow_dispatch:
@@ -15,14 +19,14 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 16
cache: 'npm'
cache-dependency-path: 'newIDE/app/package-lock.json'
cache: "npm"
cache-dependency-path: "newIDE/app/package-lock.json"
- name: Install gettext
run: sudo apt update && sudo apt install gettext -y
- name: Install newIDE dependencies
run: npm install
run: npm ci
working-directory: newIDE/app
- name: Extract translations

View File

@@ -7,6 +7,8 @@ on:
push:
branches:
- master
tags-ignore:
- "**" # Don't run on new tags
# Allows to run this workflow manually from the Actions tab.
workflow_dispatch:
@@ -18,8 +20,8 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 16
cache: 'npm'
cache-dependency-path: 'newIDE/app/package-lock.json'
cache: "npm"
cache-dependency-path: "newIDE/app/package-lock.json"
- name: Install gettext
run: sudo apt update && sudo apt install gettext -y

259
.vscode/settings.json vendored
View File

@@ -1,133 +1,134 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.associations": {
"*.idl": "java",
"Fastfile": "ruby",
"iosfwd": "cpp",
"functional": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"algorithm": "cpp",
"random": "cpp",
"__config": "cpp",
"cstddef": "cpp",
"exception": "cpp",
"initializer_list": "cpp",
"new": "cpp",
"stdexcept": "cpp",
"typeinfo": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"complex": "cpp",
"cstdarg": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"istream": "cpp",
"limits": "cpp",
"memory": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"streambuf": "cpp",
"hashtable": "cpp",
"tuple": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"__split_buffer": "cpp",
"deque": "cpp",
"iterator": "cpp",
"list": "cpp",
"map": "cpp",
"queue": "cpp",
"regex": "cpp",
"set": "cpp",
"stack": "cpp",
"string": "cpp",
"vector": "cpp",
"iostream": "cpp",
"__functional_03": "cpp",
"__hash_table": "cpp",
"__tree": "cpp",
"bitset": "cpp",
"__bit_reference": "cpp",
"__mutex_base": "cpp",
"fstream": "cpp",
"ios": "cpp",
"__locale": "cpp",
"valarray": "cpp",
"freeglut_spaceball.c": "cpp",
"__tuple": "cpp",
"hash_map": "cpp",
"hash_set": "cpp",
"system_error": "cpp",
"__nullptr": "cpp",
"__functional_base": "cpp",
"__functional_base_03": "cpp",
"chrono": "cpp",
"ratio": "cpp",
"atomic": "cpp",
"locale": "cpp",
"string_view": "cpp",
"__string": "cpp",
"cstring": "cpp",
"iomanip": "cpp",
"cstdint": "cpp",
"forward_list": "cpp",
"mutex": "cpp",
"__hash": "cpp",
"__debug": "cpp",
"__threading_support": "cpp",
"any": "cpp",
"array": "cpp",
"cinttypes": "cpp",
"numeric": "cpp",
"__memory": "cpp",
"__errc": "cpp",
"__node_handle": "cpp",
"bit": "cpp",
"optional": "cpp",
"filesystem": "cpp",
"compare": "cpp",
"concepts": "cpp",
"xfacet": "cpp",
"xhash": "cpp",
"xiosbase": "cpp",
"xlocale": "cpp",
"xlocinfo": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xmemory": "cpp",
"xstddef": "cpp",
"xstring": "cpp",
"xtr1common": "cpp",
"xtree": "cpp",
"xutility": "cpp",
"xlocbuf": "cpp",
"xlocmes": "cpp",
"xmemory0": "cpp",
"memory_resource": "cpp"
},
"files.exclude": {
"Binaries/*build*": true,
"Binaries/Output": true,
"GDJS/Runtime-dist": true,
"docs": true,
"newIDE/electron-app/dist": true,
"newIDE/app/build": true,
"newIDE/app/resources/GDJS": true,
"newIDE/electron-app/app/www": true
},
// Support for Flowtype (for newIDE):
"javascript.validate.enable": false,
"flow.useNPMPackagedFlow": true,
"files.associations": {
"*.idl": "java",
"Fastfile": "ruby",
"iosfwd": "cpp",
"functional": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"algorithm": "cpp",
"random": "cpp",
"__config": "cpp",
"cstddef": "cpp",
"exception": "cpp",
"initializer_list": "cpp",
"new": "cpp",
"stdexcept": "cpp",
"typeinfo": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"complex": "cpp",
"cstdarg": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"istream": "cpp",
"limits": "cpp",
"memory": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"streambuf": "cpp",
"hashtable": "cpp",
"tuple": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"__split_buffer": "cpp",
"deque": "cpp",
"iterator": "cpp",
"list": "cpp",
"map": "cpp",
"queue": "cpp",
"regex": "cpp",
"set": "cpp",
"stack": "cpp",
"string": "cpp",
"vector": "cpp",
"iostream": "cpp",
"__functional_03": "cpp",
"__hash_table": "cpp",
"__tree": "cpp",
"bitset": "cpp",
"__bit_reference": "cpp",
"__mutex_base": "cpp",
"fstream": "cpp",
"ios": "cpp",
"__locale": "cpp",
"valarray": "cpp",
"freeglut_spaceball.c": "cpp",
"__tuple": "cpp",
"hash_map": "cpp",
"hash_set": "cpp",
"system_error": "cpp",
"__nullptr": "cpp",
"__functional_base": "cpp",
"__functional_base_03": "cpp",
"chrono": "cpp",
"ratio": "cpp",
"atomic": "cpp",
"locale": "cpp",
"string_view": "cpp",
"__string": "cpp",
"cstring": "cpp",
"iomanip": "cpp",
"cstdint": "cpp",
"forward_list": "cpp",
"mutex": "cpp",
"__hash": "cpp",
"__debug": "cpp",
"__threading_support": "cpp",
"any": "cpp",
"array": "cpp",
"cinttypes": "cpp",
"numeric": "cpp",
"__memory": "cpp",
"__errc": "cpp",
"__node_handle": "cpp",
"bit": "cpp",
"optional": "cpp",
"filesystem": "cpp",
"compare": "cpp",
"concepts": "cpp",
"xfacet": "cpp",
"xhash": "cpp",
"xiosbase": "cpp",
"xlocale": "cpp",
"xlocinfo": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xmemory": "cpp",
"xstddef": "cpp",
"xstring": "cpp",
"xtr1common": "cpp",
"xtree": "cpp",
"xutility": "cpp",
"xlocbuf": "cpp",
"xlocmes": "cpp",
"xmemory0": "cpp",
"memory_resource": "cpp",
"__bits": "cpp",
"__verbose_abort": "cpp",
"variant": "cpp"
},
"files.exclude": {
"Binaries/*build*": true,
"Binaries/Output": true,
"GDJS/Runtime-dist": true,
"docs": true,
"newIDE/electron-app/dist": true,
"newIDE/app/build": true,
"newIDE/app/resources/GDJS": true,
"newIDE/electron-app/app/www": true
},
// Support for Flowtype (for newIDE):
"javascript.validate.enable": false,
"flow.useNPMPackagedFlow": true,
// Clang format styling (duplicated in scripts/CMakeClangUtils.txt)
"C_Cpp.clang_format_style": "{BasedOnStyle: Google, BinPackParameters: false, BinPackArguments: false}",
"prettier.prettierPath": "./GDJS/node_modules/prettier",
"prettier.configPath": "./GDJS/.prettierrc"
// Clang format styling (duplicated in scripts/CMakeClangUtils.txt)
"C_Cpp.clang_format_style": "{BasedOnStyle: Google, BinPackParameters: false, BinPackArguments: false}"
}

View File

@@ -1,100 +1,99 @@
#This is the CMake file used to build GDevelop.
#For more information, see the README.md file.
# This is the CMake file used to build GDevelop.
# For more information, see the README.md file.
cmake_minimum_required(VERSION 2.6)
cmake_policy(SET CMP0011 NEW)
cmake_minimum_required(VERSION 3.5)
# Add utility functions
include(scripts/CMakeClangUtils.txt) # To add clang-format and clang-tidy support to a target
# Macro for defining an option
macro(gd_set_option var default type docstring)
if(NOT DEFINED ${var})
set(${var} ${default})
endif()
set(${var} ${${var}} CACHE ${type} ${docstring} FORCE)
if(NOT DEFINED ${var})
set(${var} ${default})
endif()
set(${var} ${${var}} CACHE ${type} ${docstring} FORCE)
endmacro()
# Set options
gd_set_option(BUILD_CORE TRUE BOOL "TRUE to build GDevelop Core library")
gd_set_option(BUILD_GDJS TRUE BOOL "TRUE to build GDevelop JS Platform")
gd_set_option(BUILD_EXTENSIONS TRUE BOOL "TRUE to build the extensions")
gd_set_option(BUILD_TESTS TRUE BOOL "TRUE to build the tests")
# Disable deprecated code
set(NO_GUI TRUE CACHE BOOL "" FORCE) #Force disable old GUI related code.
set(NO_GUI TRUE CACHE BOOL "" FORCE) # Force disable old GUI related code.
#Setting up installation directory, for Linux (has to be done before "project" command).
IF(NOT WIN32)
if (NOT APPLE)
gd_set_option(GD_INSTALL_PREFIX "/opt/gdevelop/" STRING "The directory where GDevelop should be installed")
ELSE()
gd_set_option(GD_INSTALL_PREFIX "." STRING "The directory where GDevelop should be installed")
ENDIF()
# Setting up installation directory, for Linux (has to be done before "project" command).
if(NOT WIN32)
if(NOT APPLE)
gd_set_option(GD_INSTALL_PREFIX "/opt/gdevelop/" STRING "The directory where GDevelop should be installed")
else()
gd_set_option(GD_INSTALL_PREFIX "." STRING "The directory where GDevelop should be installed")
endif()
#As we embed SFML, prevent it to be installed system-wide
# As we embed SFML, prevent it to be installed system-wide
set(CMAKE_INSTALL_PREFIX "${GD_INSTALL_PREFIX}/useless")
ENDIF()
endif()
project(GDevelop)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
IF(NOT WIN32 AND NOT APPLE AND NOT BUILD_TESTS)
SET(CMAKE_SKIP_BUILD_RPATH TRUE) #Avoid errors when packaging for linux.
ENDIF()
IF(APPLE)
if(NOT WIN32 AND NOT APPLE AND NOT BUILD_TESTS)
set(CMAKE_SKIP_BUILD_RPATH TRUE) # Avoid errors when packaging for linux.
endif()
if(APPLE)
set(CMAKE_MACOSX_RPATH 1)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
set(CMAKE_INSTALL_RPATH ".")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_WCHAR_H_CPLUSPLUS_98_CONFORMANCE_")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-potentially-evaluated-expression")
ENDIF()
#Sanity checks
IF ("${CMAKE_BUILD_TYPE}" STREQUAL "")
message( "CMAKE_BUILD_TYPE is empty, assuming build type is Release" )
add_compile_options(
-D_WCHAR_H_CPLUSPLUS_98_CONFORMANCE_
-Wno-potentially-evaluated-expression)
endif()
# Sanity checks
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
message(STATUS "CMAKE_BUILD_TYPE is empty, assuming build type is Release")
set(CMAKE_BUILD_TYPE Release)
ENDIF()
endif()
IF("${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND NOT WIN32 AND CMAKE_COMPILER_IS_GNUCXX)
SET(CMAKE_SHARED_LINKER_FLAGS "-s") #Force stripping to avoid errors when packaging for linux.
ENDIF()
if("${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND NOT WIN32 AND CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_SHARED_LINKER_FLAGS "-s") # Force stripping to avoid errors when packaging for linux.
endif()
#Activate C++11
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=gnu++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=gnu++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x")
else()
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support (with GNU extensions). Please use a different C++ compiler.")
endif()
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Mark some warnings as errors
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# Activate as much warnings as possible to avoid errors like
# uninitialized variables or other hard to debug bugs.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-warning-option")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder-ctor -Wno-reorder -Wno-pessimizing-move -Wno-unused-variable -Wno-unused-private-field")
add_compile_options(
-Wall
-Wno-unknown-warning-option
-Wno-reorder-ctor
-Wno-reorder
-Wno-pessimizing-move
-Wno-unused-variable
-Wno-unused-private-field
# Make as much warnings considered as errors as possible (only one for now).
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=return-stack-address")
# Make as much warnings considered as errors as possible (only one for now).
-Werror=return-stack-address)
endif()
#Define common directories:
# Define common directories:
set(GD_base_dir ${CMAKE_CURRENT_SOURCE_DIR})
#Add all the CMakeLists:
ADD_SUBDIRECTORY(ExtLibs)
IF(BUILD_CORE)
ADD_SUBDIRECTORY(Core)
ENDIF()
IF(BUILD_GDJS)
ADD_SUBDIRECTORY(GDJS)
ENDIF()
IF(EMSCRIPTEN)
ADD_SUBDIRECTORY(GDevelop.js)
ENDIF()
IF(BUILD_EXTENSIONS)
ADD_SUBDIRECTORY(Extensions)
ENDIF()
# Add all the CMakeLists:
add_subdirectory(ExtLibs)
if(BUILD_CORE)
add_subdirectory(Core)
endif()
if(BUILD_GDJS)
add_subdirectory(GDJS)
endif()
if(EMSCRIPTEN)
add_subdirectory(GDevelop.js)
endif()
if(BUILD_EXTENSIONS)
add_subdirectory(Extensions)
endif()

View File

@@ -1,83 +1,98 @@
cmake_minimum_required(VERSION 2.6)
cmake_policy(SET CMP0015 NEW)
cmake_minimum_required(VERSION 3.5)
project(GDCore)
SET(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1) #Force use response file: useful for Ninja build system on Windows.
SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1)
SET(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1)
SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1)
set(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1) # Force use response file: useful for Ninja build system on Windows.
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1)
set(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1)
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1)
#Define common directories:
# Define common directories:
set(GDCORE_include_dir ${GD_base_dir}/Core PARENT_SCOPE)
set(GDCORE_lib_dir ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME} PARENT_SCOPE)
#Dependencies on external libraries:
###
# Dependencies on external libraries:
#
#Defines
###
add_definitions( -DGD_IDE_ONLY )
IF (EMSCRIPTEN)
add_definitions( -DEMSCRIPTEN )
ENDIF()
IF(CMAKE_BUILD_TYPE MATCHES "Debug")
add_definitions( -DDEBUG )
ELSE()
add_definitions( -DRELEASE )
ENDIF()
# Defines
#
add_definitions(-DGD_IDE_ONLY)
if(EMSCRIPTEN)
add_definitions(-DEMSCRIPTEN)
endif()
if("${CMAKE_BUILD_TYPE}" MATCHES "Debug")
add_definitions(-DDEBUG)
else()
add_definitions(-DRELEASE)
endif()
IF(WIN32)
add_definitions( -DWINDOWS )
add_definitions( "-DGD_CORE_API=__declspec(dllexport)" )
add_definitions( -D__GNUWIN32__ )
ELSE()
IF(APPLE)
add_definitions( -DMACOS )
ELSE()
add_definitions( -DLINUX )
ENDIF()
add_definitions( -DGD_API= )
add_definitions( -DGD_CORE_API= )
ENDIF(WIN32)
if(WIN32)
add_definitions(-DWINDOWS)
add_definitions("-DGD_CORE_API=__declspec(dllexport)")
add_definitions(-D__GNUWIN32__)
else()
if(APPLE)
add_definitions(-DMACOS)
else()
add_definitions(-DLINUX)
endif()
add_definitions(-DGD_API=)
add_definitions(-DGD_CORE_API=)
endif()
#The target
###
# The target
#
include_directories(.)
file(GLOB_RECURSE source_files GDCore/*)
file(
GLOB_RECURSE
source_files
GDCore/*)
file(GLOB_RECURSE formatted_source_files tests/* GDCore/Events/* GDCore/Extensions/* GDCore/IDE/* GDCore/Project/* GDCore/Serialization/* GDCore/Tools/*)
list(REMOVE_ITEM formatted_source_files "${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs.h" "${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs_dialogs_bitmaps.cpp")
file(
GLOB_RECURSE
formatted_source_files
tests/*
GDCore/Events/*
GDCore/Extensions/*
GDCore/IDE/*
GDCore/Project/*
GDCore/Serialization/*
GDCore/Tools/*)
list(
REMOVE_ITEM
formatted_source_files
"${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs.h"
"${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs_dialogs_bitmaps.cpp")
gd_add_clang_utils(GDCore "${formatted_source_files}")
IF(EMSCRIPTEN)
if(EMSCRIPTEN)
# Emscripten treats all libraries as static libraries
add_library(GDCore STATIC ${source_files})
ELSE()
else()
add_library(GDCore SHARED ${source_files})
ENDIF()
IF(EMSCRIPTEN)
endif()
if(EMSCRIPTEN)
set_target_properties(GDCore PROPERTIES SUFFIX ".bc")
ELSEIF(WIN32)
elseif(WIN32)
set_target_properties(GDCore PROPERTIES PREFIX "")
ELSE()
else()
set_target_properties(GDCore PROPERTIES PREFIX "lib")
ENDIF()
endif()
set(LIBRARY_OUTPUT_PATH ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME})
set(ARCHIVE_OUTPUT_PATH ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME})
set(RUNTIME_OUTPUT_PATH ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME})
#Tests
###
# Tests
#
if(BUILD_TESTS)
file(
GLOB_RECURSE
test_source_files
tests/*
)
GLOB_RECURSE
test_source_files
tests/*)
add_executable(GDCore_tests ${test_source_files})
set_target_properties(GDCore_tests PROPERTIES BUILD_WITH_INSTALL_RPATH FALSE) #Allow finding dependencies directly from build path on Mac OS X.
set_target_properties(GDCore_tests PROPERTIES BUILD_WITH_INSTALL_RPATH FALSE) # Allow finding dependencies directly from build path on Mac OS X.
target_link_libraries(GDCore_tests GDCore)
target_link_libraries(GDCore_tests ${CMAKE_DL_LIBS})
endif()

View File

@@ -15,7 +15,7 @@ using namespace std;
namespace gd {
ForEachEvent::ForEachEvent()
: BaseEvent(), objectsToPick(""), objectsToPickSelected(false) {}
: BaseEvent(), objectsToPick("") {}
vector<gd::InstructionsList*> ForEachEvent::GetAllConditionsVectors() {
vector<gd::InstructionsList*> allConditions;

View File

@@ -6,6 +6,8 @@
#ifndef FOREACHEVENT_H
#define FOREACHEVENT_H
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
namespace gd {
@@ -62,13 +64,17 @@ class GD_CORE_API ForEachEvent : public gd::BaseEvent {
virtual void UnserializeFrom(gd::Project& project,
const SerializerElement& element);
std::vector<gd::Expression*> GetAllObjectExpressions() {
std::vector<gd::Expression*> allObjectExpressions;
allObjectExpressions.push_back(&objectsToPick);
return allObjectExpressions;
}
private:
gd::Expression objectsToPick;
gd::InstructionsList conditions;
gd::InstructionsList actions;
gd::EventsList events;
bool objectsToPickSelected;
};
} // namespace gd

View File

@@ -131,30 +131,36 @@ void LinkEvent::SerializeTo(SerializerElement& element) const {
void LinkEvent::UnserializeFrom(gd::Project& project,
const SerializerElement& element) {
SerializerElement& includeElement = element.GetChild("include", 0, "Limites");
SetTarget(element.GetChild("target", 0, "Scene").GetValue().GetString());
if (includeElement.HasAttribute("includeAll")) {
// Compatibility with GDevelop <= 4.0.92
if (includeElement.GetBoolAttribute("includeAll", true)) {
SetIncludeAllEvents();
// Compatibility with GD <= 5
if (element.HasChild("include", "Limites")) {
SerializerElement& includeElement = element.GetChild("include", 0, "Limites");
if (includeElement.HasAttribute("includeAll")) {
// Compatibility with GDevelop <= 4.0.92
if (includeElement.GetBoolAttribute("includeAll", true)) {
SetIncludeAllEvents();
} else {
SetIncludeStartAndEnd(includeElement.GetIntAttribute("start"),
includeElement.GetIntAttribute("end"));
}
} else {
SetIncludeStartAndEnd(includeElement.GetIntAttribute("start"),
includeElement.GetIntAttribute("end"));
// GDevelop > 4.0.92
IncludeConfig config = static_cast<IncludeConfig>(
includeElement.GetIntAttribute("includeConfig", 0));
if (config == INCLUDE_ALL)
SetIncludeAllEvents();
else if (config == INCLUDE_EVENTS_GROUP)
SetIncludeEventsGroup(includeElement.GetStringAttribute("eventsGroup"));
else if (config == INCLUDE_BY_INDEX)
SetIncludeStartAndEnd(includeElement.GetIntAttribute("start"),
includeElement.GetIntAttribute("end"));
}
} else {
// GDevelop > 4.0.92
IncludeConfig config = static_cast<IncludeConfig>(
includeElement.GetIntAttribute("includeConfig", 0));
if (config == INCLUDE_ALL)
SetIncludeAllEvents();
else if (config == INCLUDE_EVENTS_GROUP)
SetIncludeEventsGroup(includeElement.GetStringAttribute("eventsGroup"));
else if (config == INCLUDE_BY_INDEX)
SetIncludeStartAndEnd(includeElement.GetIntAttribute("start"),
includeElement.GetIntAttribute("end"));
// Since GDevelop 5, links always include all events.
SetIncludeAllEvents();
}
// end of compatibility code
}
bool LinkEvent::AcceptVisitor(gd::EventVisitor &eventVisitor) {

View File

@@ -15,16 +15,48 @@
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/IDE/ProjectBrowserHelper.h"
namespace gd {
void ExposeProjectEffects(
const gd::Project& project,
const std::function<void(const gd::Effect& effect)>& worker) {
void EffectsCodeGenerator::DoVisitObject(gd::Object &object) {
auto &effects = object.GetEffects();
for (std::size_t e = 0; e < effects.GetEffectsCount(); e++) {
auto &effect = effects.GetEffect(e);
AddEffectIncludeFiles(effect);
}
};
void EffectsCodeGenerator::AddEffectIncludeFiles(const gd::Effect &effect) {
// TODO: this browse all the extensions every time we're trying to find
// a new effect. Might be a good idea to rework MetadataProvider to be
// faster (not sure if it is a bottleneck at all though - but could be
// for events code generation).
const gd::EffectMetadata &effectMetadata =
MetadataProvider::GetEffectMetadata(platform, effect.GetEffectType());
for (auto &includeFile : effectMetadata.GetIncludeFiles())
includeFiles.insert(includeFile);
};
void EffectsCodeGenerator::GenerateEffectsIncludeFiles(
const gd::Platform &platform,
gd::Project &project,
std::set<gd::String> &includeFiles) {
// TODO Add unit tests on this function.
// TODO Merge with UsedExtensionsFinder.
// Default lights rely on the fact that UsedExtensionsFinder doesn't find
// extension usages for effects. This has the happy side effect of not
// including Three.js when no 3D object are in the scenes.
// We need to make something explicit to avoid future bugs.
// See also gd::Project::ExposeResources for a method that traverse the whole
// project (this time for resources) and
// WholeProjectRefactorer::ExposeProjectEvents.
EffectsCodeGenerator effectsCodeGenerator(platform, includeFiles);
// Add layouts effects
for (std::size_t s = 0; s < project.GetLayoutsCount(); s++) {
auto& layout = project.GetLayout(s);
@@ -33,47 +65,13 @@ void ExposeProjectEffects(
auto& effects = layout.GetLayer(l).GetEffects();
for (std::size_t e = 0; e < effects.GetEffectsCount(); ++e) {
auto& effect = effects.GetEffect(e);
worker(effect);
}
}
for (std::size_t i = 0; i < layout.GetObjectsCount(); i++) {
auto& object = layout.GetObject(i);
auto& effects = object.GetEffects();
for (std::size_t e = 0; e < effects.GetEffectsCount(); e++) {
auto& effect = effects.GetEffect(e);
worker(effect);
effectsCodeGenerator.AddEffectIncludeFiles(effect);
}
}
}
// Add global object effects
for (std::size_t s = 0; s < project.GetObjectsCount(); s++) {
auto& effects = project.GetObject(s).GetEffects();
for (std::size_t e = 0; e < effects.GetEffectsCount(); e++) {
auto& effect = effects.GetEffect(e);
worker(effect);
}
}
}
void EffectsCodeGenerator::GenerateEffectsIncludeFiles(
const gd::Platform& platform,
const gd::Project& project,
std::set<gd::String>& includeFiles) {
ExposeProjectEffects(
project, [&platform, &includeFiles](const gd::Effect& effect) {
// TODO: this browse all the extensions every time we're trying to find
// a new effect. Might be a good idea to rework MetadataProvider to be
// faster (not sure if it is a bottleneck at all though - but could be
// for events code generation).
const gd::EffectMetadata& effectMetadata =
MetadataProvider::GetEffectMetadata(platform,
effect.GetEffectType());
for (auto& includeFile : effectMetadata.GetIncludeFiles())
includeFiles.insert(includeFile);
});
// Add objects effects
gd::ProjectBrowserHelper::ExposeProjectObjects(project, effectsCodeGenerator);
}
} // namespace gd

View File

@@ -3,16 +3,18 @@
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EffectsCodeGenerator_H
#define GDCORE_EffectsCodeGenerator_H
#pragma once
#include <set>
#include <utility>
#include <vector>
#include "GDCore/String.h"
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
namespace gd {
class Project;
class Platform;
class Effect;
} // namespace gd
namespace gd {
@@ -20,16 +22,26 @@ namespace gd {
/**
* \brief Internal class used to generate code from events
*/
class GD_CORE_API EffectsCodeGenerator {
public:
class GD_CORE_API EffectsCodeGenerator : public ArbitraryObjectsWorker {
public:
/**
* \brief Add all the include files required by the project effects.
*/
static void GenerateEffectsIncludeFiles(const gd::Platform& platform,
const gd::Project& project,
gd::Project& project,
std::set<gd::String>& includeFiles);
private:
EffectsCodeGenerator(const gd::Platform &platform_,
std::set<gd::String> &includeFiles_)
: platform(platform_), includeFiles(includeFiles_){};
void AddEffectIncludeFiles(const gd::Effect& effect);
void DoVisitObject(gd::Object &object) override;
const gd::Platform &platform;
std::set<gd::String> &includeFiles;
};
} // namespace gd
#endif // GDCORE_EffectsCodeGenerator_H

View File

@@ -267,11 +267,11 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
return "/* Unknown instruction - skipped. */";
}
AddIncludeFiles(instrInfos.codeExtraInformation.GetIncludeFiles());
AddIncludeFiles(instrInfos.GetIncludeFiles());
maxConditionsListsSize =
std::max(maxConditionsListsSize, condition.GetSubInstructions().size());
if (instrInfos.codeExtraInformation.HasCustomCodeGenerator()) {
if (instrInfos.HasCustomCodeGenerator()) {
context.EnterCustomCondition();
conditionCode += instrInfos.codeExtraInformation.customCodeGenerator(
condition, *this, context);
@@ -323,11 +323,6 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
const ObjectMetadata& objInfo =
MetadataProvider::GetObjectMetadata(platform, objectType);
if (objInfo.IsUnsupportedBaseObjectCapability(
instrInfos.GetRequiredBaseObjectCapability())) {
conditionCode +=
"/* Object with unsupported capability - skipped. */\n";
} else {
AddIncludeFiles(objInfo.includeFiles);
context.SetCurrentObject(realObjects[i]);
context.ObjectsListNeeded(realObjects[i]);
@@ -344,7 +339,6 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
context);
context.SetNoCurrentObject();
}
}
}
} else if (instrInfos.IsBehaviorInstruction()) {
@@ -459,9 +453,9 @@ gd::String EventsCodeGenerator::GenerateActionCode(
return "/* Unknown instruction - skipped. */";
}
AddIncludeFiles(instrInfos.codeExtraInformation.GetIncludeFiles());
AddIncludeFiles(instrInfos.GetIncludeFiles());
if (instrInfos.codeExtraInformation.HasCustomCodeGenerator()) {
if (instrInfos.HasCustomCodeGenerator()) {
return instrInfos.codeExtraInformation.customCodeGenerator(
action, *this, context);
}
@@ -515,10 +509,6 @@ gd::String EventsCodeGenerator::GenerateActionCode(
const ObjectMetadata& objInfo =
MetadataProvider::GetObjectMetadata(platform, objectType);
if (objInfo.IsUnsupportedBaseObjectCapability(
instrInfos.GetRequiredBaseObjectCapability())) {
actionCode += "/* Object with unsupported capability - skipped. */\n";
} else {
AddIncludeFiles(objInfo.includeFiles);
context.SetCurrentObject(realObjects[i]);
context.ObjectsListNeeded(realObjects[i]);
@@ -535,7 +525,6 @@ gd::String EventsCodeGenerator::GenerateActionCode(
optionalAsyncCallbackName);
context.SetNoCurrentObject();
}
}
}
} else if (instrInfos.IsBehaviorInstruction()) {
@@ -974,6 +963,8 @@ void EventsCodeGenerator::DeleteUselessEvents(gd::EventsList& events) {
*/
void EventsCodeGenerator::PreprocessEventList(gd::EventsList& listEvent) {
for (std::size_t i = 0; i < listEvent.GetEventsCount(); ++i) {
if (listEvent[i].IsDisabled()) continue;
listEvent[i].Preprocess(*this, listEvent, i);
if (i <
listEvent.GetEventsCount()) { // Be sure that that there is still an

View File

@@ -216,10 +216,10 @@ gd::String ExpressionCodeGenerator::GenerateFreeFunctionCode(
const std::vector<std::unique_ptr<ExpressionNode>>& parameters,
const ExpressionMetadata& expressionMetadata) {
codeGenerator.AddIncludeFiles(
expressionMetadata.codeExtraInformation.GetIncludeFiles());
expressionMetadata.GetIncludeFiles());
// Launch custom code generator if needed
if (expressionMetadata.codeExtraInformation.HasCustomCodeGenerator()) {
if (expressionMetadata.HasCustomCodeGenerator()) {
return expressionMetadata.codeExtraInformation.customCodeGenerator(
PrintParameters(parameters), codeGenerator, context);
}
@@ -242,10 +242,10 @@ gd::String ExpressionCodeGenerator::GenerateObjectFunctionCode(
codeGenerator.GetObjectsAndGroups();
codeGenerator.AddIncludeFiles(
expressionMetadata.codeExtraInformation.GetIncludeFiles());
expressionMetadata.GetIncludeFiles());
// Launch custom code generator if needed
if (expressionMetadata.codeExtraInformation.HasCustomCodeGenerator()) {
if (expressionMetadata.HasCustomCodeGenerator()) {
return expressionMetadata.codeExtraInformation.customCodeGenerator(
PrintParameters(parameters), codeGenerator, context);
}
@@ -270,11 +270,6 @@ gd::String ExpressionCodeGenerator::GenerateObjectFunctionCode(
const ObjectMetadata& objInfo = MetadataProvider::GetObjectMetadata(
codeGenerator.GetPlatform(), objectType);
if (objInfo.IsUnsupportedBaseObjectCapability(
expressionMetadata.GetRequiredBaseObjectCapability())) {
// Do nothing, skipping objects not supporting the capability required by
// this expression.
} else {
codeGenerator.AddIncludeFiles(objInfo.includeFiles);
functionOutput = codeGenerator.GenerateObjectFunctionCall(
realObjects[i],
@@ -283,7 +278,6 @@ gd::String ExpressionCodeGenerator::GenerateObjectFunctionCode(
parametersCode,
functionOutput,
context);
}
}
return functionOutput;
@@ -300,10 +294,10 @@ gd::String ExpressionCodeGenerator::GenerateBehaviorFunctionCode(
codeGenerator.GetObjectsAndGroups();
codeGenerator.AddIncludeFiles(
expressionMetadata.codeExtraInformation.GetIncludeFiles());
expressionMetadata.GetIncludeFiles());
// Launch custom code generator if needed
if (expressionMetadata.codeExtraInformation.HasCustomCodeGenerator()) {
if (expressionMetadata.HasCustomCodeGenerator()) {
return expressionMetadata.codeExtraInformation.customCodeGenerator(
PrintParameters(parameters), codeGenerator, context);
}

View File

@@ -282,6 +282,14 @@ class GD_CORE_API BaseEvent {
*/
bool IsFolded() const { return folded; }
/**
* \brief Return a list of all objects linked to the event.
*/
virtual std::vector<gd::Expression*> GetAllObjectExpressions() {
std::vector<gd::Expression*> allObjectExpressions;
return allObjectExpressions;
}
///@}
std::weak_ptr<gd::BaseEvent>

View File

@@ -19,8 +19,10 @@
#include "GDCore/Project/Project.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/MakeUnique.h"
#include "GrammarTerminals.h"
using namespace std;
using namespace gd::GrammarTerminals;
namespace gd {

View File

@@ -18,6 +18,7 @@
#include "GDCore/String.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/MakeUnique.h"
#include "GrammarTerminals.h"
namespace gd {
class Expression;
class ObjectsContainer;
@@ -28,6 +29,8 @@ class ExpressionMetadata;
namespace gd {
using namespace gd::GrammarTerminals;
/** \brief Parse an expression, returning a tree of node corresponding
* to the parsed expression.
*
@@ -211,7 +214,7 @@ class GD_CORE_API ExpressionParser2 {
}
SkipIfChar(IsClosingParenthesis);
return factor;
} else if (IsIdentifierAllowedChar()) {
} else if (CheckIfChar(IsAllowedInIdentifier)) {
return Identifier();
}
@@ -606,95 +609,6 @@ class GD_CORE_API ExpressionParser2 {
return predicate(character);
}
bool IsIdentifierAllowedChar() {
if (currentPosition >= expression.size()) return false;
gd::String::value_type character = expression[currentPosition];
// Quickly compare if the character is a number or ASCII character.
if ((character >= '0' && character <= '9') ||
(character >= 'A' && character <= 'Z') ||
(character >= 'a' && character <= 'z'))
return true;
// Otherwise do the full check against separators forbidden in identifiers.
if (!IsParameterSeparator(character) && !IsDot(character) &&
!IsQuote(character) && !IsBracket(character) &&
!IsExpressionOperator(character) && !IsTermOperator(character)) {
return true;
}
return false;
}
static bool IsWhitespace(gd::String::value_type character) {
return character == ' ' || character == '\n' || character == '\r';
}
static bool IsParameterSeparator(gd::String::value_type character) {
return character == ',';
}
static bool IsDot(gd::String::value_type character) {
return character == '.';
}
static bool IsQuote(gd::String::value_type character) {
return character == '"';
}
static bool IsBracket(gd::String::value_type character) {
return character == '(' || character == ')' || character == '[' ||
character == ']' || character == '{' || character == '}';
}
static bool IsOpeningParenthesis(gd::String::value_type character) {
return character == '(';
}
static bool IsClosingParenthesis(gd::String::value_type character) {
return character == ')';
}
static bool IsOpeningSquareBracket(gd::String::value_type character) {
return character == '[';
}
static bool IsClosingSquareBracket(gd::String::value_type character) {
return character == ']';
}
static bool IsExpressionEndingChar(gd::String::value_type character) {
return character == ',' || IsClosingParenthesis(character) ||
IsClosingSquareBracket(character);
}
static bool IsExpressionOperator(gd::String::value_type character) {
return character == '+' || character == '-' || character == '<' ||
character == '>' || character == '?' || character == '^' ||
character == '=' || character == '\\' || character == ':' ||
character == '!';
}
static bool IsUnaryOperator(gd::String::value_type character) {
return character == '+' || character == '-';
}
static bool IsTermOperator(gd::String::value_type character) {
return character == '/' || character == '*';
}
static bool IsNumberFirstChar(gd::String::value_type character) {
return character == '.' || (character >= '0' && character <= '9');
}
static bool IsNonZeroDigit(gd::String::value_type character) {
return (character >= '1' && character <= '9');
}
static bool IsZeroDigit(gd::String::value_type character) {
return character == '0';
}
bool IsNamespaceSeparator() {
// Namespace separator is a special kind of delimiter as it is 2 characters
// long
@@ -715,7 +629,7 @@ class GD_CORE_API ExpressionParser2 {
gd::String name;
size_t startPosition = currentPosition;
while (currentPosition < expression.size() &&
(IsIdentifierAllowedChar()
(CheckIfChar(IsAllowedInIdentifier)
// Allow whitespace in identifier name for compatibility
|| expression[currentPosition] == ' ')) {
name += expression[currentPosition];

View File

@@ -0,0 +1,118 @@
#pragma once
#include "GDCore/String.h"
namespace gd {
/**
* Contains functions to handle the grammar of the expressions accepted by GDevelop.
*/
namespace GrammarTerminals {
inline bool IsWhitespace(gd::String::value_type character) {
return character == ' ' || character == '\n' || character == '\r';
}
inline bool IsParameterSeparator(gd::String::value_type character) {
return character == ',';
}
inline bool IsDot(gd::String::value_type character) { return character == '.'; }
inline bool IsQuote(gd::String::value_type character) {
return character == '"';
}
inline bool IsBracket(gd::String::value_type character) {
return character == '(' || character == ')' || character == '[' ||
character == ']' || character == '{' || character == '}';
}
inline bool IsOpeningParenthesis(gd::String::value_type character) {
return character == '(';
}
inline bool IsClosingParenthesis(gd::String::value_type character) {
return character == ')';
}
inline bool IsOpeningSquareBracket(gd::String::value_type character) {
return character == '[';
}
inline bool IsClosingSquareBracket(gd::String::value_type character) {
return character == ']';
}
inline bool IsExpressionEndingChar(gd::String::value_type character) {
return character == ',' || IsClosingParenthesis(character) ||
IsClosingSquareBracket(character);
}
inline bool IsExpressionOperator(gd::String::value_type character) {
return character == '+' || character == '-' || character == '<' ||
character == '>' || character == '?' || character == '^' ||
character == '=' || character == '\\' || character == ':' ||
character == '!';
}
inline bool IsUnaryOperator(gd::String::value_type character) {
return character == '+' || character == '-';
}
inline bool IsTermOperator(gd::String::value_type character) {
return character == '/' || character == '*';
}
inline bool IsNumberFirstChar(gd::String::value_type character) {
return character == '.' || (character >= '0' && character <= '9');
}
inline bool IsNonZeroDigit(gd::String::value_type character) {
return (character >= '1' && character <= '9');
}
inline bool IsZeroDigit(gd::String::value_type character) {
return character == '0';
}
inline bool IsAdditionalReservedCharacter(gd::String::value_type character) {
// These characters are not part of the grammar - but are often used in programming language
// and could become operators or part of the grammar one day.
return character == '~' || character == '\'' || character == '%' ||
character == '#' || character == '@' || character == '|' ||
character == '&' || character == '`' || character == '$' ||
character == ';';
}
/**
* Check if the given character can be used in an identifier. This is
* any unicode character, except for:
* `, . " () [] {} + - < > ? ^ = \ : ! / * ~ ' % # @ | & $ ;`
* and backtick and whitespaces (space, line break, carriage return).
*
* This is loosely based on what is allowed in languages like JavaScript
* (see https://mathiasbynens.be/notes/javascript-properties), without support
* for unicode escape syntax, and allowing all unicode ranges. The only
* disallowed characters are the one used for the grammar.
*/
inline bool IsAllowedInIdentifier(gd::String::value_type character) {
// Quickly compare if the character is a number or ASCII character.
if ((character >= '0' && character <= '9') ||
(character >= 'A' && character <= 'Z') ||
(character >= 'a' && character <= 'z'))
return true;
// Otherwise do the full check against separators forbidden in identifiers.
if (!IsParameterSeparator(character) && !IsDot(character) &&
!IsQuote(character) && !IsBracket(character) &&
!IsExpressionOperator(character) && !IsTermOperator(character) &&
!IsWhitespace(character) && !IsAdditionalReservedCharacter(character)) {
return true;
}
return false;
}
} // namespace GrammarTerminals
} // namespace gd

View File

@@ -17,7 +17,7 @@ const gd::String& EventsCodeNameMangler::GetMangledObjectsListName(
return it->second;
}
gd::String partiallyMangledName = originalObjectName;
gd::String partiallyMangledName = GetMangledNameWithForbiddenUnderscore(originalObjectName);
static const gd::String allowedCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@@ -43,7 +43,15 @@ const gd::String& EventsCodeNameMangler::GetExternalEventsFunctionMangledName(
return it->second;
}
gd::String partiallyMangledName = externalEventsName;
gd::String partiallyMangledName = GetMangledNameWithForbiddenUnderscore(externalEventsName);
mangledExternalEventsNames[externalEventsName] = "GDExternalEvents" + partiallyMangledName;
return mangledExternalEventsNames[externalEventsName];
}
gd::String EventsCodeNameMangler::GetMangledNameWithForbiddenUnderscore(
const gd::String &name) {
gd::String partiallyMangledName = name;
static const gd::String allowedCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@@ -57,11 +65,30 @@ const gd::String& EventsCodeNameMangler::GetExternalEventsFunctionMangledName(
partiallyMangledName.replace(i, 1, "_" + gd::String::From(unallowedChar));
}
}
mangledExternalEventsNames[externalEventsName] = "GDExternalEvents" + partiallyMangledName;
return mangledExternalEventsNames[externalEventsName];
return partiallyMangledName;
}
gd::String EventsCodeNameMangler::GetMangledName(
const gd::String &name) {
gd::String partiallyMangledName = name;
static const gd::String allowedCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
for (size_t i = 0; i < partiallyMangledName.size();
++i) // Replace all unallowed letter by an underscore and the ascii
// number of the letter
{
if (allowedCharacters.find_first_of(
std::u32string(1, partiallyMangledName[i])) == gd::String::npos) {
char32_t unallowedChar = partiallyMangledName[i];
partiallyMangledName.replace(i, 1, "_" + gd::String::From(unallowedChar));
}
}
return partiallyMangledName;
}
const gd::String& ManObjListName(const gd::String &objectName) {
return EventsCodeNameMangler::Get()->GetMangledObjectsListName(objectName);
}

View File

@@ -36,6 +36,8 @@ class GD_CORE_API EventsCodeNameMangler {
const gd::String &GetExternalEventsFunctionMangledName(
const gd::String &externalEventsName);
static gd::String GetMangledName(const gd::String &name);
static EventsCodeNameMangler *Get();
static void DestroySingleton();
@@ -44,6 +46,9 @@ class GD_CORE_API EventsCodeNameMangler {
virtual ~EventsCodeNameMangler(){};
static EventsCodeNameMangler *_singleton;
// This method is inlined to avoid to copy the returned string.
static inline gd::String GetMangledNameWithForbiddenUnderscore(const gd::String &name);
std::unordered_map<gd::String, gd::String>
mangledObjectNames; ///< Memoized results of mangling for objects
std::unordered_map<gd::String, gd::String>

View File

@@ -43,6 +43,12 @@ class GD_CORE_API BuiltinExtensionsImplementer {
static void ImplementsVariablesExtension(gd::PlatformExtension& extension);
static void ImplementsWindowExtension(gd::PlatformExtension& extension);
static void ImplementsAsyncExtension(gd::PlatformExtension& extension);
static void ImplementsResizableExtension(gd::PlatformExtension& extension);
static void ImplementsScalableExtension(gd::PlatformExtension& extension);
static void ImplementsFlippableExtension(gd::PlatformExtension& extension);
static void ImplementsAnimatableExtension(gd::PlatformExtension& extension);
static void ImplementsEffectExtension(gd::PlatformExtension& extension);
static void ImplementsOpacityExtension(gd::PlatformExtension& extension);
};
} // namespace gd

View File

@@ -29,8 +29,16 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.SetIcon("res/actions/force24.png");
extension.AddInstructionOrExpressionGroupMetadata(_("Variables"))
.SetIcon("res/conditions/var24.png");
extension.AddInstructionOrExpressionGroupMetadata(_("Timers"))
.SetIcon("res/actions/timer24.png");
extension.AddInstructionOrExpressionGroupMetadata(_("Visibility"))
.SetIcon("res/actions/visibilite24.png");
extension.AddInstructionOrExpressionGroupMetadata(_("Position"))
.SetIcon("res/actions/position24_black.png");
extension.AddInstructionOrExpressionGroupMetadata(_("Angle"))
.SetIcon("res/actions/direction24_black.png");
extension.AddInstructionOrExpressionGroupMetadata(_("Size"))
.SetIcon("res/actions/scale24_black.png");
gd::ObjectMetadata& obj = extension.AddObject<gd::ObjectConfiguration>(
"", _("Base object"), _("Base object"), "res/objeticon24.png");
@@ -1101,6 +1109,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/scaleWidth_black.png")
.AddParameter("object", _("Object"));
// Deprecated
obj.AddExpression("Largeur",
_("Width"),
_("Width of the object"),
@@ -1116,6 +1125,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/scaleHeight_black.png")
.AddParameter("object", _("Object"));
// Deprecated
obj.AddExpression("Hauteur",
_("Height"),
_("Height of the object"),
@@ -1201,7 +1211,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddExpression("ObjectTimerElapsedTime",
_("Object timer value"),
_("Value of an object timer"),
_("Object timers"),
_("Timers"),
"res/actions/time.png")
.AddParameter("object", _("Object"))
.AddParameter("identifier", _("Timer's name"), "objectTimer");
@@ -1251,6 +1261,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression", _("Target X position"))
.AddParameter("expression", _("Target Y position"));
// Deprecated
obj.AddAction("EnableEffect",
_("Enable an object effect"),
_("Enable an effect on the object"),
@@ -1262,8 +1273,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("yesorno", _("Enable?"))
.MarkAsSimple()
.SetRequiresBaseObjectCapability("effect");
.SetHidden();
// Deprecated
obj.AddAction("SetEffectDoubleParameter",
_("Effect parameter (number)"),
_("Change the value of a parameter of an effect.") + "\n" +
@@ -1278,8 +1290,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectEffectParameterName", _("Parameter name"))
.AddParameter("expression", _("New value"))
.MarkAsSimple()
.SetRequiresBaseObjectCapability("effect");
.SetHidden();
// Deprecated
obj.AddAction("SetEffectStringParameter",
_("Effect parameter (string)"),
_("Change the value (string) of a parameter of an effect.") +
@@ -1295,8 +1308,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectEffectParameterName", _("Parameter name"))
.AddParameter("string", _("New value"))
.MarkAsSimple()
.SetRequiresBaseObjectCapability("effect");
.SetHidden();
// Deprecated
obj.AddAction("SetEffectBooleanParameter",
_("Effect parameter (enable or disable)"),
_("Enable or disable a parameter of an effect.") + "\n" +
@@ -1311,8 +1325,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectEffectParameterName", _("Parameter name"))
.AddParameter("yesorno", _("Enable?"))
.MarkAsSimple()
.SetRequiresBaseObjectCapability("effect");
.SetHidden();
// Deprecated
obj.AddCondition("IsEffectEnabled",
_("Effect is enabled"),
_("Check if the effect on an object is enabled."),
@@ -1323,7 +1338,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.MarkAsSimple()
.SetRequiresBaseObjectCapability("effect");
.SetHidden();
obj.AddAction("SetIncludedInParentCollisionMask",
_("Include in parent collision mask"),

View File

@@ -0,0 +1,135 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the GNU Lesser General Public
* License.
*/
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
#include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/BehaviorsSharedData.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Tools/Localization.h"
using namespace std;
namespace gd {
void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAnimatableExtension(
gd::PlatformExtension& extension) {
extension
.SetExtensionInformation("AnimatableCapability",
_("Animatable capability"),
_("Animate objects."),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/objects");
extension.AddInstructionOrExpressionGroupMetadata(_("Animations and images"))
.SetIcon("res/actions/animation24.png");
gd::BehaviorMetadata& aut = extension.AddBehavior(
"AnimatableBehavior",
_("Animatable capability"),
"Animation",
_("Animate objects."),
"",
"res/actions/animation24.png",
"AnimatableBehavior",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetHidden();
aut.AddExpressionAndConditionAndAction(
"number",
"Index",
_("Animation (by number)"),
_("the number of the animation played by the object (the number from "
"the animations list)"),
_("the number of the animation"),
_("Animations and images"),
"res/actions/animation24.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "AnimatableBehavior")
.UseStandardParameters(
"number", gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Animation index")))
.MarkAsSimple();
aut.AddExpressionAndConditionAndAction(
"string",
"Name",
_("Animation (by name)"),
_("the animation played by the object using the name of the "
"animation"),
_("the animation"),
_("Animations and images"),
"res/actions/animation24.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "AnimatableBehavior")
.UseStandardParameters(
"objectAnimationName", gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Animation name")))
.MarkAsSimple();
aut.AddScopedAction("PauseAnimation",
_("Pause the animation"),
_("Pause the animation of the object."),
_("Pause the animation of _PARAM0_"),
_("Animations and images"),
"res/actions/animation24.png",
"res/actions/animation.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "AnimatableBehavior")
.MarkAsSimple();
aut.AddScopedAction("PlayAnimation",
_("Resume the animation"),
_("Resume the animation of the object."),
_("Resume the animation of _PARAM0_"),
_("Animations and images"),
"res/actions/animation24.png",
"res/actions/animation.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "AnimatableBehavior")
.MarkAsSimple();
aut.AddExpressionAndConditionAndAction(
"number",
"SpeedScale",
_("Animation speed scale"),
_("the animation speed scale (1 = the default speed, >1 = faster and "
"<1 = slower)"),
_("the animation speed scale"),
_("Animations and images"),
"res/actions/animation24.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "AnimatableBehavior")
.UseStandardParameters(
"number", gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Speed scale")))
.MarkAsSimple();
aut.AddScopedCondition("IsAnimationPaused",
_("Animation paused"),
_("Check if the animation of an object is paused."),
_("The animation of _PARAM0_ is paused"),
_("Animations and images"),
"res/conditions/animation24.png",
"res/conditions/animation.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "AnimatableBehavior")
.MarkAsSimple();
aut.AddScopedCondition("HasAnimationEnded",
_("Animation finished"),
_("Check if the animation being played by the Sprite object "
"is finished."),
_("The animation of _PARAM0_ is finished"),
_("Animations and images"),
"res/conditions/animation24.png",
"res/conditions/animation.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "AnimatableBehavior")
.MarkAsSimple();
}
} // namespace gd

View File

@@ -0,0 +1,116 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the GNU Lesser General Public
* License.
*/
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
#include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/BehaviorsSharedData.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Tools/Localization.h"
using namespace std;
namespace gd {
void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
gd::PlatformExtension& extension) {
extension
.SetExtensionInformation("EffectCapability",
_("Effect capability"),
_("Apply visual effects to objects."),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/objects");
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
.SetIcon("res/actions/effect24.png");
gd::BehaviorMetadata& aut = extension.AddBehavior(
"EffectBehavior",
_("Effect capability"),
"Effect",
_("Apply visual effects to objects."),
"",
"res/actions/effect24.png",
"EffectBehavior",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetHidden();
aut.AddScopedAction("EnableEffect",
_("Enable an object effect"),
_("Enable an effect on the object"),
_("Enable effect _PARAM2_ on _PARAM0_: _PARAM3_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("yesorno", _("Enable?"))
.MarkAsSimple();
aut.AddScopedAction("SetEffectDoubleParameter",
_("Effect parameter (number)"),
_("Change the value of a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Parameter name"))
.AddParameter("expression", _("New value"))
.MarkAsSimple();
aut.AddScopedAction("SetEffectStringParameter",
_("Effect parameter (string)"),
_("Change the value (string) of a parameter of an effect.") +
"\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Parameter name"))
.AddParameter("string", _("New value"))
.MarkAsSimple();
aut.AddScopedAction("SetEffectBooleanParameter",
_("Effect parameter (enable or disable)"),
_("Enable or disable a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Enable _PARAM3_ for effect _PARAM2_ of _PARAM0_: _PARAM4_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Parameter name"))
.AddParameter("yesorno", _("Enable?"))
.MarkAsSimple();
aut.AddScopedCondition("IsEffectEnabled",
_("Effect is enabled"),
_("Check if the effect on an object is enabled."),
_("Effect _PARAM2_ of _PARAM0_ is enabled"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
.MarkAsSimple();
}
} // 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 GNU Lesser General Public
* License.
*/
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
#include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/BehaviorsSharedData.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Tools/Localization.h"
using namespace std;
namespace gd {
void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFlippableExtension(
gd::PlatformExtension& extension) {
extension
.SetExtensionInformation("FlippableCapability",
_("Flippable capability"),
_("Flip objects."),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/objects");
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
.SetIcon("res/actions/effect24.png");
gd::BehaviorMetadata& aut = extension.AddBehavior(
"FlippableBehavior",
_("Flippable capability"),
"Flippable",
_("Flip objects."),
"",
"res/actions/flipX24.png",
"FlippableBehavior",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetHidden();
aut.AddScopedAction("FlipX",
_("Flip the object horizontally"),
_("Flip the object horizontally"),
_("Flip horizontally _PARAM0_: _PARAM2_"),
_("Effects"),
"res/actions/flipX24.png",
"res/actions/flipX.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "FlippableBehavior")
.AddParameter("yesorno", _("Activate flipping"))
.MarkAsSimple();
aut.AddScopedAction("FlipY",
_("Flip the object vertically"),
_("Flip the object vertically"),
_("Flip vertically _PARAM0_: _PARAM2_"),
_("Effects"),
"res/actions/flipY24.png",
"res/actions/flipY.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "FlippableBehavior")
.AddParameter("yesorno", _("Activate flipping"))
.MarkAsSimple();
aut.AddScopedCondition("FlippedX",
_("Horizontally flipped"),
_("Check if the object is horizontally flipped"),
_("_PARAM0_ is horizontally flipped"),
_("Effects"),
"res/actions/flipX24.png",
"res/actions/flipX.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "FlippableBehavior");
aut.AddScopedCondition("FlippedY",
_("Vertically flipped"),
_("Check if the object is vertically flipped"),
_("_PARAM0_ is vertically flipped"),
_("Effects"),
"res/actions/flipY24.png",
"res/actions/flipY.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "FlippableBehavior");
}
} // namespace gd

View File

@@ -0,0 +1,59 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the GNU Lesser General Public
* License.
*/
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
#include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/BehaviorsSharedData.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Tools/Localization.h"
using namespace std;
namespace gd {
void GD_CORE_API BuiltinExtensionsImplementer::ImplementsOpacityExtension(
gd::PlatformExtension& extension) {
extension
.SetExtensionInformation("OpacityCapability",
_("Opacity capability"),
_("Change the object opacity."),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/objects");
extension.AddInstructionOrExpressionGroupMetadata(_("Visibility"))
.SetIcon("res/actions/opacity24.png");
gd::BehaviorMetadata& aut = extension.AddBehavior(
"OpacityBehavior",
_("Opacity capability"),
"Opacity",
_("Change the object opacity."),
"",
"res/actions/opacity24.png",
"OpacityBehavior",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetHidden();
aut.AddExpressionAndConditionAndAction(
"number",
"Value",
_("Opacity"),
_("the opacity of an object, between 0 (fully transparent) to 255 "
"(opaque)"),
_("the opacity"),
_("Visibility"),
"res/actions/opacity24.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "OpacityBehavior")
.UseStandardParameters(
"number", gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Opacity (0-255)")))
.SetFunctionName("setOpacity")
.SetGetter("getOpacity");
}
} // namespace gd

View File

@@ -0,0 +1,112 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the GNU Lesser General Public
* License.
*/
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/BehaviorsSharedData.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Tools/Localization.h"
using namespace std;
namespace gd {
void GD_CORE_API BuiltinExtensionsImplementer::ImplementsResizableExtension(
gd::PlatformExtension &extension) {
extension
.SetExtensionInformation("ResizableCapability",
_("Resizable capability"),
_("Change the object dimensions."),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/objects");
extension.AddInstructionOrExpressionGroupMetadata(_("Size")).SetIcon(
"res/actions/scale24_black.png");
gd::BehaviorMetadata &aut =
extension
.AddBehavior("ResizableBehavior",
_("Resizable capability"),
"Resizable",
_("Change the object dimensions."),
"",
"res/actions/scale24_black.png",
"ResizableBehavior",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetHidden();
aut.AddScopedAction("SetWidth",
_("Width"),
_("Change the width of the object."),
_("the width"),
_("Size"),
"res/actions/scaleWidth24_black.png",
"res/actions/scaleWidth_black.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "ResizableBehavior")
.UseStandardOperatorParameters(
"number",
ParameterOptions::MakeNewOptions().SetDescription(_("Width")))
.MarkAsAdvanced();
aut.AddScopedCondition("Width",
_("Width"),
_("Compare the width of the object."),
_("the width"),
_("Size"),
"res/conditions/scaleWidth24_black.png",
"res/conditions/scaleWidth_black.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "ResizableBehavior")
.UseStandardRelationalOperatorParameters(
"number",
ParameterOptions::MakeNewOptions().SetDescription(_("Width")))
.MarkAsAdvanced();
aut.AddScopedAction("SetHeight",
_("Height"),
_("Change the height of the object."),
_("the height"),
_("Size"),
"res/actions/scaleHeight24_black.png",
"res/actions/scaleHeight_black.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "ResizableBehavior")
.UseStandardOperatorParameters(
"number",
ParameterOptions::MakeNewOptions().SetDescription(_("Height")))
.MarkAsAdvanced();
aut.AddScopedCondition("Height",
_("Height"),
_("Compare the height of the object."),
_("the height"),
_("Size"),
"res/conditions/scaleHeight24_black.png",
"res/conditions/scaleHeight_black.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "ResizableBehavior")
.UseStandardRelationalOperatorParameters(
"number",
ParameterOptions::MakeNewOptions().SetDescription(_("Height")))
.MarkAsAdvanced();
aut.AddScopedAction(
"SetSize",
_("Size"),
_("Change the size of an object."),
_("Change the size of _PARAM0_: set to _PARAM2_ x _PARAM3_"),
_("Size"),
"res/actions/scale24_black.png",
"res/actions/scale_black.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "ResizableBehavior")
.AddParameter("expression", _("Width"))
.AddParameter("expression", _("Height"))
.MarkAsAdvanced();
}
} // namespace gd

View File

@@ -0,0 +1,90 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the GNU Lesser General Public
* License.
*/
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
#include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/BehaviorsSharedData.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Tools/Localization.h"
using namespace std;
namespace gd {
void GD_CORE_API BuiltinExtensionsImplementer::ImplementsScalableExtension(
gd::PlatformExtension& extension) {
extension
.SetExtensionInformation("ScalableCapability",
_("Scalable capability"),
_("Change the object scale."),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/objects");
extension.AddInstructionOrExpressionGroupMetadata(_("Size"))
.SetIcon("res/actions/scale24_black.png");
gd::BehaviorMetadata& aut = extension.AddBehavior(
"ScalableBehavior",
_("Scalable capability"),
"Scale",
_("Change the object scale."),
"",
"res/actions/scale24_black.png",
"ResizableBehavior",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetHidden();
aut.AddExpressionAndConditionAndAction(
"number",
"Value",
_("Scale"),
_("the scale of the object (default scale is 1)"),
_("the scale"),
_("Scale"),
"res/actions/scale24_black.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "ScalableBehavior")
.UseStandardParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Scale (1 by default)")))
.MarkAsAdvanced();
aut.AddExpressionAndConditionAndAction(
"number",
"X",
_("Scale on X axis"),
_("the scale on X axis of the object (default scale is 1)"),
_("the scale on X axis"),
_("Scale"),
"res/actions/scaleWidth24_black.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "ScalableBehavior")
.UseStandardParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Scale (1 by default)")))
.MarkAsAdvanced();
aut.AddExpressionAndConditionAndAction(
"number",
"Y",
_("Scale on Y axis"),
_("the scale on Y axis of the object (default scale is 1)"),
_("the scale on Y axis"),
_("Scale"),
"res/actions/scaleHeight24_black.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "ScalableBehavior")
.UseStandardParameters(
"number",
gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Scale (1 by default)")))
.MarkAsAdvanced();
}
} // namespace gd

View File

@@ -110,11 +110,11 @@ void Direction::UnserializeFrom(const gd::SerializerElement& element) {
.GetBoolAttribute("automatic", true));
if (spriteElement.HasChild("CustomCollisionMask"))
sprite.SetCollisionMaskAutomatic(
sprite.SetFullImageCollisionMask(
!spriteElement.GetChild("CustomCollisionMask")
.GetBoolAttribute("custom", false));
else
sprite.SetCollisionMaskAutomatic(
sprite.SetFullImageCollisionMask(
!spriteElement.GetBoolAttribute("hasCustomCollisionMask", false));
std::vector<Polygon2d> mask;
@@ -173,7 +173,7 @@ void SaveSpritesDirection(const vector<Sprite>& sprites,
.SetAttribute("automatic", sprites[i].IsDefaultCenterPoint());
spriteElement.SetAttribute("hasCustomCollisionMask",
!sprites[i].IsCollisionMaskAutomatic());
!sprites[i].IsFullImageCollisionMask());
gd::SerializerElement& collisionMaskElement =
spriteElement.AddChild("customCollisionMask");

View File

@@ -4,7 +4,9 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
#include <iostream>
#include "GDCore/Extensions/Builtin/SpriteExtension/Polygon2d.h"
using namespace std;
@@ -14,11 +16,10 @@ namespace gd {
Point Sprite::badPoint("");
Sprite::Sprite()
: automaticCollisionMask(true),
: fullImageCollisionMask(false),
origine("origine"),
centre("centre"),
automaticCentre(true) {
}
automaticCentre(true) {}
Sprite::~Sprite(){};

View File

@@ -7,6 +7,7 @@
#ifndef SPRITE_H
#define SPRITE_H
#include <memory>
#include "GDCore/Extensions/Builtin/SpriteExtension/Point.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Polygon2d.h"
#include "GDCore/String.h"
@@ -43,7 +44,7 @@ class GD_CORE_API Sprite {
/**
* \brief Get the collision mask (custom or automatically generated owing to
* IsCollisionMaskAutomatic())
* IsFullImageCollisionMask())
*
* \warning If the image has not been loaded ( using LoadImage ) and the
* collision mask is set as automatic, the returned mask won't be correct.
@@ -66,7 +67,7 @@ class GD_CORE_API Sprite {
/**
* \brief Set the custom collision mask.
* Call then `SetCollisionMaskAutomatic(false)` to use it.
* Call then `SetFullImageCollisionMask(false)` to use it.
*/
void SetCustomCollisionMask(const std::vector<Polygon2d>& collisionMask);
@@ -74,15 +75,15 @@ class GD_CORE_API Sprite {
* \brief Return true if the collision mask is a bounding box, false if a
* custom collision mask is used.
*/
inline bool IsCollisionMaskAutomatic() const {
return automaticCollisionMask;
inline bool IsFullImageCollisionMask() const {
return fullImageCollisionMask;
}
/**
* \brief Un/set use of the custom collision mask.
*/
inline void SetCollisionMaskAutomatic(bool enabled) {
automaticCollisionMask = enabled;
inline void SetFullImageCollisionMask(bool enabled) {
fullImageCollisionMask = enabled;
};
/**
@@ -161,9 +162,9 @@ class GD_CORE_API Sprite {
private:
gd::String image; ///< Name of the image to be loaded in Image Manager.
bool automaticCollisionMask; ///< True to use the custom collision mask.
///< Otherwise, a basic bounding box is returned
///< by GetCollisionMask()
bool fullImageCollisionMask; ///< True to use a bounding box wrapping the
///< whole image as collision mask. If false,
///< custom collision mask is used.
std::vector<Polygon2d> customCollisionMask; ///< Custom collision mask
std::vector<Point> points; ///< List of the points used by the sprite

View File

@@ -2,7 +2,7 @@
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the GNU Lesser General Public
* LicenFse.
* License.
*/
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
@@ -32,8 +32,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Animated object which can be used for "
"most elements of a game"),
"CppPlatform/Extensions/spriteicon.png")
.SetCategoryFullName(_("General"));
.SetCategoryFullName(_("General"))
.AddDefaultBehavior("EffectCapability::EffectBehavior")
.AddDefaultBehavior("ResizableCapability::ResizableBehavior")
.AddDefaultBehavior("ScalableCapability::ScalableBehavior")
.AddDefaultBehavior("FlippableCapability::FlippableBehavior")
.AddDefaultBehavior("OpacityCapability::OpacityBehavior")
.AddDefaultBehavior("AnimatableCapability::AnimatableBehavior");
// Deprecated
obj.AddAction("Opacity",
_("Sprite opacity"),
_("Change the opacity of a Sprite. 0 is fully transparent, 255 "
@@ -48,8 +55,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"number",
ParameterOptions::MakeNewOptions().SetDescription(
_("Opacity (0-255)")))
.MarkAsSimple();
.MarkAsSimple()
.SetHidden();
// Deprecated
obj.AddAction("ChangeAnimation",
_("Change the animation"),
_("Change the animation of the object, using the animation "
@@ -62,8 +71,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions())
.SetHidden()
.MarkAsSimple();
// Deprecated
obj.AddAction("SetAnimationName",
_("Change the animation (by name)"),
_("Change the animation of the object, using the name of the "
@@ -75,6 +86,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectAnimationName", _("Animation name"))
.SetHidden()
.MarkAsAdvanced();
obj.AddAction(
@@ -107,6 +119,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
ParameterOptions::MakeNewOptions())
.MarkAsAdvanced();
// Deprecated
obj.AddAction("PauseAnimation",
_("Pause the animation"),
_("Pause the animation of the object"),
@@ -116,8 +129,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"res/actions/animation.png")
.AddParameter("object", _("Object"), "Sprite")
.SetHidden()
.MarkAsSimple();
// Deprecated
obj.AddAction("PlayAnimation",
_("Play the animation"),
_("Play the animation of the object"),
@@ -127,8 +142,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"res/actions/animation.png")
.AddParameter("object", _("Object"), "Sprite")
.SetHidden()
.MarkAsSimple();
// Deprecated
obj.AddAction(
"ChangeAnimationSpeedScale",
_("Animation speed scale"),
@@ -143,8 +160,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.UseStandardOperatorParameters(
"number",
ParameterOptions::MakeNewOptions().SetDescription(_("Speed scale")))
.SetHidden()
.MarkAsSimple();
// Deprecated
obj.AddAction("TourneVersPos",
"Rotate an object toward a position",
"Rotate an object towards a position.",
@@ -159,8 +178,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.AddParameter("expression", _("Angular speed (degrees per second)"))
.SetDefaultValue("0")
.AddCodeOnlyParameter("currentScene", "")
.SetHidden(); // Deprecated
.SetHidden();
// Deprecated
obj.AddAction("ChangeScale",
_("Scale"),
_("Modify the scale of the specified object."),
@@ -174,8 +194,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"number",
ParameterOptions::MakeNewOptions().SetDescription(
_("Scale (1 by default)")))
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetHidden();
// Deprecated
obj.AddAction("ChangeScaleWidth",
_("Scale on X axis"),
_("Modify the scale of the width of an object."),
@@ -189,8 +211,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"number",
ParameterOptions::MakeNewOptions().SetDescription(
_("Scale (1 by default)")))
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetHidden();
// Deprecated
obj.AddAction("ChangeScaleHeight",
_("Scale on Y axis"),
_("Modify the scale of the height of an object."),
@@ -204,8 +228,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"number",
ParameterOptions::MakeNewOptions().SetDescription(
_("Scale (1 by default)")))
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetHidden();
// Deprecated
obj.AddAction("ChangeWidth",
_("Width"),
_("Change the width of a Sprite object."),
@@ -217,8 +243,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions())
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetHidden();
// Deprecated
obj.AddCondition("Width",
_("Width"),
_("Compare the width of a Sprite object."),
@@ -230,8 +258,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetHidden();
// Deprecated
obj.AddAction("ChangeHeight",
_("Height"),
_("Change the height of a Sprite object."),
@@ -243,8 +273,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions())
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetHidden();
// Deprecated
obj.AddCondition("Height",
_("Height"),
_("Compare the height of a Sprite object."),
@@ -256,8 +288,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetHidden();
// Deprecated
obj.AddAction("SetSize",
_("Size"),
_("Change the size of an object."),
@@ -269,8 +303,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Width"))
.AddParameter("expression", _("Height"))
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetHidden();
// Deprecated
obj.AddCondition(
"Animation",
_("Current animation"),
@@ -283,8 +319,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetHidden()
.MarkAsAdvanced();
// Deprecated
obj.AddCondition("AnimationName",
_("Current animation name"),
_("Check the animation played by the object."),
@@ -295,6 +333,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectAnimationName", _("Animation name"))
.SetHidden()
.MarkAsAdvanced();
obj.AddCondition(
@@ -328,6 +367,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"number", ParameterOptions::MakeNewOptions())
.MarkAsAdvanced();
// Deprecated
obj.AddCondition("AnimStopped",
_("Animation paused"),
_("Check if the animation of an object is paused."),
@@ -337,8 +377,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"res/conditions/animation.png")
.AddParameter("object", _("Object"), "Sprite")
.SetHidden()
.MarkAsSimple();
// Deprecated
obj.AddCondition("AnimationEnded",
_("Animation finished"),
_("Check if the animation being played by the Sprite object "
@@ -352,6 +394,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.MarkAsSimple()
.SetHidden();
// Deprecated
obj.AddCondition("AnimationEnded2",
_("Animation finished"),
_("Check if the animation being played by the Sprite object "
@@ -362,6 +405,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"res/conditions/animation.png")
.AddParameter("object", _("Object"), "Sprite")
.SetHidden()
.MarkAsSimple();
obj.AddCondition("ScaleWidth",
@@ -394,6 +438,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Scale (1 by default)")))
.MarkAsAdvanced();
// Deprecated
obj.AddCondition("Opacity",
_("Opacity"),
_("Compare the opacity of a Sprite, between 0 (fully "
@@ -408,7 +453,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"number",
ParameterOptions::MakeNewOptions().SetDescription(
_("Opacity to compare to (0-255)")))
.MarkAsSimple();
.MarkAsSimple()
.SetHidden();
obj.AddCondition(
"BlendMode",
@@ -456,9 +502,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Effects"),
"res/actions/flipX24.png",
"res/actions/flipX.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("yesorno", _("Activate flipping"))
.SetHidden()
.MarkAsSimple();
obj.AddAction("FlipY",
@@ -468,9 +514,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Effects"),
"res/actions/flipY24.png",
"res/actions/flipY.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("yesorno", _("Activate flipping"))
.SetHidden()
.MarkAsSimple();
obj.AddCondition("FlippedX",
@@ -480,8 +526,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Effects"),
"res/actions/flipX24.png",
"res/actions/flipX.png")
.AddParameter("object", _("Object"), "Sprite");
.AddParameter("object", _("Object"), "Sprite")
.SetHidden();
obj.AddCondition("FlippedY",
_("Vertically flipped"),
@@ -490,9 +536,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Effects"),
"res/actions/flipY24.png",
"res/actions/flipY.png")
.AddParameter("object", _("Object"), "Sprite")
.SetHidden();
.AddParameter("object", _("Object"), "Sprite");
// Deprecated
obj.AddAction("TourneVers",
"Rotate an object toward another",
"Rotate an object towards another.",
@@ -504,7 +551,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectPtr", "Rotate toward this object")
.AddCodeOnlyParameter("currentScene", "")
.SetHidden(); // Deprecated
.SetHidden();
obj.AddExpression("X",
_("X position of a point"),
@@ -542,6 +589,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectPointName", _("Name of the point"));
// Deprecated
obj.AddExpression("Direc",
_("Direction"),
_("Direction of the object"),
@@ -550,6 +598,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.SetHidden()
.AddParameter("object", _("Object"), "Sprite");
// Deprecated
obj.AddExpression("Direction",
_("Direction"),
_("Direction of the object"),
@@ -559,6 +608,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
// interface.
.AddParameter("object", _("Object"), "Sprite");
// Deprecated
obj.AddExpression("Anim",
_("Animation"),
_("Animation of the object"),
@@ -567,18 +617,22 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.SetHidden()
.AddParameter("object", _("Object"), "Sprite");
// Deprecated
obj.AddExpression("Animation",
_("Animation"),
_("Animation of the object"),
_("Animations and images"),
"res/actions/animation.png")
.SetHidden()
.AddParameter("object", _("Object"), "Sprite");
// Deprecated
obj.AddStrExpression("AnimationName",
_("Animation name"),
_("Name of the animation of the object"),
_("Animations and images"),
"res/actions/animation.png")
.SetHidden()
.AddParameter("object", _("Object"), "Sprite");
obj.AddExpression("Sprite",
@@ -595,11 +649,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"res/actions/sprite.png")
.AddParameter("object", _("Object"), "Sprite");
// Deprecated
obj.AddExpression("AnimationSpeedScale",
_("Animation speed scale"),
_("Animation speed scale"),
_("Animations and images"),
"res/actions/animation.png")
.SetHidden()
.AddParameter("object", _("Object"), "Sprite");
obj.AddExpression("ScaleX",
@@ -607,6 +663,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Scale of the width of an object"),
_("Size"),
"res/actions/scaleWidth_black.png")
.SetHidden()
.AddParameter("object", _("Object"), "Sprite");
obj.AddExpression("ScaleY",
@@ -614,14 +671,17 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Scale of the height of an object"),
_("Size"),
"res/actions/scaleHeight_black.png")
.SetHidden()
.AddParameter("object", _("Object"), "Sprite");
// Deprecated
obj.AddExpression("Opacity",
_("Opacity"),
_("Opacity"),
_("Opacity"),
"res/actions/opacity.png")
.AddParameter("object", _("Object"), "Sprite");
.AddParameter("object", _("Object"), "Sprite")
.SetHidden();
extension
.AddCondition("Collision",

View File

@@ -25,13 +25,16 @@ namespace gd {
Animation SpriteObject::badAnimation;
SpriteObject::SpriteObject() : updateIfNotVisible(false) {}
SpriteObject::SpriteObject()
: updateIfNotVisible(false), adaptCollisionMaskAutomatically(true) {}
SpriteObject::~SpriteObject(){};
void SpriteObject::DoUnserializeFrom(gd::Project& project,
const gd::SerializerElement& element) {
updateIfNotVisible = element.GetBoolAttribute("updateIfNotVisible", true);
adaptCollisionMaskAutomatically =
element.GetBoolAttribute("adaptCollisionMaskAutomatically", false);
RemoveAllAnimations();
const gd::SerializerElement& animationsElement =
@@ -80,6 +83,8 @@ void SpriteObject::DoUnserializeFrom(gd::Project& project,
void SpriteObject::DoSerializeTo(gd::SerializerElement& element) const {
element.SetAttribute("updateIfNotVisible", updateIfNotVisible);
element.SetAttribute("adaptCollisionMaskAutomatically",
adaptCollisionMaskAutomatically);
// Animations
gd::SerializerElement& animationsElement = element.AddChild("animations");

View File

@@ -47,8 +47,7 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
void ExposeResources(gd::ArbitraryResourceWorker& worker) override;
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
bool UpdateProperty(const gd::String& name,
const gd::String& value) override;
bool UpdateProperty(const gd::String& name, const gd::String& value) override;
std::map<gd::String, gd::PropertyDescriptor> GetInitialInstanceProperties(
const gd::InitialInstance& position,
@@ -118,14 +117,30 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
const std::vector<Animation>& GetAllAnimations() const { return animations; }
/**
* \brief Set if the object animation should be played even if the object is hidden
* or far from the camera.
* @brief Check if the collision mask adapts automatically to the animation.
*/
void SetUpdateIfNotVisible(bool updateIfNotVisible_) { updateIfNotVisible = updateIfNotVisible_; }
bool AdaptCollisionMaskAutomatically() const {
return adaptCollisionMaskAutomatically;
}
/**
* \brief Check if the object animation should be played even if the object is hidden
* or far from the camera (false by default).
* @brief Set if the collision mask adapts automatically to the animation.
*/
void SetAdaptCollisionMaskAutomatically(bool enable) {
adaptCollisionMaskAutomatically = enable;
}
/**
* \brief Set if the object animation should be played even if the object is
* hidden or far from the camera.
*/
void SetUpdateIfNotVisible(bool updateIfNotVisible_) {
updateIfNotVisible = updateIfNotVisible_;
}
/**
* \brief Check if the object animation should be played even if the object
* is hidden or far from the camera (false by default).
*/
bool GetUpdateIfNotVisible() const { return updateIfNotVisible; }
///@}
@@ -137,11 +152,15 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
mutable std::vector<Animation> animations;
bool updateIfNotVisible; ///< If set to true, ask the game engine to play
///< object animation even if hidden or far from the
///< screen.
///< object animation even if hidden or far from
///< the screen.
static Animation badAnimation; //< Bad animation when an out of bound
// animation is requested.
static Animation badAnimation; //< Bad animation when an out of bound
// animation is requested.
bool adaptCollisionMaskAutomatically; ///< If set to true, the collision
///< mask will be automatically
///< adapted to the animation of the
///< object.
};
} // namespace gd

View File

@@ -0,0 +1,135 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <algorithm>
#include <functional>
#include <map>
#include <memory>
#include "GDCore/Events/Instruction.h"
#include "GDCore/String.h"
#include "ParameterMetadata.h"
#include "ParameterOptions.h"
namespace gd {
class Project;
class Layout;
class EventsCodeGenerator;
class EventsCodeGenerationContext;
class SerializerElement;
} // namespace gd
namespace gd {
/**
* \brief Describe user-friendly information about an expression or an
* instruction (action or condition), its parameters and the function name as
* well as other information for code generation.
*
* \ingroup Events
*/
class GD_CORE_API AbstractFunctionMetadata {
public:
AbstractFunctionMetadata(){};
virtual ~AbstractFunctionMetadata(){};
/**
* \see gd::InstructionMetadata::AddParameter
*/
virtual AbstractFunctionMetadata &
AddParameter(const gd::String &type, const gd::String &label,
const gd::String &supplementaryInformation = "",
bool parameterIsOptional = false) = 0;
/**
* \see gd::InstructionMetadata::AddCodeOnlyParameter
*/
virtual AbstractFunctionMetadata &
AddCodeOnlyParameter(const gd::String &type,
const gd::String &supplementaryInformation) = 0;
/**
* \see gd::InstructionMetadata::SetDefaultValue
*/
virtual AbstractFunctionMetadata &
SetDefaultValue(const gd::String &defaultValue) = 0;
/**
* \see gd::InstructionMetadata::SetParameterExtraInfo
*/
virtual AbstractFunctionMetadata &
SetParameterExtraInfo(const gd::String &defaultValue) = 0;
/**
* \see gd::InstructionMetadata::SetParameterLongDescription
*/
virtual AbstractFunctionMetadata &
SetParameterLongDescription(const gd::String &longDescription) = 0;
/**
* \see gd::InstructionMetadata::SetHidden
*/
virtual AbstractFunctionMetadata &SetHidden() = 0;
/**
* Set that the instruction is private - it can't be used outside of the
* object/ behavior that it is attached too.
*/
virtual AbstractFunctionMetadata &SetPrivate() = 0;
/**
* Set that the instruction can be used in layouts or external events.
*/
virtual AbstractFunctionMetadata &SetRelevantForLayoutEventsOnly() = 0;
/**
* Set that the instruction can be used in function events.
*/
virtual AbstractFunctionMetadata &SetRelevantForFunctionEventsOnly() = 0;
/**
* Set that the instruction can be used in asynchronous function events.
*/
virtual AbstractFunctionMetadata &
SetRelevantForAsynchronousFunctionEventsOnly() = 0;
/**
* Set that the instruction can be used in custom object events.
*/
virtual AbstractFunctionMetadata &SetRelevantForCustomObjectEventsOnly() = 0;
/**
* \brief Set the function that should be called when generating the source
* code from events.
* \param functionName the name of the function to call
* \note Shortcut for `codeExtraInformation.SetFunctionName`.
*/
virtual AbstractFunctionMetadata &
SetFunctionName(const gd::String &functionName) = 0;
/**
* \brief Erase any existing include file and add the specified include.
*/
virtual AbstractFunctionMetadata &
SetIncludeFile(const gd::String &includeFile) = 0;
/**
* \brief Add a file to the already existing include files.
*/
virtual AbstractFunctionMetadata &
AddIncludeFile(const gd::String &includeFile) = 0;
/**
* \brief Get the files that must be included to use the instruction.
*/
virtual const std::vector<gd::String> &GetIncludeFiles() const = 0;
private:
};
} // namespace gd

View File

@@ -34,8 +34,7 @@ BehaviorMetadata::BehaviorMetadata(
className(className_),
iconFilename(icon24x24),
instance(instance_),
sharedDatasInstance(sharedDatasInstance_),
isEventBased(false) {
sharedDatasInstance(sharedDatasInstance_) {
SetFullName(gd::String(fullname_));
SetDescription(gd::String(description_));
SetDefaultName(gd::String(defaultName_));
@@ -52,29 +51,6 @@ BehaviorMetadata::BehaviorMetadata(
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,
@@ -420,10 +396,6 @@ const gd::String& BehaviorMetadata::GetName() const {
}
gd::Behavior& BehaviorMetadata::Get() const {
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 "
@@ -434,11 +406,20 @@ gd::Behavior& BehaviorMetadata::Get() const {
}
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();
}
const std::vector<gd::String>& BehaviorMetadata::GetRequiredBehaviorTypes() const {
requiredBehaviors.clear();
for (auto& property : Get().GetProperties()) {
const String& propertyName = property.first;
const gd::PropertyDescriptor& propertyDescriptor = property.second;
if (propertyDescriptor.GetType() == "Behavior") {
requiredBehaviors.push_back(propertyDescriptor.GetExtraInfo()[0]);
}
}
return requiredBehaviors;
}
} // namespace gd

View File

@@ -3,8 +3,10 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef BEHAVIORMETADATA_H
#define BEHAVIORMETADATA_H
#pragma once
#include "InstructionOrExpressionContainerMetadata.h"
#include <map>
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
@@ -25,7 +27,7 @@ namespace gd {
*
* \ingroup Events
*/
class GD_CORE_API BehaviorMetadata {
class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMetadata {
public:
BehaviorMetadata(
const gd::String& extensionNamespace,
@@ -67,7 +69,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* Declare a new action as being part of the behavior.
@@ -80,7 +82,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* Declare a new condition as being part of the behavior.
@@ -91,7 +93,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* Declare a new action as being part of the behavior.
@@ -102,7 +104,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* Declare a new action as being part of the extension.
*/
@@ -110,7 +112,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& fullname_,
const gd::String& description_,
const gd::String& group_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* Declare a new string expression as being part of the extension.
@@ -119,7 +121,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& fullname_,
const gd::String& description_,
const gd::String& group_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* \brief Declare a new expression and condition as being part of the
@@ -134,7 +136,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& description,
const gd::String& sentenceName,
const gd::String& group,
const gd::String& icon);
const gd::String& icon) override;
/**
* \brief Declare a new expression, condition and action as being part of the
@@ -151,7 +153,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& description,
const gd::String& sentenceName,
const gd::String& group,
const gd::String& icon);
const gd::String& icon) override;
/**
* \brief Create a new action which is the duplicate of the specified one.
@@ -160,7 +162,7 @@ class GD_CORE_API BehaviorMetadata {
* one.
*/
gd::InstructionMetadata& AddDuplicatedAction(
const gd::String& newActionName, const gd::String& copiedActionName);
const gd::String& newActionName, const gd::String& copiedActionName) override;
/**
* \brief Create a new condition which is the duplicate of the specified one.
@@ -170,7 +172,7 @@ class GD_CORE_API BehaviorMetadata {
*/
gd::InstructionMetadata& AddDuplicatedCondition(
const gd::String& newConditionName,
const gd::String& copiedConditionName);
const gd::String& copiedConditionName) override;
/**
* \brief Create a new expression which is the duplicate of the specified one.
@@ -193,9 +195,9 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& newExpressionName,
const gd::String& copiedExpressionName);
BehaviorMetadata& SetFullName(const gd::String& fullname_);
BehaviorMetadata& SetFullName(const gd::String& fullname_) override;
BehaviorMetadata& SetDefaultName(const gd::String& defaultName_);
BehaviorMetadata& SetDescription(const gd::String& description_);
BehaviorMetadata& SetDescription(const gd::String& description_) override;
BehaviorMetadata& SetGroup(const gd::String& group_);
/**
@@ -203,12 +205,12 @@ class GD_CORE_API BehaviorMetadata {
* \note The requirement may vary depending on the platform: Most of the time,
* the include file contains the declaration of the behavior.
*/
BehaviorMetadata& SetIncludeFile(const gd::String& includeFile);
BehaviorMetadata& SetIncludeFile(const gd::String& includeFile) override;
/**
* \brief Add a file to the already existing include files.
*/
BehaviorMetadata& AddIncludeFile(const gd::String& includeFile);
BehaviorMetadata& AddIncludeFile(const gd::String& includeFile) override;
/**
* \brief Add a file to the already existing required files.
@@ -221,7 +223,7 @@ class GD_CORE_API BehaviorMetadata {
* Get the help path of the behavior, relative to the GDevelop documentation
* root.
*/
const gd::String& GetHelpPath() const { return helpPath; }
const gd::String& GetHelpPath() const override { return helpPath; }
/**
* Set the help path of the behavior, relative to the GDevelop documentation
@@ -230,17 +232,17 @@ class GD_CORE_API BehaviorMetadata {
* The behavior instructions will have this help path set by
* default, unless you call SetHelpPath on them.
*/
BehaviorMetadata& SetHelpPath(const gd::String& path) {
BehaviorMetadata& SetHelpPath(const gd::String& path) override {
helpPath = path;
return *this;
}
const gd::String& GetName() const;
const gd::String& GetFullName() const { return fullname; }
const gd::String& GetName() const override;
const gd::String& GetFullName() const override { return fullname; }
const gd::String& GetDefaultName() const { return defaultName; }
const gd::String& GetDescription() const { return description; }
const gd::String& GetDescription() const override { return description; }
const gd::String& GetGroup() const { return group; }
const gd::String& GetIconFilename() const { return iconFilename; }
const gd::String& GetIconFilename() const override { return iconFilename; }
/**
* \brief Set the type of the object that this behavior can be used on.
@@ -257,6 +259,11 @@ class GD_CORE_API BehaviorMetadata {
*/
const gd::String& GetObjectType() const { return objectType; }
/**
* \brief Get the types of the behaviors that are required by this behavior.
*/
const std::vector<gd::String>& GetRequiredBehaviorTypes() const;
/**
* Check if the behavior is private - it can't be used outside of its
* extension.
@@ -272,6 +279,21 @@ class GD_CORE_API BehaviorMetadata {
return *this;
}
/**
* Check if the behavior is hidden - it can be used but not attached to
* objects by users.
*/
bool IsHidden() const { return isHidden; }
/**
* Set that the behavior is hidden - it can be used but not attached to
* objects by users.
*/
BehaviorMetadata &SetHidden() {
isHidden = true;
return *this;
}
/**
* \brief Return the associated gd::Behavior, handling behavior contents.
*
@@ -293,22 +315,22 @@ class GD_CORE_API BehaviorMetadata {
* \brief Return a reference to a map containing the names of the actions
* (as keys) and the metadata associated with (as values).
*/
std::map<gd::String, gd::InstructionMetadata>& GetAllActions() { return actionsInfos; };
std::map<gd::String, gd::InstructionMetadata>& GetAllActions() override { return actionsInfos; };
/**
* \see gd::PlatformExtension::GetAllActions
*/
std::map<gd::String, gd::InstructionMetadata>& GetAllConditions() { return conditionsInfos; };
std::map<gd::String, gd::InstructionMetadata>& GetAllConditions() override { return conditionsInfos; };
/**
* \see gd::PlatformExtension::GetAllActions
*/
std::map<gd::String, gd::ExpressionMetadata>& GetAllExpressions() { return expressionsInfos; };
std::map<gd::String, gd::ExpressionMetadata>& GetAllExpressions() override { return expressionsInfos; };
/**
* \see gd::PlatformExtension::GetAllActions
*/
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressions() { return strExpressionsInfos; };
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressions() override { return strExpressionsInfos; };
std::map<gd::String, gd::InstructionMetadata> conditionsInfos;
std::map<gd::String, gd::InstructionMetadata> actionsInfos;
@@ -328,14 +350,13 @@ class GD_CORE_API BehaviorMetadata {
gd::String group;
gd::String iconFilename;
gd::String objectType;
mutable std::vector<gd::String> requiredBehaviors;
bool isPrivate = false;
bool isHidden = false;
// 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
#endif // BEHAVIORMETADATA_H

View File

@@ -3,9 +3,10 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef EXPRESSIONMETADATA_H
#define EXPRESSIONMETADATA_H
#if defined(GD_IDE_ONLY)
#pragma once
#include "AbstractFunctionMetadata.h"
#include <functional>
#include <memory>
@@ -17,7 +18,6 @@ class Layout;
}
namespace gd {
/**
* \brief Information about how generate code for an expression
*/
@@ -27,79 +27,7 @@ class ExpressionCodeGenerationInformation {
: staticFunction(false), hasCustomCodeGenerator(false){};
virtual ~ExpressionCodeGenerationInformation(){};
/**
* \brief Set the function name which will be used when generating the code.
* \param functionName the name of the function to call
*/
ExpressionCodeGenerationInformation& SetFunctionName(
const gd::String& functionName) {
functionCallName = functionName;
return *this;
}
/**
* \brief Set that the function is static
*/
ExpressionCodeGenerationInformation& SetStatic() {
staticFunction = true;
return *this;
}
/**
* \brief Erase any existing include file and add the specified include.
*/
ExpressionCodeGenerationInformation& SetIncludeFile(
const gd::String& includeFile) {
includeFiles.clear();
includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Add a file to the already existing include files.
*/
ExpressionCodeGenerationInformation& AddIncludeFile(
const gd::String& includeFile) {
if (std::find(includeFiles.begin(), includeFiles.end(), includeFile) ==
includeFiles.end())
includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Get the files that must be included to use the instruction.
*/
const std::vector<gd::String>& GetIncludeFiles() const {
return includeFiles;
};
/**
* \brief Set that the function must be generated using a custom code
* generator.
*/
ExpressionCodeGenerationInformation& SetCustomCodeGenerator(
std::function<gd::String(const std::vector<gd::Expression>& parameters,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context)>
codeGenerator) {
hasCustomCodeGenerator = true;
customCodeGenerator = codeGenerator;
return *this;
}
ExpressionCodeGenerationInformation& RemoveCustomCodeGenerator() {
hasCustomCodeGenerator = false;
std::function<gd::String(const std::vector<gd::Expression>& parameters,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context)>
emptyFunction;
customCodeGenerator = emptyFunction;
return *this;
}
bool HasCustomCodeGenerator() const { return hasCustomCodeGenerator; }
// TODO Move these attributes to ExpressionMetadata.
bool staticFunction;
gd::String functionCallName;
bool hasCustomCodeGenerator;
@@ -107,8 +35,6 @@ class ExpressionCodeGenerationInformation {
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context)>
customCodeGenerator;
private:
std::vector<gd::String> includeFiles;
};
@@ -118,7 +44,7 @@ class ExpressionCodeGenerationInformation {
*
* \ingroup Events
*/
class GD_CORE_API ExpressionMetadata {
class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
public:
/**
* Construct a new expression metadata.
@@ -144,7 +70,7 @@ class GD_CORE_API ExpressionMetadata {
/**
* \brief Set the expression as not shown in the IDE.
*/
ExpressionMetadata& SetHidden();
ExpressionMetadata& SetHidden() override;
/**
* \brief Set the group of the instruction in the IDE.
@@ -179,7 +105,7 @@ class GD_CORE_API ExpressionMetadata {
* Set that the instruction is private - it can't be used outside of the
* object/ behavior that it is attached too.
*/
ExpressionMetadata& SetPrivate() {
ExpressionMetadata& SetPrivate() override {
isPrivate = true;
return *this;
}
@@ -216,7 +142,7 @@ class GD_CORE_API ExpressionMetadata {
/**
* Set that the instruction can be used in layouts or external events.
*/
ExpressionMetadata &SetRelevantForLayoutEventsOnly() {
ExpressionMetadata &SetRelevantForLayoutEventsOnly() override {
relevantContext = "Layout";
return *this;
}
@@ -224,7 +150,7 @@ class GD_CORE_API ExpressionMetadata {
/**
* Set that the instruction can be used in function events.
*/
ExpressionMetadata &SetRelevantForFunctionEventsOnly() {
ExpressionMetadata &SetRelevantForFunctionEventsOnly() override {
relevantContext = "Function";
return *this;
}
@@ -232,7 +158,7 @@ class GD_CORE_API ExpressionMetadata {
/**
* Set that the instruction can be used in asynchronous function events.
*/
ExpressionMetadata &SetRelevantForAsynchronousFunctionEventsOnly() {
ExpressionMetadata &SetRelevantForAsynchronousFunctionEventsOnly() override {
relevantContext = "AsynchronousFunction";
return *this;
}
@@ -240,7 +166,7 @@ class GD_CORE_API ExpressionMetadata {
/**
* Set that the instruction can be used in custom object events.
*/
ExpressionMetadata &SetRelevantForCustomObjectEventsOnly() {
ExpressionMetadata &SetRelevantForCustomObjectEventsOnly() override {
relevantContext = "Object";
return *this;
}
@@ -248,17 +174,17 @@ class GD_CORE_API ExpressionMetadata {
/**
* \see gd::InstructionMetadata::AddParameter
*/
gd::ExpressionMetadata& AddParameter(
const gd::String& type,
const gd::String& description,
const gd::String& supplementaryInformation = "",
bool parameterIsOptional = false);
gd::ExpressionMetadata &
AddParameter(const gd::String &type, const gd::String &label,
const gd::String &supplementaryInformation = "",
bool parameterIsOptional = false) override;
/**
* \see gd::InstructionMetadata::AddCodeOnlyParameter
*/
gd::ExpressionMetadata& AddCodeOnlyParameter(
const gd::String& type, const gd::String& supplementaryInformation);
gd::ExpressionMetadata &
AddCodeOnlyParameter(const gd::String &type,
const gd::String &supplementaryInformation) override;
/**
* Set the default value used in editor (or if an optional parameter is empty
@@ -266,8 +192,9 @@ class GD_CORE_API ExpressionMetadata {
*
* \see AddParameter
*/
ExpressionMetadata& SetDefaultValue(gd::String defaultValue_) {
if (!parameters.empty()) parameters.back().SetDefaultValue(defaultValue_);
ExpressionMetadata &SetDefaultValue(const gd::String &defaultValue) override {
if (!parameters.empty())
parameters.back().SetDefaultValue(defaultValue);
return *this;
};
@@ -277,7 +204,8 @@ class GD_CORE_API ExpressionMetadata {
*
* \see AddParameter
*/
ExpressionMetadata& SetParameterLongDescription(gd::String longDescription) {
ExpressionMetadata &
SetParameterLongDescription(const gd::String &longDescription) override {
if (!parameters.empty())
parameters.back().SetLongDescription(longDescription);
return *this;
@@ -290,7 +218,8 @@ class GD_CORE_API ExpressionMetadata {
*
* \see AddParameter
*/
ExpressionMetadata &SetParameterExtraInfo(const gd::String &extraInfo) {
ExpressionMetadata &SetParameterExtraInfo(
const gd::String &extraInfo) override {
if (!parameters.empty()) parameters.back().SetExtraInfo(extraInfo);
return *this;
}
@@ -312,50 +241,6 @@ class GD_CORE_API ExpressionMetadata {
return requiredBaseObjectCapability;
};
/**
* \brief Set the function that should be called when generating the source
* code from events.
* \param functionName the name of the function to call
* \note Shortcut for `codeExtraInformation.SetFunctionName`.
*/
ExpressionCodeGenerationInformation& SetFunctionName(
const gd::String& functionName) {
return codeExtraInformation.SetFunctionName(functionName);
}
/**
* \brief Return the structure containing the information about code
* generation for the expression.
*/
ExpressionCodeGenerationInformation& GetCodeExtraInformation() {
return codeExtraInformation;
}
/**
* \brief Erase any existing include file and add the specified include.
*/
ExpressionMetadata &SetIncludeFile(const gd::String &includeFile) {
codeExtraInformation.SetIncludeFile(includeFile);
return *this;
}
/**
* \brief Add a file to the already existing include files.
*/
ExpressionMetadata &AddIncludeFile(const gd::String &includeFile) {
codeExtraInformation.AddIncludeFile(includeFile);
return *this;
}
/**
* \brief Get the files that must be included to use the instruction.
*/
const std::vector<gd::String>& GetIncludeFiles() const {
return codeExtraInformation.GetIncludeFiles();
}
ExpressionCodeGenerationInformation codeExtraInformation;
bool IsShown() const { return shown; }
const gd::String& GetReturnType() const { return returnType; }
const gd::String& GetFullName() const { return fullname; }
@@ -375,6 +260,99 @@ class GD_CORE_API ExpressionMetadata {
std::vector<gd::ParameterMetadata> parameters;
/**
* \brief Set the function name which will be used when generating the code.
* \param functionName the name of the function to call
*/
ExpressionMetadata& SetFunctionName(
const gd::String& functionName) override {
codeExtraInformation.functionCallName = functionName;
return *this;
}
/**
* \brief Return the name of the function which will be called in the generated code.
*/
const gd::String &GetFunctionName() {
return codeExtraInformation.functionCallName;
}
/**
* \brief Set that the function is static
*/
ExpressionMetadata& SetStatic() {
codeExtraInformation.staticFunction = true;
return *this;
}
/**
* \brief Erase any existing include file and add the specified include.
*/
ExpressionMetadata& SetIncludeFile(
const gd::String& includeFile) override {
codeExtraInformation.includeFiles.clear();
codeExtraInformation.includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Add a file to the already existing include files.
*/
ExpressionMetadata& AddIncludeFile(
const gd::String& includeFile) override {
if (std::find(codeExtraInformation.includeFiles.begin(), codeExtraInformation.includeFiles.end(), includeFile) ==
codeExtraInformation.includeFiles.end())
codeExtraInformation.includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Get the files that must be included to use the instruction.
*/
const std::vector<gd::String>& GetIncludeFiles() const override {
return codeExtraInformation.includeFiles;
};
/**
* \brief Set that the function must be generated using a custom code
* generator.
*/
ExpressionMetadata& SetCustomCodeGenerator(
std::function<gd::String(const std::vector<gd::Expression>& parameters,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context)>
codeGenerator) {
codeExtraInformation.hasCustomCodeGenerator = true;
codeExtraInformation.customCodeGenerator = codeGenerator;
return *this;
}
ExpressionMetadata& RemoveCustomCodeGenerator() {
codeExtraInformation.hasCustomCodeGenerator = false;
std::function<gd::String(const std::vector<gd::Expression>& parameters,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context)>
emptyFunction;
codeExtraInformation.customCodeGenerator = emptyFunction;
return *this;
}
bool HasCustomCodeGenerator() const { return codeExtraInformation.hasCustomCodeGenerator; }
/**
* \brief Return the structure containing the information about code
* generation for the expression.
*
* \deprecated
*/
ExpressionMetadata& GetCodeExtraInformation() {
return *this;
}
ExpressionCodeGenerationInformation codeExtraInformation;
private:
gd::String returnType;
gd::String fullname;
@@ -391,6 +369,3 @@ class GD_CORE_API ExpressionMetadata {
};
} // namespace gd
#endif
#endif // EXPRESSIONMETADATA_H

View File

@@ -4,8 +4,10 @@
* reserved. This project is released under the MIT License.
*/
#ifndef INSTRUCTIONMETADATA_H
#define INSTRUCTIONMETADATA_H
#pragma once
#include "AbstractFunctionMetadata.h"
#include <algorithm>
#include <functional>
#include <map>
@@ -33,7 +35,7 @@ namespace gd {
*
* \ingroup Events
*/
class GD_CORE_API InstructionMetadata {
class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
public:
/**
* Construct a new instruction metadata.
@@ -96,7 +98,7 @@ class GD_CORE_API InstructionMetadata {
* Set that the instruction is private - it can't be used outside of the
* object/ behavior that it is attached too.
*/
InstructionMetadata &SetPrivate() {
InstructionMetadata &SetPrivate() override {
isPrivate = true;
return *this;
}
@@ -133,7 +135,7 @@ class GD_CORE_API InstructionMetadata {
/**
* Set that the instruction can be used in layouts or external events.
*/
InstructionMetadata &SetRelevantForLayoutEventsOnly() {
InstructionMetadata &SetRelevantForLayoutEventsOnly() override {
relevantContext = "Layout";
return *this;
}
@@ -141,7 +143,7 @@ class GD_CORE_API InstructionMetadata {
/**
* Set that the instruction can be used in function events.
*/
InstructionMetadata &SetRelevantForFunctionEventsOnly() {
InstructionMetadata &SetRelevantForFunctionEventsOnly() override {
relevantContext = "Function";
return *this;
}
@@ -149,7 +151,7 @@ class GD_CORE_API InstructionMetadata {
/**
* Set that the instruction can be used in asynchronous function events.
*/
InstructionMetadata &SetRelevantForAsynchronousFunctionEventsOnly() {
InstructionMetadata &SetRelevantForAsynchronousFunctionEventsOnly() override {
relevantContext = "AsynchronousFunction";
return *this;
}
@@ -157,7 +159,7 @@ class GD_CORE_API InstructionMetadata {
/**
* Set that the instruction can be used in custom object events.
*/
InstructionMetadata &SetRelevantForCustomObjectEventsOnly() {
InstructionMetadata &SetRelevantForCustomObjectEventsOnly() override {
relevantContext = "Object";
return *this;
}
@@ -192,7 +194,7 @@ class GD_CORE_API InstructionMetadata {
*
* Used mainly when an instruction is deprecated.
*/
InstructionMetadata &SetHidden() {
InstructionMetadata &SetHidden() override {
hidden = true;
return *this;
}
@@ -231,7 +233,7 @@ class GD_CORE_API InstructionMetadata {
const gd::String &type,
const gd::String &label,
const gd::String &supplementaryInformation = "",
bool parameterIsOptional = false);
bool parameterIsOptional = false) override;
/**
* \brief Add a parameter not displayed in editor.
@@ -245,7 +247,7 @@ class GD_CORE_API InstructionMetadata {
* \see EventsCodeGenerator::GenerateParametersCodes
*/
InstructionMetadata &AddCodeOnlyParameter(
const gd::String &type, const gd::String &supplementaryInformation);
const gd::String &type, const gd::String &supplementaryInformation) override;
/**
* \brief Set the default value used in editor (or if an optional parameter is
@@ -253,7 +255,7 @@ class GD_CORE_API InstructionMetadata {
*
* \see AddParameter
*/
InstructionMetadata &SetDefaultValue(const gd::String &defaultValue_) {
InstructionMetadata &SetDefaultValue(const gd::String &defaultValue_) override {
if (!parameters.empty()) parameters.back().SetDefaultValue(defaultValue_);
return *this;
};
@@ -265,7 +267,7 @@ class GD_CORE_API InstructionMetadata {
* \see AddParameter
*/
InstructionMetadata &SetParameterLongDescription(
const gd::String &longDescription) {
const gd::String &longDescription) override {
if (!parameters.empty())
parameters.back().SetLongDescription(longDescription);
return *this;
@@ -278,7 +280,7 @@ class GD_CORE_API InstructionMetadata {
*
* \see AddParameter
*/
InstructionMetadata &SetParameterExtraInfo(const gd::String &extraInfo) {
InstructionMetadata &SetParameterExtraInfo(const gd::String &extraInfo) override {
if (!parameters.empty()) parameters.back().SetExtraInfo(extraInfo);
return *this;
}
@@ -382,128 +384,13 @@ class GD_CORE_API InstructionMetadata {
/**
* \brief Defines information about how generate the code for an instruction
*/
class ExtraInformation {
class ExtraInformation {
public:
enum AccessType { Reference, MutatorAndOrAccessor, Mutators };
ExtraInformation() : accessType(Reference), hasCustomCodeGenerator(false){};
virtual ~ExtraInformation(){};
/**
* Set the name of the function which will be called in the generated code.
* \param functionName the name of the function to call.
*/
ExtraInformation &SetFunctionName(const gd::String &functionName_) {
functionCallName = functionName_;
return *this;
}
/**
* Set the name of the function, doing asynchronous work, which will be
* called in the generated code. This function should return an asynchronous
* task (i.e: `gdjs.AsyncTask` in the JavaScript runtime).
*
* \param functionName the name of the function doing asynchronous work to
* call.
*/
ExtraInformation &SetAsyncFunctionName(const gd::String &functionName_) {
asyncFunctionCallName = functionName_;
return *this;
}
/**
* Declare if the instruction being declared is somewhat manipulating in a
* standard way.
*/
ExtraInformation &SetManipulatedType(const gd::String &type_) {
type = type_;
return *this;
}
/**
* If InstructionMetadata::ExtraInformation::SetManipulatedType was called
* with "number" or "string", this function will tell the code generator the
* name of the getter function used to retrieve the data value.
*
* Usage example:
* \code
* obj.AddAction("String",
* _("Change the string"),
* _("Change the string of a text"),
* _("the string"),
* _("Text"),
* "CppPlatform/Extensions/text24.png",
* "CppPlatform/Extensions/text_black.png");
*
* .AddParameter("object", _("Object"), "Text", false)
* .AddParameter("operator", _("Modification operator"), "string")
* .AddParameter("string", _("String"))
* .SetFunctionName("SetString").SetManipulatedType("string").SetGetter("GetString");
*
* DECLARE_END_OBJECT_ACTION()
* \endcode
*/
ExtraInformation &SetGetter(const gd::String &getter) {
optionalAssociatedInstruction = getter;
accessType = MutatorAndOrAccessor;
return *this;
}
ExtraInformation &SetMutators(
const std::map<gd::String, gd::String> &mutators) {
optionalMutators = mutators;
accessType = Mutators;
return *this;
}
/**
* \brief Erase any existing include file and add the specified include.
*/
ExtraInformation &SetIncludeFile(const gd::String &includeFile) {
includeFiles.clear();
includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Add a file to the already existing include files.
*/
ExtraInformation &AddIncludeFile(const gd::String &includeFile) {
if (std::find(includeFiles.begin(), includeFiles.end(), includeFile) ==
includeFiles.end())
includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Get the files that must be included to use the instruction.
*/
const std::vector<gd::String> &GetIncludeFiles() const {
return includeFiles;
};
ExtraInformation &SetCustomCodeGenerator(
std::function<gd::String(Instruction &instruction,
gd::EventsCodeGenerator &codeGenerator,
gd::EventsCodeGenerationContext &context)>
codeGenerator) {
hasCustomCodeGenerator = true;
customCodeGenerator = codeGenerator;
return *this;
}
ExtraInformation &RemoveCustomCodeGenerator() {
hasCustomCodeGenerator = false;
std::function<gd::String(Instruction & instruction,
gd::EventsCodeGenerator & codeGenerator,
gd::EventsCodeGenerationContext & context)>
emptyFunction;
customCodeGenerator = emptyFunction;
return *this;
}
bool HasCustomCodeGenerator() const { return hasCustomCodeGenerator; }
// TODO Move these attributes to InstructionMetadata.
gd::String functionCallName;
gd::String asyncFunctionCallName;
gd::String type;
@@ -512,75 +399,156 @@ class GD_CORE_API InstructionMetadata {
std::map<gd::String, gd::String> optionalMutators;
bool hasCustomCodeGenerator;
std::function<gd::String(Instruction &instruction,
gd::EventsCodeGenerator &codeGenerator,
gd::EventsCodeGenerationContext &context)>
gd::EventsCodeGenerator &codeGenerator,
gd::EventsCodeGenerationContext &context)>
customCodeGenerator;
private:
std::vector<gd::String> includeFiles;
};
ExtraInformation codeExtraInformation; ///< Information about how generate
///< code for the instruction
/**
* \brief Return the structure containing the information about code
* generation for the instruction.
*/
ExtraInformation &GetCodeExtraInformation() { return codeExtraInformation; }
/**
* \brief Declare if the instruction being declared is somewhat manipulating
* in a standard way. \param type "number" or "string" \note Shortcut for
* `codeExtraInformation.SetManipulatedType(type)`.
*/
ExtraInformation &SetManipulatedType(const gd::String &type_) {
return codeExtraInformation.SetManipulatedType(type_);
}
/**
* Set the name of the function which will be called in the generated code.
* \param functionName the name of the function to call.
* \note Shortcut for `codeExtraInformation.SetFunctionName`.
*/
ExtraInformation &SetFunctionName(const gd::String &functionName) {
return codeExtraInformation.SetFunctionName(functionName);
InstructionMetadata &SetFunctionName(const gd::String &functionName_) override {
codeExtraInformation.functionCallName = functionName_;
return *this;
}
/**
* Set the name of the function, doing asynchronous work, which will be called
* in the generated code. This function should return an asynchronous task
* (i.e: `gdjs.AsyncTask` in the JavaScript runtime).
* Set the name of the function, doing asynchronous work, which will be
* called in the generated code. This function should return an asynchronous
* task (i.e: `gdjs.AsyncTask` in the JavaScript runtime).
*
* \param functionName the name of the function doing asynchronous work to
* call. \note Shortcut for `codeExtraInformation.SetAsyncFunctionName`.
* call.
*/
ExtraInformation &SetAsyncFunctionName(const gd::String &functionName) {
return codeExtraInformation.SetAsyncFunctionName(functionName);
InstructionMetadata &SetAsyncFunctionName(const gd::String &functionName_) {
codeExtraInformation.asyncFunctionCallName = functionName_;
return *this;
}
/**
* Return the name of the function which will be called in the generated code.
*/
const gd::String &GetFunctionName() {
return codeExtraInformation.functionCallName;
}
/**
* Return the name of the function, doing asynchronous work, which will be
* called in the generated code. This function should return an asynchronous
* task (i.e: `gdjs.AsyncTask` in the JavaScript runtime).
*/
const gd::String &GetAsyncFunctionName() {
return codeExtraInformation.asyncFunctionCallName;
}
/**
* \brief Declare if the instruction being declared is somewhat manipulating
* in a standard way.
*
* \param type "number" or "string"
*/
InstructionMetadata &SetManipulatedType(const gd::String &type_) {
codeExtraInformation.type = type_;
return *this;
}
/**
* If InstructionMetadata::ExtraInformation::SetManipulatedType was called
* with "number" or "string", this function will tell the code generator the
* name of the getter function used to retrieve the data value.
*
* Usage example:
* \code
* obj.AddAction("String",
* _("Change the string"),
* _("Change the string of a text"),
* _("the string"),
* _("Text"),
* "CppPlatform/Extensions/text24.png",
* "CppPlatform/Extensions/text_black.png");
*
* .AddParameter("object", _("Object"), "Text", false)
* .AddParameter("operator", _("Modification operator"), "string")
* .AddParameter("string", _("String"))
* .SetFunctionName("SetString").SetManipulatedType("string").SetGetter("GetString");
*
* DECLARE_END_OBJECT_ACTION()
* \endcode
*/
InstructionMetadata &SetGetter(const gd::String &getter) {
codeExtraInformation.optionalAssociatedInstruction = getter;
codeExtraInformation.accessType = codeExtraInformation.MutatorAndOrAccessor;
return *this;
}
InstructionMetadata &SetMutators(
const std::map<gd::String, gd::String> &mutators) {
codeExtraInformation.optionalMutators = mutators;
codeExtraInformation.accessType = codeExtraInformation.Mutators;
return *this;
}
/**
* \brief Erase any existing include file and add the specified include.
*/
InstructionMetadata &SetIncludeFile(const gd::String &includeFile) {
codeExtraInformation.SetIncludeFile(includeFile);
InstructionMetadata &SetIncludeFile(const gd::String &includeFile) override {
codeExtraInformation.includeFiles.clear();
codeExtraInformation.includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Add a file to the already existing include files.
*/
InstructionMetadata &AddIncludeFile(const gd::String &includeFile) {
codeExtraInformation.AddIncludeFile(includeFile);
InstructionMetadata &AddIncludeFile(const gd::String &includeFile) override {
if (std::find(codeExtraInformation.includeFiles.begin(), codeExtraInformation.includeFiles.end(), includeFile) ==
codeExtraInformation.includeFiles.end())
codeExtraInformation.includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Get the files that must be included to use the instruction.
*/
const std::vector<gd::String> &GetIncludeFiles() const {
return codeExtraInformation.GetIncludeFiles();
const std::vector<gd::String> &GetIncludeFiles() const override {
return codeExtraInformation.includeFiles;
};
InstructionMetadata &SetCustomCodeGenerator(
std::function<gd::String(Instruction &instruction,
gd::EventsCodeGenerator &codeGenerator,
gd::EventsCodeGenerationContext &context)>
codeGenerator) {
codeExtraInformation.hasCustomCodeGenerator = true;
codeExtraInformation.customCodeGenerator = codeGenerator;
return *this;
}
InstructionMetadata &RemoveCustomCodeGenerator() {
codeExtraInformation.hasCustomCodeGenerator = false;
std::function<gd::String(Instruction & instruction,
gd::EventsCodeGenerator & codeGenerator,
gd::EventsCodeGenerationContext & context)>
emptyFunction;
codeExtraInformation.customCodeGenerator = emptyFunction;
return *this;
}
bool HasCustomCodeGenerator() const { return codeExtraInformation.hasCustomCodeGenerator; }
/**
* \brief Return the structure containing the information about code
* generation for the instruction.
*
* \deprecated
*/
InstructionMetadata &GetCodeExtraInformation() { return *this; }
std::vector<ParameterMetadata> parameters;
private:
@@ -604,5 +572,3 @@ class GD_CORE_API InstructionMetadata {
};
} // namespace gd
#endif // INSTRUCTIONMETADATA_H

View File

@@ -0,0 +1,201 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <map>
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/String.h"
namespace gd {
class Behavior;
class BehaviorsSharedData;
class MultipleInstructionMetadata;
class InstructionMetadata;
class ExpressionMetadata;
} // namespace gd
namespace gd {
/**
* \brief Contains user-friendly information about instructions and expressions
* (usually for a behavior or an object).
*
* \ingroup Events
*/
class GD_CORE_API InstructionOrExpressionContainerMetadata {
public:
InstructionOrExpressionContainerMetadata(){};
virtual ~InstructionOrExpressionContainerMetadata(){};
/**
* Declare a new condition as being part of the behavior or object.
* \deprecated Prefer using `AddScopedCondition`, to properly namespace
* the condition.
*/
virtual gd::InstructionMetadata &
AddCondition(const gd::String &name_, const gd::String &fullname_,
const gd::String &description_, const gd::String &sentence_,
const gd::String &group_, const gd::String &icon_,
const gd::String &smallicon_) = 0;
/**
* Declare a new action as being part of the behavior or object.
* \deprecated Prefer using `AddScopedAction`, to properly namespace
* the action.
*/
virtual gd::InstructionMetadata &
AddAction(const gd::String &name_, const gd::String &fullname_,
const gd::String &description_, const gd::String &sentence_,
const gd::String &group_, const gd::String &icon_,
const gd::String &smallicon_) = 0;
/**
* Declare a new condition as being part of the behavior or object.
*/
virtual gd::InstructionMetadata &
AddScopedCondition(const gd::String &name_, const gd::String &fullname_,
const gd::String &description_,
const gd::String &sentence_, const gd::String &group_,
const gd::String &icon_, const gd::String &smallicon_) = 0;
/**
* Declare a new action as being part of the behavior or object.
*/
virtual gd::InstructionMetadata &
AddScopedAction(const gd::String &name_, const gd::String &fullname_,
const gd::String &description_, const gd::String &sentence_,
const gd::String &group_, const gd::String &icon_,
const gd::String &smallicon_) = 0;
/**
* Declare a new action as being part of the extension.
*/
virtual gd::ExpressionMetadata &
AddExpression(const gd::String &name_, const gd::String &fullname_,
const gd::String &description_, const gd::String &group_,
const gd::String &smallicon_) = 0;
/**
* Declare a new string expression as being part of the extension.
*/
virtual gd::ExpressionMetadata &
AddStrExpression(const gd::String &name_, const gd::String &fullname_,
const gd::String &description_, const gd::String &group_,
const gd::String &smallicon_) = 0;
/**
* \brief Declare a new expression and condition as being part of the
* behavior.
* \note It's recommended to use this function to avoid declaring twice a
* similar expression/condition.
*/
virtual gd::MultipleInstructionMetadata AddExpressionAndCondition(
const gd::String &type, const gd::String &name,
const gd::String &fullname, const gd::String &description,
const gd::String &sentenceName, const gd::String &group,
const gd::String &icon) = 0;
/**
* \brief Declare a new expression, condition and action as being part of the
* behavior.
* \note The action name is prefixed by "Set" (and the namespace, as the
* condition).
* \note It's recommended to use this function to avoid declaring 3 times a
* similar expression/condition/action.
*/
virtual gd::MultipleInstructionMetadata AddExpressionAndConditionAndAction(
const gd::String &type, const gd::String &name,
const gd::String &fullname, const gd::String &description,
const gd::String &sentenceName, const gd::String &group,
const gd::String &icon) = 0;
/**
* \brief Create a new action which is the duplicate of the specified one.
*
* Useful for handling a deprecated action that is just a "copy" of the new
* one.
*/
virtual gd::InstructionMetadata &
AddDuplicatedAction(const gd::String &newActionName,
const gd::String &copiedActionName) = 0;
/**
* \brief Create a new condition which is the duplicate of the specified one.
*
* Useful for handling a deprecated condition that is just a "copy" of the new
* one.
*/
virtual gd::InstructionMetadata &
AddDuplicatedCondition(const gd::String &newConditionName,
const gd::String &copiedConditionName) = 0;
virtual InstructionOrExpressionContainerMetadata &
SetFullName(const gd::String &fullname_) = 0;
virtual InstructionOrExpressionContainerMetadata &
SetDescription(const gd::String &description_) = 0;
/**
* \brief Erase any existing include file and add the specified include.
* \note The requirement may vary depending on the platform: Most of the time,
* the include file contains the declaration of the behavior.
*/
virtual InstructionOrExpressionContainerMetadata &
SetIncludeFile(const gd::String &includeFile) = 0;
/**
* \brief Add a file to the already existing include files.
*/
virtual InstructionOrExpressionContainerMetadata &
AddIncludeFile(const gd::String &includeFile) = 0;
/**
* Get the help path of the behavior, relative to the GDevelop documentation
* root.
*/
virtual const gd::String &GetHelpPath() const = 0;
/**
* Set the help path of the behavior, relative to the GDevelop documentation
* root.
*
* The behavior instructions will have this help path set by
* default, unless you call SetHelpPath on them.
*/
virtual InstructionOrExpressionContainerMetadata &
SetHelpPath(const gd::String &path) = 0;
virtual const gd::String &GetName() const = 0;
virtual const gd::String &GetFullName() const = 0;
virtual const gd::String &GetDescription() const = 0;
virtual const gd::String &GetIconFilename() const = 0;
/**
* \brief Return a reference to a map containing the names of the actions
* (as keys) and the metadata associated with (as values).
*/
virtual std::map<gd::String, gd::InstructionMetadata> &GetAllActions() = 0;
/**
* \see gd::PlatformExtension::GetAllActions
*/
virtual std::map<gd::String, gd::InstructionMetadata> &GetAllConditions() = 0;
/**
* \see gd::PlatformExtension::GetAllActions
*/
virtual std::map<gd::String, gd::ExpressionMetadata> &GetAllExpressions() = 0;
/**
* \see gd::PlatformExtension::GetAllActions
*/
virtual std::map<gd::String, gd::ExpressionMetadata> &
GetAllStrExpressions() = 0;
private:
};
} // namespace gd

View File

@@ -275,6 +275,10 @@ class GD_CORE_API MetadataProvider {
return &metadata == &badBehaviorMetadata;
}
static bool IsBadObjectMetadata(const gd::ObjectMetadata& metadata) {
return &metadata == &badObjectInfo;
}
virtual ~MetadataProvider();
private:

View File

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

View File

@@ -3,8 +3,8 @@
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef MULTIPLEINSTRUCTIONSMETADATA_H
#define MULTIPLEINSTRUCTIONSMETADATA_H
#pragma once
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/String.h"
@@ -21,7 +21,7 @@ namespace gd {
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API MultipleInstructionMetadata {
class GD_CORE_API MultipleInstructionMetadata : public AbstractFunctionMetadata {
public:
static MultipleInstructionMetadata WithExpressionAndCondition(
gd::ExpressionMetadata &expression, gd::InstructionMetadata &condition) {
@@ -45,7 +45,7 @@ class GD_CORE_API MultipleInstructionMetadata {
const gd::String &type,
const gd::String &label,
const gd::String &supplementaryInformation = "",
bool parameterIsOptional = false) {
bool parameterIsOptional = false) override {
if (expression)
expression->AddParameter(
type, label, supplementaryInformation, parameterIsOptional);
@@ -62,7 +62,7 @@ class GD_CORE_API MultipleInstructionMetadata {
* \see gd::InstructionMetadata::AddCodeOnlyParameter
*/
MultipleInstructionMetadata &AddCodeOnlyParameter(
const gd::String &type, const gd::String &supplementaryInformation) {
const gd::String &type, const gd::String &supplementaryInformation) override {
if (expression)
expression->AddCodeOnlyParameter(type, supplementaryInformation);
if (condition)
@@ -74,7 +74,7 @@ class GD_CORE_API MultipleInstructionMetadata {
/**
* \see gd::InstructionMetadata::SetDefaultValue
*/
MultipleInstructionMetadata &SetDefaultValue(const gd::String &defaultValue) {
MultipleInstructionMetadata &SetDefaultValue(const gd::String &defaultValue) override {
if (expression) expression->SetDefaultValue(defaultValue);
if (condition) condition->SetDefaultValue(defaultValue);
if (action) action->SetDefaultValue(defaultValue);
@@ -85,7 +85,7 @@ class GD_CORE_API MultipleInstructionMetadata {
* \see gd::InstructionMetadata::SetParameterExtraInfo
*/
MultipleInstructionMetadata &SetParameterExtraInfo(
const gd::String &defaultValue) {
const gd::String &defaultValue) override {
if (expression) expression->SetParameterExtraInfo(defaultValue);
if (condition) condition->SetParameterExtraInfo(defaultValue);
if (action) action->SetParameterExtraInfo(defaultValue);
@@ -96,7 +96,7 @@ class GD_CORE_API MultipleInstructionMetadata {
* \see gd::InstructionMetadata::SetParameterLongDescription
*/
MultipleInstructionMetadata &SetParameterLongDescription(
const gd::String &longDescription) {
const gd::String &longDescription) override {
if (expression) expression->SetParameterLongDescription(longDescription);
if (condition) condition->SetParameterLongDescription(longDescription);
if (action) action->SetParameterLongDescription(longDescription);
@@ -106,7 +106,7 @@ class GD_CORE_API MultipleInstructionMetadata {
/**
* \see gd::InstructionMetadata::SetHidden
*/
MultipleInstructionMetadata &SetHidden() {
MultipleInstructionMetadata &SetHidden() override {
if (expression) expression->SetHidden();
if (condition) condition->SetHidden();
if (action) action->SetHidden();
@@ -136,47 +136,47 @@ class GD_CORE_API MultipleInstructionMetadata {
return *this;
}
MultipleInstructionMetadata &SetFunctionName(const gd::String &functionName) {
MultipleInstructionMetadata &SetFunctionName(const gd::String &functionName) override {
if (expression) expression->SetFunctionName(functionName);
if (condition) condition->SetFunctionName(functionName);
if (action) action->GetCodeExtraInformation().SetFunctionName(functionName);
if (action) action->SetFunctionName(functionName);
return *this;
}
MultipleInstructionMetadata &SetGetter(const gd::String &getter) {
if (expression) expression->SetFunctionName(getter);
if (condition) condition->SetFunctionName(getter);
if (action) action->GetCodeExtraInformation().SetGetter(getter);
if (action) action->SetGetter(getter);
return *this;
}
MultipleInstructionMetadata &SetIncludeFile(const gd::String &includeFile) {
MultipleInstructionMetadata &SetIncludeFile(const gd::String &includeFile) override {
if (expression)
expression->GetCodeExtraInformation().SetIncludeFile(includeFile);
expression->SetIncludeFile(includeFile);
if (condition)
condition->GetCodeExtraInformation().SetIncludeFile(includeFile);
if (action) action->GetCodeExtraInformation().SetIncludeFile(includeFile);
condition->SetIncludeFile(includeFile);
if (action) action->SetIncludeFile(includeFile);
return *this;
}
MultipleInstructionMetadata &AddIncludeFile(const gd::String &includeFile) {
MultipleInstructionMetadata &AddIncludeFile(const gd::String &includeFile) override {
if (expression)
expression->GetCodeExtraInformation().AddIncludeFile(includeFile);
if (condition)
condition->GetCodeExtraInformation().AddIncludeFile(includeFile);
if (action) action->GetCodeExtraInformation().AddIncludeFile(includeFile);
condition->AddIncludeFile(includeFile);
if (action) action->AddIncludeFile(includeFile);
return *this;
}
/**
* \brief Get the files that must be included to use the instruction.
*/
const std::vector<gd::String> &GetIncludeFiles() const {
const std::vector<gd::String> &GetIncludeFiles() const override {
if (expression)
return expression->GetCodeExtraInformation().GetIncludeFiles();
if (condition)
return condition->GetCodeExtraInformation().GetIncludeFiles();
if (action) return action->GetCodeExtraInformation().GetIncludeFiles();
return condition->GetIncludeFiles();
if (action) return action->GetIncludeFiles();
// It can't actually happen.
throw std::logic_error("no instruction metadata");
}
@@ -184,7 +184,7 @@ class GD_CORE_API MultipleInstructionMetadata {
/**
* \see gd::InstructionMetadata::SetPrivate
*/
MultipleInstructionMetadata &SetPrivate() {
MultipleInstructionMetadata &SetPrivate() override {
if (expression) expression->SetPrivate();
if (condition) condition->SetPrivate();
if (action) action->SetPrivate();
@@ -218,6 +218,42 @@ class GD_CORE_API MultipleInstructionMetadata {
return *this;
}
/**
* Set that the instruction can be used in layouts or external events.
*/
MultipleInstructionMetadata &SetRelevantForLayoutEventsOnly() override {
if (condition) condition->SetRelevantForLayoutEventsOnly();
if (action) action->SetRelevantForLayoutEventsOnly();
return *this;
}
/**
* Set that the instruction can be used in function events.
*/
MultipleInstructionMetadata &SetRelevantForFunctionEventsOnly() override {
if (condition) condition->SetRelevantForFunctionEventsOnly();
if (action) action->SetRelevantForFunctionEventsOnly();
return *this;
}
/**
* Set that the instruction can be used in asynchronous function events.
*/
MultipleInstructionMetadata &SetRelevantForAsynchronousFunctionEventsOnly() override {
if (condition) condition->SetRelevantForAsynchronousFunctionEventsOnly();
if (action) action->SetRelevantForAsynchronousFunctionEventsOnly();
return *this;
}
/**
* Set that the instruction can be used in custom object events.
*/
MultipleInstructionMetadata &SetRelevantForCustomObjectEventsOnly() override {
if (condition) condition->SetRelevantForCustomObjectEventsOnly();
if (action) action->SetRelevantForCustomObjectEventsOnly();
return *this;
}
/**
* \brief Don't use, only here to fulfill Emscripten bindings requirements.
*/
@@ -242,5 +278,3 @@ class GD_CORE_API MultipleInstructionMetadata {
};
} // namespace gd
#endif // MULTIPLEINSTRUCTIONSMETADATA_H

View File

@@ -3,8 +3,10 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef OBJECTMETADATA_H
#define OBJECTMETADATA_H
#pragma once
#include "InstructionOrExpressionContainerMetadata.h"
#include <functional>
#include <map>
#include <set>
@@ -32,7 +34,7 @@ namespace gd {
*
* \ingroup Events
*/
class GD_CORE_API ObjectMetadata {
class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetadata {
public:
/**
* \brief Construct an object metadata, using a "blueprint" object that will
@@ -79,7 +81,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* \brief Declare a new action as being part of the extension.
@@ -92,7 +94,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* Declare a new condition as being part of the object.
@@ -103,7 +105,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* Declare a new action as being part of the object.
@@ -114,7 +116,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* \brief Declare a new expression as being part of the extension.
@@ -123,7 +125,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& fullname_,
const gd::String& description_,
const gd::String& group_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* \brief Declare a new string expression as being part of the extension.
*/
@@ -131,7 +133,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& fullname_,
const gd::String& description_,
const gd::String& group_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* \brief Declare a new expression and condition as being part of the
@@ -146,7 +148,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& description,
const gd::String& sentenceName,
const gd::String& group,
const gd::String& icon);
const gd::String& icon) override;
/**
* \brief Declare a new expression, condition and action as being part of the
@@ -163,7 +165,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& description,
const gd::String& sentenceName,
const gd::String& group,
const gd::String& icon);
const gd::String& icon) override;
/**
* \brief Create a new action which is the duplicate of the specified one.
@@ -172,7 +174,7 @@ class GD_CORE_API ObjectMetadata {
* one.
*/
gd::InstructionMetadata& AddDuplicatedAction(
const gd::String& newActionName, const gd::String& copiedActionName);
const gd::String& newActionName, const gd::String& copiedActionName) override;
/**
* \brief Create a new condition which is the duplicate of the specified one.
@@ -182,23 +184,23 @@ class GD_CORE_API ObjectMetadata {
*/
gd::InstructionMetadata& AddDuplicatedCondition(
const gd::String& newConditionName,
const gd::String& copiedConditionName);
const gd::String& copiedConditionName) override;
/**
* \brief Set the name shown to the user.
*/
ObjectMetadata& SetFullName(const gd::String& fullname_);
ObjectMetadata& SetFullName(const gd::String& fullname_) override;
/**
* \brief Set the description shown to the user.
*/
ObjectMetadata& SetDescription(const gd::String& description_);
ObjectMetadata& SetDescription(const gd::String& description_) override;
/**
* \brief Get the help path of the object, relative to the GDevelop
* documentation root.
*/
const gd::String& GetHelpPath() const { return helpPath; }
const gd::String& GetHelpPath() const override { return helpPath; }
/**
* \brief Set the help path of the object, relative to the GDevelop
@@ -207,7 +209,7 @@ class GD_CORE_API ObjectMetadata {
* The object instructions will have this help path set by
* default, unless you call SetHelpPath on them.
*/
ObjectMetadata& SetHelpPath(const gd::String& path) {
ObjectMetadata& SetHelpPath(const gd::String& path) override {
helpPath = path;
return *this;
}
@@ -222,38 +224,34 @@ class GD_CORE_API ObjectMetadata {
}
/**
* \brief The "capabilities" that are offered by the base object that are
* *not* supported by this object, and should be hidden in the editor
* interface.
* \brief The "capabilities" that are offered by through behaviors.
*/
const std::set<gd::String>& GetUnsupportedBaseObjectCapabilities() const {
return unsupportedBaseObjectCapabilities;
const std::set<gd::String>& GetDefaultBehaviors() const {
return defaultBehaviorTypes;
}
/**
* \brief Add a "capability" that is offered by the base object that is *not*
* supported by this object, and should be hidden in the editor interface.
* \brief Return true if object has a default behavior of the given type.
*/
ObjectMetadata& AddUnsupportedBaseObjectCapability(
const gd::String& capability) {
unsupportedBaseObjectCapabilities.insert(capability);
bool HasDefaultBehavior(const gd::String& behaviorType) const {
return defaultBehaviorTypes.find(behaviorType) != defaultBehaviorTypes.end();
}
/**
* \brief Add a "capability" that is offered by through a behavior.
*/
ObjectMetadata& AddDefaultBehavior(
const gd::String& behaviorType) {
defaultBehaviorTypes.insert(behaviorType);
return *this;
}
/**
* \brief Check if a "capability" that is offered by the base object is *not*
* supported by this object, and should be hidden in the editor interface.
*/
bool IsUnsupportedBaseObjectCapability(const gd::String& capability) const {
return unsupportedBaseObjectCapabilities.find(capability) != unsupportedBaseObjectCapabilities.end();
}
const gd::String& GetName() const { return name; }
const gd::String& GetFullName() const { return fullname; }
const gd::String& GetName() const override { return name; }
const gd::String& GetFullName() const override { return fullname; }
const gd::String& GetCategoryFullName() const { return categoryFullName; }
const gd::String& GetHelpUrl() const { return helpUrl; }
const gd::String& GetDescription() const { return description; }
const gd::String& GetIconFilename() const { return iconFilename; }
const gd::String& GetDescription() const override { return description; }
const gd::String& GetIconFilename() const override { return iconFilename; }
/**
* \brief Set the URL pointing to the help page about this object
@@ -267,33 +265,33 @@ class GD_CORE_API ObjectMetadata {
* \note The requirement may vary depending on the platform: Most of the time,
* the include file contains the declaration of the object.
*/
ObjectMetadata& SetIncludeFile(const gd::String& includeFile);
ObjectMetadata& SetIncludeFile(const gd::String& includeFile) override;
/**
* \brief Add a file to the already existing include files.
*/
ObjectMetadata& AddIncludeFile(const gd::String& includeFile);
ObjectMetadata& AddIncludeFile(const gd::String& includeFile) override;
/**
* \brief Return a reference to a map containing the names of the actions
* (as keys) and the metadata associated with (as values).
*/
std::map<gd::String, gd::InstructionMetadata>& GetAllActions() { return actionsInfos; };
std::map<gd::String, gd::InstructionMetadata>& GetAllActions() override { return actionsInfos; };
/**
* \see gd::PlatformExtension::GetAllActions
*/
std::map<gd::String, gd::InstructionMetadata>& GetAllConditions() { return conditionsInfos; };
std::map<gd::String, gd::InstructionMetadata>& GetAllConditions() override { return conditionsInfos; };
/**
* \see gd::PlatformExtension::GetAllActions
*/
std::map<gd::String, gd::ExpressionMetadata>& GetAllExpressions() { return expressionsInfos; };
std::map<gd::String, gd::ExpressionMetadata>& GetAllExpressions() override { return expressionsInfos; };
/**
* \see gd::PlatformExtension::GetAllActions
*/
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressions() { return strExpressionsInfos; };
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressions() override { return strExpressionsInfos; };
/**
* \brief Set the object to be hidden in the IDE.
@@ -329,7 +327,7 @@ class GD_CORE_API ObjectMetadata {
gd::String description;
gd::String iconFilename;
gd::String categoryFullName;
std::set<gd::String> unsupportedBaseObjectCapabilities;
std::set<gd::String> defaultBehaviorTypes;
bool hidden = false;
std::shared_ptr<gd::ObjectConfiguration>
@@ -341,4 +339,3 @@ class GD_CORE_API ObjectMetadata {
};
} // namespace gd
#endif // OBJECTMETADATA_H

View File

@@ -273,25 +273,6 @@ 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);
@@ -653,7 +634,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
GetAllActions().begin();
it != GetAllActions().end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
GetAllActions().erase(it++);
} else
++it;
@@ -663,7 +644,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
GetAllConditions().begin();
it != GetAllConditions().end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
GetAllConditions().erase(it++);
} else
++it;
@@ -673,7 +654,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
GetAllExpressions().begin();
it != GetAllExpressions().end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
GetAllExpressions().erase(it++);
} else
++it;
@@ -683,7 +664,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
GetAllStrExpressions().begin();
it != GetAllStrExpressions().end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
GetAllStrExpressions().erase(it++);
} else
++it;
@@ -699,7 +680,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.actionsInfos.begin();
it != obj.actionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.actionsInfos.erase(it++);
} else
++it;
@@ -709,7 +690,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.conditionsInfos.begin();
it != obj.conditionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.conditionsInfos.erase(it++);
} else
++it;
@@ -719,7 +700,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.expressionsInfos.begin();
it != obj.expressionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.expressionsInfos.erase(it++);
} else
++it;
@@ -729,7 +710,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.strExpressionsInfos.begin();
it != obj.strExpressionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.strExpressionsInfos.erase(it++);
} else
++it;
@@ -746,7 +727,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.actionsInfos.begin();
it != obj.actionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.actionsInfos.erase(it++);
} else
++it;
@@ -756,7 +737,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.conditionsInfos.begin();
it != obj.conditionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.conditionsInfos.erase(it++);
} else
++it;
@@ -766,7 +747,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.expressionsInfos.begin();
it != obj.expressionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.expressionsInfos.erase(it++);
} else
++it;
@@ -776,7 +757,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.strExpressionsInfos.begin();
it != obj.strExpressionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.strExpressionsInfos.erase(it++);
} else
++it;

View File

@@ -421,6 +421,32 @@ class GD_CORE_API PlatformExtension {
*/
const gd::String& GetIconUrl() const { return iconUrl; }
/**
* \brief Return keywords that help search engines find this extension.
*/
const std::vector<gd::String>& GetTags() const { return tags; }
/**
* \brief Set keywords that help search engines find this extension.
*/
PlatformExtension& SetTags(const gd::String& csvTags) {
tags.clear();
tags = csvTags.Split(',');
for (size_t i = 0; i < tags.size(); i++)
{
tags[i] = tags[i].Trim().LowerCase();
}
return *this;
}
/**
* \brief Add a keyword that help search engines find this extension.
*/
PlatformExtension& AddTag(const gd::String& tag) {
tags.push_back(tag);
return *this;
}
/**
* \brief Check if the extension is flagged as being deprecated.
*/
@@ -661,6 +687,7 @@ private:
gd::String helpPath; ///< The relative path to the help for this extension in
///< the documentation.
gd::String iconUrl; ///< The URL to the icon to be shown for this extension.
std::vector<gd::String> tags;
std::map<gd::String, gd::ObjectMetadata> objectsInfos;
std::map<gd::String, gd::BehaviorMetadata> behaviorsInfo;

View File

@@ -0,0 +1,23 @@
#include "BehaviorDefaultFlagClearer.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 BehaviorDefaultFlagClearer::DoVisitObject(gd::Object& object) {
};
void BehaviorDefaultFlagClearer::DoVisitBehavior(gd::Behavior& behavior) {
behavior.SetDefaultBehavior(false);
};
BehaviorDefaultFlagClearer::~BehaviorDefaultFlagClearer() {}
} // namespace gd

View File

@@ -0,0 +1,34 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <set>
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/String.h"
namespace gd {
class Object;
class Behavior;
} // namespace gd
namespace gd {
/**
* @brief This is used for project exports to keep default behaviors in
* serialized data used by Runtime.
*/
class GD_CORE_API BehaviorDefaultFlagClearer : public ArbitraryObjectsWorker {
public:
BehaviorDefaultFlagClearer() {};
virtual ~BehaviorDefaultFlagClearer();
private:
void DoVisitObject(gd::Object& object) override;
void DoVisitBehavior(gd::Behavior& behavior) override;
};
}; // namespace gd

View File

@@ -555,6 +555,22 @@ void EventsRefactorer::RemoveObjectInEvents(const gd::Platform& platform,
}
}
gd::String ReplaceAllOccurrencesCaseInsensitive(gd::String context,
const gd::String& from,
const gd::String& to) {
size_t lookHere = 0;
size_t foundHere;
size_t fromSize = from.size();
size_t toSize = to.size();
while ((foundHere = context.FindCaseInsensitive(from, lookHere)) !=
gd::String::npos) {
context.replace(foundHere, fromSize, to);
lookHere = foundHere + toSize;
}
return context;
}
std::vector<EventsSearchResult> EventsRefactorer::ReplaceStringInEvents(
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
@@ -570,6 +586,32 @@ std::vector<EventsSearchResult> EventsRefactorer::ReplaceStringInEvents(
for (std::size_t i = 0; i < events.size(); ++i) {
bool eventModified = false;
std::vector<gd::Expression*> allObjectExpressions =
events[i].GetAllObjectExpressions();
for (std::size_t j = 0; j < allObjectExpressions.size(); ++j) {
gd::String newExpressionPlainString =
matchCase ? allObjectExpressions[j]->GetPlainString().FindAndReplace(
toReplace, newString, true)
: ReplaceAllOccurrencesCaseInsensitive(
allObjectExpressions[j]->GetPlainString(),
toReplace,
newString);
if (newExpressionPlainString !=
allObjectExpressions[j]->GetPlainString()) {
*allObjectExpressions[j] = gd::Expression(newExpressionPlainString);
if (!eventModified) {
modifiedEvents.push_back(EventsSearchResult(
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
&events,
i));
eventModified = true;
}
}
}
if (inConditions) {
vector<gd::InstructionsList*> conditionsVectors =
events[i].GetAllConditionsVectors();
@@ -642,22 +684,6 @@ std::vector<EventsSearchResult> EventsRefactorer::ReplaceStringInEvents(
return modifiedEvents;
}
gd::String ReplaceAllOccurrencesCaseInsensitive(gd::String context,
gd::String from,
const gd::String& to) {
size_t lookHere = 0;
size_t foundHere;
size_t fromSize = from.size();
size_t toSize = to.size();
while ((foundHere = context.FindCaseInsensitive(from, lookHere)) !=
gd::String::npos) {
context.replace(foundHere, fromSize, to);
lookHere = foundHere + toSize;
}
return context;
}
bool EventsRefactorer::ReplaceStringInActions(gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& actions,
@@ -789,6 +815,24 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
for (std::size_t i = 0; i < events.size(); ++i) {
bool eventAddedInResults = false;
std::vector<gd::Expression*> allObjectExpressions =
events[i].GetAllObjectExpressions();
for (std::size_t j = 0; j < allObjectExpressions.size(); ++j) {
size_t foundPosition =
matchCase
? allObjectExpressions[j]->GetPlainString().find(search)
: allObjectExpressions[j]->GetPlainString().FindCaseInsensitive(
search);
if (foundPosition != gd::String::npos && !eventAddedInResults) {
results.push_back(EventsSearchResult(
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
&events,
i));
eventAddedInResults = true;
}
}
if (inConditions) {
vector<gd::InstructionsList*> conditionsVectors =
events[i].GetAllConditionsVectors();
@@ -803,6 +847,7 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
&events,
i));
eventAddedInResults = true;
}
}
}
@@ -820,6 +865,7 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
&events,
i));
eventAddedInResults = true;
}
}
}

View File

@@ -104,14 +104,6 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(const gd::Functi
!metadata.GetRequiredBaseObjectCapability().empty()) {
const gd::ObjectMetadata &objectMetadata =
MetadataProvider::GetObjectMetadata(platform, objectType);
if (objectMetadata.IsUnsupportedBaseObjectCapability(
metadata.GetRequiredBaseObjectCapability())) {
RaiseTypeError(
_("This expression exists, but it can't be used on this object."),
function.objectNameLocation);
return returnType;
}
}
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {

View File

@@ -87,11 +87,22 @@ protected:
std::unique_ptr<gd::ExpressionNode> &parameterNode,
size_t parameterIndex, const gd::String &lastObjectName) {
if (parameterMetadata.GetType() == "layer") {
// Remove quotes, it won't match if it's not a literal anyway.
lastLayerName = expressionPlainString.substr(
parameterNode->location.GetStartPosition() + 1,
parameterNode->location.GetEndPosition() -
parameterNode->location.GetStartPosition() - 2);
if (parameterNode->location.GetEndPosition() -
parameterNode->location.GetStartPosition() <
2) {
// This is either the base layer or an invalid layer name.
// Keep it as is.
lastLayerName = expressionPlainString.substr(
parameterNode->location.GetStartPosition(),
parameterNode->location.GetEndPosition() -
parameterNode->location.GetStartPosition());
} else {
// Remove quotes, so it can be compared to the layer name.
lastLayerName = expressionPlainString.substr(
parameterNode->location.GetStartPosition() + 1,
parameterNode->location.GetEndPosition() -
parameterNode->location.GetStartPosition() - 2);
}
}
if (parameterMetadata.GetType() == parameterType) {
auto parameterExpressionPlainString = expressionPlainString.substr(
@@ -143,9 +154,15 @@ bool ProjectElementRenamer::DoVisitInstruction(gd::Instruction &instruction,
const gd::Expression &parameterValue, size_t parameterIndex,
const gd::String &lastObjectName) {
if (parameterMetadata.GetType() == "layer") {
// Remove quotes, it won't match if it's not a literal anyway.
lastLayerName = parameterValue.GetPlainString().substr(
1, parameterValue.GetPlainString().length() - 2);
if (parameterValue.GetPlainString().length() < 2) {
// This is either the base layer or an invalid layer name.
// Keep it as is.
lastLayerName = parameterValue.GetPlainString();
} else {
// Remove quotes, so it can be compared to the layer name.
lastLayerName = parameterValue.GetPlainString().substr(
1, parameterValue.GetPlainString().length() - 2);
}
}
if (parameterMetadata.GetType() == parameterType &&
@@ -165,7 +182,6 @@ bool ProjectElementRenamer::DoVisitInstruction(gd::Instruction &instruction,
node->Visit(finder);
if (finder.GetOccurrences().size() > 0) {
gd::String newNameWithQuotes = "\"" + newName + "\"";
gd::String oldParameterValue = parameterValue.GetPlainString();
gd::String newParameterValue;

View File

@@ -17,9 +17,11 @@
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ResourcesManager.h"
#include "GDCore/Project/Effect.h"
#include "GDCore/Tools/Log.h"
#include "GDCore/IDE/ResourceExposer.h"
using namespace std;
@@ -131,29 +133,9 @@ void ArbitraryResourceWorker::ExposeEmbeddeds(gd::String& resourceName) {
std::cout << targetResourceName << std::endl;
gd::Resource& targetResource =
resourcesManager->GetResource(targetResourceName);
const gd::String& targetResourceKind = targetResource.GetKind();
gd::String potentiallyUpdatedTargetResourceName = targetResourceName;
if (targetResourceKind == "audio") {
ExposeAudio(potentiallyUpdatedTargetResourceName);
} else if (targetResourceKind == "bitmapFont") {
ExposeBitmapFont(potentiallyUpdatedTargetResourceName);
} else if (targetResourceKind == "font") {
ExposeFont(potentiallyUpdatedTargetResourceName);
} else if (targetResourceKind == "image") {
ExposeImage(potentiallyUpdatedTargetResourceName);
} else if (targetResourceKind == "json") {
ExposeJson(potentiallyUpdatedTargetResourceName);
} else if (targetResourceKind == "tilemap") {
ExposeTilemap(potentiallyUpdatedTargetResourceName);
} else if (targetResourceKind == "tileset") {
ExposeTileset(potentiallyUpdatedTargetResourceName);
} else if (targetResourceKind == "video") {
ExposeVideo(potentiallyUpdatedTargetResourceName);
} else if (targetResourceKind == "model3D") {
ExposeModel3D(potentiallyUpdatedTargetResourceName);
}
ExposeResourceWithType(targetResource.GetKind(), potentiallyUpdatedTargetResourceName);
if (potentiallyUpdatedTargetResourceName != targetResourceName) {
// The resource name was renamed. Also update the mapping.
@@ -170,6 +152,48 @@ void ArbitraryResourceWorker::ExposeEmbeddeds(gd::String& resourceName) {
}
}
void ArbitraryResourceWorker::ExposeResourceWithType(
const gd::String &resourceType, gd::String &resourceName) {
if (resourceType == "image") {
ExposeImage(resourceName);
return;
}
if (resourceType == "model3D") {
ExposeModel3D(resourceName);
return;
}
if (resourceType == "audio") {
ExposeAudio(resourceName);
return;
}
if (resourceType == "font") {
ExposeFont(resourceName);
return;
}
if (resourceType == "bitmapFont") {
ExposeBitmapFont(resourceName);
return;
}
if (resourceType == "tilemap") {
ExposeTilemap(resourceName);
return;
}
if (resourceType == "tileset") {
ExposeTileset(resourceName);
return;
}
if (resourceType == "json") {
ExposeJson(resourceName);
return;
}
if (resourceType == "video") {
ExposeVideo(resourceName);
return;
}
gd::LogError("Unexpected resource type: " + resourceType + " for: " + resourceName);
return;
}
void ArbitraryResourceWorker::ExposeResource(gd::Resource& resource) {
if (!resource.UseFile()) return;
@@ -180,86 +204,98 @@ void ArbitraryResourceWorker::ExposeResource(gd::Resource& resource) {
ArbitraryResourceWorker::~ArbitraryResourceWorker() {}
/**
* Launch the specified resource worker on every resource referenced in the
* events.
*/
class ResourceWorkerInEventsWorker : public ArbitraryEventsWorker {
public:
ResourceWorkerInEventsWorker(const gd::Project& project_,
gd::ArbitraryResourceWorker& worker_)
: project(project_), worker(worker_){};
virtual ~ResourceWorkerInEventsWorker(){};
bool ResourceWorkerInEventsWorker::DoVisitInstruction(gd::Instruction& instruction, bool isCondition) {
const auto& platform = project.GetCurrentPlatform();
const auto& metadata = isCondition
? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
private:
bool DoVisitInstruction(gd::Instruction& instruction, bool isCondition) {
const auto& platform = project.GetCurrentPlatform();
const auto& metadata = isCondition
? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
instruction.GetParameters(),
metadata.GetParameters(),
[this, &instruction](const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterExpression,
size_t parameterIndex,
const gd::String& lastObjectName) {
const String& parameterValue = parameterExpression.GetPlainString();
if (parameterMetadata.GetType() ==
"police" || // Should be renamed fontResource
parameterMetadata.GetType() == "fontResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeFont(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
} else if (parameterMetadata.GetType() == "soundfile" ||
parameterMetadata.GetType() ==
"musicfile") { // Should be renamed audioResource
gd::String updatedParameterValue = parameterValue;
worker.ExposeAudio(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
} else if (parameterMetadata.GetType() == "bitmapFontResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeBitmapFont(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
} else if (parameterMetadata.GetType() == "imageResource") {
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);
} else if (parameterMetadata.GetType() == "tilemapResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeTilemap(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
} else if (parameterMetadata.GetType() == "tilesetResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeTileset(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
} else if (parameterMetadata.GetType() == "model3DResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeModel3D(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
}
});
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
instruction.GetParameters(),
metadata.GetParameters(),
[this, &instruction](const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterExpression,
size_t parameterIndex,
const gd::String& lastObjectName) {
const String& parameterValue = parameterExpression.GetPlainString();
if (parameterMetadata.GetType() ==
"police" || // Should be renamed fontResource
parameterMetadata.GetType() == "fontResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeFont(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
} else if (parameterMetadata.GetType() == "soundfile" ||
parameterMetadata.GetType() ==
"musicfile") { // Should be renamed audioResource
gd::String updatedParameterValue = parameterValue;
worker.ExposeAudio(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
} else if (parameterMetadata.GetType() == "bitmapFontResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeBitmapFont(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
} else if (parameterMetadata.GetType() == "imageResource") {
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);
} else if (parameterMetadata.GetType() == "tilemapResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeTilemap(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
} else if (parameterMetadata.GetType() == "tilesetResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeTileset(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
} else if (parameterMetadata.GetType() == "model3DResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeModel3D(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
}
});
return false;
};
const gd::Project& project;
gd::ArbitraryResourceWorker& worker;
return false;
};
void LaunchResourceWorkerOnEvents(const gd::Project& project,
gd::EventsList& events,
gd::ArbitraryResourceWorker& worker) {
ResourceWorkerInEventsWorker eventsWorker(project, worker);
gd::ResourceWorkerInEventsWorker eventsWorker(project, worker);
eventsWorker.Launch(events);
}
gd::ResourceWorkerInEventsWorker
GetResourceWorkerOnEvents(const gd::Project &project,
gd::ArbitraryResourceWorker &worker) {
gd::ResourceWorkerInEventsWorker eventsWorker(project, worker);
return eventsWorker;
}
void ResourceWorkerInObjectsWorker::DoVisitObject(gd::Object &object) {
object.GetConfiguration().ExposeResources(worker);
auto& effects = object.GetEffects();
for (size_t effectIndex = 0; effectIndex < effects.GetEffectsCount(); effectIndex++)
{
auto& effect = effects.GetEffect(effectIndex);
gd::ResourceExposer::ExposeEffectResources(project.GetCurrentPlatform(), effect, worker);
}
};
void ResourceWorkerInObjectsWorker::DoVisitBehavior(gd::Behavior &behavior){
// TODO Allow behaviors to expose resources
};
gd::ResourceWorkerInObjectsWorker
GetResourceWorkerOnObjects(const gd::Project &project,
gd::ArbitraryResourceWorker &worker) {
gd::ResourceWorkerInObjectsWorker eventsWorker(project, worker);
return eventsWorker;
}
} // namespace gd
#endif

View File

@@ -4,13 +4,14 @@
* reserved. This project is released under the MIT License.
*/
#ifndef ARBITRARYRESOURCEWORKER_H
#define ARBITRARYRESOURCEWORKER_H
#pragma once
#include <map>
#include <memory>
#include <vector>
#include "GDCore/String.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
namespace gd {
class BaseEvent;
}
@@ -53,6 +54,11 @@ class GD_CORE_API ArbitraryResourceWorker {
*/
void ExposeResources(gd::ResourcesManager *resourcesManager);
/**
* \brief Expose a resource from a given type.
*/
void ExposeResourceWithType(const gd::String& resourceType, gd::String& resourceName);
/**
* \brief Expose an image, which is always a reference to a "image" resource.
*/
@@ -132,18 +138,47 @@ class GD_CORE_API ArbitraryResourceWorker {
};
/**
* Tool function iterating over each event and calling
* Expose(Actions/Conditions)Resources for each actions and conditions with the
* ArbitraryResourceWorker passed as argument.
*
* \see gd::ArbitraryResourceWorker
* \ingroup IDE
* Launch the specified resource worker on every resource referenced in the
* events.
*/
void GD_CORE_API
LaunchResourceWorkerOnEvents(const gd::Project &project,
gd::EventsList &events,
gd::ArbitraryResourceWorker &worker);
class ResourceWorkerInEventsWorker : public gd::ArbitraryEventsWorker {
public:
ResourceWorkerInEventsWorker(const gd::Project &project_,
gd::ArbitraryResourceWorker &worker_)
: project(project_), worker(worker_){};
virtual ~ResourceWorkerInEventsWorker(){};
private:
bool DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) override;
const gd::Project &project;
gd::ArbitraryResourceWorker &worker;
};
ResourceWorkerInEventsWorker GD_CORE_API GetResourceWorkerOnEvents(
const gd::Project &project, gd::ArbitraryResourceWorker &worker);
/**
* Launch the specified resource worker on every resource referenced in the
* objects.
*/
class GD_CORE_API ResourceWorkerInObjectsWorker
: public gd::ArbitraryObjectsWorker {
public:
ResourceWorkerInObjectsWorker(const gd::Project &project_, gd::ArbitraryResourceWorker &worker_)
: project(project_), worker(worker_){};
~ResourceWorkerInObjectsWorker() {}
private:
void DoVisitObject(gd::Object &object) override;
void DoVisitBehavior(gd::Behavior &behavior) override;
const gd::Project &project;
gd::ArbitraryResourceWorker &worker;
};
gd::ResourceWorkerInObjectsWorker GD_CORE_API
GetResourceWorkerOnObjects(const gd::Project &project, gd::ArbitraryResourceWorker &worker);
} // namespace gd
#endif // ARBITRARYRESOURCEWORKER_H

View File

@@ -9,6 +9,7 @@
#include "GDCore/Project/Project.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/Log.h"
#include "GDCore/IDE/ResourceExposer.h"
using namespace std;
@@ -19,7 +20,7 @@ std::vector<gd::String> ProjectResourcesAdder::GetAllUseless(
std::vector<gd::String> unusedResources;
// Search for resources used in the project
gd::ResourcesInUseHelper resourcesInUse;
project.ExposeResources(resourcesInUse);
gd::ResourceExposer::ExposeWholeProjectResources(project, resourcesInUse);
std::set<gd::String>& usedResources = resourcesInUse.GetAll(resourceType);
// Search all resources not used

View File

@@ -12,6 +12,7 @@
#include "GDCore/Project/Project.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/Log.h"
#include "GDCore/IDE/ResourceExposer.h"
using namespace std;
@@ -26,7 +27,7 @@ bool ProjectResourcesCopier::CopyAllResourcesTo(
bool preserveDirectoryStructure) {
// Check if there are some resources with absolute filenames
gd::ResourcesAbsolutePathChecker absolutePathChecker(fs);
originalProject.ExposeResources(absolutePathChecker);
gd::ResourceExposer::ExposeWholeProjectResources(originalProject, absolutePathChecker);
auto projectDirectory = fs.DirNameFrom(originalProject.GetProjectFile());
std::cout << "Copying all resources from " << projectDirectory << " to "
@@ -41,10 +42,10 @@ bool ProjectResourcesCopier::CopyAllResourcesTo(
preserveAbsoluteFilenames);
if (updateOriginalProject) {
originalProject.ExposeResources(resourcesMergingHelper);
gd::ResourceExposer::ExposeWholeProjectResources(originalProject, resourcesMergingHelper);
} else {
std::shared_ptr<gd::Project> project(new gd::Project(originalProject));
project->ExposeResources(resourcesMergingHelper);
gd::ResourceExposer::ExposeWholeProjectResources(*project, resourcesMergingHelper);
}
// Copy resources

View File

@@ -13,6 +13,7 @@
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/String.h"
#include "GDCore/IDE/ResourceExposer.h"
namespace gd {
@@ -23,7 +24,7 @@ namespace gd {
* Usage example:
\code
gd::ResourcesInUseHelper resourcesInUse;
project.ExposeResources(resourcesInUse);
gd::ResourceExposer::ExposeWholeProjectResources(project, resourcesInUse);
//Get a set with the name of all images in the project:
std::set<gd::String> & usedImages = resourcesInUse.GetAllImages();

View File

@@ -197,7 +197,7 @@ void ProjectBrowserHelper::ExposeProjectObjects(
// Global objects
worker.Launch(project);
// Layers objects
// Layout objects
for (size_t i = 0; i < project.GetLayoutsCount(); i++) {
worker.Launch(project.GetLayout(i));
}

View File

@@ -11,6 +11,8 @@
#include "GDCore/Project/ExternalLayout.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/IDE/WholeProjectBrowser.h"
#include "GDCore/IDE/Events/BehaviorDefaultFlagClearer.h"
namespace gd {
@@ -19,6 +21,10 @@ void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project &project) {
while (project.GetExternalEventsCount() > 0)
project.RemoveExternalEvents(project.GetExternalEvents(0).GetName());
gd::BehaviorDefaultFlagClearer behaviorDefaultFlagClearer;
gd::WholeProjectBrowser wholeProjectBrowser;
wholeProjectBrowser.ExposeObjects(project, behaviorDefaultFlagClearer);
for (unsigned int i = 0; i < project.GetLayoutsCount(); ++i) {
project.GetLayout(i).GetObjectGroups().Clear();
project.GetLayout(i).GetEvents().Clear();

View File

@@ -0,0 +1,101 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "ResourceExposer.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/EventsFunctionTools.h"
#include "GDCore/IDE/Project/ArbitraryBehaviorSharedDataWorker.h"
#include "GDCore/IDE/Project/ArbitraryEventBasedBehaviorsWorker.h"
#include "GDCore/IDE/Project/ArbitraryEventsFunctionsWorker.h"
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/IDE/ProjectBrowserHelper.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/Effect.h"
#include "GDCore/String.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
namespace gd {
void ResourceExposer::ExposeWholeProjectResources(gd::Project& project, gd::ArbitraryResourceWorker& worker) {
// See also gd::ProjectBrowserHelper::ExposeProjectEvents for a method that
// traverse the whole project (this time for events) and ExposeProjectEffects
// (this time for effects).
gd::ResourcesManager* resourcesManager = &(project.GetResourcesManager());
// Expose any project resources as files.
worker.ExposeResources(resourcesManager);
project.GetPlatformSpecificAssets().ExposeResources(worker);
// Expose event resources
auto eventWorker = gd::GetResourceWorkerOnEvents(project, worker);
gd::ProjectBrowserHelper::ExposeProjectEvents(
project, eventWorker);
// Expose object configuration resources
auto objectWorker = gd::GetResourceWorkerOnObjects(project, worker);
gd::ProjectBrowserHelper::ExposeProjectObjects(
project, objectWorker);
// Expose layer effect resources
for (std::size_t layoutIndex = 0; layoutIndex < project.GetLayoutsCount();
layoutIndex++) {
auto &layout = project.GetLayout(layoutIndex);
for (std::size_t layerIndex = 0; layerIndex < layout.GetLayersCount();
layerIndex++) {
auto &layer = layout.GetLayer(layerIndex);
auto &effects = layer.GetEffects();
for (size_t effectIndex = 0; effectIndex < effects.GetEffectsCount();
effectIndex++) {
auto &effect = effects.GetEffect(effectIndex);
gd::ResourceExposer::ExposeEffectResources(project.GetCurrentPlatform(),
effect, worker);
}
}
}
// Expose loading screen background image if present
auto& loadingScreen = project.GetLoadingScreen();
if (loadingScreen.GetBackgroundImageResourceName() != "")
worker.ExposeImage(loadingScreen.GetBackgroundImageResourceName());
}
void ResourceExposer::ExposeEffectResources(
gd::Platform &platform, gd::Effect &effect,
gd::ArbitraryResourceWorker &worker) {
auto &effectMetadata =
MetadataProvider::GetEffectMetadata(platform, effect.GetEffectType());
for (auto &propertyPair : effectMetadata.GetProperties()) {
auto &propertyName = propertyPair.first;
auto &propertyDescriptor = propertyPair.second;
if (propertyDescriptor.GetType() == "resource" &&
propertyDescriptor.GetExtraInfo().size() > 0) {
auto &resourceType = propertyDescriptor.GetExtraInfo()[0];
const gd::String &resourceName = effect.GetStringParameter(propertyName);
gd::String potentiallyUpdatedResourceName = resourceName;
worker.ExposeResourceWithType(resourceType,
potentiallyUpdatedResourceName);
if (potentiallyUpdatedResourceName != resourceName) {
effect.SetStringParameter(propertyName, potentiallyUpdatedResourceName);
}
}
}
}
} // namespace gd

View File

@@ -0,0 +1,38 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
namespace gd {
class Platform;
class Project;
class ArbitraryResourceWorker;
class Effect;
} // namespace gd
namespace gd {
/**
* \brief
*/
class GD_CORE_API ResourceExposer {
public:
/**
* \brief Called ( e.g. during compilation ) so as to inventory internal
* resources, sometimes update their filename or any other work or resources.
*
* See WholeProjectRefactorer for the same thing for events.
*
* \see WholeProjectRefactorer
* \see ArbitraryResourceWorker
*/
static void ExposeWholeProjectResources(gd::Project &project,
gd::ArbitraryResourceWorker &worker);
static void ExposeEffectResources(gd::Platform &platform, gd::Effect &effect,
gd::ArbitraryResourceWorker &worker);
};
} // namespace gd

File diff suppressed because it is too large Load Diff

View File

@@ -456,6 +456,26 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::EventsBasedObject& eventsBasedObject);
/**
* \brief Remove all the instances from one layer.
*/
static void RemoveLayer(gd::Project &project, gd::Layout &layout,
const gd::String &layerName);
/**
* \brief Move all the instances from one layer into another.
*/
static void MergeLayers(gd::Project &project, gd::Layout &layout,
const gd::String &originLayerName,
const gd::String &targetLayerName);
/**
* \brief Return the number of instances on the layer named \a layerName and
* all its associated layouts.
*/
static size_t GetLayoutAndExternalLayoutLayerInstancesCount(
gd::Project &project, gd::Layout &layout, const gd::String &layerName);
virtual ~WholeProjectRefactorer(){};
private:

View File

@@ -23,11 +23,23 @@ namespace gd {
class GD_CORE_API Behavior: public BehaviorConfigurationContainer {
public:
Behavior(): BehaviorConfigurationContainer() {};
Behavior(): BehaviorConfigurationContainer(), isDefaultBehavior(false) {};
Behavior(const gd::String& name_, const gd::String& type_)
: BehaviorConfigurationContainer(name_, type_) {};
: BehaviorConfigurationContainer(name_, type_),
isDefaultBehavior(false) {};
virtual ~Behavior();
virtual Behavior* Clone() const override { return new Behavior(*this); }
bool IsDefaultBehavior() const {
return isDefaultBehavior;
}
void SetDefaultBehavior(bool isDefaultBehavior_) {
isDefaultBehavior = isDefaultBehavior_;
}
private:
bool isDefaultBehavior;
};
} // namespace gd

View File

@@ -31,10 +31,10 @@ namespace gd {
*/
class GD_CORE_API BehaviorConfigurationContainer {
public:
BehaviorConfigurationContainer(){};
BehaviorConfigurationContainer(const gd::String& name_, const gd::String& type_)
: name(name_), type(type_){};
BehaviorConfigurationContainer() : folded(false){};
BehaviorConfigurationContainer(const gd::String& name_,
const gd::String& type_)
: name(name_), type(type_), folded(false){};
virtual ~BehaviorConfigurationContainer();
virtual BehaviorConfigurationContainer* Clone() const { return new BehaviorConfigurationContainer(*this); }
@@ -61,7 +61,7 @@ class GD_CORE_API BehaviorConfigurationContainer {
/**
* \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
*/
@@ -104,6 +104,17 @@ class GD_CORE_API BehaviorConfigurationContainer {
const gd::SerializerElement& GetContent() const { return content; };
gd::SerializerElement& GetContent() { return content; };
/**
* \brief Set if the behavior configuration panel should be folded in the UI.
*/
void SetFolded(bool fold = true) { folded = fold; }
/**
* \brief True if the behavior configuration panel should be folded in the UI.
*/
bool IsFolded() const { return folded; }
protected:
/**
* \brief Called when the IDE wants to know about the custom properties of the
@@ -148,6 +159,7 @@ protected:
///< in the form "ExtensionName::BehaviorTypeName"
gd::SerializerElement content; // Storage for the behavior properties
bool folded;
};
} // namespace gd

View File

@@ -77,7 +77,7 @@ class GD_CORE_API EventsBasedBehavior: public AbstractEventsBasedEntity {
* \brief Check if the behavior is private - it can't be used outside of its
* extension.
*/
bool IsPrivate() { return isPrivate; }
bool IsPrivate() const { return isPrivate; }
/**
* \brief Set that the behavior is private - it can't be used outside of its

View File

@@ -201,7 +201,7 @@ class GD_CORE_API EventsFunction {
/**
* \brief Returns true if the function is private.
*/
bool IsPrivate() { return isPrivate; }
bool IsPrivate() const { return isPrivate; }
/**
* \brief Sets the privateness of the function.

View File

@@ -207,6 +207,13 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
return dependencies;
};
/**
* \brief Returns the list of dependencies.
*/
const std::vector<gd::DependencyMetadata>& GetAllDependencies() const {
return dependencies;
};
///@}
/** \name Serialization

View File

@@ -134,8 +134,19 @@ void InitialInstancesContainer::MoveInstancesToLayer(
}
}
std::size_t InitialInstancesContainer::GetLayerInstancesCount(
const gd::String &layerName) const {
std::size_t count = 0;
for (const gd::InitialInstance &instance : initialInstances) {
if (instance.GetLayer() == layerName) {
count++;
}
}
return count;
}
bool InitialInstancesContainer::SomeInstancesAreOnLayer(
const gd::String& layerName) {
const gd::String& layerName) const {
return std::any_of(initialInstances.begin(),
initialInstances.end(),
[&layerName](const InitialInstance& currentInstance) {
@@ -144,7 +155,7 @@ bool InitialInstancesContainer::SomeInstancesAreOnLayer(
}
bool InitialInstancesContainer::HasInstancesOfObject(
const gd::String& objectName) {
const gd::String& objectName) const {
return std::any_of(initialInstances.begin(),
initialInstances.end(),
[&objectName](const InitialInstance& currentInstance) {

View File

@@ -4,8 +4,8 @@
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_INITIALINSTANCESCONTAINER_H
#define GDCORE_INITIALINSTANCESCONTAINER_H
#pragma once
#include <list>
#include "GDCore/Project/InitialInstance.h"
#include "GDCore/String.h"
@@ -54,7 +54,6 @@ class GD_CORE_API InitialInstancesContainer {
return new InitialInstancesContainer(*this);
};
#if defined(GD_IDE_ONLY)
/**
* Must construct the class from the source
* A such method is needed as the IDE may want to store copies of some
@@ -71,7 +70,6 @@ class GD_CORE_API InitialInstancesContainer {
* from an object which is not a MyContainer"; } \endcode
*/
void Create(const InitialInstancesContainer &source);
#endif
/** \name Instances management
* Members functions related to managing the instances
@@ -100,7 +98,6 @@ class GD_CORE_API InitialInstancesContainer {
void IterateOverInstancesWithZOrdering(InitialInstanceFunctor &func,
const gd::String &layer);
#if defined(GD_IDE_ONLY)
/**
* \brief Insert the specified \a instance into the list and return a
* a reference to the newly added instance.
@@ -140,22 +137,27 @@ class GD_CORE_API InitialInstancesContainer {
void RenameInstancesOfObject(const gd::String &oldName,
const gd::String &newName);
/**
* \brief Return the number of instances on the layer named \a layerName.
*/
std::size_t GetLayerInstancesCount(const gd::String &layerName) const;
/**
* \brief Return true if there is at least one instance on the layer named \a
* layerName.
*/
bool SomeInstancesAreOnLayer(const gd::String &layerName);
bool SomeInstancesAreOnLayer(const gd::String &layerName) const;
/**
* \brief Return true if there is at least one instance of the given object.
*/
bool HasInstancesOfObject(const gd::String &objectName);
bool HasInstancesOfObject(const gd::String &objectName) const;
/**
* \brief Remove all instances
*/
void Clear();
#endif
///@}
/** \name Saving and loading
@@ -163,12 +165,10 @@ class GD_CORE_API InitialInstancesContainer {
*/
///@{
#if defined(GD_IDE_ONLY)
/**
* \brief Serialize instances container.
*/
virtual void SerializeTo(SerializerElement &element) const;
#endif
/**
* \brief Unserialize the instances container.
@@ -265,5 +265,3 @@ class GD_CORE_API HighestZOrderFinder : public gd::InitialInstanceFunctor {
};
} // namespace gd
#endif // GDCORE_INITIALINSTANCESCONTAINER_H

View File

@@ -507,6 +507,81 @@ gd::String GD_CORE_API GetTypeOfObject(const gd::ObjectsContainer& project,
return type;
}
void GD_CORE_API FilterBehaviorNamesFromObject(
const gd::Object &object, const gd::String &behaviorType,
std::vector<gd::String> &behaviorNames) {
for (size_t i = 0; i < behaviorNames.size(); i++) {
auto &behaviorName = behaviorNames[i];
if (!object.HasBehaviorNamed(behaviorName) ||
object.GetBehavior(behaviorName).GetTypeName() != behaviorType) {
behaviorNames.erase(behaviorNames.begin() + i);
}
}
}
std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
const gd::ObjectsContainer &project, const gd::ObjectsContainer &layout,
const gd::String &objectOrGroupName, const gd::String &behaviorType,
bool searchInGroups) {
// Search in objects
if (layout.HasObjectNamed(objectOrGroupName)) {
auto &object = layout.GetObject(objectOrGroupName);
auto behaviorNames = object.GetAllBehaviorNames();
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
return behaviorNames;
}
if (project.HasObjectNamed(objectOrGroupName)) {
auto &object = project.GetObject(objectOrGroupName);
auto behaviorNames = object.GetAllBehaviorNames();
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
return behaviorNames;
}
if (!searchInGroups) {
std::vector<gd::String> behaviorNames;
return behaviorNames;
}
// Search in groups
const gd::ObjectsContainer *container;
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
container = &layout;
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
container = &project;
} else {
std::vector<gd::String> behaviorNames;
return behaviorNames;
}
const vector<gd::String> &groupsObjects =
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
// Empty groups don't contain any behavior.
if (groupsObjects.empty()) {
std::vector<gd::String> behaviorNames;
return behaviorNames;
}
auto behaviorNames = GetBehaviorNamesInObjectOrGroup(
project, layout, groupsObjects[0], behaviorType, false);
for (size_t i = 1; i < groupsObjects.size(); i++) {
auto &objectName = groupsObjects[i];
if (layout.HasObjectNamed(objectName)) {
auto &object = layout.GetObject(objectName);
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
return behaviorNames;
}
if (project.HasObjectNamed(objectName)) {
auto &object = project.GetObject(objectName);
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
return behaviorNames;
}
if (behaviorNames.size() == 0) {
return behaviorNames;
}
}
return behaviorNames;
}
bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
const gd::ObjectsContainer &layout,
const gd::String &objectOrGroupName,
@@ -520,6 +595,56 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
return project.GetObject(objectOrGroupName).HasBehaviorNamed(behaviorName);
}
if (!searchInGroups) {
return false;
}
// Search in groups
const gd::ObjectsContainer *container;
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
container = &layout;
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
container = &project;
} else {
return false;
}
const vector<gd::String> &groupsObjects =
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
// Empty groups don't contain any behavior.
if (groupsObjects.empty()) {
return false;
}
// Check that all objects have the behavior.
for (auto &&object : groupsObjects) {
if (!HasBehaviorInObjectOrGroup(project, layout, object, behaviorName,
false)) {
return false;
}
}
return true;
}
bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::String objectOrGroupName,
gd::String behaviorName,
bool searchInGroups) {
// Search in objects
if (layout.HasObjectNamed(objectOrGroupName)) {
auto &object = layout.GetObject(objectOrGroupName);
return object.HasBehaviorNamed(behaviorName) &&
object.GetBehavior(behaviorName).IsDefaultBehavior();
}
if (project.HasObjectNamed(objectOrGroupName)) {
auto &object = project.GetObject(objectOrGroupName);
return object.HasBehaviorNamed(behaviorName) &&
object.GetBehavior(behaviorName).IsDefaultBehavior();
}
if (!searchInGroups) {
return false;
}
// Search in groups
const gd::ObjectsContainer *container;
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
@@ -537,7 +662,7 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
}
// Check that all objects have the same type.
for (auto &&object : groupsObjects) {
if (!HasBehaviorInObjectOrGroup(project, layout, object, behaviorName,
if (!IsDefaultBehavior(project, layout, object, behaviorName,
false)) {
return false;
}
@@ -545,6 +670,54 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
return true;
}
gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
const gd::String& objectOrGroupName,
const gd::String& behaviorName,
bool searchInGroups) {
// Search in objects
if (layout.HasObjectNamed(objectOrGroupName)) {
auto &object = layout.GetObject(objectOrGroupName);
return object.HasBehaviorNamed(behaviorName) ?
object.GetBehavior(behaviorName).GetTypeName() : "";
}
if (project.HasObjectNamed(objectOrGroupName)) {
auto &object = project.GetObject(objectOrGroupName);
return object.HasBehaviorNamed(behaviorName) ?
object.GetBehavior(behaviorName).GetTypeName() : "";
}
if (!searchInGroups) {
return "";
}
// Search in groups
const gd::ObjectsContainer *container;
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
container = &layout;
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
container = &project;
} else {
return "";
}
const vector<gd::String> &groupsObjects =
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
// Empty groups don't contain any behavior.
if (groupsObjects.empty()) {
return "";
}
// Check that all objects have the behavior with the same type.
auto behaviorType = GetTypeOfBehaviorInObjectOrGroup(
project, layout, groupsObjects[0], behaviorName, false);
for (auto &&object : groupsObjects) {
if (GetTypeOfBehaviorInObjectOrGroup(project, layout, object, behaviorName,
false) != behaviorType) {
return "";
}
}
return behaviorType;
}
gd::String GD_CORE_API GetTypeOfBehavior(const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::String name,

View File

@@ -443,13 +443,39 @@ gd::String GD_CORE_API GetTypeOfObject(const ObjectsContainer& game,
gd::String objectName,
bool searchInGroups = true);
/**
* \brief Check if an object or all object of a group has a behavior.
* \brief Check if an object or all objects of a group has a behavior.
*/
bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
const gd::ObjectsContainer &layout,
const gd::String &objectOrGroupName,
const gd::String &behaviorName,
bool searchInGroups = true);
/**
* \brief Get the names of behavior of a given type if an object or all objects of a group has it.
*/
std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
const gd::ObjectsContainer &project, const gd::ObjectsContainer &layout,
const gd::String &objectOrGroupName, const gd::String &behaviorType,
bool searchInGroups);
/**
* \brief Check if a behavior is a default one or doesn't exist in an object or
* all objects of a group.
*/
bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::String objectOrGroupName,
gd::String behaviorName,
bool searchInGroups = true);
/**
* \brief Get the type of a behavior if an object or all objects of a group has it.
*/
gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
const gd::ObjectsContainer &layout,
const gd::String &objectOrGroupName,
const gd::String &behaviorName,
bool searchInGroups = true);
/**
* \brief Get a type from a behavior name
* @return Type of the behavior.

View File

@@ -134,7 +134,6 @@ void Object::UnserializeFrom(gd::Project& project,
objectVariables.UnserializeFrom(
element.GetChild("variables", 0, "Variables"));
behaviors.clear();
if (element.HasChild("effects")) {
const SerializerElement& effectsElement = element.GetChild("effects");
@@ -210,6 +209,11 @@ void Object::SerializeTo(SerializerElement& element) const {
std::vector<gd::String> allBehaviors = GetAllBehaviorNames();
for (std::size_t i = 0; i < allBehaviors.size(); ++i) {
const gd::Behavior& behavior = GetBehavior(allBehaviors[i]);
// Default behaviors are added at the object creation according to metadata.
// They don't need to be serialized.
if (behavior.IsDefaultBehavior()) {
continue;
}
SerializerElement& behaviorElement = behaviorsElement.AddChild("behavior");
behavior.SerializeTo(behaviorElement);

View File

@@ -15,13 +15,12 @@
#include <vector>
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Parsers/GrammarTerminals.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/Events/UsedExtensionsFinder.h"
#include "GDCore/IDE/PlatformManager.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/Project/CustomObjectConfiguration.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/ExternalEvents.h"
@@ -49,6 +48,11 @@ using namespace std;
namespace gd {
// By default, disallow unicode in identifiers, but this can be set to true
// by the IDE. In the future, this will be set to true by default, keeping backward compatibility.
// We keep it disabled by default to progressively ask users to test it in real projects.
bool Project::allowUsageOfUnicodeIdentifierNames = false;
Project::Project()
: name(_("Project")),
version("1.0.0"),
@@ -82,9 +86,47 @@ Project::~Project() {}
void Project::ResetProjectUuid() { projectUuid = UUID::MakeUuid4(); }
std::unique_ptr<gd::Object> Project::CreateObject(
const gd::String& type, const gd::String& name) const {
return gd::make_unique<Object>(name, type, CreateObjectConfiguration(type));
std::unique_ptr<gd::Object>
Project::CreateObject(const gd::String &objectType, const gd::String &name) const {
std::unique_ptr<gd::Object> object =
gd::make_unique<Object>(name, objectType, CreateObjectConfiguration(objectType));
auto &platform = GetCurrentPlatform();
auto &project = *this;
auto addDefaultBehavior =
[&platform,
&project,
&object,
&objectType](const gd::String& behaviorType) {
auto &behaviorMetadata =
gd::MetadataProvider::GetBehaviorMetadata(platform, behaviorType);
if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
gd::LogWarning("Object: " + objectType + " has an unknown default behavior: " + behaviorType);
return;
}
auto* behavior = object->AddNewBehavior(project, behaviorType,
behaviorMetadata.GetDefaultName());
behavior->SetDefaultBehavior(true);
};
if (Project::HasEventsBasedObject(objectType)) {
addDefaultBehavior("EffectCapability::EffectBehavior");
addDefaultBehavior("ResizableCapability::ResizableBehavior");
addDefaultBehavior("ScalableCapability::ScalableBehavior");
addDefaultBehavior("FlippableCapability::FlippableBehavior");
}
else {
auto &objectMetadata = gd::MetadataProvider::GetObjectMetadata(platform, objectType);
if (MetadataProvider::IsBadObjectMetadata(objectMetadata)) {
gd::LogWarning("Object: " + name + " has an unknown type: " + objectType);
}
for (auto &behaviorType : objectMetadata.GetDefaultBehaviors()) {
addDefaultBehavior(behaviorType);
}
}
return std::move(object);
}
std::unique_ptr<gd::ObjectConfiguration> Project::CreateObjectConfiguration(
@@ -630,8 +672,10 @@ void Project::UnserializeFrom(const SerializerElement& element) {
SetAdaptGameResolutionAtRuntime(
propElement.GetBoolAttribute("adaptGameResolutionAtRuntime", false));
SetSizeOnStartupMode(propElement.GetStringAttribute("sizeOnStartupMode", ""));
SetAntialiasingMode(propElement.GetStringAttribute("antialiasingMode", "MSAA"));
SetAntialisingEnabledOnMobile(propElement.GetBoolAttribute("antialisingEnabledOnMobile", false));
SetAntialiasingMode(
propElement.GetStringAttribute("antialiasingMode", "MSAA"));
SetAntialisingEnabledOnMobile(
propElement.GetBoolAttribute("antialisingEnabledOnMobile", false));
SetProjectUuid(propElement.GetStringAttribute("projectUuid", ""));
SetAuthor(propElement.GetChild("author", 0, "Auteur").GetValue().GetString());
SetPackageName(propElement.GetStringAttribute("packageName"));
@@ -887,7 +931,8 @@ void Project::SerializeTo(SerializerElement& element) const {
adaptGameResolutionAtRuntime);
propElement.SetAttribute("sizeOnStartupMode", sizeOnStartupMode);
propElement.SetAttribute("antialiasingMode", antialiasingMode);
propElement.SetAttribute("antialisingEnabledOnMobile", isAntialisingEnabledOnMobile);
propElement.SetAttribute("antialisingEnabledOnMobile",
isAntialisingEnabledOnMobile);
propElement.SetAttribute("projectUuid", projectUuid);
propElement.SetAttribute("folderProject", folderProject);
propElement.SetAttribute("packageName", packageName);
@@ -993,58 +1038,57 @@ void Project::SerializeTo(SerializerElement& element) const {
externalSourceFilesElement.AddChild("sourceFile"));
}
bool Project::ValidateName(const gd::String& name) {
void Project::AllowUsageOfUnicodeIdentifierNames(bool enable) {
allowUsageOfUnicodeIdentifierNames = enable;
}
bool Project::IsNameSafe(const gd::String& name) {
if (name.empty()) return false;
if (isdigit(name[0])) return false;
gd::String allowedCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
return !(name.find_first_not_of(allowedCharacters) != gd::String::npos);
if (!allowUsageOfUnicodeIdentifierNames) {
gd::String legacyAllowedCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
return !(name.find_first_not_of(legacyAllowedCharacters) != gd::String::npos);
} else {
for (auto character : name) {
if (!GrammarTerminals::IsAllowedInIdentifier(character)) {
return false;
}
}
return true;
}
}
void Project::ExposeResources(gd::ArbitraryResourceWorker& worker) {
// See also gd::ProjectBrowserHelper::ExposeProjectEvents for a method that
// traverse the whole project (this time for events) and ExposeProjectEffects
// (this time for effects). Ideally, this method could be moved outside of
// gd::Project.
gd::String Project::GetSafeName(const gd::String& name) {
if (name.empty()) return "Unnamed";
gd::ResourcesManager* resourcesManager = &GetResourcesManager();
gd::String newName = name;
// Add project resources
worker.ExposeResources(resourcesManager);
platformSpecificAssets.ExposeResources(worker);
if (isdigit(name[0])) newName = "_" + newName;
// 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).GetConfiguration().ExposeResources(worker);
}
gd::String legacyAllowedCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
LaunchResourceWorkerOnEvents(*this, GetLayout(s).GetEvents(), worker);
}
// Add external events resources
for (std::size_t s = 0; s < GetExternalEventsCount(); s++) {
LaunchResourceWorkerOnEvents(
*this, GetExternalEvents(s).GetEvents(), worker);
}
// Add events functions extensions resources
for (std::size_t e = 0; e < GetEventsFunctionsExtensionsCount(); e++) {
auto& eventsFunctionsExtension = GetEventsFunctionsExtension(e);
for (auto&& eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
LaunchResourceWorkerOnEvents(*this, eventsFunction->GetEvents(), worker);
for (size_t i = 0;i < newName.size();++i) {
// Note that iterating on the characters is not super efficient (O(n^2), which
// could be avoided with an iterator), but this function is not critical for performance
// (only used to generate a name when a user creates a new entity or rename one).
auto character = newName[i];
bool isAllowed =
allowUsageOfUnicodeIdentifierNames
? GrammarTerminals::IsAllowedInIdentifier(character)
: legacyAllowedCharacters.find(character) != gd::String::npos;
// Replace all unallowed letters by an underscore.
if (!isAllowed) {
newName.replace(i, 1, '_');
}
}
// Add global objects resources
for (std::size_t j = 0; j < GetObjectsCount(); ++j) {
GetObject(j).GetConfiguration().ExposeResources(worker);
}
// Add loading screen background image if present
if (loadingScreen.GetBackgroundImageResourceName() != "")
worker.ExposeImage(loadingScreen.GetBackgroundImageResourceName());
return newName;
}
bool Project::HasSourceFile(gd::String name, gd::String language) const {

View File

@@ -942,16 +942,6 @@ class GD_CORE_API Project : public ObjectsContainer {
*/
ResourcesManager& GetResourcesManager() { return resourcesManager; }
/**
* \brief Called ( e.g. during compilation ) so as to inventory internal
* resources, sometimes update their filename or any other work or resources.
*
* See WholeProjectRefactorer for the same thing for events.
*
* \see WholeProjectRefactorer
* \see ArbitraryResourceWorker
*/
void ExposeResources(gd::ArbitraryResourceWorker& worker);
///@}
/** \name Variable management
@@ -975,15 +965,35 @@ class GD_CORE_API Project : public ObjectsContainer {
///@}
/** \name Other
/** \name Identifier names
*/
///@{
/**
* Check if unicode names are allowed in identifier names.
* \see IsNameSafe
* \see GetSafeName
*/
static bool IsUsageOfUnicodeIdentifierNamesAllowed() { return allowUsageOfUnicodeIdentifierNames; };
/**
* Set if unicode names are allowed in identifier names.
* \see IsNameSafe
* \see GetSafeName
*/
static void AllowUsageOfUnicodeIdentifierNames(bool enable);
/**
* Return true if \a name is valid (can be used safely for an object,
* behavior, events function name, etc...).
*/
static bool ValidateName(const gd::String& name);
static bool IsNameSafe(const gd::String& name);
/**
* Return a name, based on the one passed in parameter, that can be safely used
* for an object, behavior, events function name, etc...
*/
static gd::String GetSafeName(const gd::String& name);
///@}
/** \name External source files
@@ -1118,6 +1128,8 @@ class GD_CORE_API Project : public ObjectsContainer {
///< time the project was saved.
mutable unsigned int gdBuildVersion; ///< The GD build version used the last
///< time the project was saved.
static bool allowUsageOfUnicodeIdentifierNames;
};
} // namespace gd

View File

@@ -251,26 +251,26 @@ String& String::replace_if(iterator i1, iterator i2, std::function<bool(char32_t
return *this;
}
String& String::RemoveConsecutiveOccurrences(iterator i1, iterator i2, const char c)
{
std::vector<std::pair<size_type, size_type>> ranges_to_remove;
for(iterator current_index = i1.base(); current_index < i2.base(); current_index++)
{
if (*current_index == c){
iterator current_subindex = current_index;
std::advance(current_subindex, 1);
if (*current_subindex == c) {
while(current_subindex < end() && *current_subindex == c)
{
current_subindex++;
}
replace(std::distance(begin(), current_index),
std::distance(current_index, current_subindex),
c);
std::advance(current_index, 1);
}
String &String::RemoveConsecutiveOccurrences(iterator i1,
iterator i2,
const char c) {
iterator end = i2;
for (iterator current_index = i1.base(); current_index < end.base();
current_index++) {
if (*current_index == c) {
iterator current_subindex = current_index;
current_subindex++;
while (current_subindex < end.base() && *current_subindex == c) {
current_subindex++;
}
difference_type difference_to_replace =
std::distance(current_index, current_subindex);
if (difference_to_replace > 1) {
replace(
std::distance(begin(), current_index), difference_to_replace, c);
std::advance(end, -(difference_to_replace - 1));
}
}
}
return *this;
}
@@ -686,6 +686,16 @@ String GD_CORE_API operator+(const char *lhs, const String &rhs)
return str;
}
const String& GD_CORE_API operator||(const String& lhs, const String &rhs)
{
return lhs.empty() ? rhs : lhs;
}
String GD_CORE_API operator||(String lhs, const char *rhs)
{
return lhs.empty() ? rhs : lhs;
}
bool GD_CORE_API operator==( const String &lhs, const String &rhs )
{
return (lhs.compare(rhs) == 0);

View File

@@ -699,6 +699,10 @@ String GD_CORE_API operator+(String lhs, const char *rhs);
*/
String GD_CORE_API operator+(const char *lhs, const String &rhs);
const String& GD_CORE_API operator||(const String &lhs, const String &rhs);
String GD_CORE_API operator||(String lhs, const char *rhs);
/**
* \}
*/

View File

@@ -22,6 +22,10 @@
#include "DummyPlatform.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
#include "catch.hpp"
#include "GDCore/IDE/ResourceExposer.h"
#include "GDCore/Project/Effect.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/ExternalEvents.h"
class ArbitraryResourceWorkerTest : public gd::ArbitraryResourceWorker {
public:
@@ -55,7 +59,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
"res4", "path/to/file4.png", "audio");
ArbitraryResourceWorkerTest worker;
project.ExposeResources(worker);
gd::ResourceExposer::ExposeWholeProjectResources(project, worker);
REQUIRE(worker.files.size() == 4);
REQUIRE(std::find(worker.files.begin(),
worker.files.end(),
@@ -78,7 +82,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
worker.files.clear();
worker.images.clear();
project.ExposeResources(worker);
gd::ResourceExposer::ExposeWholeProjectResources(project, worker);
REQUIRE(worker.files.size() == 4);
REQUIRE(worker.images.size() == 1);
REQUIRE(worker.images[0] == "res1");
@@ -124,7 +128,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
standardEvent.GetActions().Insert(instruction);
layout.GetEvents().InsertEvent(standardEvent);
project.ExposeResources(worker);
gd::ResourceExposer::ExposeWholeProjectResources(project, worker);
REQUIRE(worker.bitmapFonts.size() == 1);
REQUIRE(worker.bitmapFonts[0] == "res3");
REQUIRE(worker.images.size() == 1);
@@ -132,4 +136,207 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
REQUIRE(worker.audios.size() == 1);
REQUIRE(worker.audios[0] == "res4");
}
SECTION("Can find resource usage in external events") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
project.GetResourcesManager().AddResource(
"res1", "path/to/file1.png", "image");
project.GetResourcesManager().AddResource(
"res2", "path/to/file2.png", "image");
project.GetResourcesManager().AddResource(
"res3", "path/to/file3.fnt", "bitmapFont");
project.GetResourcesManager().AddResource(
"res4", "path/to/file4.png", "audio");
ArbitraryResourceWorkerTest worker;
auto& externalEvents = project.InsertNewExternalEvents("MyExternalEvents", 0);
gd::StandardEvent standardEvent;
gd::Instruction instruction;
instruction.SetType("MyExtension::DoSomethingWithResources");
instruction.SetParametersCount(3);
instruction.SetParameter(0, "res3");
instruction.SetParameter(1, "res1");
instruction.SetParameter(2, "res4");
standardEvent.GetActions().Insert(instruction);
externalEvents.GetEvents().InsertEvent(standardEvent);
// MyExternalEvents doesn't need to be used in any layout events.
gd::ResourceExposer::ExposeWholeProjectResources(project, worker);
REQUIRE(worker.bitmapFonts.size() == 1);
REQUIRE(worker.bitmapFonts[0] == "res3");
REQUIRE(worker.images.size() == 1);
REQUIRE(worker.images[0] == "res1");
REQUIRE(worker.audios.size() == 1);
REQUIRE(worker.audios[0] == "res4");
}
SECTION("Can find resource usage in event-based functions") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
project.GetResourcesManager().AddResource(
"res1", "path/to/file1.png", "image");
project.GetResourcesManager().AddResource(
"res2", "path/to/file2.png", "image");
project.GetResourcesManager().AddResource(
"res3", "path/to/file3.png", "image");
ArbitraryResourceWorkerTest worker;
auto& extension = project.InsertNewEventsFunctionsExtension("MyEventExtention", 0);
auto& function = extension.InsertNewEventsFunction("MyFreeFunction", 0);
gd::StandardEvent standardEvent;
gd::Instruction instruction;
instruction.SetType("MyExtension::DoSomethingWithResources");
instruction.SetParametersCount(3);
instruction.SetParameter(0, "res3");
instruction.SetParameter(1, "res1");
instruction.SetParameter(2, "res4");
standardEvent.GetActions().Insert(instruction);
function.GetEvents().InsertEvent(standardEvent);
// MyEventExtention::MyFreeFunction doesn't need to be actually used in events.
gd::ResourceExposer::ExposeWholeProjectResources(project, worker);
REQUIRE(worker.bitmapFonts.size() == 1);
REQUIRE(worker.bitmapFonts[0] == "res3");
REQUIRE(worker.images.size() == 1);
REQUIRE(worker.images[0] == "res1");
REQUIRE(worker.audios.size() == 1);
REQUIRE(worker.audios[0] == "res4");
}
SECTION("Can find resource usage in event-based behavior functions") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
project.GetResourcesManager().AddResource(
"res1", "path/to/file1.png", "image");
project.GetResourcesManager().AddResource(
"res2", "path/to/file2.png", "image");
project.GetResourcesManager().AddResource(
"res3", "path/to/file3.png", "image");
ArbitraryResourceWorkerTest worker;
auto& extension = project.InsertNewEventsFunctionsExtension("MyEventExtention", 0);
auto& behavior = extension.GetEventsBasedBehaviors().InsertNew("MyBehavior", 0);
auto& function = behavior.GetEventsFunctions().InsertNewEventsFunction("MyFunction", 0);
gd::StandardEvent standardEvent;
gd::Instruction instruction;
instruction.SetType("MyExtension::DoSomethingWithResources");
instruction.SetParametersCount(3);
instruction.SetParameter(0, "res3");
instruction.SetParameter(1, "res1");
instruction.SetParameter(2, "res4");
standardEvent.GetActions().Insert(instruction);
function.GetEvents().InsertEvent(standardEvent);
// MyEventExtention::MyBehavior::MyFunction doesn't need to be actually used in events.
gd::ResourceExposer::ExposeWholeProjectResources(project, worker);
REQUIRE(worker.bitmapFonts.size() == 1);
REQUIRE(worker.bitmapFonts[0] == "res3");
REQUIRE(worker.images.size() == 1);
REQUIRE(worker.images[0] == "res1");
REQUIRE(worker.audios.size() == 1);
REQUIRE(worker.audios[0] == "res4");
}
SECTION("Can find resource usage in event-based object functions") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
project.GetResourcesManager().AddResource(
"res1", "path/to/file1.png", "image");
project.GetResourcesManager().AddResource(
"res2", "path/to/file2.png", "image");
project.GetResourcesManager().AddResource(
"res3", "path/to/file3.png", "image");
ArbitraryResourceWorkerTest worker;
auto& extension = project.InsertNewEventsFunctionsExtension("MyEventExtention", 0);
auto& object = extension.GetEventsBasedObjects().InsertNew("MyObject", 0);
auto& function = object.GetEventsFunctions().InsertNewEventsFunction("MyFunction", 0);
gd::StandardEvent standardEvent;
gd::Instruction instruction;
instruction.SetType("MyExtension::DoSomethingWithResources");
instruction.SetParametersCount(3);
instruction.SetParameter(0, "res3");
instruction.SetParameter(1, "res1");
instruction.SetParameter(2, "res4");
standardEvent.GetActions().Insert(instruction);
function.GetEvents().InsertEvent(standardEvent);
// MyEventExtention::MyObject::MyFunction doesn't need to be actually used in events.
gd::ResourceExposer::ExposeWholeProjectResources(project, worker);
REQUIRE(worker.bitmapFonts.size() == 1);
REQUIRE(worker.bitmapFonts[0] == "res3");
REQUIRE(worker.images.size() == 1);
REQUIRE(worker.images[0] == "res1");
REQUIRE(worker.audios.size() == 1);
REQUIRE(worker.audios[0] == "res4");
}
SECTION("Can find resource usage in layer effects") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
project.GetResourcesManager().AddResource(
"res1", "path/to/file1.png", "image");
project.GetResourcesManager().AddResource(
"res2", "path/to/file2.png", "image");
project.GetResourcesManager().AddResource(
"res3", "path/to/file3.png", "image");
ArbitraryResourceWorkerTest worker;
auto& layout = project.InsertNewLayout("Scene", 0);
layout.InsertNewLayer("MyLayer", 0);
auto& layer = layout.GetLayer("MyLayer");
auto& effect = layer.GetEffects().InsertNewEffect("MyEffect", 0);
effect.SetEffectType("MyExtension::EffectWithResource");
effect.SetStringParameter("texture", "res1");
gd::ResourceExposer::ExposeWholeProjectResources(project, worker);
REQUIRE(worker.files.size() == 3);
REQUIRE(worker.images.size() == 1);
REQUIRE(worker.images[0] == "res1");
}
SECTION("Can find resource usage in object effects") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
project.GetResourcesManager().AddResource(
"res1", "path/to/file1.png", "image");
project.GetResourcesManager().AddResource(
"res2", "path/to/file2.png", "image");
project.GetResourcesManager().AddResource(
"res3", "path/to/file3.png", "image");
ArbitraryResourceWorkerTest worker;
auto& layout = project.InsertNewLayout("Scene", 0);
layout.InsertNewLayer("MyLayer", 0);
auto& layer = layout.GetLayer("MyLayer");
auto& object = layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto& effect = object.GetEffects().InsertNewEffect("MyEffect", 0);
effect.SetEffectType("MyExtension::EffectWithResource");
effect.SetStringParameter("texture", "res1");
gd::ResourceExposer::ExposeWholeProjectResources(project, worker);
REQUIRE(worker.files.size() == 3);
REQUIRE(worker.images.size() == 1);
REQUIRE(worker.images[0] == "res1");
}
}

View File

@@ -113,17 +113,6 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
auto& baseObject = baseObjectExtension->AddObject<gd::ObjectConfiguration>(
"", "Dummy Base Object", "Dummy Base Object", "");
// Add this expression for all objects. But it requires a "capability".
baseObject
.AddStrExpression("GetSomethingRequiringEffectCapability",
"Get something, but this requires the effect capability for the object.",
"",
"",
"")
.AddParameter("object", _("Object"), "")
.AddParameter("expression", _("Number parameter"))
.SetRequiresBaseObjectCapability("effect")
.SetFunctionName("getSomethingRequiringEffectCapability");
baseObject
.AddExpression("GetFromBaseExpression",
"This works on any object.",
@@ -133,6 +122,84 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
.AddParameter("object", _("Object"), "")
.SetFunctionName("getFromBaseExpression");
// Declare default behaviors that are used by event-based objects to avoid
// warnings.
{
std::shared_ptr<gd::PlatformExtension> extension =
std::shared_ptr<gd::PlatformExtension>(new gd::PlatformExtension);
extension
->SetExtensionInformation("ResizableCapability",
_("Resizable capability"),
_("Change the object dimensions."),
"", "");
gd::BehaviorMetadata& aut = extension->AddBehavior(
"ResizableBehavior",
_("Resizable capability"),
"Resizable",
_("Change the object dimensions."),
"", "", "",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetHidden();
platform.AddExtension(extension);
}
{
std::shared_ptr<gd::PlatformExtension> extension =
std::shared_ptr<gd::PlatformExtension>(new gd::PlatformExtension);
extension
->SetExtensionInformation("ScalableCapability",
_("Scalable capability"),
_("Change the object scale."),
"", "");
gd::BehaviorMetadata& aut = extension->AddBehavior(
"ScalableBehavior",
_("Scalable capability"),
"Scale",
_("Change the object scale."),
"", "", "",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetHidden();
platform.AddExtension(extension);
}
{
std::shared_ptr<gd::PlatformExtension> extension =
std::shared_ptr<gd::PlatformExtension>(new gd::PlatformExtension);
extension
->SetExtensionInformation("FlippableCapability",
_("Flippable capability"),
_("Flip objects."),
"", "");
gd::BehaviorMetadata& aut = extension->AddBehavior(
"FlippableBehavior",
_("Flippable capability"),
"Flippable",
_("Flip objects."),
"", "", "",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetHidden();
platform.AddExtension(extension);
}
{
std::shared_ptr<gd::PlatformExtension> extension =
std::shared_ptr<gd::PlatformExtension>(new gd::PlatformExtension);
extension
->SetExtensionInformation("EffectCapability",
_("Effect capability"),
_("Apply visual effects to objects."),
"", "");
gd::BehaviorMetadata& aut = extension->AddBehavior(
"EffectBehavior",
_("Effect capability"),
"Effect",
_("Apply visual effects to objects."),
"", "", "",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetHidden();
platform.AddExtension(extension);
}
// Create an extension with various stuff inside.
std::shared_ptr<gd::PlatformExtension> extension =
std::shared_ptr<gd::PlatformExtension>(new gd::PlatformExtension);
@@ -396,14 +463,53 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
gd::make_unique<gd::BehaviorsSharedData>());
}
{
gd::BehaviorMetadata &effectBehavior =
extension
->AddBehavior("EffectBehavior",
_("Effect capability"),
"Effect",
_("Apply visual effects to objects."),
"",
"res/actions/effect24.png", "EffectBehavior",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetHidden();
// Add this expression for the effect capability.
effectBehavior
.AddStrExpression("GetSomethingRequiringEffectCapability",
"Get something, but this requires the effect "
"capability for the object.",
"",
"",
"")
.AddParameter("object", _("Object"), "")
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("expression", _("Number parameter"))
.SetFunctionName("getSomethingRequiringEffectCapability");
}
{
auto& object = extension
->AddObject<gd::ObjectConfiguration>(
"FakeObjectWithUnsupportedCapability",
"FakeObjectWithUnsupportedCapability",
"This is FakeObjectWithUnsupportedCapability",
"FakeObjectWithDefaultBehavior",
"FakeObjectWithDefaultBehavior",
"This is FakeObjectWithDefaultBehavior",
"")
.AddUnsupportedBaseObjectCapability("effect");
.AddDefaultBehavior("MyExtension::EffectBehavior");
}
// Declare an event-based behavior to avoid warnings.
{
extension->AddBehavior("MyEventsBasedBehavior",
"My event-based behavior",
"MyEventsBasedBehavior",
"Avoid warnings",
"Group",
"Icon.png",
"MyEventsBasedBehavior",
gd::make_unique<gd::Behavior>(),
gd::make_unique<gd::BehaviorsSharedData>());
}
// Actions and expressions with several parameter types.
@@ -465,6 +571,17 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
.AddParameter("layerEffectParameterName", _("Parameter name"));
}
{
auto& effect = extension
->AddEffect("EffectWithResource")
.SetFullName("Effect with resource")
.MarkAsOnlyWorkingFor2D();
auto& effectProperties = effect.GetProperties();
effectProperties["texture"]
.SetType("resource")
.AddExtraInfo("image");
}
platform.AddExtension(commonInstructionsExtension);
platform.AddExtension(baseObjectExtension);
platform.AddExtension(extension);

View File

@@ -24,13 +24,13 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
layout1.InsertNewObject(
project, "MyExtension::Sprite", "MyOtherSpriteObject", 1);
layout1.InsertNewObject(project,
"MyExtension::FakeObjectWithUnsupportedCapability",
"MyFakeObjectWithUnsupportedCapability",
"MyExtension::FakeObjectWithDefaultBehavior",
"FakeObjectWithDefaultBehavior",
2);
auto &group = layout1.GetObjectGroups().InsertNew("AllObjects");
group.AddObject("MySpriteObject");
group.AddObject("MyOtherSpriteObject");
group.AddObject("MyFakeObjectWithUnsupportedCapability");
group.AddObject("FakeObjectWithDefaultBehavior");
gd::ExpressionParser2 parser;
@@ -342,7 +342,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
SECTION("supported capability") {
// Capability is supported, so the expression is valid.
auto node = parser.ParseExpression(
"MySpriteObject.GetSomethingRequiringEffectCapability(123)");
"FakeObjectWithDefaultBehavior.Effect::GetSomethingRequiringEffectCapability(123)");
gd::ExpressionCodeGenerator expressionCodeGenerator("string",
"",
codeGenerator,
@@ -352,12 +352,12 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
node->Visit(expressionCodeGenerator);
REQUIRE(
expressionCodeGenerator.GetOutput() ==
"MySpriteObject.getSomethingRequiringEffectCapability(123) ?? \"\"");
"FakeObjectWithDefaultBehavior::Effect.getSomethingRequiringEffectCapability(123) ?? \"\"");
}
SECTION("unsupported capability") {
// Capability is not supported, so the expression is not even valid.
auto node =
parser.ParseExpression("MyFakeObjectWithUnsupportedCapability."
parser.ParseExpression("MySpriteObject::Effect."
"GetSomethingRequiringEffectCapability(123)");
gd::ExpressionCodeGenerator expressionCodeGenerator("string",
"",
@@ -366,14 +366,16 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "\"\"");
REQUIRE(
expressionCodeGenerator.GetOutput() ==
"/* Error during generation, function not found: GetSomethingRequiringEffectCapability */ \"\"");
}
SECTION("group with partial support") {
// We use a group, capability is supported only by one object of the
// group. The expression itself is valid, but code generation should skip
// the objects with unsupported capability.
auto node = parser.ParseExpression(
"AllObjects.GetSomethingRequiringEffectCapability(123)");
"AllObjects.Effect::GetSomethingRequiringEffectCapability(123)");
gd::ExpressionCodeGenerator expressionCodeGenerator("string",
"",
codeGenerator,
@@ -381,10 +383,13 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(
expressionCodeGenerator.GetOutput() ==
"MyOtherSpriteObject.getSomethingRequiringEffectCapability(123) ?? "
"MySpriteObject.getSomethingRequiringEffectCapability(123) ?? \"\"");
REQUIRE(expressionCodeGenerator.GetOutput() ==
"FakeObjectWithDefaultBehavior::Effect."
"getSomethingRequiringEffectCapability(123) ?? "
"MyOtherSpriteObject::Effect."
"getSomethingRequiringEffectCapability(123) ?? "
"MySpriteObject::Effect.getSomethingRequiringEffectCapability("
"123) ?? \"\"");
}
}
SECTION("Function name") {

View File

@@ -21,16 +21,18 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
SetupProjectWithDummyPlatform(project, platform);
auto &layout1 = project.InsertNewLayout("Layout1", 0);
auto &myObject = layout1.InsertNewObject(project, "BuiltinObject", "MyObject", 0);
// Create an instance of BuiltinObject.
// This is not possible in practice.
auto &myObject = layout1.InsertNewObject(project, "", "MyObject", 0);
myObject.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
auto &myGroup = layout1.GetObjectGroups().InsertNew("MyGroup", 0);
myGroup.AddObject(myObject.GetName());
layout1.InsertNewObject(project, "MyExtension::Sprite", "MySpriteObject", 1);
layout1.InsertNewObject(project,
"MyExtension::FakeObjectWithUnsupportedCapability",
"MyFakeObjectWithUnsupportedCapability",
"MyExtension::FakeObjectWithDefaultBehavior",
"FakeObjectWithDefaultBehavior",
2);
gd::ExpressionParser2 parser;
@@ -340,6 +342,20 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
"Cannot find an expression with this name: Idontexist\n"
"Double check that you've not made any typo in the name.");
}
{
auto node = parser.ParseExpression("🅸🅳🅾🅽🆃🅴🆇🅸🆂🆃😄(\"hello\"");
REQUIRE(node != nullptr);
gd::ExpressionValidator validator(platform, project, layout1, "string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 2);
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
"The list of parameters is not terminated. Add a closing "
"parenthesis to end the parameters.");
REQUIRE(validator.GetFatalErrors()[1]->GetMessage() ==
"Cannot find an expression with this name: 🅸🅳🅾🅽🆃🅴🆇🅸🆂🆃😄\n"
"Double check that you've not made any typo in the name.");
}
{
auto node = parser.ParseExpression("=\"test\"");
REQUIRE(node != nullptr);
@@ -694,6 +710,17 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
"You must enter a number.");
REQUIRE(validator.GetFatalErrors()[0]->GetStartPosition() == 0);
}
{
auto node = parser.ParseExpression("ab😊d");
REQUIRE(node != nullptr);
gd::ExpressionValidator validator(platform, project, layout1, "number");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
"You must enter a number.");
REQUIRE(validator.GetFatalErrors()[0]->GetStartPosition() == 0);
}
{
auto node = parser.ParseExpression("abcd[0]");
REQUIRE(node != nullptr);
@@ -790,14 +817,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
gd::ExpressionValidator validator(platform, project, layout1, "number");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 3);
REQUIRE(validator.GetFatalErrors()[1]->GetMessage() ==
"No operator found. Did you forget to enter an operator (like +, "
"-, * or /) between numbers or expressions?");
REQUIRE(validator.GetFatalErrors()[1]->GetStartPosition() == 4);
// TODO Should error be removed?
REQUIRE(validator.GetFatalErrors()[2]->GetMessage() ==
"You must enter a number.");
REQUIRE(validator.GetFatalErrors().size() != 0);
}
{
auto node = parser.ParseExpression("123 ? 456");
@@ -805,10 +825,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
gd::ExpressionValidator validator(platform, project, layout1, "number");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
"You've used an operator that is not supported. Operator should be "
"either +, -, / or *.");
REQUIRE(validator.GetFatalErrors().size() != 0);
}
{
auto node = parser.ParseExpression("1//2");
@@ -917,6 +934,26 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 0);
}
{
auto node = parser.ParseExpression("😅");
REQUIRE(node != nullptr);
auto &identifierNode = dynamic_cast<gd::IdentifierNode &>(*node);
REQUIRE(identifierNode.identifierName == "😅");
gd::ExpressionValidator validator(platform, project, layout1, "object");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 0);
}
{
auto node = parser.ParseExpression("中文");
REQUIRE(node != nullptr);
auto &identifierNode = dynamic_cast<gd::IdentifierNode &>(*node);
REQUIRE(identifierNode.identifierName == "中文");
gd::ExpressionValidator validator(platform, project, layout1, "object");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 0);
}
{
auto node = parser.ParseExpression("Hello World 1");
@@ -1092,6 +1129,46 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
REQUIRE(textNode.text == "2");
REQUIRE(identifierNode.identifierName == "three");
}
SECTION("identifier parameter (unicode)") {
auto node = parser.ParseExpression(
"WhateverObject.WhateverBehavior::WhateverFunction(1, \"2\", 😄)");
REQUIRE(node != nullptr);
auto &functionNode = dynamic_cast<gd::FunctionCallNode &>(*node);
REQUIRE(functionNode.functionName == "WhateverFunction");
REQUIRE(functionNode.objectName == "WhateverObject");
REQUIRE(functionNode.behaviorName == "WhateverBehavior");
REQUIRE(functionNode.parameters.size() == 3);
auto &numberNode =
dynamic_cast<gd::NumberNode &>(*functionNode.parameters[0]);
auto &textNode =
dynamic_cast<gd::TextNode &>(*functionNode.parameters[1]);
auto &identifierNode =
dynamic_cast<gd::IdentifierNode &>(*functionNode.parameters[2]);
REQUIRE(numberNode.number == "1");
REQUIRE(textNode.text == "2");
REQUIRE(identifierNode.identifierName == "😄");
}
SECTION("unicode for object, behavior and function") {
auto node = parser.ParseExpression(
"🧸.🗣️::🔔(1, \"2\", 😄)");
REQUIRE(node != nullptr);
auto &functionNode = dynamic_cast<gd::FunctionCallNode &>(*node);
REQUIRE(functionNode.functionName == "🔔");
REQUIRE(functionNode.objectName == "🧸");
REQUIRE(functionNode.behaviorName == "🗣️");
REQUIRE(functionNode.parameters.size() == 3);
auto &numberNode =
dynamic_cast<gd::NumberNode &>(*functionNode.parameters[0]);
auto &textNode =
dynamic_cast<gd::TextNode &>(*functionNode.parameters[1]);
auto &identifierNode =
dynamic_cast<gd::IdentifierNode &>(*functionNode.parameters[2]);
REQUIRE(numberNode.number == "1");
REQUIRE(textNode.text == "2");
REQUIRE(identifierNode.identifierName == "😄");
}
}
SECTION("Valid function calls ('number|string' type)") {
@@ -1669,7 +1746,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
auto &identifierNode = dynamic_cast<gd::IdentifierNode &>(*node);
REQUIRE(identifierNode.identifierName == "myVariable");
REQUIRE(identifierNode.childIdentifierName == "myChild");
gd::ExpressionValidator validator(platform, project, layout1, "scenevar");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 0);
@@ -1766,14 +1843,14 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
REQUIRE(identifierObject2Node.identifierName == "MyObject2");
REQUIRE(variable1Node.identifierName == "MyVar1");
REQUIRE(variable2Node.identifierName == "MyVar2");
auto variable1ObjectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
platform, project, layout1, "", variable1Node);
REQUIRE(variable1ObjectName == "MyObject1");
auto variable2ObjectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
platform, project, layout1, "", variable2Node);
REQUIRE(variable2ObjectName == "MyObject2");
gd::ExpressionValidator validator(platform, project, layout1, "string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 0);
@@ -1797,14 +1874,14 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
REQUIRE(identifierObject1Node.identifierName == "MyObject1");
REQUIRE(variable1Node.identifierName == "MyVar1");
REQUIRE(variable2Node.identifierName == "MyVar2");
auto variable1ObjectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
platform, project, layout1, "", variable1Node);
REQUIRE(variable1ObjectName == "MyObject1");
auto variable2ObjectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
platform, project, layout1, "", variable2Node);
REQUIRE(variable2ObjectName == "MyObject1");
gd::ExpressionValidator validator(platform, project, layout1, "string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 0);
@@ -1821,11 +1898,11 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
dynamic_cast<gd::IdentifierNode &>(*functionNode.parameters[0]);
REQUIRE(variable1Node.identifierName == "MyVar1");
auto variable1ObjectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
platform, project, layout1, "MySpriteObject", variable1Node);
REQUIRE(variable1ObjectName == "MySpriteObject");
gd::ExpressionValidator validator(platform, project, layout1, "number");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 0);
@@ -1843,11 +1920,11 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
REQUIRE(variable1Node.identifierName == "MyVar1");
REQUIRE(variable1Node.childIdentifierName == "MyChild");
auto variable1ObjectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
platform, project, layout1, "MySpriteObject", variable1Node);
REQUIRE(variable1ObjectName == "MySpriteObject");
gd::ExpressionValidator validator(platform, project, layout1, "number");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 0);
@@ -1899,29 +1976,29 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
}
SECTION(
"Valid function call with an object expression requiring a capability") {
"Valid function call with a default behavior") {
auto node = parser.ParseExpression(
"MySpriteObject.GetSomethingRequiringEffectCapability(123)");
"FakeObjectWithDefaultBehavior.Effect::GetSomethingRequiringEffectCapability(123)");
REQUIRE(node != nullptr);
gd::ExpressionValidator validator(platform, project, layout1, "string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 0);
REQUIRE(validator.GetAllErrors().size() == 0);
}
SECTION(
"Invalid function call with an object expression requiring a "
"capability") {
"Invalid function call with an object that doesn't have a default behavior") {
auto node =
parser.ParseExpression("MyFakeObjectWithUnsupportedCapability."
parser.ParseExpression("MySpriteObject.Effect::"
"GetSomethingRequiringEffectCapability(123)");
REQUIRE(node != nullptr);
gd::ExpressionValidator validator(platform, project, layout1, "string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
"This expression exists, but it can't be used on this object.");
REQUIRE(validator.GetFatalErrors().size() == 0);
REQUIRE(validator.GetAllErrors().size() == 1);
REQUIRE(validator.GetAllErrors()[0]->GetMessage() ==
"This behavior is not attached to this object.");
}
SECTION("Fuzzy/random tests") {

133
Core/tests/Layout.cpp Normal file
View File

@@ -0,0 +1,133 @@
/*
* GDevelop Core
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
/**
* @file Tests covering layout content helper methods.
*/
#include "GDCore/Project/Layout.h"
#include "DummyPlatform.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/Project.h"
#include "catch.hpp"
using namespace gd;
namespace {
void SetupProject(gd::Project &project, gd::Platform &platform){
};
} // namespace
TEST_CASE("Layout", "[common]") {
SECTION("Find the type of a behavior in a object") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
object.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(project, layout, "MyObject",
"MyBehavior", true) ==
"MyExtension::MyBehavior");
}
SECTION("Give an empty type for an object that doesn't have the behavior") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(project, layout, "MyObject",
"MyBehavior", true) == "");
}
SECTION("Find the type of a behavior in a group") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
gd::Object &object2 =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject2", 0);
object2.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
auto &group = layout.GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(project, layout, "MyGroup",
"MyBehavior", true) ==
"MyExtension::MyBehavior");
}
SECTION("Give an empty type for a group with an object missing the behavior") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
gd::Object &object2 =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject2", 0);
// object2 doesn't have the behavior.
auto &group = layout.GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(project, layout, "MyGroup",
"MyBehavior", true) == "");
}
SECTION("Give an empty type for a group with behaviors of same name but different types") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
gd::Object &object2 =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject2", 0);
object2.AddNewBehavior(project, "MyExtension::MyOtherBehavior",
"MyBehavior");
auto &group = layout.GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(project, layout, "MyGroup",
"MyBehavior", true) == "");
}
SECTION("Give an empty type for an empty group") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
auto &group = layout.GetObjectGroups().InsertNew("MyGroup", 0);
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(project, layout, "MyGroup",
"MyBehavior", true) == "");
}
}

45
Core/tests/Object.cpp Normal file
View File

@@ -0,0 +1,45 @@
/*
* 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 "GDCore/Project/Object.h"
#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/Builtin/SpriteExtension/SpriteObject.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/CustomObjectConfiguration.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/Layout.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;
TEST_CASE("Object", "[common]") {
SECTION("Create an object with default behaviors") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.InsertNewObject(
project, "MyExtension::FakeObjectWithDefaultBehavior", "MyObject", 0);
REQUIRE(object.HasBehaviorNamed("Effect"));
REQUIRE(object.GetBehavior("Effect").IsDefaultBehavior());
}
}

View File

@@ -225,4 +225,41 @@ TEST_CASE("ObjectSerialization", "[common]") {
auto clonedObject = object.Clone();
CheckCustomObjectConfiguration(*(clonedObject.get()));
}
SECTION("Exclude default behaviors from serialization") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.InsertNewObject(
project, "MyExtension::FakeObjectWithDefaultBehavior", "MyObject", 0);
REQUIRE(object.HasBehaviorNamed("Effect"));
object.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
REQUIRE(object.HasBehaviorNamed("MyBehavior"));
SerializerElement projectElement;
project.SerializeTo(projectElement);
// Check serialized behaviors.
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);
auto &behaviorsElement = objectElement.GetChild("behaviors");
behaviorsElement.ConsiderAsArrayOf("behavior");
REQUIRE(behaviorsElement.GetChildrenCount() == 1);
auto &behaviorElement = behaviorsElement.GetChild(0);
REQUIRE(behaviorElement.GetStringAttribute("name") == "MyBehavior");
}
}

View File

@@ -16,6 +16,7 @@
#include "GDCore/Tools/SystemStats.h"
#include "GDCore/Tools/VersionWrapper.h"
#include "catch.hpp"
#include "GDCore/IDE/ResourceExposer.h"
class MockFileSystem : public gd::AbstractFileSystem {
public:
@@ -75,7 +76,7 @@ TEST_CASE("ResourcesMergingHelper", "[common]") {
project.GetResourcesManager().AddResource(
"Image3", "subfolder/image3.png", "image");
project.ExposeResources(resourcesMerger);
gd::ResourceExposer::ExposeWholeProjectResources(project, resourcesMerger);
auto resourcesFilenames =
resourcesMerger.GetAllResourcesOldAndNewFilename();
@@ -101,7 +102,7 @@ TEST_CASE("ResourcesMergingHelper", "[common]") {
project.GetResourcesManager().AddResource(
"Image3", "subfolder/image3.png", "image");
project.ExposeResources(resourcesMerger);
gd::ResourceExposer::ExposeWholeProjectResources(project, resourcesMerger);
auto resourcesFilenames =
resourcesMerger.GetAllResourcesOldAndNewFilename();

View File

@@ -11,6 +11,7 @@
#include "GDCore/CommonTools.h"
#include "GDCore/Project/Project.h"
#include "catch.hpp"
#include "GDCore/IDE/ResourceExposer.h"
TEST_CASE("ResourcesRenamer", "[common]") {
SECTION("It renames resources that are exposed") {
@@ -34,7 +35,7 @@ TEST_CASE("ResourcesRenamer", "[common]") {
project.GetPlatformSpecificAssets().Set(
"android", "some-other-icon", "Resource2");
project.ExposeResources(resourcesRenamer);
gd::ResourceExposer::ExposeWholeProjectResources(project, resourcesRenamer);
// Check that resources were renamed were used.
REQUIRE(project.GetPlatformSpecificAssets().Get("android", "some-icon") ==
@@ -72,7 +73,7 @@ TEST_CASE("ResourcesRenamer", "[common]") {
project.GetPlatformSpecificAssets().Set(
"android", "some-other-icon", "Resource2");
project.ExposeResources(resourcesRenamer);
gd::ResourceExposer::ExposeWholeProjectResources(project, resourcesRenamer);
// TODO: This should not be necessary, but for now not all resources support embeddeds,
// so we must call it manually:

39
Core/tests/String.cpp Normal file
View File

@@ -0,0 +1,39 @@
/*
* 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 String class of GDevelop Core.
*/
#include "GDCore/String.h"
#include <algorithm>
#include <initializer_list>
#include <map>
#include "GDCore/CommonTools.h"
#include "catch.hpp"
TEST_CASE("String", "[common]") {
SECTION("ReplaceConsecutiveOccurrences") {
gd::String str = " ";
REQUIRE(str.RemoveConsecutiveOccurrences(str.begin(), str.end(), ' ') ==
" ");
str = "L'opacité de NewSprite = \" \"";
REQUIRE(str.RemoveConsecutiveOccurrences(str.begin(), str.end(), ' ') ==
"L'opacité de NewSprite = \" \"");
str = "ccccccccc";
REQUIRE(str.RemoveConsecutiveOccurrences(str.begin(), str.end(), 'c') ==
"c");
str = "c";
REQUIRE(str.RemoveConsecutiveOccurrences(str.begin(), str.end(), 'c') ==
"c");
str = "";
REQUIRE(str.RemoveConsecutiveOccurrences(str.begin(), str.end(), ' ') ==
"");
str = "Set animation of NewSprite to ";
REQUIRE(str.RemoveConsecutiveOccurrences(str.begin(), str.end(), ' ') ==
"Set animation of NewSprite to ");
}
}

View File

@@ -3348,10 +3348,21 @@ const gd::Instruction &CreateActionWithLayerParameter(gd::Project &project,
action.SetParameter(3, gd::Expression("\"My layer\""));
return event.GetActions().Insert(action);
}
const gd::Instruction &CreateActionWithEmptyLayerParameter(gd::Project &project,
gd::EventsList &events) {
gd::StandardEvent &event = dynamic_cast<gd::StandardEvent &>(
events.InsertNewEvent(project, "BuiltinCommonInstructions::Standard"));
gd::Instruction action;
action.SetType("MyExtension::SetCameraCenterX");
action.SetParametersCount(4);
action.SetParameter(3, gd::Expression(""));
return event.GetActions().Insert(action);
}
const gd::Instruction &
CreateExpressionWithLayerParameter(gd::Project &project,
gd::EventsList &events) {
gd::EventsList &events,
const gd::String &layerName) {
gd::StandardEvent &event = dynamic_cast<gd::StandardEvent &>(
events.InsertNewEvent(project, "BuiltinCommonInstructions::Standard"));
@@ -3359,8 +3370,8 @@ CreateExpressionWithLayerParameter(gd::Project &project,
action.SetType("MyExtension::DoSomething");
action.SetParametersCount(1);
action.SetParameter(
0, gd::Expression("MyExtension::CameraCenterX(\"My layer\") + "
"MyExtension::CameraCenterX(\"My layer\")"));
0, gd::Expression("MyExtension::CameraCenterX(\"" + layerName + "\") + "
"MyExtension::CameraCenterX(\"" + layerName + "\")"));
return event.GetActions().Insert(action);
}
} // namespace
@@ -3390,13 +3401,13 @@ TEST_CASE("RenameLayer", "[common]") {
project, otherExternalEvents.GetEvents());
auto &layoutExpression =
CreateExpressionWithLayerParameter(project, layout.GetEvents());
CreateExpressionWithLayerParameter(project, layout.GetEvents(), "My layer");
auto &externalExpression =
CreateExpressionWithLayerParameter(project, externalEvents.GetEvents());
CreateExpressionWithLayerParameter(project, externalEvents.GetEvents(), "My layer");
auto &otherLayoutExpression =
CreateExpressionWithLayerParameter(project, otherLayout.GetEvents());
CreateExpressionWithLayerParameter(project, otherLayout.GetEvents(), "My layer");
auto &otherExternalExpression = CreateExpressionWithLayerParameter(
project, otherExternalEvents.GetEvents());
project, otherExternalEvents.GetEvents(), "My layer");
gd::WholeProjectRefactorer::RenameLayer(project, layout, "My layer",
"My renamed layer");
@@ -3434,7 +3445,7 @@ TEST_CASE("RenameLayer", "[common]") {
auto &layout = project.InsertNewLayout("My layout", 0);
auto &layoutExpression =
CreateExpressionWithLayerParameter(project, layout.GetEvents());
CreateExpressionWithLayerParameter(project, layout.GetEvents(), "My layer");
gd::WholeProjectRefactorer::RenameLayer(project, layout, "My layer",
"layerA");
@@ -3443,6 +3454,57 @@ TEST_CASE("RenameLayer", "[common]") {
"MyExtension::CameraCenterX(\"layerA\") + "
"MyExtension::CameraCenterX(\"layerA\")");
}
SECTION("Can rename a layer when a layer parameter is empty") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &layout = project.InsertNewLayout("My layout", 0);
auto &layoutAction =
CreateActionWithEmptyLayerParameter(project, layout.GetEvents());
gd::WholeProjectRefactorer::RenameLayer(project, layout, "My layer",
"layerA");
REQUIRE(layoutAction.GetParameter(0).GetPlainString() == "");
}
SECTION("Can't rename a layer to an empty name") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &layout = project.InsertNewLayout("My layout", 0);
auto &layoutExpression =
CreateExpressionWithLayerParameter(project, layout.GetEvents(), "My layer");
gd::WholeProjectRefactorer::RenameLayer(project, layout, "My layer",
"");
REQUIRE(layoutExpression.GetParameter(0).GetPlainString() ==
"MyExtension::CameraCenterX(\"My layer\") + "
"MyExtension::CameraCenterX(\"My layer\")");
}
SECTION("Can't rename a layer from an empty name") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &layout = project.InsertNewLayout("My layout", 0);
auto &layoutExpression =
CreateExpressionWithLayerParameter(project, layout.GetEvents(), "");
gd::WholeProjectRefactorer::RenameLayer(project, layout, "", "My layer");
REQUIRE(layoutExpression.GetParameter(0).GetPlainString() ==
"MyExtension::CameraCenterX(\"\") + "
"MyExtension::CameraCenterX(\"\")");
}
}
namespace {
@@ -3625,7 +3687,6 @@ TEST_CASE("RenameLayerEffect", "[common]") {
auto &wrongLayerExpression =
CreateExpressionWithLayerEffectParameter(project, layout.GetEvents(), "My layer 2");
std::cout << "RenameLayerEffect" << std::endl;
gd::WholeProjectRefactorer::RenameLayerEffect(project, layout, layer, "My effect",
"My renamed effect");
@@ -3659,3 +3720,129 @@ TEST_CASE("RenameLayerEffect", "[common]") {
"MyExtension::LayerEffectParameter(\"My layer 2\", \"My effect\")");
}
}
TEST_CASE("RemoveLayer", "[common]") {
SECTION("Can remove instances in a layout and its associated external layouts") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &layout = project.InsertNewLayout("My layout", 0);
auto &otherLayout = project.InsertNewLayout("My other layout", 1);
layout.InsertNewLayer("My layer", 0);
otherLayout.InsertNewLayer("My layer", 0);
auto &externalLayout =
project.InsertNewExternalLayout("My external layout", 0);
auto &otherExternalLayout =
project.InsertNewExternalLayout("My other external layout", 0);
externalLayout.SetAssociatedLayout("My layout");
otherExternalLayout.SetAssociatedLayout("My other layout");
auto &initialInstances = layout.GetInitialInstances();
initialInstances.InsertNewInitialInstance().SetLayer("My layer");
initialInstances.InsertNewInitialInstance().SetLayer("My layer");
initialInstances.InsertNewInitialInstance().SetLayer("My layer");
initialInstances.InsertNewInitialInstance().SetLayer("");
initialInstances.InsertNewInitialInstance().SetLayer("");
auto &externalInitialInstances = externalLayout.GetInitialInstances();
externalInitialInstances.InsertNewInitialInstance().SetLayer("My layer");
externalInitialInstances.InsertNewInitialInstance().SetLayer("My layer");
externalInitialInstances.InsertNewInitialInstance().SetLayer("");
auto &otherInitialInstances = otherLayout.GetInitialInstances();
otherInitialInstances.InsertNewInitialInstance().SetLayer("My layer");
auto &otherExternalInitialInstances = otherExternalLayout.GetInitialInstances();
otherExternalInitialInstances.InsertNewInitialInstance().SetLayer("My layer");
REQUIRE(initialInstances.GetInstancesCount() == 5);
REQUIRE(externalInitialInstances.GetInstancesCount() == 3);
REQUIRE(otherInitialInstances.GetInstancesCount() == 1);
REQUIRE(otherExternalInitialInstances.GetInstancesCount() == 1);
REQUIRE(initialInstances.GetLayerInstancesCount("My layer") == 3);
REQUIRE(externalInitialInstances.GetLayerInstancesCount("My layer") == 2);
gd::WholeProjectRefactorer::RemoveLayer(project, layout, "My layer");
REQUIRE(initialInstances.GetInstancesCount() == 2);
REQUIRE(externalInitialInstances.GetInstancesCount() == 1);
REQUIRE(otherInitialInstances.GetInstancesCount() == 1);
REQUIRE(otherExternalInitialInstances.GetInstancesCount() == 1);
REQUIRE(initialInstances.GetLayerInstancesCount("My layer") == 0);
REQUIRE(externalInitialInstances.GetLayerInstancesCount("My layer") == 0);
}
}
TEST_CASE("MergeLayers", "[common]") {
SECTION("Can merge instances from a layout into another layout (and their associated external layouts)") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &layout = project.InsertNewLayout("My layout", 0);
auto &otherLayout = project.InsertNewLayout("My other layout", 1);
layout.InsertNewLayer("My layer", 0);
otherLayout.InsertNewLayer("My layer", 0);
auto &externalLayout =
project.InsertNewExternalLayout("My external layout", 0);
auto &otherExternalLayout =
project.InsertNewExternalLayout("My other external layout", 0);
externalLayout.SetAssociatedLayout("My layout");
otherExternalLayout.SetAssociatedLayout("My other layout");
auto &initialInstances = layout.GetInitialInstances();
initialInstances.InsertNewInitialInstance().SetLayer("My layer");
initialInstances.InsertNewInitialInstance().SetLayer("My layer");
initialInstances.InsertNewInitialInstance().SetLayer("My layer");
initialInstances.InsertNewInitialInstance().SetLayer("");
initialInstances.InsertNewInitialInstance().SetLayer("");
initialInstances.InsertNewInitialInstance().SetLayer("My other layer");
auto &externalInitialInstances = externalLayout.GetInitialInstances();
externalInitialInstances.InsertNewInitialInstance().SetLayer("My layer");
externalInitialInstances.InsertNewInitialInstance().SetLayer("My layer");
externalInitialInstances.InsertNewInitialInstance().SetLayer("");
externalInitialInstances.InsertNewInitialInstance().SetLayer("My other layer");
auto &otherInitialInstances = otherLayout.GetInitialInstances();
otherInitialInstances.InsertNewInitialInstance().SetLayer("My layer");
auto &otherExternalInitialInstances = otherExternalLayout.GetInitialInstances();
otherExternalInitialInstances.InsertNewInitialInstance().SetLayer("My layer");
REQUIRE(initialInstances.GetInstancesCount() == 6);
REQUIRE(externalInitialInstances.GetInstancesCount() == 4);
REQUIRE(otherInitialInstances.GetInstancesCount() == 1);
REQUIRE(otherExternalInitialInstances.GetInstancesCount() == 1);
REQUIRE(initialInstances.GetLayerInstancesCount("My layer") == 3);
REQUIRE(externalInitialInstances.GetLayerInstancesCount("My layer") == 2);
gd::WholeProjectRefactorer::MergeLayers(project, layout, "My layer", "");
// No instance was removed.
REQUIRE(initialInstances.GetInstancesCount() == 6);
REQUIRE(externalInitialInstances.GetInstancesCount() == 4);
REQUIRE(otherInitialInstances.GetInstancesCount() == 1);
REQUIRE(otherExternalInitialInstances.GetInstancesCount() == 1);
// No instance remain in "My layer".
REQUIRE(initialInstances.GetLayerInstancesCount("My layer") == 0);
REQUIRE(externalInitialInstances.GetLayerInstancesCount("My layer") == 0);
// Layers with the same name in other layouts are untouched.
REQUIRE(otherInitialInstances.GetLayerInstancesCount("My layer") == 1);
REQUIRE(otherExternalInitialInstances.GetLayerInstancesCount("My layer") == 1);
// Other layers from the same layout are untouched.
REQUIRE(initialInstances.GetLayerInstancesCount("My other layer") == 1);
REQUIRE(externalInitialInstances.GetLayerInstancesCount("My other layer") == 1);
}
}

View File

@@ -0,0 +1 @@

View File

@@ -16,7 +16,13 @@ namespace gdjs {
/**
* Base class for 3D objects.
*/
export abstract class RuntimeObject3D extends gdjs.RuntimeObject {
export abstract class RuntimeObject3D
extends gdjs.RuntimeObject
implements
gdjs.Resizable,
gdjs.Scalable,
gdjs.Flippable,
gdjs.Base3DHandler {
/**
* Position on the Z axis.
*/
@@ -257,6 +263,11 @@ namespace gdjs {
this.invalidateHitboxes();
}
setSize(newWidth: number, newHeight: number): void {
this.setWidth(newWidth);
this.setHeight(newHeight);
}
/**
* Set the object size on the Z axis (called "depth").
*/

View File

@@ -6,6 +6,9 @@ namespace gdjs {
target: EffectsTarget,
effectData: EffectData
): gdjs.PixiFiltersTools.Filter {
if (typeof THREE === 'undefined') {
return new gdjs.PixiFiltersTools.EmptyFilter();
}
return new (class implements gdjs.PixiFiltersTools.Filter {
light: THREE.AmbientLight;
_isEnabled: boolean;

View File

@@ -0,0 +1,189 @@
/*
* GDevelop JS Platform
* Copyright 2013-2023 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
namespace gdjs {
export interface Base3DHandler {
/**
* Set the object position on the Z axis.
*/
setZ(z: float): void;
/**
* Get the object position on the Z axis.
*/
getZ(): float;
/**
* Set the object rotation on the X axis.
*
* This is an Euler angle. Objects use the `ZYX` order.
*
* @param angle the rotation angle on the X axis in degree
*/
setRotationX(angle: float): void;
/**
* Set the object rotation on the Y axis.
*
* This is an Euler angle. Objects use the `ZYX` order.
*
* @param angle the rotation angle on the Y axis in degree
*/
setRotationY(angle: float): void;
/**
* Get the object rotation on the X axis in degree.
*
* This is an Euler angle. Objects use the `ZYX` order.
*/
getRotationX(): float;
/**
* Get the object rotation on the Y axis in degree.
*
* This is an Euler angle. Objects use the `ZYX` order.
*/
getRotationY(): float;
/**
* Turn the object around the scene X axis at its center.
* @param deltaAngle the rotation angle in degree
*/
turnAroundX(deltaAngle: float): void;
/**
* Turn the object around the scene Y axis at its center.
* @param deltaAngle the rotation angle in degree
*/
turnAroundY(deltaAngle: float): void;
/**
* Turn the object around the scene Z axis at its center.
* @param deltaAngle the rotation angle in degree
*/
turnAroundZ(deltaAngle: float): void;
/**
* Get the object size on the Z axis (called "depth").
*/
getDepth(): float;
/**
* Set the object size on the Z axis (called "depth").
*/
setDepth(depth: float): void;
/**
* Change the scale on Z axis of the object (changing its depth).
*
* @param newScale The new scale (must be greater than 0).
*/
setScaleZ(newScale: number): void;
/**
* Get the scale of the object on Z axis.
*
* @return the scale of the object on Z axis
*/
getScaleZ(): float;
flipZ(enable: boolean): void;
isFlippedZ(): boolean;
}
/**
* A behavior that forwards the Base3D interface to its object.
*/
export class Base3DBehavior
extends gdjs.RuntimeBehavior
implements Base3DHandler {
private object: gdjs.RuntimeObject & Base3DHandler;
constructor(
instanceContainer: gdjs.RuntimeInstanceContainer,
behaviorData,
owner: gdjs.RuntimeObject & Base3DHandler
) {
super(instanceContainer, behaviorData, owner);
this.object = owner;
}
updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean {
// Nothing to update.
return true;
}
onDeActivate() {}
onDestroy() {}
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}
setZ(z: float): void {
this.object.setZ(z);
}
getZ(): float {
return this.object.getZ();
}
setRotationX(angle: float): void {
this.object.setRotationX(angle);
}
setRotationY(angle: float): void {
this.object.setRotationY(angle);
}
getRotationX(): float {
return this.object.getRotationX();
}
getRotationY(): float {
return this.object.getRotationY();
}
turnAroundX(deltaAngle: float): void {
this.object.turnAroundX(deltaAngle);
}
turnAroundY(deltaAngle: float): void {
this.object.turnAroundY(deltaAngle);
}
turnAroundZ(deltaAngle: float): void {
this.object.turnAroundZ(deltaAngle);
}
getDepth(): float {
return this.object.getDepth();
}
setDepth(depth: float): void {
this.object.setDepth(depth);
}
setScaleZ(newScale: number): void {
this.object.setScaleZ(newScale);
}
getScaleZ(): float {
return this.object.getScaleZ();
}
flipZ(enable: boolean): void {
this.object.flipZ(enable);
}
isFlippedZ(): boolean {
return this.object.isFlippedZ();
}
}
gdjs.registerBehavior('Scene3D::Base3DBehavior', gdjs.Base3DBehavior);
}

View File

@@ -1,20 +1,23 @@
cmake_minimum_required(VERSION 2.6)
cmake_policy(SET CMP0015 NEW)
cmake_minimum_required(VERSION 3.5)
project(Scene3D)
gd_add_extension_includes()
#Defines
###
# Defines
#
gd_add_extension_definitions(Scene3D)
#The targets
###
# The targets
#
include_directories(.)
file(GLOB source_files *.cpp *.h)
file(
GLOB
source_files
*.cpp
*.h)
gd_add_clang_utils(Scene3D "${source_files}")
gd_add_extension_target(Scene3D "${source_files}")
#Linker files for the IDE extension
###
# Linker files for the IDE extension
#
gd_extension_link_libraries(Scene3D)

View File

@@ -6,6 +6,9 @@ namespace gdjs {
target: EffectsTarget,
effectData: EffectData
): gdjs.PixiFiltersTools.Filter {
if (typeof THREE === 'undefined') {
return new gdjs.PixiFiltersTools.EmptyFilter();
}
return new (class implements gdjs.PixiFiltersTools.Filter {
light: THREE.DirectionalLight;
rotationObject: THREE.Group;

View File

@@ -6,6 +6,9 @@ namespace gdjs {
target: EffectsTarget,
effectData: EffectData
): gdjs.PixiFiltersTools.Filter {
if (typeof THREE === 'undefined') {
return new gdjs.PixiFiltersTools.EmptyFilter();
}
return new (class implements gdjs.PixiFiltersTools.Filter {
fog: THREE.FogExp2;

View File

@@ -6,6 +6,9 @@ namespace gdjs {
target: EffectsTarget,
effectData: EffectData
): gdjs.PixiFiltersTools.Filter {
if (typeof THREE === 'undefined') {
return new gdjs.PixiFiltersTools.EmptyFilter();
}
return new (class implements gdjs.PixiFiltersTools.Filter {
light: THREE.HemisphereLight;
rotationObject: THREE.Group;

View File

@@ -38,6 +38,191 @@ module.exports = {
.addInstructionOrExpressionGroupMetadata(_('3D'))
.setIcon('res/conditions/3d_box.svg');
{
const base3D = extension.addBehavior(
"Base3DBehavior",
_("3D capability"),
"Object3D",
_("Move the object in 3D space."),
"",
"res/conditions/3d_box.svg",
"Base3DBehavior",
new gd.Behavior(),
new gd.BehaviorsSharedData())
.setHidden()
.setIncludeFile('Extensions/3D/Base3DBehavior.js');
base3D
.addExpressionAndConditionAndAction(
'number',
'Z',
_('Z (elevation)'),
_('the Z position (the "elevation")'),
_('the Z position'),
_('Position'),
'res/conditions/3d_box.svg'
)
.addParameter('object', _('3D object'))
.addParameter("behavior", _("Behavior"), "Base3DBehavior")
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setFunctionName('setZ')
.setGetter('getZ');
base3D
.addExpressionAndConditionAndAction(
'number',
'Depth',
_('Depth (size on Z axis)'),
_('the depth (size on Z axis)'),
_('the depth'),
_('Size'),
'res/conditions/3d_box.svg'
)
.addParameter('object', _('3D object'))
.addParameter("behavior", _("Behavior"), "Base3DBehavior")
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setFunctionName('setDepth')
.setGetter('getDepth');
base3D
.addExpressionAndConditionAndAction(
'number',
'ScaleZ',
_('Scale on Z axis'),
_("the scale on Z axis of an object (default scale is 1)"),
_("the scale on Z axis scale"),
_('Scale'),
'res/conditions/3d_box.svg'
)
.addParameter('object', _('3D object'))
.addParameter("behavior", _("Behavior"), "Base3DBehavior")
.useStandardParameters(
'number',
gd.ParameterOptions.makeNewOptions().setDescription(
_('Scale (1 by default)')
)
)
.markAsAdvanced()
.setFunctionName('setScaleZ')
.setGetter('getScaleZ');
base3D
.addScopedAction(
'FlipZ',
_('Flip the object on Z'),
_('Flip the object on Z axis'),
_('Flip on Z axis _PARAM0_: _PARAM2_'),
_('Effects'),
'res/conditions/3d_box.svg',
'res/conditions/3d_box.svg'
)
.addParameter('object', _('3D object'))
.addParameter("behavior", _("Behavior"), "Base3DBehavior")
.addParameter('yesorno', _('Activate flipping'))
.markAsSimple()
.setFunctionName('flipZ');
base3D
.addScopedCondition(
'FlippedZ',
_('Flipped on Z'),
_('Check if the object is flipped on Z axis'),
_('_PARAM0_ is flipped on Z axis'),
_('Effects'),
'res/conditions/3d_box.svg',
'res/conditions/3d_box.svg'
)
.addParameter('object', _('3D object'))
.addParameter("behavior", _("Behavior"), "Base3DBehavior")
.setFunctionName('isFlippedZ');
base3D
.addExpressionAndConditionAndAction(
'number',
'RotationX',
_('Rotation on X axis'),
_('the rotation on X axis'),
_('the rotation on X axis'),
_('Angle'),
'res/conditions/3d_box.svg'
)
.addParameter('object', _('3D object'))
.addParameter("behavior", _("Behavior"), "Base3DBehavior")
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setFunctionName('setRotationX')
.setGetter('getRotationX');
base3D
.addExpressionAndConditionAndAction(
'number',
'RotationY',
_('Rotation on Y axis'),
_('the rotation on Y axis'),
_('the rotation on Y axis'),
_('Angle'),
'res/conditions/3d_box.svg'
)
.addParameter('object', _('3D object'))
.addParameter("behavior", _("Behavior"), "Base3DBehavior")
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setFunctionName('setRotationY')
.setGetter('getRotationY');
base3D
.addScopedAction(
'TurnAroundX',
_('Turn around X axis'),
_(
"Turn the object around X axis. This axis doesn't move with the object rotation."
),
_('Turn _PARAM0_ from _PARAM2_° around X axis'),
_('Angle'),
'res/conditions/3d_box.svg',
'res/conditions/3d_box.svg'
)
.addParameter('object', _('3D object'))
.addParameter("behavior", _("Behavior"), "Base3DBehavior")
.addParameter('number', _('Rotation angle'), '', false)
.markAsAdvanced()
.setFunctionName('turnAroundX');
base3D
.addScopedAction(
'TurnAroundY',
_('Turn around Y axis'),
_(
"Turn the object around Y axis. This axis doesn't move with the object rotation."
),
_('Turn _PARAM0_ from _PARAM2_° around Y axis'),
_('Angle'),
'res/conditions/3d_box.svg',
'res/conditions/3d_box.svg'
)
.addParameter('object', _('3D object'))
.addParameter("behavior", _("Behavior"), "Base3DBehavior")
.addParameter('number', _('Rotation angle'), '', false)
.markAsAdvanced()
.setFunctionName('turnAroundY');
base3D
.addScopedAction(
'TurnAroundZ',
_('Turn around Z axis'),
_(
"Turn the object around Z axis. This axis doesn't move with the object rotation."
),
_('Turn _PARAM0_ from _PARAM2_° around Z axis'),
_('Angle'),
'res/conditions/3d_box.svg',
'res/conditions/3d_box.svg'
)
.addParameter('object', _('3D object'))
.addParameter("behavior", _("Behavior"), "Base3DBehavior")
.addParameter('number', _('Rotation angle'), '', false)
.markAsAdvanced()
.setFunctionName('turnAroundZ');
}
{
const object = extension
.addObject(
@@ -48,13 +233,20 @@ module.exports = {
new gd.Model3DObjectConfiguration()
)
.setCategoryFullName(_('3D'))
.addUnsupportedBaseObjectCapability('effect')
// Effects are unsupported because the object is not rendered with PIXI.
.addDefaultBehavior('ResizableCapability::ResizableBehavior')
.addDefaultBehavior('ScalableCapability::ScalableBehavior')
.addDefaultBehavior('FlippableCapability::FlippableBehavior')
.addDefaultBehavior('AnimatableCapability::AnimatableBehavior')
.addDefaultBehavior('Scene3D::Base3DBehavior')
.setIncludeFile('Extensions/3D/A_RuntimeObject3D.js')
.addIncludeFile('Extensions/3D/A_RuntimeObject3DRenderer.js')
.addIncludeFile('Extensions/3D/Model3DRuntimeObject.js')
.addIncludeFile('Extensions/3D/Model3DRuntimeObject3DRenderer.js');
// Properties expressions/conditions/actions:
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -67,9 +259,12 @@ module.exports = {
)
.addParameter('object', _('3D model'), 'Model3DObject', false)
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setHidden()
.setFunctionName('setZ')
.setGetter('getZ');
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -82,9 +277,11 @@ module.exports = {
)
.addParameter('object', _('3D model'), 'Model3DObject', false)
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setHidden()
.setFunctionName('setDepth')
.setGetter('getDepth');
// Deprecated
object
.addScopedAction(
'SetWidth',
@@ -100,10 +297,12 @@ module.exports = {
'number',
gd.ParameterOptions.makeNewOptions()
)
.setHidden()
.markAsAdvanced()
.setFunctionName('setWidth')
.setGetter('getWidth');
// Deprecated
object
.addScopedCondition(
'Width',
@@ -119,9 +318,11 @@ module.exports = {
'number',
gd.ParameterOptions.makeNewOptions()
)
.setHidden()
.markAsAdvanced()
.setFunctionName('getWidth');
// Deprecated
object
.addScopedAction(
'SetHeight',
@@ -137,10 +338,12 @@ module.exports = {
'number',
gd.ParameterOptions.makeNewOptions()
)
.setHidden()
.markAsAdvanced()
.setFunctionName('setHeight')
.setGetter('getHeight');
// Deprecated
object
.addScopedCondition(
'Height',
@@ -156,9 +359,11 @@ module.exports = {
'number',
gd.ParameterOptions.makeNewOptions()
)
.setHidden()
.markAsAdvanced()
.setFunctionName('getHeight');
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -171,9 +376,11 @@ module.exports = {
)
.addParameter('object', _('3D model'), 'Model3DObject', false)
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setHidden()
.setFunctionName('setHeight')
.setGetter('getHeight');
// Deprecated
object
.addScopedAction(
'Scale',
@@ -191,10 +398,12 @@ module.exports = {
_('Scale (1 by default)')
)
)
.setHidden()
.markAsAdvanced()
.setFunctionName('setScale')
.setGetter('getScale');
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -212,10 +421,12 @@ module.exports = {
_('Scale (1 by default)')
)
)
.setHidden()
.markAsAdvanced()
.setFunctionName('setScaleX')
.setGetter('getScaleX');
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -233,10 +444,12 @@ module.exports = {
_('Scale (1 by default)')
)
)
.setHidden()
.markAsAdvanced()
.setFunctionName('setScaleY')
.setGetter('getScaleY');
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -255,9 +468,11 @@ module.exports = {
)
)
.markAsAdvanced()
.setHidden()
.setFunctionName('setScaleZ')
.setGetter('getScaleZ');
// Deprecated
object
.addScopedAction(
'FlipX',
@@ -270,9 +485,11 @@ module.exports = {
)
.addParameter('object', _('3D model'), 'Model3DObject')
.addParameter('yesorno', _('Activate flipping'))
.setHidden()
.markAsSimple()
.setFunctionName('flipX');
// Deprecated
object
.addScopedAction(
'FlipY',
@@ -285,9 +502,11 @@ module.exports = {
)
.addParameter('object', _('3D model'), 'Model3DObject')
.addParameter('yesorno', _('Activate flipping'))
.setHidden()
.markAsSimple()
.setFunctionName('flipY');
// Deprecated
object
.addScopedAction(
'FlipZ',
@@ -301,8 +520,10 @@ module.exports = {
.addParameter('object', _('3D model'), 'Model3DObject')
.addParameter('yesorno', _('Activate flipping'))
.markAsSimple()
.setHidden()
.setFunctionName('flipZ');
// Deprecated
object
.addScopedCondition(
'FlippedX',
@@ -314,8 +535,10 @@ module.exports = {
'res/actions/flipX.png'
)
.addParameter('object', _('3D model'), 'Model3DObject')
.setHidden()
.setFunctionName('isFlippedX');
// Deprecated
object
.addScopedCondition(
'FlippedY',
@@ -327,8 +550,10 @@ module.exports = {
'res/actions/flipY.png'
)
.addParameter('object', _('3D model'), 'Model3DObject')
.setHidden()
.setFunctionName('isFlippedY');
// Deprecated
object
.addScopedCondition(
'FlippedZ',
@@ -340,8 +565,10 @@ module.exports = {
'res/conditions/3d_box.svg'
)
.addParameter('object', _('3D model'), 'Model3DObject')
.setHidden()
.setFunctionName('isFlippedZ');
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -354,9 +581,11 @@ module.exports = {
)
.addParameter('object', _('3D model'), 'Model3DObject', false)
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setHidden()
.setFunctionName('setRotationX')
.setGetter('getRotationX');
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -369,9 +598,11 @@ module.exports = {
)
.addParameter('object', _('3D model'), 'Model3DObject', false)
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setHidden()
.setFunctionName('setRotationY')
.setGetter('getRotationY');
// Deprecated
object
.addScopedAction(
'TurnAroundX',
@@ -387,8 +618,10 @@ module.exports = {
.addParameter('object', _('3D model'), 'Model3DObject', false)
.addParameter('number', _('Rotation angle'), '', false)
.markAsAdvanced()
.setHidden()
.setFunctionName('turnAroundX');
// Deprecated
object
.addScopedAction(
'TurnAroundY',
@@ -404,8 +637,10 @@ module.exports = {
.addParameter('object', _('3D model'), 'Model3DObject', false)
.addParameter('number', _('Rotation angle'), '', false)
.markAsAdvanced()
.setHidden()
.setFunctionName('turnAroundY');
// Deprecated
object
.addScopedAction(
'TurnAroundZ',
@@ -421,8 +656,10 @@ module.exports = {
.addParameter('object', _('3D model'), 'Model3DObject', false)
.addParameter('number', _('Rotation angle'), '', false)
.markAsAdvanced()
.setHidden()
.setFunctionName('turnAroundZ');
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -438,9 +675,11 @@ module.exports = {
.addParameter('object', _('3D model'), 'Model3DObject')
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.markAsSimple()
.setHidden()
.setFunctionName('setAnimationIndex')
.setGetter('getAnimationIndex');
// Deprecated
object
.addExpressionAndConditionAndAction(
'string',
@@ -459,9 +698,11 @@ module.exports = {
)
)
.markAsAdvanced()
.setHidden()
.setFunctionName('setAnimationName')
.setGetter('getAnimationName');
// Deprecated
object
.addAction(
'PauseAnimation',
@@ -474,8 +715,10 @@ module.exports = {
)
.addParameter('object', _('3D model'), 'Model3DObject')
.markAsSimple()
.setHidden()
.setFunctionName('pauseAnimation');
// Deprecated
object
.addAction(
'ResumeAnimation',
@@ -488,8 +731,10 @@ module.exports = {
)
.addParameter('object', _('3D model'), 'Model3DObject')
.markAsSimple()
.setHidden()
.setFunctionName('resumeAnimation');
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -508,9 +753,11 @@ module.exports = {
gd.ParameterOptions.makeNewOptions().setDescription(_('Speed scale'))
)
.markAsSimple()
.setHidden()
.setFunctionName('setAnimationSpeedScale')
.setGetter('getAnimationSpeedScale');
// Deprecated
object
.addCondition(
'IsAnimationPaused',
@@ -523,8 +770,10 @@ module.exports = {
)
.addParameter('object', _('3D model'), 'Model3DObject')
.markAsSimple()
.setHidden()
.setFunctionName('isAnimationPaused');
// Deprecated
object
.addCondition(
'HasAnimationEnded',
@@ -539,6 +788,7 @@ module.exports = {
)
.addParameter('object', _('3D model'), 'Model3DObject')
.markAsSimple()
.setHidden()
.setFunctionName('hasAnimationEnded');
}
@@ -864,13 +1114,19 @@ module.exports = {
Cube3DObject
)
.setCategoryFullName(_('3D'))
.addUnsupportedBaseObjectCapability('effect')
// Effects are unsupported because the object is not rendered with PIXI.
.addDefaultBehavior('ResizableCapability::ResizableBehavior')
.addDefaultBehavior('ScalableCapability::ScalableBehavior')
.addDefaultBehavior('FlippableCapability::FlippableBehavior')
.addDefaultBehavior('Scene3D::Base3DBehavior')
.setIncludeFile('Extensions/3D/A_RuntimeObject3D.js')
.addIncludeFile('Extensions/3D/A_RuntimeObject3DRenderer.js')
.addIncludeFile('Extensions/3D/Cube3DRuntimeObject.js')
.addIncludeFile('Extensions/3D/Cube3DRuntimeObjectPixiRenderer.js');
// Properties expressions/conditions/actions:
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -883,9 +1139,11 @@ module.exports = {
)
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setHidden()
.setFunctionName('setZ')
.setGetter('getZ');
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -898,9 +1156,11 @@ module.exports = {
)
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setHidden()
.setFunctionName('setDepth')
.setGetter('getDepth');
// Deprecated
object
.addScopedAction(
'SetWidth',
@@ -916,10 +1176,12 @@ module.exports = {
'number',
gd.ParameterOptions.makeNewOptions()
)
.setHidden()
.markAsAdvanced()
.setFunctionName('setWidth')
.setGetter('getWidth');
// Deprecated
object
.addScopedCondition(
'Width',
@@ -935,9 +1197,11 @@ module.exports = {
'number',
gd.ParameterOptions.makeNewOptions()
)
.setHidden()
.markAsAdvanced()
.setFunctionName('getWidth');
// Deprecated
object
.addScopedAction(
'SetHeight',
@@ -953,10 +1217,12 @@ module.exports = {
'number',
gd.ParameterOptions.makeNewOptions()
)
.setHidden()
.markAsAdvanced()
.setFunctionName('setHeight')
.setGetter('getHeight');
// Deprecated
object
.addScopedCondition(
'Height',
@@ -972,9 +1238,11 @@ module.exports = {
'number',
gd.ParameterOptions.makeNewOptions()
)
.setHidden()
.markAsAdvanced()
.setFunctionName('getHeight');
// Deprecated
object
.addScopedAction(
'Scale',
@@ -992,10 +1260,12 @@ module.exports = {
_('Scale (1 by default)')
)
)
.setHidden()
.markAsAdvanced()
.setFunctionName('setScale')
.setGetter('getScale');
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -1013,10 +1283,12 @@ module.exports = {
_('Scale (1 by default)')
)
)
.setHidden()
.markAsAdvanced()
.setFunctionName('setScaleX')
.setGetter('getScaleX');
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -1034,10 +1306,12 @@ module.exports = {
_('Scale (1 by default)')
)
)
.setHidden()
.markAsAdvanced()
.setFunctionName('setScaleY')
.setGetter('getScaleY');
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -1056,9 +1330,11 @@ module.exports = {
)
)
.markAsAdvanced()
.setHidden()
.setFunctionName('setScaleZ')
.setGetter('getScaleZ');
// Deprecated
object
.addScopedAction(
'FlipX',
@@ -1072,8 +1348,10 @@ module.exports = {
.addParameter('object', _('3D cube'), 'Cube3DObject')
.addParameter('yesorno', _('Activate flipping'))
.markAsSimple()
.setHidden()
.setFunctionName('flipX');
// Deprecated
object
.addScopedAction(
'FlipY',
@@ -1087,8 +1365,10 @@ module.exports = {
.addParameter('object', _('3D cube'), 'Cube3DObject')
.addParameter('yesorno', _('Activate flipping'))
.markAsSimple()
.setHidden()
.setFunctionName('flipY');
// Deprecated
object
.addScopedAction(
'FlipZ',
@@ -1102,8 +1382,10 @@ module.exports = {
.addParameter('object', _('3D cube'), 'Cube3DObject')
.addParameter('yesorno', _('Activate flipping'))
.markAsSimple()
.setHidden()
.setFunctionName('flipZ');
// Deprecated
object
.addScopedCondition(
'FlippedX',
@@ -1115,8 +1397,10 @@ module.exports = {
'res/actions/flipX.png'
)
.addParameter('object', _('3D cube'), 'Cube3DObject')
.setHidden()
.setFunctionName('isFlippedX');
// Deprecated
object
.addScopedCondition(
'FlippedY',
@@ -1128,8 +1412,10 @@ module.exports = {
'res/actions/flipY.png'
)
.addParameter('object', _('3D cube'), 'Cube3DObject')
.setHidden()
.setFunctionName('isFlippedY');
// Deprecated
object
.addScopedCondition(
'FlippedZ',
@@ -1141,8 +1427,10 @@ module.exports = {
'res/conditions/3d_box.svg'
)
.addParameter('object', _('3D cube'), 'Cube3DObject')
.setHidden()
.setFunctionName('isFlippedZ');
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -1156,8 +1444,10 @@ module.exports = {
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setFunctionName('setRotationX')
.setHidden()
.setGetter('getRotationX');
// Deprecated
object
.addExpressionAndConditionAndAction(
'number',
@@ -1171,6 +1461,7 @@ module.exports = {
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setFunctionName('setRotationY')
.setHidden()
.setGetter('getRotationY');
object
@@ -1197,6 +1488,7 @@ module.exports = {
.setFunctionName('setFaceVisibility')
.setGetter('isFaceVisible');
// Deprecated
object
.addScopedAction(
'TurnAroundX',
@@ -1212,8 +1504,10 @@ module.exports = {
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
.addParameter('number', _('Rotation angle'), '', false)
.markAsAdvanced()
.setHidden()
.setFunctionName('turnAroundX');
// Deprecated
object
.addScopedAction(
'TurnAroundY',
@@ -1229,8 +1523,10 @@ module.exports = {
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
.addParameter('number', _('Rotation angle'), '', false)
.markAsAdvanced()
.setHidden()
.setFunctionName('turnAroundY');
// Deprecated
object
.addScopedAction(
'TurnAroundZ',
@@ -1246,6 +1542,7 @@ module.exports = {
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
.addParameter('number', _('Rotation angle'), '', false)
.markAsAdvanced()
.setHidden()
.setFunctionName('turnAroundZ');
object

View File

@@ -6,6 +6,9 @@ namespace gdjs {
target: EffectsTarget,
effectData: EffectData
): gdjs.PixiFiltersTools.Filter {
if (typeof THREE === 'undefined') {
return new gdjs.PixiFiltersTools.EmptyFilter();
}
return new (class implements gdjs.PixiFiltersTools.Filter {
fog: THREE.Fog;

View File

@@ -21,7 +21,7 @@ using namespace std;
Model3DObjectConfiguration::Model3DObjectConfiguration()
: width(100), height(100), depth(100), rotationX(0), rotationY(0),
rotationZ(0), modelResourceName(""), materialType("Basic"),
rotationZ(0), modelResourceName(""), materialType("StandardWithoutMetalness"),
originLocation("ModelOrigin"), centerLocation("ModelOrigin"),
keepAspectRatio(true) {}

View File

@@ -48,7 +48,9 @@ namespace gdjs {
/**
* A 3D object which displays a 3D model.
*/
export class Model3DRuntimeObject extends gdjs.RuntimeObject3D {
export class Model3DRuntimeObject
extends gdjs.RuntimeObject3D
implements gdjs.Animatable {
_renderer: gdjs.Model3DRuntimeObjectRenderer;
_modelResourceName: string;

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