Compare commits

...

772 Commits

Author SHA1 Message Date
Clément Pasteau
451d525b36 Fix objects owned by Multiplayer host not being properly migrated when host changes (#7078) 2024-10-17 15:35:41 +02:00
D8H
c755946d42 Add tutorial bubbles on actions replacing deprecated ones (#7077) 2024-10-17 15:12:24 +02:00
D8H
7a6b6fbf7f Update instance renderers when an event-based object is deleted, renamed or pasted (#7076) 2024-10-17 13:22:18 +02:00
github-actions[bot]
730c8283e5 Update translations [skip ci] (#7070)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-10-17 11:14:55 +02:00
D8H
7ea250706c Close custom object tabs when they are deleted from their extension (#7074) 2024-10-17 11:14:26 +02:00
Florian Rival
db7a108354 Reduce time before session analytics to improve bounce detection 2024-10-17 11:06:20 +02:00
AlexandreS
2e15d68bce Change max project warning copy and Add callout in Save to storage provider dialog (#7069)
Don't show in changelog
2024-10-17 11:05:33 +02:00
Florian Rival
f6c9e1408c Bump newIDE version 2024-10-17 00:37:34 +02:00
D8H
0b3d4d048a Fix autocompletion of layers and points for custom object children (#7071) 2024-10-17 00:35:54 +02:00
Clément Pasteau
5d625dd497 Always show instant-build page, even if not linked to a game (#7072) 2024-10-17 00:32:46 +02:00
D8H
079eca829a Fix a regression on the capability check in the editor (#7073)
Don't show in changelog
2024-10-17 00:18:42 +02:00
D8H
35b5f92c59 Fix object lists not always up-to-date in the extension events editor after adding an object in the custom object editor (#7068) 2024-10-16 17:33:35 +02:00
github-actions[bot]
70eb95b132 Update translations [skip ci] (#7064)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-10-16 15:15:57 +02:00
AlexandreS
7c7ee8b7fc Warn not enough cloud projects in quick customization flow (#7065) 2024-10-16 14:37:30 +02:00
Clément Pasteau
3556dd2e3c Improvements across the app (#7067)
* Shorter button label for github star
* More in app tutorials on the same row on mobile
* Smaller icon to get app on mobile
* Reduce spacing in Login & Signup dialog to see more
* Redirect store when in a dead end of game templates
* Improve guided lessons descriptions & re-order them
* Allow closing & deleting an opened cloud project
2024-10-16 14:26:26 +02:00
D8H
f74f77f66a Fix custom object editor not closed when the extension is renamed (#7066) 2024-10-16 13:11:25 +02:00
AlexandreS
712eb4b647 Avoid intermittent game crash, due to an audio issue, when resuming the game (when focused back again) (#7063) 2024-10-16 10:57:02 +02:00
D8H
c4474c766d Fix mouse and key parameters for event-functions (#7052) 2024-10-16 09:43:20 +02:00
github-actions[bot]
ad17a21973 Update translations [skip ci] (#7043)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-10-16 09:41:29 +02:00
D8H
5001411ccb Fix custom object loading when opening a project (#7060) 2024-10-16 09:38:16 +02:00
Florian Rival
05939f5c3e Fix extraction to custom object sometimes using an already used name (#7059) 2024-10-16 09:08:49 +02:00
Florian Rival
91978d4c6e Fix wait action in custom objects (#7056) 2024-10-15 17:15:07 +02:00
AlexandreS
d6433d89f0 Add icons to help understand to scroll during in app tutorial (#7057) 2024-10-15 14:43:37 +02:00
Clément Pasteau
e652ab9f5a Prevent players from claiming a leaderboard score as an anonymous user (#7055) 2024-10-15 14:36:40 +02:00
Florian Rival
e7decc7b92 Fix silent exceptions when resource loading finished after an instance was reset/removed (#7054)
Only show in developer changelog
2024-10-15 12:39:20 +02:00
AlexandreS
33dcc04112 Add support for free trial notification (#7053)
Don't show in changelog
2024-10-14 17:42:44 +02:00
Florian Rival
58ba2668c2 Add clang-tidy and builds with assertions/memory sanitizers for libGD.js (#7051)
Only show in developer changelog
2024-10-14 12:06:42 +02:00
Florian Rival
b34e802dcb Add a test with diagnostics that used to crash the app
Don't show in changelog
2024-10-14 09:39:07 +02:00
Florian Rival
31dac9cc93 Fix memory corruption/crashes when events in extensions had errors (#7050) 2024-10-13 22:44:36 +02:00
Florian Rival
ab97258832 Fix more tests and uninitialized variable (#7049)
Only show in developer changelog
2024-10-13 21:15:52 +02:00
Florian Rival
2ece223737 Fix wrong argument passed in a test (#7048) 2024-10-13 18:06:22 +02:00
Florian Rival
8342873b6e Fix missing or wrong arguments in GDevelop.js tests (#7047)
* These were "silently succeeding" but would create issues when Emscipten is run with SAFE_HEAP=1.

Only show in developer changelog
2024-10-13 17:39:54 +02:00
github-actions[bot]
0a85fd3814 Update translations [skip ci] (#7038)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-10-11 15:00:20 +02:00
Clément Pasteau
fe15b6d30b Update CSP (#7042)
Do not show in changelog
2024-10-11 14:59:59 +02:00
Florian Rival
f3c3559518 Fix warning 2024-10-11 14:56:36 +02:00
D8H
a403b1343b Fix extraction of 3D custom objects and prevent extracting 2D+3D custom objects (#7040) 2024-10-11 13:42:06 +02:00
D8H
83dba6c21e Allow to open the custom object editor from objects drop-down menu (#7039) 2024-10-11 12:45:23 +02:00
Florian Rival
7a4aea6557 Fix extension not regenerated after extracting instances to a custom object 2024-10-11 11:12:52 +02:00
AlexandreS
82a6abacb4 Suggest starter tilemaps when creating a tilemap from scratch (#7035) 2024-10-11 10:52:47 +02:00
AlexandreS
f60613cc64 Use user limits to determine if version history feature can be used (#7036)
Don't show in changelog
2024-10-11 10:47:32 +02:00
github-actions[bot]
274aedb3d9 Update translations [skip ci] (#7032)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-10-11 10:20:02 +02:00
D8H
efb31c3caf Fix text wrapping issue in the editor when used as a custom object child (#7034) 2024-10-11 09:05:36 +02:00
D8H
6781c0fd6e Add a drop-down menu action to extract instances as custom objects (#7030) 2024-10-10 20:13:42 +02:00
D8H
e9781133e1 Fix events refactoring when duplicating custom behaviors or custom objects (#7005) 2024-10-10 19:48:31 +02:00
Florian Rival
8972e0e3a6 Bump version (#7033) 2024-10-10 16:54:55 +02:00
Aurélien Vivet
4c76a5979b Add a new in-app tutorial explaining how to use a Tilemap (#6989) 2024-10-10 16:36:32 +02:00
D8H
484a0daec4 Show the tolerance in the sentence of "Is object turned toward" condition (#7022) 2024-10-10 16:25:38 +02:00
AlexandreS
de432c1bf2 Add a "Tilemap" filter in the Asset Store (#7031) 2024-10-10 16:15:18 +02:00
github-actions[bot]
8c7dcc1c23 Update translations [skip ci] (#7015)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-10-10 14:56:12 +02:00
AlexandreS
39648af248 Add margin between socials and donate link in profile (#7029)
Don't show in changelog
2024-10-10 10:21:15 +02:00
AlexandreS
5c7bbf5293 Add error callback to tilemap texture parsing (#7027)
To prevent crashes in the preview
2024-10-10 10:19:26 +02:00
Florian Rival
9d97b9d0eb Fix exception 't.bind is not a function' when a resource has an empty file (#7028) 2024-10-09 15:06:28 +02:00
AlexandreS
b39b12864f Add context menu options to duplicate instruction parameter or behavior property (#7026) 2024-10-08 15:50:28 +02:00
D8H
2c3dbbbbde Fix an exception when a touch is ended and then started in the same frame at runtime (#7025) 2024-10-08 11:45:40 +02:00
Clément Pasteau
72cc60bae9 Remove searchbar from Learn page. (#7024)
* As it does not return relevant results, it is thought best to remove it for now.
2024-10-07 18:16:16 +02:00
AlexandreS
c03e94849b Handle line breaks in font resource lines in resource store (#7023)
Don't show in changelog
2024-10-07 18:06:19 +02:00
AlexandreS
80daaf5e5b Fix Teach tab missing education resources button (#7021) 2024-10-07 17:25:04 +02:00
D8H
cb457cfd04 Fix the action to change the animation elapsed time for sprites and 3d models (#7020) 2024-10-07 17:18:40 +02:00
D8H
0a55aa631b Disable the "support us" dialog during an in-app tutorial (#7019) 2024-10-07 15:44:02 +02:00
AlexandreS
8e104f9ae4 Fix text input focus messing with the input manager (#7013) 2024-10-07 12:41:10 +02:00
D8H
a90b9a27e9 [Physics2] Avoid an exception when the object position is not finite (#7017) 2024-10-07 11:11:36 +02:00
D8H
6321e82f63 [Physics2] Forbid negative damping values (#7016) 2024-10-04 18:06:12 +02:00
AlexandreS
05fc63ab1b Fix ghost hitboxes on tilemap when tiles are flipped (#6990) 2024-10-04 17:25:34 +02:00
AlexandreS
85a6a21934 Do not display guided lesson tooltip if an error boundary is displayed (#7014)
Don't show in changelog
2024-10-04 17:23:28 +02:00
Clément Pasteau
a9741e7b42 Handle internal navigation for promotions (#7012)
Do not show in changelog
2024-10-04 17:22:56 +02:00
github-actions[bot]
23afe7b71c Update translations [skip ci] (#7011)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-10-04 17:22:22 +02:00
AlexandreS
85757e6d98 Rework asset store display when looking for a font or an audio (#7009)
The asset store is not available anymore when looking for other types of resource (image, 3D models, spine).
2024-10-04 15:56:50 +02:00
github-actions[bot]
524ca4dbb3 Update translations [skip ci] (#7002)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-10-03 17:40:13 +02:00
Aurélien Vivet
55cf710ef5 Add GitHub url to community tab (#7008) 2024-10-03 17:39:11 +02:00
Clément Pasteau
eee7e7f04c Remove most titles from home for a cleaner UI (#7010)
Do not show in changelog
2024-10-03 17:38:20 +02:00
Clément Pasteau
ecd984e08b Allow opening any homepage tab from url (#7007)
Do not show in changelog
2024-10-03 17:15:16 +02:00
D8H
d0a7fbbd02 Fix a regression on existing external tile map collision mask (#7004)
- Don't show in changelog
2024-10-02 14:44:07 +02:00
D8H
2a2c930b74 Add vertical alignment property for text object (#6975)
- Fix proportional anchors on custom object children
2024-10-02 11:17:48 +02:00
D8H
f6cb203029 Allow to filter external tile map collision per layer (#6998) 2024-10-02 10:14:52 +02:00
Florian Rival
fe743bbe57 Fix usage of libGD.js in Node 2024-09-30 19:06:24 +02:00
D8H
78c31408d4 Add a comment about anchor calculus (#6976)
- Don't show in changelog
2024-09-30 18:50:13 +02:00
github-actions[bot]
75a038344a Update translations [skip ci] (#7000)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-09-30 14:58:05 +02:00
Clément Pasteau
f0567b674c Fix example thumbnails (#7001) 2024-09-30 14:43:00 +02:00
Clément Pasteau
9b85f35856 Fix typo (#6999) 2024-09-30 08:40:38 +02:00
github-actions[bot]
f4568febf2 Update translations [skip ci] (#6995)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-09-30 08:14:52 +02:00
Clément Pasteau
de7f60b693 Bump to 5.4.214 (#6993) 2024-09-28 19:22:46 +02:00
Florian Rival
3a595b200e Update README [skip ci] [ci skip]
Don't show in changelog
2024-09-28 11:47:27 +02:00
AlexandreS
431b5929e8 Fine tune teach section display (#6994)
Don't show in changelog
2024-09-27 15:15:27 +02:00
github-actions[bot]
ec2e82cee5 Update translations [skip ci] (#6992)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-09-27 12:37:48 +02:00
Florian Rival
76517f1a2a Adapt margins in objects panel 2024-09-27 11:27:19 +02:00
Florian Rival
43f5bd1c0e Allow to edit object properties, behaviors, variables and effects directly from the properties panel (#6898)
* When an object is selected (or when "Edit object" button is clicked in the properties panel after choosing an instance), the properties panel will show the properties of the object.
* This allows for fast edition of most elements of an object: appearance, properties, but also behaviors, variables and effects. Most workflow and iterations on your game should be faster, from adapting the appearance of a text to tweaking behaviors and updating the preview to check the result in realtime.
2024-09-27 10:56:39 +02:00
github-actions[bot]
7198a22ae2 Update translations [skip ci] (#6964)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-09-26 10:43:31 +02:00
AlexandreS
46c52905f6 Add context menu to move Sprite object animation in list (#6987) 2024-09-25 17:28:58 +02:00
AlexandreS
40954bf497 Fix some crashes happening in preview (#6988) 2024-09-25 17:26:01 +02:00
Clément Pasteau
02c06ac6e7 Fix iOS automatic exports when using admob (#6986)
* internal ios deployment-target was conflicting between the plugins used, when admob was used in the project, preventing to build the app
2024-09-25 09:52:19 +02:00
AlexandreS
1fa3f59a77 Add possibility to paint tilemap with a rectangle selection from the tileset (#6977) 2024-09-23 17:37:20 +02:00
Clément Pasteau
cc371273ce Improve Quick Customization flow (#6978)
* Simplify the number of objects suggested for replacing
* Simplify the number of behavior properties suggested for tweaking
* New section to update the in-game title
* Simplify publication at the end of the flow
2024-09-23 15:07:31 +02:00
AlexandreS
364ec2ecfb Fix crashes in Preview due to ill-formed color values (#6980)
- Make color parsing from string more robust (issues when setting colors in Sprite, BBText, Particle emitter and effects with colors)
- Allow use of hex strings and shorthand hex strings in color fields
- Remove UI glitch when switching effect type and both effects have parameters with identical names
2024-09-23 09:21:37 +02:00
D8H
0d36a27b87 Fix anchor behavior when the object has a custom origin (#6970) 2024-09-18 13:54:10 +02:00
D8H
6d597a430b Always show custom objects in the extension editor (#6974) 2024-09-18 13:21:04 +02:00
Clément Pasteau
27b71b08e5 Fix instance selection rectangle not being flipped properly (#6971) 2024-09-18 09:51:08 +02:00
AlexandreS
82158f7073 Fix DismissableTutorialMessage stories typing (#6972)
Do not show in changelog
2024-09-18 09:50:35 +02:00
AlexandreS
8ba352d4ba Fix min width on right container (#6969)
Don't show in changelog
2024-09-17 17:35:48 +02:00
D8H
6cda5d08be Fix missing flippingZ accessors (#6968)
- Don't show in changelog
2024-09-17 16:00:14 +02:00
D8H
1a3a27b73b Fix custom object flipping (#6967)
Do not show in changelog
2024-09-17 15:15:25 +02:00
Clément Pasteau
96d912a6f2 Fix store UI (wrong centering of items) (#6965) 2024-09-17 14:23:28 +02:00
D8H
ed3acd5f0d Layout custom objects children according to their anchors in the editor (#6939) 2024-09-17 12:43:16 +02:00
AlexandreS
3f269206d1 Bump newIDE version (#6963) 2024-09-17 12:37:04 +02:00
github-actions[bot]
76b5aefdbc Update translations [skip ci] (#6961) 2024-09-17 12:36:38 +02:00
AlexandreS
9ef7af803c Change teacher resources list to include upcoming lessons (#6956) 2024-09-17 12:27:45 +02:00
D8H
c77f9b9e0c Fix a crash in the new behavior dialog (#6962)
- The crash happened when the extensions didn't load as expected.
2024-09-17 12:18:26 +02:00
D8H
035ddb8a7a Fix hot reload of object variables in object instances (#6958) 2024-09-17 12:14:10 +02:00
AlexandreS
e7dac1bafc Tilemap improvements (#6957)
- Improve performance display when painting
- Fix painting when tilemap is rotated
- Allow atlas size to be something else than a tile size multiple and ignore last column and row
- Display error message only when the the tile size is greater than the atlas image
- Do not crash preview if tilemap badly configured
- Add object name in actions and conditions
2024-09-17 11:18:30 +02:00
github-actions[bot]
54f00e7c57 Update translations [skip ci] (#6951)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-09-17 10:06:45 +02:00
Clément Pasteau
0bf9dae2b0 Fix icon of credit packages (#6960)
Do not show in changelog
2024-09-17 10:06:18 +02:00
Florian Rival
428aac8ab0 Fix sprite animation lists and selection checkbox
Don't show in changelog
2024-09-15 17:44:21 +02:00
Florian Rival
9391fc2841 Remove warnings during C++ emscripten compilation 2024-09-13 15:51:55 +02:00
Florian Rival
cea34337c6 Backport improvements made for objects panel (#6955)
Do not show in changelog
2024-09-13 15:26:49 +02:00
Clément Pasteau
dc45f3dae5 Allow changing Opacity & Flip directly in Instance Properties Panel (#6935)
* This allows playing around with instances directly on the canvas instead of relying on the actions to flip or change opacity and needing to start a preview
2024-09-13 13:39:03 +02:00
AlexandreS
0ca26a865e Authenticate plans and pricing systems fetch calls (#6952) 2024-09-13 11:45:23 +02:00
Clément Pasteau
1bce13f326 Bump to 5.4.212 (#6950) 2024-09-12 16:42:52 +02:00
github-actions[bot]
34f8f5750a Update translations [skip ci] (#6943)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-09-12 16:16:06 +02:00
AlexandreS
3b9a612094 Fix tilemap object edge cases causing crashes (#6945) 2024-09-12 15:49:02 +02:00
Clément Pasteau
3a84ed7c89 Fix object images not displaying on quick customization (#6949)
Do not show in changelog
2024-09-12 15:07:22 +02:00
AlexandreS
ef604fd442 Display active pricing systems only (#6948)
Don't show in changelog
2024-09-12 12:09:13 +02:00
Clément Pasteau
d88dc4772f Catch callback functions of Firebase preventing JS crash (#6946)
Only show in developer changelog
2024-09-11 17:32:49 +02:00
AlexandreS
02d40a1d52 Fix: Catch errors when handling electron browser window (#6944) 2024-09-11 09:13:40 +02:00
Clément Pasteau
35082825d4 Fix triggering the onWheel only when an input is focused (#6940) 2024-09-10 17:35:17 +02:00
Clément Pasteau
6a7c3daa8e Fix wheel increment (#6938) 2024-09-09 14:15:38 +02:00
Clément Pasteau
95af02bada Bump to 5.4.211 (#6937) 2024-09-09 13:56:35 +02:00
Clément Pasteau
30516a903e Fix instance number properties which could not be saved to 0 (#6936)
* Also add back the ability to use keyboard arrows and mouse wheel to control the value finely
2024-09-09 13:56:19 +02:00
Florian Rival
762f7ca19c Avoid unnecessary recompilation of many C++ files at each build
Only show in developer changelog
2024-09-09 13:39:34 +02:00
Florian Rival
852bf78c81 Show a loading texture for Panel Sprite instead of a error texture (#6931) 2024-09-09 13:04:15 +02:00
github-actions[bot]
b0da0cee34 Update translations [skip ci] (#6925)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-09-09 11:13:35 +02:00
Aurélien Vivet
73771f938b Fix checkered background in collision and points editor (#6928) 2024-09-06 16:20:59 +02:00
Florian Rival
b9dbe6dbb5 Fix exception when changing an external tilemap file after it was initially missing (#6929) 2024-09-06 16:05:57 +02:00
Florian Rival
0c2341c6e5 Fix crash in the scene editor when changing the Panel Sprite tiled/stretched option (#6926) 2024-09-05 18:25:13 +02:00
Florian Rival
e9b4de2ca9 Fix tilemap instance error when no image set (#6923)
Only show in developer changelog
2024-09-05 16:08:59 +02:00
Clément Pasteau
75a4114ce8 Fix extension generation for docs (#6924) 2024-09-05 16:04:48 +02:00
Clément Pasteau
20abb9b45a Bump to 5.4.210 (#6922) 2024-09-05 11:54:52 +02:00
github-actions[bot]
56436fd44a Update translations [skip ci] (#6921)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-09-05 11:54:35 +02:00
AlexandreS
0dd5fc55c9 Improve subscriptions dialog to display current plan at the top (#6918)
* Mainly useful for old subscriptions that are not available in the list of available ones anymore.
2024-09-05 09:37:43 +02:00
github-actions[bot]
93db4cb508 Update translations [skip ci] (#6919)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-09-05 08:43:06 +02:00
D8H
f7888abf45 Allow custom objects to use the anchor behavior on their children (#6917) 2024-09-04 19:00:49 +02:00
github-actions[bot]
c8144da704 Update translations [skip ci] (#6909)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-09-04 15:25:50 +02:00
Giordane Oliveira
832e8cd593 Update AdMob banner so they cover part of the game screen instead of reducing it (#6900)
* In most games, it's better to design the game with the size of the ad banner in mind - which will cover either part of the top or bottom of the screen. Previously, the game size was reduced which was making it difficult to properly design a game and would introduce bad looking black borders.
2024-09-04 09:14:12 +02:00
AlexandreS
ef66a9f1a4 Add support for math formula in instance properties panel fields (#6914)
* For example, you can enter `100 + 50` or `100 + 70/2` or `ToDeg(sin(2.3))` in the instance editor fields
2024-09-03 18:41:38 +02:00
Florian Rival
5efbaa8c58 Add automated crash reporting from previews (#6915)
* This will allow to detect any bugs or crash in the game engine without relying on manual reports from users on GitHub. Note that exceptions and errors in JavaScript code blocks won't be reported. This can be deactivated in preferences if you prefer not to have GDevelop send these crash reports at all.
2024-09-03 16:52:53 +02:00
AlexandreS
ecbf38ccda Remove effects tab (and actions and conditions) wrongly shown for Tilemap objects (#6916) 2024-09-03 16:33:57 +02:00
AlexandreS
b3fcfc3f55 Avoid exponential loop when scrolling out of view on the Scene editor (#6912) 2024-09-03 09:33:45 +02:00
D8H
a515836add Avoid to duplicate custom object data in the project files (#6904)
- Fix hot-reload of sprite object animations
2024-09-02 18:52:27 +02:00
D8H
a7c81b47b2 Fix text input not properly deleted when used in a Custom Object (#6910) 2024-09-02 17:59:39 +02:00
D8H
0f22e462ad Keep clearing object lists before the events too (#6913)
- Don't show in changelog
2024-09-02 17:43:47 +02:00
AlexandreS
e6e4d9048f Add action to set Text object font (#6911) 2024-09-02 16:25:41 +02:00
github-actions[bot]
12f5f95d0c Update translations [skip ci] (#6902)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-09-02 13:53:57 +02:00
D8H
c52168a967 Fix memory clearing/leak when a scene is paused or stopped (#6123) 2024-09-02 13:52:37 +02:00
AlexandreS
1e33a13cc5 Improve tilemap preview rendering (#6908)
- Remove FPS limitation
- Avoid useless computations
2024-09-02 12:10:43 +02:00
Vladyslav Pohorielov
505debd60c Add expressions to get Spine point attachments positions (#6907) 2024-09-02 10:35:30 +02:00
Aurélien Vivet
e3b7109154 Add a default shortcut for adding a comment in the Events Sheet (#6879) 2024-09-02 09:22:13 +02:00
D8H
9e25899d3e Remove an "only" in GDJS tests (#6906)
- Don't show in changelog
2024-08-31 00:28:10 +02:00
AlexandreS
87cb8f0d47 Activate user after creating it (#6901)
Don't show in changelog
2024-08-30 09:57:38 +02:00
github-actions[bot]
481c6da992 Update translations [skip ci] (#6886)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-08-30 09:28:33 +02:00
AlexandreS
7cbebbb82f Fix some tilemap UX paintpoints (#6899)
- When using a mouse, use left click only to paint. Middle click can be used to pan the view.
- Fix issues with undo/redo tile setting
2024-08-29 20:08:05 +02:00
AlexandreS
fcf668788b Add interface for teacher to manage education users (#6891) 2024-08-29 18:42:25 +02:00
D8H
0cc844a77f Make the experimental custom object visual editor accessible (#6897)
* This is an *experimental**, *still work-in-progress*, editor to build objects inside GDevelop - from small, reusable UI objects to larger parts of your game.
2024-08-29 18:33:25 +02:00
Clément Pasteau
a234d9bd35 Show game ads earnings (#6896)
* You can now see the earnings of the games you've published on gd.games, thanks to ads, at the top of your Games dashboard
* You can cash out that amount if you reach the threshold or exchange it with GDevelop credits
2024-08-29 18:27:40 +02:00
D8H
465a6ce2ab Fix custom objects hot-reloading (#6887)
- Don't show in changelog
2024-08-29 18:13:54 +02:00
D8H
7e2e19eb33 Improve tile map collision precision (#6895) 2024-08-29 18:13:08 +02:00
D8H
95101763f7 Hide the drop-down list about quick customization visibility (#6893) 2024-08-28 16:59:24 +02:00
D8H
d4bd5fc671 Hide required behavior properties in the object editor (#6889) 2024-08-28 14:07:36 +02:00
D8H
c7fcf48ba5 Hide a duplicated expression to get the text of a text input (#6892) 2024-08-28 14:07:23 +02:00
D8H
8926d4406f Fix to forbid default parameters from being dragged and dropped (#6888) 2024-08-27 19:20:45 +02:00
Clément Pasteau
9ed2173038 Multiplayer game host migration (#6878)
* Host of a multiplayer game is now automatically migrated to a new one, picked from the list of players, with the lowest ping.
* A new condition is available "Is host migrating" in order to adapt the game while the migration happens. This can take up to a few seconds. If your game has no interactions between players, you can leave it like this. Otherwise, you may want to pause the game while the host is changing!
* A new action is available to configure the lobby game to end instead of migrating when the host leaves. (This is useful if you prefer the host not changing during your game)
2024-08-27 14:30:36 +02:00
github-actions[bot]
2fc3bc337f Update translations [skip ci] (#6885)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-08-27 11:49:01 +02:00
Clément Pasteau
0b7cac79ef Allow changing Sync Rate of objects in a multiplayer game (#6884)
* Default sync rate of objects is now set to 30 times per second (was 60 before, but 30 is enough for most games)
* A new action can be used to update this value depending on the type of your game, at the cost of bandwidth. Fast-paced competitive? go for 60. Slow turn-based game? 10 is probably enough, or even less!
2024-08-26 18:27:27 +02:00
D8H
8721c0099e [Physics2] Merge the 2 world scale properties into one (#6865) 2024-08-26 15:16:01 +02:00
Aurélien Vivet
4453eee3b9 Fix default values for the Adjustement effect (#6883) 2024-08-26 14:11:44 +02:00
github-actions[bot]
0215ab7dbb Update translations [skip ci] (#6874)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-08-26 14:10:00 +02:00
AlexandreS
87f6d5b99f Fix update notifications translations on Desktop app (#6882) 2024-08-26 10:57:39 +02:00
D8H
a440b16f84 Fix a memory issue with default custom object configurations (#6881)
- Don't show in changelog
2024-08-23 20:30:45 +02:00
D8H
f3822ba0df Allow to center objects with the anchor behavior (#6880) 2024-08-23 19:02:31 +02:00
D8H
6c5813affd Fix hot-reload for variables (#6877) 2024-08-23 15:03:40 +02:00
D8H
be4fe62bb6 Allow to override custom objects default property values or to follow them (#6861) 2024-08-23 14:12:13 +02:00
AlexandreS
0a29999894 Add possibility to drop variable after last item (#6875) 2024-08-22 09:59:07 +02:00
Florian Rival
e8ac41f37e Fix formatting 2024-08-21 13:09:04 +02:00
Florian Rival
70657ae334 Fix stretched button and wording
Don't show in changelog
2024-08-21 11:24:54 +02:00
Arthur Pacaud (arthuro555)
39ae2d4852 Replace electron-is with electron-is-dev (#6852)
Only show in developer changelog
2024-08-21 09:32:38 +02:00
github-actions[bot]
39815bfe6c Update translations [skip ci] (#6872)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-08-21 09:17:42 +02:00
Florian Rival
9ff8db25dd Fix missing version file for C++ tests (#6873)
Don't show in changelog
2024-08-20 23:20:39 +02:00
Florian Rival
1da887f656 Bump newIDE version (#6871) 2024-08-20 18:25:06 +02:00
github-actions[bot]
e88ae0a7a9 Update translations [skip ci] (#6869)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-08-20 17:56:54 +02:00
Florian Rival
7ae74990b2 Add callouts on quick customization 2024-08-20 15:42:50 +02:00
Florian Rival
22ea1ce42c Fade in asset previews and animate quick publishing illustration
Don't show in changelog
2024-08-20 12:53:56 +02:00
D8H
a54367e360 Remove unused imports (#6870)
- Don't show in changelog
2024-08-20 10:57:32 +02:00
D8H
011abaf808 Allow drag and drop in the extension function parameter editor (#6847) 2024-08-20 10:29:52 +02:00
Florian Rival
a606a6567a Avoid useless loaders in asset store 2024-08-19 23:41:27 +02:00
Florian Rival
c9a6b88422 Fix scrolling wrongly retained between steps of Quick Customization dialog
Don't show in changelog
2024-08-19 17:59:25 +02:00
AlexandreS
e7f7fb1583 Fix having to select another function to reopen the same function on mobile in the extension editor (#6868) 2024-08-19 16:09:53 +02:00
github-actions[bot]
3cbb6644d4 Update translations [skip ci] (#6835)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-08-19 15:09:55 +02:00
AlexandreS
d34db53e09 Fix extension's behavior and object properties lists not scrolling on mobile (#6866) 2024-08-19 13:43:26 +02:00
Florian Rival
9c62a5e0f1 Fix unserialization of quick customization settings
Also remove VersionPriv.h from source control

Don't show in changelog
2024-08-19 12:13:12 +02:00
D8H
4b04101638 Allow custom objects and behaviors to use resources from properties (#6862)
Only show in developer changelog
2024-08-18 21:22:35 +02:00
Florian Rival
ad31a7843a Add VersionPriv.h to git ignored files [skip ci]
Don't show in changelog
2024-08-18 18:15:29 +02:00
Florian Rival
57371c3759 Add "Quick Customization" in the Get Started page (#6856)
* Choose a starter game and quickly replace objects and tweak their behaviors. The game is then automatically published so it can be shared: this is perfect for new users to get a taste of how a game works and make their own remix of a game before going further.
2024-08-18 18:04:53 +02:00
Vladyslav Pohorielov
6e7fc75e75 Fix GDevelop project files so they are versioned with the same version as the editor (#6859)
Only show in developer changelog
2024-08-14 21:10:11 +02:00
D8H
65653c92d6 Fix asset packs not opening from the home page (#6855)
- Don't show in changelog
2024-08-09 18:59:10 +02:00
D8H
a4106b7f79 Add an option in objects context menu to quickly swap assets of Sprites and 3D models (#6840)
* This is perfect for quickly prototyping or trying new game art
* Animation of the object that are missing in the asset are replaced by a copy of the 1st asset animation. 3D model volume is adjusted to stay the same while keeping asset proportions.
2024-08-09 13:40:26 +02:00
Florian Rival
3e9f2f3f3a Update README [skip ci] [ci skip] 2024-08-08 19:35:33 +02:00
AlexandreS
45f25df292 Fix storybook and add story for AsyncSemiControlledTextField (#6854) 2024-08-08 15:09:49 +02:00
AlexandreS
55eddb4972 Rework education marketing section (#6853)
Don't show in changelog
2024-08-08 13:45:17 +02:00
D8H
75566c9f38 Avoid to use an intermediate ThreeGroup for custom objects in the editor (#6837)
- 2D custom objects displayed in the editor now also use the origin point of their 1st child unless an hidden property force a location.
2024-08-07 18:24:39 +02:00
AlexandreS
8db8cbe3c2 Display the number of tilemap objects available in premium asset packs before purchase (#6851) 2024-08-07 16:40:50 +02:00
D8H
dd8c5dce2e Fix access to the prefab editor by hiding the drop-down menu item (#6850) 2024-08-06 11:47:49 +02:00
Arthur Pacaud (arthuro555)
2810056626 Allow hot-reloading of 3D models (#6848) 2024-08-05 21:33:14 +02:00
D8H
d082d4f5a4 Fix child object recycling in custom objects (#6846) 2024-08-05 10:08:58 +02:00
Florian Rival
eaa0f4077f Bump newIDE version (#6844) 2024-08-02 12:01:32 +02:00
D8H
7d73f58bc4 Fix a crash when renaming a child variable (#6839) 2024-08-01 16:13:51 +02:00
AlexandreS
9171b40429 Fix sentence in tile id action/condition (#6836) 2024-07-31 17:44:28 +02:00
AlexandreS
242fc49342 Bump newIDE version (#6834) 2024-07-31 14:18:56 +02:00
github-actions[bot]
7081fd570c Update translations [skip ci] (#6831) 2024-07-31 14:10:55 +02:00
D8H
34ecdce7fa Fix a regression on the virtual joystick position in the editor (#6832) 2024-07-31 12:03:22 +02:00
Joseph Spagnuolo
3a0903a19f Fix: correctly update version numbers after extension update (#6828) 2024-07-31 11:56:30 +02:00
AlexandreS
e1a4f88ba6 Implement new design for education marketing form (#6829) 2024-07-31 11:48:07 +02:00
AlexandreS
ed59498835 Remove unused imports (#6830) 2024-07-31 11:41:08 +02:00
D8H
4b70653a0b Add animation autocompletion for object groups (#6817) 2024-07-31 10:19:31 +02:00
github-actions[bot]
48dd91043a Update translations [skip ci] (#6825) 2024-07-31 09:14:58 +02:00
Aurélien Vivet
30e7ef5865 Fix some languages names (#6779)
Update iso-639-1 dependency 

---------

Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-07-30 18:13:14 +02:00
D8H
289c555fe4 Fix a crash in the object group editor of events-functions (#6823) 2024-07-30 18:01:43 +02:00
Florian Rival
803a55869c Forbid usage of constructor.name in the codebase (#6819)
Only show in developer changelog
2024-07-30 17:33:22 +02:00
AlexandreS
282f4c184f Add distraction-free mode for students (#6821) 2024-07-30 17:31:59 +02:00
AlexandreS
875237cc8b Fix global objects not being rendered on the scene editor (#6822) 2024-07-30 17:05:58 +02:00
github-actions[bot]
7aeb44d05e Update translations [skip ci] (#6820) 2024-07-30 17:03:25 +02:00
Florian Rival
e445ff710e Fix tilemap drawing blocked if touch going out of the canvas
Don't show in changelog
2024-07-30 11:05:36 +02:00
Florian Rival
e016babf71 Increase cloud project names max length (#6818) 2024-07-29 19:54:12 +02:00
github-actions[bot]
6a34e3c1db Update translations [skip ci] (#6802) 2024-07-29 16:50:52 +02:00
AlexandreS
82e819c033 Fix a few things in the new object group dialog (#6814)
Don't show in changelog
2024-07-29 16:49:38 +02:00
AlexandreS
72e5deeef3 Fix mobile users experience with tilemap painting (#6813)
Don't show in changelog
2024-07-29 15:53:53 +02:00
D8H
a91cc4557f Fix to make platformer wall collisions with tile maps more precise (#6810) 2024-07-29 15:35:52 +02:00
D8H
b2c953a31d Fix behavior autocompletion to be case insensitive (#6812) 2024-07-29 15:32:38 +02:00
D8H
b29fbaa1f8 Fix name collision between group variables and object variables (#6808)
- Don't show in changelog
2024-07-29 10:50:32 +02:00
D8H
e8faa17e12 Add a search bar in the properties editor (#6807) 2024-07-27 18:16:26 +02:00
D8H
2585ad5dca Avoid children variables to collapse in the editor after an undo (#6805) 2024-07-26 14:43:38 +02:00
D8H
a9108fa87b Add a tolerance parameter on the "linear velocity angle" condition (#6804) 2024-07-26 14:27:17 +02:00
D8H
cd3186d2d8 Fix duplicated "email" choice for text input type (#6803) 2024-07-26 12:22:36 +02:00
D8H
6a737f7d51 Fix particle emitter blending mode action (#6801) 2024-07-26 12:01:19 +02:00
github-actions[bot]
9211aa7a3b Update translations [skip ci] (#6799)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-07-26 11:41:23 +02:00
D8H
864ba181e9 Improve a comment (#6800)
Don't show in changelog
2024-07-26 11:22:52 +02:00
D8H
10fa3296a9 Fix text input disabled/read only actions, as well as a few other actions (#6797) 2024-07-26 11:04:25 +02:00
AlexandreS
2fb39b9dbe Add tooltips on tilemap painting icons (#6798)
Don't show in changelog
2024-07-26 10:00:27 +02:00
Clément Pasteau
6f43e896d6 Bump version to 5.4.206 (#6796) 2024-07-25 18:06:10 +02:00
github-actions[bot]
122df05f99 Update translations [skip ci] (#6795)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-07-25 18:05:36 +02:00
D8H
b7a5122b07 Add a variable editor for object groups (#6781) 2024-07-25 17:21:05 +02:00
Clément Pasteau
eb9d680d95 Instantly update lobby when a player leaves mid-game (#6794)
* Prevents seeing a player who has disconnected still in the lobby
2024-07-25 16:05:47 +02:00
github-actions[bot]
354da42a9e Update translations [skip ci] (#6791)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-07-25 14:22:52 +02:00
AlexandreS
aca37fdade Fix tile set identifier computation (#6792)
Don't show in changelog
Also adds expressions to get tileset dimensions
2024-07-25 12:39:33 +02:00
Clément Pasteau
bb6eb01153 New condition for multiplayer games to know if a player is connected (#6790) 2024-07-25 09:49:07 +02:00
github-actions[bot]
9fb086dcdf Update translations [skip ci] (#6787)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-07-24 18:48:20 +02:00
D8H
7e60a0246e Fix custom object getDrawableX/Y (#6789)
- Don't show in changelog
2024-07-24 17:48:00 +02:00
D8H
3cb2da3de5 Add autocompletion for parameter fields in events-based object events (#6770)
- Don't show in changelog
2024-07-24 17:23:20 +02:00
AlexandreS
ef23470a00 Add new object: (Integrated) TileMap (#6782)
This PR adds a new TileMap object that can be configured directly in GDevelop.

Import an atlas image, configure the tile size and start painting in the editor!
You can also configure which tiles should have a hit box and use them as platforms.
2024-07-24 17:06:13 +02:00
Clément Pasteau
196ea5e480 Fix multiplayer notifications (#6788)
Do not show in changelog
2024-07-24 15:14:53 +02:00
Clément Pasteau
e732f1952c Fix typo (#6786)
Do not show in changelog
2024-07-23 17:23:19 +02:00
github-actions[bot]
f5f024cc42 Update translations [skip ci] (#6784)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-07-23 17:16:20 +02:00
Clément Pasteau
6a3df62598 Improve lobbies connections (#6762)
* Lobby start is now more reliable, and wait for everyone to be connected to the host to start the game, rather than wait on a fixed countdown. This can speed up the start (as well as slow it down on slower connections.)
  * A timeout is still in place to start the game without the missing players if they couldn't connect

* Lobbies can now be joined after the game is started, if defined as such in the lobbies section of the game dashboard
  * new actions & conditions are available

* Slightly improve disconnection time in preview
2024-07-23 16:13:50 +02:00
D8H
75f049d911 Show the top of the 1st page when the asset store search changes (#6765) 2024-07-22 16:17:50 +02:00
D8H
4d0ac6f355 Add icons for scenes and scene events (#6785)
- Don't show in changelog
2024-07-22 15:22:36 +02:00
D8H
00a5c93b35 Automatically rename identifiers in event-based objects (#6769)
- Don't show in changelog
2024-07-22 15:14:03 +02:00
D8H
a90cc83967 Add a dialog to choose between 2D and 3D when creating a custom object (#6776) 2024-07-22 14:43:50 +02:00
Aurélien Vivet
87a5934df3 Update the AdMob extension to support Play Services v23 (#6780) 2024-07-22 13:42:09 +02:00
github-actions[bot]
d0245b8f1a Update translations [skip ci] (#6774)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-07-22 12:54:05 +02:00
D8H
45d73df6fb Fix initialization of local array variables (#6777) 2024-07-22 11:07:47 +02:00
AlexandreS
7ac600e92d Fix svg attrs (#6783)
Don't show in changelog
2024-07-22 10:31:50 +02:00
Aurélien Vivet
7ba8d0133e Declare shortcut CTRL+D to duplicate in object list (#6273)
Add duplicate shortcuts to objects list.
- Also applies the same shortcuts to the objects groups list.

---------

Co-authored-by: osmaneTKT <72160458+osmaneTKT@users.noreply.github.com>
2024-07-18 09:53:06 +02:00
D8H
e9adaa94c5 Remove unused imports (#6778)
Do not show in changelog
2024-07-17 10:24:36 +02:00
D8H
35da31c5c5 Add icons on tabs (#6771) 2024-07-16 14:44:11 +02:00
Aurélien Vivet
e65492e1a1 Translate properly the messages about a new update. (#6775) 2024-07-15 15:38:28 +02:00
AlexandreS
44827ea372 Fix errors when reading source files for autocompletions in JS events (#6773) 2024-07-15 11:01:24 +02:00
github-actions[bot]
ab3ffe6785 Update translations [skip ci] (#6759)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-07-12 16:09:59 +02:00
D8H
d83d049ac9 Fix GDJS type declarations and tests (#6768)
- Don't show in changelog
2024-07-11 14:37:10 +02:00
Aurélien Vivet
67a7bd7af2 Remove dead code (#6767)
Only show in developer changelog
2024-07-11 14:13:55 +02:00
D8H
6db5267878 Allow to drag and drop custom object properties (#6766) 2024-07-11 14:11:24 +02:00
Florian Rival
a51c223c9c Add experimental, work-in-progress visual editor for custom objects (aka "prefabs"/"templates") (#6699)
* Still to do: 
  * Properly handle effects (disable 3D effects) for layers
  * Handle hot reloading properly
  * Avoid duplicating the configuration of the custom object inside each object created from it. Instead, only store the modified values.
  * Add a "Extract as a custom object ("prefab")" when selecting instances in a scene.
  * Add a dialog to give choice between 2D or 3D object when creating one.
  * Make sure "behavior shared data" are properly handled (physics, pathfinding...)
  * Check if we need to give an expression to translate coordinates from the parent to the local custom object.
  * Ensure a deleted custom object does not break the editor

Co-authored-by: Davy Hélard <davy.helard@gmail.com>
2024-07-11 11:27:34 +02:00
Arthur Pacaud (arthuro555)
0a4e5a1012 Add an action (#6191) 2024-07-10 22:48:22 +02:00
D8H
acce714736 Fix raycast test. (#6763)
Do not show in changelog
2024-07-10 14:53:37 +02:00
Florian Rival
3c34a8806b Fix message asking to check Apple/Google account for subscription not always shown (#6761)
- This was the case when the app was opened from https://editor.gdevelop.io?initial-dialog=subscription
2024-07-09 16:42:01 +02:00
Florian Rival
1d4cb7bef0 Fix checkbox to disable ads not displayed properly after being changed (#6760)
* Also address some part of the game dashboard that could be outdated after changes
2024-07-09 16:41:44 +02:00
Clément Pasteau
7badacd24a Fix not building peerjs for web runtime (#6758) 2024-07-09 12:06:10 +02:00
github-actions[bot]
11ab92fc0e Update translations [skip ci] (#6752)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-07-09 10:02:32 +02:00
D8H
ddb1e335bc Improve raycast precision when the distance is 0 (#6757) 2024-07-08 14:51:29 +02:00
Tristan Rhodes
8d035a774d Add Star History to bottom of README (#6749) [skip ci] 2024-07-07 21:25:33 +02:00
Aurélien Vivet
5b1e3565d3 Remove dead code (TinyXml) (#6754)
Only show in developer changelog
2024-07-05 17:45:57 +02:00
Tristan Rhodes
8c88038bfb Added new condition to check the zoom of a camera of a layer (#6747) 2024-07-04 14:05:35 +02:00
D8H
f62811974d Remove an error about object name collision in object variable fields (#6751) 2024-07-04 12:56:25 +02:00
Florian Rival
b516037d2b Fix opening an example from a link or command line argument (#6750)
* An example opened from a link (typically, from the website) will now properly ask for the location where to save it, and will handle leaderboards and multiplayer.
2024-07-04 11:28:58 +02:00
D8H
98befc8000 Fix group list updating. (#6748)
Do not show in changelog
2024-07-03 10:57:59 +02:00
Clément Pasteau
377231fb37 Bump to 5.4.205 (#6746) 2024-07-03 10:27:36 +02:00
github-actions[bot]
22ae8ac489 Update translations [skip ci] (#6744)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-07-03 10:27:24 +02:00
Clément Pasteau
40674fd3b9 Guided lessons opening fixes (#6745)
Do not show in changelog
2024-07-02 17:40:46 +02:00
Clément Pasteau
0792e59b24 Speed up lobbies process in preview (#6743)
- start countdown is reduced
- players are readied automatically
2024-07-02 16:12:51 +02:00
github-actions[bot]
8ba6ad7b43 Update translations [skip ci] (#6741)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-07-02 15:48:29 +02:00
Clément Pasteau
84b07bc84d Open all scenes and focus on first one when opening a guided lesson (#6740)
Do not show in changelog
2024-07-02 15:48:09 +02:00
Clément Pasteau
c46d39cbed Fix returning player auth on first preview (#6742)
Do not show in changelog
2024-07-02 15:21:48 +02:00
github-actions[bot]
b96132964c Update translations [skip ci] (#6734)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-07-02 14:13:22 +02:00
Tristan Rhodes
130cd1e3a7 "Change platform type" action now uses a dropdown selector (#6727) 2024-07-02 14:11:39 +02:00
Clément Pasteau
fbbcf25bf5 Allow tagging a behavior of a multiplayer object as not synced (#6737)
* Also fix the synchronization of the activated state of a behavior
2024-07-02 14:05:51 +02:00
Aurélien Vivet
ffaae4d3d4 New guided lesson - Creating a Multiplayer Co-op game (#6736) 2024-07-02 10:35:36 +02:00
D8H
75d79a7758 Display errors on variable parameters about name collisions with objects (#6732) 2024-07-01 16:42:43 +02:00
D8H
d91fb78848 Use a new icon for global variables (#6735)
- Don't show in changelog
2024-07-01 15:15:41 +02:00
D8H
e0a2ed1654 Fix a refreshing issue of the object list in functions (#6725)
- Fix the default parameters when pasting a function in a behavior
2024-07-01 14:49:09 +02:00
Florian Rival
d5f2be1c19 Add an extra link to create a variable (#6730) 2024-07-01 14:28:51 +02:00
github-actions[bot]
7abcfe8af2 Update translations [skip ci] (#6731)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-07-01 13:01:08 +02:00
Clément Pasteau
b86dd9efce Bump memory for tests (#6733)
Do not show in changelog
2024-07-01 13:00:47 +02:00
github-actions[bot]
15f6b62c5b Update translations [skip ci] (#6724)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-07-01 12:04:26 +02:00
Clément Pasteau
eb995ec7c7 Fix emscripten core version (#6729)
Show in developer changelog only
2024-07-01 12:03:46 +02:00
D8H
a076571120 Fix some array variable expressions visibility (#6728) 2024-07-01 11:37:50 +02:00
Clément Pasteau
ec9cb790e7 Improve multiplayer messages by automatically detecting and using best compression method for lobby (#6690)
- Also remove dependency on P2P extension
2024-07-01 10:52:01 +02:00
D8H
4a283add00 Fix events shortcuts from triggering when a dialog is opened (#6726) 2024-06-30 17:31:00 +02:00
D8H
6b3faa42bb Make variables easier to declare on the fly (#6721) 2024-06-27 21:13:18 +02:00
Florian Rival
555ee61e63 Fix badges text color
Don't show in changelog
2024-06-27 13:00:33 +02:00
github-actions[bot]
b838c8549b Update translations [skip ci] (#6722)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-06-27 10:44:05 +02:00
Clément Pasteau
33db6ee359 Fix message sender expression (#6723)
Do not show in changelog
2024-06-27 10:43:42 +02:00
Clément Pasteau
f361d3e1fa Automatically log the user as a player in a preview (#6714)
* Simplifies creating & testing a game in preview, when using player authentication or multiplayer extensions
2024-06-27 09:38:23 +02:00
github-actions[bot]
441401f34c Update translations [skip ci] (#6719)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-06-26 16:09:55 +02:00
Aurélien Vivet
558daa2075 Remove extra "Add" words in the events context menu (#6713) 2024-06-26 09:37:50 +02:00
AlexandreS
cd475316df Limit leaderboard customization css field length (#6720) 2024-06-26 07:42:41 +02:00
D8H
8b21e72c85 Fix to avoid new variables from being added at the top (#6718) 2024-06-25 17:34:12 +02:00
github-actions[bot]
a9d6f18c11 Update translations [skip ci] (#6689)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-06-25 17:10:32 +02:00
Clément Pasteau
f58e1113b6 Add new actions and expressions for multiplayer (#6717)
* Send a variable with a custom message
* Retrieve the player number of the sender
2024-06-25 17:07:38 +02:00
D8H
f82b5fc66d Fix local variables default values when the wait action is used (#6715) 2024-06-25 16:14:40 +02:00
AlexandreS
2f19a9bb33 Improve some icons in the editor (variables, mobile toolbar) (#6700) 2024-06-25 12:42:41 +02:00
Dennis Fehr
8f739d85c2 Fix dragging bug in the Events Sheet when the indent scale is not 1x (#6702) 2024-06-25 10:07:09 +02:00
AlexandreS
f23847617d Add possibility for players to login with Google/Apple in game. (#6711) 2024-06-24 18:22:43 +02:00
Clément Pasteau
876332a782 Fix multiplayer lobbies properly opening after login (#6712) 2024-06-24 18:15:32 +02:00
D8H
93c74c9fd6 Use property names instead of property labels in descriptions and sentences of internal behavior instructions (#6708) 2024-06-23 17:45:21 +02:00
Florian Rival
e92d8496ac Add missing Spine Runtime license agreement and link to Spine website (#6701) 2024-06-21 18:18:03 +02:00
AlexandreS
35e67a6d26 Try to register game before copying lobby configuration (#6696)
Don't show in changelog
2024-06-20 18:04:29 +02:00
Clément Pasteau
740c7ae8bc Upgrade CircleCI macOS builders to m1 (#6688)
Only show in developer changelog
2024-06-20 10:26:47 +02:00
Clément Pasteau
432a91c47b Bump to 5.4.204 (#6682) 2024-06-20 08:40:39 +02:00
Clément Pasteau
799bc762aa Fix wrong import (#6687)
Do not show in changelog
2024-06-20 08:40:26 +02:00
github-actions[bot]
147a0eed53 Update translations [skip ci] (#6683)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-06-20 07:58:09 +02:00
Aurélien Vivet
920e1d423f rename tutorial (#6684)
Do not show in changelog
2024-06-19 20:41:05 +02:00
Aurélien Vivet
c013f319ee Add the new guided lesson: Fire Bullets with an action from a behavior (#6681) 2024-06-19 19:49:46 +02:00
Clément Pasteau
db53e84c6f Add more params to lobby connection (#6677)
Do not show in changelog
2024-06-19 19:02:13 +02:00
github-actions[bot]
4b85f710a9 Update translations [skip ci] (#6673)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-06-19 18:06:54 +02:00
Clément Pasteau
07a350dadd Use a separate logger for debugging multiplayer (#6680)
Do not show in changelog
2024-06-19 17:07:20 +02:00
Clément Pasteau
7ccbf91973 Automatically disable default controls for synchronized objects (#6678)
* For top down & platformer objects, when the object is not owned by the current player, it will automatically have default controls disabled
2024-06-18 18:19:56 +02:00
Clément Pasteau
410fecf715 Multiplayer improvements (#6676)
* An object changing layer during the game is now properly moved to the layer on the other players games
* Video object can be synced as well
* Pathfinding behavior is now properly synced, allowing a smooth prediction on other players games
* Spine object is now synced as well
2024-06-18 16:52:41 +02:00
AlexandreS
967bf5cbe3 Reinstate shadow behind snackbar (#6674)
Don't show in changelog
2024-06-18 15:37:32 +02:00
github-actions[bot]
0020f72850 Update translations [skip ci] (#6669)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-06-18 12:39:01 +02:00
Clément Pasteau
0eb7b85e77 Improve multiplayer sync (#6672)
* Fix a rare case where the lobby was joined but did not appear as such in the interface
* Text inputs are now synced properly
* Add 2 new expressions for current player ping & username
* Fix Physics2 behavior being properly synced
2024-06-18 12:38:16 +02:00
Florian Rival
063bf51783 Add 'reference' to generated documentation reference page titles [skip ci]
Don't show in changelog
2024-06-18 10:50:50 +02:00
Clément Pasteau
482fb3b85e Allow customizing the Events sheet indent scale (#6671)
Co-authored-by: Dennis Fehr <dennis.james.fehr@gmail.com> @cyraid
2024-06-18 10:49:39 +02:00
Florian Rival
9a4a84d2af Fix Player object ownership action/condition sentence 2024-06-17 21:56:50 +02:00
Florian Rival
9a705b98e2 Fix crash when launching multiple previews with a pop-up blocker 2024-06-17 18:37:50 +02:00
Clément Pasteau
da940abdc2 Multiplayer fixes (#6668)
* Prevent verticesBuffer to be synced for Physics2
* Ensure we create a force if no recycled are available
2024-06-17 18:35:20 +02:00
github-actions[bot]
528b8f4e6c Update translations [skip ci] (#6663)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-06-17 15:06:36 +02:00
Clément Pasteau
7212d56a1b Add folders for multiplayer extension (#6667)
Do not show in changelog
2024-06-17 14:53:12 +02:00
Clément Pasteau
5cba43335c Fix sentence for taking ownership (#6666)
Do not show in changelog
2024-06-17 14:28:08 +02:00
Clément Pasteau
324698e269 Fix parsing wrongly the variableNetworkId (#6665)
Do not show in changelog
2024-06-17 14:19:40 +02:00
Clément Pasteau
d219bf05d3 Fix the animation frame update for a Sprite when receiving new animation from the network (#6664) 2024-06-17 13:20:26 +02:00
D8H
9cbc421d74 Generate a default sentence for event-based functions (#6638) 2024-06-16 23:18:54 +02:00
Florian Rival
f63d9d1b5c Bump version 2024-06-16 10:30:32 +02:00
github-actions[bot]
dd5d0669b1 Update translations [skip ci] (#6661)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-06-16 10:29:40 +02:00
Clément Pasteau
e681632e60 Fix correctly parsing custom messages (#6662)
Do not show in changelog
2024-06-14 18:45:16 +02:00
AlexandreS
0bcb219e00 Inform lobbies iframe if opened from preview in native mobile app (#6659)
Don't show in changelog
2024-06-14 17:09:55 +02:00
D8H
6d5e9c1676 Fix regression on activate behavior action parameter (typo) (#6660)
- Don't show in changelog
2024-06-14 17:06:26 +02:00
github-actions[bot]
5ded5648bf Update translations [skip ci] (#6658)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-06-14 16:39:48 +02:00
AlexandreS
687f926bc5 Add logic to copy lobby configuration when opening an example (#6657)
Don't show in changelog
2024-06-14 15:41:58 +02:00
github-actions[bot]
4a2d573956 Update translations [skip ci] (#6641)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-06-14 15:39:12 +02:00
Clément Pasteau
ce77414f85 Allow assigning variable owners for multiplayer games (#6651)
* Actions can be used at the beginning of the game or a scene, to define scene and global variables as synchronised by another player, or not synchronised at all
2024-06-14 15:37:37 +02:00
D8H
298ff6311d Fix game properties editor to avoid empty values to make project saving fail (#6656) 2024-06-14 13:04:47 +02:00
Clément Pasteau
ca0a000ae1 Use a unique key for root extension configuration row (#6655)
Do not show in changelog
2024-06-14 11:21:58 +02:00
D8H
dc87f138a6 Fix expression validation for variables with brackets (#6652) 2024-06-13 18:38:35 +02:00
Aurélien Vivet
28af860aff Add a new guided lesson: Top-down movement for pixel perfect game (#6650) 2024-06-13 16:12:50 +02:00
AlexandreS
4dbc607314 Support boolean expected value in in-app tutorial (#6654)
Only show in developer changelog
2024-06-13 14:10:02 +02:00
Clément Pasteau
bfefe9baf4 Synchronize 3D objects properties properly over network (#6649) 2024-06-11 12:31:36 +02:00
Florian Rival
2332359c19 Fetch in-app tutorial descriptions/titles instead of hardcoding them (#6647)
Only show in developer changelog
2024-06-10 15:55:27 +02:00
D8H
68b6c443c3 Fix variables editor shortcut from events tabs (#6646) 2024-06-10 15:36:27 +02:00
D8H
37e113baaa Fix a regression on the expression autocompletion layout (#6645)
Don't show in changelog
2024-06-10 10:42:21 +02:00
D8H
a8a8c142a3 Fix format (#6642)
Don't show in changelog
2024-06-08 12:38:33 +02:00
D8H
012e625a47 Fix regression on activate behavior action parameter (#6639)
Don't show in changelog
2024-06-07 18:03:29 +02:00
github-actions[bot]
c0e6d98e4c Update translations [skip ci] (#6637) 2024-06-07 17:35:17 +02:00
D8H
ab63e02862 Fill empty behavior parameters in actions/conditions when a behavior is attached to an object (#6633) 2024-06-07 17:09:58 +02:00
D8H
1b13127a2f Display errors on objects with missing behaviors in the event sheet (#6632) 2024-06-07 16:52:13 +02:00
Florian Rival
3de0861172 Bump version (#6636) 2024-06-07 16:42:16 +02:00
github-actions[bot]
795417c915 Update translations [skip ci] (#6634)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-06-07 16:32:01 +02:00
Clément Pasteau
e8540dd720 Fix multiplayer tests (#6635) 2024-06-07 16:31:37 +02:00
Clément Pasteau
3c5fee0535 Add experimental support for multiplayer games ("GDevelop Multiplayer") (#6613) 2024-06-07 14:12:58 +02:00
github-actions[bot]
7f2806bd89 Update translations [skip ci] (#6618)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-06-07 09:54:34 +02:00
D8H
886fdb464e Fix a regression on the 1st scene loading (#6630)
- Don't show in changelog
2024-06-06 13:15:59 +02:00
AlexandreS
6aaeda6c49 UI improvements (#6631)
- Use red color for notifications badge
- Make snackbars have the same theme as the interface
2024-06-06 13:14:32 +02:00
AlexandreS
830e35b368 Add saving suggestions (#6627)
- Displays a message to remind you to save your project after significant changes
- Adds a dot badge to the Save icon to remind you you didn't save
2024-06-06 10:58:18 +02:00
D8H
fa4a621888 Fix variable autocompletion scope icon (#6628)
- Don't show in changelog
2024-06-05 18:22:22 +02:00
D8H
8756932c12 Fix the variable editor global tab initial opening (#6626)
- Don't show in changelog
2024-06-05 14:23:31 +02:00
D8H
0b5f929773 Display expression errors on repeat loops (#6625) 2024-06-05 13:49:14 +02:00
Aurélien Vivet
183fba4720 Add a new guided lesson: Platformer (#6623) 2024-06-05 10:27:01 +02:00
D8H
9d608a0e93 Fix project manager shortcuts from triggering when a dialog is open (#6624) 2024-06-04 19:06:44 +02:00
D8H
5bbfd81d89 Allow object variables to take the same name as an object (#6622)
- It also fixes the variable instance dialog cancellation.
- Don't show in changelog
2024-06-04 16:18:26 +02:00
Florian Rival
a441bb04ef Add "pip install setuptools" for Windows to readme (#6611)
Only show in developer changelog
2024-06-04 13:40:24 +02:00
D8H
ccf5e390d6 Fix 2D custom objects Z-order in the editor (#6620) 2024-06-03 23:05:02 +02:00
D8H
e633aa77c2 Remove unused import (#6619)
- Don't show in changelog
2024-06-03 19:16:31 +02:00
D8H
12275d0814 Always keep events when an object is deleted (#6615) 2024-06-03 18:04:11 +02:00
AlexandreS
4ed1889856 Add asset from asset store next to the selected item in the objects list (#6614)
- Also : hides variables list when multiple instances selected
2024-06-03 18:01:30 +02:00
D8H
ae6ac2068b Show object thumbnails in "for each object" loops (#6617) 2024-06-03 17:59:56 +02:00
github-actions[bot]
a31c5cfac3 Update translations [skip ci] (#6581)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-06-03 14:39:46 +02:00
D8H
1917d5aedd Rename child-variable occurencies in events (#6602) 2024-06-03 13:26:18 +02:00
D8H
d0c85cd3bc Remove extension metadata from exported data.json (#6612)
- Don't show in changelog
2024-06-03 11:51:56 +02:00
D8H
afed90ccef Show extension variables and properties in the tree (#6610)
- Don't show in changelog
2024-06-03 10:52:26 +02:00
D8H
ff9c6e5cf3 Display missing objects in the diagnostic report (#6608) 2024-06-03 10:48:45 +02:00
D8H
199d315e29 Add an icon for variables, parameters and properties in expression autocompletions (#6609) 2024-06-02 17:14:22 +02:00
AlexandreS
ddf426c2fd Handle Diagnostic report dialog when in app tutorial running (#6607) 2024-05-31 14:28:43 +02:00
AlexandreS
43648b0a18 Fix issues around local in-app tutorial development (#6606)
Don't show in changelog
2024-05-31 12:02:34 +02:00
AlexandreS
96e5d6966a Add possibility to load WIP in-app tutorial from local file (#6603) 2024-05-31 10:44:24 +02:00
Florian Rival
eb256b3412 Display some badges to earn on the Get Started page (#6604) 2024-05-31 09:13:34 +02:00
AlexandreS
d89bfd27f8 Fix: Improve analytics panel display (#6601) 2024-05-29 15:56:05 +02:00
D8H
7cef3b3a41 Fix local structure variable declaration generation (#6599)
- Don't show in changelog
2024-05-28 18:48:34 +02:00
AlexandreS
f3a87a2159 Fix local network preview url opening (#6598) 2024-05-28 16:55:19 +02:00
D8H
4df91f3e77 Fix rename refactoring from replacing variable occurrences from a smaller scope (#6596) 2024-05-28 13:49:12 +02:00
D8H
8ca82ef457 Add a button to add local variables (#6593)
- Don't show in changelog
2024-05-28 13:18:14 +02:00
D8H
0c3719ff0c Fix boolean value shown in local variable declarations (#6594)
- Don't show in changelog
2024-05-28 13:17:16 +02:00
D8H
a76ba988b2 Fix variable renaming to avoid to take an object name (#6597) 2024-05-28 13:05:17 +02:00
AlexandreS
8f002541ef Maintain subscriptions bought with PayPal until the end of the paid period (#6592) 2024-05-27 11:52:21 +02:00
D8H
6fd82376a8 Fix group variables autocompletion (#6595)
- Don't show in changelog
2024-05-27 11:20:13 +02:00
D8H
db2d6f90a3 Allow to use any variable in some actions (#6589)
- Don't show in changelog
2024-05-25 00:31:10 +02:00
Florian Rival
f32180d923 Allow to enter Twitter username in profile (#6591)
* If you follow the GDevelop Twitter account, a badge and some credits will be given to your account as a thank you!
2024-05-24 19:20:59 +02:00
D8H
4886cf4fd3 Fix the event height after adding local variables (#6590)
- Also fix local variable dialog cancel.
- Don't show in changelog
2024-05-24 16:39:11 +02:00
D8H
0fd25c381a Allow event-based extensions to declare unified variable parameters (#6588)
- Don't show in changelog
2024-05-24 12:27:47 +02:00
D8H
916e642465 Avoid to change a variable type when checking its type (#6587)
- Don't show in changelog
2024-05-24 10:56:12 +02:00
DavidMLPalma
eaebc16f49 Clean multi-file project folders at each save to avoid stale files (#6501) 2024-05-24 09:25:56 +02:00
D8H
231d92a2fa Allow any variables in for each child loops (#6585)
- Don't show in changelog
2024-05-23 18:30:11 +02:00
AlexandreS
e3cc01e902 Add form in Classroom tab to send education resources samples (#6584) 2024-05-23 16:21:31 +02:00
Florian Rival
fe68286eaf Allow to enter your Tiktok username (#6583)
* If you follow GDevelop page, a badge and some credits will be given to your account as a thank you for following us!
2024-05-22 18:06:26 +02:00
D8H
7d95e44b51 Fix renaming of local variables in sub-events (#6582)
- Don't show in changelog
2024-05-21 19:53:56 +02:00
Florian Rival
9b448f1ddf Update wording when changing subscription
Don't show in changelog
2024-05-21 12:56:08 +02:00
D8H
8f34a100e5 Fix extracted external layout name (#6580)
- Don't show in changelog
2024-05-21 10:10:06 +02:00
github-actions[bot]
cc3a9af8ce Update translations [skip ci] (#6545)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-05-21 08:17:25 +02:00
D8H
75bfa5cb45 Unify variable instructions and handle local variables (#6459)
- Global or scene variables can be used with a unique action and condition.
- Object variables can be used with a unique action and condition.
- Variables need to be declared following the same logic as the new expression syntax.
- Local variable can be declared on events
- Extensions have their own variables
- Show a diagnostic report when a preview is launched and there are missing scene variables, object variables or behaviors.
  - This is especially useful if external events are shared between several scenes.
2024-05-20 23:14:07 +02:00
D8H
5ac8f411fe Fix resources with empty name from being used or created (#6578) 2024-05-20 19:38:16 +02:00
D8H
870247a3df Add the "destroy when finished" parameter in events for opacity tweens (#6579) 2024-05-20 17:48:31 +02:00
D8H
80b68d3bb5 Add a hover message on linked external events when they come from another scene (#6563) 2024-05-20 14:22:46 +02:00
D8H
6e8a8d6868 Fix shared properties not being add to the scene when adding a behavior from the instruction editor (#6577) 2024-05-20 14:15:25 +02:00
AlexandreS
2310f2a618 Fix example opening not working from the example dialog (#6564) 2024-05-15 16:38:51 +02:00
D8H
f8bd3fca00 Add a drop-down menu action to extract selected instances as an external layout (#6561) 2024-05-14 19:34:39 +02:00
Clément Pasteau
92b9203ce8 Hide game templates when searching in asset store (#6556) 2024-05-13 09:18:43 +02:00
Florian Rival
4ca859c8b9 Allow player authentication in a leaderboard (#6552)
* Enable leaderboards to launch authentication and claim an anonymous score that was just sent
* Also automatically attach a score sent to the logged in player (unless deactivated)
* Make various fixes for authentication on iOS
2024-05-10 10:38:33 +02:00
AlexandreS
701b5a3250 Fix platform icons generation for cloud projects from desktop app (#6551) 2024-05-06 10:38:43 +02:00
Arthur Pacaud (arthuro555)
1e87b74d48 Disable caching in preview server (#6553)
* Useful in case the preview is proxied through a CDN

Only show in developer changelog
2024-05-05 16:48:00 +02:00
AlexandreS
b7a4bab53c Few fixes for the compact instance properties editor (#6547)
- Improve panel spacing
- Remove Restore icon on dimension fields if the instance uses the default size.
- When locking/unlocking multiple instances, apply same value to every instances
2024-05-02 11:48:42 +02:00
Clément Pasteau
2223b6516b Improve Marketing plan logic (#6546)
Do not show in changelog
2024-04-29 17:14:29 +02:00
AlexandreS
7d89208e7b Fix cloud project autosave crashing on Firefox versions <=125 (#6544) 2024-04-29 11:56:24 +02:00
AlexandreS
70508292e4 Bump newIDE version (#6541) 2024-04-25 11:38:53 +02:00
github-actions[bot]
c899db1dba Update translations [skip ci] (#6540) 2024-04-25 11:38:34 +02:00
D8H
2fb27f430e Fix "is on platform" condition that was no longer do anything (#6538) 2024-04-25 11:12:33 +02:00
AlexandreS
6cd2400848 Fix animation placeholder vertical centering (#6539) 2024-04-25 09:57:40 +02:00
github-actions[bot]
fadccba757 Update translations [skip ci] (#6533)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-04-24 15:14:35 +02:00
Florian Rival
29a43514ce Add a banner to encourage to fill the github username in the profile (#6536) 2024-04-24 13:35:51 +02:00
Florian Rival
e64ab94f76 Remove dead code (#6535)
Don't show in changelog
2024-04-23 18:22:57 +02:00
Florian Rival
ed969d2909 Add a field to enter the GitHub username in the user profile (#6534) 2024-04-23 17:48:15 +02:00
AlexandreS
77bf67fdf0 Bump newIDE version (#6532) 2024-04-23 10:38:42 +02:00
github-actions[bot]
580c7a370c Update translations [skip ci] (#6520) 2024-04-23 10:24:37 +02:00
Florian Rival
266f0f2b6e Disable rating of feedbacks that have no text 2024-04-22 10:40:34 +02:00
Florian Rival
58af6aacb4 Add tutorials in the Learn page for education subscribers (#6526) 2024-04-21 21:58:08 +02:00
D8H
1c4ee1c928 Fix some crashes when conditions with objectList are used without any behavior (#6529) 2024-04-21 11:16:31 +02:00
AlexandreS
0275476bec Fix cloud project autosave crash happening in particular situations (#6527) 2024-04-19 17:03:30 +02:00
AlexandreS
3f0194acf0 Increase lower toolbars size and padding on mobile (#6525) 2024-04-19 15:47:32 +02:00
AlexandreS
017d8b28c2 Fix copy (#6524)
Don't show in changelog
2024-04-19 11:21:21 +02:00
AlexandreS
4b518ba0fc Fix undefined resources when opening cloud project autosave after a time of inactivity (#6523) 2024-04-18 11:08:16 +02:00
AlexandreS
e4938b25b5 Fix dimensions set to 0 0 0 on instance when switching layer (#6522) 2024-04-18 10:35:38 +02:00
AlexandreS
c56ad2d277 Bump newIDE version (#6521) 2024-04-17 10:10:02 +02:00
github-actions[bot]
f069f9d942 Update translations [skip ci] (#6515)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-04-17 09:35:34 +02:00
D8H
9f7c60a69e Fix the particles emitter not to delete itself when the emission is paused (#6505)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-04-17 09:34:06 +02:00
AlexandreS
774bf0db61 Update limits for pro subscribers in stories (#6519)
Don't show in changelog
2024-04-16 16:49:14 +02:00
AlexandreS
ccd9c5c0ff Fix: Remove useless horizontal scroll in tree view (#6518) 2024-04-16 11:40:04 +02:00
AlexandreS
5b130a34e3 Fix: Holding space now prevents from resize/rotating an instance (#6516)
---------

Co-authored-by: Leonardo Alves <leonardo.alves@tecnico.ulisboa.pt>
2024-04-15 17:34:18 +02:00
AlexandreS
3e6d147660 Instance properties panel rework
The instance properties panel of the scene editor has been reworked into a more compact and user-friendly panel.
2024-04-15 15:29:27 +02:00
github-actions[bot]
433d85db94 Update translations [skip ci] (#6499)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-04-15 11:15:04 +02:00
D8H
b75f707b30 Use new icons for variable parameters in events (#6512) 2024-04-09 16:58:25 +02:00
Florian Rival
67799eb3eb Improve user profiles by showing games, asset packs and game templates made by the user (#6511)
* The app now shows the same profiles as those you can see on gd.games
2024-04-09 13:31:31 +02:00
AlexandreS
1173210386 Fix cloud projects autosave feature (#6510) 2024-04-08 19:12:19 +02:00
D8H
007cc48291 Fix missing object name field in some object editors (#6506) 2024-04-05 17:31:47 +02:00
D8H
12813c9ad9 Fix Sprite collision mask updating when animation frames don't share the same one (#6504) 2024-04-05 14:56:44 +02:00
Clément Pasteau
e503e34059 Fix asset pack & game template licenses being correctly purchased (#6502)
* An issue was always selecting the first license when the purchase dialog opened
2024-04-04 10:40:45 +02:00
Clément Pasteau
4bf576a889 Bump to 5.3.198 (#6500) 2024-04-03 17:57:57 +02:00
D8H
eff1c1bcb6 Fix a regression on "animation by index" action when the index is not an integer (#6498) 2024-04-03 15:00:40 +02:00
Clément Pasteau
abce34f2b1 Bump to 5.3.197 (#6497)
Do not show in changelog
2024-04-03 10:08:23 +02:00
github-actions[bot]
07276d5e16 Update translations [skip ci] (#6496)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-04-03 10:07:26 +02:00
Arthur Pacaud (arthuro555)
1fdd8cc792 Add an action to allow disabling P2P direct connections (#6475) 2024-04-02 22:38:41 +02:00
AlexandreS
79e40605d5 Fix collapse/expand arrow on event sheet for light themes (#6495) 2024-04-02 22:36:00 +02:00
D8H
fcc91e3fea Fix issues with Sprite animation frame updates (#6493) 2024-04-02 21:14:48 +02:00
github-actions[bot]
5c66623631 Update translations [skip ci] (#6487)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-03-28 12:07:38 +01:00
AlexandreS
5637642e1b Compute max discount instead of using hardcoded value (#6488)
Don't show in changelog
2024-03-28 11:05:13 +01:00
Florian Rival
7e8b44af2e Fix expressions involving a variable (or property) of type number/string wrongly rejected when an operator like + was used after them (#6467)
* For example, "Your score is " + NumberVariable + " points" was rejected, because the second operator type was not properly inferred.
* If something does not work in your game anymore, double check if your expressions in the events sheets are not underlined in red. Sometimes, adding `ToString(` or `ToNumber(` around it might be required.
2024-03-28 09:42:41 +01:00
Clément Pasteau
0dd4650aae Bump to 5.3.196 (#6486)
Do not show in changelog
2024-03-28 09:35:22 +01:00
github-actions[bot]
c7cac31830 Update translations [skip ci] (#6457)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-03-28 08:57:13 +01:00
Clément Pasteau
56cb8581c4 Fix plugin-consent version for admob (#6485) 2024-03-27 19:09:42 +01:00
Florian Rival
1993040b70 Add community leaderboard to highlight members doing great feedbacks (#6484) 2024-03-27 18:47:14 +01:00
AlexandreS
883991081a Define app theme related CSS variables at HTML body level (#6483)
Only show in developer changelog
2024-03-27 17:48:19 +01:00
D8H
7d8afef1ad Fix collision mask of rotated Spine objects (#6482)
- Fixes rotation of Spine objects in the editor.
2024-03-27 16:35:55 +01:00
Florian Rival
8178595546 Use a CSS module for SimpleTextField, to avoid name clashes (#6481)
Only show in developer changelog
2024-03-27 12:06:53 +01:00
AlexandreS
a478068c64 Add possibility to subscribe to GDevelop on a yearly basis (#6462) 2024-03-27 11:26:44 +01:00
Tristan Rhodes
368da1b610 New action for Physics behavior: Set the linear velocity towards an angle (#5670) 2024-03-27 08:27:00 +01:00
D8H
4ee43202e9 Fix sprite with resource tests (#6479)
- Don't show in changelog
2024-03-26 15:34:31 +01:00
Florian Rival
602fdf4bfd Fix warning
Don't show in changelog
2024-03-26 11:40:16 +01:00
Florian Rival
6110acafcc Add buttons to rate the quality of feedbacks (#6478)
* When you receive a feedback on a game, go to the Game Dashboard (or check the email notification for the feedback) to rank the comment as great, good or not useful. If a comment is abusive, spammy or harmful, you can also report it as such.
* Users making the best comments will be showcased in a leaderboard on the community page and on gd.games
* As a game creator, you're also benefit from this: games with the most rated feedbacks will be displayed in a leaderboard and on gd.games. We encourage you to take the time to rate the feedbacks you're receiving so your game becomes more visible to the community!
2024-03-26 11:28:45 +01:00
D8H
a3696ca9d1 Allow custom objects to use animations (#6426) 2024-03-25 10:47:28 +01:00
Clément Pasteau
1bb473b0b0 Display questions when canceling a subscription (#6471) 2024-03-22 14:07:59 +01:00
Florian Rival
4376b4f36e Improve first screen layouts (#6468) 2024-03-22 10:33:42 +01:00
Florian Rival
6ecbae9c35 Display the coordinates of the center point of a Sprite even when set automatically
Fix #6472
2024-03-22 10:33:05 +01:00
D8H
93e9fc6aed Fix missing expressions for text object (#6470) 2024-03-21 10:30:25 +01:00
Clément Pasteau
7c0a7a4152 Game templates in changelog (#6458)
Do not show in changelog
2024-03-14 16:42:38 +01:00
Clément Pasteau
d4cdb3ff83 Bump to 5.3.195 (#6455) 2024-03-14 16:20:15 +01:00
AlexandreS
a7cac91e45 Fix warning about end of subscription (#6456)
Do not show in changelog
2024-03-14 15:49:09 +01:00
D8H
6a6d72cd9a Fix games from crashing when a scene contains a wrapped text object with a big font size (#6453) 2024-03-14 15:36:34 +01:00
github-actions[bot]
11d74b3ea5 Update translations [skip ci] (#6442)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-03-14 15:31:27 +01:00
Clément Pasteau
5b65cf84eb Fix survey mobile (#6454)
Do not show in changelog
2024-03-14 15:00:57 +01:00
Clément Pasteau
6b7af0474f Improve Guided lessons (#6446)
* Lessons have been slightly reworked overall
* Most languages are now supported
* A new option allows to fill a value automatically with a button, speeding up the typing part
2024-03-14 14:40:12 +01:00
D8H
99f7e55044 Fix the object effect color tween action (#6452) 2024-03-14 14:13:28 +01:00
AlexandreS
6b522b1c31 Add support for game sessions achievements notifications (#6449) 2024-03-14 12:18:42 +01:00
D8H
0f35e48690 Allow to change text of custom objects like any text object (#6450) 2024-03-14 11:50:55 +01:00
D8H
53d19dd628 Fix custom object capability changes to be applied right away (#6447) 2024-03-14 10:49:33 +01:00
Florian Rival
155dc1bec8 Display redesigned subscription plans (#6440)
Don't show in changelog
2024-03-14 10:45:29 +01:00
D8H
be26e39eae Fix 3D custom objects CenterZ expression and condition (#6448) 2024-03-13 14:07:24 +01:00
TRP
90fa5ea8e8 Add action to draw a fillet rectangle with Shape painter (rounded rectangle with inverted corners) (#6433) 2024-03-12 16:11:02 +01:00
Florian Rival
4845251f78 Fix broken editor panels drag'n'drop (#6444) 2024-03-11 11:34:27 +01:00
Arthur Pacaud (arthuro555)
31ef3fec58 Add TypeScript type checking to JsExtension.js files (#6321) 2024-03-09 17:22:12 +01:00
Clément Pasteau
292b23ea17 Fix usage displayer (#6441)
* Fix wrong logic for usage displayer

* Bump version too
2024-03-08 18:11:11 +01:00
github-actions[bot]
9c5a5db7a8 Update translations [skip ci] (#6439)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-03-08 16:40:48 +01:00
Clément Pasteau
d73ae4c56e Bump to 5.3.193 (#6436) 2024-03-08 14:30:29 +01:00
D8H
339929e021 Sort 3D effects to show light and fog effects first (#6437) 2024-03-08 14:17:56 +01:00
github-actions[bot]
cea1cf20f1 Update translations [skip ci] (#6438)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-03-08 14:16:04 +01:00
github-actions[bot]
4ec2705f75 Update translations [skip ci] (#6435)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-03-08 12:36:52 +01:00
AlexandreS
408f6f8134 Display notifications to the user (#6432) 2024-03-08 12:15:21 +01:00
github-actions[bot]
c64bac0010 Update translations [skip ci] (#6424)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-03-08 09:54:15 +01:00
Clément Pasteau
f8d5c89ebf Allow using credits to start builds when quota is exhausted (#6430) 2024-03-08 09:26:18 +01:00
Florian Rival
ca3bb40e96 Store an achievement when finishing a tutorial (#6431) 2024-03-07 16:18:50 +01:00
Florian Rival
713d437b70 Fix naming of license file for Electron
Don't show in changelog
2024-03-07 10:15:04 +01:00
Florian Rival
09381c3836 Fix warning
Don't show in changelog
2024-03-06 17:47:08 +01:00
Florian Rival
ea4c2e0827 Fix useless query param
Don't show in changelog
2024-03-06 17:38:31 +01:00
Florian Rival
a5d1149c21 Rework the Get Started page to directly show recommendations for all users (#6428) 2024-03-06 17:35:30 +01:00
Florian Rival
119b0fadce Avoid rendering all asset packs and loading 100+ images in the Shop/Asset Store tab (#6425) 2024-03-06 17:11:32 +01:00
D8H
7111859768 Remove useless import (#6427)
Don't show in changelog
2024-03-05 15:44:07 +01:00
Vladyslav Pohorielov
08dfb4d36b Include PixiJS Spine pre-built files as part of the extension, like other extensions (#6340)
Only show in developer changelog
2024-03-05 15:28:23 +01:00
Florian Rival
cacd482af9 Fix type check for GDJS and documentation generation 2024-03-05 14:34:34 +01:00
D8H
3568a58019 Allow custom objects to be used as 3D objects (#6369)
- Custom objects like the 3D particle emitter can be used as any other 3D object
  - with the same set of actions and conditions thanks to the 3D capability
  - in the scene editor, their Z position and 3D rotations can be changed
- Fix child creation in `doStepPostEvent` function
2024-03-05 13:51:41 +01:00
Florian Rival
a32d5fcd7e Add file to ease detection of GDevelop by tool like SteamDB or Itch (#6423) 2024-03-05 13:12:16 +01:00
github-actions[bot]
1a999fd2dd Update translations [skip ci] (#6413)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-03-04 18:13:44 +01:00
Florian Rival
76648764bb Refactor EditorMosaic, add some placeholder for potential screen adaptation (#6421)
Don't show in changelog
2024-03-04 16:47:36 +01:00
Vladyslav Pohorielov
c25803c122 Fix Spine resources not loaded properly in games in the web-app version of GDevelop (#6416) 2024-03-04 16:03:48 +01:00
D8H
ba8d7f4e38 Fix a crash that sometimes happens when deleting links of an object (#6411) 2024-03-01 17:18:01 +01:00
AlexandreS
e1c22f6994 Display QRCode at the end of the gd games export flow (#6410) 2024-03-01 16:36:29 +01:00
Clément Pasteau
7b70f9172f Bump to 5.3.192 (#6408) 2024-03-01 12:58:55 +01:00
github-actions[bot]
a871e0f2ec Update translations [skip ci] (#6406)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-03-01 12:51:58 +01:00
Clément Pasteau
f6499e1163 Fix export flow with gdgames and show warning when game is not owned (#6407) 2024-03-01 12:34:23 +01:00
github-actions[bot]
d03e58636d Update translations [skip ci] (#6404)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-03-01 10:17:35 +01:00
AlexandreS
a7be928f2f Fix icons generating utility not working on macOS (#6405) 2024-02-29 17:07:35 +01:00
AlexandreS
7c83610d28 Fix missing s in Reponsive (#6403)
Don't show in changelog
2024-02-29 10:03:44 +01:00
github-actions[bot]
1a1e92b072 Update translations [skip ci] (#6398)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-02-29 09:52:55 +01:00
Florian Rival
5118f13e0b Add support for usages with 30 days period (#6401) 2024-02-28 18:20:41 +01:00
Clément Pasteau
f3ee18cdc7 Fix share tab and other design improvements on mobile + info alert when build is running (#6400)
Do not show in changelog
2024-02-28 15:12:33 +01:00
AlexandreS
c5584f746e Upgrade automatic pull request action (#6399)
Don't show in changelog
2024-02-28 14:34:57 +01:00
AlexandreS
706a6de94c Bump newIDE version (#6389) 2024-02-28 13:54:16 +01:00
github-actions[bot]
8c750b54dd Update translations [skip ci] (#6397)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2024-02-28 13:54:01 +01:00
AlexandreS
649d744664 Remove tree view nav with left and right arrow keys in project manager and events function list (#6396) 2024-02-28 13:53:30 +01:00
Florian Rival
12a6fec18e Ensure special characters like parenthesis are removed from Cordova project name to allow proper iOS app store upload (#6395)
Don't show in changelog
2024-02-28 13:35:13 +01:00
github-actions[bot]
7fc4aa47f6 Update translations [skip ci] (#6394)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-02-28 11:44:06 +01:00
github-actions[bot]
483f78fa75 Update translations [skip ci] (#6393)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-02-28 11:25:10 +01:00
Clément Pasteau
35b80818dc Improve export flow's overall design (#6392) 2024-02-28 11:04:42 +01:00
github-actions[bot]
b3f19726dc Update translations [skip ci] (#6391)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2024-02-28 10:50:47 +01:00
D8H
dd332e3cce Fix boolean property instruction group (#6386) 2024-02-28 10:24:03 +01:00
D8H
dc95a7511f Use a tree view for the project manager (#6346)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-02-27 16:51:59 +01:00
github-actions[bot]
77130c7d2e Update translations [skip ci] (#6382)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2024-02-27 16:25:46 +01:00
AlexandreS
8d1c3e8290 Improve display performance on Project and Team members lists (#6388) 2024-02-27 15:24:10 +01:00
AlexandreS
63570fd3c8 Paginate list of games (#6387) 2024-02-27 12:39:06 +01:00
AlexandreS
6945409280 Fix: Update BBText hitboxes when text changes (#6385)
- Also: Deprecate current font family setting action that uses a string as input and create a new action that uses a selector instead.
2024-02-27 08:57:17 +01:00
AlexandreS
e345b2726f Fix URL opening action on iOS (#6384) 2024-02-26 12:04:52 +01:00
github-actions[bot]
3a2a662f62 Update translations [skip ci] (#6380)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-02-23 19:35:40 +01:00
Clément Pasteau
73d850f933 Fix missing dependencies (#6381) 2024-02-23 19:35:24 +01:00
github-actions[bot]
1f2293e7d6 Update translations [skip ci] (#6371)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2024-02-23 18:54:24 +01:00
Clément Pasteau
b038984097 Display promotions & announcements only on a few pages & make it scrollable (#6379)
Do not show in changelog
2024-02-23 18:53:56 +01:00
AlexandreS
a45a5bfe7e Remove shuffling of data from backend services (#6378) 2024-02-23 17:33:25 +01:00
Florian Rival
8cbefa0cde Add support for iOS Cloud builds and automated publishing to App Store Connect (#6373)
* This allows to build directly from GDevelop, without any additional development tool or access to a Mac, a game for iOS.
* Builds can be done for development (testing on iPhone/iPad) or for the App Store directly.
* An Apple Developer account is required, so that you can generate the required certificate files (and authentication keys for uploading to App Store Connect).
* Using these new "iOS cloud builds" requires a Gold or a Pro subscription.
2024-02-23 16:42:09 +01:00
AlexandreS
1d607d474a Fix: Display audio previews in premium asset pack previews (#6377) 2024-02-23 16:07:17 +01:00
Florian Rival
3cd6e36a73 Fix scrollbars not properly styled in latest Chrome (#6376) 2024-02-23 12:16:51 +01:00
Florian Rival
cfbec2df4a Fix naming 2024-02-23 09:30:26 +01:00
Clément Pasteau
2823fde86a Few game template improvements (#6375)
Do not show in changelog
2024-02-22 14:36:33 +01:00
D8H
f29ae50f2e Fix 3d model resource changes not being detected by the other fields of the object editor (#6374) 2024-02-22 11:40:36 +01:00
Clément Pasteau
ba40c67941 Improve visibility on small tablets and mobiles in landscape (#6372)
* Prevent the screen to be detected as mobile and some layout to shift unnecessarily
2024-02-22 10:23:20 +01:00
D8H
c8ca3c2931 Fix a crash when the camera Z is changed and there is no 3D object in the project (#6370) 2024-02-21 10:36:33 +01:00
github-actions[bot]
0bb0969ab8 Update translations [skip ci] (#6365)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-02-20 12:07:31 +01:00
Clément Pasteau
3b0a7c442f Hide slideshow arrows when not hovering (#6367)
* And handle keyboard navigation

Do not show in changelog
2024-02-20 12:00:56 +01:00
AlexandreS
df3c95c466 Bump newIDE version (#6366) 2024-02-19 16:26:05 +01:00
AlexandreS
482d52ff5a Open example store from all templates list of build section (#6364)
Don't show in changelog
2024-02-19 16:13:19 +01:00
github-actions[bot]
5a78c763ef Update translations [skip ci] (#6358)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2024-02-19 14:15:40 +01:00
AlexandreS
3393af4b3b Add button to see more templates on the build section (#6359) 2024-02-19 13:57:41 +01:00
D8H
c2b77c9df7 Fix platformer character position when its height changes (#6360) 2024-02-19 12:57:26 +01:00
Clément Pasteau
514e4692ab Display promotion items on the homepage (#6353) 2024-02-19 12:45:49 +01:00
AlexandreS
210e59f201 Fix: Auto scroll to instruction item when editing an instruction (#6361) 2024-02-19 12:22:38 +01:00
D8H
e2058052f2 Fix a crash that sometimes happens when several sounds are played at the same time (#6357) 2024-02-19 11:04:01 +01:00
github-actions[bot]
90dca41e20 Update translations [skip ci] (#6351)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2024-02-19 10:29:05 +01:00
AlexandreS
15b463dad1 Add possibility to claim a monthly asset pack free of charge (#6350)
For gold and startup subscribers only
2024-02-16 17:54:45 +01:00
github-actions[bot]
a97a1f8a86 Update translations [skip ci] (#6348)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-02-16 14:15:40 +01:00
D8H
901f84daaa Add bloom and color effects for 3D layers (#6228)
- Add 3D Effects for color adjustment and bloom.
- A lower quality anti-aliasing is used when post-processing is enable (SMAA instead of MSAA).
- Upgrade to Three.js 0.160.0.
2024-02-16 14:12:46 +01:00
Clément Pasteau
6af50ae5c0 Show all products on app stores, purchasable with GDevelop credits (#6349) 2024-02-16 11:19:10 +01:00
AlexandreS
f7bd4bee6e Fix conflict between opening and previewing a private game template from the store section (#6347) 2024-02-15 14:39:11 +01:00
github-actions[bot]
4a4b015242 Update translations [skip ci] (#6345)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-02-15 14:35:19 +01:00
Clément Pasteau
75ee0b68e3 Allow buying asset packs and game templates with credits (#6343) 2024-02-14 17:03:38 +01:00
github-actions[bot]
778104447c Update translations [skip ci] (#6336)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2024-02-13 18:52:45 +01:00
D8H
a4ddc0a6ef Fix parameters drop-down list for properties of type choices (#6342) 2024-02-13 14:32:30 +01:00
D8H
3e713029e2 Fix visibility of hidden extension functions starting with an object parameter from within the extension (#6341) 2024-02-13 11:27:57 +01:00
D8H
7eb5402ee2 Keep original object and resource names when exporting assets (#6329) 2024-02-12 19:16:53 +01:00
AlexandreS
25adb026b8 Fix typo (#6337)
Don't show in changelog
2024-02-09 12:14:48 +01:00
Clément Pasteau
54bd2960ac Fix doublons in example tags search (#6335) 2024-02-09 12:14:34 +01:00
AlexandreS
1fde65b5e3 Fix template opening (#6334)
Don't show in changelog
2024-02-09 12:06:28 +01:00
github-actions[bot]
b4295b4077 Update translations [skip ci] (#6332)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2024-02-09 11:42:05 +01:00
AlexandreS
c7a929374d Fix homepage navigation (#6333)
Don't show in changelog
2024-02-09 10:09:02 +01:00
AlexandreS
7571e64396 Bump newIDE version (#6331) 2024-02-09 10:08:38 +01:00
github-actions[bot]
198267d7cb Update translations [skip ci] (#6325)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2024-02-09 09:36:53 +01:00
Aurélien Vivet
0982424d0d Set a preference for the importation of resources for projects stored on the computer (#6318) 2024-02-09 09:33:58 +01:00
D8H
29747690c2 Remove unused method declaration (#6330)
* don't show in changelog
2024-02-08 19:14:41 +01:00
AlexandreS
ad74532752 Remove unused import (#6328)
Don't show in changelog
2024-02-08 15:56:15 +01:00
AlexandreS
80e5376f74 Make opening screen more stable and reliable (#6327) 2024-02-08 15:40:50 +01:00
D8H
cc24eab2aa Allow to set the text outline and shadow from the object editor (#6246)
* Avoid the shadow to be cut out.
* Fix the shadow angle action.
2024-02-08 13:11:18 +01:00
D8H
423c8165ad Collapse advanced behavior properties (#6326) 2024-02-08 13:08:52 +01:00
D8H
0af00818dc Allow to select instances with a selection rectangle starting from within another instance holding Shift (#6304) 2024-02-07 16:24:37 +01:00
D8H
9f5c783d73 Keep 3D model origin as part of the object when used as the object origin (#6303)
- In case you choose "Model origin" for the "Origin point" property and the model origin is outside of the model, the model size may be smaller than in previous releases. To solve the issue you can:
  - Choose one of the other options for the "Origin point" property
  - Reset the "Scaling factor" to its previous value to get back the same size as before
  - Modify the model to set the origin nearer to the geometry
- Also fix the scaling of flat 3D models
2024-02-07 15:26:07 +01:00
github-actions[bot]
ad65971c01 Update translations [skip ci] (#6320)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-02-07 14:43:44 +01:00
Clément Pasteau
85ef9a9561 Fix casing gdevelop (#6323)
Do not show in changelog
2024-02-07 12:40:24 +01:00
AlexandreS
455d77fcdf Add possibility to cancel edition with Piskel/Jfxr/Yarn from the editor (#6319) 2024-02-05 18:12:43 +01:00
github-actions[bot]
02093fec0f Update translations [skip ci] (#6300)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-02-05 10:51:30 +01:00
Clément Pasteau
8227ab9cad Fix add assets button from shop being always visible (#6316) 2024-02-05 10:43:57 +01:00
D8H
f8eb91f3d2 Fix a crash when exporting assets sharing the same resources (#6314) 2024-02-03 13:41:09 +01:00
AlexandreS
a260aa5e3e Hide play tab for student profiles (#6313) 2024-02-02 11:13:37 +01:00
AlexandreS
4d8d93a550 Put Instances list search bar at the same place as the other panels in Scene editor (#6312) 2024-02-02 10:23:22 +01:00
AlexandreS
cf160bcca1 Improve game templates and examples display on build page (#6309) 2024-02-01 15:25:49 +01:00
D8H
44a0e22f97 Add autocompletion for "input type" action of text input objects (#6308) 2024-02-01 11:54:09 +01:00
D8H
d47d3285b2 Fix particle emitters not deleting itself when all their particles die before being displayed (#6306) 2024-01-31 20:12:28 +01:00
D8H
2ee6590967 Avoid event-functions to be selected when their menu is shown (#6301) 2024-01-30 11:44:16 +01:00
AlexandreS
cd77951e1a Fix game template/example search when there are only game templates matching (#6302) 2024-01-30 11:37:24 +01:00
D8H
fa4efef857 Fix a missing parameter in the sentence of the tween progress condition (#6299) 2024-01-30 10:35:25 +01:00
AlexandreS
bc8204d696 Remove cancel button when not logging in with provider (#6298)
Don't show in changelog
2024-01-30 10:07:18 +01:00
github-actions[bot]
b2eab5a327 Update translations [skip ci] (#6285)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-01-30 09:38:18 +01:00
Clément Pasteau
dba65822dd Avoid showing a loader on profile and user chip on subsequent loads (#6296) 2024-01-30 09:23:09 +01:00
AlexandreS
8f155e4322 Fix version history displaying loader on locally-stored projects (#6295) 2024-01-29 17:34:30 +01:00
D8H
13ebe5c588 Select the highest 3D objects first (#6294) 2024-01-29 16:18:48 +01:00
AlexandreS
bcd8e5608a Fix action/condition selector not updating on object change (#6291) 2024-01-29 14:18:44 +01:00
D8H
14e444413d Use the object name as the default new image name (#6293) 2024-01-29 14:01:53 +01:00
D8H
a2f75bc0dc Show installed version in the extension detail dialog (#6292) 2024-01-29 12:37:30 +01:00
D8H
6914e01a15 Fix behavior function renaming (#6290) 2024-01-29 11:18:23 +01:00
D8H
90b5f7a322 Fix the orthographic camera zoom update and its default Z position (#6288) 2024-01-29 11:17:57 +01:00
AlexandreS
13cf9b1d0b Show error box when there's an error logging in with provider (#6284)
Do not show in changelog
2024-01-26 16:28:48 +01:00
Clément Pasteau
6fc0198298 Bump version to 5.3.188 (#6283) 2024-01-26 16:26:11 +01:00
github-actions[bot]
0999ba611d Update translations [skip ci] (#6265)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-01-26 16:25:56 +01:00
Clément Pasteau
119d1af76a Game template bundles can be displayed and bought (#6275)
Do not show in changelog
2024-01-26 16:17:58 +01:00
AlexandreS
d6b4dacb1e Add possibility to sign up using Google, GitHub and Apple (#6249) 2024-01-26 15:46:18 +01:00
D8H
9edb3cfe91 Fix missing collision masks on new Sprite objects (#6282) 2024-01-26 15:25:12 +01:00
D8H
d44a1c3537 Generate particle textures only once (#6280) 2024-01-26 14:33:52 +01:00
AlexandreS
8cc84e5728 Fix legacy plans not showing in the user profile
Also: adds back the possibility to cancel a legacy subscription
2024-01-26 14:17:59 +01:00
D8H
76130b43d4 Handle export of assets with animations sharing frames (#6274) 2024-01-26 13:46:42 +01:00
D8H
40b0823b91 Fix a memory leak in the 2D particle emitter (#6278) 2024-01-26 12:23:13 +01:00
D8H
9b447e08e2 Forbid life-cycle functions to be renamed (#6269) 2024-01-25 14:53:07 +01:00
Aurélien Vivet
10314a1911 Fix focus not set in deletion confirmation dialog (#6270) 2024-01-25 14:16:17 +01:00
D8H
d0195719c2 Fix the 2 columns layout that may show hidden properties (#6268) 2024-01-25 12:18:52 +01:00
D8H
dd8c040381 Fix a crash when displaying the contextual menu of titles in object group lists (#6263) 2024-01-25 11:45:17 +01:00
D8H
5e0c8a92aa Fix a crash in the sprite editor of a child-object (#6266) 2024-01-25 11:44:31 +01:00
github-actions[bot]
977c102ddc Update translations [skip ci] (#6264)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2024-01-25 10:58:54 +01:00
Clément Pasteau
849d79d5d7 Avoid creating multiple canvas for ThreeJS (#6259) 2024-01-25 10:58:24 +01:00
D8H
28f7c9ae0b Fix a crash when the scale tween action is used in a 2D game (#6260) 2024-01-25 10:49:34 +01:00
github-actions[bot]
38e58327fa Update translations [skip ci] (#6244)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-01-24 11:22:04 +01:00
Clément Pasteau
3cc29efaa2 Remove report button on editor crash to avoid cluttering Github issues (#6247)
Do not show in changelog
2024-01-24 11:14:38 +01:00
Clément Pasteau
65eb76fb57 use newer electron builder (#6227)
Co-authored-by: romw314 <106016361+romw314@users.noreply.github.com>
2024-01-24 11:14:19 +01:00
AlexandreS
9eb721662f Remove useless margins (#6242)
Don't show in changelog
2024-01-23 14:22:39 +01:00
github-actions[bot]
b10b131010 Update translations [skip ci] (#6238)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2024-01-23 14:13:37 +01:00
Tristan Rhodes
b5fd1bb351 Improved wording "Stop music and sounds at the beginning of this scene" (#6240) 2024-01-23 14:05:31 +01:00
Aurélien Vivet
f1c9521625 Fix sentence of the Draw a Torus action (#6239) 2024-01-23 11:00:28 +01:00
github-actions[bot]
6ceb3c2c10 Update translations [skip ci] (#6234)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2024-01-22 15:38:34 +01:00
AlexandreS
43827876cd Fix subscription changes (#6236)
Don't show in changelog
2024-01-22 15:37:15 +01:00
AlexandreS
62b746300a Adapt credit banner button color to each theme (#6237)
Don't show in changelog
2024-01-22 15:29:33 +01:00
AlexandreS
769ebcd91c Fix credit banner text color on light themes (#6235)
Don't show in changelog
2024-01-22 11:12:57 +01:00
Florian Rival
70d5de16bf Fix Windows code signing (#6233) 2024-01-21 22:03:44 +01:00
Clément Pasteau
7fbe1bd23d Bump version to 5.3.187 (#6214) 2024-01-18 17:58:12 +01:00
github-actions[bot]
de8a679e31 Update translations [skip ci] (#6217)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-01-18 17:57:31 +01:00
Clément Pasteau
a1a4029b35 Introduce GDevelop credits and Marketing Campaigns (#6209)
* Credits can now be purchased from your Profile
* They can be used to purchase marketing campaigns, in order to promote your game on gd.games, with GDevelop social networks, or even within GDevelop itself.
* In the upcoming months, credits will unlock more and more exclusive perks in the app
2024-01-18 17:20:28 +01:00
Clément Pasteau
a377467031 Revert "Type JsExtensions files with typescript" (#6220)
Don't show in changelog
2024-01-18 16:01:28 +01:00
AlexandreS
dd090fd1d7 Abort login with providers (#6215)
Don't show in changelog
2024-01-18 12:32:01 +01:00
D8H
26ee9b3891 Avoid to add useless attributes on serialized extensions (#6216)
Don't show in changelog
2024-01-18 09:53:53 +01:00
Arthur Pacaud (arthuro555)
ad18eab4ae Type JsExtension.js files with TypeScript (#6200)
* Also improve typing of the C++ Core classes in TypeScript.

Only show in developer changelog
2024-01-18 09:53:24 +01:00
github-actions[bot]
007fc36a2e Update translations [skip ci] (#6184)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2024-01-18 09:36:40 +01:00
D8H
c8ebfde85b Fix platformer characters turn back speed when the deceleration is greater than the acceleration (#6208) 2024-01-17 18:32:14 +01:00
Vladyslav Pohorielov
d0005ba2cb Add support for Spine objects (2D skeletal animation) (#5927)
* This allows to use animatable 2D objects created with Spine (purchase a licence on [their website](https://esotericsoftware.com/) if you're interested).
* 2D skeletal animation allows for very smooth animations, and keep resource usage low compared to animations made of frames like Sprite objects. It's perfect for 2D games and can be used for animated characters, avatars, UI elements.
* Many thanks to @f0nar and @LousyMolars for their work on this new feature and associated game examples!

---------

Co-authored-by: Vladyslav Pohorielov <vpohorielov@playtika.com>
Co-authored-by: Gleb Volkov <glebusheg@gmail.com>
Co-authored-by: Florian Rival <Florian.rival@gmail.com>
Co-authored-by: Davy Hélard <davy.helard@gmail.com>
2024-01-17 18:19:08 +01:00
D8H
f623b352ee Hide deprecated properties of the platformer character behind a button (#6199) 2024-01-17 10:53:55 +01:00
D8H
16e2d8a005 Move some properties of the platformer character behavior in 2 columns (#6197) 2024-01-16 12:22:13 +01:00
D8H
7654883cb1 Allow to use orthographic camera in 3D layers (#6187) 2024-01-15 23:05:23 +01:00
D8H
3ae5db2a49 Fix scale and camera zoom tweens from setting NaN when the initial value was 0 (#6178) 2024-01-15 14:44:10 +01:00
Arthur Pacaud (arthuro555)
9ed002c879 Add expression to read the authenticated user unique identifier (#6192)
* This is useful if you want to interface with a third party or in-house solution to store user data.
2024-01-15 14:00:14 +01:00
Florian Rival
d4283c2350 Add new icon for 3D model objects (#6186) 2024-01-12 18:24:43 +01:00
AlexandreS
5a176d21e7 Add SSO to login/sign up (#6167)
Feature hidden in live environment.

Don't show in changelog
2024-01-12 14:45:16 +01:00
D8H
bfdfd7f0fb Improve the new UI of the extension editor (#6165)
- Add icons for behavior and object in the function tree
- Move the indicators on the right.
- Remove the big button.
- Fix the effect icon.
- Add checkboxes for the visibility.
- Rename on double click.
- Fix indentation.
- Hide the 3 dots button.

- Don't show in changelog
2024-01-12 13:11:16 +01:00
AlexandreS
aae75f2232 Fix use of Warning icon in tooltips (#6183)
Don't show in changelog
2024-01-12 13:04:20 +01:00
github-actions[bot]
977092c0a3 Update translations [skip ci] (#6179)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2024-01-12 12:38:05 +01:00
D8H
556688cedb Add pagination to asset store results (#6174) 2024-01-11 17:52:46 +01:00
github-actions[bot]
ce93dc5310 Update translations [skip ci] (#6170)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-01-10 15:57:04 +01:00
Clément Pasteau
d6d425db4f Show premium game templates from the same author on a template's page (#6168) 2024-01-10 15:42:51 +01:00
AlexandreS
2737e75639 Fix merge issue (#6169)
Don't show in changelog
2024-01-10 15:35:31 +01:00
github-actions[bot]
36eab18133 Update translations [skip ci] (#6164)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2024-01-09 16:30:55 +01:00
Clément Pasteau
48acbb12ee Decode filenames from any URLs before using them (#6018)
Only show in developer changelog
2024-01-09 16:00:09 +01:00
Florian Rival
21904e46f1 Avoid an extra click to purchase an asset pack or game template (#6161) 2024-01-09 15:32:33 +01:00
AlexandreS
94753ac053 Get subscription plans from server (#6128)
Don't show in changelog
2024-01-09 15:28:28 +01:00
github-actions[bot]
b160ee9b27 Update translations [skip ci] (#6147)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2024-01-09 15:15:24 +01:00
D8H
f76e8a72b6 Make the function property editor better adapt to small size (#6158) 2024-01-08 18:11:18 +01:00
D8H
5bc342688d Fix the cameras position to keep them centered on the object they follow when the game resolution is changed (#3821)
- Also fix the camera position for pixel-art games when a zoom and a game resolution change is used to have big pixels
2024-01-08 12:43:50 +01:00
D8H
3e6204c0eb Remember the size of mosaic nodes when they are uncollapsed (#6156)
- Don't show in changelog
2024-01-08 12:42:31 +01:00
D8H
7b1c340ad0 Fix game crashing at loading when video files are missing (#6155) 2024-01-08 12:08:48 +01:00
D8H
fac724dc3f Fix the indentation of extensions exported from the web-app (#6148) 2024-01-05 11:47:54 +01:00
D8H
9b4151f64c Add a button to export all the objetcs of a scene to submit them to the asset store (#4848)
* The dialog can be reached from the hidden drop-down menu of "Scene objects".
2024-01-05 11:09:27 +01:00
github-actions[bot]
6b5ab6c811 Update translations [skip ci] (#6130)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2024-01-05 10:06:13 +01:00
Clément Pasteau
5943092b0c Fix correctly taking folders into account when adding assets from the Home Store (#6146) 2024-01-05 10:05:44 +01:00
D8H
deb0c5ffc3 Display events functions of extensions in a tree view (#6133) 2024-01-04 18:14:44 +01:00
Clément Pasteau
c56fa03bf6 Fix crash when trying to access a child of a non existing structure child in an expression (#6144) 2024-01-04 16:20:49 +01:00
D8H
0d49d449db Import several animations to a sprite object in one go (#6035)
- Sprite animations are automatically created when several image files are selected and they ends with an animation name and an optional frame index (most naming conversions should work).
2024-01-04 11:02:04 +01:00
Clément Pasteau
fdd702cd09 Fix renaming a layer with external layouts (#6140)
* Instances of external layouts and of the attached scene are now all moved properly to the renamed layer
2024-01-04 10:31:34 +01:00
Clément Pasteau
5a8e4a7ca9 Allow confirming and canceling confirmation dialogs with keyboard shortcuts (#6138) 2024-01-03 14:52:36 +01:00
D8H
2e4e91c21e Add tween actions (position, rotation and depth) for 3D objects (#6122) 2024-01-02 10:03:59 +01:00
AlexandreS
6ece930809 Use axios error extractor where possible (#6132)
Only show in developer changelog
2023-12-27 19:40:16 +01:00
AlexandreS
c5baa81977 Display Game template categories with chips (#6129)
Don't show in changelog
2023-12-27 16:10:19 +01:00
github-actions[bot]
d24be38874 Update translations [skip ci] (#6109)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-12-27 10:35:14 +01:00
AlexandreS
1efffbbb78 Fix: Avoid project commit error by retrying call to server (#6127) 2023-12-26 12:12:25 +01:00
D8H
090d76a368 Show a drop-down list for string with choices parameters (#6120) 2023-12-22 15:31:43 +01:00
D8H
d44a9375de Add variables autocompletion for groups in variable fields (#6110) 2023-12-21 12:20:14 +01:00
AlexandreS
5a2a3893f9 Remove dashboard from profile dialog (#6113) 2023-12-21 12:08:23 +01:00
AlexandreS
0a6b0dc785 Use cloud storage provider internal name (#6108)
Don't show in changelog
2023-12-20 12:15:04 +01:00
github-actions[bot]
02e99726dc Update translations [skip ci] (#6103)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-12-20 11:55:13 +01:00
AlexandreS
843055d8df Add error message when versions fail to load (#6105)
Don't show in changelog
2023-12-20 11:40:07 +01:00
AlexandreS
f7fda5cb5e Fix placeholder thumbnail in objects lists for prefabs (#6107) 2023-12-20 11:37:28 +01:00
AlexandreS
e529642aec Fix program opening count logic when user has never acknowledged the feature (#6106)
Don't show in changelog
2023-12-20 10:01:35 +01:00
AlexandreS
c8e10d7043 Bump newIDE version (#6104) 2023-12-19 12:25:29 +01:00
AlexandreS
5f0de0e9a7 Adapt extract changelog script to currently used format (#6102)
Only show in developer changelog
2023-12-19 12:18:25 +01:00
github-actions[bot]
e51638ce4b Update translations [skip ci] (#6101)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-12-19 12:17:54 +01:00
AlexandreS
0fbd6a606a Add possibility to restore a previous version of a cloud project (#6022)
- Display all the project versions (paginated)
- Allow to open any version and name it for better tracking
- Make it possible to restore a given version
2023-12-19 11:50:28 +01:00
github-actions[bot]
2fa543c3db Update translations [skip ci] (#6083)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-12-18 16:56:41 +01:00
AlexandreS
38e35c9695 Prevent crash on new object dialog (#6099) 2023-12-18 16:50:21 +01:00
Florian Rival
ad13a1a101 Fix changes done in an extension not applied when clicking on 'Share' immediately without a preview or navigation in the editor (#6098) 2023-12-18 16:02:27 +01:00
AlexandreS
cb9d98d027 Wait 10 program openings before displaying GamesDashboard info (#6097)
Don't show in changelog
2023-12-18 15:51:23 +01:00
D8H
064c3f1572 Fix warning in the object list (#6091)
- don't show in changelog
2023-12-15 18:46:40 +01:00
D8H
9e5320f9d4 Add an item menu to add sub-folders in object folders (#6090) 2023-12-15 17:56:19 +01:00
Clément Pasteau
a1826d355d Rework subscriptions display in Profile (#6089) 2023-12-15 17:27:48 +01:00
D8H
32a3a094d1 Add new objects under the selected one in the list (#6087) 2023-12-15 16:51:50 +01:00
D8H
ee7dc2654b Fix parameter value choices autocompletion (#6086) 2023-12-15 12:02:24 +01:00
Clément Pasteau
64ffad3c0a Bump to 5.3.185 (#6082) 2023-12-14 14:06:01 +01:00
github-actions[bot]
dcc62f078f Update translations [skip ci] (#6076)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2023-12-14 13:54:43 +01:00
D8H
d920f05dbc Fix animation scanning in the 3D model object editor (#6080) 2023-12-14 13:28:38 +01:00
AlexandreS
ac82be800b Fix: update file metadata when saving cloud project triggers new commit (#6074) 2023-12-13 16:50:50 +01:00
Aurélien Vivet
2c92ae4042 Fix typo (#6075) 2023-12-13 16:35:36 +01:00
Clément Pasteau
465e934605 Bump version to 5.3.184 (#6072) 2023-12-13 14:34:04 +01:00
github-actions[bot]
248ba7675e Update translations [skip ci] (#6070)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-12-13 14:19:15 +01:00
AlexandreS
fd2b59ba45 Revert "Use python3 to update bindings (#6068)" (#6071)
This reverts commit 6edf63e98f.

Only show in developer changelog
2023-12-13 12:01:14 +01:00
Clément Pasteau
be54236ece Fix using which from key event when not defined (#6069)
Do not show in changelog
2023-12-13 11:59:57 +01:00
AlexandreS
6edf63e98f Use python3 to update bindings (#6068)
Only show in developer changelog
2023-12-13 11:36:44 +01:00
github-actions[bot]
034f1ad9cc Update translations [skip ci] (#6057)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2023-12-12 15:42:47 +01:00
Florian Rival
94b8c31ac2 Allow to increment position of points of sprites by 0.5 in the editor 2023-12-12 15:11:21 +01:00
Florian Rival
57d1241e2d Allow to increment position of vertices of collision masks by 0.5 2023-12-12 15:08:50 +01:00
github-actions[bot]
eb4708ca87 Update translations [skip ci] (#6051)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2023-12-11 14:47:52 +01:00
D8H
fac710780b Fix a flash of 1 black frame the first time a scene is started (#6048) 2023-12-11 14:41:27 +01:00
github-actions[bot]
d28aac325a Update translations [skip ci] (#6033)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2023-12-11 14:18:26 +01:00
Clément Pasteau
306b341ee5 Education premium users now also have a dedicated Discord channel (#6047) 2023-12-11 14:17:09 +01:00
D8H
1d8e04cb78 Allow to set 3D models dimensions with a scaling factor (#6044)
- It allows to keep consistent dimensions for a set of 3D models
2023-12-11 12:13:17 +01:00
Clément Pasteau
3b2855de59 Fix a possible crash when closing an app window (#6046) 2023-12-11 10:29:10 +01:00
AlexandreS
d5c2982b2d Increase home page mobile menu icon sizes (#6034) 2023-12-08 10:58:05 +01:00
Clément Pasteau
315b7387b3 Bump version to 5.3.183 (#6032) 2023-12-07 16:21:12 +01:00
Clément Pasteau
f4f92566f4 Remove showing GDevelop templates first + increase visibility (#6031)
Do not show in changelog
2023-12-07 15:56:22 +01:00
github-actions[bot]
7b72d4e080 Update translations [skip ci] (#6030)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2023-12-07 15:56:06 +01:00
D8H
ae96ebf79c Fix heavy assets failing to download on slow connections (#6024) 2023-12-07 15:36:27 +01:00
D8H
be813a0271 Start games without any loading screen if assets are ready before half the fade-in (#6025)
- This only works if the watermark is enabled.
- It allows players to start a game a 2nd time almost instantly.
2023-12-07 15:21:30 +01:00
github-actions[bot]
b306d80915 Update translations [skip ci] (#6020)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-12-07 11:56:18 +01:00
AlexandreS
9baed02aa1 Improve project list refreshing UI/UX (#6026) 2023-12-07 11:43:29 +01:00
Clément Pasteau
1b4c5c1b1c Improve export copy & logic (#6023)
Do not show in changelog
2023-12-06 15:13:30 +01:00
Arthur Pacaud (arthuro555)
4f04190614 Add automatic generation of TypeScript types for Core (in addition to existing Flow types) (#5429)
Only show in developer changelog
2023-12-05 18:47:20 +01:00
AlexandreS
d3134ecde9 Bump newIDE version (#6019) 2023-12-05 17:13:32 +01:00
1943 changed files with 180314 additions and 86877 deletions

View File

@@ -11,13 +11,24 @@
version: 2.1
orbs:
aws-cli: circleci/aws-cli@2.0.6
macos: circleci/macos@2.5.1 # For Rosetta (see below)
node: circleci/node@5.2.0 # For a recent npm version (see below)
jobs:
# Build the **entire** app for macOS.
build-macos:
macos:
xcode: 14.2.0
resource_class: macos.m1.large.gen1
steps:
- checkout
# Install Rosetta for AWS CLI and disable TSO to speed up S3 uploads (https://support.circleci.com/hc/en-us/articles/19334402064027-Troubleshooting-slow-uploads-to-S3-for-jobs-using-an-m1-macOS-resource-class)
- macos/install-rosetta
- run: sudo sysctl net.inet.tcp.tso=0
# Install a recent version of npm to workaround a notarization issue because of a symlink made by npm: https://github.com/electron-userland/electron-builder/issues/7755
# Node.js v20.14.0 comes with npm v10.7.0.
- node/install:
node-version: "20.14.0"
# System dependencies (for Emscripten and upload)
- run:
@@ -165,6 +176,7 @@ jobs:
# Build the WebAssembly library only (so that it's cached on a S3 and easy to re-use).
build-gdevelop_js-wasm-only:
resource_class: medium+ # Compilation time decrease linearly with the number of CPUs, but not linking (so "large" does not speedup total build time).
docker:
- image: cimg/node:16.13
@@ -221,10 +233,83 @@ jobs:
name: Deploy to S3 (latest)
command: aws s3 sync Binaries/embuild/GDevelop.js s3://gdevelop-gdevelop.js/$(git rev-parse --abbrev-ref HEAD)/latest/
# Build the WebAssembly library with clang-tidy and memory sanitizers.
build-gdevelop_js-debug-sanitizers-and-extra-checks:
resource_class: xlarge # Total time decrease linearly with the number of CPUs.
docker:
- image: cimg/node:16.13
working_directory: ~/GDevelop
steps:
- checkout
- aws-cli/setup
# System dependencies (for Emscripten)
- run:
name: Install dependencies for Emscripten
command: sudo apt-get update && sudo apt install cmake
- run:
name: Install dependencies for clang-tidy v19
command: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 19 && sudo apt install clang-tidy-19
- run:
name: Install Python3 dependencies for Emscripten
command: sudo apt install python-is-python3 python3-distutils -y
- run:
name: Install Emscripten (for GDevelop.js)
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 3.1.21 && ./emsdk activate 3.1.21 && cd ..
# GDevelop.js dependencies
- restore_cache:
keys:
- gdevelop.js-linux-nodejs-dependencies-{{ checksum "GDevelop.js/package-lock.json" }}
# fallback to using the latest cache if no exact match is found
- gdevelop.js-linux-nodejs-dependencies-
- run:
name: Install GDevelop.js dependencies and build it
command: cd GDevelop.js && npm install && cd ..
# Build GDevelop.js
- run:
name: Build GDevelop.js ('debug-sanitizers' variant)
command: cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build -- --variant=debug-sanitizers
- run:
name: Run clang-tidy
command: cd GDevelop.js && npm run lint
- run:
name: Run tests
command: cd GDevelop.js && npm run test -- --maxWorkers=4
# Upload artifacts (CircleCI)
- store_artifacts:
path: Binaries/embuild/GDevelop.js
# Upload artifacts (AWS)
- run:
name: Deploy to S3 (specific commit)
command: aws s3 sync Binaries/embuild/GDevelop.js s3://gdevelop-gdevelop.js/$(git rev-parse --abbrev-ref HEAD)/variant/debug-sanitizers/commit/$(git rev-parse HEAD)/
workflows:
builds:
gdevelop_js-wasm:
jobs:
- build-gdevelop_js-wasm-only
gdevelop_js-wasm-extra-checks:
jobs:
- build-gdevelop_js-debug-sanitizers-and-extra-checks:
# Extra checks are resource intensive so don't all run them.
filters:
branches:
only:
- master
- /experimental-build.*/
builds:
jobs:
- build-macos:
filters:
branches:

4
.clang-tidy Normal file
View File

@@ -0,0 +1,4 @@
Checks: 'clang-diagnostic-*,clang-analyzer-*,cppcoreguidelines-*,-cppcoreguidelines-explicit-virtual-functions,-cppcoreguidelines-avoid-const-or-ref-data-members,-cppcoreguidelines-special-member-functions,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-non-private-member-variables-in-classes,-cppcoreguidelines-owning-memory,-cppcoreguidelines-virtual-class-destructor,-clang-analyzer-optin.performance.Padding,-cppcoreguidelines-narrowing-conversions'
WarningsAsErrors: 'cppcoreguidelines-pro-type-member-init, clang-analyzer-optin.cplusplus.UninitializedObject'
HeaderFilterRegex: '.*'
FormatStyle: none

3
.gitattributes vendored
View File

@@ -1,12 +1,11 @@
Core/GDCore/Serialization/rapidjson/rapidjson.h/* linguist-vendored
Core/GDCore/TinyXml/* linguist-vendored
Extensions/ParticleSystem/SPARK/* linguist-vendored
Extensions/PhysicsBehavior/Box2D/* linguist-vendored
Extensions/PhysicsBehavior/box2djs/* linguist-vendored
Extensions/Physics2Behavior/box2d.js linguist-vendored
Extensions/BBText/pixi-multistyle-text/* linguist-vendored
Extensions/P2P/A_peer.js linguist-vendored
Extensions/Multiplayer/peer.js linguist-vendored
Extensions/Shopify/shopify-buy.umd.polyfilled.min.js linguist-vendored
Extensions/TileMap/pako/* linguist-vendored
Extensions/TileMap/pixi-tilemap/* linguist-vendored
Extensions/TweenBehavior/shifty.js linguist-vendored

View File

@@ -19,7 +19,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 20
cache: "npm"
cache-dependency-path: "newIDE/app/package-lock.json"
@@ -58,7 +58,7 @@ jobs:
working-directory: newIDE/app
- name: Create a Pull Request with the changes
uses: peter-evans/create-pull-request@v5
uses: peter-evans/create-pull-request@v6
with:
commit-message: Update translations [skip ci]
branch: chore/update-translations

View File

@@ -56,6 +56,7 @@ blocks:
- name: GDJS typing and documentation generation
commands:
- checkout
- cache restore newIDE-app-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum newIDE/app/package-lock.json)
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
- cache restore GDJS-tests-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/tests/package-lock.json)
- cd GDJS

View File

@@ -17,11 +17,11 @@ cache:
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- ubuntu-toolchain-r-test
packages:
# Build dependencies:
- cmake
- p7zip-full
# Build dependencies:
- cmake
- p7zip-full
before_install:
# This workaround is required to avoid libstdc++ errors (Emscripten requires a recent version of libstdc++)
@@ -29,47 +29,48 @@ before_install:
- sudo dpkg --force-all -i libstdc++6
install:
# Ensure we use a recent version of Node.js (and npm).
# Ensure we use a recent version of Node.js (and npm).
- nvm install v16 && nvm use v16
#Compile the tests only for GDCore
#Compile the tests only for GDCore
- mkdir .build-tests
- cd .build-tests
- cmake -DBUILD_GDJS=FALSE -DBUILD_TESTS=TRUE -DCMAKE_CXX_COMPILER=$(which $CXX) -DCMAKE_C_COMPILER=$(which $CC) ..
- make -j 4
- cd ..
# Install Emscripten (for GDevelop.js)
- git clone https://github.com/juj/emsdk.git
# Install Emscripten (for GDevelop.js)
# Specify the tag for the core repository to avois breaking changes.
- git clone --depth 1 --branch 3.1.21 https://github.com/juj/emsdk.git
- cd emsdk && ./emsdk install 3.1.21 && ./emsdk activate 3.1.21 && cd ..
# Install GDevelop.js dependencies
# Install GDevelop.js dependencies
- cd GDevelop.js && npm install && cd ..
# Build GDevelop.js
# (in a subshell to avoid Emscripten polluting the Node.js and npm version for the rest of the build)
# Build GDevelop.js
# (in a subshell to avoid Emscripten polluting the Node.js and npm version for the rest of the build)
- (set -e; cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build && cd ..)
# Install newIDE tests dependencies
# Install newIDE tests dependencies
- npm -v
- cd newIDE/app && npm install
- cd ../..
# Install GDJS tests dependencies
# Install GDJS tests dependencies
- cd GDJS && npm install && cd tests && npm install
- cd ../..
script:
# GDCore tests:
# GDCore tests:
- cd .build-tests
- Core/GDCore_tests
- cd ..
# GDevelop.js tests
# GDevelop.js tests
- cd GDevelop.js
- npm test
- cd ..
# newIDE tests:
# newIDE tests:
- cd newIDE/app
- npm test
- npm run flow
- npm run check-format
- npm run check-script-types
- cd ../..
# GDJS tests:
# GDJS tests:
- cd GDJS
- npm run check-format
- cd ..

View File

@@ -107,7 +107,7 @@
"description": "Define a parameter in a GDevelop extension definition.",
"prefix": "gdparam",
"body": [
".addParameter('${1|string,expression,object,behavior,yesorno,stringWithSelector,scenevar,globalvar,objectvar,objectList,objectListWithoutPicking,color,key,sceneName,file,layer,relationalOperator,operator,trueorfalse,musicfile,soundfile,police,mouse,passwordjoyaxis,camera,objectPtr,forceMultiplier|}', '${2:Parameter description}', '${3:Optional parameter data}', /*parameterIsOptional=*/${4|false,true|})"
".addParameter('${1|string,expression,object,behavior,yesorno,stringWithSelector,scenevar,globalvar,objectvar,objectList,objectListWithoutPicking,color,key,sceneName,file,layer,relationalOperator,operator,trueorfalse,musicfile,soundfile,mouse,passwordjoyaxis,camera,objectPtr,forceMultiplier|}', '${2:Parameter description}', '${3:Optional parameter data}', /*parameterIsOptional=*/${4|false,true|})"
]
},
"Add code only parameter": {

View File

@@ -114,7 +114,8 @@
"__bits": "cpp",
"__verbose_abort": "cpp",
"variant": "cpp",
"charconv": "cpp"
"charconv": "cpp",
"execution": "cpp"
},
"files.exclude": {
"Binaries/*build*": true,

1
.vscode/tasks.json vendored
View File

@@ -8,6 +8,7 @@
"group": "build",
"label": "Start development server",
"detail": "Starts the GDevelop development server.",
"options": { "env": { "NODE_OPTIONS": "--max-old-space-size=8192" } },
"problemMatcher": [
{
"owner": "cra",

View File

@@ -60,7 +60,7 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND NOT WIN32 AND CMAKE_COMPILER_IS_
endif()
#Activate C++11
set(CMAKE_CXX_STANDARD 11) # Upgrading to C++17 would need to remove usage of bind2nd (should be easy).
set(CMAKE_CXX_STANDARD 11) # Upgrading to C++17 should be tried.
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Mark some warnings as errors
@@ -69,12 +69,18 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# uninitialized variables or other hard to debug bugs.
add_compile_options(
-Wall
-Wextra
-Wuninitialized
-Wconditional-uninitialized
-Wno-unknown-warning-option
-Wno-reorder-ctor
-Wno-reorder
-Wno-unused-parameter
-Wno-pessimizing-move
-Wno-unused-variable
-Wno-unused-variable # Not a good style, but not a risk
-Wno-unused-private-field
-Wno-ignored-qualifiers # Not a risk
-Wno-sign-compare # Not a big risk
# Make as much warnings considered as errors as possible (only one for now).
-Werror=return-stack-address

View File

@@ -11,6 +11,11 @@ set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1)
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)
# Create VersionPriv.h - only useful for testing.
if (NOT EMSCRIPTEN)
file(WRITE "${GD_base_dir}/Core/GDCore/Tools/VersionPriv.h" "#define GD_VERSION_STRING \"0.0.0-0\"")
endif()
# Dependencies on external libraries:
#

View File

@@ -58,99 +58,7 @@
* Common functions and tools for programming.
*/
/**
* \defgroup TinyXml Integrated TinyXml library
*
* See the full documentation of TinyXml [here](http://www.grinninglizard.com/tinyxmldocs/index.html).
*/
/**
* \defgroup SpriteObjectExtension Standard Sprite Object extension
* \ingroup BuiltinExtensions
*/
/**
* \class TiXmlAttribute
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlAttributeSet
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlBase
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlComment
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlCursor
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlDeclaration
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlDocument
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlElement
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlHandle
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlNode
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlOutStream
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlParsingData
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlPrinter
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlString
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlText
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlUnknown
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
/**
* \class TiXmlVisitor
* \brief Part of the tinyxml library
* \ingroup TinyXml
*/
*/

View File

@@ -49,7 +49,8 @@ vector<pair<gd::Expression*, gd::ParameterMetadata> >
ForEachChildVariableEvent::GetAllExpressionsWithMetadata() {
vector<pair<gd::Expression*, gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("scenevar");
auto metadata = gd::ParameterMetadata().SetType("variable");
metadata.SetExtraInfo("AllowUndeclaredVariable");
allExpressionsWithMetadata.push_back(
std::make_pair(&iterableVariableName, metadata));
allExpressionsWithMetadata.push_back(
@@ -63,7 +64,8 @@ vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
ForEachChildVariableEvent::GetAllExpressionsWithMetadata() const {
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("scenevar");
auto metadata = gd::ParameterMetadata().SetType("variable");
metadata.SetExtraInfo("AllowUndeclaredVariable");
allExpressionsWithMetadata.push_back(
std::make_pair(&iterableVariableName, metadata));
allExpressionsWithMetadata.push_back(

View File

@@ -8,7 +8,6 @@
#include "GDCore/Events/Serialization.h"
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/TinyXml/tinyxml.h"
using namespace std;

View File

@@ -10,7 +10,6 @@
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/Serialization.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/TinyXml/tinyxml.h"
using namespace std;

View File

@@ -4,8 +4,8 @@
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_REPEATEVENT_H
#define GDCORE_REPEATEVENT_H
#pragma once
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
namespace gd {
@@ -36,10 +36,10 @@ class GD_CORE_API RepeatEvent : public gd::BaseEvent {
const gd::InstructionsList& GetActions() const { return actions; };
gd::InstructionsList& GetActions() { return actions; };
const gd::String& GetRepeatExpression() const {
return repeatNumberExpression.GetPlainString();
const gd::Expression& GetRepeatExpression() const {
return repeatNumberExpression;
};
void SetRepeatExpression(gd::String repeatNumberExpression_) {
void SetRepeatExpressionPlainString(gd::String repeatNumberExpression_) {
repeatNumberExpression = gd::Expression(repeatNumberExpression_);
};
@@ -68,5 +68,3 @@ class GD_CORE_API RepeatEvent : public gd::BaseEvent {
};
} // namespace gd
#endif // GDCORE_REPEATEVENT_H

View File

@@ -15,7 +15,8 @@ using namespace std;
namespace gd {
StandardEvent::StandardEvent() : BaseEvent() {}
StandardEvent::StandardEvent()
: BaseEvent(), variables(gd::VariablesContainer::SourceType::Local) {}
StandardEvent::~StandardEvent(){};
@@ -57,6 +58,9 @@ void StandardEvent::SerializeTo(SerializerElement& element) const {
if (!events.IsEmpty())
gd::EventsListSerialization::SerializeEventsTo(events,
element.AddChild("events"));
if (HasVariables()) {
variables.SerializeTo(element.AddChild("variables"));
}
}
void StandardEvent::UnserializeFrom(gd::Project& project,
@@ -71,6 +75,11 @@ void StandardEvent::UnserializeFrom(gd::Project& project,
gd::EventsListSerialization::UnserializeEventsFrom(
project, events, element.GetChild("events", 0, "Events"));
}
variables.Clear();
if (element.HasChild("variables")) {
variables.UnserializeFrom(element.GetChild("variables"));
}
}
} // namespace gd

View File

@@ -4,13 +4,13 @@
* reserved. This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#ifndef GDCORE_STANDARDEVENT_H
#define GDCORE_STANDARDEVENT_H
#pragma once
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Instruction.h"
#include "GDCore/Events/InstructionsList.h"
#include "GDCore/Project/VariablesContainer.h"
namespace gd {
class Instruction;
class Project;
@@ -33,6 +33,10 @@ class GD_CORE_API StandardEvent : public gd::BaseEvent {
virtual const gd::EventsList& GetSubEvents() const { return events; };
virtual gd::EventsList& GetSubEvents() { return events; };
virtual bool CanHaveVariables() const { return true; }
virtual const gd::VariablesContainer& GetVariables() const { return variables; };
virtual gd::VariablesContainer& GetVariables() { return variables; };
const gd::InstructionsList& GetConditions() const { return conditions; };
gd::InstructionsList& GetConditions() { return conditions; };
@@ -53,9 +57,7 @@ class GD_CORE_API StandardEvent : public gd::BaseEvent {
gd::InstructionsList conditions;
gd::InstructionsList actions;
EventsList events;
VariablesContainer variables;
};
} // namespace gd
#endif // GDCORE_STANDARDEVENT_H
#endif

View File

@@ -72,8 +72,6 @@ class GD_CORE_API WhileEvent : public gd::BaseEvent {
///< de/activate infinite loop warning when the
///< user create the event
mutable unsigned int whileConditionsHeight;
int GetConditionsHeight() const;
int GetActionsHeight() const;
int GetWhileConditionsHeight() const;

View File

@@ -0,0 +1,129 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <memory>
#include <vector>
#include "GDCore/String.h"
#include "GDCore/Tools/MakeUnique.h"
namespace gd {
/**
* \brief
*/
class GD_CORE_API ProjectDiagnostic {
public:
enum ErrorType {
UndeclaredVariable,
MissingBehavior,
UnknownObject,
MismatchedObjectType,
};
ProjectDiagnostic(ErrorType type_,
const gd::String &message_,
const gd::String &actualValue_,
const gd::String &expectedValue_,
const gd::String &objectName_ = "")
: type(type_),
message(message_),
actualValue(actualValue_),
expectedValue(expectedValue_),
objectName(objectName_) {};
virtual ~ProjectDiagnostic() {};
ErrorType GetType() const { return type; };
const gd::String &GetMessage() const { return message; }
const gd::String &GetObjectName() const { return objectName; }
const gd::String &GetActualValue() const { return actualValue; }
const gd::String &GetExpectedValue() const { return expectedValue; }
private:
ErrorType type;
gd::String message;
gd::String objectName;
gd::String actualValue;
gd::String expectedValue;
};
/**
* \brief
*/
class GD_CORE_API DiagnosticReport {
public:
DiagnosticReport() {};
virtual ~DiagnosticReport() {};
void Add(const gd::ProjectDiagnostic &projectDiagnostic) {
projectDiagnostics.push_back(
gd::make_unique<gd::ProjectDiagnostic>(projectDiagnostic));
};
const ProjectDiagnostic &Get(std::size_t index) const {
return *projectDiagnostics[index].get();
};
std::size_t Count() const { return projectDiagnostics.size(); };
const gd::String &GetSceneName() const { return sceneName; }
void SetSceneName(const gd::String &sceneName_) { sceneName = sceneName_; }
void LogAllDiagnostics() {
for (auto &diagnostic : projectDiagnostics) {
std::cout << diagnostic->GetMessage()
<< "(object: " << diagnostic->GetObjectName()
<< ", actual value: " << diagnostic->GetActualValue()
<< ", expected value: " << diagnostic->GetExpectedValue() << ")"
<< std::endl;
}
}
private:
std::vector<std::unique_ptr<gd::ProjectDiagnostic>> projectDiagnostics;
gd::String sceneName;
};
/**
* \brief
*/
class GD_CORE_API WholeProjectDiagnosticReport {
public:
WholeProjectDiagnosticReport() {};
virtual ~WholeProjectDiagnosticReport() {};
const DiagnosticReport &Get(std::size_t index) const {
return *diagnosticReports[index].get();
};
void Clear() { diagnosticReports.clear(); };
DiagnosticReport &AddNewDiagnosticReportForScene(
const gd::String &sceneName) {
auto diagnosticReport = gd::make_unique<gd::DiagnosticReport>();
diagnosticReport->SetSceneName(sceneName);
diagnosticReports.push_back(std::move(diagnosticReport));
return *diagnosticReports[diagnosticReports.size() - 1].get();
};
std::size_t Count() const { return diagnosticReports.size(); };
bool HasAnyIssue() {
for (auto &diagnosticReport : diagnosticReports) {
if (diagnosticReport->Count() > 0) {
return true;
}
}
return false;
}
private:
std::vector<std::unique_ptr<gd::DiagnosticReport>> diagnosticReports;
};
} // namespace gd

View File

@@ -15,6 +15,7 @@
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/IDE/ProjectBrowserHelper.h"
namespace gd {
@@ -47,6 +48,9 @@ void EffectsCodeGenerator::GenerateEffectsIncludeFiles(
// TODO Merge with UsedExtensionsFinder.
// TODO Factorize with the iteration on all effects for resource exposure.
// TODO Implement an ArbitraryEffectWorker and add a method in ProjectBrowserHelper
// See also gd::Project::ExposeResources for a method that traverse the whole
// project (this time for resources) and
// WholeProjectRefactorer::ExposeProjectEvents.
@@ -68,6 +72,27 @@ void EffectsCodeGenerator::GenerateEffectsIncludeFiles(
// Add objects effects
gd::ProjectBrowserHelper::ExposeProjectObjects(project, effectsCodeGenerator);
// Add event-based objects layouts effects
for (std::size_t s = 0; s < project.GetEventsFunctionsExtensionsCount();
s++) {
auto &eventsFunctionExtension = project.GetEventsFunctionsExtension(s);
auto &eventsBasedObjects = eventsFunctionExtension.GetEventsBasedObjects();
for (std::size_t objectIndex = 0;
objectIndex < eventsBasedObjects.GetCount(); ++objectIndex) {
auto &eventsBasedObject = eventsBasedObjects.Get(objectIndex);
auto &layers = eventsBasedObject.GetLayers();
for (std::size_t l = 0; l < layers.GetLayersCount(); ++l) {
auto &effects = layers.GetLayer(l).GetEffects();
for (std::size_t e = 0; e < effects.GetEffectsCount(); ++e) {
auto &effect = effects.GetEffect(e);
effectsCodeGenerator.AddEffectIncludeFiles(effect);
}
}
}
}
}
} // namespace gd

View File

@@ -3,8 +3,8 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef EVENTSCODEGENERATIONCONTEXT_H
#define EVENTSCODEGENERATIONCONTEXT_H
#pragma once
#include <map>
#include <memory>
#include <set>
@@ -325,4 +325,3 @@ class GD_CORE_API EventsCodeGenerationContext {
};
} // namespace gd
#endif // EVENTSCODEGENERATIONCONTEXT_H

View File

@@ -14,6 +14,7 @@
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/Events/ExpressionVariableNameFinder.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/ObjectsContainersList.h"
@@ -41,14 +42,15 @@ gd::String EventsCodeGenerator::GenerateRelationalOperatorCall(
const vector<gd::String>& arguments,
const gd::String& callStartString,
std::size_t startFromArgument) {
std::size_t relationalOperatorIndex = instrInfos.parameters.size();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.size();
std::size_t relationalOperatorIndex = instrInfos.parameters.GetParametersCount();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.GetParametersCount();
++i) {
if (instrInfos.parameters[i].GetType() == "relationalOperator")
if (instrInfos.parameters.GetParameter(i).GetType() == "relationalOperator") {
relationalOperatorIndex = i;
}
}
// Ensure that there is at least one parameter after the relational operator
if (relationalOperatorIndex + 1 >= instrInfos.parameters.size()) {
if (relationalOperatorIndex + 1 >= instrInfos.parameters.GetParametersCount()) {
ReportError();
return "";
}
@@ -75,11 +77,11 @@ gd::String EventsCodeGenerator::GenerateRelationalOperatorCall(
/**
* @brief Generate a relational operation
*
*
* @param relationalOperator the operator
* @param lhs the left hand operand
* @param rhs the right hand operand
* @return gd::String
* @return gd::String
*/
gd::String EventsCodeGenerator::GenerateRelationalOperation(
const gd::String& relationalOperator,
@@ -121,14 +123,16 @@ gd::String EventsCodeGenerator::GenerateOperatorCall(
const gd::String& callStartString,
const gd::String& getterStartString,
std::size_t startFromArgument) {
std::size_t operatorIndex = instrInfos.parameters.size();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.size();
std::size_t operatorIndex = instrInfos.parameters.GetParametersCount();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.GetParametersCount();
++i) {
if (instrInfos.parameters[i].GetType() == "operator") operatorIndex = i;
if (instrInfos.parameters.GetParameter(i).GetType() == "operator") {
operatorIndex = i;
}
}
// Ensure that there is at least one parameter after the operator
if (operatorIndex + 1 >= instrInfos.parameters.size()) {
if (operatorIndex + 1 >= instrInfos.parameters.GetParametersCount()) {
ReportError();
return "";
}
@@ -190,14 +194,16 @@ gd::String EventsCodeGenerator::GenerateCompoundOperatorCall(
const vector<gd::String>& arguments,
const gd::String& callStartString,
std::size_t startFromArgument) {
std::size_t operatorIndex = instrInfos.parameters.size();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.size();
std::size_t operatorIndex = instrInfos.parameters.GetParametersCount();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.GetParametersCount();
++i) {
if (instrInfos.parameters[i].GetType() == "operator") operatorIndex = i;
if (instrInfos.parameters.GetParameter(i).GetType() == "operator") {
operatorIndex = i;
}
}
// Ensure that there is at least one parameter after the operator
if (operatorIndex + 1 >= instrInfos.parameters.size()) {
if (operatorIndex + 1 >= instrInfos.parameters.GetParametersCount()) {
ReportError();
return "";
}
@@ -241,25 +247,27 @@ gd::String EventsCodeGenerator::GenerateMutatorCall(
const vector<gd::String>& arguments,
const gd::String& callStartString,
std::size_t startFromArgument) {
std::size_t operatorIndex = instrInfos.parameters.size();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.size();
std::size_t operatorIndex = instrInfos.parameters.GetParametersCount();
for (std::size_t i = startFromArgument; i < instrInfos.parameters.GetParametersCount();
++i) {
if (instrInfos.parameters[i].GetType() == "operator") operatorIndex = i;
if (instrInfos.parameters.GetParameter(i).GetType() == "operator") {
operatorIndex = i;
}
}
// Ensure that there is at least one parameter after the operator
if (operatorIndex + 1 >= instrInfos.parameters.size()) {
if (operatorIndex + 1 >= instrInfos.parameters.GetParametersCount()) {
ReportError();
return "";
}
gd::String operatorStr = arguments[operatorIndex];
if (operatorStr.size() > 2)
if (operatorStr.size() > 2 && operatorStr[0] == '\"') {
operatorStr = operatorStr.substr(
1,
operatorStr.length() - 1 -
1); // Operator contains quote which must be removed.
}
auto mutators = instrInfos.codeExtraInformation.optionalMutators;
auto mutator = mutators.find(operatorStr);
if (mutator == mutators.end()) {
@@ -279,6 +287,9 @@ gd::String EventsCodeGenerator::GenerateMutatorCall(
argumentsStr += arguments[i];
}
}
if (instrInfos.GetManipulatedType() == "boolean") {
return callStartString + "(" + argumentsStr + ")." + mutator->second;
}
return callStartString + "(" + argumentsStr + ")." + mutator->second + "(" +
rhs + ")";
@@ -312,23 +323,36 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
}
// Insert code only parameters and be sure there is no lack of parameter.
while (condition.GetParameters().size() < instrInfos.parameters.size()) {
while (condition.GetParameters().size() < instrInfos.parameters.GetParametersCount()) {
vector<gd::Expression> parameters = condition.GetParameters();
parameters.push_back(gd::Expression(""));
condition.SetParameters(parameters);
}
gd::EventsCodeGenerator::CheckBehaviorParameters(condition, instrInfos);
// Verify that there are no mismatches between object type in parameters.
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
if (ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType())) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
if (ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType())) {
gd::String objectInParameter =
condition.GetParameter(pNb).GetPlainString();
if (!GetObjectsContainersList().HasObjectOrGroupNamed(objectInParameter)) {
const auto &expectedObjectType =
instrInfos.parameters.GetParameter(pNb).GetExtraInfo();
const auto &actualObjectType =
GetObjectsContainersList().GetTypeOfObject(objectInParameter);
if (!GetObjectsContainersList().HasObjectOrGroupNamed(
objectInParameter)) {
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::UnknownObject, "",
objectInParameter, "");
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
return "/* Unknown object - skipped. */";
} else if (!instrInfos.parameters[pNb].GetExtraInfo().empty() &&
GetObjectsContainersList().GetTypeOfObject(objectInParameter) !=
instrInfos.parameters[pNb].GetExtraInfo()) {
} else if (!expectedObjectType.empty() &&
actualObjectType != expectedObjectType) {
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::MismatchedObjectType, "",
actualObjectType, expectedObjectType, objectInParameter);
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
return "/* Mismatched object type - skipped. */";
}
}
@@ -336,7 +360,7 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
if (instrInfos.IsObjectInstruction()) {
gd::String objectName = condition.GetParameter(0).GetPlainString();
if (!objectName.empty() && !instrInfos.parameters.empty()) {
if (!objectName.empty() && instrInfos.parameters.GetParametersCount() > 0) {
std::vector<gd::String> realObjects =
GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
for (std::size_t i = 0; i < realObjects.size(); ++i) {
@@ -364,15 +388,22 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
}
}
} else if (instrInfos.IsBehaviorInstruction()) {
gd::String objectName = condition.GetParameter(0).GetPlainString();
gd::String behaviorType = GetObjectsContainersList().GetTypeOfBehavior(condition.GetParameter(1).GetPlainString());
if (instrInfos.parameters.size() >= 2) {
if (instrInfos.parameters.GetParametersCount() >= 2) {
const gd::String &objectName = condition.GetParameter(0).GetPlainString();
const gd::String &behaviorName =
condition.GetParameter(1).GetPlainString();
const gd::String &actualBehaviorType =
GetObjectsContainersList().GetTypeOfBehavior(behaviorName);
std::vector<gd::String> realObjects =
GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
GetObjectsContainersList().ExpandObjectName(
objectName, context.GetCurrentObject());
const BehaviorMetadata &autoInfo =
MetadataProvider::GetBehaviorMetadata(platform, actualBehaviorType);
for (std::size_t i = 0; i < realObjects.size(); ++i) {
// Setup context
const BehaviorMetadata& autoInfo =
MetadataProvider::GetBehaviorMetadata(platform, behaviorType);
AddIncludeFiles(autoInfo.includeFiles);
context.SetCurrentObject(realObjects[i]);
context.ObjectsListNeeded(realObjects[i]);
@@ -382,7 +413,7 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
condition.GetParameters(), instrInfos.parameters, context);
conditionCode += GenerateBehaviorCondition(
realObjects[i],
condition.GetParameter(1).GetPlainString(),
behaviorName,
autoInfo,
arguments,
instrInfos,
@@ -457,6 +488,33 @@ gd::String EventsCodeGenerator::GenerateConditionsListCode(
return outputCode;
}
void EventsCodeGenerator::CheckBehaviorParameters(
const gd::Instruction &instruction,
const gd::InstructionMetadata &instrInfos) {
gd::ParameterMetadataTools::IterateOverParameters(
instruction.GetParameters(), instrInfos.parameters,
[this](const gd::ParameterMetadata &parameterMetadata,
const gd::Expression &parameterValue,
const gd::String &lastObjectName) {
if (ParameterMetadata::IsBehavior(parameterMetadata.GetType())) {
const gd::String &behaviorName = parameterValue.GetPlainString();
const gd::String &actualBehaviorType =
GetObjectsContainersList().GetTypeOfBehaviorInObjectOrGroup(
lastObjectName, behaviorName);
const gd::String &expectedBehaviorType =
parameterMetadata.GetExtraInfo();
if (!expectedBehaviorType.empty() &&
actualBehaviorType != expectedBehaviorType) {
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::MissingBehavior, "",
actualBehaviorType, expectedBehaviorType, lastObjectName);
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
}
}
});
}
/**
* Generate code for an action.
*/
@@ -488,21 +546,35 @@ gd::String EventsCodeGenerator::GenerateActionCode(
: instrInfos.codeExtraInformation.functionCallName;
// Be sure there is no lack of parameter.
while (action.GetParameters().size() < instrInfos.parameters.size()) {
while (action.GetParameters().size() < instrInfos.parameters.GetParametersCount()) {
vector<gd::Expression> parameters = action.GetParameters();
parameters.push_back(gd::Expression(""));
action.SetParameters(parameters);
}
gd::EventsCodeGenerator::CheckBehaviorParameters(action, instrInfos);
// Verify that there are no mismatches between object type in parameters.
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
if (ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType())) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
if (ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType())) {
gd::String objectInParameter = action.GetParameter(pNb).GetPlainString();
if (!GetObjectsContainersList().HasObjectOrGroupNamed(objectInParameter)) {
const auto &expectedObjectType =
instrInfos.parameters.GetParameter(pNb).GetExtraInfo();
const auto &actualObjectType =
GetObjectsContainersList().GetTypeOfObject(objectInParameter);
if (!GetObjectsContainersList().HasObjectOrGroupNamed(
objectInParameter)) {
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::UnknownObject, "",
objectInParameter, "");
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
return "/* Unknown object - skipped. */";
} else if (!instrInfos.parameters[pNb].GetExtraInfo().empty() &&
GetObjectsContainersList().GetTypeOfObject(objectInParameter) !=
instrInfos.parameters[pNb].GetExtraInfo()) {
} else if (!expectedObjectType.empty() &&
actualObjectType != expectedObjectType) {
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::MismatchedObjectType, "",
actualObjectType, expectedObjectType, objectInParameter);
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
return "/* Mismatched object type - skipped. */";
}
}
@@ -512,7 +584,7 @@ gd::String EventsCodeGenerator::GenerateActionCode(
if (instrInfos.IsObjectInstruction()) {
gd::String objectName = action.GetParameter(0).GetPlainString();
if (!instrInfos.parameters.empty()) {
if (instrInfos.parameters.GetParametersCount() > 0) {
std::vector<gd::String> realObjects =
GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
for (std::size_t i = 0; i < realObjects.size(); ++i) {
@@ -540,17 +612,22 @@ gd::String EventsCodeGenerator::GenerateActionCode(
}
}
} else if (instrInfos.IsBehaviorInstruction()) {
gd::String objectName = action.GetParameter(0).GetPlainString();
gd::String behaviorType = GetObjectsContainersList().GetTypeOfBehavior(action.GetParameter(1).GetPlainString());
if (instrInfos.parameters.GetParametersCount() >= 2) {
const gd::String &objectName = action.GetParameter(0).GetPlainString();
const gd::String &behaviorName = action.GetParameter(1).GetPlainString();
const gd::String &actualBehaviorType =
GetObjectsContainersList().GetTypeOfBehavior(behaviorName);
if (instrInfos.parameters.size() >= 2) {
std::vector<gd::String> realObjects =
GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
GetObjectsContainersList().ExpandObjectName(
objectName, context.GetCurrentObject());
const BehaviorMetadata &autoInfo =
MetadataProvider::GetBehaviorMetadata(platform, actualBehaviorType);
AddIncludeFiles(autoInfo.includeFiles);
for (std::size_t i = 0; i < realObjects.size(); ++i) {
// Setup context
const BehaviorMetadata& autoInfo =
MetadataProvider::GetBehaviorMetadata(platform, behaviorType);
AddIncludeFiles(autoInfo.includeFiles);
context.SetCurrentObject(realObjects[i]);
context.ObjectsListNeeded(realObjects[i]);
@@ -559,7 +636,7 @@ gd::String EventsCodeGenerator::GenerateActionCode(
action.GetParameters(), instrInfos.parameters, context);
actionCode +=
GenerateBehaviorAction(realObjects[i],
action.GetParameter(1).GetPlainString(),
behaviorName,
autoInfo,
functionCallName,
arguments,
@@ -583,6 +660,29 @@ gd::String EventsCodeGenerator::GenerateActionCode(
return actionCode;
}
gd::String EventsCodeGenerator::GenerateLocalVariablesStackAccessor() {
return (HasProjectAndLayout() ? GetCodeNamespace()
: "eventsFunctionContext") +
".localVariables";
}
gd::String EventsCodeGenerator::GenerateAnyOrSceneVariableGetter(
const gd::Expression &variableExpression,
EventsCodeGenerationContext &context) {
const auto variableName = gd::ExpressionVariableNameFinder::GetVariableName(
*variableExpression.GetRootNode());
gd::String variableParameterType =
GetProjectScopedContainers().GetVariablesContainersList().Has(
variableName)
? "variable"
: "scenevar";
return gd::ExpressionCodeGenerator::GenerateExpressionCode(
*this, context, variableParameterType,
variableExpression.GetPlainString(), "", "AllowUndeclaredVariable");
}
const EventsCodeGenerator::CallbackDescriptor
EventsCodeGenerator::GenerateCallback(
const gd::String& callbackID,
@@ -607,14 +707,23 @@ EventsCodeGenerator::GenerateCallback(
actionsCode += "} //End of subevents\n";
}
gd::String restoreLocalVariablesCode;
restoreLocalVariablesCode +=
"asyncObjectsList.restoreLocalVariablesContainers(" +
GenerateLocalVariablesStackAccessor() + ");\n";
// Compose the callback function and add outside main
const gd::String actionsDeclarationsCode =
GenerateObjectsDeclarationCode(callbackContext);
const gd::String clearLocalVariablesCode =
GenerateLocalVariablesStackAccessor() + ".length = 0;\n";
const gd::String callbackCode = callbackFunctionName + " = function (" +
GenerateEventsParameters(callbackContext) +
") {\n" + actionsDeclarationsCode +
actionsCode + "}\n";
") {\n" + restoreLocalVariablesCode +
actionsDeclarationsCode + actionsCode +
clearLocalVariablesCode + "}\n";
AddCustomCodeOutsideMain(callbackCode);
@@ -677,13 +786,13 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
if (ParameterMetadata::IsExpression("number", metadata.GetType())) {
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
*this, context, "number", parameter, lastObjectName);
*this, context, "number", parameter, lastObjectName, metadata.GetExtraInfo());
} else if (ParameterMetadata::IsExpression("string", metadata.GetType())) {
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
*this, context, "string", parameter, lastObjectName);
*this, context, "string", parameter, lastObjectName, metadata.GetExtraInfo());
} else if (ParameterMetadata::IsExpression("variable", metadata.GetType())) {
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
*this, context, metadata.GetType(), parameter, lastObjectName);
*this, context, metadata.GetType(), parameter, lastObjectName, metadata.GetExtraInfo());
} else if (ParameterMetadata::IsObject(metadata.GetType())) {
// It would be possible to run a gd::ExpressionCodeGenerator if later
// objects can have nested objects, or function returning objects.
@@ -695,7 +804,8 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
} else if (metadata.GetType() == "operator") {
argOutput += parameter.GetPlainString();
if (argOutput != "=" && argOutput != "+" && argOutput != "-" &&
argOutput != "/" && argOutput != "*") {
argOutput != "/" && argOutput != "*" && argOutput != "True" &&
argOutput != "False" && argOutput != "Toggle") {
cout << "Warning: Bad operator: Set to = by default." << endl;
argOutput = "=";
}
@@ -714,9 +824,11 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
metadata.GetType() == "tilesetResource" ||
metadata.GetType() == "videoResource" ||
metadata.GetType() == "model3DResource" ||
metadata.GetType() == "atlasResource" ||
metadata.GetType() == "spineResource" ||
// Deprecated, old parameter names:
metadata.GetType() == "password" || metadata.GetType() == "musicfile" ||
metadata.GetType() == "soundfile" || metadata.GetType() == "police") {
metadata.GetType() == "soundfile") {
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
} else if (metadata.GetType() == "mouse") {
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
@@ -758,7 +870,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
vector<gd::String> EventsCodeGenerator::GenerateParametersCodes(
const vector<gd::Expression>& parameters,
const vector<gd::ParameterMetadata>& parametersInfo,
const ParameterMetadataContainer& parametersInfo,
EventsCodeGenerationContext& context,
std::vector<std::pair<gd::String, gd::String> >*
supplementaryParametersTypes) {
@@ -863,6 +975,11 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(
gd::EventsList& events, EventsCodeGenerationContext& parentContext) {
gd::String output;
for (std::size_t eId = 0; eId < events.size(); ++eId) {
auto& event = events[eId];
if (event.HasVariables()) {
GetProjectScopedContainers().GetVariablesContainersList().Push(event.GetVariables());
}
// Each event has its own context : Objects picked in an event are totally
// different than the one picked in another.
gd::EventsCodeGenerationContext newContext;
@@ -883,13 +1000,17 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(
auto& context = reuseParentContext ? reusedContext : newContext;
gd::String eventCoreCode = events[eId].GenerateEventCode(*this, context);
gd::String eventCoreCode = event.GenerateEventCode(*this, context);
gd::String scopeBegin = GenerateScopeBegin(context);
gd::String scopeEnd = GenerateScopeEnd(context);
gd::String declarationsCode = GenerateObjectsDeclarationCode(context);
output += "\n" + scopeBegin + "\n" + declarationsCode + "\n" +
eventCoreCode + "\n" + scopeEnd + "\n";
if (event.HasVariables()) {
GetProjectScopedContainers().GetVariablesContainersList().Pop();
}
}
return output;
@@ -986,10 +1107,10 @@ gd::String EventsCodeGenerator::GenerateFreeCondition(
// Add logical not if needed
bool conditionAlreadyTakeCareOfInversion = false;
for (std::size_t i = 0; i < instrInfos.parameters.size();
for (std::size_t i = 0; i < instrInfos.parameters.GetParametersCount();
++i) // Some conditions already have a "conditionInverted" parameter
{
if (instrInfos.parameters[i].GetType() == "conditionInverted")
if (instrInfos.parameters.GetParameter(i).GetType() == "conditionInverted")
conditionAlreadyTakeCareOfInversion = true;
}
if (!conditionAlreadyTakeCareOfInversion && conditionInverted)
@@ -1010,7 +1131,7 @@ gd::String EventsCodeGenerator::GenerateObjectCondition(
// Prepare call
// Add a static_cast if necessary
gd::String objectFunctionCallNamePart =
(!instrInfos.parameters[0].GetExtraInfo().empty())
(!instrInfos.parameters.GetParameter(0).GetExtraInfo().empty())
? "static_cast<" + objInfo.className + "*>(" +
GetObjectListName(objectName, context) + "[i])->" +
instrInfos.codeExtraInformation.functionCallName
@@ -1065,7 +1186,13 @@ gd::String EventsCodeGenerator::GenerateFreeAction(
// Generate call
gd::String call;
if (instrInfos.codeExtraInformation.type == "number" ||
instrInfos.codeExtraInformation.type == "string") {
instrInfos.codeExtraInformation.type == "string" ||
// Boolean actions declared with addExpressionAndConditionAndAction uses
// MutatorAndOrAccessor even though they don't declare an operator parameter.
// Boolean operators are only used with SetMutators or SetCustomCodeGenerator.
(instrInfos.codeExtraInformation.type == "boolean" &&
instrInfos.codeExtraInformation.accessType ==
gd::InstructionMetadata::ExtraInformation::AccessType::Mutators)) {
if (instrInfos.codeExtraInformation.accessType ==
gd::InstructionMetadata::ExtraInformation::MutatorAndOrAccessor)
call = GenerateOperatorCall(
@@ -1249,7 +1376,8 @@ EventsCodeGenerator::EventsCodeGenerator(const gd::Project& project_,
compilationForRuntime(false),
maxCustomConditionsDepth(0),
maxConditionsListsSize(0),
eventsListNextUniqueId(0){};
eventsListNextUniqueId(0),
diagnosticReport(nullptr){};
EventsCodeGenerator::EventsCodeGenerator(
const gd::Platform& platform_,
@@ -1263,6 +1391,7 @@ EventsCodeGenerator::EventsCodeGenerator(
compilationForRuntime(false),
maxCustomConditionsDepth(0),
maxConditionsListsSize(0),
eventsListNextUniqueId(0){};
eventsListNextUniqueId(0),
diagnosticReport(nullptr){};
} // namespace gd

View File

@@ -3,8 +3,7 @@
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EVENTSCODEGENERATOR_H
#define GDCORE_EVENTSCODEGENERATOR_H
#pragma once
#include <set>
#include <utility>
@@ -12,8 +11,10 @@
#include "GDCore/Events/Event.h"
#include "GDCore/Events/Instruction.h"
#include "GDCore/Events/CodeGeneration/DiagnosticReport.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/String.h"
namespace gd {
class EventsList;
class Expression;
@@ -127,7 +128,7 @@ class GD_CORE_API EventsCodeGenerator {
*/
std::vector<gd::String> GenerateParametersCodes(
const std::vector<gd::Expression>& parameters,
const std::vector<gd::ParameterMetadata>& parametersInfo,
const ParameterMetadataContainer& parametersInfo,
EventsCodeGenerationContext& context,
std::vector<std::pair<gd::String, gd::String> >*
supplementaryParametersTypes = 0);
@@ -336,6 +337,16 @@ class GD_CORE_API EventsCodeGenerator {
return projectScopedContainers;
}
/**
* @brief Give access to the project scoped containers as code generation might
* push and pop variable containers (for local variables).
* This could be passed as a parameter recursively in code generation, but this requires
* heavy refactoring. Instead, we use this single instance.
*/
gd::ProjectScopedContainers& GetProjectScopedContainers() {
return projectScopedContainers;
}
/**
* \brief Return true if the code generation is done for a given project and
* layout. If not, this means that the code is generated for a function.
@@ -372,6 +383,14 @@ class GD_CORE_API EventsCodeGenerator {
*/
size_t GetMaxConditionsListsSize() const { return maxConditionsListsSize; }
void SetDiagnosticReport(gd::DiagnosticReport* diagnosticReport_) {
diagnosticReport = diagnosticReport_;
}
gd::DiagnosticReport* GetDiagnosticReport() {
return diagnosticReport;
}
/**
* \brief Generate the full name for accessing to a boolean variable used for
* conditions.
@@ -448,7 +467,7 @@ class GD_CORE_API EventsCodeGenerator {
*/
virtual gd::String GetCodeNamespace() { return ""; };
enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE };
enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE, ANY_VARIABLE };
/**
* Generate a single unique number for the specified instruction.
@@ -478,7 +497,20 @@ class GD_CORE_API EventsCodeGenerator {
const gd::String& lhs,
const gd::String& rhs);
protected:
/**
* \brief Generate the code to access the local variables stack.
*/
virtual gd::String GenerateLocalVariablesStackAccessor();
/**
* \brief Generate an any variable getter that fallbacks on scene variable for
* compatibility reason.
*/
gd::String
GenerateAnyOrSceneVariableGetter(const gd::Expression &variableExpression,
EventsCodeGenerationContext &context);
protected:
virtual const gd::String GenerateRelationalOperatorCodes(
const gd::String& operatorString);
@@ -496,7 +528,7 @@ class GD_CORE_API EventsCodeGenerator {
parameter -> string
* - operator : Used to update a value using a setter and a getter -> string
* - key, mouse, objectvar, scenevar, globalvar, password, musicfile,
soundfile, police -> string
soundfile -> string
* - trueorfalse, yesorno -> boolean ( See GenerateTrue/GenerateFalse ).
*
* <br><br>
@@ -534,11 +566,15 @@ class GD_CORE_API EventsCodeGenerator {
const VariableScope& scope,
gd::EventsCodeGenerationContext& context,
const gd::String& objectName) {
// This code is only used as a mock.
// See the real implementation in GDJS.
if (scope == LAYOUT_VARIABLE) {
return "getLayoutVariable(" + variableName + ")";
} else if (scope == PROJECT_VARIABLE) {
return "getProjectVariable(" + variableName + ")";
} else if (scope == ANY_VARIABLE) {
return "getAnyVariable(" + variableName + ")";
}
return "getVariableForObject(" + objectName + ", " + variableName + ")";
@@ -779,6 +815,10 @@ class GD_CORE_API EventsCodeGenerator {
virtual gd::String GenerateGetBehaviorNameCode(
const gd::String& behaviorName);
void CheckBehaviorParameters(
const gd::Instruction &instruction,
const gd::InstructionMetadata &instrInfos);
const gd::Platform& platform; ///< The platform being used.
gd::ProjectScopedContainers projectScopedContainers;
@@ -809,8 +849,9 @@ class GD_CORE_API EventsCodeGenerator {
instructionUniqueIds; ///< The unique ids generated for instructions.
size_t eventsListNextUniqueId; ///< The next identifier to use for an events
///< list function name.
gd::DiagnosticReport* diagnosticReport;
};
} // namespace gd
#endif // GDCORE_EVENTSCODEGENERATOR_H

View File

@@ -31,6 +31,7 @@
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
#include "GDCore/Events/CodeGeneration/DiagnosticReport.h"
namespace gd {
@@ -39,7 +40,8 @@ gd::String ExpressionCodeGenerator::GenerateExpressionCode(
EventsCodeGenerationContext& context,
const gd::String& rootType,
const gd::Expression& expression,
const gd::String& rootObjectName) {
const gd::String& rootObjectName,
const gd::String& extraInfo) {
ExpressionCodeGenerator generator(rootType, rootObjectName, codeGenerator, context);
auto node = expression.GetRootNode();
@@ -52,13 +54,34 @@ gd::String ExpressionCodeGenerator::GenerateExpressionCode(
gd::ExpressionValidator validator(codeGenerator.GetPlatform(),
codeGenerator.GetProjectScopedContainers(),
rootType);
rootType,
extraInfo);
node->Visit(validator);
if (!validator.GetFatalErrors().empty()) {
std::cout << "Error: \"" << validator.GetFatalErrors()[0]->GetMessage()
<< "\" in: \"" << expression.GetPlainString() << "\" ("
<< rootType << ")" << std::endl;
auto *diagnosticReport = codeGenerator.GetDiagnosticReport();
if (diagnosticReport) {
for (auto *error : validator.GetFatalErrors()) {
if (error->GetType() ==
gd::ExpressionParserError::ErrorType::UndeclaredVariable ||
error->GetType() ==
gd::ExpressionParserError::ErrorType::UnknownIdentifier) {
const auto& variableName = error->GetActualValue();
if (!variableName.empty()) {
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::UndeclaredVariable,
error->GetMessage(), error->GetActualValue(),
"", error->GetObjectName());
diagnosticReport->Add(projectDiagnostic);
}
}
}
}
return generator.GenerateDefaultValue(rootType);
}
@@ -110,11 +133,13 @@ void ExpressionCodeGenerator::OnVisitVariableNode(VariableNode& node) {
if (gd::ParameterMetadata::IsExpression("variable", type)) {
// The node is a variable inside an expression waiting for a *variable* to be returned, not its value.
EventsCodeGenerator::VariableScope scope =
type == "globalvar"
type == "variable"
? gd::EventsCodeGenerator::ANY_VARIABLE
: type == "globalvar"
? gd::EventsCodeGenerator::PROJECT_VARIABLE
: ((type == "scenevar")
: type == "scenevar"
? gd::EventsCodeGenerator::LAYOUT_VARIABLE
: gd::EventsCodeGenerator::OBJECT_VARIABLE);
: gd::EventsCodeGenerator::OBJECT_VARIABLE;
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
codeGenerator.GetObjectsContainersList(),
@@ -137,19 +162,8 @@ void ExpressionCodeGenerator::OnVisitVariableNode(VariableNode& node) {
output += codeGenerator.GenerateVariableValueAs(type);
}, [&]() {
if (!codeGenerator.HasProjectAndLayout()) {
gd::LogWarning("Tried to generate access to a variable without a project/scene - the code generator only works for global and scene variables for now.");
output += GenerateDefaultValue(type);
return;
}
// This could be adapted in the future if more scopes are supported.
EventsCodeGenerator::VariableScope scope = gd::EventsCodeGenerator::PROJECT_VARIABLE;
if (codeGenerator.GetProjectScopedContainers().GetVariablesContainersList().GetBottomMostVariablesContainer()->Has(node.name)) {
scope = gd::EventsCodeGenerator::LAYOUT_VARIABLE;
}
output += codeGenerator.GenerateGetVariable(node.name, scope, context, "");
output += codeGenerator.GenerateGetVariable(
node.name, gd::EventsCodeGenerator::ANY_VARIABLE, context, "");
if (node.child) node.child->Visit(*this);
output += codeGenerator.GenerateVariableValueAs(type);
}, [&]() {
@@ -209,11 +223,13 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
codeGenerator.GenerateObject(node.identifierName, type, context);
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
EventsCodeGenerator::VariableScope scope =
type == "globalvar"
type == "variable"
? gd::EventsCodeGenerator::ANY_VARIABLE
: type == "globalvar"
? gd::EventsCodeGenerator::PROJECT_VARIABLE
: ((type == "scenevar")
: type == "scenevar"
? gd::EventsCodeGenerator::LAYOUT_VARIABLE
: gd::EventsCodeGenerator::OBJECT_VARIABLE);
: gd::EventsCodeGenerator::OBJECT_VARIABLE;
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
codeGenerator.GetObjectsContainersList(),
@@ -236,19 +252,9 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
node.childIdentifierName, gd::EventsCodeGenerator::OBJECT_VARIABLE, context, node.identifierName);
output += codeGenerator.GenerateVariableValueAs(type);
}, [&]() {
if (!codeGenerator.HasProjectAndLayout()) {
gd::LogWarning("Tried to generate access to a variable without a project/scene - the code generator only works for global and scene variables for now.");
output += GenerateDefaultValue(type);
return;
}
// This could be adapted in the future if more scopes are supported at runtime.
EventsCodeGenerator::VariableScope scope = gd::EventsCodeGenerator::PROJECT_VARIABLE;
if (variablesContainersList.GetBottomMostVariablesContainer()->Has(node.identifierName)) {
scope = gd::EventsCodeGenerator::LAYOUT_VARIABLE;
}
output += codeGenerator.GenerateGetVariable(node.identifierName, scope, context, "");
output += codeGenerator.GenerateGetVariable(
node.identifierName, gd::EventsCodeGenerator::ANY_VARIABLE, context,
"");
if (!node.childIdentifierName.empty()) {
output += codeGenerator.GenerateVariableAccessor(node.childIdentifierName);
}
@@ -424,11 +430,11 @@ gd::String ExpressionCodeGenerator::GenerateParametersCodes(
size_t nonCodeOnlyParameterIndex = 0;
gd::String parametersCode;
for (std::size_t i = initialParameterIndex;
i < expressionMetadata.parameters.size();
i < expressionMetadata.GetParameters().GetParametersCount();
++i) {
if (i != initialParameterIndex) parametersCode += ", ";
auto& parameterMetadata = expressionMetadata.parameters[i];
auto& parameterMetadata = expressionMetadata.GetParameters().GetParameter(i);
if (!parameterMetadata.IsCodeOnly()) {
if (nonCodeOnlyParameterIndex < parameters.size()) {
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),

View File

@@ -59,7 +59,8 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
EventsCodeGenerationContext& context,
const gd::String& type,
const gd::Expression& expression,
const gd::String& objectName = "");
const gd::String& objectName = "",
const gd::String& extraInfo = "");
const gd::String& GetOutput() { return output; };

View File

@@ -17,6 +17,7 @@
namespace gd {
EventsList BaseEvent::badSubEvents;
VariablesContainer BaseEvent::badLocalVariables;
std::vector<gd::String> BaseEvent::emptyDependencies;
gd::String BaseEvent::emptySourceFile;
@@ -28,6 +29,8 @@ BaseEvent::BaseEvent()
bool BaseEvent::HasSubEvents() const { return !GetSubEvents().IsEmpty(); }
bool BaseEvent::HasVariables() const { return GetVariables().Count() > 0; }
gd::String BaseEvent::GenerateEventCode(
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {

View File

@@ -3,9 +3,7 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#ifndef GDCORE_EVENT_H
#define GDCORE_EVENT_H
#pragma once
#include <iostream>
#include <memory>
@@ -26,6 +24,7 @@ class SerializerElement;
class Instruction;
class EventVisitor;
class ReadOnlyEventVisitor;
class VariablesContainer;
} // namespace gd
namespace gd {
@@ -92,6 +91,32 @@ class GD_CORE_API BaseEvent {
*/
bool HasSubEvents() const;
/**
* Derived class have to redefine this function, so as to return true, if they
* can have local variables.
*/
virtual bool CanHaveVariables() const { return false; }
/**
* Return the local variables, if applicable.
*/
virtual const gd::VariablesContainer& GetVariables() const {
return badLocalVariables;
};
/**
* Return the local variables, if applicable.
*/
virtual gd::VariablesContainer& GetVariables() {
return badLocalVariables;
};
/**
* \brief Return true if the events has local variables.
* \warning This is only applicable when CanHaveVariables() return true.
*/
bool HasVariables() const;
/**
* \brief Return a list of all conditions of the event.
* \note Used to preprocess or search in the conditions.
@@ -301,6 +326,7 @@ class GD_CORE_API BaseEvent {
///< Used for saving the event for instance.
static gd::EventsList badSubEvents;
static gd::VariablesContainer badLocalVariables;
static std::vector<gd::String> emptyDependencies;
static gd::String emptySourceFile;
};
@@ -325,6 +351,3 @@ class EmptyEvent : public BaseEvent {
};
} // namespace gd
#endif // GDCORE_EVENT_H
#endif

View File

@@ -18,7 +18,6 @@ class BaseEvent;
namespace gd {
class SerializerElement;
}
class TiXmlElement;
#undef CreateEvent

View File

@@ -38,7 +38,7 @@ using namespace gd::GrammarTerminals;
* parser by refactoring out the dependency on gd::MetadataProvider (injecting
* instead functions to be called to query supported functions).
*
* \see gd::ExpressionParserDiagnostic
* \see gd::ExpressionParserError
* \see gd::ExpressionNode
*/
class GD_CORE_API ExpressionParser2 {
@@ -547,28 +547,28 @@ class GD_CORE_API ExpressionParser2 {
}
///@}
std::unique_ptr<ExpressionParserDiagnostic> ValidateOperator(
std::unique_ptr<ExpressionParserError> ValidateOperator(
gd::String::value_type operatorChar) {
if (operatorChar == '+' || operatorChar == '-' || operatorChar == '/' ||
operatorChar == '*') {
return gd::make_unique<ExpressionParserDiagnostic>();
return std::unique_ptr<ExpressionParserError>(nullptr);
}
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
gd::ExpressionParserError::ErrorType::InvalidOperator,
_("You've used an operator that is not supported. Operator should be "
"either +, -, / or *."),
GetCurrentPosition());
}
std::unique_ptr<ExpressionParserDiagnostic> ValidateUnaryOperator(
std::unique_ptr<ExpressionParserError> ValidateUnaryOperator(
gd::String::value_type operatorChar,
size_t position) {
if (operatorChar == '+' || operatorChar == '-') {
return gd::make_unique<ExpressionParserDiagnostic>();
return std::unique_ptr<ExpressionParserError>(nullptr);
}
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
gd::ExpressionParserError::ErrorType::InvalidOperator,
_("You've used an \"unary\" operator that is not supported. Operator "
"should be "
"either + or -."),
@@ -719,13 +719,15 @@ class GD_CORE_API ExpressionParser2 {
std::unique_ptr<ExpressionParserError> RaiseSyntaxError(
const gd::String &message) {
return std::move(gd::make_unique<ExpressionParserError>(
"syntax_error", message, GetCurrentPosition()));
gd::ExpressionParserError::ErrorType::SyntaxError, message,
GetCurrentPosition()));
}
std::unique_ptr<ExpressionParserError> RaiseTypeError(
const gd::String &message, size_t beginningPosition) {
return std::move(gd::make_unique<ExpressionParserError>(
"type_error", message, beginningPosition, GetCurrentPosition()));
gd::ExpressionParserError::ErrorType::MismatchedType, message,
beginningPosition, GetCurrentPosition()));
}
///@}

View File

@@ -6,5 +6,5 @@
#include "ExpressionParser2Node.h"
namespace gd {
gd::String ExpressionParserDiagnostic::noMessage = "";
}

View File

@@ -3,14 +3,14 @@
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EXPRESSIONPARSER2NODES_H
#define GDCORE_EXPRESSIONPARSER2NODES_H
#pragma once
#include <memory>
#include <vector>
#include "ExpressionParser2NodeWorker.h"
#include "GDCore/String.h"
namespace gd {
class Expression;
class ObjectsContainer;
@@ -36,54 +36,61 @@ struct GD_CORE_API ExpressionParserLocation {
private:
bool isValid;
size_t startPosition;
size_t endPosition;
};
/**
* \brief A diagnostic that can be attached to a gd::ExpressionNode.
*/
struct GD_CORE_API ExpressionParserDiagnostic {
virtual ~ExpressionParserDiagnostic() = default;
virtual bool IsError() { return false; }
virtual const gd::String &GetMessage() { return noMessage; }
virtual size_t GetStartPosition() { return 0; }
virtual size_t GetEndPosition() { return 0; }
private:
static gd::String noMessage;
size_t startPosition = 0;
size_t endPosition = 0;
};
/**
* \brief An error that can be attached to a gd::ExpressionNode.
*/
struct GD_CORE_API ExpressionParserError : public ExpressionParserDiagnostic {
ExpressionParserError(const gd::String &type_,
struct GD_CORE_API ExpressionParserError {
enum ErrorType {
SyntaxError,
InvalidOperator,
MismatchedType,
UndeclaredVariable,
UnknownIdentifier,
BracketsNotAllowedForObjects,
TooFewParameters,
TooManyParameters,
InvalidFunctionName,
MalformedVariableParameter,
MalformedObjectParameter,
UnknownParameterType,
MissingBehavior,
VariableNameCollision,
};
ExpressionParserError(gd::ExpressionParserError::ErrorType type_,
const gd::String &message_,
const ExpressionParserLocation &location_)
: type(type_), message(message_), location(location_){};
ExpressionParserError(const gd::String &type_,
const gd::String &message_,
size_t position_)
const ExpressionParserLocation &location_,
const gd::String &actualValue_ = "",
const gd::String &objectName_ = "")
: type(type_), message(message_), location(location_),
actualValue(actualValue_), objectName(objectName_){};
ExpressionParserError(gd::ExpressionParserError::ErrorType type_,
const gd::String &message_, size_t position_)
: type(type_), message(message_), location(position_){};
ExpressionParserError(const gd::String &type_,
const gd::String &message_,
size_t startPosition_,
ExpressionParserError(gd::ExpressionParserError::ErrorType type_,
const gd::String &message_, size_t startPosition_,
size_t endPosition_)
: type(type_),
message(message_),
: type(type_), message(message_),
location(startPosition_, endPosition_){};
virtual ~ExpressionParserError(){};
bool IsError() override { return true; }
const gd::String &GetMessage() override { return message; }
size_t GetStartPosition() override { return location.GetStartPosition(); }
size_t GetEndPosition() override { return location.GetEndPosition(); }
gd::ExpressionParserError::ErrorType GetType() { return type; }
const gd::String &GetMessage() { return message; }
const gd::String &GetObjectName() { return objectName; }
const gd::String &GetActualValue() { return actualValue; }
size_t GetStartPosition() { return location.GetStartPosition(); }
size_t GetEndPosition() { return location.GetEndPosition(); }
private:
gd::String type;
private:
gd::ExpressionParserError::ErrorType type;
gd::String message;
ExpressionParserLocation location;
gd::String objectName;
gd::String actualValue;
};
/**
@@ -95,7 +102,7 @@ struct GD_CORE_API ExpressionNode {
virtual ~ExpressionNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker){};
std::unique_ptr<ExpressionParserDiagnostic> diagnostic;
std::unique_ptr<ExpressionParserError> diagnostic;
ExpressionParserLocation location; ///< The location of the entire node. Some
/// nodes might have other locations
/// stored inside them. For example, a
@@ -425,5 +432,3 @@ struct GD_CORE_API EmptyNode : public FunctionCallOrObjectFunctionNameOrEmptyNod
};
} // namespace gd
#endif

View File

@@ -182,10 +182,10 @@ void EventsListSerialization::UpdateInstructionsFromGD2x(
// Common updates for some parameters
const std::vector<gd::Expression>& parameters = instr.GetParameters();
for (std::size_t j = 0;
j < parameters.size() && j < metadata.parameters.size();
j < parameters.size() && j < metadata.parameters.GetParametersCount();
++j) {
if (metadata.parameters[j].GetType() == "relationalOperator" ||
metadata.parameters[j].GetType() == "operator") {
if (metadata.parameters.GetParameter(j).GetType() == "relationalOperator" ||
metadata.parameters.GetParameter(j).GetType() == "operator") {
if (j == parameters.size() - 1) {
std::cout << "ERROR: No more parameters after a [relational]operator "
"when trying to update an instruction from GD2.x";

View File

@@ -66,6 +66,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
// Deprecated
extension
.AddAction("CopyArgumentToVariable",
_("Copy function parameter to variable"),
@@ -78,9 +79,25 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
.SetHelpPath("/events/functions/return")
.AddParameter("functionParameterName", _("Parameter name"), "variable")
.AddParameter("scenevar", _("Scene variable"))
.SetHidden()
.MarkAsAdvanced();
extension
.AddAction("CopyArgumentToVariable2",
_("Copy function parameter to variable"),
_("Copy a function parameter (also called \"argument\") to a variable. "
"The parameter type must be a variable."),
_("Copy the parameter _PARAM0_ into the variable _PARAM1_"),
"",
"res/function32.png",
"res/function32.png")
.SetHelpPath("/events/functions/return")
.AddParameter("functionParameterName", _("Parameter name"), "variable")
.AddParameter("variable", _("Variable"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
// Deprecated
extension
.AddAction("CopyVariableToArgument",
_("Copy variable to function parameter"),
@@ -93,6 +110,21 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
.SetHelpPath("/events/functions/return")
.AddParameter("functionParameterName", _("Parameter name"), "variable")
.AddParameter("scenevar", _("Scene variable"))
.SetHidden()
.MarkAsAdvanced();
extension
.AddAction("CopyVariableToArgument2",
_("Copy variable to function parameter"),
_("Copy a variable to function parameter (also called \"argument\"). "
"The parameter type must be a variable."),
_("Copy the variable _PARAM1_ into the parameter _PARAM0_"),
"",
"res/function32.png",
"res/function32.png")
.SetHelpPath("/events/functions/return")
.AddParameter("functionParameterName", _("Parameter name"), "variable")
.AddParameter("variable", _("Variable"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();

View File

@@ -417,6 +417,93 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.SetDefaultValue("\"\"")
.MarkAsAdvanced();
obj.AddAction("SetNumberObjectVariable",
_("Change variable value"),
_("Modify the number value of an object variable."),
_("the variable _PARAM1_"),
_("Variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions())
.SetRelevantForLayoutEventsOnly();
obj.AddAction("SetStringObjectVariable",
_("Change text variable"),
_("Modify the text of an object variable."),
_("the variable _PARAM1_"),
_("Variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardOperatorParameters("string",
ParameterOptions::MakeNewOptions())
.SetRelevantForLayoutEventsOnly();
obj.AddAction("SetBooleanObjectVariable",
_("Change boolean variable"),
_("Modify the boolean value of an object variable."),
_("Change the variable _PARAM1_ of _PARAM0_: _PARAM2_"),
_("Variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.AddParameter("operator", _("Value"), "boolean")
// This parameter allows to keep the operand expression
// when the editor switch between variable instructions.
.AddCodeOnlyParameter("yesorno", _("Value"))
.SetRelevantForLayoutEventsOnly();
obj.AddCondition("NumberObjectVariable",
_("Variable value"),
_("Compare the number value of an object variable."),
_("the variable _PARAM1_"),
_("Variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetRelevantForLayoutEventsOnly();
obj.AddCondition("StringObjectVariable",
_("Text variable"),
_("Compare the text of an object variable."),
_("the variable _PARAM1_"),
_("Variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"string", ParameterOptions::MakeNewOptions())
.SetRelevantForLayoutEventsOnly();
obj.AddCondition("BooleanObjectVariable",
_("Boolean variable"),
_("Compare the boolean value of an object variable."),
_("The variable _PARAM1_ of _PARAM0_ is _PARAM2_"),
_("Variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true")
// This parameter allows to keep the operand expression
// when the editor switch between variable instructions.
.AddCodeOnlyParameter("yesorno", _("Value"))
.SetRelevantForLayoutEventsOnly();
obj.AddAction("ModVarObjet",
_("Change number variable"),
_("Modify the number value of an object variable."),
@@ -428,7 +515,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions());
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
obj.AddAction("ModVarObjetTxt",
_("Change text variable"),
@@ -441,7 +529,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardOperatorParameters("string",
ParameterOptions::MakeNewOptions());
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
obj.AddAction("SetObjectVariableAsBoolean",
_("Change boolean variable"),
@@ -454,7 +543,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.AddParameter("trueorfalse", _("New Value:"));
.AddParameter("trueorfalse", _("New Value:"))
.SetRelevantForFunctionEventsOnly();
obj.AddAction(
"ToggleObjectVariableAsBoolean",
@@ -469,7 +559,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"));
.AddParameter("objectvar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
obj.AddCondition("ObjectVariableChildExists",
_("Child existence"),
@@ -657,7 +748,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions());
"number", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
obj.AddCondition("VarObjetTxt",
_("Text variable"),
@@ -670,7 +762,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"string", ParameterOptions::MakeNewOptions());
"string", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
obj.AddCondition("ObjectVariableAsBoolean",
_("Boolean variable"),
@@ -683,7 +776,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true");
.SetDefaultValue("true")
.SetRelevantForFunctionEventsOnly();
obj.AddCondition("VarObjetDef",
"Variable defined",
@@ -697,6 +791,48 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("string", _("Variable"))
.SetHidden(); // Deprecated.
obj.AddAction(
"PushStringToObjectVariable",
_("Add text variable"),
_("Adds a text (string) to the end of an object array variable."),
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("string", _("Text to add"))
.MarkAsAdvanced()
.SetRelevantForLayoutEventsOnly();
obj.AddAction("PushNumberToObjectVariable",
_("Add variable array value"),
_("Adds a number to the end of an object array variable."),
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("expression", _("Number to add"))
.MarkAsAdvanced()
.SetRelevantForLayoutEventsOnly();
obj.AddAction(
"PushBooleanToObjectVariable",
_("Add boolean variable"),
_("Adds a boolean to the end of an object array variable."),
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("trueorfalse", _("Boolean to add"))
.MarkAsAdvanced()
.SetRelevantForLayoutEventsOnly();
// Deprecated
obj.AddAction(
"ObjectVariablePush",
_("Add existing variable"),
@@ -708,6 +844,23 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("scenevar", _("Scene variable with the content to add"))
.SetParameterLongDescription(_("The content of the object variable will "
"*be copied* and added at the "
"end of the array."))
.MarkAsAdvanced()
.SetHidden();
obj.AddAction(
"ObjectVariablePush2",
_("Add existing variable"),
_("Adds an existing variable to the end of an object array variable."),
_("Add variable _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("variable", _("Scene variable with the content to add"))
.SetParameterLongDescription(_("The content of the object variable will "
"*be copied* and added at the "
"end of the array."))
@@ -724,7 +877,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("string", _("Text to add"))
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
obj.AddAction("ObjectVariablePushNumber",
_("Add number variable"),
@@ -736,7 +890,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("expression", _("Number to add"))
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
obj.AddAction(
"ObjectVariablePushBool",
@@ -749,7 +904,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("trueorfalse", _("Boolean to add"))
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
obj.AddAction(
"ObjectVariableRemoveAt",
@@ -1203,7 +1359,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Variables"),
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"));
.AddParameter("objectvar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
obj.AddExpression(
"VariableChildCount",
@@ -1220,7 +1377,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Variables"),
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"));
.AddParameter("objectvar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
obj.AddExpression("ObjectTimerElapsedTime",
_("Object timer value"),
@@ -1281,8 +1439,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Enable an effect on the object"),
_("Enable effect _PARAM1_ on _PARAM0_: _PARAM2_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("yesorno", _("Enable?"))
@@ -1297,8 +1455,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"names) in the effects window."),
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
@@ -1315,8 +1473,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"names) in the effects window."),
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
@@ -1332,8 +1490,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"names) in the effects window."),
_("Enable _PARAM2_ for effect _PARAM1_ of _PARAM0_: _PARAM3_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
@@ -1347,8 +1505,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Check if the effect on an object is enabled."),
_("Effect _PARAM1_ of _PARAM0_ is enabled"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.MarkAsSimple()
@@ -1610,6 +1768,22 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression",
_("Angle of tolerance, in degrees (0: minimum tolerance)"))
.AddCodeOnlyParameter("conditionInverted", "")
.SetHidden()
.MarkAsAdvanced();
extension
.AddCondition("IsTurnedTowardObject",
_("An object is turned toward another"),
_("Check if an object is turned toward another"),
_("_PARAM0_ is turned toward _PARAM1_ ± _PARAM2_°"),
_("Angle"),
"res/conditions/estTourne24.png",
"res/conditions/estTourne.png")
.AddParameter("objectList", _("Name of the object"))
.AddParameter("objectList", _("Name of the second object"))
.AddParameter("expression",
_("Angle of tolerance, in degrees (0: minimum tolerance)"))
.AddCodeOnlyParameter("conditionInverted", "")
.MarkAsAdvanced();
extension

View File

@@ -27,7 +27,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
extension.AddInstructionOrExpressionGroupMetadata(_("Layers and cameras"))
.SetIcon("res/conditions/camera24.png");
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
.SetIcon("res/actions/effect24.png");
.SetIcon("res/actions/effect_black.svg");
extension
.AddExpressionAndConditionAndAction(
@@ -327,6 +327,25 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.SetDefaultValue("0");
extension
.AddCondition(
"CameraZoom",
_("Camera zoom"),
_("Compare the zoom of a camera of a layer."),
_("Zoom of camera _PARAM2_ of layer _PARAM1_"),
"",
"res/conditions/camera24.png",
"res/conditions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.SetDefaultValue("0")
.UseStandardRelationalOperatorParameters(
"number", gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Zoom")))
.MarkAsAdvanced();
extension
.AddAction(
"FixCamera",
@@ -450,8 +469,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of layer _PARAM1_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
@@ -469,8 +488,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of layer _PARAM1_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
@@ -488,8 +507,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"names) in the effects window."),
_("Enable _PARAM3_ for effect _PARAM2_ of layer _PARAM1_: _PARAM4_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
@@ -504,8 +523,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
_("The effect on a layer is enabled"),
_("Effect _PARAM2_ on layer _PARAM1_ is enabled"),
_(""),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
@@ -518,8 +537,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
_("Enable an effect on a layer"),
_("Enable effect _PARAM2_ on layer _PARAM1_: _PARAM3_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")

View File

@@ -24,7 +24,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
"Open source (MIT License)")
.SetExtensionHelpPath("/objects");
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
.SetIcon("res/actions/effect24.png");
.SetIcon("res/actions/effect_black.svg");
gd::BehaviorMetadata& aut = extension.AddBehavior(
"EffectBehavior",
@@ -32,7 +32,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
"Effect",
_("Apply visual effects to objects."),
"",
"res/actions/effect24.png",
"res/actions/effect_black.svg",
"EffectBehavior",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
@@ -43,8 +43,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
_("Enable an effect on the object"),
_("Enable effect _PARAM2_ on _PARAM0_: _PARAM3_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
@@ -58,8 +58,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
@@ -75,8 +75,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
@@ -91,8 +91,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
"names) in the effects window."),
_("Enable _PARAM3_ for effect _PARAM2_ of _PARAM0_: _PARAM4_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
@@ -105,8 +105,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
_("Check if the effect on an object is enabled."),
_("Effect _PARAM2_ of _PARAM0_ is enabled"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))

View File

@@ -24,7 +24,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFlippableExtension(
"Open source (MIT License)")
.SetExtensionHelpPath("/objects");
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
.SetIcon("res/actions/effect24.png");
.SetIcon("res/actions/effect_black.svg");
gd::BehaviorMetadata& aut = extension.AddBehavior(
"FlippableBehavior",

View File

@@ -68,19 +68,22 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
extension
.AddStrExpression("ToJSON",
_("Convert scene variable to JSON"),
_("Convert a scene variable to JSON"),
_("Convert variable to JSON"),
_("Convert a variable to JSON"),
_("JSON"),
"res/conditions/toujours24_black.png")
.AddParameter("scenevar", _("Scene variable to be stringified"));
.AddParameter("variable", _("The variable to be stringified"),
"AllowUndeclaredVariable");
// Deprecated
extension
.AddStrExpression("GlobalVarToJSON",
_("Convert global variable to JSON"),
_("Convert a global variable to JSON"),
_("JSON"),
"res/conditions/toujours24_black.png")
.AddParameter("globalvar", _("The global variable to be stringified"));
.AddParameter("globalvar", _("The global variable to be stringified"))
.SetHidden();
extension
.AddStrExpression("ObjectVarToJSON",
@@ -91,6 +94,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
.AddParameter("objectPtr", _("The object with the variable"))
.AddParameter("objectvar", _("The object variable to be stringified"));
// Deprecated
extension
.AddAction(
"JSONToVariableStructure",
@@ -102,8 +106,10 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
"res/actions/net.png")
.AddParameter("string", _("JSON string"))
.AddParameter("scenevar", _("Variable where store the JSON object"))
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetHidden();
// Deprecated
extension
.AddAction("JSONToGlobalVariableStructure",
_("Convert JSON to global variable"),
@@ -116,6 +122,20 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
.AddParameter("string", _("JSON string"))
.AddParameter("globalvar",
_("Global variable where store the JSON object"))
.MarkAsAdvanced()
.SetHidden();
extension
.AddAction(
"JSONToVariableStructure2",
_("Convert JSON to a variable"),
_("Parse a JSON object and store it into a variable"),
_("Convert JSON string _PARAM0_ and store it into variable _PARAM1_"),
"",
"res/actions/net24.png",
"res/actions/net.png")
.AddParameter("string", _("JSON string"))
.AddParameter("variable", _("Variable where to store the JSON object"))
.MarkAsAdvanced();
extension

View File

@@ -98,6 +98,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
.AddParameter("string", _("Group"))
.AddParameter("string", _("Text"));
// Deprecated
extension
.AddAction(
"LireFichierExp",
@@ -114,8 +115,27 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
.AddParameter("string", _("Storage name"))
.AddParameter("string", _("Group"))
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("scenevar", _("Scene variables"));
.AddParameter("scenevar", _("Scene variable"))
.SetHidden();
extension
.AddAction(
"ReadNumberFromStorage",
_("Load a value"),
_("Load the value saved in the specified element and store it in a "
"variable.\nSpecify the structure leading to the element using / "
"(example : Root/Level/Current)\nSpaces are forbidden in element "
"names."),
_("Load _PARAM1_ from storage _PARAM0_ and store value in _PARAM3_"),
"",
"res/actions/fichier24.png",
"res/actions/fichier.png")
.AddParameter("string", _("Storage name"))
.AddParameter("string", _("Group"))
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("variable", _("Variable"));
// Deprecated
extension
.AddAction(
"LireFichierTxt",
@@ -133,7 +153,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
.AddParameter("string", _("Storage name"))
.AddParameter("string", _("Group"))
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("scenevar", _("Scene variables"));
.AddParameter("scenevar", _("Scene variable"))
.SetHidden();
extension
.AddAction(
"ReadStringFromStorage",
_("Load a text"),
_("Load the text saved in the specified element and store it in a "
"variable.\nSpecify the structure leading to the element using / "
"(example : Root/Level/Current)\nSpaces are forbidden in element "
"names."),
_("Load _PARAM1_ from storage _PARAM0_ and store as text in "
"_PARAM3_"),
"",
"res/actions/fichier24.png",
"res/actions/fichier.png")
.AddParameter("string", _("Storage name"))
.AddParameter("string", _("Group"))
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("variable", _("Variable"));
extension
.AddAction("DeleteGroupFichier",

View File

@@ -338,6 +338,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.SetDefaultValue("0");
// Deprecated
extension
.AddCondition(
"PopStartedTouch",
@@ -354,6 +355,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
.AddCodeOnlyParameter("currentScene", "")
.SetHidden();
// Deprecated
extension
.AddCondition(
"PopEndedTouch",
@@ -370,6 +372,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
.AddCodeOnlyParameter("currentScene", "")
.SetHidden();
// Deprecated
extension
.AddCondition(
"HasAnyTouchStarted",

View File

@@ -6,8 +6,6 @@
#include "GDCore/Extensions/Builtin/SpriteExtension/Animation.h"
#include <vector>
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
#include "GDCore/String.h"
namespace gd {

View File

@@ -4,13 +4,11 @@
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_ANIMATION_H
#define GDCORE_ANIMATION_H
#pragma once
#include <vector>
#include "GDCore/String.h"
namespace gd {
class Direction;
}
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
namespace gd {
@@ -93,4 +91,3 @@ class GD_CORE_API Animation {
};
} // namespace gd
#endif // GDCORE_ANIMATION_H

View File

@@ -3,12 +3,12 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_DIRECTION_H
#define GDCORE_DIRECTION_H
#pragma once
#include <vector>
#include "GDCore/String.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
namespace gd {
class Sprite;
class SerializerElement;
}
@@ -142,4 +142,3 @@ class GD_CORE_API Direction {
};
} // namespace gd
#endif // GDCORE_DIRECTION_H

View File

@@ -0,0 +1,164 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteAnimationList.h"
#include <algorithm>
#include "GDCore/CommonTools.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Animation.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/Project/InitialInstance.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/Localization.h"
namespace gd {
Animation SpriteAnimationList::badAnimation;
SpriteAnimationList::SpriteAnimationList()
: adaptCollisionMaskAutomatically(true) {}
SpriteAnimationList::~SpriteAnimationList(){};
void SpriteAnimationList::UnserializeFrom(const gd::SerializerElement& element) {
adaptCollisionMaskAutomatically =
element.GetBoolAttribute("adaptCollisionMaskAutomatically", false);
RemoveAllAnimations();
const gd::SerializerElement& animationsElement =
element.GetChild("animations", 0, "Animations");
animationsElement.ConsiderAsArrayOf("animation", "Animation");
for (std::size_t i = 0; i < animationsElement.GetChildrenCount(); ++i) {
const gd::SerializerElement& animationElement =
animationsElement.GetChild(i);
Animation newAnimation;
newAnimation.useMultipleDirections = animationElement.GetBoolAttribute(
"useMultipleDirections", false, "typeNormal");
newAnimation.SetName(animationElement.GetStringAttribute("name", ""));
// Compatibility with GD <= 3.3
if (animationElement.HasChild("Direction")) {
for (std::size_t j = 0;
j < animationElement.GetChildrenCount("Direction");
++j) {
Direction direction;
direction.UnserializeFrom(animationElement.GetChild("Direction", j));
newAnimation.SetDirectionsCount(newAnimation.GetDirectionsCount() + 1);
newAnimation.SetDirection(direction,
newAnimation.GetDirectionsCount() - 1);
}
}
// End of compatibility code
else {
const gd::SerializerElement& directionsElement =
animationElement.GetChild("directions");
directionsElement.ConsiderAsArrayOf("direction");
for (std::size_t j = 0; j < directionsElement.GetChildrenCount(); ++j) {
Direction direction;
direction.UnserializeFrom(directionsElement.GetChild(j));
newAnimation.SetDirectionsCount(newAnimation.GetDirectionsCount() + 1);
newAnimation.SetDirection(direction,
newAnimation.GetDirectionsCount() - 1);
}
}
AddAnimation(newAnimation);
}
}
void SpriteAnimationList::SerializeTo(gd::SerializerElement& element) const {
element.SetAttribute("adaptCollisionMaskAutomatically",
adaptCollisionMaskAutomatically);
// Animations
gd::SerializerElement& animationsElement = element.AddChild("animations");
animationsElement.ConsiderAsArrayOf("animation");
for (std::size_t k = 0; k < GetAnimationsCount(); k++) {
gd::SerializerElement& animationElement =
animationsElement.AddChild("animation");
animationElement.SetAttribute("useMultipleDirections",
GetAnimation(k).useMultipleDirections);
animationElement.SetAttribute("name", GetAnimation(k).GetName());
gd::SerializerElement& directionsElement =
animationElement.AddChild("directions");
directionsElement.ConsiderAsArrayOf("direction");
for (std::size_t l = 0; l < GetAnimation(k).GetDirectionsCount(); l++) {
GetAnimation(k).GetDirection(l).SerializeTo(
directionsElement.AddChild("direction"));
}
}
}
void SpriteAnimationList::ExposeResources(gd::ArbitraryResourceWorker& worker) {
for (std::size_t j = 0; j < GetAnimationsCount(); j++) {
for (std::size_t k = 0; k < GetAnimation(j).GetDirectionsCount(); k++) {
for (std::size_t l = 0;
l < GetAnimation(j).GetDirection(k).GetSpritesCount();
l++) {
worker.ExposeImage(
GetAnimation(j).GetDirection(k).GetSprite(l).GetImageName());
}
}
}
}
bool SpriteAnimationList::HasAnimationNamed(const gd::String &name) const {
return !name.empty() && (find_if(animations.begin(), animations.end(),
[&name](const Animation &animation) {
return animation.GetName() == name;
}) != animations.end());
}
const Animation& SpriteAnimationList::GetAnimation(std::size_t nb) const {
if (nb >= animations.size()) return badAnimation;
return animations[nb];
}
Animation& SpriteAnimationList::GetAnimation(std::size_t nb) {
if (nb >= animations.size()) return badAnimation;
return animations[nb];
}
void SpriteAnimationList::AddAnimation(const Animation& animation) {
animations.push_back(animation);
}
bool SpriteAnimationList::RemoveAnimation(std::size_t nb) {
if (nb >= GetAnimationsCount()) return false;
animations.erase(animations.begin() + nb);
return true;
}
void SpriteAnimationList::SwapAnimations(std::size_t firstIndex,
std::size_t secondIndex) {
if (firstIndex < animations.size() && secondIndex < animations.size() &&
firstIndex != secondIndex)
std::swap(animations[firstIndex], animations[secondIndex]);
}
void SpriteAnimationList::MoveAnimation(std::size_t oldIndex, std::size_t newIndex) {
if (oldIndex >= animations.size() || newIndex >= animations.size()) return;
auto animation = animations[oldIndex];
animations.erase(animations.begin() + oldIndex);
animations.insert(animations.begin() + newIndex, animation);
}
} // namespace gd

View File

@@ -0,0 +1,124 @@
/*
* 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 "GDCore/Extensions/Builtin/SpriteExtension/Animation.h"
namespace gd {
class InitialInstance;
class SerializerElement;
class PropertyDescriptor;
class ArbitraryResourceWorker;
} // namespace gd
namespace gd {
/**
* \brief A list of animations, containing directions with images and collision mask.
*
* It's used in the configuration of object that implements image-based animations.
*
* \see Animation
* \see Direction
* \see Sprite
* \ingroup SpriteObjectExtension
*/
class GD_CORE_API SpriteAnimationList {
public:
SpriteAnimationList();
virtual ~SpriteAnimationList();
void ExposeResources(gd::ArbitraryResourceWorker& worker);
/**
* \brief Return the animation at the specified index.
* If the index is out of bound, a "bad animation" object is returned.
*/
const Animation& GetAnimation(std::size_t nb) const;
/**
* \brief Return the animation at the specified index.
* If the index is out of bound, a "bad animation" object is returned.
*/
Animation& GetAnimation(std::size_t nb);
/**
* \brief Return the number of animations this object has.
*/
std::size_t GetAnimationsCount() const { return animations.size(); };
/**
* \brief Return true if an animation exists for a given name.
*/
bool HasAnimationNamed(const gd::String &name) const;
/**
* \brief Add an animation at the end of the existing ones.
*/
void AddAnimation(const Animation& animation);
/**
* \brief Remove an animation.
*/
bool RemoveAnimation(std::size_t nb);
/**
* \brief Remove all animations.
*/
void RemoveAllAnimations() { animations.clear(); }
/**
* \brief Return true if the object hasn't any animation.
*/
bool HasNoAnimations() const { return animations.empty(); }
/**
* \brief Swap the position of two animations
*/
void SwapAnimations(std::size_t firstIndex, std::size_t secondIndex);
/**
* \brief Change the position of the specified animation
*/
void MoveAnimation(std::size_t oldIndex, std::size_t newIndex);
/**
* \brief Return a read-only reference to the vector containing all the
* animation of the object.
*/
const std::vector<Animation>& GetAllAnimations() const { return animations; }
/**
* @brief Check if the collision mask adapts automatically to the animation.
*/
bool AdaptCollisionMaskAutomatically() const {
return adaptCollisionMaskAutomatically;
}
/**
* @brief Set if the collision mask adapts automatically to the animation.
*/
void SetAdaptCollisionMaskAutomatically(bool enable) {
adaptCollisionMaskAutomatically = enable;
}
void UnserializeFrom(const gd::SerializerElement& element);
void SerializeTo(gd::SerializerElement& element) const;
private:
mutable std::vector<Animation> animations;
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

@@ -33,6 +33,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"most elements of a game."),
"CppPlatform/Extensions/spriteicon.png")
.SetCategoryFullName(_("General"))
.SetOpenFullEditorLabel(_("Edit animations"))
.AddDefaultBehavior("EffectCapability::EffectBehavior")
.AddDefaultBehavior("ResizableCapability::ResizableBehavior")
.AddDefaultBehavior("ScalableCapability::ScalableBehavior")

View File

@@ -23,127 +23,45 @@
namespace gd {
Animation SpriteObject::badAnimation;
SpriteObject::SpriteObject()
: updateIfNotVisible(false), adaptCollisionMaskAutomatically(true) {}
: updateIfNotVisible(false),
preScale(1) {}
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 =
element.GetChild("animations", 0, "Animations");
animationsElement.ConsiderAsArrayOf("animation", "Animation");
for (std::size_t i = 0; i < animationsElement.GetChildrenCount(); ++i) {
const gd::SerializerElement& animationElement =
animationsElement.GetChild(i);
Animation newAnimation;
newAnimation.useMultipleDirections = animationElement.GetBoolAttribute(
"useMultipleDirections", false, "typeNormal");
newAnimation.SetName(animationElement.GetStringAttribute("name", ""));
// Compatibility with GD <= 3.3
if (animationElement.HasChild("Direction")) {
for (std::size_t j = 0;
j < animationElement.GetChildrenCount("Direction");
++j) {
Direction direction;
direction.UnserializeFrom(animationElement.GetChild("Direction", j));
newAnimation.SetDirectionsCount(newAnimation.GetDirectionsCount() + 1);
newAnimation.SetDirection(direction,
newAnimation.GetDirectionsCount() - 1);
}
}
// End of compatibility code
else {
const gd::SerializerElement& directionsElement =
animationElement.GetChild("directions");
directionsElement.ConsiderAsArrayOf("direction");
for (std::size_t j = 0; j < directionsElement.GetChildrenCount(); ++j) {
Direction direction;
direction.UnserializeFrom(directionsElement.GetChild(j));
newAnimation.SetDirectionsCount(newAnimation.GetDirectionsCount() + 1);
newAnimation.SetDirection(direction,
newAnimation.GetDirectionsCount() - 1);
}
}
AddAnimation(newAnimation);
}
preScale = element.GetDoubleAttribute("preScale", 1);
animations.UnserializeFrom(element);
}
void SpriteObject::DoSerializeTo(gd::SerializerElement& element) const {
element.SetAttribute("updateIfNotVisible", updateIfNotVisible);
element.SetAttribute("adaptCollisionMaskAutomatically",
adaptCollisionMaskAutomatically);
// Animations
gd::SerializerElement& animationsElement = element.AddChild("animations");
animationsElement.ConsiderAsArrayOf("animation");
for (std::size_t k = 0; k < GetAnimationsCount(); k++) {
gd::SerializerElement& animationElement =
animationsElement.AddChild("animation");
animationElement.SetAttribute("useMultipleDirections",
GetAnimation(k).useMultipleDirections);
animationElement.SetAttribute("name", GetAnimation(k).GetName());
gd::SerializerElement& directionsElement =
animationElement.AddChild("directions");
directionsElement.ConsiderAsArrayOf("direction");
for (std::size_t l = 0; l < GetAnimation(k).GetDirectionsCount(); l++) {
GetAnimation(k).GetDirection(l).SerializeTo(
directionsElement.AddChild("direction"));
}
if (preScale != 1) {
element.SetAttribute("preScale", preScale);
}
animations.SerializeTo(element);
}
std::map<gd::String, gd::PropertyDescriptor> SpriteObject::GetProperties()
const {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[_("Animate even if hidden or far from the screen")]
.SetValue(updateIfNotVisible ? "true" : "false")
.SetType("Boolean");
properties["PLEASE_ALSO_SHOW_EDIT_BUTTON_THANKS"].SetValue("");
return properties;
}
bool SpriteObject::UpdateProperty(const gd::String& name,
const gd::String& value) {
if (name == _("Animate even if hidden or far from the screen"))
updateIfNotVisible = value == "1";
return true;
}
void SpriteObject::ExposeResources(gd::ArbitraryResourceWorker& worker) {
for (std::size_t j = 0; j < GetAnimationsCount(); j++) {
for (std::size_t k = 0; k < GetAnimation(j).GetDirectionsCount(); k++) {
for (std::size_t l = 0;
l < GetAnimation(j).GetDirection(k).GetSpritesCount();
l++) {
worker.ExposeImage(
GetAnimation(j).GetDirection(k).GetSprite(l).GetImageName());
}
}
}
animations.ExposeResources(worker);
}
std::map<gd::String, gd::PropertyDescriptor>
SpriteObject::GetInitialInstanceProperties(
const gd::InitialInstance& initialInstance,
gd::Project& project,
gd::Layout& scene) {
const gd::InitialInstance& initialInstance) {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties["animation"] =
gd::PropertyDescriptor(
@@ -157,9 +75,7 @@ SpriteObject::GetInitialInstanceProperties(
bool SpriteObject::UpdateInitialInstanceProperty(
gd::InitialInstance& initialInstance,
const gd::String& name,
const gd::String& value,
gd::Project& project,
gd::Layout& scene) {
const gd::String& value) {
if (name == "animation") {
initialInstance.SetRawDoubleProperty(
"animation", std::max(0, value.empty() ? 0 : value.To<int>()));
@@ -168,42 +84,25 @@ bool SpriteObject::UpdateInitialInstanceProperty(
return true;
}
const Animation& SpriteObject::GetAnimation(std::size_t nb) const {
if (nb >= animations.size()) return badAnimation;
return animations[nb];
size_t SpriteObject::GetAnimationsCount() const {
return animations.GetAnimationsCount();
}
Animation& SpriteObject::GetAnimation(std::size_t nb) {
if (nb >= animations.size()) return badAnimation;
return animations[nb];
const gd::String &SpriteObject::GetAnimationName(size_t index) const {
return animations.GetAnimation(index).GetName();
}
void SpriteObject::AddAnimation(const Animation& animation) {
animations.push_back(animation);
bool SpriteObject::HasAnimationNamed(
const gd::String &name) const {
return animations.HasAnimationNamed(name);
}
bool SpriteObject::RemoveAnimation(std::size_t nb) {
if (nb >= GetAnimationsCount()) return false;
animations.erase(animations.begin() + nb);
return true;
const SpriteAnimationList& SpriteObject::GetAnimations() const {
return animations;
}
void SpriteObject::SwapAnimations(std::size_t firstIndex,
std::size_t secondIndex) {
if (firstIndex < animations.size() && secondIndex < animations.size() &&
firstIndex != secondIndex)
std::swap(animations[firstIndex], animations[secondIndex]);
}
void SpriteObject::MoveAnimation(std::size_t oldIndex, std::size_t newIndex) {
if (oldIndex >= animations.size() || newIndex >= animations.size()) return;
auto animation = animations[oldIndex];
animations.erase(animations.begin() + oldIndex);
animations.insert(animations.begin() + newIndex, animation);
SpriteAnimationList& SpriteObject::GetAnimations() {
return animations;
}
} // namespace gd

View File

@@ -4,18 +4,15 @@
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_SPRITEOBJECT_H
#define GDCORE_SPRITEOBJECT_H
#include "GDCore/Extensions/Builtin/SpriteExtension/Animation.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
#pragma once
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteAnimationList.h"
#include "GDCore/Project/Object.h"
namespace gd {
class InitialInstance;
class Object;
class Layout;
class Sprite;
class Animation;
class SerializerElement;
class PropertyDescriptor;
} // namespace gd
@@ -50,85 +47,26 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
bool UpdateProperty(const gd::String& name, const gd::String& value) override;
std::map<gd::String, gd::PropertyDescriptor> GetInitialInstanceProperties(
const gd::InitialInstance& position,
gd::Project& project,
gd::Layout& scene) override;
const gd::InitialInstance& position) override;
bool UpdateInitialInstanceProperty(gd::InitialInstance& position,
const gd::String& name,
const gd::String& value,
gd::Project& project,
gd::Layout& scene) override;
const gd::String& value) override;
/** \name Animations
* Methods related to animations management
*/
///@{
size_t GetAnimationsCount() const override;
const gd::String &GetAnimationName(size_t index) const override;
bool HasAnimationNamed(const gd::String &animationName) const override;
/**
* \brief Return the animation at the specified index.
* If the index is out of bound, a "bad animation" object is returned.
* \brief Return the animation configuration.
*/
const Animation& GetAnimation(std::size_t nb) const;
const SpriteAnimationList& GetAnimations() const;
/**
* \brief Return the animation at the specified index.
* If the index is out of bound, a "bad animation" object is returned.
* @brief Return the animation configuration.
*/
Animation& GetAnimation(std::size_t nb);
/**
* \brief Return the number of animations this object has.
*/
std::size_t GetAnimationsCount() const { return animations.size(); };
/**
* \brief Add an animation at the end of the existing ones.
*/
void AddAnimation(const Animation& animation);
/**
* \brief Remove an animation.
*/
bool RemoveAnimation(std::size_t nb);
/**
* \brief Remove all animations.
*/
void RemoveAllAnimations() { animations.clear(); }
/**
* \brief Return true if the object hasn't any animation.
*/
bool HasNoAnimations() const { return animations.empty(); }
/**
* \brief Swap the position of two animations
*/
void SwapAnimations(std::size_t firstIndex, std::size_t secondIndex);
/**
* \brief Change the position of the specified animation
*/
void MoveAnimation(std::size_t oldIndex, std::size_t newIndex);
/**
* \brief Return a read-only reference to the vector containing all the
* animation of the object.
*/
const std::vector<Animation>& GetAllAnimations() const { return animations; }
/**
* @brief Check if the collision mask adapts automatically to the animation.
*/
bool AdaptCollisionMaskAutomatically() const {
return adaptCollisionMaskAutomatically;
}
/**
* @brief Set if the collision mask adapts automatically to the animation.
*/
void SetAdaptCollisionMaskAutomatically(bool enable) {
adaptCollisionMaskAutomatically = enable;
}
SpriteAnimationList& GetAnimations();
/**
* \brief Set if the object animation should be played even if the object is
@@ -143,25 +81,35 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
* is hidden or far from the camera (false by default).
*/
bool GetUpdateIfNotVisible() const { return updateIfNotVisible; }
///@}
/**
* \brief Return the scale applied to object to evaluate the default dimensions.
*/
double GetPreScale() { return preScale; }
/**
* \brief Set the scale applied to object to evaluate the default dimensions.
*
* Its value must be strictly positive.
*/
void SetPreScale(double preScale_) {
if (preScale_ <= 0) {
return;
}
preScale = preScale_;
}
private:
void DoUnserializeFrom(gd::Project& project,
const gd::SerializerElement& element) override;
void DoSerializeTo(gd::SerializerElement& element) const override;
mutable std::vector<Animation> animations;
SpriteAnimationList animations;
bool updateIfNotVisible; ///< If set to true, ask the game engine to play
///< object animation even if hidden or far from
///< the screen.
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.
double preScale;
};
} // namespace gd
#endif // GDCORE_SPRITEOBJECT_H

View File

@@ -25,29 +25,271 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension.AddInstructionOrExpressionGroupMetadata(_("Variables"))
.SetIcon("res/conditions/var24.png");
extension
.AddCondition("NumberVariable",
_("Variable value"),
_("Compare the number value of a variable."),
_("The variable _PARAM0_"),
"",
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("variable", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions());
extension
.AddCondition("StringVariable",
_("Variable value"),
_("Compare the text (string) of a variable."),
_("The variable _PARAM0_"),
"",
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("variable", _("Variable"))
.UseStandardRelationalOperatorParameters(
"string", ParameterOptions::MakeNewOptions());
extension
.AddCondition(
"BooleanVariable",
_("Variable value"),
_("Compare the boolean value of a variable."),
_("The variable _PARAM0_ is _PARAM1_"),
"",
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("variable", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true")
// This parameter allows to keep the operand expression
// when the editor switch between variable instructions.
.AddCodeOnlyParameter("trueorfalse", "");
extension
.AddAction("SetNumberVariable",
_("Change variable value"),
_("Modify the number value of a variable."),
_("the variable _PARAM0_"),
"",
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("variable", _("Variable"))
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions());
extension
.AddAction("SetStringVariable",
_("Change text variable"),
_("Modify the text (string) of a variable."),
_("the variable _PARAM0_"),
"",
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("variable", _("Variable"))
.UseStandardOperatorParameters("string",
ParameterOptions::MakeNewOptions());
extension
.AddAction(
"SetBooleanVariable",
_("Change boolean variable"),
_("Modify the boolean value of a variable."),
_("Change the variable _PARAM0_: _PARAM1_"),
"",
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("variable", _("Variable"))
.AddParameter("operator", _("Value"), "boolean")
// This parameter allows to keep the operand expression
// when the editor switch between variable instructions.
.AddCodeOnlyParameter("trueorfalse", "");
extension
.AddCondition(
"VariableChildCount",
_("Number of children"),
_("Compare the number of children in an array variable."),
_("The number of children in the array variable _PARAM0_"),
_("Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("variable", _("Array variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.MarkAsAdvanced();
extension
.AddCondition("VariableChildExists2",
_("Child existence"),
_("Check if the specified child of the structure "
"variable exists."),
_("Child _PARAM1_ of variable _PARAM0_ exists"),
_("Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("variable", _("Variable"))
.AddParameter("string", _("Name of the child"))
.MarkAsAdvanced();
extension
.AddAction(
"RemoveVariableChild",
_("Remove a child"),
_("Remove a child from a structure variable."),
_("Remove child _PARAM1_ from structure variable _PARAM0_"),
_("Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("variable", _("Structure variable"))
.AddParameter("string", _("Child's name"))
.MarkAsAdvanced();
extension
.AddAction("ClearVariableChildren",
_("Clear children"),
_("Remove all the children from the structure or array "
"variable."),
_("Clear children from variable _PARAM0_"),
_("Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("variable", _("Structure or array variable"))
.MarkAsAdvanced();
extension
.AddAction("PushVariable",
_("Add existing variable"),
_("Adds an existing variable at the end of an array "
"variable."),
_("Add variable _PARAM1_ to array variable _PARAM0_"),
_("Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("variable", _("Array variable"))
.AddParameter("variable", _("Variable with the content to add"))
.SetParameterLongDescription(
_("The content of the variable will *be copied* and added at the "
"end of the array."))
.MarkAsAdvanced();
extension
.AddAction(
"PushString",
_("Add text variable"),
_("Adds a text (string) at the end of a array variable."),
_("Add the value _PARAM1_ to array variable _PARAM0_"),
_("Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("variable", _("Array variable"))
.AddParameter("string", _("Text to add"))
.MarkAsAdvanced();
extension
.AddAction("PushNumber",
_("Add variable array value"),
_("Adds a number at the end of an array variable."),
_("Add the value _PARAM1_ to array variable _PARAM0_"),
_("Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("variable", _("Array variable"))
.AddParameter("expression", _("Number to add"))
.MarkAsAdvanced();
extension
.AddAction("PushBoolean",
_("Add boolean variable"),
_("Adds a boolean at the end of an array variable."),
_("Add the value _PARAM1_ to array variable _PARAM0_"),
_("Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("variable", _("Array variable"))
.AddParameter("trueorfalse", _("Boolean to add"))
.MarkAsAdvanced();
extension
.AddAction("RemoveVariableAt",
_("Remove variable by index"),
_("Removes a variable at the specified index of an array "
"variable."),
_("Remove variable at index _PARAM1_ from array "
"variable _PARAM0_"),
_("Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("variable", _("Array variable"))
.AddParameter("expression", _("Index to remove"))
.MarkAsAdvanced();
extension
.AddStrExpression(
"VariableFirstString",
_("First text child"),
_("Get the value of the first element of an array variable, if "
"it is a text (string)."),
_("Arrays and structures"),
"res/actions/var.png")
.AddParameter("variable", _("Array variable"));
extension
.AddExpression(
"VariableFirstNumber",
_("First number child"),
_("Get the value of the first element of an array variable, if "
"it is a number."),
_("Arrays and structures"),
"res/actions/var.png")
.AddParameter("variable", _("Array variable"));
extension
.AddStrExpression(
"VariableLastString",
_("Last text child"),
_("Get the value of the last element of an array variable, if "
"it is a text (string)."),
_("Arrays and structures"),
"res/actions/var.png")
.AddParameter("variable", _("Array variable"));
extension
.AddExpression(
"VariableLastNumber",
_("Last number child"),
_("Get the value of the last element of an array variable, if "
"it is a number."),
_("Arrays and structures"),
"res/actions/var.png")
.AddParameter("variable", _("Array variable"));
// Legacy instructions
extension
.AddCondition("VarScene",
_("Number variable"),
_("Compare the number value of a scene variable."),
_("The number of scene variable _PARAM0_"),
_("Scene variables"),
_("External variables/Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions());
"number", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
extension
.AddCondition("VarSceneTxt",
_("Text variable"),
_("Compare the text (string) of a scene variable."),
_("The text of scene variable _PARAM0_"),
_("Scene variables"),
_("External variables/Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"string", ParameterOptions::MakeNewOptions());
"string", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
extension
.AddCondition(
@@ -55,12 +297,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Boolean variable"),
_("Compare the boolean value of a scene variable."),
_("The boolean value of scene variable _PARAM0_ is _PARAM1_"),
_("Scene variables"),
_("External variables/Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true");
.SetDefaultValue("true")
.SetRelevantForFunctionEventsOnly();
extension
.AddCondition("VariableChildExists",
@@ -68,11 +311,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Check if the specified child of the scene structure "
"variable exists."),
_("Child _PARAM1_ of scene variable _PARAM0_ exists"),
_("Scene variables/Arrays and structures"),
_("External variables/Scene variables/Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.AddParameter("string", _("Name of the child"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -81,11 +325,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Check if the specified child of the global structure "
"variable exists."),
_("Child _PARAM1_ of global variable _PARAM0_ exists"),
_("Global variables/Arrays and structures"),
_("External variables/Global variables/Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.AddParameter("string", _("Name of the child"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -93,7 +338,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"Variable defined",
"Test if the scene variable exists.",
"Scene variable _PARAM0_ is defined",
_("Scene variables"),
_("External variables/Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddCodeOnlyParameter("currentScene", "")
@@ -105,12 +350,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Number variable"),
_("Compare the number value of a global variable."),
_("the global variable _PARAM0_"),
_("Global variables"),
_("External variables/Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -118,12 +364,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Text variable"),
_("Compare the text (string) of a global variable."),
_("the text of the global variable _PARAM0_"),
_("Global variables"),
_("External variables/Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"string", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -132,19 +379,20 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Boolean variable"),
_("Compare the boolean value of a global variable."),
_("The boolean value of global variable _PARAM0_ is _PARAM1_"),
_("Global variables"),
_("External variables/Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true");
.SetDefaultValue("true")
.SetRelevantForFunctionEventsOnly();
extension
.AddCondition("VarGlobalDef",
"Variable defined",
"Test if a global variable exists.",
"Global variable _PARAM0_ is defined",
_("Global variables"),
_("External variables/Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddCodeOnlyParameter("currentScene", "")
@@ -157,24 +405,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Change number variable"),
_("Modify the number value of a scene variable."),
_("the scene variable _PARAM0_"),
_("Scene variables"),
_("External variables/Scene variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions());
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
extension
.AddAction("ModVarSceneTxt",
_("Change text variable"),
_("Modify the text (string) of a scene variable."),
_("the text of scene variable _PARAM0_"),
_("Scene variables"),
_("External variables/Scene variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardOperatorParameters("string",
ParameterOptions::MakeNewOptions());
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
extension
.AddAction(
@@ -182,11 +432,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Change boolean variable"),
_("Modify the boolean value of a scene variable."),
_("Set the boolean value of scene variable _PARAM0_ to _PARAM1_"),
_("Scene variables"),
_("External variables/Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.AddParameter("trueorfalse", _("New Value:"));
.AddParameter("trueorfalse", _("New Value:"))
.SetRelevantForFunctionEventsOnly();
extension
.AddAction("ToggleSceneVariableAsBoolean",
@@ -195,22 +446,24 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("If it was true, it will become false, and if it was "
"false it will become true."),
_("Toggle the boolean value of scene variable _PARAM0_"),
_("Scene variables"),
_("External variables/Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"));
.AddParameter("scenevar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
extension
.AddAction("ModVarGlobal",
_("Change number variable"),
_("Modify the number value of a global variable."),
_("the global variable _PARAM0_"),
_("Global variables"),
_("External variables/Global variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -218,12 +471,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Change text variable"),
_("Modify the text (string) of a global variable."),
_("the text of global variable _PARAM0_"),
_("Global variables"),
_("External variables/Global variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardOperatorParameters("string",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -232,11 +486,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Change boolean variable"),
_("Modify the boolean value of a global variable."),
_("Set the boolean value of global variable _PARAM0_ to _PARAM1_"),
_("Global variables"),
_("External variables/Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.AddParameter("trueorfalse", _("New Value:"));
.AddParameter("trueorfalse", _("New Value:"))
.SetRelevantForFunctionEventsOnly();
extension
.AddAction("ToggleGlobalVariableAsBoolean",
@@ -245,10 +500,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("If it was true, it will become false, and if it was "
"false it will become true."),
_("Toggle the boolean value of global variable _PARAM0_"),
_("Global variables"),
_("External variables/Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"));
.AddParameter("globalvar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
extension
.AddAction(
@@ -256,12 +512,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Remove a child"),
_("Remove a child from a scene structure variable."),
_("Remove child _PARAM1_ from scene structure variable _PARAM0_"),
_("Scene variables/Arrays and structures"),
_("External variables/Scene variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Structure variable"))
.AddParameter("string", _("Child's name"))
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
extension
.AddAction(
@@ -269,12 +526,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Remove a child"),
_("Remove a child from a global structure variable."),
_("Remove child _PARAM1_ from global structure variable _PARAM0_"),
_("Global variables/Arrays and structures"),
_("External variables/Global variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Structure variable"))
.AddParameter("string", _("Child's name"))
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
extension
.AddAction("VariableClearChildren",
@@ -282,10 +540,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Remove all the children from the scene structure or array "
"variable."),
_("Clear children from scene variable _PARAM0_"),
_("Scene variables/Arrays and structures"),
_("External variables/Scene variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Structure or array variable"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -294,10 +553,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Remove all the children from the global structure or array "
"variable."),
_("Clear children from global variable _PARAM0_"),
_("Global variables/Arrays and structures"),
_("External variables/Global variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Structure or array variable"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -306,7 +566,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Adds an existing variable at the end of a scene array "
"variable."),
_("Add variable _PARAM1_ to array variable _PARAM0_"),
_("Scene variables/Arrays and structures"),
_("External variables/Scene variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
@@ -314,6 +574,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
.SetParameterLongDescription(
_("The content of the variable will *be copied* and added at the "
"end of the array."))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -322,11 +583,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Add text variable"),
_("Adds a text (string) at the end of a scene array variable."),
_("Add text _PARAM1_ to array variable _PARAM0_"),
_("Scene variables/Arrays and structures"),
_("External variables/Scene variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.AddParameter("string", _("Text to add"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -334,11 +596,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Add number variable"),
_("Adds a number at the end of a scene array variable."),
_("Add number _PARAM1_ to array variable _PARAM0_"),
_("Scene variables/Arrays and structures"),
_("External variables/Scene variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.AddParameter("expression", _("Number to add"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -346,11 +609,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Add boolean variable"),
_("Adds a boolean at the end of a scene array variable."),
_("Add boolean _PARAM1_ to array variable _PARAM0_"),
_("Scene variables/Arrays and structures"),
_("External variables/Scene variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.AddParameter("trueorfalse", _("Boolean to add"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -360,11 +624,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"variable."),
_("Remove variable at index _PARAM1_ from scene array "
"variable _PARAM0_"),
_("Scene variables/Arrays and structures"),
_("External variables/Scene variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.AddParameter("expression", _("Index to remove"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -373,12 +638,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Number of children"),
_("Compare the number of children in a scene array variable."),
_("The number of children in the array variable _PARAM0_"),
_("Scene variables/Arrays and structures"),
_("External variables/Scene variables/Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Array variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -387,9 +653,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("First text child"),
_("Get the value of the first element of a scene array variable, if "
"it is a text (string)."),
_("Scene variables/Arrays and structures"),
_("External variables/Scene variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"));
.AddParameter("scenevar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
extension
.AddExpression(
@@ -397,9 +664,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("First number child"),
_("Get the value of the first element of a scene array variable, if "
"it is a number."),
_("Scene variables/Arrays and structures"),
_("External variables/Scene variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"));
.AddParameter("scenevar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
extension
.AddStrExpression(
@@ -407,9 +675,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Last text child"),
_("Get the value of the last element of a scene array variable, if "
"it is a text (string)."),
_("Scene variables/Arrays and structures"),
_("External variables/Scene variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"));
.AddParameter("scenevar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
extension
.AddExpression(
@@ -417,9 +686,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Last number child"),
_("Get the value of the last element of a scene array variable, if "
"it is a number."),
_("Scene variables/Arrays and structures"),
_("External variables/Scene variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"));
.AddParameter("scenevar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
extension
.AddAction(
@@ -427,7 +697,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Add existing variable"),
_("Adds an existing variable at the end of a global array variable."),
_("Add variable _PARAM1_ to array variable _PARAM0_"),
_("Global variables/Arrays and structures"),
_("External variables/Global variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
@@ -435,6 +705,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
.SetParameterLongDescription(
_("The content of the variable will *be copied* and added at the "
"end of the array."))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -444,11 +715,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"array variable."),
_("Remove variable at index _PARAM1_ from global array "
"variable _PARAM0_"),
_("Global variables/Arrays and structures"),
_("External variables/Global variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.AddParameter("expression", _("Index to remove"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -457,11 +729,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Add text variable"),
_("Adds a text (string) at the end of a global array variable."),
_("Add text _PARAM1_ to array variable _PARAM0_"),
_("Global variables/Arrays and structures"),
_("External variables/Global variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.AddParameter("string", _("Text to add"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -469,11 +742,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Add number variable"),
_("Adds a number at the end of a global array variable."),
_("Add number _PARAM1_ to array variable _PARAM0_"),
_("Global variables/Arrays and structures"),
_("External variables/Global variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.AddParameter("expression", _("Number to add"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -481,11 +755,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Add boolean variable"),
_("Adds a boolean at the end of a global array variable."),
_("Add boolean _PARAM1_ to array variable _PARAM0_"),
_("Global variables/Arrays and structures"),
_("External variables/Global variables/Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.AddParameter("trueorfalse", _("Boolean to add"))
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -494,12 +769,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Number of children"),
_("Compare the number of children in a global array variable."),
_("The number of children of the array variable _PARAM0_"),
_("Global variables/Arrays and structures"),
_("External variables/Global variables/Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Array variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
@@ -507,18 +783,20 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("First text child"),
_("Value of the first element of a global array "
"variable, if it is a text (string) variable."),
_("Global variables/Arrays and structures"),
_("External variables/Global variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"));
.AddParameter("globalvar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
extension
.AddExpression("GlobalVariableFirstNumber",
_("First number child"),
_("Value of the first element of a global array "
"variable, if it is a number variable"),
_("Global variables/Arrays and structures"),
_("External variables/Global variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"));
.AddParameter("globalvar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
extension
.AddStrExpression(
@@ -526,9 +804,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Last text child"),
_("Value of the last element of a global array variable, if "
"it is a text (string) variable."),
_("Global variables/Arrays and structures"),
_("External variables/Global variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"));
.AddParameter("globalvar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
extension
.AddExpression(
@@ -536,59 +815,65 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Last number child"),
_("Value of the last element of a global array variable, if "
"it is a number variable"),
_("Global variables/Arrays and structures"),
_("External variables/Global variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"));
.AddParameter("globalvar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
extension
.AddExpression("GlobalVariableChildCount",
_("Number of children"),
_("Number of children in a global array or "
"structure variable"),
_("Global variables/Arrays and structures"),
_("External variables/Global variables/Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array or structure variable"));
.AddParameter("globalvar", _("Array or structure variable"))
.SetRelevantForFunctionEventsOnly();
extension
.AddExpression("VariableChildCount",
_("Number of children"),
_("Number of children in a scene array or "
"structure variable"),
_("Scene variables/Arrays and structures"),
_("Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array or structure variable"));
.AddParameter("variable", _("Array or structure variable"), "AllowUndeclaredVariable");
extension
.AddExpression("Variable",
_("Number variable"),
_("Number value of a scene variable"),
_("Scene variables"),
_("External variables/Scene variables"),
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"));
.AddParameter("scenevar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
extension
.AddStrExpression("VariableString",
_("Text variable"),
_("Text of a scene variable"),
_("Scene variables"),
_("External variables/Scene variables"),
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"));
.AddParameter("scenevar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
extension
.AddExpression("GlobalVariable",
_("Number variable"),
_("Number value of a global variable"),
_("Global variables"),
_("External variables/Global variables"),
"res/actions/var.png")
.AddParameter("globalvar", _("Name of the global variable"));
.AddParameter("globalvar", _("Name of the global variable"))
.SetRelevantForFunctionEventsOnly();
extension
.AddStrExpression("GlobalVariableString",
_("Text variable"),
_("Text of a global variable"),
_("Global variables"),
_("External variables/Global variables"),
"res/actions/var.png")
.AddParameter("globalvar", _("Variable"));
.AddParameter("globalvar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
}
} // namespace gd

View File

@@ -114,6 +114,8 @@ public:
/**
* \brief Erase any existing include file and add the specified include.
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
virtual AbstractFunctionMetadata &
SetIncludeFile(const gd::String &includeFile) = 0;

View File

@@ -13,12 +13,15 @@
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/BehaviorsSharedData.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/MakeUnique.h"
#include "GDCore/Tools/Log.h"
namespace gd {
const std::map<gd::String, gd::PropertyDescriptor> BehaviorMetadata::badProperties;
BehaviorMetadata::BehaviorMetadata(
const gd::String& extensionNamespace_,
const gd::String& nameWithNamespace,
@@ -47,8 +50,14 @@ BehaviorMetadata::BehaviorMetadata(
"BehaviorMetadata is valid for: " + nameWithNamespace);
}
if (instance) instance->SetTypeName(nameWithNamespace);
if (sharedDatasInstance) sharedDatasInstance->SetTypeName(nameWithNamespace);
if (instance) {
instance->SetTypeName(nameWithNamespace);
instance->InitializeContent();
}
if (sharedDatasInstance) {
sharedDatasInstance->SetTypeName(nameWithNamespace);
sharedDatasInstance->InitializeContent();
}
}
gd::InstructionMetadata& BehaviorMetadata::AddCondition(
@@ -405,18 +414,44 @@ gd::Behavior& BehaviorMetadata::Get() const {
return *instance;
}
gd::BehaviorsSharedData* BehaviorMetadata::GetSharedDataInstance() const {
std::map<gd::String, gd::PropertyDescriptor> BehaviorMetadata::GetProperties() const {
if (!instance) {
return badProperties;
}
// TODO Properties should be declared on BehaviorMetadata directly.
// - Add 2 `properties` members (one for shared properties)
// - Add methods to declare new properties
return instance->GetProperties();
}
gd::BehaviorsSharedData* BehaviorMetadata::GetSharedDataInstance() const {
return sharedDatasInstance.get();
}
std::map<gd::String, gd::PropertyDescriptor> BehaviorMetadata::GetSharedProperties() const {
if (!sharedDatasInstance) {
return badProperties;
}
// TODO Properties should be declared on BehaviorMetadata directly.
// - Add 2 `properties` members (one for shared properties)
// - Add methods to declare new properties
return sharedDatasInstance->GetProperties();
}
const std::vector<gd::String>& BehaviorMetadata::GetRequiredBehaviorTypes() const {
requiredBehaviors.clear();
for (auto& property : Get().GetProperties()) {
if (!instance) {
return requiredBehaviors;
}
for (auto& property : instance->GetProperties()) {
const String& propertyName = property.first;
const gd::PropertyDescriptor& propertyDescriptor = property.second;
if (propertyDescriptor.GetType() == "Behavior") {
requiredBehaviors.push_back(propertyDescriptor.GetExtraInfo()[0]);
const auto& extraInfos = propertyDescriptor.GetExtraInfo();
if (extraInfos.size() > 0) {
requiredBehaviors.push_back(extraInfos[0]);
}
}
}
return requiredBehaviors;

View File

@@ -12,12 +12,14 @@
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/String.h"
#include "GDCore/Project/QuickCustomization.h"
namespace gd {
class Behavior;
class BehaviorsSharedData;
class MultipleInstructionMetadata;
class InstructionMetadata;
class ExpressionMetadata;
class PropertyDescriptor;
} // namespace gd
namespace gd {
@@ -40,10 +42,10 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
const gd::String& className_,
std::shared_ptr<gd::Behavior> instance,
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance);
/**
* \brief Construct a behavior metadata, without "blueprint" behavior.
*
*
* \note This is used by events based behaviors.
*/
BehaviorMetadata(
@@ -204,6 +206,8 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
* \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.
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
BehaviorMetadata& SetIncludeFile(const gd::String& includeFile) override;
@@ -294,23 +298,59 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
return *this;
}
QuickCustomization::Visibility GetQuickCustomizationVisibility() const {
return quickCustomizationVisibility;
}
BehaviorMetadata &SetQuickCustomizationVisibility(QuickCustomization::Visibility visibility) {
quickCustomizationVisibility = visibility;
return *this;
}
BehaviorMetadata &SetOpenFullEditorLabel(const gd::String& label) {
openFullEditorLabel = label;
return *this;
}
const gd::String& GetOpenFullEditorLabel() const {
return openFullEditorLabel;
}
/**
* \brief Return the associated gd::Behavior, handling behavior contents.
*
*
* \note Returns a dumb Behavior for events based behaviors as CustomBehavior
* are using EventBasedBehavior.
*/
gd::Behavior& Get() const;
/**
* \brief Called when the IDE wants to know about the custom properties of the
* behavior.
*
* \return a std::map with properties names as key.
* \see gd::PropertyDescriptor
*/
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
/**
* \brief Return the associated gd::BehaviorsSharedData, handling behavior
* shared data, if any (nullptr if none).
*
*
* \note Returns nullptr for events based behaviors as they don't declare
* shared data yet.
*/
gd::BehaviorsSharedData* GetSharedDataInstance() const;
/**
* \brief Called when the IDE wants to know about the custom shared properties
* of the behavior.
*
* \return a std::map with properties names as key.
* \see gd::PropertyDescriptor
*/
std::map<gd::String, gd::PropertyDescriptor> GetSharedProperties() const;
/**
* \brief Return a reference to a map containing the names of the actions
* (as keys) and the metadata associated with (as values).
@@ -353,10 +393,14 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
mutable std::vector<gd::String> requiredBehaviors;
bool isPrivate = false;
bool isHidden = false;
gd::String openFullEditorLabel;
QuickCustomization::Visibility quickCustomizationVisibility = QuickCustomization::Visibility::Default;
// TODO: Nitpicking: convert these to std::unique_ptr to clarify ownership.
std::shared_ptr<gd::Behavior> instance;
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance;
static const std::map<gd::String, gd::PropertyDescriptor> badProperties;
};
} // namespace gd

View File

@@ -65,6 +65,8 @@ class GD_CORE_API EffectMetadata {
/**
* \brief Clear any existing include file and add the specified include file.
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
EffectMetadata& SetIncludeFile(const gd::String& includeFile);
@@ -183,10 +185,10 @@ class GD_CORE_API EffectMetadata {
gd::String fullname;
gd::String description;
std::vector<gd::String> includeFiles;
bool isMarkedAsNotWorkingForObjects;
bool isMarkedAsOnlyWorkingFor2D;
bool isMarkedAsOnlyWorkingFor3D;
bool isMarkedAsUnique;
bool isMarkedAsNotWorkingForObjects = false;
bool isMarkedAsOnlyWorkingFor2D = false;
bool isMarkedAsOnlyWorkingFor3D = false;
bool isMarkedAsUnique = false;
std::map<gd::String, gd::PropertyDescriptor> properties;
};

View File

@@ -19,7 +19,8 @@ EventMetadata::EventMetadata(const gd::String &name_,
: fullname(fullname_),
description(description_),
group(group_),
instance(instance_) {
instance(instance_),
hasCustomCodeGenerator(false) {
ClearCodeGenerationAndPreprocessing();
if (instance) instance->SetType(name_);
}

View File

@@ -83,7 +83,7 @@ class GD_CORE_API EventMetadata {
gd::String group;
std::shared_ptr<gd::BaseEvent> instance;
bool hasCustomCodeGenerator;
bool hasCustomCodeGenerator = false;
std::function<gd::String(gd::BaseEvent& event,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context)>

View File

@@ -38,43 +38,37 @@ gd::ExpressionMetadata& ExpressionMetadata::AddParameter(
const gd::String& description,
const gd::String& supplementaryInformation,
bool parameterIsOptional) {
gd::ParameterMetadata info;
info.SetType(type);
info.description = description;
info.codeOnly = false;
info.SetOptional(parameterIsOptional);
info.SetExtraInfo(
parameters.AddNewParameter("")
.SetType(type)
.SetDescription(description)
.SetCodeOnly(false)
.SetOptional(parameterIsOptional)
.SetExtraInfo(
// For objects/behavior, the supplementary information
// parameter is an object/behavior type...
((gd::ParameterMetadata::IsObject(type) ||
gd::ParameterMetadata::IsBehavior(type))
// Prefix with the namespace if it's not already there.
&& (supplementaryInformation.find(
PlatformExtension::GetNamespaceSeparator()) != gd::String::npos)
? supplementaryInformation
: (supplementaryInformation.empty()
PlatformExtension::GetNamespaceSeparator()) == gd::String::npos)
? (supplementaryInformation.empty()
? ""
: extensionNamespace + supplementaryInformation)));
: extensionNamespace + supplementaryInformation)
: supplementaryInformation));
// TODO: Assert against supplementaryInformation === "emsc" (when running with
// Emscripten), and warn about a missing argument when calling addParameter.
parameters.push_back(info);
return *this;
}
gd::ExpressionMetadata& ExpressionMetadata::AddCodeOnlyParameter(
const gd::String& type, const gd::String& supplementaryInformation) {
gd::ParameterMetadata info;
info.SetType(type);
info.codeOnly = true;
info.SetExtraInfo(supplementaryInformation);
parameters.push_back(info);
gd::ExpressionMetadata &ExpressionMetadata::AddCodeOnlyParameter(
const gd::String &type, const gd::String &supplementaryInformation) {
parameters.AddNewParameter("").SetType(type).SetCodeOnly().SetExtraInfo(
supplementaryInformation);
return *this;
}
gd::ExpressionMetadata& ExpressionMetadata::SetRequiresBaseObjectCapability(
const gd::String& capability) {
requiredBaseObjectCapability = capability;

View File

@@ -193,8 +193,9 @@ class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
* \see AddParameter
*/
ExpressionMetadata &SetDefaultValue(const gd::String &defaultValue) override {
if (!parameters.empty())
parameters.back().SetDefaultValue(defaultValue);
if (parameters.GetParametersCount() > 0) {
parameters.GetInternalVector().back()->SetDefaultValue(defaultValue);
}
return *this;
};
@@ -206,8 +207,9 @@ class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
*/
ExpressionMetadata &
SetParameterLongDescription(const gd::String &longDescription) override {
if (!parameters.empty())
parameters.back().SetLongDescription(longDescription);
if (parameters.GetParametersCount() > 0) {
parameters.GetInternalVector().back()->SetLongDescription(longDescription);
}
return *this;
};
@@ -220,7 +222,9 @@ class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
*/
ExpressionMetadata &SetParameterExtraInfo(
const gd::String &extraInfo) override {
if (!parameters.empty()) parameters.back().SetExtraInfo(extraInfo);
if (parameters.GetParametersCount() > 0) {
parameters.GetInternalVector().back()->SetExtraInfo(extraInfo);
}
return *this;
}
@@ -248,19 +252,16 @@ class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
const gd::String& GetGroup() const { return group; }
const gd::String& GetSmallIconFilename() const { return smallIconFilename; }
const gd::ParameterMetadata& GetParameter(std::size_t id) const {
return parameters[id];
return parameters.GetParameter(id);
};
gd::ParameterMetadata& GetParameter(std::size_t id) {
return parameters[id];
return parameters.GetParameter(id);
};
std::size_t GetParametersCount() const { return parameters.size(); };
const std::vector<gd::ParameterMetadata>& GetParameters() const {
std::size_t GetParametersCount() const { return parameters.GetParametersCount(); };
const gd::ParameterMetadataContainer& GetParameters() const {
return parameters;
};
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
@@ -288,6 +289,8 @@ class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
/**
* \brief Erase any existing include file and add the specified include.
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
ExpressionMetadata& SetIncludeFile(
const gd::String& includeFile) override {
@@ -366,6 +369,8 @@ class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
bool isPrivate;
gd::String requiredBaseObjectCapability;
gd::String relevantContext;
gd::ParameterMetadataContainer parameters;
};
} // namespace gd

View File

@@ -9,6 +9,7 @@
#include "GDCore/CommonTools.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/ParameterMetadataContainer.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/Log.h"
@@ -68,16 +69,16 @@ InstructionMetadata& InstructionMetadata::AddParameter(
gd::ParameterMetadata::IsBehavior(type))
// Prefix with the namespace if it's not already there.
&& (supplementaryInformation.find(
PlatformExtension::GetNamespaceSeparator()) != gd::String::npos)
? supplementaryInformation
: (supplementaryInformation.empty()
PlatformExtension::GetNamespaceSeparator()) == gd::String::npos)
? (supplementaryInformation.empty()
? ""
: extensionNamespace + supplementaryInformation)));
: extensionNamespace + supplementaryInformation)
: supplementaryInformation));
// TODO: Assert against supplementaryInformation === "emsc" (when running with
// Emscripten), and warn about a missing argument when calling addParameter.
parameters.push_back(info);
parameters.AddParameter(info);
return *this;
}
@@ -88,7 +89,7 @@ InstructionMetadata& InstructionMetadata::AddCodeOnlyParameter(
info.codeOnly = true;
info.SetExtraInfo(supplementaryInformation);
parameters.push_back(info);
parameters.AddParameter(info);
return *this;
}
@@ -102,7 +103,7 @@ InstructionMetadata& InstructionMetadata::UseStandardOperatorParameters(
AddParameter(
"yesorno",
options.description.empty() ? _("New value") : options.description);
size_t valueParamIndex = parameters.size() - 1;
size_t valueParamIndex = parameters.GetParametersCount() - 1;
if (isObjectInstruction || isBehaviorInstruction) {
gd::String templateSentence = _("Set _PARAM0_ as <subject>: <value>");
@@ -127,8 +128,8 @@ InstructionMetadata& InstructionMetadata::UseStandardOperatorParameters(
options.description.empty() ? _("Value") : options.description,
options.typeExtraInfo);
size_t operatorParamIndex = parameters.size() - 2;
size_t valueParamIndex = parameters.size() - 1;
size_t operatorParamIndex = parameters.GetParametersCount() - 2;
size_t valueParamIndex = parameters.GetParametersCount() - 1;
if (isObjectInstruction || isBehaviorInstruction) {
gd::String templateSentence = _("Change <subject> of _PARAM0_: <operator> <value>");
@@ -181,8 +182,8 @@ InstructionMetadata::UseStandardRelationalOperatorParameters(
AddParameter(type,
options.description.empty() ? _("Value to compare") : options.description,
options.typeExtraInfo);
size_t operatorParamIndex = parameters.size() - 2;
size_t valueParamIndex = parameters.size() - 1;
size_t operatorParamIndex = parameters.GetParametersCount() - 2;
size_t valueParamIndex = parameters.GetParametersCount() - 1;
if (isObjectInstruction || isBehaviorInstruction) {
gd::String templateSentence = _("<subject> of _PARAM0_ <operator> <value>");

View File

@@ -14,6 +14,7 @@
#include <memory>
#include "GDCore/Events/Instruction.h"
#include "GDCore/Project/ParameterMetadataContainer.h"
#include "GDCore/String.h"
#include "ParameterMetadata.h"
#include "ParameterOptions.h"
@@ -61,12 +62,12 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
const gd::String &GetDescription() const { return description; }
const gd::String &GetSentence() const { return sentence; }
const gd::String &GetGroup() const { return group; }
ParameterMetadata &GetParameter(size_t i) { return parameters[i]; }
ParameterMetadata &GetParameter(size_t i) { return parameters.GetParameter(i); }
const ParameterMetadata &GetParameter(size_t i) const {
return parameters[i];
return parameters.GetParameter(i);
}
size_t GetParametersCount() const { return parameters.size(); }
const std::vector<ParameterMetadata> &GetParameters() const {
size_t GetParametersCount() const { return parameters.GetParametersCount(); }
const ParameterMetadataContainer &GetParameters() const {
return parameters;
}
const gd::String &GetIconFilename() const { return iconFilename; }
@@ -256,7 +257,9 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
* \see AddParameter
*/
InstructionMetadata &SetDefaultValue(const gd::String &defaultValue_) override {
if (!parameters.empty()) parameters.back().SetDefaultValue(defaultValue_);
if (parameters.GetParametersCount() > 0) {
parameters.GetInternalVector().back()->SetDefaultValue(defaultValue_);
}
return *this;
};
@@ -268,8 +271,9 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
*/
InstructionMetadata &SetParameterLongDescription(
const gd::String &longDescription) override {
if (!parameters.empty())
parameters.back().SetLongDescription(longDescription);
if (parameters.GetParametersCount() > 0) {
parameters.GetInternalVector().back()->SetLongDescription(longDescription);
}
return *this;
}
@@ -281,7 +285,9 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
* \see AddParameter
*/
InstructionMetadata &SetParameterExtraInfo(const gd::String &extraInfo) override {
if (!parameters.empty()) parameters.back().SetExtraInfo(extraInfo);
if (parameters.GetParametersCount() > 0) {
parameters.GetInternalVector().back()->SetExtraInfo(extraInfo);
}
return *this;
}
@@ -456,6 +462,15 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
return *this;
}
/**
* \brief Return the type manipulated in a standard way by the instruction.
*
* \param type "number" or "string"
*/
const gd::String &GetManipulatedType() const {
return codeExtraInformation.type;
}
/**
* If InstructionMetadata::ExtraInformation::SetManipulatedType was called
* with "number" or "string", this function will tell the code generator the
@@ -494,6 +509,8 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
/**
* \brief Erase any existing include file and add the specified include.
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
InstructionMetadata &SetIncludeFile(const gd::String &includeFile) override {
codeExtraInformation.includeFiles.clear();
@@ -549,7 +566,7 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
*/
InstructionMetadata &GetCodeExtraInformation() { return *this; }
std::vector<ParameterMetadata> parameters;
ParameterMetadataContainer parameters;
private:
gd::String fullname;

View File

@@ -142,6 +142,8 @@ public:
* \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.
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
virtual InstructionOrExpressionContainerMetadata &
SetIncludeFile(const gd::String &includeFile) = 0;

View File

@@ -454,11 +454,12 @@ const gd::ParameterMetadata* MetadataProvider::GetFunctionCallParameterMetadata(
// TODO use a badMetadata instead of a nullptr?
const gd::ParameterMetadata* parameterMetadata = nullptr;
while (metadataParameterIndex <
metadata.parameters.size()) {
if (!metadata.parameters[metadataParameterIndex]
metadata.GetParameters().GetParametersCount()) {
if (!metadata.GetParameters().GetParameter(metadataParameterIndex)
.IsCodeOnly()) {
if (visibleParameterIndex == parameterIndex) {
parameterMetadata = &metadata.parameters[metadataParameterIndex];
parameterMetadata =
&metadata.GetParameters().GetParameter(metadataParameterIndex);
}
visibleParameterIndex++;
}

View File

@@ -288,8 +288,8 @@ class GD_CORE_API MetadataProvider {
static EffectMetadata badEffectMetadata;
static gd::InstructionMetadata badInstructionMetadata;
static gd::ExpressionMetadata badExpressionMetadata;
int useless; // Useless member to avoid emscripten "must have a positive
// integer typeid pointer" runtime error.
int useless = 0; // Useless member to avoid emscripten "must have a positive
// integer typeid pointer" runtime error.
};
} // namespace gd

View File

@@ -150,6 +150,10 @@ class GD_CORE_API MultipleInstructionMetadata : public AbstractFunctionMetadata
return *this;
}
/**
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
MultipleInstructionMetadata &SetIncludeFile(const gd::String &includeFile) override {
if (expression)
expression->SetIncludeFile(includeFile);

View File

@@ -264,6 +264,8 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
* \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 object.
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
* error prone.
*/
ObjectMetadata& SetIncludeFile(const gd::String& includeFile) override;
@@ -321,6 +323,15 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
*/
bool IsRenderedIn3D() const { return isRenderedIn3D; }
ObjectMetadata &SetOpenFullEditorLabel(const gd::String& label) {
openFullEditorLabel = label;
return *this;
}
const gd::String& GetOpenFullEditorLabel() const {
return openFullEditorLabel;
}
std::map<gd::String, gd::InstructionMetadata> conditionsInfos;
std::map<gd::String, gd::InstructionMetadata> actionsInfos;
std::map<gd::String, gd::ExpressionMetadata> expressionsInfos;
@@ -342,6 +353,7 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
std::set<gd::String> defaultBehaviorTypes;
bool hidden = false;
bool isRenderedIn3D = false;
gd::String openFullEditorLabel;
std::shared_ptr<gd::ObjectConfiguration>
blueprintObject; ///< The "blueprint" object to be copied when a new

View File

@@ -4,8 +4,8 @@
* reserved. This project is released under the MIT License.
*/
#ifndef PARAMETER_METADATA_H
#define PARAMETER_METADATA_H
#pragma once
#include <map>
#include <memory>
@@ -29,6 +29,12 @@ class GD_CORE_API ParameterMetadata {
ParameterMetadata();
virtual ~ParameterMetadata(){};
/**
* \brief Return a pointer to a new ParameterMetadata constructed from
* this one.
*/
ParameterMetadata* Clone() const { return new ParameterMetadata(*this); };
/**
* \brief Return the metadata of the parameter type.
*/
@@ -248,5 +254,3 @@ class GD_CORE_API ParameterMetadata {
};
} // namespace gd
#endif // PARAMETER_METADATA_H

View File

@@ -9,6 +9,7 @@
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/ObjectsContainersList.h"
#include "GDCore/Project/ParameterMetadataContainer.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
#include "InstructionMetadata.h"
@@ -20,13 +21,13 @@ const ParameterMetadata ParameterMetadataTools::badParameterMetadata;
void ParameterMetadataTools::ParametersToObjectsContainer(
const gd::Project& project,
const std::vector<gd::ParameterMetadata>& parameters,
const ParameterMetadataContainer& parameters,
gd::ObjectsContainer& outputObjectsContainer) {
outputObjectsContainer.GetObjects().clear();
gd::String lastObjectName;
for (std::size_t i = 0; i < parameters.size(); ++i) {
const auto& parameter = parameters[i];
for (std::size_t i = 0; i < parameters.GetParametersCount(); ++i) {
const auto& parameter = parameters.GetParameter(i);
if (parameter.GetName().empty()) continue;
if (gd::ParameterMetadata::IsObject(parameter.GetType())) {
@@ -61,31 +62,34 @@ void ParameterMetadataTools::ParametersToObjectsContainer(
}
void ParameterMetadataTools::ForEachParameterMatchingSearch(
const std::vector<const std::vector<gd::ParameterMetadata>*>&
const std::vector<const ParameterMetadataContainer*>&
parametersVectorsList,
const gd::String& search,
std::function<void(const gd::ParameterMetadata&)> cb) {
for (auto it = parametersVectorsList.rbegin();
it != parametersVectorsList.rend();
++it) {
const std::vector<gd::ParameterMetadata>* parametersVector = *it;
const ParameterMetadataContainer* parametersVector = *it;
for (const auto& parameterMetadata: *parametersVector) {
if (parameterMetadata.GetName().FindCaseInsensitive(search) != gd::String::npos) cb(parameterMetadata);
for (const auto &parameterMetadata :
parametersVector->GetInternalVector()) {
if (parameterMetadata->GetName().FindCaseInsensitive(search) !=
gd::String::npos)
cb(*parameterMetadata);
}
}
}
bool ParameterMetadataTools::Has(
const std::vector<const std::vector<gd::ParameterMetadata>*>& parametersVectorsList,
const std::vector<const ParameterMetadataContainer*>& parametersVectorsList,
const gd::String& parameterName) {
for (auto it = parametersVectorsList.rbegin();
it != parametersVectorsList.rend();
++it) {
const std::vector<gd::ParameterMetadata>* parametersVector = *it;
const ParameterMetadataContainer* parametersVector = *it;
for (const auto& parameterMetadata: *parametersVector) {
if (parameterMetadata.GetName() == parameterName) return true;
for (const auto& parameterMetadata: parametersVector->GetInternalVector()) {
if (parameterMetadata->GetName() == parameterName) return true;
}
}
@@ -93,16 +97,18 @@ bool ParameterMetadataTools::Has(
}
const gd::ParameterMetadata& ParameterMetadataTools::Get(
const std::vector<const std::vector<gd::ParameterMetadata>*>&
const std::vector<const ParameterMetadataContainer*>&
parametersVectorsList,
const gd::String& parameterName) {
for (auto it = parametersVectorsList.rbegin();
it != parametersVectorsList.rend();
++it) {
const std::vector<gd::ParameterMetadata>* parametersVector = *it;
const ParameterMetadataContainer* parametersVector = *it;
for (const auto& parameterMetadata: *parametersVector) {
if (parameterMetadata.GetName() == parameterName) return parameterMetadata;
for (const auto &parameterMetadata :
parametersVector->GetInternalVector()) {
if (parameterMetadata->GetName() == parameterName)
return *parameterMetadata;
}
}
@@ -111,7 +117,7 @@ const gd::ParameterMetadata& ParameterMetadataTools::Get(
void ParameterMetadataTools::IterateOverParameters(
const std::vector<gd::Expression>& parameters,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
const ParameterMetadataContainer& parametersMetadata,
std::function<void(const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
const gd::String& lastObjectName)> fn) {
@@ -128,15 +134,17 @@ void ParameterMetadataTools::IterateOverParameters(
void ParameterMetadataTools::IterateOverParametersWithIndex(
const std::vector<gd::Expression>& parameters,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
const ParameterMetadataContainer& parametersMetadata,
std::function<void(const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
size_t parameterIndex,
const gd::String& lastObjectName)> fn) {
gd::String lastObjectName = "";
for (std::size_t pNb = 0; pNb < parametersMetadata.size(); ++pNb) {
const gd::ParameterMetadata& parameterMetadata = parametersMetadata[pNb];
const gd::Expression& parameterValue =
for (std::size_t pNb = 0; pNb < parametersMetadata.GetParametersCount();
++pNb) {
const gd::ParameterMetadata &parameterMetadata =
parametersMetadata.GetParameter(pNb);
const gd::Expression &parameterValue =
pNb < parameters.size() ? parameters[pNb].GetPlainString() : "";
const gd::Expression& parameterValueOrDefault =
parameterValue.GetPlainString().empty() && parameterMetadata.IsOptional()
@@ -179,10 +187,10 @@ void ParameterMetadataTools::IterateOverParametersWithIndex(
size_t parameterIndex = 0;
for (size_t metadataIndex = (isObjectFunction ? 1 : 0);
metadataIndex < metadata.parameters.size() &&
metadataIndex < metadata.GetParameters().GetParametersCount() &&
parameterIndex < node.parameters.size();
++metadataIndex) {
auto &parameterMetadata = metadata.parameters[metadataIndex];
auto &parameterMetadata = metadata.GetParameters().GetParameter(metadataIndex);
if (parameterMetadata.IsCodeOnly()) {
continue;
}
@@ -204,16 +212,17 @@ void ParameterMetadataTools::IterateOverParametersWithIndex(
}
size_t ParameterMetadataTools::GetObjectParameterIndexFor(
const std::vector<gd::ParameterMetadata>& parametersMetadata,
const ParameterMetadataContainer& parametersMetadata,
size_t parameterIndex) {
// By convention, parameters that require
// an object (mainly, "objectvar" and "behavior") should be placed after
// the object in the list of parameters (if possible, just after).
// Search "lastObjectName" in the codebase for other place where this
// convention is enforced.
for (std::size_t pNb = parameterIndex; pNb < parametersMetadata.size();
pNb--) {
if (gd::ParameterMetadata::IsObject(parametersMetadata[pNb].GetType())) {
for (std::size_t pNb = parameterIndex;
pNb < parametersMetadata.GetParametersCount(); pNb--) {
if (gd::ParameterMetadata::IsObject(
parametersMetadata.GetParameter(pNb).GetType())) {
return pNb;
}
}

View File

@@ -15,6 +15,7 @@ class ObjectsContainer;
class ObjectsContainersList;
class ParameterMetadata;
class Expression;
class ParameterMetadataContainer;
struct FunctionCallNode;
struct ExpressionNode;
} // namespace gd
@@ -24,20 +25,20 @@ class GD_CORE_API ParameterMetadataTools {
public:
static void ParametersToObjectsContainer(
const gd::Project& project,
const std::vector<gd::ParameterMetadata>& parameters,
const ParameterMetadataContainer& parameters,
gd::ObjectsContainer& outputObjectsContainer);
static void ForEachParameterMatchingSearch(
const std::vector<const std::vector<gd::ParameterMetadata>*>& parametersVectorsList,
const std::vector<const ParameterMetadataContainer*>& parametersVectorsList,
const gd::String& search,
std::function<void(const gd::ParameterMetadata&)> cb);
static bool Has(
const std::vector<const std::vector<gd::ParameterMetadata>*>& parametersVectorsList,
const std::vector<const ParameterMetadataContainer*>& parametersVectorsList,
const gd::String& parameterName);
static const gd::ParameterMetadata& Get(
const std::vector<const std::vector<gd::ParameterMetadata>*>& parametersVectorsList,
const std::vector<const ParameterMetadataContainer*>& parametersVectorsList,
const gd::String& parameterName);
/**
@@ -47,7 +48,7 @@ class GD_CORE_API ParameterMetadataTools {
*/
static void IterateOverParameters(
const std::vector<gd::Expression>& parameters,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
const ParameterMetadataContainer& parametersMetadata,
std::function<void(const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
const gd::String& lastObjectName)> fn);
@@ -59,7 +60,7 @@ class GD_CORE_API ParameterMetadataTools {
*/
static void IterateOverParametersWithIndex(
const std::vector<gd::Expression>& parameters,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
const ParameterMetadataContainer& parametersMetadata,
std::function<void(const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
size_t parameterIndex,
@@ -84,7 +85,7 @@ class GD_CORE_API ParameterMetadataTools {
* it's linked to.
*/
static size_t GetObjectParameterIndexFor(
const std::vector<gd::ParameterMetadata>& parametersMetadata,
const ParameterMetadataContainer& parametersMetadata,
size_t parameterIndex);
private:

View File

@@ -53,20 +53,23 @@ const gd::String &ValueTypeMetadata::GetExpressionPrimitiveValueType(
const gd::String &
ValueTypeMetadata::GetPrimitiveValueType(const gd::String &parameterType) {
if (parameterType == "variable" ||
gd::ValueTypeMetadata::IsTypeExpression("variable", parameterType)) {
return ValueTypeMetadata::variableType;
if (parameterType == "number" ||
gd::ValueTypeMetadata::IsTypeValue("number", parameterType)) {
return ValueTypeMetadata::numberType;
}
if (parameterType == "boolean" || parameterType == "yesorno" ||
parameterType == "trueorfalse") {
return ValueTypeMetadata::booleanType;
}
// These 2 types are not strings from the code generator point of view,
// but it is for event-based extensions.
if (parameterType == "key" || parameterType == "mouse") {
if (parameterType == "string" ||
gd::ValueTypeMetadata::IsTypeValue("string", parameterType)) {
return ValueTypeMetadata::stringType;
}
return GetExpressionPrimitiveValueType(parameterType);
if (parameterType == "variable" ||
gd::ValueTypeMetadata::IsTypeValue("variable", parameterType)) {
return ValueTypeMetadata::variableType;
}
if (parameterType == "boolean" ||
gd::ValueTypeMetadata::IsTypeValue("boolean", parameterType)) {
return ValueTypeMetadata::booleanType;
}
return parameterType;
}
const gd::String ValueTypeMetadata::numberValueType = "number";

View File

@@ -111,21 +111,21 @@ class GD_CORE_API ValueTypeMetadata {
* given type.
*/
bool IsNumber() const {
return gd::ValueTypeMetadata::IsTypeExpression("number", name);
return gd::ValueTypeMetadata::IsTypeValue("number", name);
}
/**
* \brief Return true if the type is a string.
*/
bool IsString() const {
return gd::ValueTypeMetadata::IsTypeExpression("string", name);
return gd::ValueTypeMetadata::IsTypeValue("string", name);
}
/**
* \brief Return true if the type is a boolean.
*/
bool IsBoolean() const {
return gd::ValueTypeMetadata::IsTypeExpression("boolean", name);
return gd::ValueTypeMetadata::IsTypeValue("boolean", name);
}
/**
@@ -135,7 +135,7 @@ class GD_CORE_API ValueTypeMetadata {
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
*/
bool IsVariable() const {
return gd::ValueTypeMetadata::IsTypeExpression("variable", name);
return gd::ValueTypeMetadata::GetPrimitiveValueType(name) == "variable";
}
/**
@@ -175,7 +175,9 @@ class GD_CORE_API ValueTypeMetadata {
}
/**
* \brief Return true if the type is an expression of the given type.
* \brief Return true if the type is an expression of the given type from the
* caller point of view.
*
* \note If you are adding a new type of parameter, also add it in the IDE (
* see EventsFunctionParametersEditor, ParameterRenderingService
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
@@ -186,6 +188,7 @@ class GD_CORE_API ValueTypeMetadata {
return parameterType == "number" || parameterType == "expression" ||
parameterType == "camera" || parameterType == "forceMultiplier";
} else if (type == "string") {
// "key" and "mouse" are not mapped her, see GetPrimitiveValueType.
return parameterType == "string" || parameterType == "layer" ||
parameterType == "color" || parameterType == "file" ||
parameterType == "stringWithSelector" ||
@@ -210,14 +213,39 @@ class GD_CORE_API ValueTypeMetadata {
parameterType == "scenevar";
} else if (type == "resource") {
return parameterType == "fontResource" ||
parameterType == "soundfile" ||
parameterType == "musicfile" ||
parameterType == "audioResource" ||
parameterType == "videoResource" ||
parameterType == "bitmapFontResource" ||
parameterType == "imageResource" ||
parameterType == "jsonResource" ||
parameterType == "tilemapResource" ||
parameterType == "tilesetResource" ||
parameterType == "model3DResource";
parameterType == "model3DResource" ||
parameterType == "atlasResource" ||
parameterType == "spineResource" ||
// Deprecated, old parameter types:
parameterType == "soundfile" ||
parameterType == "musicfile";
}
return false;
}
/**
* \brief Return true if the type is a value of the given primitive type from
* the function events point of view
*/
static bool IsTypeValue(const gd::String &type,
const gd::String &parameterType) {
if (gd::ValueTypeMetadata::IsTypeExpression(type, parameterType)) {
return true;
}
// These 2 parameter types are not strings from the outside of a function as
// the generator add quote around a text, but from the events inside of the
// function the parameter is a string.
//
// See EventsCodeGenerator::GenerateParameterCodes
if (type == "string") {
return parameterType == "key" || parameterType == "mouse";
}
return false;
}

View File

@@ -96,11 +96,11 @@ std::shared_ptr<gd::PlatformExtension> Platform::GetExtension(
std::unique_ptr<gd::ObjectConfiguration> Platform::CreateObjectConfiguration(
gd::String type) const {
if (creationFunctionTable.find(type) == creationFunctionTable.end()) {
gd::LogWarning("Tried to create an object with an unknown type: " + type
gd::LogWarning("Tried to create an object configuration with an unknown type: " + type
+ " for platform " + GetName() + "!");
type = "";
if (creationFunctionTable.find("") == creationFunctionTable.end()) {
gd::LogError("Unable to create a Base object!");
gd::LogFatalError("Unable to create a base object configuration!");
return nullptr;
}
}

View File

@@ -808,6 +808,24 @@ gd::String PlatformExtension::GetObjectFullType(const gd::String &extensionName,
return extensionName + separator + objectName;
}
gd::String PlatformExtension::GetExtensionFromFullObjectType(const gd::String& type) {
const auto separatorIndex =
type.find(PlatformExtension::GetNamespaceSeparator());
if (separatorIndex == std::string::npos) {
return "";
}
return type.substr(0, separatorIndex);
}
gd::String PlatformExtension::GetObjectNameFromFullObjectType(const gd::String& type) {
const auto separatorIndex =
type.find(PlatformExtension::GetNamespaceSeparator());
if (separatorIndex == std::string::npos) {
return "";
}
return type.substr(separatorIndex + 2);
}
PlatformExtension::PlatformExtension()
: deprecated(false), category(_("General")) {}

View File

@@ -40,8 +40,7 @@ class Object;
class ObjectConfiguration;
} // namespace gd
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()>
CreateFunPtr;
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()> CreateFunPtr;
namespace gd {
@@ -51,25 +50,25 @@ namespace gd {
*/
class GD_CORE_API CompilationInfo {
public:
CompilationInfo() : informationCompleted(false){};
virtual ~CompilationInfo(){};
CompilationInfo() {};
virtual ~CompilationInfo() {};
bool informationCompleted;
bool informationCompleted = false;
bool runtimeOnly; ///< True if the extension was compiled for a runtime use
///< only
bool runtimeOnly = false; ///< True if the extension was compiled for a
///< runtime use only
#if defined(__GNUC__)
int gccMajorVersion;
int gccMinorVersion;
int gccPatchLevel;
int gccMajorVersion = 0;
int gccMinorVersion = 0;
int gccPatchLevel = 0;
#endif
int sfmlMajorVersion;
int sfmlMinorVersion;
int sfmlMajorVersion = 0;
int sfmlMinorVersion = 0;
gd::String gdCoreVersion;
int sizeOfpInt;
int sizeOfpInt = 0;
};
struct GD_CORE_API DuplicatedInstructionOptions {
@@ -239,11 +238,12 @@ class GD_CORE_API PlatformExtension {
* \param instance The "blueprint" object to be copied when a new object is
asked for.
*/
gd::ObjectMetadata& AddObject(const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon_,
std::shared_ptr<gd::ObjectConfiguration> instance);
gd::ObjectMetadata& AddObject(
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon_,
std::shared_ptr<gd::ObjectConfiguration> instance);
/**
* \brief Declare a new events based object as being part of the extension.
@@ -253,11 +253,10 @@ class GD_CORE_API PlatformExtension {
* \param description The user friendly description of the object
* \param icon The icon of the object.
*/
gd::ObjectMetadata& AddEventsBasedObject(
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon_);
gd::ObjectMetadata& AddEventsBasedObject(const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon_);
/**
* \brief Declare a new behavior as being part of the extension.
@@ -285,22 +284,6 @@ class GD_CORE_API PlatformExtension {
std::shared_ptr<gd::Behavior> instance,
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance);
/**
* \brief Declare a new events based behavior as being part of the extension.
*
* \param name The name of the behavior
* \param fullname The user friendly name of the behavior
* \param description The user friendly description of the behavior
* \param group The behavior category label
* \param icon The icon of the behavior.
*/
gd::BehaviorMetadata& AddEventsBasedBehavior(
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& group_,
const gd::String& icon_);
/**
* \brief Declare a new effect as being part of the extension.
* \param name The internal name of the effect (also called effect type).
@@ -436,8 +419,7 @@ class GD_CORE_API PlatformExtension {
PlatformExtension& SetTags(const gd::String& csvTags) {
tags.clear();
tags = csvTags.Split(',');
for (size_t i = 0; i < tags.size(); i++)
{
for (size_t i = 0; i < tags.size(); i++) {
tags[i] = tags[i].Trim().LowerCase();
}
return *this;
@@ -650,26 +632,30 @@ class GD_CORE_API PlatformExtension {
*/
static gd::String GetNamespaceSeparator() { return "::"; }
static gd::String GetEventsFunctionFullType(const gd::String &extensionName,
const gd::String &functionName);
static gd::String GetEventsFunctionFullType(const gd::String& extensionName,
const gd::String& functionName);
static gd::String
GetBehaviorEventsFunctionFullType(const gd::String &extensionName,
const gd::String &behaviorName,
const gd::String &functionName);
static gd::String GetBehaviorEventsFunctionFullType(
const gd::String& extensionName,
const gd::String& behaviorName,
const gd::String& functionName);
static gd::String GetBehaviorFullType(const gd::String &extensionName,
const gd::String &behaviorName);
static gd::String GetBehaviorFullType(const gd::String& extensionName,
const gd::String& behaviorName);
static gd::String
GetObjectEventsFunctionFullType(const gd::String &extensionName,
const gd::String &objectName,
const gd::String &functionName);
static gd::String GetObjectEventsFunctionFullType(
const gd::String& extensionName,
const gd::String& objectName,
const gd::String& functionName);
static gd::String GetObjectFullType(const gd::String &extensionName,
const gd::String &objectName);
static gd::String GetObjectFullType(const gd::String& extensionName,
const gd::String& objectName);
private:
static gd::String GetExtensionFromFullObjectType(const gd::String& type);
static gd::String GetObjectNameFromFullObjectType(const gd::String& type);
private:
/**
* Set the namespace (the string all actions/conditions/expressions start
* with).
@@ -684,10 +670,10 @@ private:
gd::String fullname; ///< Name displayed to users in the editor.
gd::String informations; ///< Description displayed to users in the editor.
gd::String category;
gd::String author; ///< Author displayed to users in the editor.
gd::String license; ///< License name displayed to users in the editor.
bool deprecated; ///< true if the extension is deprecated and shouldn't be
///< shown in IDE.
gd::String author; ///< Author displayed to users in the editor.
gd::String license; ///< License name displayed to users in the editor.
bool deprecated; ///< true if the extension is deprecated and shouldn't be
///< shown in IDE.
gd::String helpPath; ///< The relative path to the help for this extension in
///< the documentation.
gd::String iconUrl; ///< The URL to the icon to be shown for this extension.

View File

@@ -5,6 +5,8 @@
* project is released under the MIT License.
*/
// NOLINTBEGIN
#ifndef GDCORE_PLATFORMEXTENSION_INL
#define GDCORE_PLATFORMEXTENSION_INL
@@ -36,3 +38,5 @@ gd::ObjectMetadata& PlatformExtension::AddObject(const gd::String& name,
} // namespace gd
#endif
// NOLINTEND

View File

@@ -26,12 +26,9 @@ void EventBasedBehaviorBrowser::ExposeEvents(
void EventBasedBehaviorBrowser::ExposeEvents(
gd::Project &project, gd::ArbitraryEventsWorkerWithContext &worker) const {
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
project, eventsBasedBehavior, worker);
project, eventsFunctionsExtension, eventsBasedBehavior, worker);
}
void EventBasedBehaviorBrowser::ExposeObjects(
gd::Project &project, gd::ArbitraryObjectsWorker &worker) const {}
void EventBasedBehaviorBrowser::ExposeFunctions(
gd::Project &project, gd::ArbitraryEventsFunctionsWorker &worker) const {
worker.Launch(eventsBasedBehavior.GetEventsFunctions());
@@ -43,7 +40,4 @@ void EventBasedBehaviorBrowser::ExposeEventBasedBehaviors(
worker.Launch(eventsBasedBehavior);
}
void EventBasedBehaviorBrowser::ExposeBehaviorSharedDatas(
gd::Project &project, gd::ArbitraryBehaviorSharedDataWorker &worker) const {}
} // namespace gd

View File

@@ -29,8 +29,11 @@ namespace gd {
*/
class GD_CORE_API EventBasedBehaviorBrowser : public ProjectBrowser {
public:
EventBasedBehaviorBrowser(gd::EventsBasedBehavior &eventsBasedBehavior_)
: eventsBasedBehavior(eventsBasedBehavior_) {}
EventBasedBehaviorBrowser(
const gd::EventsFunctionsExtension &eventsFunctionsExtension_,
gd::EventsBasedBehavior &eventsBasedBehavior_)
: eventsFunctionsExtension(eventsFunctionsExtension_),
eventsBasedBehavior(eventsBasedBehavior_) {}
/**
* \brief Call the specified worker on all events of the event-based
@@ -48,7 +51,7 @@ public:
* This should be the preferred way to traverse all the events of an event-based behavior.
*/
void
ExposeEvents(gd::Project &project,
ExposeEvents(gd::Project &project,
gd::ArbitraryEventsWorkerWithContext &worker) const override;
/**
@@ -64,7 +67,7 @@ public:
* \brief Do nothing.
*/
void ExposeObjects(gd::Project &project,
gd::ArbitraryObjectsWorker &worker) const override;
gd::ArbitraryObjectsWorker &worker) const override {};
/**
* \brief Call the specified worker on the event-based behavior.
@@ -77,9 +80,10 @@ public:
* \brief Do nothing.
*/
void ExposeBehaviorSharedDatas(gd::Project &project,
gd::ArbitraryBehaviorSharedDataWorker &worker) const override;
gd::ArbitraryBehaviorSharedDataWorker &worker) const override {};
private:
const gd::EventsFunctionsExtension &eventsFunctionsExtension;
gd::EventsBasedBehavior &eventsBasedBehavior;
};

View File

@@ -0,0 +1,37 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "EventBasedObjectBrowser.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Project/ArbitraryEventBasedBehaviorsWorker.h"
#include "GDCore/IDE/Project/ArbitraryEventsFunctionsWorker.h"
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/IDE/Project/ArbitraryBehaviorSharedDataWorker.h"
#include "GDCore/IDE/ProjectBrowserHelper.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
namespace gd {
void EventBasedObjectBrowser::ExposeEvents(
gd::Project &project, gd::ArbitraryEventsWorker &worker) const {
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
project, eventsBasedObject, worker);
}
void EventBasedObjectBrowser::ExposeEvents(
gd::Project &project, gd::ArbitraryEventsWorkerWithContext &worker) const {
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
project, eventsFunctionsExtension, eventsBasedObject, worker);
}
void EventBasedObjectBrowser::ExposeFunctions(
gd::Project &project, gd::ArbitraryEventsFunctionsWorker &worker) const {
worker.Launch(eventsBasedObject.GetEventsFunctions());
}
} // 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 MIT License.
*/
#pragma once
#include "GDCore/IDE/ProjectBrowser.h"
namespace gd {
class Project;
class String;
class EventsFunctionsExtension;
class EventsFunction;
class EventsBasedBehavior;
class EventsBasedObject;
class ArbitraryEventsWorker;
class ArbitraryEventsWorkerWithContext;
class ArbitraryEventsFunctionsWorker;
class ArbitraryObjectsWorker;
class ArbitraryEventBasedBehaviorsWorker;
class ArbitraryBehaviorSharedDataWorker;
} // namespace gd
namespace gd {
/**
* \brief Expose event-based object contents to workers.
*/
class GD_CORE_API EventBasedObjectBrowser : public ProjectBrowser {
public:
EventBasedObjectBrowser(
const gd::EventsFunctionsExtension &eventsFunctionsExtension_,
gd::EventsBasedObject &eventsBasedObject_)
: eventsFunctionsExtension(eventsFunctionsExtension_),
eventsBasedObject(eventsBasedObject_) {}
/**
* \brief Call the specified worker on all events of the event-based
* object.
*
* This should be the preferred way to traverse all the events of an event-based object.
*/
void ExposeEvents(gd::Project &project,
gd::ArbitraryEventsWorker &worker) const override;
/**
* \brief Call the specified worker on all events of the event-based
* object.
*
* This should be the preferred way to traverse all the events of an event-based object.
*/
void
ExposeEvents(gd::Project &project,
gd::ArbitraryEventsWorkerWithContext &worker) const override;
/**
* \brief Call the specified worker on all functions of the event-based object
*
* This should be the preferred way to traverse all the function signatures
* of an event-based object.
*/
void ExposeFunctions(gd::Project &project,
gd::ArbitraryEventsFunctionsWorker &worker) const override;
/**
* \brief Do nothing.
*/
void ExposeObjects(gd::Project &project,
gd::ArbitraryObjectsWorker &worker) const override {};
/**
* @brief Do nothing.
*/
void ExposeEventBasedBehaviors(
gd::Project &project,
gd::ArbitraryEventBasedBehaviorsWorker &worker) const override {};
/**
* \brief Do nothing.
*/
void ExposeBehaviorSharedDatas(gd::Project &project,
gd::ArbitraryBehaviorSharedDataWorker &worker) const override {};
private:
const gd::EventsFunctionsExtension &eventsFunctionsExtension;
gd::EventsBasedObject &eventsBasedObject;
};
} // namespace gd

View File

@@ -14,29 +14,27 @@
#include "GDCore/Events/Expression.h"
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
using namespace std;
namespace gd {
ArbitraryEventsWorker::~ArbitraryEventsWorker() {}
AbstractArbitraryEventsWorker::~AbstractArbitraryEventsWorker() {}
void ArbitraryEventsWorker::VisitEventList(gd::EventsList& events) {
void AbstractArbitraryEventsWorker::VisitEventList(gd::EventsList& events) {
DoVisitEventList(events);
for (std::size_t i = 0; i < events.size();) {
if (events[i].AcceptVisitor(*this))
events.RemoveEvent(i);
else {
if (events[i].CanHaveSubEvents())
VisitEventList(events[i].GetSubEvents());
++i;
}
}
}
bool ArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
bool AbstractArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
bool shouldDelete = DoVisitEvent(event);
if (shouldDelete) return true;
@@ -55,15 +53,17 @@ bool ArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
*expressionAndMetadata.first, expressionAndMetadata.second);
}
if (!shouldDelete && event.CanHaveSubEvents()) {
VisitEventList(event.GetSubEvents());
}
return shouldDelete;
}
bool ArbitraryEventsWorker::VisitLinkEvent(gd::LinkEvent& linkEvent) {
bool AbstractArbitraryEventsWorker::VisitLinkEvent(gd::LinkEvent& linkEvent) {
return DoVisitLinkEvent(linkEvent);
}
void ArbitraryEventsWorker::VisitInstructionList(
void AbstractArbitraryEventsWorker::VisitInstructionList(
gd::InstructionsList& instructions, bool areConditions) {
DoVisitInstructionList(instructions, areConditions);
@@ -79,22 +79,19 @@ void ArbitraryEventsWorker::VisitInstructionList(
}
}
bool ArbitraryEventsWorker::VisitInstruction(gd::Instruction& instruction,
bool AbstractArbitraryEventsWorker::VisitInstruction(gd::Instruction& instruction,
bool isCondition) {
return DoVisitInstruction(instruction, isCondition);
}
bool ArbitraryEventsWorker::VisitEventExpression(gd::Expression& expression,
bool AbstractArbitraryEventsWorker::VisitEventExpression(gd::Expression& expression,
const gd::ParameterMetadata& metadata) {
return DoVisitEventExpression(expression, metadata);
}
ArbitraryEventsWorkerWithContext::~ArbitraryEventsWorkerWithContext() {}
AbstractReadOnlyArbitraryEventsWorker::~AbstractReadOnlyArbitraryEventsWorker() {}
ReadOnlyArbitraryEventsWorker::~ReadOnlyArbitraryEventsWorker() {}
void ReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events) {
void AbstractReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events) {
DoVisitEventList(events);
for (std::size_t i = 0; i < events.size(); ++i) {
@@ -109,7 +106,7 @@ void ReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events)
}
}
void ReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
void AbstractReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
DoVisitEvent(event);
const vector<const gd::InstructionsList*> conditionsVectors =
@@ -130,11 +127,11 @@ void ReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
}
}
void ReadOnlyArbitraryEventsWorker::VisitLinkEvent(const gd::LinkEvent& linkEvent) {
void AbstractReadOnlyArbitraryEventsWorker::VisitLinkEvent(const gd::LinkEvent& linkEvent) {
DoVisitLinkEvent(linkEvent);
}
void ReadOnlyArbitraryEventsWorker::VisitInstructionList(
void AbstractReadOnlyArbitraryEventsWorker::VisitInstructionList(
const gd::InstructionsList& instructions, bool areConditions) {
DoVisitInstructionList(instructions, areConditions);
@@ -150,21 +147,73 @@ void ReadOnlyArbitraryEventsWorker::VisitInstructionList(
}
}
void ReadOnlyArbitraryEventsWorker::VisitInstruction(const gd::Instruction& instruction,
void AbstractReadOnlyArbitraryEventsWorker::VisitInstruction(const gd::Instruction& instruction,
bool isCondition) {
DoVisitInstruction(instruction, isCondition);
}
void ReadOnlyArbitraryEventsWorker::VisitEventExpression(const gd::Expression& expression,
void AbstractReadOnlyArbitraryEventsWorker::VisitEventExpression(const gd::Expression& expression,
const gd::ParameterMetadata& metadata) {
DoVisitEventExpression(expression, metadata);
}
void ReadOnlyArbitraryEventsWorker::StopAnyEventIteration() {
void AbstractReadOnlyArbitraryEventsWorker::StopAnyEventIteration() {
shouldStopIteration = true;
}
ArbitraryEventsWorker::~ArbitraryEventsWorker() {}
bool ArbitraryEventsWorker::VisitEvent(gd::BaseEvent &event) {
return AbstractArbitraryEventsWorker::VisitEvent(event);
}
ArbitraryEventsWorkerWithContext::~ArbitraryEventsWorkerWithContext() {}
bool ArbitraryEventsWorkerWithContext::VisitEvent(gd::BaseEvent &event) {
if (!event.HasVariables()) {
return AbstractArbitraryEventsWorker::VisitEvent(event);
}
// Push local variables
auto newProjectScopedContainers =
ProjectScopedContainers::MakeNewProjectScopedContainersWithLocalVariables(
*currentProjectScopedContainers, event);
auto *parentProjectScopedContainers = currentProjectScopedContainers;
currentProjectScopedContainers = &newProjectScopedContainers;
bool shouldDelete = AbstractArbitraryEventsWorker::VisitEvent(event);
// Pop local variables
currentProjectScopedContainers = parentProjectScopedContainers;
return shouldDelete;
}
ReadOnlyArbitraryEventsWorker::~ReadOnlyArbitraryEventsWorker() {}
void ReadOnlyArbitraryEventsWorker::VisitEvent(
const gd::BaseEvent &event) {
AbstractReadOnlyArbitraryEventsWorker::VisitEvent(event);
}
ReadOnlyArbitraryEventsWorkerWithContext::~ReadOnlyArbitraryEventsWorkerWithContext() {}
void ReadOnlyArbitraryEventsWorkerWithContext::VisitEvent(
const gd::BaseEvent &event) {
if (!event.HasVariables()) {
AbstractReadOnlyArbitraryEventsWorker::VisitEvent(event);
return;
}
// Push local variables
auto newProjectScopedContainers =
ProjectScopedContainers::MakeNewProjectScopedContainersWithLocalVariables(
*currentProjectScopedContainers, event);
auto *parentProjectScopedContainers = currentProjectScopedContainers;
currentProjectScopedContainers = &newProjectScopedContainers;
AbstractReadOnlyArbitraryEventsWorker::VisitEvent(event);
// Pop local variables
currentProjectScopedContainers = parentProjectScopedContainers;
}
} // namespace gd

View File

@@ -3,8 +3,8 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_ARBITRARYEVENTSWORKER_H
#define GDCORE_ARBITRARYEVENTSWORKER_H
#pragma once
#include <map>
#include <memory>
#include <vector>
@@ -12,6 +12,7 @@
#include "GDCore/Events/EventVisitor.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/String.h"
namespace gd {
class Instruction;
class BaseEvent;
@@ -25,27 +26,24 @@ class ParameterMetadata;
namespace gd {
/**
* \brief ArbitraryEventsWorker is an abstract class used to browse events (and
* instructions) and do some work on them. Can be used to implement refactoring
* for example.
* \brief AbstractArbitraryEventsWorker is a base abstract class used to browse events (and
* instructions) and do some work on them. It must not be inherited directly.
*
* \see gd::ArbitraryEventsWorker
* \see gd::ArbitraryEventsWorkerWithContext
*
* \ingroup IDE
*/
class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
class GD_CORE_API AbstractArbitraryEventsWorker : private EventVisitor {
public:
ArbitraryEventsWorker(){};
virtual ~ArbitraryEventsWorker();
AbstractArbitraryEventsWorker(){};
virtual ~AbstractArbitraryEventsWorker();
/**
* \brief Launch the worker on the specified events list.
*/
void Launch(gd::EventsList& events) { VisitEventList(events); };
protected:
virtual bool VisitEvent(gd::BaseEvent& event) override;
void VisitEventList(gd::EventsList& events);
private:
void VisitEventList(gd::EventsList& events);
bool VisitEvent(gd::BaseEvent& event) override;
bool VisitLinkEvent(gd::LinkEvent& linkEvent) override;
void VisitInstructionList(gd::InstructionsList& instructions,
bool areConditions);
@@ -101,6 +99,31 @@ class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
}
};
/**
* \brief ArbitraryEventsWorker is an abstract class used to browse events (and
* instructions) and do some work on them. Can be used to implement refactoring
* for example.
*
* \see gd::ArbitraryEventsWorkerWithContext
*
* \ingroup IDE
*/
class GD_CORE_API ArbitraryEventsWorker : public AbstractArbitraryEventsWorker {
public:
ArbitraryEventsWorker(){};
virtual ~ArbitraryEventsWorker();
/**
* \brief Launch the worker on the specified events list.
*/
void Launch(gd::EventsList &events) {
AbstractArbitraryEventsWorker::VisitEventList(events);
};
private:
bool VisitEvent(gd::BaseEvent &event) override;
};
/**
* \brief An events worker that will know about the context (the objects
* container). Useful for workers working on expressions notably.
@@ -110,10 +133,10 @@ class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
* \ingroup IDE
*/
class GD_CORE_API ArbitraryEventsWorkerWithContext
: public ArbitraryEventsWorker {
: public AbstractArbitraryEventsWorker {
public:
ArbitraryEventsWorkerWithContext()
: projectScopedContainers(nullptr){};
: currentProjectScopedContainers(nullptr){};
virtual ~ArbitraryEventsWorkerWithContext();
/**
@@ -121,53 +144,50 @@ class GD_CORE_API ArbitraryEventsWorkerWithContext
* giving the objects container on which the events are applying to.
*/
void Launch(gd::EventsList& events,
const gd::ProjectScopedContainers& projectScopedContainers_) {
projectScopedContainers = &projectScopedContainers_;
ArbitraryEventsWorker::Launch(events);
const gd::ProjectScopedContainers& projectScopedContainers) {
currentProjectScopedContainers = &projectScopedContainers;
AbstractArbitraryEventsWorker::VisitEventList(events);
};
void Launch(gd::EventsList& events) = delete;
protected:
protected:
const gd::ProjectScopedContainers& GetProjectScopedContainers() {
// Pointers are guaranteed to be not nullptr after
// Launch was called.
return *projectScopedContainers;
return *currentProjectScopedContainers;
};
const gd::ObjectsContainersList& GetObjectsContainersList() {
// Pointers are guaranteed to be not nullptr after
// Launch was called.
return projectScopedContainers->GetObjectsContainersList();
return currentProjectScopedContainers->GetObjectsContainersList();
};
private:
const gd::ProjectScopedContainers* projectScopedContainers;
bool VisitEvent(gd::BaseEvent& event) override;
const gd::ProjectScopedContainers* currentProjectScopedContainers;
};
/**
* \brief ReadOnlyArbitraryEventsWorker is an abstract class used to browse events (and
* instructions). It can be used to implement autocompletion for example.
* instructions). It must not be inherited directly.
*
* \see gd::ReadOnlyArbitraryEventsWorker
* \see gd::ReadOnlyArbitraryEventsWorkerWithContext
*
* \ingroup IDE
*/
class GD_CORE_API ReadOnlyArbitraryEventsWorker : private ReadOnlyEventVisitor {
class GD_CORE_API AbstractReadOnlyArbitraryEventsWorker : private ReadOnlyEventVisitor {
public:
ReadOnlyArbitraryEventsWorker() : shouldStopIteration(false) {};
virtual ~ReadOnlyArbitraryEventsWorker();
/**
* \brief Launch the worker on the specified events list.
*/
void Launch(const gd::EventsList& events) { VisitEventList(events); };
AbstractReadOnlyArbitraryEventsWorker() : shouldStopIteration(false) {};
virtual ~AbstractReadOnlyArbitraryEventsWorker();
protected:
void StopAnyEventIteration() override;
virtual void VisitEvent(const gd::BaseEvent& event) override;
void VisitEventList(const gd::EventsList& events);
private:
void VisitEventList(const gd::EventsList& events);
void VisitEvent(const gd::BaseEvent& event) override;
void VisitLinkEvent(const gd::LinkEvent& linkEvent) override;
void VisitInstructionList(const gd::InstructionsList& instructions,
bool areConditions);
@@ -213,6 +233,31 @@ protected:
bool shouldStopIteration;
};
/**
* \brief ReadOnlyArbitraryEventsWorker is an abstract class used to browse events (and
* instructions). It can be used to implement autocompletion for example.
*
* \see gd::ReadOnlyArbitraryEventsWorkerWithContext
*
* \ingroup IDE
*/
class GD_CORE_API ReadOnlyArbitraryEventsWorker
: public AbstractReadOnlyArbitraryEventsWorker {
public:
ReadOnlyArbitraryEventsWorker(){};
virtual ~ReadOnlyArbitraryEventsWorker();
/**
* \brief Launch the worker on the specified events list.
*/
void Launch(const gd::EventsList &events) {
AbstractReadOnlyArbitraryEventsWorker::VisitEventList(events);
};
private:
void VisitEvent(const gd::BaseEvent &event) override;
};
/**
* \brief An events worker that will know about the context (the objects
* container). Useful for workers working on expressions notably.
@@ -222,10 +267,10 @@ protected:
* \ingroup IDE
*/
class GD_CORE_API ReadOnlyArbitraryEventsWorkerWithContext
: public ReadOnlyArbitraryEventsWorker {
: public AbstractReadOnlyArbitraryEventsWorker {
public:
ReadOnlyArbitraryEventsWorkerWithContext()
: projectScopedContainers(nullptr){};
: currentProjectScopedContainers(nullptr){};
virtual ~ReadOnlyArbitraryEventsWorkerWithContext();
/**
@@ -233,24 +278,22 @@ class GD_CORE_API ReadOnlyArbitraryEventsWorkerWithContext
* giving the objects container on which the events are applying to.
*/
void Launch(const gd::EventsList& events,
const gd::ProjectScopedContainers& projectScopedContainers_) {
projectScopedContainers = &projectScopedContainers_;
ReadOnlyArbitraryEventsWorker::Launch(events);
const gd::ProjectScopedContainers& projectScopedContainers) {
currentProjectScopedContainers = &projectScopedContainers;
AbstractReadOnlyArbitraryEventsWorker::VisitEventList(events);
};
void Launch(gd::EventsList& events) = delete;
protected:
protected:
const gd::ProjectScopedContainers& GetProjectScopedContainers() {
// Pointers are guaranteed to be not nullptr after
// Launch was called.
return *projectScopedContainers;
return *currentProjectScopedContainers;
};
private:
const gd::ProjectScopedContainers* projectScopedContainers;
void VisitEvent(const gd::BaseEvent& event) override;
const gd::ProjectScopedContainers* currentProjectScopedContainers;
};
} // namespace gd
#endif // GDCORE_ARBITRARYEVENTSWORKER_H

View File

@@ -0,0 +1,65 @@
/*
* GDevelop Core
* Copyright 2008-2024 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "BehaviorParametersFiller.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Instruction.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
namespace gd {
bool BehaviorParametersFiller::DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) {
const auto &metadata = isCondition
? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
instruction.GetParameters(), metadata.GetParameters(),
[&](const gd::ParameterMetadata &parameterMetadata,
const gd::Expression &parameterValue, size_t parameterIndex,
const gd::String &lastObjectName) {
if (parameterMetadata.GetValueTypeMetadata().IsBehavior() &&
parameterValue.GetPlainString().length() == 0) {
auto &expectedBehaviorTypeName =
parameterMetadata.GetValueTypeMetadata().GetExtraInfo();
auto &objectsContainersList =
projectScopedContainers.GetObjectsContainersList();
auto behaviorNames =
objectsContainersList.GetBehaviorsOfObject(lastObjectName, true);
gd::String foundBehaviorName = "";
for (auto &behaviorName : behaviorNames) {
auto behaviorTypeName =
objectsContainersList.GetTypeOfBehavior(behaviorName, false);
if (behaviorTypeName == expectedBehaviorTypeName) {
foundBehaviorName = behaviorName;
break;
}
}
if (!foundBehaviorName.empty()) {
instruction.SetParameter(parameterIndex,
gd::Expression(foundBehaviorName));
}
}
});
return false;
}
BehaviorParametersFiller::~BehaviorParametersFiller() {}
} // namespace gd

View File

@@ -0,0 +1,45 @@
/*
* GDevelop Core
* Copyright 2008-2024 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
#include <map>
#include <memory>
#include <vector>
namespace gd {
class Instruction;
class Platform;
class ProjectScopedContainers;
} // namespace gd
namespace gd {
/**
* \brief Fill empty behavior parameters with any behavior that matches the
* required behavior type.
*
* \ingroup IDE
*/
class GD_CORE_API BehaviorParametersFiller : public ArbitraryEventsWorker {
public:
BehaviorParametersFiller(
const gd::Platform &platform_,
const gd::ProjectScopedContainers &projectScopedContainers_)
: platform(platform_),
projectScopedContainers(projectScopedContainers_){};
virtual ~BehaviorParametersFiller();
private:
bool DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) override;
const gd::Platform &platform;
const gd::ProjectScopedContainers &projectScopedContainers;
};
} // namespace gd

View File

@@ -72,12 +72,12 @@ public:
gd::String lastObjectParameter = "";
const gd::InstructionMetadata &instrInfos =
MetadataProvider::GetActionMetadata(platform, instruction.GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].GetType()) ||
"number", instrInfos.parameters.GetParameter(pNb).GetType()) ||
ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].GetType())) {
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
auto node = instruction.GetParameter(pNb).GetRootNode();
node->Visit(*this);
}

View File

@@ -86,9 +86,11 @@ class GD_CORE_API IdentifierFinderExpressionNodeWorker
}
size_t parameterIndex = 0;
for (size_t metadataIndex = (isObjectFunction ? 1 : 0); metadataIndex < metadata.parameters.size()
&& parameterIndex < node.parameters.size(); ++metadataIndex) {
auto& parameterMetadata = metadata.parameters[metadataIndex];
for (size_t metadataIndex = (isObjectFunction ? 1 : 0);
metadataIndex < metadata.GetParameters().GetParametersCount() &&
parameterIndex < node.parameters.size();
++metadataIndex) {
auto& parameterMetadata = metadata.GetParameters().GetParameter(metadataIndex);
if (parameterMetadata.IsCodeOnly()) {
continue;
}
@@ -144,10 +146,10 @@ class GD_CORE_API IdentifierFinderEventWorker
platform, instruction.GetType())
: MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
// The parameter has the searched type...
if (instrInfos.parameters[pNb].GetType() == "identifier"
&& instrInfos.parameters[pNb].GetExtraInfo() == identifierType) {
if (instrInfos.parameters.GetParameter(pNb).GetType() == "identifier"
&& instrInfos.parameters.GetParameter(pNb).GetExtraInfo() == identifierType) {
//...remember the value of the parameter.
if (objectName.empty() || lastObjectParameter == objectName) {
results.insert(instruction.GetParameter(pNb).GetPlainString());
@@ -155,9 +157,9 @@ class GD_CORE_API IdentifierFinderEventWorker
}
// Search in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].GetType()) ||
"number", instrInfos.parameters.GetParameter(pNb).GetType()) ||
ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].GetType())) {
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
auto node = instruction.GetParameter(pNb).GetRootNode();
IdentifierFinderExpressionNodeWorker searcher(
@@ -170,7 +172,7 @@ class GD_CORE_API IdentifierFinderEventWorker
}
// Remember the value of the last "object" parameter.
else if (gd::ParameterMetadata::IsObject(
instrInfos.parameters[pNb].GetType())) {
instrInfos.parameters.GetParameter(pNb).GetType())) {
lastObjectParameter =
instruction.GetParameter(pNb).GetPlainString();
}

View File

@@ -296,7 +296,7 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
};
bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& actions,
gd::String oldName,
gd::String newName) {
@@ -305,14 +305,14 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
for (std::size_t aId = 0; aId < actions.size(); ++aId) {
const gd::InstructionMetadata& instrInfos =
MetadataProvider::GetActionMetadata(platform, actions[aId].GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
// Replace object's name in parameters
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType()) &&
if (gd::ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType()) &&
actions[aId].GetParameter(pNb).GetPlainString() == oldName)
actions[aId].SetParameter(pNb, gd::Expression(newName));
// Replace object's name in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].GetType())) {
"number", instrInfos.parameters.GetParameter(pNb).GetType())) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
@@ -322,7 +322,7 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].GetType())) {
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
@@ -347,7 +347,7 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
bool EventsRefactorer::RenameObjectInConditions(
const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& conditions,
gd::String oldName,
gd::String newName) {
@@ -357,14 +357,14 @@ bool EventsRefactorer::RenameObjectInConditions(
const gd::InstructionMetadata& instrInfos =
MetadataProvider::GetConditionMetadata(platform,
conditions[cId].GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
// Replace object's name in parameters
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType()) &&
if (gd::ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType()) &&
conditions[cId].GetParameter(pNb).GetPlainString() == oldName)
conditions[cId].SetParameter(pNb, gd::Expression(newName));
// Replace object's name in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].GetType())) {
"number", instrInfos.parameters.GetParameter(pNb).GetType())) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
@@ -374,7 +374,7 @@ bool EventsRefactorer::RenameObjectInConditions(
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].GetType())) {
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
@@ -399,7 +399,7 @@ bool EventsRefactorer::RenameObjectInConditions(
bool EventsRefactorer::RenameObjectInEventParameters(
const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::Expression& expression,
gd::ParameterMetadata parameterMetadata,
gd::String oldName,
@@ -432,7 +432,7 @@ bool EventsRefactorer::RenameObjectInEventParameters(
}
void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::EventsList& events,
gd::String oldName,
gd::String newName) {
@@ -475,7 +475,7 @@ void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
}
bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& actions,
gd::String name) {
bool somethingModified = false;
@@ -485,16 +485,16 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
const gd::InstructionMetadata& instrInfos =
MetadataProvider::GetActionMetadata(platform, actions[aId].GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
// Find object's name in parameters
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType()) &&
if (gd::ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType()) &&
actions[aId].GetParameter(pNb).GetPlainString() == name) {
deleteMe = true;
break;
}
// Find object's name in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].GetType())) {
"number", instrInfos.parameters.GetParameter(pNb).GetType())) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, projectScopedContainers, "number", *node, name)) {
@@ -504,7 +504,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
}
// Find object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].GetType())) {
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, projectScopedContainers, "string", *node, name)) {
@@ -532,7 +532,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
bool EventsRefactorer::RemoveObjectInConditions(
const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& conditions,
gd::String name) {
bool somethingModified = false;
@@ -543,16 +543,16 @@ bool EventsRefactorer::RemoveObjectInConditions(
const gd::InstructionMetadata& instrInfos =
MetadataProvider::GetConditionMetadata(platform,
conditions[cId].GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
// Find object's name in parameters
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType()) &&
if (gd::ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType()) &&
conditions[cId].GetParameter(pNb).GetPlainString() == name) {
deleteMe = true;
break;
}
// Find object's name in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].GetType())) {
"number", instrInfos.parameters.GetParameter(pNb).GetType())) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, projectScopedContainers, "number", *node, name)) {
@@ -562,7 +562,7 @@ bool EventsRefactorer::RemoveObjectInConditions(
}
// Find object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].GetType())) {
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, projectScopedContainers, "string", *node, name)) {
@@ -588,31 +588,6 @@ bool EventsRefactorer::RemoveObjectInConditions(
return somethingModified;
}
void EventsRefactorer::RemoveObjectInEvents(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::EventsList& events,
gd::String name) {
for (std::size_t i = 0; i < events.size(); ++i) {
vector<gd::InstructionsList*> conditionsVectors =
events[i].GetAllConditionsVectors();
for (std::size_t j = 0; j < conditionsVectors.size(); ++j) {
bool conditionsModified = RemoveObjectInConditions(
platform, projectScopedContainers, *conditionsVectors[j], name);
}
vector<gd::InstructionsList*> actionsVectors =
events[i].GetAllActionsVectors();
for (std::size_t j = 0; j < actionsVectors.size(); ++j) {
bool actionsModified = RemoveObjectInActions(
platform, projectScopedContainers, *actionsVectors[j], name);
}
if (events[i].CanHaveSubEvents())
RemoveObjectInEvents(
platform, projectScopedContainers, events[i].GetSubEvents(), name);
}
}
gd::String ReplaceAllOccurrencesCaseInsensitive(gd::String context,
const gd::String& from,
const gd::String& to) {

View File

@@ -3,8 +3,8 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EVENTSREFACTORER_H
#define GDCORE_EVENTSREFACTORER_H
#pragma once
#include <memory>
#include <vector>
@@ -81,19 +81,11 @@ class GD_CORE_API EventsRefactorer {
* events ).
*/
static void RenameObjectInEvents(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::EventsList& events,
gd::String oldName,
gd::String newName);
/**
* Remove all actions or conditions using an object
*/
static void RemoveObjectInEvents(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::EventsList& events,
gd::String name);
/**
* Search for a gd::String in events
*
@@ -136,7 +128,7 @@ class GD_CORE_API EventsRefactorer {
* \return true if something was modified.
*/
static bool RenameObjectInActions(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& instructions,
gd::String oldName,
gd::String newName);
@@ -148,7 +140,7 @@ class GD_CORE_API EventsRefactorer {
* \return true if something was modified.
*/
static bool RenameObjectInConditions(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& instructions,
gd::String oldName,
gd::String newName);
@@ -161,7 +153,7 @@ class GD_CORE_API EventsRefactorer {
*/
static bool RenameObjectInEventParameters(
const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::Expression& expression,
gd::ParameterMetadata parameterMetadata,
gd::String oldName,
@@ -173,7 +165,7 @@ class GD_CORE_API EventsRefactorer {
* \return true if something was modified.
*/
static bool RemoveObjectInConditions(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& conditions,
gd::String name);
@@ -183,7 +175,7 @@ class GD_CORE_API EventsRefactorer {
* \return true if something was modified.
*/
static bool RemoveObjectInActions(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& conditions,
gd::String name);
@@ -250,5 +242,3 @@ class GD_CORE_API EventsRefactorer {
};
} // namespace gd
#endif // GDCORE_EVENTSREFACTORER_H

View File

@@ -0,0 +1,103 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/EventsVariableInstructionTypeSwitcher.h"
#include <map>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
#include "GDCore/IDE/Events/ExpressionVariableNameFinder.h"
#include "GDCore/IDE/VariableInstructionSwitcher.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/Project/VariablesContainer.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
namespace gd {
VariablesContainer EventsVariableInstructionTypeSwitcher::nullVariablesContainer;
bool EventsVariableInstructionTypeSwitcher::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
const auto& metadata = isCondition
? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
instruction.GetParameters(),
metadata.GetParameters(),
[&](const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
size_t parameterIndex,
const gd::String& lastObjectName) {
const gd::String& type = parameterMetadata.GetType();
if (!gd::ParameterMetadata::IsExpression("variable", type) ||
!gd::VariableInstructionSwitcher::IsSwitchableVariableInstruction(
instruction.GetType())) {
return;
}
const auto variableName =
gd::ExpressionVariableNameFinder::GetVariableName(
*parameterValue.GetRootNode());
const gd::VariablesContainer *variablesContainer = nullptr;
if (type == "objectvar") {
const auto &objectsContainersList =
GetProjectScopedContainers().GetObjectsContainersList();
if (objectsContainersList.HasObjectOrGroupWithVariableNamed(
lastObjectName, variableName) !=
gd::ObjectsContainersList::VariableExistence::DoesNotExist) {
variablesContainer =
GetProjectScopedContainers()
.GetObjectsContainersList()
.GetObjectOrGroupVariablesContainer(lastObjectName);
}
} else {
if (GetProjectScopedContainers().GetVariablesContainersList().Has(
variableName)) {
variablesContainer =
&GetProjectScopedContainers()
.GetVariablesContainersList()
.GetVariablesContainerFromVariableName(variableName);
}
}
// Every occurrence of the variable or its children are checked.
// Ensuring that a child is actually the one with a type change would
// take more time.
if (variablesContainer == &targetVariablesContainer ||
lastObjectName == groupName) {
if (typeChangedVariableNames.find(variableName) !=
typeChangedVariableNames.end()) {
gd::VariableInstructionSwitcher::
SwitchBetweenUnifiedInstructionIfNeeded(
platform, GetProjectScopedContainers(), instruction);
}
}
});
return false;
}
EventsVariableInstructionTypeSwitcher::~EventsVariableInstructionTypeSwitcher() {}
} // namespace gd

View File

@@ -0,0 +1,68 @@
/*
* GDevelop Core
* Copyright 2008-2024 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <map>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class VariablesContainer;
class Platform;
} // namespace gd
namespace gd {
/**
* \brief Switch the types of variable instructions for a given set of
* variables.
*
* \see gd::VariableInstructionSwitcher
*
* \ingroup IDE
*/
class GD_CORE_API EventsVariableInstructionTypeSwitcher
: public ArbitraryEventsWorkerWithContext {
public:
EventsVariableInstructionTypeSwitcher(
const gd::Platform &platform_,
const std::unordered_set<gd::String> &typeChangedVariableNames_,
const gd::VariablesContainer &targetVariablesContainer_)
: platform(platform_),
typeChangedVariableNames(typeChangedVariableNames_),
targetVariablesContainer(targetVariablesContainer_), groupName(""){};
EventsVariableInstructionTypeSwitcher(
const gd::Platform &platform_,
const std::unordered_set<gd::String> &typeChangedVariableNames_,
const gd::String &groupName_)
: platform(platform_),
typeChangedVariableNames(typeChangedVariableNames_),
targetVariablesContainer(nullVariablesContainer),
groupName(groupName_){};
virtual ~EventsVariableInstructionTypeSwitcher();
private:
bool DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) override;
const gd::Platform &platform;
const gd::VariablesContainer &targetVariablesContainer;
/**
* Groups don't have VariablesContainer, so `targetVariablesContainer` will be
* pointing to `nullVariablesContainer` and the group name is use instead to
* check which instruction to modify.
*/
const gd::String groupName;
const std::unordered_set<gd::String> &typeChangedVariableNames;
static VariablesContainer nullVariablesContainer;
};
} // namespace gd

View File

@@ -20,6 +20,9 @@
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
#include "GDCore/IDE/Events/ExpressionVariableNameFinder.h"
#include "GDCore/IDE/VariableInstructionSwitcher.h"
#include "GDCore/IDE/WholeProjectRefactorer.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ProjectScopedContainers.h"
@@ -29,6 +32,8 @@
namespace gd {
VariablesContainer EventsVariableReplacer::nullVariablesContainer;
/**
* \brief Go through the nodes and rename variables,
* or signal if the instruction must be renamed if a removed variable is used.
@@ -41,22 +46,26 @@ class GD_CORE_API ExpressionVariableReplacer
ExpressionVariableReplacer(
const gd::Platform& platform_,
const gd::ProjectScopedContainers& projectScopedContainers_,
const VariablesRenamingChangesetNode& variablesRenamingChangesetRoot_,
const std::unordered_set<gd::String>& removedVariableNames_,
const gd::VariablesContainer& targetVariablesContainer_,
const std::unordered_map<gd::String, gd::String>& oldToNewVariableNames_,
const std::unordered_set<gd::String>& removedVariableNames_)
const gd::String &groupName_,
const gd::String &forcedInitialObjectName)
: hasDoneRenaming(false),
removedVariableUsed(false),
platform(platform_),
projectScopedContainers(projectScopedContainers_),
forcedInitialVariablesContainer(nullptr),
forcedVariablesContainer(nullptr),
forcedObjectName(forcedInitialObjectName),
variablesRenamingChangesetRoot(variablesRenamingChangesetRoot_),
removedVariableNames(removedVariableNames_),
targetVariablesContainer(targetVariablesContainer_),
oldToNewVariableNames(oldToNewVariableNames_),
removedVariableNames(removedVariableNames_){};
targetGroupName(groupName_){};
virtual ~ExpressionVariableReplacer(){};
void SetForcedInitialVariablesContainer(
const gd::VariablesContainer* forcedInitialVariablesContainer_) {
forcedInitialVariablesContainer = forcedInitialVariablesContainer_;
forcedVariablesContainer = forcedInitialVariablesContainer_;
}
bool HasDoneRenaming() const { return hasDoneRenaming; }
@@ -79,21 +88,30 @@ class GD_CORE_API ExpressionVariableReplacer
// The node represents a variable or an object name on which a variable
// will be accessed.
if (forcedInitialVariablesContainer) {
if (forcedVariablesContainer) {
const gd::String oldVariableName = node.name;
PushVariablesRenamingChangesetRoot();
// A scope was forced. Honor it: it means this node represents a variable
// of the forced variables container.
if (forcedInitialVariablesContainer == &targetVariablesContainer) {
if (forcedVariablesContainer == &targetVariablesContainer ||
IsTargetingObjectGroup(forcedObjectName)) {
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
}
if (node.child) node.child->Visit(*this);
if (node.child) {
bool hasBeenPushed =
PushVariablesRenamingChangesetNodeForVariable(oldVariableName);
node.child->Visit(*this);
PopVariablesRenamingChangesetNode(hasBeenPushed);
}
PopVariablesRenamingChangesetNode(true);
return;
}
// Match the potential *new* name of the variable, because refactorings are
// done after changes in the variables container.
projectScopedContainers.MatchIdentifierWithName<void>(
GetPotentialNewName(node.name),
node.name,
[&]() {
// This represents an object.
// Remember the object name.
@@ -103,14 +121,21 @@ class GD_CORE_API ExpressionVariableReplacer
},
[&]() {
// This is a variable.
if (projectScopedContainers.GetVariablesContainersList()
.HasVariablesContainer(targetVariablesContainer)) {
if (&projectScopedContainers.GetVariablesContainersList()
.GetVariablesContainerFromVariableName(node.name) ==
&targetVariablesContainer) {
// The node represents a variable, that can come from the target
// (because the target is in the scope), replace or remove it:
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
PushVariablesRenamingChangesetRoot();
RenameVariableAndVisitChild(node.name, node.child.get());
PopVariablesRenamingChangesetNode(true);
} else {
if (node.child) {
PushVariablesRenamingChangesetNodeForIgnoredVariables();
node.child->Visit(*this);
PopVariablesRenamingChangesetNode(true);
}
}
if (node.child) node.child->Visit(*this);
},
[&]() {
// This is a property.
@@ -121,14 +146,7 @@ class GD_CORE_API ExpressionVariableReplacer
if (node.child) node.child->Visit(*this);
},
[&]() {
// This is something else - potentially a deleted variable.
if (projectScopedContainers.GetVariablesContainersList()
.HasVariablesContainer(targetVariablesContainer)) {
// The node represents a variable, that can come from the target
// (because the target is in the scope), replace or remove it:
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
}
// This is something else.
if (node.child) node.child->Visit(*this);
});
}
@@ -136,25 +154,50 @@ class GD_CORE_API ExpressionVariableReplacer
auto& objectsContainersList =
projectScopedContainers.GetObjectsContainersList();
if (!objectNameToUseForVariableAccessor.empty()) {
// This is always true because MatchIdentifierWithName is used to get
// objectNameToUseForVariableAccessor.
if (objectsContainersList.HasObjectOrGroupVariablesContainer(
objectNameToUseForVariableAccessor, targetVariablesContainer)) {
objectNameToUseForVariableAccessor, targetVariablesContainer) ||
IsTargetingObjectGroup(objectNameToUseForVariableAccessor)) {
objectNameToUseForVariableAccessor = "";
// The node represents an object variable, and this object variables are
// the target. Do the replacement or removals:
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
PushVariablesRenamingChangesetRoot();
RenameVariableAndVisitChild(node.name, node.child.get());
PopVariablesRenamingChangesetNode(true);
}
} else {
RenameVariableAndVisitChild(node.name, node.child.get());
}
objectNameToUseForVariableAccessor = "";
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
objectNameToUseForVariableAccessor = "";
// TODO Literal expressions could be checked to handle renaming in
// `expression` and in `child`.
node.expression->Visit(*this);
if (node.child) node.child->Visit(*this);
if (node.child) {
PushVariablesRenamingChangesetNodeForIgnoredVariables();
node.child->Visit(*this);
PopVariablesRenamingChangesetNode(true);
}
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
void OnVisitIdentifierNode(IdentifierNode &node) override {
auto renameVariableAndChild = [this, &node]() {
PushVariablesRenamingChangesetRoot();
const gd::String oldVariableName = node.identifierName;
RenameOrRemoveVariableOfTargetVariableContainer(node.identifierName);
if (!node.childIdentifierName.empty()) {
bool hasBeenPushed =
PushVariablesRenamingChangesetNodeForVariable(oldVariableName);
RenameOrRemoveVariableOfTargetVariableContainer(
node.childIdentifierName);
PopVariablesRenamingChangesetNode(hasBeenPushed);
}
PopVariablesRenamingChangesetNode(true);
};
auto& objectsContainersList =
projectScopedContainers.GetObjectsContainersList();
@@ -162,11 +205,12 @@ class GD_CORE_API ExpressionVariableReplacer
// (and if it's a variable reference or a value does not have any importance
// here).
if (forcedInitialVariablesContainer) {
if (forcedVariablesContainer) {
// A scope was forced. Honor it: it means this node represents a variable
// of the forced variables container.
if (forcedInitialVariablesContainer == &targetVariablesContainer) {
RenameOrRemoveVariableOfTargetVariableContainer(node.identifierName);
if (forcedVariablesContainer == &targetVariablesContainer ||
IsTargetingObjectGroup(forcedObjectName)) {
renameVariableAndChild();
}
return;
}
@@ -174,25 +218,28 @@ class GD_CORE_API ExpressionVariableReplacer
// Match the potential *new* name of the variable, because refactorings are
// done after changes in the variables container.
projectScopedContainers.MatchIdentifierWithName<void>(
GetPotentialNewName(node.identifierName),
node.identifierName,
[&]() {
// This represents an object.
if (objectsContainersList.HasObjectOrGroupVariablesContainer(
node.identifierName, targetVariablesContainer)) {
node.identifierName, targetVariablesContainer) ||
IsTargetingObjectGroup(node.identifierName)) {
// The node represents an object variable, and this object variables
// are the target. Do the replacement or removals:
PushVariablesRenamingChangesetRoot();
RenameOrRemoveVariableOfTargetVariableContainer(
node.childIdentifierName);
PopVariablesRenamingChangesetNode(true);
}
},
[&]() {
// This is a variable.
if (projectScopedContainers.GetVariablesContainersList()
.HasVariablesContainer(targetVariablesContainer)) {
if (&projectScopedContainers.GetVariablesContainersList()
.GetVariablesContainerFromVariableName(
node.identifierName) == &targetVariablesContainer) {
// The node represents a variable, that can come from the target
// (because the target is in the scope), replace or remove it:
RenameOrRemoveVariableOfTargetVariableContainer(
node.identifierName);
renameVariableAndChild();
}
},
[&]() {
@@ -202,14 +249,7 @@ class GD_CORE_API ExpressionVariableReplacer
// This is a parameter.
},
[&]() {
// This is something else - potentially a deleted variable.
if (projectScopedContainers.GetVariablesContainersList()
.HasVariablesContainer(targetVariablesContainer)) {
// The node represents a variable, that can come from the target
// (because the target is in the scope), replace or remove it:
RenameOrRemoveVariableOfTargetVariableContainer(
node.identifierName);
}
// This is something else.
});
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
@@ -231,31 +271,33 @@ class GD_CORE_API ExpressionVariableReplacer
// force the "scope" at which starts the evalution of variables.
if (parameterMetadata && parameterMetadata->GetValueTypeMetadata()
.IsLegacyPreScopedVariable()) {
const gd::VariablesContainer* oldForcedInitialVariablesContainer =
forcedInitialVariablesContainer;
const gd::VariablesContainer *oldForcedVariablesContainer =
forcedVariablesContainer;
const gd::String &oldForcedObjectName = forcedObjectName;
forcedInitialVariablesContainer = nullptr;
forcedVariablesContainer = nullptr;
forcedObjectName = "";
if (parameterMetadata->GetType() == "globalvar") {
forcedInitialVariablesContainer =
forcedVariablesContainer =
projectScopedContainers.GetVariablesContainersList()
.GetTopMostVariablesContainer();
} else if (parameterMetadata->GetType() == "scenevar") {
forcedInitialVariablesContainer =
forcedVariablesContainer =
projectScopedContainers.GetVariablesContainersList()
.GetBottomMostVariablesContainer();
} else if (parameterMetadata->GetType() == "objectvar") {
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
platform,
projectScopedContainers.GetObjectsContainersList(),
node.objectName,
*node.parameters[parameterIndex].get());
forcedInitialVariablesContainer =
platform, projectScopedContainers.GetObjectsContainersList(),
node.objectName, *node.parameters[parameterIndex].get());
forcedVariablesContainer =
projectScopedContainers.GetObjectsContainersList()
.GetObjectOrGroupVariablesContainer(objectName);
forcedObjectName = objectName;
}
node.parameters[parameterIndex]->Visit(*this);
forcedInitialVariablesContainer = oldForcedInitialVariablesContainer;
forcedVariablesContainer = oldForcedVariablesContainer;
forcedObjectName = oldForcedObjectName;
} else {
// For any other parameter, there is no special treatment being needed.
node.parameters[parameterIndex]->Visit(*this);
@@ -268,19 +310,28 @@ class GD_CORE_API ExpressionVariableReplacer
bool hasDoneRenaming;
bool removedVariableUsed;
const gd::String& GetPotentialNewName(const gd::String& oldName) {
return oldToNewVariableNames.count(oldName) >= 1
? oldToNewVariableNames.find(oldName)->second
: oldName;
bool IsTargetingObjectGroup(const gd::String &objectGroupName) {
return !targetGroupName.empty() && objectGroupName == targetGroupName;
}
bool RenameOrRemoveVariableOfTargetVariableContainer(
gd::String& variableName) {
const auto *currentVariablesRenamingChangesetNode =
GetCurrentVariablesRenamingChangesetNode();
if (!currentVariablesRenamingChangesetNode) {
return false;
}
const auto &oldToNewVariableNames =
currentVariablesRenamingChangesetNode->oldToNewVariableNames;
if (oldToNewVariableNames.count(variableName) >= 1) {
variableName = oldToNewVariableNames.find(variableName)->second;
hasDoneRenaming = true;
return true;
} else if (removedVariableNames.count(variableName) >= 1) {
} else if (
// Only the root variable is checked for removing.
currentVariablesRenamingChangesetNode ==
&variablesRenamingChangesetRoot &&
removedVariableNames.count(variableName) >= 1) {
removedVariableUsed = true;
return true;
}
@@ -288,24 +339,88 @@ class GD_CORE_API ExpressionVariableReplacer
return false; // Nothing was changed or done.
}
void RenameVariableAndVisitChild(gd::String &variableName,
ExpressionNode *childNode) {
// `variableName` is modified by
// `RenameOrRemoveVariableOfTargetVariableContainer`.
const gd::String oldVariableName = variableName;
RenameOrRemoveVariableOfTargetVariableContainer(variableName);
if (childNode) {
bool hasBeenPushed =
PushVariablesRenamingChangesetNodeForVariable(oldVariableName);
childNode->Visit(*this);
PopVariablesRenamingChangesetNode(hasBeenPushed);
}
}
void PushVariablesRenamingChangesetRoot() {
variablesRenamingChangesetNodeStack.push_back(&variablesRenamingChangesetRoot);
}
void PushVariablesRenamingChangesetNodeForIgnoredVariables() {
variablesRenamingChangesetNodeStack.push_back(nullptr);
}
const gd::VariablesRenamingChangesetNode *GetCurrentVariablesRenamingChangesetNode() {
return variablesRenamingChangesetNodeStack.size() == 0 ?
&variablesRenamingChangesetRoot :
variablesRenamingChangesetNodeStack
[variablesRenamingChangesetNodeStack.size() - 1];
}
bool PushVariablesRenamingChangesetNodeForVariable(const gd::String& variableName) {
const auto *currentVariablesRenamingChangesetNode = GetCurrentVariablesRenamingChangesetNode();
if (!currentVariablesRenamingChangesetNode) {
// There were already no more change on a parent.
return false;
}
const auto &childVariablesRenamingChangesetNodeItr =
currentVariablesRenamingChangesetNode->modifiedVariables.find(
variableName);
if (childVariablesRenamingChangesetNodeItr ==
currentVariablesRenamingChangesetNode->modifiedVariables.end()) {
// There is no more change on the current variable child.
variablesRenamingChangesetNodeStack.push_back(nullptr);
}
else {
variablesRenamingChangesetNodeStack.push_back(
childVariablesRenamingChangesetNodeItr->second.get());
}
return true;
}
void PopVariablesRenamingChangesetNode(bool hasBeenPushed) {
if (hasBeenPushed) {
variablesRenamingChangesetNodeStack.pop_back();
}
}
// Scope:
const gd::Platform& platform;
const gd::ProjectScopedContainers& projectScopedContainers;
const gd::VariablesContainer* forcedInitialVariablesContainer;
const gd::VariablesContainer* forcedVariablesContainer;
gd::String forcedObjectName;
// Renaming or removing to do:
const gd::VariablesContainer& targetVariablesContainer;
const std::unordered_map<gd::String, gd::String>& oldToNewVariableNames;
/**
* Groups don't have VariablesContainer, so `targetVariablesContainer` will be
* pointing to `nullVariablesContainer` and the group name is use instead to
* check which variable accesses to modify in expressions.
*/
const gd::String& targetGroupName;
const VariablesRenamingChangesetNode &variablesRenamingChangesetRoot;
const std::unordered_set<gd::String>& removedVariableNames;
gd::String objectNameToUseForVariableAccessor;
std::vector<const VariablesRenamingChangesetNode*> variablesRenamingChangesetNodeStack;
};
const gd::VariablesContainer*
EventsVariableReplacer::FindForcedVariablesContainerIfAny(
const gd::String& type, const gd::String& lastObjectName) {
// Handle legacy pre-scoped variable parameters: in this case, we
// force the "scope" at which starts the evalution of variables.
// force the "scope" at which starts the evaluation of variables.
if (type == "objectvar") {
return GetProjectScopedContainers()
.GetObjectsContainersList()
@@ -350,9 +465,11 @@ bool EventsVariableReplacer::DoVisitInstruction(gd::Instruction& instruction,
if (node) {
ExpressionVariableReplacer renamer(platform,
GetProjectScopedContainers(),
variablesRenamingChangesetRoot,
removedVariableNames,
targetVariablesContainer,
oldToNewVariableNames,
removedVariableNames);
targetGroupName,
type == "objectvar" ? lastObjectName : "");
renamer.SetForcedInitialVariablesContainer(
FindForcedVariablesContainerIfAny(type, lastObjectName));
node->Visit(renamer);
@@ -382,9 +499,11 @@ bool EventsVariableReplacer::DoVisitEventExpression(
if (node) {
ExpressionVariableReplacer renamer(platform,
GetProjectScopedContainers(),
variablesRenamingChangesetRoot,
removedVariableNames,
targetVariablesContainer,
oldToNewVariableNames,
removedVariableNames);
targetGroupName,
"");
renamer.SetForcedInitialVariablesContainer(
FindForcedVariablesContainerIfAny(type, ""));
node->Visit(renamer);

View File

@@ -4,6 +4,7 @@
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <map>
#include <memory>
#include <unordered_map>
@@ -12,11 +13,13 @@
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class BaseEvent;
class VariablesContainer;
class EventsList;
class Platform;
struct VariablesRenamingChangesetNode;
} // namespace gd
namespace gd {
@@ -32,13 +35,24 @@ class GD_CORE_API EventsVariableReplacer
public:
EventsVariableReplacer(
const gd::Platform &platform_,
const gd::VariablesContainer &targetVariablesContainer_,
const std::unordered_map<gd::String, gd::String> &oldToNewVariableNames_,
const std::unordered_set<gd::String> &removedVariableNames_)
const VariablesRenamingChangesetNode &variablesRenamingChangesetRoot_,
const std::unordered_set<gd::String> &removedVariableNames_,
const gd::VariablesContainer &targetVariablesContainer_)
: platform(platform_),
variablesRenamingChangesetRoot(variablesRenamingChangesetRoot_),
removedVariableNames(removedVariableNames_),
targetVariablesContainer(targetVariablesContainer_),
oldToNewVariableNames(oldToNewVariableNames_),
removedVariableNames(removedVariableNames_){};
targetGroupName("") {};
EventsVariableReplacer(
const gd::Platform &platform_,
const VariablesRenamingChangesetNode &variablesRenamingChangesetRoot_,
const std::unordered_set<gd::String> &removedVariableNames_,
const gd::String &targetGroupName_)
: platform(platform_),
variablesRenamingChangesetRoot(variablesRenamingChangesetRoot_),
removedVariableNames(removedVariableNames_),
targetVariablesContainer(nullVariablesContainer),
targetGroupName(targetGroupName_) {};
virtual ~EventsVariableReplacer();
private:
@@ -52,9 +66,16 @@ class GD_CORE_API EventsVariableReplacer
const gd::Platform &platform;
const gd::VariablesContainer &targetVariablesContainer;
gd::String objectName;
const std::unordered_map<gd::String, gd::String> &oldToNewVariableNames;
/**
* Groups don't have VariablesContainer, so `targetVariablesContainer` will be
* pointing to `nullVariablesContainer` and the group name is use instead to
* check which variable accesses to modify in expressions.
*/
const gd::String targetGroupName;
const VariablesRenamingChangesetNode &variablesRenamingChangesetRoot;
const std::unordered_set<gd::String> &removedVariableNames;
static VariablesContainer nullVariablesContainer;
};
} // namespace gd

View File

@@ -93,9 +93,11 @@ class GD_CORE_API VariableFinderExpressionNodeWorker
}
size_t parameterIndex = 0;
for (size_t metadataIndex = (isObjectFunction ? 1 : 0); metadataIndex < metadata.parameters.size()
&& parameterIndex < node.parameters.size(); ++metadataIndex) {
auto& parameterMetadata = metadata.parameters[metadataIndex];
for (size_t metadataIndex = (isObjectFunction ? 1 : 0);
metadataIndex < metadata.GetParameters().GetParametersCount() &&
parameterIndex < node.parameters.size();
++metadataIndex) {
auto& parameterMetadata = metadata.GetParameters().GetParameter(metadataIndex);
if (parameterMetadata.IsCodeOnly()) {
continue;
}
@@ -150,18 +152,18 @@ class GD_CORE_API VariableFinderEventWorker
platform, instruction.GetType())
: MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
// The parameter has the searched type...
if (instrInfos.parameters[pNb].GetType() == parameterType) {
if (instrInfos.parameters.GetParameter(pNb).GetType() == parameterType) {
//...remember the value of the parameter.
if (objectName.empty() || lastObjectParameter == objectName)
results.insert(instruction.GetParameter(pNb).GetPlainString());
}
// Search in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].GetType()) ||
"number", instrInfos.parameters.GetParameter(pNb).GetType()) ||
ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].GetType())) {
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
auto node = instruction.GetParameter(pNb).GetRootNode();
VariableFinderExpressionNodeWorker searcher(
@@ -174,7 +176,7 @@ class GD_CORE_API VariableFinderEventWorker
}
// Remember the value of the last "object" parameter.
else if (gd::ParameterMetadata::IsObject(
instrInfos.parameters[pNb].GetType())) {
instrInfos.parameters.GetParameter(pNb).GetType())) {
lastObjectParameter =
instruction.GetParameter(pNb).GetPlainString();
}
@@ -229,7 +231,7 @@ std::set<gd::String> EventsVariablesFinder::FindAllObjectVariables(
const gd::Platform& platform,
const gd::Project& project,
const gd::Layout& layout,
const gd::Object& object) {
const gd::String& objectName) {
std::set<gd::String> results;
FindArgumentsInEventsAndDependencies(
@@ -238,7 +240,7 @@ std::set<gd::String> EventsVariablesFinder::FindAllObjectVariables(
project,
layout,
"objectvar",
object.GetName());
objectName);
return results;
}

View File

@@ -63,14 +63,14 @@ class EventsVariablesFinder {
*
* \param project The project
* \param layout The layout to use.
* \param object The object to be scanned
* \param objectName The name of the object to be scanned
* \return A std::set containing the names of all object variables used.
*/
static std::set<gd::String> FindAllObjectVariables(
const gd::Platform& platform,
const gd::Project& project,
const gd::Layout& layout,
const gd::Object& object);
const gd::String& objectName);
private:

View File

@@ -3,8 +3,7 @@
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
#define GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
#pragma once
#include <memory>
#include <vector>
@@ -20,7 +19,7 @@
#include "GDCore/IDE/Events/ExpressionNodeLocationFinder.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
#include "GDCore/IDE/Events/ExpressionVariableParentFinder.h"
#include "GDCore/IDE/Events/ExpressionVariablePathFinder.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/Project/Variable.h"
@@ -147,6 +146,19 @@ struct GD_CORE_API ExpressionCompletionDescription {
return *this;
}
/**
* \brief Return the scope of the variable, for a variable completion.
*/
gd::VariablesContainer::SourceType GetVariableScope() const {
return variableScope;
}
ExpressionCompletionDescription &
SetVariableScope(gd::VariablesContainer::SourceType variableScope_) {
variableScope = variableScope_;
return *this;
}
/**
* \brief Return the prefix that must be completed.
*/
@@ -315,6 +327,7 @@ struct GD_CORE_API ExpressionCompletionDescription {
size_t replacementEndPosition_)
: completionKind(completionKind_),
variableType(gd::Variable::Number),
variableScope(gd::VariablesContainer::Unknown),
replacementStartPosition(replacementStartPosition_),
replacementEndPosition(replacementEndPosition_),
isExact(false),
@@ -324,18 +337,19 @@ struct GD_CORE_API ExpressionCompletionDescription {
private:
CompletionKind completionKind;
gd::Variable::Type variableType;
gd::Variable::Type variableType = gd::Variable::Unknown;
gd::VariablesContainer::SourceType variableScope = gd::VariablesContainer::Unknown;
gd::String type;
gd::String prefix;
gd::String completion;
size_t replacementStartPosition;
size_t replacementEndPosition;
size_t replacementStartPosition = 0;
size_t replacementEndPosition = 0;
gd::String objectName;
gd::String behaviorName;
bool isExact;
bool isLastParameter;
const gd::ParameterMetadata* parameterMetadata;
const gd::ObjectConfiguration* objectConfiguration;
bool isExact = false;
bool isLastParameter = false;
const gd::ParameterMetadata* parameterMetadata = &badParameterMetadata;
const gd::ObjectConfiguration* objectConfiguration = &badObjectConfiguration;
static const gd::ParameterMetadata badParameterMetadata;
static const gd::ObjectConfiguration badObjectConfiguration;
@@ -449,11 +463,15 @@ class GD_CORE_API ExpressionCompletionFinder
MetadataProvider::GetFunctionCallMetadata(
platform, objectsContainersList, *functionCall);
const gd::ParameterMetadata* parameterMetadata = nullptr;
while (metadataParameterIndex < metadata.parameters.size()) {
if (!metadata.parameters[metadataParameterIndex].IsCodeOnly()) {
const gd::ParameterMetadata *parameterMetadata = nullptr;
while (metadataParameterIndex <
metadata.GetParameters().GetParametersCount()) {
if (!metadata.GetParameters()
.GetParameter(metadataParameterIndex)
.IsCodeOnly()) {
if (visibleParameterIndex == parameterIndex) {
parameterMetadata = &metadata.parameters[metadataParameterIndex];
parameterMetadata =
&metadata.GetParameters().GetParameter(metadataParameterIndex);
}
visibleParameterIndex++;
}
@@ -525,7 +543,7 @@ class GD_CORE_API ExpressionCompletionFinder
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
VariableAndItsParent variableAndItsParent =
gd::ExpressionVariableParentFinder::GetLastParentOfNode(
gd::ExpressionVariablePathFinder::GetLastParentOfNode(
platform, projectScopedContainers, node);
// If no child, we're at the end of a variable (like `GrandChild` in
@@ -666,7 +684,7 @@ class GD_CORE_API ExpressionCompletionFinder
[&]() {
// This is a variable.
VariableAndItsParent variableAndItsParent =
gd::ExpressionVariableParentFinder::GetLastParentOfNode(
gd::ExpressionVariablePathFinder::GetLastParentOfNode(
platform, projectScopedContainers, node);
AddCompletionsForChildrenVariablesOf(
@@ -933,6 +951,7 @@ class GD_CORE_API ExpressionCompletionFinder
location.GetEndPosition());
description.SetCompletion(variableName);
description.SetVariableType(variable.GetType());
description.SetVariableScope(variablesContainer.GetSourceType());
completions.push_back(description);
if (eagerlyCompleteIfExactMatch && variableName == search) {
@@ -958,6 +977,7 @@ class GD_CORE_API ExpressionCompletionFinder
location.GetEndPosition());
description.SetCompletion(variableName);
description.SetVariableType(variable.GetType());
description.SetVariableScope(gd::VariablesContainer::Object);
completions.push_back(description);
if (eagerlyCompleteIfExactMatch && variableName == search) {
@@ -1012,6 +1032,10 @@ class GD_CORE_API ExpressionCompletionFinder
location.GetEndPosition());
description.SetCompletion(variableName);
description.SetVariableType(variable.GetType());
description.SetVariableScope(
projectScopedContainers.GetVariablesContainersList()
.GetVariablesContainerFromVariableName(variableName)
.GetSourceType());
completions.push_back(description);
if (eagerlyCompleteIfExactMatch && variableName == search) {
@@ -1060,6 +1084,10 @@ class GD_CORE_API ExpressionCompletionFinder
location.GetEndPosition());
description.SetCompletion(variableName);
description.SetVariableType(variable.GetType());
description.SetVariableScope(
projectScopedContainers.GetVariablesContainersList()
.GetVariablesContainerFromVariableName(variableName)
.GetSourceType());
completions.push_back(description);
if (eagerlyCompleteIfExactMatch && variableName == search) {
@@ -1113,5 +1141,3 @@ class GD_CORE_API ExpressionCompletionFinder
};
} // namespace gd
#endif // GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H

View File

@@ -33,8 +33,10 @@ class GD_CORE_API ExpressionNodeLocationFinder
* \brief Initialize the finder to search at the specified position.
*/
ExpressionNodeLocationFinder(size_t searchedPosition_)
: searchedPosition(searchedPosition_), foundNode(nullptr){};
virtual ~ExpressionNodeLocationFinder(){};
: searchedPosition(searchedPosition_),
foundNode(nullptr),
parentNode(nullptr) {};
virtual ~ExpressionNodeLocationFinder() {};
/**
* \brief Helper function to find the deepest node at the search position, if

View File

@@ -72,7 +72,7 @@ class GD_CORE_API ExpressionTypeFinder : public ExpressionParser2NodeWorker {
child(nullptr) {};
const gd::String &GetType() {
return gd::ParameterMetadata::GetExpressionValueType(type);
return gd::ValueTypeMetadata::GetExpressionPrimitiveValueType(type);
};
void OnVisitSubExpressionNode(SubExpressionNode& node) override {

View File

@@ -36,13 +36,15 @@ namespace {
* (by convention, 1 for object functions and 2 for behavior functions).
*/
size_t GetMinimumParametersNumber(
const std::vector<gd::ParameterMetadata>& parameters,
const gd::ParameterMetadataContainer& parameters,
size_t initialParameterIndex) {
size_t nb = 0;
for (std::size_t i = initialParameterIndex; i < parameters.size(); ++i) {
if (!parameters[i].IsOptional() && !parameters[i].codeOnly) nb++;
for (std::size_t i = initialParameterIndex;
i < parameters.GetParametersCount(); ++i) {
if (!parameters.GetParameter(i).IsOptional() &&
!parameters.GetParameter(i).IsCodeOnly())
nb++;
}
return nb;
}
@@ -51,13 +53,14 @@ size_t GetMinimumParametersNumber(
* (by convention, 1 for object functions and 2 for behavior functions).
*/
size_t GetMaximumParametersNumber(
const std::vector<gd::ParameterMetadata>& parameters,
const gd::ParameterMetadataContainer& parameters,
size_t initialParameterIndex) {
size_t nb = 0;
for (std::size_t i = initialParameterIndex; i < parameters.size(); ++i) {
if (!parameters[i].codeOnly) nb++;
for (std::size_t i = initialParameterIndex;
i < parameters.GetParametersCount(); ++i) {
if (!parameters.GetParameter(i).IsCodeOnly())
nb++;
}
return nb;
}
@@ -106,20 +109,20 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
auto variableExistence = objectsContainersList.HasObjectOrGroupWithVariableNamed(identifier.identifierName, identifier.childIdentifierName);
if (variableExistence == gd::ObjectsContainersList::DoesNotExist) {
RaiseTypeError(_("This variable does not exist on this object or group."),
identifier.childIdentifierNameLocation);
RaiseUndeclaredVariableError(_("This variable does not exist on this object or group."),
identifier.childIdentifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
return true; // We should have found a variable.
}
else if (variableExistence == gd::ObjectsContainersList::ExistsOnlyOnSomeObjectsOfTheGroup) {
RaiseTypeError(_("This variable only exists on some objects of the group. It must be declared for all objects."),
identifier.childIdentifierNameLocation);
RaiseUndeclaredVariableError(_("This variable only exists on some objects of the group. It must be declared for all objects."),
identifier.childIdentifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
return true; // We should have found a variable.
}
else if (variableExistence == gd::ObjectsContainersList::GroupIsEmpty) {
RaiseTypeError(_("This group is empty. Add an object to this group first."),
identifier.identifierNameLocation);
RaiseUndeclaredVariableError(_("This group is empty. Add an object to this group first."),
identifier.identifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
return true; // We should have found a variable.
}
@@ -166,8 +169,7 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
return true; // We found a property, even if the child is not allowed.
}
const gd::NamedPropertyDescriptor& property = projectScopedContainers
.GetPropertiesContainersList().Get(identifier.identifierName).second;
const gd::NamedPropertyDescriptor& property = propertiesContainersList.Get(identifier.identifierName).second;
if (property.GetType() == "Number") {
childType = Type::Number;
@@ -248,9 +250,10 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
if (!function.behaviorName.empty() &&
!objectsContainersList.HasBehaviorInObjectOrGroup(function.objectName,
function.behaviorName)) {
RaiseTypeError(_("This behavior is not attached to this object."),
function.behaviorNameLocation,
/*isFatal=*/false);
RaiseError(gd::ExpressionParserError::ErrorType::MissingBehavior,
_("This behavior is not attached to this object."),
function.behaviorNameLocation,
/*isFatal=*/false, function.behaviorName, function.objectName);
return returnType;
}
@@ -264,11 +267,11 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
if (function.functionName.empty()) {
RaiseError("invalid_function_name",
RaiseError(gd::ExpressionParserError::ErrorType::InvalidFunctionName,
_("Enter the name of the function to call."),
function.location);
} else {
RaiseError("invalid_function_name",
RaiseError(gd::ExpressionParserError::ErrorType::InvalidFunctionName,
_("Cannot find an expression with this name: ") +
function.functionName + "\n" +
_("Double check that you've not made any typo in the name."),
@@ -322,11 +325,11 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
// Validate parameters count
size_t minParametersCount = GetMinimumParametersNumber(
metadata.parameters,
metadata.GetParameters(),
ExpressionParser2::WrittenParametersFirstIndex(function.objectName,
function.behaviorName));
size_t maxParametersCount = GetMaximumParametersNumber(
metadata.parameters,
metadata.GetParameters(),
ExpressionParser2::WrittenParametersFirstIndex(function.objectName,
function.behaviorName));
if (function.parameters.size() < minParametersCount ||
@@ -341,13 +344,13 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
if (function.parameters.size() < minParametersCount) {
RaiseError(
"too_few_parameters",
gd::ExpressionParserError::ErrorType::TooFewParameters,
_("You have not entered enough parameters for the expression.") +
" " + expectedCountMessage,
function.location);
} else {
RaiseError(
"extra_parameter",
gd::ExpressionParserError::ErrorType::TooManyParameters,
_("This parameter was not expected by this expression. Remove it "
"or verify that you've entered the proper expression name.") +
" " + expectedCountMessage,
@@ -366,17 +369,20 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
for (int parameterIndex = 0; parameterIndex < function.parameters.size();
parameterIndex++) {
auto& parameter = function.parameters[parameterIndex];
while (metadata.GetParameters()[metadataIndex].IsCodeOnly()) {
while (metadata.GetParameters().GetParameter(metadataIndex).IsCodeOnly()) {
// The sizes are already checked above.
metadataIndex++;
}
auto& parameterMetadata = metadata.GetParameters()[metadataIndex];
auto& parameterMetadata = metadata.GetParameters().GetParameter(metadataIndex);
if (!parameterMetadata.IsOptional() ||
dynamic_cast<EmptyNode*>(parameter.get()) == nullptr) {
auto currentParentType = parentType;
parentType = StringToType(parameterMetadata.GetType());
auto parentParameterExtraInfo = currentParameterExtraInfo;
currentParameterExtraInfo = &parameterMetadata.GetExtraInfo();
parameter->Visit(*this);
currentParameterExtraInfo = parentParameterExtraInfo;
parentType = currentParentType;
const gd::String& expectedParameterType = parameterMetadata.GetType();
@@ -384,7 +390,7 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
ExpressionValidator::variableTypeString, expectedParameterType)) {
if (dynamic_cast<IdentifierNode*>(parameter.get()) == nullptr &&
dynamic_cast<VariableNode*>(parameter.get()) == nullptr) {
RaiseError("malformed_variable_parameter",
RaiseError(gd::ExpressionParserError::ErrorType::MalformedVariableParameter,
_("A variable name was expected but something else was "
"written. Enter just the name of the variable for this "
"parameter."),
@@ -392,7 +398,7 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
}
} else if (gd::ParameterMetadata::IsObject(expectedParameterType)) {
if (dynamic_cast<IdentifierNode*>(parameter.get()) == nullptr) {
RaiseError("malformed_object_parameter",
RaiseError(gd::ExpressionParserError::ErrorType::MalformedObjectParameter,
_("An object name was expected but something else was "
"written. Enter just the name of the object for this "
"parameter."),
@@ -406,7 +412,7 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
!gd::ParameterMetadata::IsExpression(
ExpressionValidator::stringTypeString,
expectedParameterType)) {
RaiseError("unknown_parameter_type",
RaiseError(gd::ExpressionParserError::ErrorType::UnknownParameterType,
_("This function is improperly set up. Reach out to the "
"extension developer or a GDevelop maintainer to fix "
"this issue"),
@@ -440,6 +446,10 @@ const gd::String& ExpressionValidator::TypeToString(Type type) {
return numberOrStringTypeString;
case Type::Variable:
return variableTypeString;
case Type::LegacyVariable:
// This function is only used to display error.
// Users don't care if it's legacy or not.
return variableTypeString;
case Type::Object:
return objectTypeString;
case Type::Empty:
@@ -466,7 +476,12 @@ ExpressionValidator::Type ExpressionValidator::StringToType(
if (type == ExpressionValidator::variableTypeString ||
gd::ParameterMetadata::IsExpression(
ExpressionValidator::variableTypeString, type)) {
return Type::Variable;
if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
return Type::LegacyVariable;
}
else {
return Type::Variable;
}
}
if (type == ExpressionValidator::objectTypeString ||
gd::ParameterMetadata::IsObject(type)) {

View File

@@ -3,8 +3,7 @@
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EXPRESSIONVALIDATOR_H
#define GDCORE_EXPRESSIONVALIDATOR_H
#pragma once
#include <memory>
#include <vector>
@@ -39,12 +38,14 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
public:
ExpressionValidator(const gd::Platform &platform_,
const gd::ProjectScopedContainers & projectScopedContainers_,
const gd::String &rootType_)
const gd::String &rootType_,
const gd::String &extraInfo_ = "")
: platform(platform_),
projectScopedContainers(projectScopedContainers_),
parentType(StringToType(gd::ParameterMetadata::GetExpressionValueType(rootType_))),
parentType(StringToType(gd::ValueTypeMetadata::GetExpressionPrimitiveValueType(rootType_))),
childType(Type::Unknown),
forbidsUsageOfBracketsBecauseParentIsObject(false) {};
forbidsUsageOfBracketsBecauseParentIsObject(false),
currentParameterExtraInfo(&extraInfo_) {};
virtual ~ExpressionValidator(){};
/**
@@ -65,7 +66,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
*
* Expressions with fatal error can't be generated.
*/
const std::vector<ExpressionParserDiagnostic*>& GetFatalErrors() {
const std::vector<ExpressionParserError*>& GetFatalErrors() {
return fatalErrors;
};
@@ -74,7 +75,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
*
* No errors means that the expression is valid.
*/
const std::vector<ExpressionParserDiagnostic*>& GetAllErrors() {
const std::vector<ExpressionParserError*>& GetAllErrors() {
return allErrors;
};
@@ -86,19 +87,21 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
void OnVisitOperatorNode(OperatorNode& node) override {
ReportAnyError(node);
// The "required" type ("parentType") will be used when visiting the first operand.
// Note that it may be refined thanks to this first operand (see later).
node.leftHandSide->Visit(*this);
const Type leftType = childType;
const Type leftType = childType; // Store the type of the first operand.
if (leftType == Type::Number) {
if (node.op == ' ') {
RaiseError("syntax_error",
RaiseError(gd::ExpressionParserError::ErrorType::SyntaxError,
"No operator found. Did you forget to enter an operator (like +, -, "
"* or /) between numbers or expressions?", node.rightHandSide->location);
}
}
else if (leftType == Type::String) {
if (node.op == ' ') {
RaiseError("syntax_error",
RaiseError(gd::ExpressionParserError::ErrorType::SyntaxError,
"You must add the operator + between texts or expressions. For "
"example: \"Your name: \" + VariableString(PlayerName).", node.rightHandSide->location);
}
@@ -113,22 +116,26 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
_("Operators (+, -, /, *) can't be used with an object name. Remove "
"the operator."),
node.rightHandSide->location);
} else if (leftType == Type::Variable) {
} else if (leftType == Type::Variable || leftType == Type::LegacyVariable) {
RaiseOperatorError(
_("Operators (+, -, /, *) can't be used in variable names. Remove "
"the operator from the variable name."),
node.rightHandSide->location);
}
parentType = leftType;
// The "required" type ("parentType") of the second operator is decided by:
// - the parent type. Unless it can (`number|string`) or should (`unknown`) be refined, then:
// - the first operand.
parentType = ShouldTypeBeRefined(parentType) ? leftType : parentType;
node.rightHandSide->Visit(*this);
const Type rightType = childType;
// The type is decided by the first operand, unless it can (`number|string`)
// or should (`unknown`) be refined, in which case we go for the right
// operand (which got visited knowing the type of the first operand, so it's
// The type of the overall operator ("childType") is decided by:
// - the parent type. Unless it can (`number|string`) or should (`unknown`) be refined, then:
// - the first operand. Unless it can (`number|string`) or should (`unknown`) be refined, then:
// - the right operand (which got visited knowing the type of the first operand, so it's
// equal or strictly more precise than the left operand).
childType = (leftType == Type::Unknown || leftType == Type::NumberOrString) ? leftType : rightType;
childType = ShouldTypeBeRefined(parentType) ? (ShouldTypeBeRefined(leftType) ? leftType : rightType) : parentType;
}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
ReportAnyError(node);
@@ -156,7 +163,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
_("Operators (+, -) can't be used with an object name. Remove the "
"operator."),
node.location);
} else if (rightType == Type::Variable) {
} else if (rightType == Type::Variable || rightType == Type::LegacyVariable) {
RaiseTypeError(
_("Operators (+, -) can't be used in variable names. Remove "
"the operator from the variable name."),
@@ -194,7 +201,14 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
ReportAnyError(node);
if (parentType == Type::Variable) {
childType = Type::Variable;
childType = parentType;
CheckVariableExistence(node.location, node.name);
if (node.child) {
node.child->Visit(*this);
}
} else if (parentType == Type::LegacyVariable) {
childType = parentType;
if (node.child) {
node.child->Visit(*this);
@@ -264,7 +278,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
ReportAnyError(node);
if (forbidsUsageOfBracketsBecauseParentIsObject) {
RaiseError("brackets_not_allowed_for_objects",
RaiseError(gd::ExpressionParserError::ErrorType::BracketsNotAllowedForObjects,
_("You can't use the brackets to access an object variable. "
"Use a dot followed by the variable name, like this: "
"`MyObject.MyVariable`."),
@@ -273,9 +287,14 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
forbidsUsageOfBracketsBecauseParentIsObject = false;
Type currentParentType = parentType;
Type currentChildType = childType;
parentType = Type::NumberOrString;
auto parentParameterExtraInfo = currentParameterExtraInfo;
currentParameterExtraInfo = nullptr;
node.expression->Visit(*this);
currentParameterExtraInfo = parentParameterExtraInfo;
parentType = currentParentType;
childType = currentChildType;
if (node.child) {
node.child->Visit(*this);
@@ -287,7 +306,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
if (!ValidateObjectVariableOrVariableOrProperty(node)) {
// The identifier is not a variable, so either the variable is not properly declared
// or it's a text without quotes.
RaiseTypeError(_("You must wrap your text inside double quotes "
RaiseUnknownIdentifierError(_("You must wrap your text inside double quotes "
"(example: \"Hello world\")."),
node.location);
}
@@ -295,20 +314,22 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
else if (parentType == Type::Number) {
if (!ValidateObjectVariableOrVariableOrProperty(node)) {
// The identifier is not a variable, so the variable is not properly declared.
RaiseTypeError(
_("You must enter a number."), node.location);
RaiseUnknownIdentifierError(_("You must enter a number."), node.location);
}
}
else if (parentType == Type::NumberOrString) {
if (!ValidateObjectVariableOrVariableOrProperty(node)) {
// The identifier is not a variable, so either the variable is not properly declared
// or it's a text without quotes.
RaiseTypeError(
RaiseUnknownIdentifierError(
_("You must enter a number or a text, wrapped inside double quotes (example: \"Hello world\"), or a variable name."),
node.location);
}
}
else if (parentType != Type::Object && parentType != Type::Variable) {
else if (parentType == Type::Variable) {
CheckVariableExistence(node.location, node.identifierName);
}
else if (parentType != Type::Object && parentType != Type::LegacyVariable) {
// It can't happen.
RaiseTypeError(
_("You've entered a name, but this type was expected:") + " " + TypeToString(parentType),
@@ -332,7 +353,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
} else if (parentType == Type::String) {
message = _(
"You must enter a text (between quotes) or a valid expression call.");
} else if (parentType == Type::Variable) {
} else if (parentType == Type::Variable || parentType == Type::LegacyVariable) {
message = _("You must enter a variable name.");
} else if (parentType == Type::Object) {
message = _("You must enter a valid object name.");
@@ -345,12 +366,51 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
}
private:
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, Object, Empty};
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, LegacyVariable, Object, Empty};
Type ValidateFunction(const gd::FunctionCallNode& function);
bool ValidateObjectVariableOrVariableOrProperty(const gd::IdentifierNode& identifier);
void CheckVariableExistence(const ExpressionParserLocation &location, const gd::String& name) {
if (!currentParameterExtraInfo || *currentParameterExtraInfo != "AllowUndeclaredVariable") {
projectScopedContainers.MatchIdentifierWithName<void>(
name,
[&]() {
// This represents an object.
RaiseVariableNameCollisionError(
_("This variable has the same name as an object. Consider "
"renaming one or the other."),
location, name);
},
[&]() {
// This is a variable.
},
[&]() {
// This is a property.
// This error won't happen unless the priority is changed.
RaiseVariableNameCollisionError(
_("This variable has the same name as a property. Consider "
"renaming one or the other."),
location, name);
},
[&]() {
// This is a parameter.
// This error won't happen unless the priority is changed.
RaiseVariableNameCollisionError(
_("This variable has the same name as a parameter. Consider "
"renaming one or the other."),
location, name);
},
[&]() {
// This is something else.
RaiseUndeclaredVariableError(
_("No variable with this name found."), location,
name);
});
}
}
void ReportAnyError(const ExpressionNode& node, bool isFatal = true) {
if (node.diagnostic && node.diagnostic->IsError()) {
if (node.diagnostic) {
// Syntax errors are holden by the AST nodes.
// It's fine to give pointers on them as the AST live longer than errors
// handling.
@@ -361,10 +421,13 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
}
}
void RaiseError(const gd::String &type,
const gd::String &message, const ExpressionParserLocation &location, bool isFatal = true) {
void RaiseError(gd::ExpressionParserError::ErrorType type,
const gd::String &message,
const ExpressionParserLocation &location, bool isFatal = true,
const gd::String &actualValue = "",
const gd::String &objectName = "") {
auto diagnostic = gd::make_unique<ExpressionParserError>(
type, message, location);
type, message, location, actualValue, objectName);
allErrors.push_back(diagnostic.get());
if (isFatal) {
fatalErrors.push_back(diagnostic.get());
@@ -375,14 +438,39 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
supplementalErrors.push_back(std::move(diagnostic));
}
void RaiseTypeError(
const gd::String &message, const ExpressionParserLocation &location, bool isFatal = true) {
RaiseError("type_error", message, location, isFatal);
void RaiseUnknownIdentifierError(const gd::String &message,
const ExpressionParserLocation &location) {
RaiseError(gd::ExpressionParserError::ErrorType::UnknownIdentifier, message,
location);
}
void RaiseOperatorError(
const gd::String &message, const ExpressionParserLocation &location) {
RaiseError("invalid_operator", message, location);
void RaiseUndeclaredVariableError(const gd::String &message,
const ExpressionParserLocation &location,
const gd::String &variableName,
const gd::String &objectName = "") {
RaiseError(gd::ExpressionParserError::ErrorType::UndeclaredVariable,
message, location, true, variableName, objectName);
}
void RaiseVariableNameCollisionError(const gd::String &message,
const ExpressionParserLocation &location,
const gd::String &variableName,
const gd::String &objectName = "") {
RaiseError(gd::ExpressionParserError::ErrorType::VariableNameCollision,
message, location, false, variableName, objectName);
}
void RaiseTypeError(const gd::String &message,
const ExpressionParserLocation &location,
bool isFatal = true) {
RaiseError(gd::ExpressionParserError::ErrorType::MismatchedType, message,
location, isFatal);
}
void RaiseOperatorError(const gd::String &message,
const ExpressionParserLocation &location) {
RaiseError(gd::ExpressionParserError::ErrorType::InvalidOperator, message,
location);
}
void ReadChildTypeFromVariable(gd::Variable::Type variableType) {
@@ -395,6 +483,10 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
}
}
static bool ShouldTypeBeRefined(Type type) {
return (type == Type::Unknown || type == Type::NumberOrString);
}
static Type StringToType(const gd::String &type);
static const gd::String &TypeToString(Type type);
static const gd::String unknownTypeString;
@@ -402,20 +494,21 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
static const gd::String stringTypeString;
static const gd::String numberOrStringTypeString;
static const gd::String variableTypeString;
static const gd::String legacyVariableTypeString;
static const gd::String objectTypeString;
static const gd::String identifierTypeString;
static const gd::String emptyTypeString;
std::vector<ExpressionParserDiagnostic*> fatalErrors;
std::vector<ExpressionParserDiagnostic*> allErrors;
std::vector<std::unique_ptr<ExpressionParserDiagnostic>> supplementalErrors;
std::vector<ExpressionParserError*> fatalErrors;
std::vector<ExpressionParserError*> allErrors;
std::vector<std::unique_ptr<ExpressionParserError>> supplementalErrors;
Type childType; ///< The type "discovered" down the tree and passed up.
Type parentType; ///< The type "required" by the top of the tree.
bool forbidsUsageOfBracketsBecauseParentIsObject;
const gd::String *currentParameterExtraInfo;
const gd::Platform &platform;
const gd::ProjectScopedContainers &projectScopedContainers;
};
} // namespace gd
#endif // GDCORE_EXPRESSIONVALIDATOR_H

View File

@@ -0,0 +1,55 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
namespace gd {
/**
* \brief Find the variable name from a variable expression.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionVariableNameFinder : public ExpressionParser2NodeWorker {
public:
static const gd::String GetVariableName(gd::ExpressionNode& node) {
gd::ExpressionVariableNameFinder typeFinder;
node.Visit(typeFinder);
return typeFinder.variableName;
}
virtual ~ExpressionVariableNameFinder(){};
protected:
ExpressionVariableNameFinder()
: variableName("") {};
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
void OnVisitOperatorNode(OperatorNode& node) override {}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
void OnVisitNumberNode(NumberNode& node) override {}
void OnVisitTextNode(TextNode& node) override {}
void OnVisitVariableNode(VariableNode& node) override {
variableName = node.name;
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {}
void OnVisitIdentifierNode(IdentifierNode& node) override {
variableName = node.identifierName;
}
void OnVisitEmptyNode(EmptyNode& node) override {}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {}
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {}
private:
gd::String variableName;
};
} // namespace gd

View File

@@ -1,370 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <memory>
#include <vector>
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/Project/Variable.h"
#include "GDCore/Tools/Localization.h"
namespace gd {
class Expression;
class ObjectsContainer;
class Platform;
class ParameterMetadata;
class ExpressionMetadata;
} // namespace gd
namespace gd {
/**
* \brief Contains a variables container or a variable. Useful
* to refer to the parent of a variable (which can be a VariablesContainer
* or another Variable).
*/
struct VariableAndItsParent {
const gd::VariablesContainer* parentVariablesContainer;
const gd::Variable* parentVariable;
};
/**
* \brief Find the last parent (i.e: the variables container) of a node representing a variable.
*
* Useful for completions, to know which variables can be entered in a node.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionVariableParentFinder
: public ExpressionParser2NodeWorker {
public:
static VariableAndItsParent GetLastParentOfNode(
const gd::Platform& platform,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::ExpressionNode& node) {
gd::ExpressionVariableParentFinder typeFinder(
platform, projectScopedContainers);
node.Visit(typeFinder);
return typeFinder.variableAndItsParent;
}
virtual ~ExpressionVariableParentFinder(){};
protected:
ExpressionVariableParentFinder(
const gd::Platform& platform_,
const gd::ProjectScopedContainers& projectScopedContainers_)
: platform(platform_),
projectScopedContainers(projectScopedContainers_),
variableNode(nullptr),
thisIsALegacyPrescopedVariable(false),
bailOutBecauseEmptyVariableName(false),
legacyPrescopedVariablesContainer(nullptr){};
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
void OnVisitOperatorNode(OperatorNode& node) override {}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
void OnVisitNumberNode(NumberNode& node) override {}
void OnVisitTextNode(TextNode& node) override {}
void OnVisitVariableNode(VariableNode& node) override {
if (variableNode != nullptr) {
// This is not possible
return;
}
variableNode = &node;
// Check if the parent is a function call, in which we might be dealing
// with a legacy pre-scoped variable parameter:
if (node.parent) node.parent->Visit(*this);
if (thisIsALegacyPrescopedVariable) {
// The node represents a variable name, and the variables container
// containing it was identified in the FunctionCallNode.
childVariableNames.insert(childVariableNames.begin(), node.name);
if (legacyPrescopedVariablesContainer)
variableAndItsParent = WalkUntilLastParent(
*legacyPrescopedVariablesContainer, childVariableNames);
} else {
// Otherwise, the identifier is to be interpreted as usual:
// it can be an object (on which a variable is accessed),
// or a variable.
projectScopedContainers.MatchIdentifierWithName<void>(
node.name,
[&]() {
// This is an object.
const auto* variablesContainer =
projectScopedContainers.GetObjectsContainersList()
.GetObjectOrGroupVariablesContainer(node.name);
if (variablesContainer)
variableAndItsParent =
WalkUntilLastParent(*variablesContainer, childVariableNames);
},
[&]() {
// This is a variable.
if (projectScopedContainers.GetVariablesContainersList().Has(
node.name)) {
variableAndItsParent = WalkUntilLastParent(
projectScopedContainers.GetVariablesContainersList().Get(
node.name),
childVariableNames);
}
},
[&]() {
// Ignore properties here.
// There is no support for "children" of properties.
},
[&]() {
// Ignore parameters here.
// There is no support for "children" of parameters.
},
[&]() {
// Ignore unrecognised identifiers here.
});
}
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
if (node.name.empty() && node.child) {
// A variable accessor should always have a name if it has a child (i.e: another accessor).
// While the parser may have generated an empty name,
// flag this so we avoid finding a wrong parent (and so, run the risk of giving
// wrong autocompletions).
bailOutBecauseEmptyVariableName = true;
}
childVariableNames.insert(childVariableNames.begin(), node.name);
if (node.parent) node.parent->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
if (variableNode != nullptr) {
// This is not possible
return;
}
// This node is not necessarily a variable node.
// It will be checked when visiting the FunctionCallNode, just after.
variableNode = &node;
// Check if the parent is a function call, in which we might be dealing
// with a legacy pre-scoped variable parameter:
if (node.parent) node.parent->Visit(*this);
if (thisIsALegacyPrescopedVariable) {
// The identifier represents a variable name, and the variables container
// containing it was identified in the FunctionCallNode.
if (!node.childIdentifierName.empty())
childVariableNames.insert(childVariableNames.begin(),
node.childIdentifierName);
childVariableNames.insert(childVariableNames.begin(),
node.identifierName);
if (legacyPrescopedVariablesContainer)
variableAndItsParent = WalkUntilLastParent(
*legacyPrescopedVariablesContainer, childVariableNames);
} else {
// Otherwise, the identifier is to be interpreted as usual:
// it can be an object (on which a variable is accessed),
// or a variable.
projectScopedContainers.MatchIdentifierWithName<void>(
node.identifierName,
[&]() {
// This is an object.
if (!node.childIdentifierName.empty())
childVariableNames.insert(childVariableNames.begin(),
node.childIdentifierName);
const auto* variablesContainer =
projectScopedContainers.GetObjectsContainersList()
.GetObjectOrGroupVariablesContainer(node.identifierName);
if (variablesContainer)
variableAndItsParent =
WalkUntilLastParent(*variablesContainer, childVariableNames);
},
[&]() {
// This is a variable.
if (!node.childIdentifierName.empty())
childVariableNames.insert(childVariableNames.begin(),
node.childIdentifierName);
if (projectScopedContainers.GetVariablesContainersList().Has(
node.identifierName)) {
variableAndItsParent = WalkUntilLastParent(
projectScopedContainers.GetVariablesContainersList().Get(
node.identifierName),
childVariableNames);
}
},
[&]() {
// Ignore properties here.
// There is no support for "children" of properties.
},
[&]() {
// Ignore parameters here.
// There is no support for "children" of properties.
},
[&]() {
// Ignore unrecognised identifiers here.
});
}
}
void OnVisitEmptyNode(EmptyNode& node) override {}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
// Add a child with an empty name, which will be interpreted as
// "take the first child/item of the structure/array".
childVariableNames.insert(childVariableNames.begin(), "");
if (node.parent) node.parent->Visit(*this);
}
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {
if (variableNode == nullptr) {
return;
}
int parameterIndex = -1;
for (int i = 0; i < functionCall.parameters.size(); i++) {
if (functionCall.parameters.at(i).get() == variableNode) {
parameterIndex = i;
break;
}
}
if (parameterIndex < 0) {
return;
}
const auto& objectsContainersList =
projectScopedContainers.GetObjectsContainersList();
const gd::ParameterMetadata* parameterMetadata =
MetadataProvider::GetFunctionCallParameterMetadata(
platform, objectsContainersList, functionCall, parameterIndex);
if (parameterMetadata == nullptr) return; // Unexpected
// Support for legacy pre-scoped variables:
if (parameterMetadata->GetValueTypeMetadata().IsLegacyPreScopedVariable()) {
if (parameterMetadata->GetType() == "objectvar") {
// Legacy convention where a "objectvar"
// parameter represents a variable of the object represented by the
// previous "object" parameter. The object on which the function is
// called is returned if no previous parameters are objects.
gd::String objectName = functionCall.objectName;
for (int previousIndex = parameterIndex - 1; previousIndex >= 0;
previousIndex--) {
const gd::ParameterMetadata* previousParameterMetadata =
MetadataProvider::GetFunctionCallParameterMetadata(
platform, objectsContainersList, functionCall, previousIndex);
if (previousParameterMetadata != nullptr &&
gd::ParameterMetadata::IsObject(
previousParameterMetadata->GetType())) {
auto previousParameterNode =
functionCall.parameters[previousIndex].get();
IdentifierNode* objectNode =
dynamic_cast<IdentifierNode*>(previousParameterNode);
objectName = objectNode->identifierName;
break;
}
}
legacyPrescopedVariablesContainer =
projectScopedContainers.GetObjectsContainersList()
.GetObjectOrGroupVariablesContainer(objectName);
thisIsALegacyPrescopedVariable = true;
} else if (parameterMetadata->GetType() == "scenevar") {
legacyPrescopedVariablesContainer =
projectScopedContainers.GetVariablesContainersList()
.GetBottomMostVariablesContainer();
thisIsALegacyPrescopedVariable = true;
} else if (parameterMetadata->GetType() == "globalvar") {
legacyPrescopedVariablesContainer =
projectScopedContainers.GetVariablesContainersList()
.GetTopMostVariablesContainer();
thisIsALegacyPrescopedVariable = true;
}
} else {
thisIsALegacyPrescopedVariable = false;
legacyPrescopedVariablesContainer = nullptr;
}
}
private:
VariableAndItsParent WalkUntilLastParent(
const gd::Variable& variable,
const std::vector<gd::String>& childVariableNames,
size_t startIndex = 0) {
if (bailOutBecauseEmptyVariableName)
return {}; // Do not even attempt to find the parent if we had an issue when visiting nodes.
const gd::Variable* currentVariable = &variable;
// Walk until size - 1 as we want the last parent.
for (size_t index = startIndex; index + 1 < childVariableNames.size();
++index) {
const gd::String& childName = childVariableNames[index];
if (childName.empty()) {
if (currentVariable->GetChildrenCount() == 0) {
// The array or structure is empty, we can't walk through it - there
// is no "parent".
return {};
}
if (currentVariable->GetType() == gd::Variable::Array) {
currentVariable = &currentVariable->GetAtIndex(0);
} else {
currentVariable =
currentVariable->GetAllChildren().begin()->second.get();
}
} else {
if (!currentVariable->HasChild(childName)) {
// Non existing child - there is no "parent".
return {};
}
currentVariable = &currentVariable->GetChild(childName);
}
}
// Return the last parent of the chain of variables (so not the last variable
// but the one before it).
return {.parentVariable = currentVariable};
}
VariableAndItsParent WalkUntilLastParent(
const gd::VariablesContainer& variablesContainer,
const std::vector<gd::String>& childVariableNames) {
if (bailOutBecauseEmptyVariableName)
return {}; // Do not even attempt to find the parent if we had an issue when visiting nodes.
if (childVariableNames.empty())
return {}; // There is no "parent" to the variables container itself.
const gd::String& firstChildName = *childVariableNames.begin();
const gd::Variable* variable = variablesContainer.Has(firstChildName) ?
&variablesContainer.Get(firstChildName) : nullptr;
if (childVariableNames.size() == 1 || !variable)
return {// Only one child: the parent is the variables container itself.
.parentVariablesContainer = &variablesContainer};
return WalkUntilLastParent(*variable, childVariableNames, 1);
}
gd::ExpressionNode* variableNode;
std::vector<gd::String> childVariableNames;
bool thisIsALegacyPrescopedVariable;
bool bailOutBecauseEmptyVariableName;
const gd::VariablesContainer* legacyPrescopedVariablesContainer;
VariableAndItsParent variableAndItsParent;
const gd::Platform& platform;
const gd::ProjectScopedContainers& projectScopedContainers;
};
} // namespace gd

View File

@@ -0,0 +1,195 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "ExpressionVariablePathFinder.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
namespace gd {
/**
* \brief Find the pre-scoped container of legacy variables or the object name
* from the function call node.
*/
class GD_CORE_API ExpressionLiteralFinder : public ExpressionParser2NodeWorker {
public:
virtual ~ExpressionLiteralFinder(){};
gd::String literalValue;
ExpressionLiteralFinder() : literalValue(""){};
protected:
void OnVisitSubExpressionNode(SubExpressionNode &node) override {}
void OnVisitOperatorNode(OperatorNode &node) override {}
void OnVisitUnaryOperatorNode(UnaryOperatorNode &node) override {}
void OnVisitNumberNode(NumberNode &node) override {
literalValue = node.number;
}
void OnVisitTextNode(TextNode &node) override { literalValue = node.text; }
void OnVisitVariableNode(VariableNode &node) override {}
void OnVisitVariableAccessorNode(VariableAccessorNode &node) override {}
void OnVisitIdentifierNode(IdentifierNode &node) override {}
void OnVisitEmptyNode(EmptyNode &node) override {}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode &node) override {}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode &node) override {}
void OnVisitFunctionCallNode(FunctionCallNode &functionCall) override {}
};
void ExpressionVariablePathFinder::OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode &node) {
// Try to find a literal accessor or add a child with an empty name, which
// will be interpreted as "take the first child/item of the structure/array".
gd::ExpressionLiteralFinder expressionLiteralFinder;
if (node.expression) {
node.expression->Visit(expressionLiteralFinder);
}
childVariableNames.push_back(expressionLiteralFinder.literalValue);
if (node.child && &node != lastNodeToCheck) {
node.child->Visit(*this);
}
}
/**
* \brief Find the pre-scoped container of legacy variables or the object name
* from the function call node.
*/
class GD_CORE_API ExpressionVariableContextFinder
: public ExpressionParser2NodeWorker {
public:
virtual ~ExpressionVariableContextFinder(){};
gd::String objectName;
gd::String parameterType;
gd::ExpressionNode* variableNode;
ExpressionVariableContextFinder(
const gd::Platform& platform_,
const gd::ProjectScopedContainers& projectScopedContainers_)
: platform(platform_),
projectScopedContainers(projectScopedContainers_),
variableNode(nullptr),
objectName(""),
parameterType("") {};
protected:
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
void OnVisitOperatorNode(OperatorNode& node) override {}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
void OnVisitNumberNode(NumberNode& node) override {}
void OnVisitTextNode(TextNode& node) override {}
void OnVisitVariableNode(VariableNode& node) override {
if (variableNode) {
// This is not possible
return;
}
variableNode = &node;
// Check if the parent is a function call, in which we might be dealing
// with a legacy pre-scoped variable parameter:
if (node.parent) node.parent->Visit(*this);
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
if (node.parent) node.parent->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
if (variableNode) {
// This is not possible
return;
}
// This node is not necessarily a variable node.
// It will be checked when visiting the FunctionCallNode, just after.
variableNode = &node;
// Check if the parent is a function call, in which we might be dealing
// with a legacy pre-scoped variable parameter:
if (node.parent) node.parent->Visit(*this);
}
void OnVisitEmptyNode(EmptyNode& node) override {}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
if (node.parent) node.parent->Visit(*this);
}
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {
int parameterIndex = -1;
for (int i = 0; i < functionCall.parameters.size(); i++) {
if (functionCall.parameters.at(i).get() == variableNode) {
parameterIndex = i;
break;
}
}
if (parameterIndex < 0) {
return;
}
const auto& objectsContainersList =
projectScopedContainers.GetObjectsContainersList();
const gd::ParameterMetadata* parameterMetadata =
MetadataProvider::GetFunctionCallParameterMetadata(
platform, objectsContainersList, functionCall, parameterIndex);
if (parameterMetadata == nullptr) return; // Unexpected
if (parameterMetadata->GetType() == "objectvar") {
// Legacy convention where a "objectvar"
// parameter represents a variable of the object represented by the
// previous "object" parameter. The object on which the function is
// called is returned if no previous parameters are objects.
objectName = functionCall.objectName;
for (int previousIndex = parameterIndex - 1; previousIndex >= 0;
previousIndex--) {
const gd::ParameterMetadata* previousParameterMetadata =
MetadataProvider::GetFunctionCallParameterMetadata(
platform, objectsContainersList, functionCall, previousIndex);
if (previousParameterMetadata != nullptr &&
gd::ParameterMetadata::IsObject(
previousParameterMetadata->GetType())) {
auto previousParameterNode =
functionCall.parameters[previousIndex].get();
IdentifierNode* objectNode =
dynamic_cast<IdentifierNode*>(previousParameterNode);
objectName = objectNode->identifierName;
break;
}
}
parameterType = parameterMetadata->GetType();
}
}
private:
const gd::Platform& platform;
const gd::ProjectScopedContainers& projectScopedContainers;
};
VariableAndItsParent ExpressionVariablePathFinder::GetLastParentOfNode(
const gd::Platform &platform,
const gd::ProjectScopedContainers &projectScopedContainers,
gd::ExpressionNode &node) {
gd::ExpressionVariableContextFinder contextFinder(platform,
projectScopedContainers);
node.Visit(contextFinder);
if (!contextFinder.variableNode) {
return {};
}
gd::ExpressionVariablePathFinder typeFinder(platform, projectScopedContainers,
contextFinder.parameterType,
contextFinder.objectName, &node);
contextFinder.variableNode->Visit(typeFinder);
if (typeFinder.variableName.empty() || !typeFinder.variablesContainer) {
return {};
}
return typeFinder.WalkUntilLastParent(*typeFinder.variablesContainer,
typeFinder.childVariableNames);
}
} // namespace gd

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