Compare commits

...

471 Commits

Author SHA1 Message Date
Florian Rival
7aae4a8189 Use separately built GDevelop.js for Windows and Linux builds 2025-05-28 17:03:26 +02:00
D8H
8713a496b4 Declare the assets dimensions according to their variants in exported GDO (#7623) 2025-05-27 19:30:25 +02:00
Clément Pasteau
a3033f2db1 Update badge link to suggest opening profile after first click (#7624) 2025-05-27 10:59:57 +02:00
Florian Rival
5fb8faffc1 Improve Particle emitter description
Don't show in changelog
2025-05-25 17:02:02 +02:00
Clément Pasteau
a883955703 Add the Premium course to the Education curriculum (#7619) 2025-05-22 15:38:29 +02:00
Clément Pasteau
b39d7adcbc Fix displaying Teach tab if no members (#7617)
Do not show in changelog
2025-05-20 17:19:24 +02:00
github-actions[bot]
c577c8db71 Update extension translations [skip ci] (#7615)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-05-16 15:53:02 +02:00
Clément Pasteau
d7d17400dd Fix error accessing deleted objects after an object is deleted from a scene (#7612) 2025-05-15 18:18:09 +02:00
D8H
b219d50fd8 Fix a typo in the "hand brake" action (#7613)
- Don't show in changelog
2025-05-15 16:48:30 +02:00
Clément Pasteau
88f318e6df Bump to 5.5.231 (#7610)
Do not show in changelog
2025-05-15 11:03:54 +02:00
github-actions[bot]
d12ac44b7d Update translations [skip ci] (#7611)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-05-15 11:03:32 +02:00
Clément Pasteau
7155eea716 Show gd.games homepage on play section by default on mobile (#7609) 2025-05-15 10:46:49 +02:00
github-actions[bot]
ca0796f131 Update translations [skip ci] (#7595)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-05-15 10:35:56 +02:00
Clément Pasteau
c4b33e2481 Prevent continuing to use GDevelop if not all extensions have been loaded (#7608)
* GDevelop sometimes has faulty updates, for instance when the computer is shut down during an update. This was causing the app to be incomplete and projects to become corrupted after a save (ex: BBText objects being broken)
* This check shows an unskippable dialog suggesting a re-install of GDevelop
2025-05-15 10:15:42 +02:00
D8H
ff95564b6b Add new 3D physics-based vehicle behavior (#7479)
* You can now simulate realistic 3D cars using the new Vehicle behavior powered by the 3D physics engine.
* Advanced details can be customized: from wheel setup and gear ratios to engine torque, steering, brakes, anti-roll bars, and drivetrain (front/rear).
* The default setup offers a semi-realistic, arcade-style driving feel. For smoother gameplay, explore the example projects to see how fine-tuning makes a big difference.
* Jolt physics engine was upgraded to version 0.34.0.
2025-05-14 10:52:47 +02:00
Clément Pasteau
cecf1ab791 Fix crash when selecting a resource after switching tabs in the Resource selection dialog (#7607) 2025-05-14 10:28:12 +02:00
D8H
a571445e0e Allow custom objects to self-destruct (#7605) 2025-05-12 14:03:21 +02:00
D8H
89e418cd24 Fix grid snapping of pasted instances (#7602) 2025-05-12 11:41:42 +02:00
Florian Rival
896ccfcffa Add hint that mapper behaviors should be used for platformer (#7601)
Don't show in changelog
2025-05-12 10:51:09 +02:00
Clément Pasteau
d98d181755 Fix typo (#7604)
Do not show in changelog
2025-05-12 10:30:08 +02:00
Florian Rival
3c63f9b617 Update 3D extension internal descriptions
Only show in developer changelog
2025-05-08 12:26:54 +02:00
D8H
8312bbe4f8 Fix 3D Physics "apply force/impulse toward position" action (#7600) 2025-05-06 21:04:02 +02:00
Clément Pasteau
bb77a71f26 Bump to 5.5.230 (#7593)
Do not show in changelog
2025-05-06 10:10:48 +02:00
D8H
4353469554 Fix bitmap text alignment and rotation (#7597)
* Fix BBText rotation
2025-05-05 20:10:21 +02:00
Clément Pasteau
46ea431f62 Fix firebase tests (#7594)
Do not show in changelog
2025-05-05 15:16:39 +02:00
github-actions[bot]
2d29d43355 Update translations [skip ci] (#7577)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-05-05 11:22:08 +02:00
Clément Pasteau
28a4e253a1 Update desktop & web icons with latest GDevelop branding (#7578) 2025-05-05 10:22:40 +02:00
D8H
f3dcb8eec8 Fix asset export for objects with unused children overriding (#7590) 2025-05-05 09:53:11 +02:00
Florian Rival
bf9e38ff31 Improve descriptions of boolean logic conditions
Only show in developer changelog
2025-05-04 16:08:36 +02:00
D8H
87649b9def Ensure variants downloaded from the store comply to their events-based object (#7587) 2025-05-02 12:51:58 +02:00
D8H
60d332e872 Fix rendered custom objects in the editor with an overriding of children configuration (#7585)
- Fix children overriding to only apply to the default variant at runtime
2025-05-02 12:51:14 +02:00
D8H
bdab12b1e6 Fix variant edition: forbid to edit variants from the store (they should be duplicated instead) (#7586) 2025-05-02 12:05:49 +02:00
Florian Rival
02f795f2c1 Update AI requests wording 2025-04-29 09:52:19 +02:00
AlexandreS
6e64d8521f Submit ai question with Ctrl+Enter or Go to button of mobile soft keyboard (#7579)
Don't show in changelog
2025-04-28 18:51:39 +02:00
Clément Pasteau
0e9aea1c9d Fix showing Checkered background on sprite project resources (#7580)
Do not show in changelog
2025-04-28 18:31:24 +02:00
Clément Pasteau
99901bf539 Bump newIDE version (#7576) 2025-04-28 12:07:23 +02:00
github-actions[bot]
53f1d745f5 Update translations [skip ci] (#7572)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-04-28 10:28:31 +02:00
D8H
b72034a475 Fix the sentence parameter of "loading progress" condition (#7574) 2025-04-28 10:27:04 +02:00
AlexandreS
926f6a2c56 Remove useless param when changing user subscription (#7573)
Don't show in changelog
2025-04-25 17:20:23 +02:00
D8H
32cc6a3109 Fix an anchor behavior test (#7571)
- Don't show in changelogs
2025-04-25 11:04:48 +02:00
github-actions[bot]
f9ab65155d Update translations [skip ci] (#7561)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-04-25 10:57:40 +02:00
github-actions[bot]
d700a9d26d Update extension translations [skip ci] (#7565)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-04-25 10:57:08 +02:00
Florian Rival
297b88ed60 Improve description of the condition to compare a timer value 2025-04-24 17:14:52 +02:00
Aurélien Vivet
06cef654b0 Add explanatory tooltip to game analytics graph (#7559) 2025-04-24 15:17:14 +02:00
D8H
c5dd26c93b Remove another unused import (#7568)
Don't show in changelog
2025-04-24 12:28:21 +02:00
D8H
e0f3b221bd Remove unused import (#7567)
Don't show in changelog
2025-04-24 12:07:43 +02:00
D8H
896f56e850 Allow to switch between variants of custom objects (#7403)
- Variants allows to restyle custom objects
- They can be customized with the graphical editor
- The asset store will progressively use them notably for UI elements (buttons, sliders)
2025-04-24 11:05:00 +02:00
Aurélien Vivet
cee43ce9df Fix typo in GuidedLessons.js (#7566)
Do not show in changelog
2025-04-24 10:11:56 +02:00
D8H
5e61712e55 Fix various issues with the 3D physics engine (#7564)
* Fix the box shape to always be oriented on Z
* Fix memory leaks
2025-04-23 19:55:06 +02:00
Clément Pasteau
b3fa34ce3c Typo in description (#7560)
Do not show in changelog
2025-04-22 10:14:19 +02:00
github-actions[bot]
1bdb4c0369 Update extension translations [skip ci] (#7558)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-04-18 18:21:21 +02:00
github-actions[bot]
2822fab5ed Update translations [skip ci] (#7553)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2025-04-18 18:20:58 +02:00
AlexandreS
658ac381fb Send language when requesting chapters when not authenticated (#7557)
Don't show in changelog
2025-04-18 17:10:19 +02:00
D8H
80cf54cb1b Fix anchored object position when the object and the camera is moved (#7556) 2025-04-18 12:50:43 +02:00
AlexandreS
2f56f6b715 Add new course about UI/UX essentials (#7555)
Keep learning with GDevelop with this new course about UI/UX essentials to make sure your game delivers the best experience to your players!
2025-04-18 11:13:04 +02:00
Clément Pasteau
9784113574 Fix allowing resource swap in resource editor on web (#7554)
Do not show in changelog
2025-04-16 17:59:54 +02:00
Clément Pasteau
e2de3bec34 Update worker url logic + consistent lights + fix using in resources list (#7551)
Do not show in changelog
2025-04-16 16:27:24 +02:00
github-actions[bot]
e837df4882 Update translations [skip ci] (#7550)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-04-15 16:13:22 +02:00
Clément Pasteau
2f44dab18b 3D models can now be previewed (#7547)
* Screenshots are taken for each 3D Model (using .glb extension) so they can be easily recognized in the editor
* Those previews are visible in the Resources tab, in the 3D Model object dialog, or when swapping/selecting from a project resource
2025-04-15 16:02:55 +02:00
Aurélien Vivet
10049ce42a Add a button to copy the Ask AI response (#7548) 2025-04-15 15:59:32 +02:00
D8H
8d9a60f819 Use a shorter label for the button to toggle parameters in drop-down list (#7549) 2025-04-15 15:58:38 +02:00
Florian Rival
8ea8c421b2 Fix TextContainerExtension description 2025-04-14 18:42:03 +02:00
github-actions[bot]
f7b026f1cc Update translations [skip ci] (#7544)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-04-14 17:27:25 +02:00
Florian Rival
623535f7fd Revert test timemout (not supported by CRA)
Don't show in changelog
2025-04-14 09:20:28 +02:00
Florian Rival
3f0ff4a9de Increase default timeout for IDE tests
Avoid failing an AppVeyor Windows build because of a timeout
2025-04-11 14:08:53 +02:00
Clément Pasteau
883ca6d535 Allow selecting resources that are already in the project when editing an object (#7541) 2025-04-11 12:21:06 +02:00
github-actions[bot]
77f56829b3 Update translations [skip ci] (#7537)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-04-08 10:36:24 +02:00
Clément Pasteau
12a842e197 Fix Piskel crashing with black screen when doing multiple undos (#7539) 2025-04-08 09:33:16 +02:00
Clément Pasteau
7145e6d049 Hide Ask AI for student accounts (#7533)
Do not show in changelog
2025-04-07 11:10:52 +02:00
László Nyiri
caa18e5fcb Fix "Never reached character" error during GDevelop.js build (#7536)
Only show in developer changelog
2025-04-07 09:20:26 +02:00
github-actions[bot]
61bf8a7cab Update translations [skip ci] (#7529)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-04-04 11:32:48 +02:00
Clément Pasteau
98b3687157 Fix cmake version for mac builds (#7531)
Do not show in changelog
2025-04-04 11:20:20 +02:00
github-actions[bot]
4b4fba2c7a Update extension translations [skip ci] (#7532)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-04-04 11:18:44 +02:00
Clément Pasteau
cedb9429c7 Improve languages dialog display (#7528)
Do not show in changelog
2025-04-02 11:28:27 +02:00
github-actions[bot]
d844b4d380 Update extension translations [skip ci] (#7527)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-04-02 10:07:12 +02:00
github-actions[bot]
e4265553e0 Update translations [skip ci] (#7526)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-04-02 09:13:15 +02:00
Florian Rival
2524b0b9d2 Update wording
Don't show in changelog
2025-04-01 18:02:37 +02:00
Florian Rival
20d16b8a57 Add minor improvements to Ask AI
Don't show in changelog
2025-04-01 13:26:14 +02:00
github-actions[bot]
67aa1ce062 Update translations [skip ci] (#7524)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-04-01 10:37:54 +02:00
Florian Rival
1759dda870 Fix formatting 2025-04-01 00:21:01 +02:00
Florian Rival
03dce1d90a Add dialog to report AI message feedback 2025-04-01 00:16:31 +02:00
Florian Rival
4e9556e948 Fix tests and improve wording of tilemaps 2025-03-31 22:53:07 +02:00
D8H
a02b8dcfe0 Add vertical alignement for BitmapText and BBText (#7523) 2025-03-31 21:00:58 +02:00
Florian Rival
416ef44ee1 Improve Ask AI tab
Don't show in changelog
2025-03-31 18:46:48 +02:00
github-actions[bot]
aa90621899 Update translations [skip ci] (#7516)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-31 11:14:33 +02:00
github-actions[bot]
3d3f04f63e Update extension translations [skip ci] (#7521)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-31 10:42:15 +02:00
Clément Pasteau
e1cc21c225 Bump to 5.5.228 (#7515) 2025-03-28 16:47:06 +01:00
github-actions[bot]
9f90bf595e Update translations [skip ci] (#7510)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-03-28 16:43:58 +01:00
Florian Rival
94d49d8c36 Make variable internal naming consistent and update max height for compact text area fields
Don't show in changelog
2025-03-28 16:34:52 +01:00
github-actions[bot]
1d8c435fe0 Update extension translations [skip ci] (#7514)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-28 15:04:01 +01:00
Clément Pasteau
573eafe777 Fix tab tooltip being stuck when closing tab + improve design (#7513) 2025-03-28 11:33:06 +01:00
Florian Rival
15ff9bedd9 Add "Ask AI" (#7486)
* The "Ask AI" tab allows you to access an AI that is a GDevelop expert. _Think of it as "ChatGPT" but that is trained on GDevelop and knows everything about it._ It can give you advices and guide you through GDevelop, features, extensions and has knowledge of what you use in your game (scenes, objects, behaviors).
  * Unsure how to do something? Ask the AI.
  * Want to get a better understanding of a concept you don't understand? Ask the AI.
  * Have an idea but unsure where to start? Ask the AI.
* The AI gives its answer according to the full knowledge of features, reviewed extensions and game building with GDevelop. It's perfect for beginners or when you want to quickly get an answer without having to search for a long time.
* This is experimental. As with any AI, it can make mistakes or give answers that are wrong or not the best way to do something - you can put a thumb up or thumb down on each answer if you want to report something.
  Feel free to check answers with the members of the community on the forum or on Discord. We'll actively improve the AI according to the results it gives.
* The AI was worked to be concise, efficient and fast. If you have a GDevelop membership (silver, gold, pro) you will have an allowance for free AI request every month. You can unlock more AI requests or get some with a free account with credits.
2025-03-27 15:31:16 +01:00
Clément Pasteau
9431ee7316 Remove useless commits in changelog script (#7511)
Do not show in changelog
2025-03-27 13:58:47 +01:00
Florian Rival
333de61ead Reduce some analytics events frequency (#7512)
Don't show in changelog
2025-03-27 13:19:32 +01:00
Clément Pasteau
1433a5f65c Bump 5.5.227 (#7509)
Do not show in changelog
2025-03-27 10:50:53 +01:00
github-actions[bot]
ab1e566aef Update translations [skip ci] (#7506)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-26 14:54:50 +01:00
Clément Pasteau
1a4f9317d1 Slightly improve guided lessons design on mobile (#7504) 2025-03-26 14:45:58 +01:00
Clément Pasteau
af4a6a9313 Fix "Manage subscription" Profile button not working (#7507) 2025-03-26 14:40:39 +01:00
Florian Rival
5f3066d35a Update physics engine/behavior description (#7505)
Only show in developer changelog
2025-03-25 19:38:11 +01:00
Clément Pasteau
3d4f4c1441 Fix locale import (#7503)
Do not show in changelog
2025-03-25 15:25:51 +01:00
github-actions[bot]
4da5efcff2 Update translations [skip ci] (#7497)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-25 15:00:44 +01:00
Clément Pasteau
dde472fd31 Improve locales import (#7502)
Do not show in changelog
2025-03-25 14:48:42 +01:00
Clément Pasteau
94e8cf2229 Update CrazyGames logo to official version (#7499) 2025-03-24 18:30:24 +01:00
github-actions[bot]
17f1bff1cd Update extension translations [skip ci] (#7498)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-24 18:05:50 +01:00
Clément Pasteau
a0c0c3d7b0 Show possible announcements on Create section (#7496)
Do not show in changelog
2025-03-24 15:08:46 +01:00
github-actions[bot]
41b255fdd9 Update translations [skip ci] (#7490)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2025-03-21 16:37:41 +01:00
D8H
085b425431 Add a deprecation warning on text entry object actions (#7484) 2025-03-21 15:57:11 +01:00
github-actions[bot]
5957738070 Update translations [skip ci] (#7471)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-21 15:44:13 +01:00
Clément Pasteau
7caeae93d6 Fix translation update script (#7489)
Do not show in changelog
2025-03-21 15:23:37 +01:00
Clément Pasteau
ae09ad50ec Automatically translate reviewed extensions and their actions and conditions (#7478) 2025-03-21 15:09:06 +01:00
AlexandreS
495b99356d Add tooltip for tabs (#7482) 2025-03-20 10:27:38 -07:00
D8H
e432a7fa67 Fix extension bug report link (#7483) 2025-03-19 14:58:41 +01:00
AlexandreS
8ba69ce338 Send message to gd.games iframe when soft keyboard opens (#7472) 2025-03-18 09:55:24 -07:00
D8H
767b632db9 Fix the Anchor behavior when the deprecated property is used (#7481) 2025-03-18 17:42:59 +01:00
D8H
49749fbd88 Fix 3D model animations when a negative time scale is used (#7474) 2025-03-14 14:26:06 +01:00
Clément Pasteau
99873e5c76 Fix youtube link (#7470)
Do not show in changelog
2025-03-12 15:41:49 +01:00
github-actions[bot]
3e87e5f76a Update translations [skip ci] (#7467)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-12 10:00:43 +01:00
Clément Pasteau
be5cc49928 Fix discord role claim & other display issues in the profile (#7468) 2025-03-12 09:48:06 +01:00
Clément Pasteau
4bdf7172a6 Merge pull request #7466 from 4ian/youtube-highlight
Highlight youtube sub in profile
2025-03-11 13:05:39 +01:00
Clément Pasteau
9f9f7824ef Highlight youtube sub in profile 2025-03-11 13:00:10 +01:00
Florian Rival
b24e0b79bd Merge pull request #7465 from 4ian/bump-226
Bump to 5.5.226
2025-03-11 09:44:25 +00:00
Clément Pasteau
827b2cf3d8 Merge pull request #7458 from 4ian/chore/update-translations
[Auto PR] Update translations
2025-03-11 10:43:43 +01:00
ClementPasteau
7a4142a1c9 Update translations [skip ci] 2025-03-11 09:37:46 +00:00
Clément Pasteau
78671abb91 Bump to 5.5.226 2025-03-11 10:37:30 +01:00
Clément Pasteau
11df078b74 Merge pull request #7463 from 4ian/youtube-sub-badge
New badge can be unlocked when subscribing to YouTube channel
2025-03-11 10:30:43 +01:00
Clément Pasteau
9001bfd8e2 Merge pull request #7461 from 4ian/fix-animation-crossfade-switch-problem
fix "is finished" animation condition
2025-03-11 10:26:26 +01:00
Neyl
0d2778c8db Update Model3DRuntimeObject3DRenderer.ts 2025-03-11 09:51:58 +01:00
Neyl
ee98e8a329 Update Model3DRuntimeObject3DRenderer.ts 2025-03-11 09:42:16 +01:00
Clément Pasteau
a2e48fdd6c Fix display on desktop 2025-03-10 18:08:17 +01:00
D8H
187018cdd3 [Spine] Fix "Animation finished" condition (#7464) 2025-03-10 17:57:27 +01:00
Neyl
c7622c3abe Update Model3DRuntimeObject3DRenderer.ts 2025-03-10 16:47:08 +01:00
Clément Pasteau
7dca48b8bd New badge can be unlocked when subscribing to YouTube channel 2025-03-10 16:33:50 +01:00
D8H
e9c625abc6 Automatically rename and delete object instance variables (#7454) 2025-03-10 16:05:39 +01:00
Neyl
71f7b59ab5 nitpicked 2025-03-10 15:10:08 +01:00
Neyl
8630452b89 updated comments 2025-03-10 14:57:57 +01:00
Clément Pasteau
b1a91bdc4c Update player token logic to be fetched on project opening (#7460)
Do not show in changelog
2025-03-10 14:51:33 +01:00
Neyl
638c661138 Update Model3DRuntimeObject3DRenderer.ts 2025-03-10 14:41:03 +01:00
Neyl
5dfd26c6f6 fix animation crossfade issue 2025-03-10 14:39:09 +01:00
D8H
a79e87dc7a Fix 3D sprites being all black (#7459) 2025-03-10 13:06:05 +01:00
ViktorVovk
6490c1c4ad Refactor logic to get file URLs in gdjs.SoundManager (#7433)
Only show in developer changelog

Co-authored-by: Vovk Viktor <vvovk@playtika.com>
2025-03-10 11:34:16 +01:00
D8H
05963806f1 Close the extension tabs when it's updated (#7453) 2025-03-10 11:29:15 +01:00
D8H
c4e1d2e5f8 Improve animation state displaying in the capabilities test example (#7455)
- Don't show in changelog
2025-03-10 10:16:34 +01:00
AlexandreS
92f13abafc Fix tile set not updated when tilemap resource file is change outside of GDevelop (#7457) 2025-03-10 09:36:36 +01:00
Clément Pasteau
ae3438b5f9 Send event when opening play section + rename event (#7452)
Do not show in changelog
2025-03-07 16:22:58 +01:00
D8H
ff572a2777 Close the extension tabs when it's updated (#7451) 2025-03-07 16:11:00 +01:00
Clément Pasteau
e2320ec717 Add events when swapping assets (#7450)
Do not show in changelog
2025-03-07 15:50:06 +01:00
Clément Pasteau
bce459b2d2 Add missing event data (#7449)
Do not show in changelog
2025-03-06 15:31:26 +01:00
D8H
95dddc48b6 Deprecate old variable actions and conditions in extensions (#7406)
- The extension variables must be used instead
- Old extensions can be maintained by copy-pasting existing old actions and conditions from the extension events
2025-03-06 13:13:14 +01:00
Clément Pasteau
d39f210630 Bump 5.5.225 (#7447) 2025-03-06 12:08:31 +01:00
github-actions[bot]
090649f125 Update translations [skip ci] (#7440)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-06 12:01:45 +01:00
Clément Pasteau
7c8c02911c Improve Guided Lessons by preventing clicking outside of the next action (#7444) 2025-03-06 11:54:37 +01:00
D8H
0c6a28c0a1 Fix onCreated functions not being called on behaviors added at hot-reload (#7443) 2025-03-04 14:26:21 +01:00
Florian Rival
b9d5974356 Fix expression documentation not displaying parameters 2025-03-04 00:13:22 +01:00
D8H
74a1e11cfc Improve the abs expression documentation (#7442) 2025-03-03 21:53:52 +01:00
D8H
c712d0bb9e Forbid to install assets or behaviors from extensions incompatible with the editor (#7441) 2025-03-03 20:43:48 +01:00
Clément Pasteau
828e6e031a Update AdMob extension to handle Consent & Tracking Authorization on iOS (#7431)
* Admob will now initialize 2 seconds after the app loads, giving more control to when it starts. This is particularily helpful for App Store validations, with Tracking Authorization message.
* New conditions are available to know AdMob initialization status: "AdMob initializing" and "AdMob Initialized".
* New action to stop the auto-initialization: "Prevent AdMob auto initialization" and new action to trigger the initialization: "Initialize AdMob manually".
  * Typically, you'd prevent the initialization at the beginning of the scene, and trigger it manually when a user interacts with a button or something, so you can control when they'll see the consent messages.
2025-03-03 10:53:59 +01:00
D8H
727f991c01 Allow anchored objects to be moved from their initial position (#7417)
* If an anchored object is moved using events (or another behavior), it will stay on its new position.
  This allows to anchor objects on the left, right, top or bottom of the screen (or inside the bounds of a custom object, for example in a dialog) and still allow them to move.
2025-03-03 10:52:15 +01:00
D8H
5d4523b925 Fix object parameter not shown when editing an action/condition when the object doesn't exist (#7373) 2025-03-03 10:40:06 +01:00
github-actions[bot]
3f7cbc731a Update translations [skip ci] (#7434)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2025-03-03 10:38:44 +01:00
D8H
c1dfa34f0d Deprecate internal actions and conditions to set and compare property values in extension events (#7405)
- The unified variable action and condition must be used instead.
2025-03-03 10:31:05 +01:00
D8H
cf39de49d6 Allow custom objects to declare multi-line text properties (#7436) 2025-02-28 17:23:51 +01:00
D8H
5b325dd8ec Fix access to objects in variable expressions of "for each child variable" loops (#7435) 2025-02-28 11:06:51 +01:00
Clément Pasteau
1f42331cbf Allow selecting a Pixel Art version of 2D starting points (#7425)
* Available for Platformer, Top-Down & Physics templates
2025-02-27 18:06:15 +01:00
Florian Rival
224f17b90a Add missing await 2025-02-27 17:27:58 +01:00
D8H
3541d356e0 Fix text alignment at runtime (#7432) 2025-02-27 10:58:18 +01:00
github-actions[bot]
63e79d678a Update translations [skip ci] (#7416)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-02-27 09:32:51 +01:00
Florian Rival
812153ffb3 Allow the embedded games platform to ask for opening external urls
Don't show in changelog
2025-02-26 15:26:26 +01:00
Clément Pasteau
c62ea9e10a Show error if games frame does not load (#7430) 2025-02-26 14:13:54 +01:00
Clément Pasteau
04c63b2c74 Fix using non-existing vars in calc() (#7427)
Do not show in changelog
2025-02-26 11:15:18 +01:00
Florian Rival
dcc3bae17e Fix warning
Don't show in changelog
2025-02-25 10:31:21 +01:00
Florian Rival
441834cad5 Prepare custom token to speed up embedded game frame login (#7423)
Don't show in changelog
2025-02-25 10:14:15 +01:00
Florian Rival
d4352ba5d9 Adapt embedded game frame position and allow sharing
Don't show in changelog
2025-02-24 19:35:29 +01:00
Clément Pasteau
163239d08d Fix toggle "update game page" sometimes not being visible when publishing. (#7422)
* This could happen when the last build was too old, and the interface considered the game as new, so published it automatically to the game page.
2025-02-24 15:23:39 +01:00
Florian Rival
e3e9b41672 Display first letter of tabs when at minimum size 2025-02-24 12:24:17 +01:00
inspace
7ba7c220e9 Ensure cursor position is correct when a mouse down event is detected (#7412)
Only show in developer changelog
2025-02-24 11:30:36 +01:00
AlexandreS
617bf2c5b9 Add missing keys in keyboard condition/action (#7421)
- Added Left and Right bracket and the Menu keys
2025-02-24 10:38:14 +01:00
Clément Pasteau
d647d1e397 Fix top bar to be draggable on desktop, except tabs (#7420) 2025-02-24 10:32:44 +01:00
Florian Rival
c5bf9730aa Refactor toolbar and titlebar display and ensure game iframe is hidden when not on the Play tab (#7419)
Don't show in changelog
2025-02-23 15:28:32 +01:00
Florian Rival
c5022596b8 Make the games/page in Play section to take the full width
Don't shown in changelog
2025-02-22 14:37:36 +01:00
D8H
6e61c48898 Fix a regression that hid all 3D models in the editor (#7418)
Don't show in changelog
2025-02-22 14:00:56 +01:00
Clément Pasteau
75fc55bac4 Rework the Play section to have games played inside the app (#7372) 2025-02-20 18:46:00 +01:00
github-actions[bot]
8a4916fd93 Update translations [skip ci] (#7414) 2025-02-20 10:08:45 +01:00
AlexandreS
b008863281 Do not show the reminder if the editor was just idle for too long (#7413) 2025-02-19 15:56:25 +01:00
github-actions[bot]
f0377771a8 Update translations [skip ci] (#7399)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2025-02-19 09:33:26 +01:00
D8H
299ef90f93 [3D character] Fix the "is moving" condition when moving sideways (#7411) 2025-02-17 14:01:37 +01:00
D8H
800c3333d4 Improve typing of the 3D object editor renderers (#7410)
- Don't show in changelog
2025-02-17 12:57:27 +01:00
AlexandreS
303ebfaf1b Refresh in app tutorial message in preview when hot reloading preview (#7407)
Don't show in changelog
2025-02-17 12:06:44 +01:00
AlexandreS
288e4f4b75 Fix: Remove crash when opening 3D Racing game example external layouts
- Use default values when updating Cube 3D three object in editor (#7408)
2025-02-17 11:30:54 +01:00
Clément Pasteau
15db4be4a1 Fix typo (#7402)
Do not show in changelog
2025-02-14 10:08:01 +01:00
D8H
925ffa74ec Allow to tween 3D boxes tint color (#7401)
- Don't show in changelog
2025-02-13 12:35:52 +01:00
D8H
752d047464 Upgrade GDJS to Prettier 3.4.2 (#7398)
- Don't show in changelog
2025-02-12 18:50:02 +01:00
D8H
7a21f9533e Upgrade to TypeScript 5.4.5 (#7394)
- Don't show in changelog
2025-02-12 17:51:36 +01:00
Ansel Games
9820770fb3 Update "Create objects from an external layout" action to show all parameters in the events sheet (#7383) 2025-02-12 17:49:23 +01:00
D8H
a92784295a Fix GDJS test resource paths (#7397) 2025-02-12 17:41:19 +01:00
Neyl
81f6c62bb1 Update Animation Crossfade default value to a more realistic one (100ms) (#7395) 2025-02-12 17:13:36 +01:00
github-actions[bot]
a1bbb1c14c Update translations [skip ci] (#7388)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2025-02-12 16:56:29 +01:00
Clément Pasteau
9154144228 Fix a project opened from a file being always detected as a new game in the dashboard (#7392) 2025-02-12 16:55:59 +01:00
AlexandreS
c0176dfb2b Add lightweight markdown interpreter for in-app tutorial in-game messages (#7391)
Don't show in changelog
2025-02-12 14:35:32 +01:00
AlexandreS
23cd527d94 Fix spatial sound action not applied if sound is not playing yet (#7393) 2025-02-12 14:33:46 +01:00
Neyl
fa2cdb1624 fix crossfade duration in 3D model editor 2025-02-12 12:02:08 +01:00
Clément Pasteau
03eca4de4b Upgrade pixi to 7.4.2 (#7190) 2025-02-11 14:20:59 +01:00
Clément Pasteau
841484e5b7 Disable lazy loading on authorized images, fixing the image stuck with a loader (#7389) 2025-02-11 10:58:47 +01:00
github-actions[bot]
b88c5b08f5 Update translations [skip ci] (#7370)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-02-11 09:36:17 +01:00
Aurélien Vivet
3f2043f248 Add a clearer warning before the deletion of a game and a project. (#7368)
* This is mainly to prevent accidental deletion of games
2025-02-11 09:35:33 +01:00
Florian Rival
6941e64418 Adapt tabs width according to screen width, to keep them visible on screen as much as possible (#7387) 2025-02-10 18:24:48 +01:00
Neyl
fb7bb9181d add support for crossfading animations for 3D models
the new option allows to smoothly transition between animations. The fading duration can be customized with an action.
2025-02-10 17:56:18 +01:00
AlexandreS
7ee50a2568 Fix: Prevent accidentally saving a project in the root folder of the editor 2025-02-10 13:04:23 +01:00
AlexandreS
90cdc875a9 Add possibility to display message in the preview when an in-app tutorial is running (#7379) 2025-02-10 10:59:35 +01:00
Florian Rival
47d0fba205 Fix a crash when searching instructions after extension are re-generated (#7377)
* Also improve the display of actions/conditions/expressions when searched with a clearer visual separator for their folders
2025-02-07 16:03:09 +01:00
Aurélien Vivet
db745369dc Re-order in-app tutorials (#7378) 2025-02-07 15:30:19 +01:00
D8H
7c49346bed Add a warning on array children with inconsistent type (#7376) 2025-02-06 18:29:38 +01:00
AlexandreS
b9a7786ab0 Add an action to join a lobby in one-click (#7352) 2025-02-06 18:04:41 +01:00
AlexandreS
76c09908c8 Fix border radius added by browser on text input (#7375) 2025-02-06 14:45:54 +01:00
Neyl
b6e186e775 Tint color for 3D cube (#7354)
add a tint color property for 3D cube.
2025-02-06 11:10:39 +01:00
D8H
8c98239e12 Allow to swap assets of any object type (#7365) 2025-02-04 17:22:53 +01:00
AlexandreS
4d56333ae7 Display shorter title in Curriculum's table of content when available (#7371) 2025-02-04 16:22:13 +01:00
AlexandreS
146794d33a Bump newIDE version (#7369) 2025-02-04 15:32:07 +01:00
AlexandreS
3a685c62df Refine free conditions/actions search to give priority to results with the search word in the displayed name (#7360) 2025-02-04 11:28:43 +01:00
github-actions[bot]
8bcbf9bd47 Update translations [skip ci] (#7353)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-02-04 10:25:13 +01:00
Clément Pasteau
601a4e214e Fix games sometimes disappearing from the dashboard (#7366)
* This was caused by games wrongly being considered as not saved during the export, and they were hidden from the dashboard afterwards
2025-02-04 10:07:06 +01:00
D8H
3d0b264130 [Physics3D] Fix remaining hit-boxes of deleted character (#7359)
- Also fix 3D character behavior deactivation
2025-02-03 17:54:38 +01:00
D8H
97e989dee0 Ensure behaviors are compatible with the object before pasting them (#7343) 2025-02-03 13:02:41 +01:00
D8H
6440149fc8 Change documentation pages of some actions and conditions to point to more specific pages (#7364) 2025-02-03 12:58:28 +01:00
Neyl
232359f0a4 FIX the destroy of the form, "is submitted" condition icon, and readonly & disable feature (#7363)
Fix the destroy of the form, readonly and disable feature, and a typo for "is submitted" condition icon
2025-02-03 12:52:57 +01:00
Florian Rival
bf7ecd9ceb Add "Scroll" text to in-app tutorial highlights (#7356)
Don't show in changelog
2025-01-30 11:31:30 +01:00
D8H
2ba7075a7a Update the "trigger once" help page link (#7355) 2025-01-28 19:05:58 +01:00
Clément Pasteau
e45256cebb Fix a few issues with displaying projects correctly in the create section (#7349) 2025-01-27 18:51:25 +01:00
Florian Rival
1ee2d57d2f Bump newIDE version 2025-01-27 18:35:49 +01:00
github-actions[bot]
e890d8f211 Update translations [skip ci] (#7348)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-01-27 18:34:42 +01:00
Florian Rival
e70f8532f6 Improve course display 2025-01-27 16:54:42 +01:00
Florian Rival
446494156b Fix crash when adding/modifying functions in extensions (#7351) 2025-01-26 21:40:11 +01:00
D8H
15a1d392a1 Fix extension usage listing for example web pages (#7339) 2025-01-24 15:19:49 +01:00
AlexandreS
65b5aa6bac Use new compact UI in the Preferences dialog (#7345) 2025-01-24 14:02:48 +01:00
Florian Rival
cbaa785b95 Fix log and extra character
Don't show in changelog
2025-01-24 13:46:05 +01:00
github-actions[bot]
b6091de09a Update translations [skip ci] (#7341)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2025-01-24 13:29:17 +01:00
Clément Pasteau
b53dc29f43 Add preferences menu item back in the File menu (#7346) 2025-01-24 13:28:56 +01:00
Aurélien Vivet
0848a109d4 Bring consistency on arrow direction for UI items that can be opened/closed (#7322) 2025-01-24 10:50:51 +01:00
Florian Rival
4bf21e94eb Change in-app tutorials order 2025-01-24 10:43:05 +01:00
Clément Pasteau
2d6b2c1753 Improve homepage bottom bar icons on mobile (#7342) 2025-01-23 18:31:04 +01:00
AlexandreS
c4e230d9ba Split text input padding into 2 separate properties (#7338)
Don't show in changelog
2025-01-23 16:12:18 +01:00
D8H
56ab2fdd05 Revert "Fix used extension check false positive from usused object or behavior events (#7331)" (#7340)
This reverts commit cb24f191fd.

Don't show in changelog
2025-01-23 14:11:13 +01:00
github-actions[bot]
872f4032ff Update translations [skip ci] (#7337)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-01-23 11:56:54 +01:00
D8H
428b4c21a8 Disable panel sprite tilling by default (#7335)
* This ensures the rendering is more performant by default
2025-01-23 09:43:40 +01:00
D8H
cb24f191fd Fix used extension check false positive from usused object or behavior events (#7331)
- Don't show in changelog
2025-01-22 17:17:39 +01:00
github-actions[bot]
994f6bf150 Update translations [skip ci] (#7334)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2025-01-22 15:55:56 +01:00
AlexandreS
3e2f05460a Bump newIDE version (#7333) 2025-01-22 15:46:04 +01:00
github-actions[bot]
c775cde9df Update translations [skip ci] (#7318)
Co-authored-by: NeylMahfouf2608 <26115084+NeylMahfouf2608@users.noreply.github.com>
2025-01-22 15:37:51 +01:00
AlexandreS
6ab736a048 Return exact matches when searching for an instruction (#7330) 2025-01-22 15:35:12 +01:00
Neyl
f805182ce4 Improvement features for Input text box (#7308)
padding, max-length and text-align can now be configured on the text input object
new condition "Input is submitted" to check if the input has been submitted with the keyboard on all platforms
2025-01-22 14:20:29 +01:00
D8H
a14f1a187e Fix a few typo in Physics3D (#7332)
- Don't show in changelog
2025-01-22 11:35:52 +01:00
D8H
d08bf97471 Fix conflict between variable or property and parameter in variable setters (#7329)
- Don't show in changelog
2025-01-21 19:16:43 +01:00
D8H
093e15e105 Fix EventsFunctionsContainer copy constructor now copy the owner (#7327)
- Don't show in changelog
2025-01-20 14:35:37 +01:00
D8H
60e36f37b1 Remove EventsFunctionsExtension inheritance to EventsFunctionsContainer (#7326)
- developer changelog only
2025-01-20 11:29:55 +01:00
D8H
ad7ce3c725 [3D character] Fix the "is falling" condition from being true when the character is going up (#7325) 2025-01-19 01:00:43 +01:00
D8H
c6f83f4431 Fix behavior property generation and value. (#7324) 2025-01-19 01:00:05 +01:00
D8H
4a685db574 Fix parameters list not updating when the function configuration was changed (#7321) 2025-01-17 20:06:08 +01:00
D8H
f3dea010fb Fix syntax errors not showing up on mouse button and key parameters (#7320)
- Don't show in changelog
2025-01-17 20:05:29 +01:00
D8H
5025e03dff Fix 3D physics characters to keep rotation around X and Y intact (#7319) 2025-01-17 15:42:46 +01:00
Florian Rival
64771c6faf Give back focus to preview, when updating a preview on the web-app 2025-01-17 13:10:09 +01:00
github-actions[bot]
d4987c4739 Update translations [skip ci] (#7314)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-01-17 10:48:59 +01:00
Clément Pasteau
56575e7afd Introduce new subscription dialog design for creators without a plan (#7316) 2025-01-17 10:39:04 +01:00
Florian Rival
9a0df077b3 Fix a crash when opening a project missing a custom object that was loaded in the previously opened project (#7317) 2025-01-16 23:27:32 +01:00
AlexandreS
4bf3ef8ad4 Use the folder structure when choosing an object/group in an action/condition (#7297) 2025-01-16 12:03:58 +01:00
Clément Pasteau
6242e8c97a Fix not being able to drag the app from the top bar (#7315)
Do not show in changelog
2025-01-16 12:02:47 +01:00
D8H
d6c99b27af Allow to use parameters and properties in the variable action and condition (#7124) 2025-01-15 23:28:18 +01:00
AlexandreS
7844ee102e Fix issue that was not showing cubes when they have all their faces shown with no textures (#7313) 2025-01-15 18:17:38 +01:00
github-actions[bot]
7d713d9428 Update translations [skip ci] (#7311)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-01-15 17:36:12 +01:00
Clément Pasteau
22056d3c08 Fix adding draggable space only on title bar (#7312)
Do not show in changelog
2025-01-15 17:28:43 +01:00
D8H
2ce35a1520 Allow 3D physics characters to push each other (#7292) 2025-01-15 10:52:21 +01:00
AlexandreS
b04c15f23c Add objects installed from the asset store in selected folder (#7287) 2025-01-15 10:32:15 +01:00
D8H
2ab246696b Add autocompletion for keyboard key properties in the behavior editor (#7310) 2025-01-15 09:57:45 +01:00
Florian Rival
6b4c00c987 Add missing JS files thumbnail
Don't show in changelog
2025-01-15 09:52:56 +01:00
github-actions[bot]
9c4a190a4d Update translations [skip ci] (#7300)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-01-15 09:50:36 +01:00
Clément Pasteau
1070a489e7 Fix dialog overflow because of cross (#7309)
Don't show in changelog
2025-01-15 09:24:37 +01:00
Clément Pasteau
d2a8cb6727 Improve title bar on multiple platforms optimizing the space at the top of the app (#7306) 2025-01-14 17:29:55 +01:00
D8H
2638c4f593 Fix getter and setter generation for animation properties (#7307)
- Don't show in changelog
2025-01-14 14:51:27 +01:00
D8H
4be2386efe Allow to toggle between drop-down list and expression for mouse button and key parameters (#7305) 2025-01-14 13:53:10 +01:00
AlexandreS
8be099d50a Add possibility to open GDevelop in the browser on the premium course (#7304) 2025-01-13 19:12:14 +01:00
Clément Pasteau
713698d3d6 Fix wrong margins for dense design of sub card (#7303)
Do not show in changelog
2025-01-13 13:32:11 +01:00
Clément Pasteau
8b36908fd8 Merge project manager & app burger menu buttons (#7289)
* The goal of this change is to simplify the top left corner of the app, by merging the App burger menu and the Project manager button into one. Having 2 buttons was causing confusion in the flow of using the app, by mistakenly pressing the wrong button.
* The app menu buttons that are useful are now displayed at the top of the project manager drawer, on the relevant platforms: Web, Windows & mobile, because other platforms have a built-in OS menu.
2025-01-13 10:11:32 +01:00
D8H
c0722dc441 [2D Physics] Reduce the CPU footprint of static objects (#7299) 2025-01-10 16:39:20 +01:00
D8H
9c6a1bed2c [3D Physics] Reduce the CPU footprint of static objects (#7298) 2025-01-10 12:58:53 +01:00
github-actions[bot]
a8a4d14ee1 Update translations [skip ci] (#7291)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-01-10 10:23:16 +01:00
Florian Rival
b27abfbe5d Add text vertical alignment in quick customzation
Don't show in changelog
2025-01-10 10:07:37 +01:00
Neyl
28b585aefa Allow behavior properties to be an animation name, displayed with a selector 2025-01-09 14:21:04 +01:00
AlexandreS
0623b6acd9 Fix variable list usability (#7290)
- When renaming a variable in the instance panel:
  - the caret position is kept
  - the user can erase the whole field without the name being replaced by "Unnamed" instantly
- When opening the variables editor from a variable field, the currently selected variable is selected in the list (even if child of a variable)
2025-01-08 16:44:13 +01:00
github-actions[bot]
1a833bc388 Update translations [skip ci] (#7272)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2025-01-07 11:04:19 +01:00
D8H
827f187e10 Add Pixi and Three type definitions for JS events (#7266) 2025-01-07 10:34:51 +01:00
Florian Rival
0f25b80a66 Fix margins
Don't show in changelog
2025-01-06 22:06:15 +01:00
Clément Pasteau
fbf9710cc5 Use premium colors in most places where a subscription can be purchased (#7284) 2025-01-06 20:56:49 +01:00
Clément Pasteau
3d80709029 Fix correctly exporting desktop icon when project is saved in the cloud (#7282) 2025-01-06 17:54:59 +01:00
AlexandreS
5ab9c565b0 Simplify shop navigation state to avoid useless renderings (#7283)
Only show in developer changelog
2025-01-06 17:01:41 +01:00
Florian Rival
e237fc4b21 Add experimental support for importing JS source files in extensions (#7278)
* See more about using [JavaScript on this page](https://wiki.gdevelop.io/gdevelop5/events/js-code/javascript-in-extensions/#experimental-new-option-javascript-files-in-your-project).

Only show in developer changelog
2025-01-06 11:02:28 +01:00
D8H
18892f97f3 Remove unused import and fix a typo (#7277) 2025-01-04 11:19:42 +01:00
D8H
0ec0654032 Allow to make custom objects private to an extension (#7275) 2025-01-03 19:36:38 +01:00
D8H
8e29c723e8 [3D physics character] Fix a 1-frame delay on the "is falling" condition (#7276) 2025-01-03 19:33:33 +01:00
Clément Pasteau
6acde2865a Fix opening windows in foreground on windows everywhere in app (#7274)
* Ensure electron/remote is used
2025-01-02 16:36:43 +01:00
Clément Pasteau
49e176a98f Scroll to projects when opening from dashboard (#7273)
Do not show in changelog
2025-01-02 15:16:30 +01:00
D8H
71c2a0be01 Add a property to choose the maximum stair height a 3D character can walk (#7265) 2025-01-02 13:18:46 +01:00
Clément Pasteau
4ad1a0dd68 Bump 221 (#7271) 2025-01-02 11:20:00 +01:00
github-actions[bot]
a556690307 Update translations [skip ci] (#7269)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-01-02 11:17:46 +01:00
Clément Pasteau
6950f323b3 Disable type checking in JS Events until all autocompletions are properly handled (#7270) 2025-01-02 11:09:59 +01:00
github-actions[bot]
de129f6cc4 Update translations [skip ci] (#7252)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2025-01-02 10:57:33 +01:00
Clément Pasteau
b3b88a0445 Fix wrong prop name & add translations (#7268)
Do not show in changelog
2025-01-02 10:57:08 +01:00
D8H
8e8f3a7d55 Fix the collision conditions for 3D physics characters (#7264)
* Migrate to Jolt 0.31.0
2024-12-31 16:58:08 +01:00
D8H
cc6b4a283a Enable type checking on the Dialog Tree implementation (#7263)
- Don't show in changelog
2024-12-31 13:03:16 +01:00
D8H
f393f36bad Add a tooltip on some physics properties (#7262) 2024-12-30 18:23:20 +01:00
Florian Rival
5261f5a431 Remove logs for audio events when manipulating a sound/music on an unused channel (#7260) 2024-12-29 15:50:05 +01:00
AlexandreS
1a6cf8d69a Paginate feedbacks (#7259)
Also:
* Display 3 last projects only in context menu
2024-12-27 14:09:45 +01:00
AlexandreS
e93b38fee4 Fix asset preview being too zoomed in (#7255) 2024-12-27 14:08:06 +01:00
Florian Rival
22c7215071 Increase bottom drawer bottom margin on mobile
Don't show in changelog
2024-12-22 13:06:01 +01:00
Florian Rival
a221990c57 Ensure Home tab still shown when project opened on small screens
* Also smoothly scroll to the active tab
2024-12-22 12:43:33 +01:00
AlexandreS
85f6e74a5c Fix mobile horizontal scroll (#7254)
Don't show in changelog
2024-12-20 10:57:46 +01:00
Florian Rival
6577432b27 Bump newIDE version 2024-12-19 16:59:15 +01:00
AlexandreS
16d94b5e38 When duplicating a project, ask for the new name and if link with game should be kept (#7253)
Don't show in changelog
2024-12-19 16:50:38 +01:00
Florian Rival
88a2060364 Fix warning 2024-12-19 16:12:59 +01:00
Florian Rival
2d0ffee102 Improve subscription dialog and profile 2024-12-19 15:39:35 +01:00
D8H
aa30f3c465 Fix a regression on parameter editor lock (#7249)
Do not show in changelog
2024-12-19 11:43:41 +01:00
github-actions[bot]
cfcb4b557f Update translations [skip ci] (#7248)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-12-19 11:42:58 +01:00
Clément Pasteau
d8db679a1d Show "Get Premium" button with enhanced colors (#7251) 2024-12-19 11:33:03 +01:00
Florian Rival
01503d46c1 Bump newIDE version 2024-12-18 18:16:59 +01:00
Florian Rival
02d44bbba4 Remove unused API method to initialize game rendering [skip ci] (#7235) 2024-12-18 18:16:13 +01:00
D8H
b6d8170a00 [3D character] Allow to set higher speed than the maximum speed (#7245)
Don't show in changelog
2024-12-18 18:15:50 +01:00
github-actions[bot]
554c4c8f58 Update translations [skip ci] (#7239)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-12-18 18:14:59 +01:00
D8H
9e29146841 Fix a regression on custom object life-cycle parameters not being locked (#7247) 2024-12-18 18:03:41 +01:00
AlexandreS
189e971cd2 Fix: Highlight the currently opened project if multiple projects with same uuid (#7244)
Don't show in changelog
2024-12-18 17:54:46 +01:00
Florian Rival
deab962081 Fix regression in extensions loading (#7242) 2024-12-18 12:26:56 +01:00
D8H
e2281dfd82 Add 3D physics and 3D character behaviors (#7149)
* The 3D physics engine is powered by [Jolt Physics](https://github.com/jrouwe/JoltPhysics) a modern, performant, battle-tested, fully featured 3D physics engine used in AAA games, like Horizon: Forbidden West. The new 3D physics engine is perfect for making FPS, TPS, 3D platformer and in the future 3D racing games or any 3D game.
* Similar to the 2D physics engine, you can add the 3D Physics behavior to your object. For example, add the behavior to platforms with the type set to "Static".
* You can choose the collider shape: box, sphere, cylinder or capsule and modify physics properties of the objects having this behavior - much like the 2D physics engine.
* For characters, a dedicated "3D Physics Character" behavior is available. Pair it with one or more additional behaviors to get controls working out of the box: "3D Shooter keyboard mapper", "3D Platformer keyboard mapper", etc...
* Take a look at the new examples to give it a try! New examples and behaviors will be progressively added.
2024-12-17 18:00:48 +01:00
AlexandreS
44daf709e4 Fix asset store display speed and reduce the burst of requests (#7241) 2024-12-17 17:37:02 +01:00
Florian Rival
c9e5272367 Allow to browse marketing boosts from analytics screen
Also fix a warning

Don't show in changelog
2024-12-17 16:38:11 +01:00
AlexandreS
63584d171f Change scene editor title depending if instance or object edited on mobile (#7240) 2024-12-17 14:07:51 +01:00
D8H
092efbe462 Merge the function properties and parameters tabs in the extension editor (#7231) 2024-12-17 13:18:38 +01:00
AlexandreS
fc86b4e2dd Fix: Apply z offset to instance even if no z in instance data (#7238) 2024-12-17 08:46:06 +01:00
github-actions[bot]
3415626552 Update translations [skip ci] (#7208)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-12-16 16:36:27 +01:00
AlexandreS
fd2e87cc5c Polishing the new Create tab (#7236)
Don't show in changelog
2024-12-16 15:46:32 +01:00
Clément Pasteau
ecc8c3176d Remove unnecessary templates page (#7234)
Do not show in changelog
2024-12-16 12:13:12 +01:00
Clément Pasteau
1c855226a8 Fix loader on games list (#7233)
Don't show in changelog
2024-12-16 11:22:59 +01:00
Clément Pasteau
558d3a869c Merge Build & Manage tabs (#7217)
* The games you create are now accessible in one place only, simplifying the whole creation experience
* From the Create tab, you can now access the projects you're working on, as well as manage the games you have published
2024-12-16 11:01:43 +01:00
Florian Rival
c22f8afaf1 Fix installing extensions with dependencies from assets (#7232)
Only show in developer changelog
2024-12-14 18:46:58 +01:00
Florian Rival
7ece6c6759 Fix warning 2024-12-14 17:50:49 +01:00
D8H
f1ac388c46 Adapt the condition column size in the Events Sheet (#7230)
* Also change the default extension editor layout.
2024-12-14 16:21:42 +01:00
D8H
8a0045b3b0 Rename events-function parameters in events (#7215) 2024-12-13 19:57:14 +01:00
AlexandreS
4bcac31489 Introduce step-by-step course to master GDevelop (#7223) 2024-12-13 17:52:32 +01:00
Dima Lifanchuk
ff1086ce3b Expose initializeRenderers and initializeCanvas to allow initializing the game rendering manually (#7224) 2024-12-13 16:01:18 +01:00
D8H
e5d77da357 Add and fix tests on boolean variable conditions (#7227)
- Don't show in changelog
2024-12-13 15:10:51 +01:00
AlexandreS
536b0d5c38 Fix title missing in curriculum lessons (#7226) 2024-12-13 09:53:51 +01:00
Florian Rival
ada7dba959 Fix installing assets with resource kinds like bitmap texts (#7222) 2024-12-09 18:29:20 +01:00
Florian Rival
1b0c088f71 Add error display for some obvious semantic/type errors in JavaScript code blocks 2024-12-03 18:25:25 +01:00
Florian Rival
b9b09c1fef Use a better looking invalid/missing texture placeholder (#7218) 2024-12-02 17:26:57 +01:00
Florian Rival
066c8cd387 Add description and screenshots for Rich PWA install (desktop) 2024-12-02 16:24:03 +01:00
Florian Rival
a06ef20011 Improve scripts to download release artifacts in parallel [skip ci]
Don't show in changelog
2024-11-30 20:33:25 +01:00
Florian Rival
2052db6a39 Fix test 2024-11-30 14:06:55 +01:00
danvervlad
35fd7e972b Allow to provide a canvas to be used for the game rendering instead of creating a new one (#7199)
Only show in developer changelog
2024-11-29 17:51:12 +01:00
D8H
d110e83f6f Fix a crash when Physics behavior is used on object smaller than 0.1 pixel (#7209) 2024-11-29 15:49:02 +01:00
Florian Rival
13bdfa4379 Add a test for ensuring default behaviors on objects (#7211) 2024-11-29 15:38:47 +01:00
D8H
689bc014f3 Fix isUsingLegacyInstancesRenderer attribute not being read (#7210)
- only show in dev changelog
2024-11-29 15:28:31 +01:00
Florian Rival
a4f7aa6c43 Fix default behaviors not added properly to objects in functions (#7206) 2024-11-29 14:13:09 +01:00
Florian Rival
39690d6a02 Bump newIDE version 2024-11-28 16:52:26 +01:00
github-actions[bot]
3260b285af Update translations [skip ci] (#7201)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-11-28 16:28:11 +01:00
D8H
8743f70aaf Disable the variable editor button for object parameters (#7202) 2024-11-28 16:05:49 +01:00
Florian Rival
eae75bdc72 Fix potential crashes in events function edition (#7204)
* Also hide object groups tabs in functions (unless there are groups already) - it's not recommended to use them anymore
2024-11-28 14:00:01 +01:00
D8H
825cff7ba3 Fix function configuration editor layout when shown as a side panel (#7203) 2024-11-28 13:57:23 +01:00
D8H
aa12248d86 Fix custom objects inner area expansion on Z axis (#7200) 2024-11-27 14:54:45 +01:00
github-actions[bot]
d0f3abc38d Update translations [skip ci] (#7196)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-11-27 09:32:36 +01:00
D8H
e111706a27 Fix variables from being renamed with a property (#7186) 2024-11-26 17:58:59 +01:00
Florian Rival
e4f3db71c5 Allow opening a project linked to a game directly from the game dashboard (#7167) 2024-11-26 17:43:10 +01:00
Clément Pasteau
08a7949056 Fix keys (#7195)
Do not show in changelog
2024-11-26 15:42:04 +01:00
Florian Rival
1912916778 Add an option to keep layer centered when the game size changes, or keep top-left fixed (as before) (#7188)
* Also fix anchor behavior when used on layers where the camera was moved
2024-11-26 15:41:11 +01:00
D8H
59685bc4c4 Fix function sentence field content not wrapping (#7191) 2024-11-26 12:38:08 +01:00
github-actions[bot]
717948c558 Update translations [skip ci] (#7171)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-11-26 11:44:43 +01:00
D8H
a81c45f91a Fix position conflicts between Physics and other movement behaviors (#7189) 2024-11-26 11:25:41 +01:00
Clément Pasteau
76eaa747c9 Rework Game Creation dialog (#7179)
* It now becomes the entry point for creating a new game suggesting:
  * the empty project option (as before)
  * NEW: starting points for your projects, to bootstrap your platformer, top-down or physics game. They are extremely simple template, that can be used to avoid starting from scratch, which can be scary & difficult.
  * the list of finished games that be remixed into your own, with a search.
2024-11-25 14:20:58 +01:00
AlexandreS
26c95d1745 Show error box to user when an error occurred creating students (#7187) 2024-11-25 11:47:33 +01:00
Florian Rival
e0c72fd113 Improve typing of EventsFunctionContext 2024-11-22 17:24:20 +01:00
Clément Pasteau
2a6e98c27f Update publish flow to allow creating links if game is not owned (#7184) 2024-11-22 09:57:46 +01:00
AlexandreS
5f01ce8701 Initialize opacity at 255 for tilemaps (#7182)
Don't show in changelog
2024-11-21 15:52:20 +01:00
AlexandreS
6ed0e8e4cc Fix: Build tilemap renderer from an empty tilemap to be able to create tilemaps in-game (#7181) 2024-11-21 14:48:17 +01:00
Clément Pasteau
fbea483609 Remove games dashboard new feature highlight (#7180) 2024-11-21 14:44:51 +01:00
Aurélien Vivet
90004e3f83 Remove dead code regarding "alwaysLoaded" (#7175)
Only show in developer changelog
2024-11-20 21:32:00 +01:00
D8H
e6343dfe18 Fix the parameter name field to avoid changing the name when no change was done (#7178) 2024-11-20 18:48:04 +01:00
Florian Rival
ac6b64ba9b Add an option to extend width or height and never crop the game area (#7177) 2024-11-20 16:53:47 +01:00
Florian Rival
44b18cb111 Upload files in batch for web-app previews (#7176)
Only show in developer changelog
2024-11-18 17:36:00 +01:00
Clément Pasteau
c5fc7e08f5 Update marketing boosts display (#7174) 2024-11-18 15:30:22 +01:00
Florian Rival
9eada905f9 Add "Create new folder" menu item inside "Move to folder" menu (#7172) 2024-11-18 11:28:40 +01:00
Clément Pasteau
13aab9a8e8 Improve LAN preview network to detect local ip properly (#7170) 2024-11-18 10:29:17 +01:00
github-actions[bot]
dda85cf630 Update translations [skip ci] (#7163)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-11-15 10:39:57 +01:00
Clément Pasteau
0f81e4c088 Fixes game dashboard (#7166)
Do not show in changelog
2024-11-14 18:27:52 +01:00
Clément Pasteau
5419493349 Fix height when switching to mobile design (#7165) 2024-11-14 16:41:23 +01:00
Clément Pasteau
272766c705 Automatically use a screenshot from the latest preview as the game thumbnail if none are set (#7156) 2024-11-14 12:07:09 +01:00
D8H
a06138b31e Fix sprite scaling factor when a custom size is set (#7164) 2024-11-14 11:09:07 +01:00
Florian Rival
74a7ba5a09 Bump newIDE version 2024-11-14 09:54:25 +01:00
github-actions[bot]
3914d0377f Update translations [skip ci] (#7158)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-11-14 09:50:18 +01:00
D8H
092b29fa0e Fix uninitialized members in default constructor of ProjectScopedContainers (#7162)
Don't show in changelog
2024-11-13 17:39:20 +01:00
D8H
16762960dc Allow legacy scene variable parameters to use extension variables (#7121) 2024-11-13 17:17:02 +01:00
Clément Pasteau
33101ead64 Fix correctly using the app icon when exporting to desktop (#7161) 2024-11-13 17:08:24 +01:00
D8H
de73d617b0 Fix missing error in expressions for missing object variables with children (#7159) 2024-11-13 16:16:46 +01:00
D8H
446b0db05f Reduce the risk of name collisions between objects, variables, parameters and properties (#7148) 2024-11-13 15:16:41 +01:00
Clément Pasteau
66ab7abab7 Fix default color values for shape painter (#7155) 2024-11-13 11:59:53 +01:00
Clément Pasteau
a80b540f06 Fix game dashboard param (#7157)
Don't show in changelog
2024-11-13 11:56:00 +01:00
github-actions[bot]
38761aeec1 Update translations [skip ci] (#7153)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-11-13 11:00:11 +01:00
Clément Pasteau
602dc9d791 Improve login & signup dialogs design (#7152) 2024-11-13 10:23:02 +01:00
Florian Rival
162a70316a Make resource import error dialog less scary
Don't show in changelog
2024-11-12 18:27:37 +01:00
github-actions[bot]
10e8094375 Update translations [skip ci] (#7147)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-11-12 18:26:26 +01:00
AlexandreS
82af8dd7f3 Reduce the number of refreshes of the team when opening the profile dialog (#7150)
Do not show in changelog
2024-11-12 18:16:44 +01:00
Clément Pasteau
8cf739aa78 Merge Community & Play tabs (#7139) 2024-11-12 18:15:19 +01:00
AlexandreS
f3f3d24706 Deprecate google drive support (#7151) 2024-11-12 18:13:04 +01:00
Florian Rival
83f80b2350 Move back up links in Learn page and question block 2024-11-12 17:27:05 +01:00
danvervlad
1172326ae0 Add "dispose" method to RuntimeGame and various classes (#7118)
* This allows to fully release resources, textures and anything else that is linked to a gdjs.RuntimeGame. This can be useful if multiple games must be loaded/unloaded/changed in a single web page.

Only show in developer changelog
2024-11-12 17:19:50 +01:00
AlexandreS
aed09d86b3 Improve landscape mode and responsiveness of the UI on small screens (#7142) 2024-11-12 15:40:43 +01:00
Florian Rival
c2d03050b8 Add sort field (creation date, weekly sessions, all time sessions) for the list of games in the Manage tab 2024-11-11 17:50:59 +01:00
D8H
2e941c5afc Add tests on property renaming in expressions (#7146)
- Don't show in changelog
2024-11-11 17:23:18 +01:00
Florian Rival
a3f80f2607 Fix metrics in the new game dashboard wrongly limited to 7 days
Don't show in changelog
2024-11-11 16:42:20 +01:00
github-actions[bot]
3497eb2945 Update translations [skip ci] (#7127)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-11-11 15:18:16 +01:00
MTSyntho
b9a1f50d13 Add mention to Three.js in README (#7144) 2024-11-10 19:22:18 +01:00
Florian Rival
52d239b60c Add a button to ask any question in the Learn page (#7143) 2024-11-10 15:36:49 +01:00
AlexandreS
c549e277a7 Various fixes for the new game dashboard (#7141)
Don't show in changelog
2024-11-08 17:27:04 +01:00
inspace
afed5d57f7 Only add watermark styles in case showWatermark is true (#7140)
* This avoids using a DOM API if not needed.

Only show in developer changelog
2024-11-08 16:27:59 +01:00
D8H
a3f7176c42 [Physics2] Fix a memory leak on object instances (#7136) 2024-11-08 14:53:38 +01:00
Florian Rival
223268554b Fix Dialogue Tree returning sometimes a string instead of a number in expressions reading variables 2024-11-08 13:46:13 +01:00
AlexandreS
43ef037a07 Display game-related data and services in a dashboard (#7114) 2024-11-08 11:55:43 +01:00
Clément Pasteau
20d2e06fc6 Fix login dialog stuck in loading after trying to use a provider (#7138) 2024-11-07 17:52:55 +01:00
Clément Pasteau
9f795c405a Fix destroying an object even if flagged as "DoNothing" in the multiplayer behavior (#7137) 2024-11-07 14:08:02 +01:00
Florian Rival
0155344ec3 Fix dialogue tree crashing the game when syntax errors are present 2024-11-06 20:09:51 +01:00
Clément Pasteau
71d6d6a165 Fix thumbnail height for screenshots in quick customization (#7134)
Don't show in changelog
2024-11-06 16:04:07 +01:00
Clément Pasteau
edd14b5f8b Fix thumbnail condition in marketing package (#7133)
Do not show in changelog
2024-11-06 15:30:44 +01:00
Clément Pasteau
77d60b699b Prevent opening variables dialog for objects & groups if there is no object (#7132) 2024-11-06 14:49:16 +01:00
Florian Rival
5bc80537b7 Fix leaderboards not properly replaced in projects using them in custom objects (#7131) 2024-11-06 12:46:34 +01:00
Clément Pasteau
f93b850382 Improve object collision masks & points dialog button label (#7130) 2024-11-06 10:13:16 +01:00
Clément Pasteau
da7cae08a1 Fix game thumbnail taking too much space on mobile in Quick Customization dialog (#7128) 2024-11-05 14:46:54 +01:00
Florian Rival
0ae68877b7 Fix centering of "UI layers" after a screen orientation change (#7126)
* This happened often on mobile (iOS notably) and sometimes when resizing the window on desktop too.
2024-11-05 13:45:54 +01:00
github-actions[bot]
32c4e040e0 Update translations [skip ci] (#7120)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-11-05 11:44:03 +01:00
D8H
74034a0ac1 Show object effect drop-down list for parameters in extension editor (#7119)
- Shows object thumbnails in custom objects event functions
2024-10-31 17:02:39 +01:00
github-actions[bot]
1b41225822 Update translations [skip ci] (#7113)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-10-31 11:34:24 +01:00
Clément Pasteau
c620ed75b3 Take automatic game screenshots in Quick Customization previews (#7116) 2024-10-31 11:33:58 +01:00
Florian Rival
edc577067b Add comments to document a risk with ProjectScopedContainers
This is when used with custom objects for editing objects.

Only show in developer changelog
2024-10-31 11:01:41 +01:00
D8H
e00a85909d Replace the "add folder" button by a drop-down menu action (#7117) 2024-10-31 10:51:57 +01:00
D8H
70e6fc7f7f Add a button at the top of the object list to add new objects (#7111) 2024-10-29 16:52:04 +01:00
D8H
b9a899f82e Fix 3D model sizes in the editor when aspect ratio is free (#7115) 2024-10-29 16:46:33 +01:00
Arthur Pacaud (arthuro555)
c38d14ca83 Add gdcore-tools hook (#7112)
Only show in developer changelog
2024-10-29 09:26:48 +01:00
github-actions[bot]
e6b6406a95 Update translations [skip ci] (#7110)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-10-28 09:39:16 +01:00
Florian Rival
ff7c6de660 Fix issues when reworking a quick customization project (#7109)
* Don't duplicate the project multiple times if already saved
* When the game is exported a second time, the game page was not properly updated
2024-10-25 18:34:26 +02:00
github-actions[bot]
8d78ec6070 Update translations [skip ci] (#7104)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-10-25 15:43:53 +02:00
Florian Rival
3c2876e08d Fix adding an object from context menu when the Objects panel is closed (#7107) 2024-10-25 10:21:10 +02:00
Clément Pasteau
a68bac6667 Allow uploading gd.games thumbnail directly from the Game Dashboard (#7106) 2024-10-25 09:39:10 +02:00
Florian Rival
53eafe098c Don't show save reminders in quick customization 2024-10-24 17:17:24 +02:00
AlexandreS
ab519d41a1 Fix instances paste from a scene to another (#7105)
Also:
- Fix instance variable editor opening in CustomObject editor
- Fix tilemap painting in CustomObject editor
2024-10-23 17:53:31 +02:00
D8H
5ea03b83f0 Fix a crash at runtime when an animatable custom object has no animation (#7102) 2024-10-23 15:09:06 +02:00
github-actions[bot]
f2d4778459 Update translations [skip ci] (#7098)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-10-23 09:44:39 +02:00
Clément Pasteau
56662fb9b5 Add warnings for variables ownership (#7100)
Do not show in changelog
2024-10-22 18:41:45 +02:00
Clément Pasteau
0788de3d87 UX Improvements across the app (#7099)
* Make New project dialog simpler
* Prevent icons from being always at the end on RTL languages
* Improve number of items displayed on mobile across the app
* Hide tabs in Resources if only 1 is available
2024-10-22 16:29:31 +02:00
AlexandreS
6b7bc361a7 Bump newIDE version (#7097) 2024-10-22 15:05:52 +02:00
github-actions[bot]
32a6e188e7 Update translations [skip ci] (#7088) 2024-10-22 15:03:49 +02:00
D8H
00f67ca7c7 Allow custom objects to use leaderboard properties (#7081) 2024-10-22 14:43:47 +02:00
AlexandreS
bb5291ac6f Improve Max projects callout (#7096)
Don't show in changelog
2024-10-22 11:38:21 +02:00
D8H
a2ea751007 Fix to forbid behavior properties from being used as values in expressions (#7095) 2024-10-21 19:58:32 +02:00
D8H
1a4270195b Fix autocompletion by hiding parameters and properties of type "behavior" (#7094) 2024-10-21 18:46:30 +02:00
D8H
3df42cce3e Fix default parameter of action with operator functions not displaying in the editor (#7093) 2024-10-21 17:48:34 +02:00
D8H
b8de302f7e Optimize custom object layouting in the editor (#7090) 2024-10-21 15:16:06 +02:00
AlexandreS
6a2bc6109c Display Audio Resource parameter field for functions actions (#7092) 2024-10-21 14:54:46 +02:00
D8H
0383f8a7e1 Fix text input visibility when its custom object is hidden (#7089) 2024-10-21 12:41:47 +02:00
D8H
bde7e1896d Fix a crash when an instance with a wrong object name is in a custom object (#7079) 2024-10-21 10:23:46 +02:00
github-actions[bot]
32d855992e Update translations [skip ci] (#7075)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-10-21 09:14:26 +02:00
Florian Rival
d54c1e2f38 Display context menu using an "action sheet" like drawer on mobile/touchscreens (#7087) 2024-10-20 21:47:22 +02:00
D8H
f09a1dd5b2 Fix wrong custom objects duplication when updating an extension (#7086) 2024-10-20 21:26:45 +02:00
Florian Rival
f4e3f2449a Add larger buttons in quick customization and danger buttons in some interfaces 2024-10-19 19:23:46 +02:00
Florian Rival
a6b2cba281 Update wording [skip ci]
Don't show in changelog
2024-10-19 16:37:24 +02:00
Florian Rival
54237114d9 Ensure GDevelop.js build is done using release mode if not specified [skip ci]
Only show in developer changelog
2024-10-19 16:30:23 +02:00
Florian Rival
3c5bcf2762 Add preview analytics to understand if done by new users
Don't show in changelog
2024-10-19 16:27:54 +02:00
D8H
d66ea06a4c Fix resource used in behavior properties not being exported (#7084)
Only show in developer changelog
2024-10-18 18:45:52 +02:00
AlexandreS
228479c81b Fix check on cloud projects count (#7083)
Don't show in changelog
2024-10-18 16:41:15 +02:00
AlexandreS
1e55c359d8 Fix changing the shape painter colors in the properties panel/object editor (#7082) 2024-10-18 14:24:46 +02:00
1378 changed files with 84804 additions and 30333 deletions

View File

@@ -14,7 +14,7 @@ orbs:
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 the **entire** app for macOS (including the GDevelop.js library).
build-macos:
macos:
xcode: 14.2.0
@@ -94,7 +94,7 @@ jobs:
name: Deploy to S3 (latest)
command: export PATH=~/.local/bin:$PATH && aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/latest/
# Build the **entire** app for Linux.
# Build the app for Linux (using a pre-built GDevelop.js library).
build-linux:
# CircleCI docker workers are failing if they don't have enough memory (no swap)
resource_class: xlarge
@@ -107,44 +107,25 @@ jobs:
- checkout
- aws-cli/setup
# System dependencies (for Electron Builder and Emscripten)
# System dependencies (for Electron Builder)
- run:
name: Install dependencies for Emscripten
command: sudo apt-get update && sudo apt install cmake
- run:
name: Install Python3 dependencies for Emscripten
command: sudo apt install python-is-python3 python3-distutils -y
- 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 ..
name: Update system dependencies
command: sudo apt-get update
- run:
name: Install system dependencies for Electron builder
command: sudo apt install icnsutils && sudo apt install graphicsmagick && sudo apt install rsync
# GDevelop.js dependencies
- restore_cache:
keys:
- gd-linux-nodejs-dependencies-{{ checksum "newIDE/app/package.json" }}-{{ checksum "newIDE/electron-app/package.json" }}-{{ checksum "GDevelop.js/package.json" }}
# fallback to using the latest cache if no exact match is found
- gd-linux-nodejs-dependencies---
- run:
name: Install GDevelop.js dependencies and build it
command: cd GDevelop.js && npm install && cd ..
# Build GDevelop.js (and run tests to ensure it works)
- run:
name: Build GDevelop.js
# Use "--runInBand" as it's faster and avoid deadlocks on CircleCI Linux machines (probably because limited in processes number).
command: cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build && npm test -- --runInBand && cd ..
# GDevelop IDE dependencies (after building GDevelop.js to avoid downloading a pre-built version)
# GDevelop IDE dependencies (using an exact version of GDevelop.js, built previously)
- run:
name: Install GDevelop IDE dependencies
command: cd newIDE/app && npm install && cd ../electron-app && npm install
command: export REQUIRES_EXACT_LIBGD_JS_VERSION=true && cd newIDE/app && npm install && cd ../electron-app && npm install
- save_cache:
paths:
@@ -295,10 +276,26 @@ jobs:
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)/
# Trigger AppVeyor build, which finishes building the Windows app
# (using GDevelop.js built in a previous step).
trigger-appveyor-windows-build:
docker:
- image: cimg/node:16.13
steps:
- run:
name: Trigger AppVeyor Windows build
command: |
curl -H "Content-Type: application/json" \
-H "Authorization: Bearer ${APPVEYOR_API_KEY}" \
--data "{
\"accountName\": \"4ian\",
\"projectSlug\": \"gdevelop\",
\"branch\": \"${CIRCLE_BRANCH}\"
}" \
-X POST https://ci.appveyor.com/api/builds
workflows:
gdevelop_js-wasm:
jobs:
- build-gdevelop_js-wasm-only
gdevelop_js-wasm-extra-checks:
jobs:
- build-gdevelop_js-debug-sanitizers-and-extra-checks:
@@ -310,13 +307,28 @@ workflows:
- /experimental-build.*/
builds:
jobs:
- build-gdevelop_js-wasm-only
- build-macos:
# The macOS version builds by itself GDevelop.js
# (so we verify we can build it on macOS).
# requires:
# - build-gdevelop_js-wasm-only
filters:
branches:
only:
- master
- /experimental-build.*/
- build-linux:
requires:
- build-gdevelop_js-wasm-only
filters:
branches:
only:
- master
- /experimental-build.*/
- trigger-appveyor-windows-build:
requires:
- build-gdevelop_js-wasm-only
filters:
branches:
only:

1
.gitattributes vendored
View File

@@ -3,6 +3,7 @@ Extensions/ParticleSystem/SPARK/* linguist-vendored
Extensions/PhysicsBehavior/Box2D/* linguist-vendored
Extensions/PhysicsBehavior/box2djs/* linguist-vendored
Extensions/Physics2Behavior/box2d.js linguist-vendored
Extensions/Physics3DBehavior/*.wasm-compat.js linguist-vendored
Extensions/BBText/pixi-multistyle-text/* linguist-vendored
Extensions/P2P/A_peer.js linguist-vendored
Extensions/Multiplayer/peer.js linguist-vendored

22
.github/workflows/gdcore-tools-hook.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
# This worflow notifies arthuro555's gdcore-tools repository when a new release is published.
#
# This is used to allow gdcore-tools, a library to use GDCore outside of GDevelop,
# to attempt to automatically build, test, and publish a release for the new
# GDevelop version.
name: Trigger gdcore-tools pipeline
on:
release:
types: [published]
jobs:
dispatch-event:
runs-on: ubuntu-latest
steps:
- name: Repository Dispatch
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.GDCORE_TOOLS_PAT }}
repository: arthuro555/gdcore-tools
event-type: gdevelop-release
client-payload: '{"release": ${{ toJson(github.event.release) }}}'

View File

@@ -0,0 +1,47 @@
# GitHub Action to update extension translations.
# It copies the latest messages.js files from the GDevelop-extensions repository
# and opens a Pull Request with the changes on GDevelop's repository.
name: Update extension translations
on:
push:
branches:
- master
tags-ignore:
- "**" # Don't run on new tags
workflow_dispatch: # Allows manual triggering from the Actions tab
jobs:
update-extension-translations:
runs-on: ubuntu-latest
steps:
- name: Checkout current repository
uses: actions/checkout@v3
- name: Clone GDevelop-extensions repository
run: git clone https://github.com/GDevelopApp/GDevelop-extensions.git /tmp/GDevelop-extensions
- name: Copy and rename translation files
run: |
mkdir -p newIDE/app/src/locales
for folder in /tmp/GDevelop-extensions/.translations/*; do
if [ -d "$folder" ]; then
lang=$(basename "$folder")
mkdir -p "newIDE/app/src/locales/$lang"
cp "$folder/messages.js" "newIDE/app/src/locales/$lang/extension-messages.js"
fi
done
cp /tmp/GDevelop-extensions/.translations/LocalesMetadata.js newIDE/app/src/locales/ExtensionLocalesMetadata.js
- name: Create Pull Request with updated translations
uses: peter-evans/create-pull-request@v6
with:
commit-message: Update extension translations [skip ci]
branch: chore/update-extension-translations
delete-branch: true
title: "[Auto PR] Update extension translations"
body: |
This updates the extension translations by copying the latest messages.js files from the GDevelop-extensions repository.
Each messages.js file is renamed to extension-messages.js and placed in the corresponding language folder under `newIDE/app/src/locales`.
Please review the changes carefully before merging.

View File

@@ -1358,12 +1358,30 @@ gd::String EventsCodeGenerator::GeneratePropertyGetter(const gd::PropertiesConta
return "getProperty" + property.GetName() + "As" + type + "()";
}
gd::String EventsCodeGenerator::GeneratePropertyGetterWithoutCasting(
const gd::PropertiesContainer &propertiesContainer,
const gd::NamedPropertyDescriptor &property) {
return "getProperty" + property.GetName() + "()";
}
gd::String EventsCodeGenerator::GeneratePropertySetterWithoutCasting(
const gd::PropertiesContainer &propertiesContainer,
const gd::NamedPropertyDescriptor &property,
const gd::String &operandCode) {
return "setProperty" + property.GetName() + "(" + operandCode + ")";
}
gd::String EventsCodeGenerator::GenerateParameterGetter(const gd::ParameterMetadata& parameter,
const gd::String& type,
gd::EventsCodeGenerationContext& context) {
return "getParameter" + parameter.GetName() + "As" + type + "()";
}
gd::String EventsCodeGenerator::GenerateParameterGetterWithoutCasting(
const gd::ParameterMetadata &parameter) {
return "getParameter" + parameter.GetName() + "()";
}
EventsCodeGenerator::EventsCodeGenerator(const gd::Project& project_,
const gd::Layout& layout,
const gd::Platform& platform_)

View File

@@ -467,7 +467,14 @@ class GD_CORE_API EventsCodeGenerator {
*/
virtual gd::String GetCodeNamespace() { return ""; };
enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE, ANY_VARIABLE };
enum VariableScope {
LAYOUT_VARIABLE = 0,
PROJECT_VARIABLE,
OBJECT_VARIABLE,
ANY_VARIABLE,
VARIABLE_OR_PROPERTY,
VARIABLE_OR_PROPERTY_OR_PARAMETER
};
/**
* Generate a single unique number for the specified instruction.
@@ -510,6 +517,11 @@ class GD_CORE_API EventsCodeGenerator {
GenerateAnyOrSceneVariableGetter(const gd::Expression &variableExpression,
EventsCodeGenerationContext &context);
virtual gd::String GeneratePropertySetterWithoutCasting(
const gd::PropertiesContainer &propertiesContainer,
const gd::NamedPropertyDescriptor &property,
const gd::String &operandCode);
protected:
virtual const gd::String GenerateRelationalOperatorCodes(
const gd::String& operatorString);
@@ -565,7 +577,8 @@ protected:
const gd::String& variableName,
const VariableScope& scope,
gd::EventsCodeGenerationContext& context,
const gd::String& objectName) {
const gd::String& objectName,
bool hasChild) {
// This code is only used as a mock.
// See the real implementation in GDJS.
if (scope == LAYOUT_VARIABLE) {
@@ -573,7 +586,9 @@ protected:
} else if (scope == PROJECT_VARIABLE) {
return "getProjectVariable(" + variableName + ")";
} else if (scope == ANY_VARIABLE) {
} else if (scope == ANY_VARIABLE || scope == VARIABLE_OR_PROPERTY ||
scope == VARIABLE_OR_PROPERTY_OR_PARAMETER) {
// TODO Split the 3 cases to make tests stronger.
return "getAnyVariable(" + variableName + ")";
}
@@ -627,11 +642,18 @@ protected:
const gd::String& type,
gd::EventsCodeGenerationContext& context);
virtual gd::String GeneratePropertyGetterWithoutCasting(
const gd::PropertiesContainer &propertiesContainer,
const gd::NamedPropertyDescriptor &property);
virtual gd::String GenerateParameterGetter(
const gd::ParameterMetadata& parameter,
const gd::String& type,
gd::EventsCodeGenerationContext& context);
virtual gd::String
GenerateParameterGetterWithoutCasting(const gd::ParameterMetadata &parameter);
/**
* \brief Generate the code to reference an object which is
* in an empty/null state.

View File

@@ -135,18 +135,20 @@ void ExpressionCodeGenerator::OnVisitVariableNode(VariableNode& node) {
EventsCodeGenerator::VariableScope scope =
type == "variable"
? gd::EventsCodeGenerator::ANY_VARIABLE
: type == "globalvar"
? gd::EventsCodeGenerator::PROJECT_VARIABLE
: type == "scenevar"
? gd::EventsCodeGenerator::LAYOUT_VARIABLE
: gd::EventsCodeGenerator::OBJECT_VARIABLE;
: type == "variableOrProperty"
? gd::EventsCodeGenerator::VARIABLE_OR_PROPERTY
: type == "variableOrPropertyOrParameter"
? gd::EventsCodeGenerator::VARIABLE_OR_PROPERTY_OR_PARAMETER
: type == "globalvar" ? gd::EventsCodeGenerator::PROJECT_VARIABLE
: type == "scenevar" ? gd::EventsCodeGenerator::LAYOUT_VARIABLE
: gd::EventsCodeGenerator::OBJECT_VARIABLE;
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
codeGenerator.GetObjectsContainersList(),
rootObjectName,
node);
output += codeGenerator.GenerateGetVariable(
node.name, scope, context, objectName);
node.name, scope, context, objectName, node.child != nullptr);
if (node.child) node.child->Visit(*this);
} else {
// The node represents a variable or an object variable in an expression waiting for its *value* to be returned.
@@ -163,7 +165,7 @@ void ExpressionCodeGenerator::OnVisitVariableNode(VariableNode& node) {
output += codeGenerator.GenerateVariableValueAs(type);
}, [&]() {
output += codeGenerator.GenerateGetVariable(
node.name, gd::EventsCodeGenerator::ANY_VARIABLE, context, "");
node.name, gd::EventsCodeGenerator::ANY_VARIABLE, context, "", node.child != nullptr);
if (node.child) node.child->Visit(*this);
output += codeGenerator.GenerateVariableValueAs(type);
}, [&]() {
@@ -184,8 +186,9 @@ void ExpressionCodeGenerator::OnVisitVariableAccessorNode(
VariableAccessorNode& node) {
if (!objectNameToUseForVariableAccessor.empty()) {
// Use the name of the object passed by the parent, as we need both to access an object variable.
output += codeGenerator.GenerateGetVariable(node.name,
gd::EventsCodeGenerator::OBJECT_VARIABLE, context, objectNameToUseForVariableAccessor);
output += codeGenerator.GenerateGetVariable(
node.name, gd::EventsCodeGenerator::OBJECT_VARIABLE, context,
objectNameToUseForVariableAccessor, node.child != nullptr);
// We have accessed an object variable, from now we can continue accessing the child variables
// (including using the bracket notation).
@@ -222,24 +225,27 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
output +=
codeGenerator.GenerateObject(node.identifierName, type, context);
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
EventsCodeGenerator::VariableScope scope =
EventsCodeGenerator::VariableScope scope =
type == "variable"
? gd::EventsCodeGenerator::ANY_VARIABLE
: type == "globalvar"
? gd::EventsCodeGenerator::PROJECT_VARIABLE
: type == "scenevar"
? gd::EventsCodeGenerator::LAYOUT_VARIABLE
: gd::EventsCodeGenerator::OBJECT_VARIABLE;
: type == "variableOrProperty"
? gd::EventsCodeGenerator::VARIABLE_OR_PROPERTY
: type == "variableOrPropertyOrParameter"
? gd::EventsCodeGenerator::VARIABLE_OR_PROPERTY_OR_PARAMETER
: type == "globalvar" ? gd::EventsCodeGenerator::PROJECT_VARIABLE
: type == "scenevar" ? gd::EventsCodeGenerator::LAYOUT_VARIABLE
: gd::EventsCodeGenerator::OBJECT_VARIABLE;
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
codeGenerator.GetObjectsContainersList(),
rootObjectName,
node);
output += codeGenerator.GenerateGetVariable(
node.identifierName, scope, context, objectName);
if (!node.childIdentifierName.empty()) {
output += codeGenerator.GenerateVariableAccessor(node.childIdentifierName);
}
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
codeGenerator.GetPlatform(), codeGenerator.GetObjectsContainersList(),
rootObjectName, node);
output += codeGenerator.GenerateGetVariable(
node.identifierName, scope, context, objectName,
!node.childIdentifierName.empty());
if (!node.childIdentifierName.empty()) {
output +=
codeGenerator.GenerateVariableAccessor(node.childIdentifierName);
}
} else {
const auto& variablesContainersList = codeGenerator.GetProjectScopedContainers().GetVariablesContainersList();
const auto& propertiesContainersList = codeGenerator.GetProjectScopedContainers().GetPropertiesContainersList();
@@ -249,12 +255,13 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
codeGenerator.GetProjectScopedContainers().MatchIdentifierWithName<void>(node.identifierName, [&]() {
// Generate the code to access the object variable.
output += codeGenerator.GenerateGetVariable(
node.childIdentifierName, gd::EventsCodeGenerator::OBJECT_VARIABLE, context, node.identifierName);
node.childIdentifierName, gd::EventsCodeGenerator::OBJECT_VARIABLE,
context, node.identifierName, !node.childIdentifierName.empty());
output += codeGenerator.GenerateVariableValueAs(type);
}, [&]() {
output += codeGenerator.GenerateGetVariable(
node.identifierName, gd::EventsCodeGenerator::ANY_VARIABLE, context,
"");
node.identifierName, gd::EventsCodeGenerator::VARIABLE_OR_PROPERTY_OR_PARAMETER, context,
"", !node.childIdentifierName.empty());
if (!node.childIdentifierName.empty()) {
output += codeGenerator.GenerateVariableAccessor(node.childIdentifierName);
}

View File

@@ -18,8 +18,6 @@ namespace gd {
EventsList BaseEvent::badSubEvents;
VariablesContainer BaseEvent::badLocalVariables;
std::vector<gd::String> BaseEvent::emptyDependencies;
gd::String BaseEvent::emptySourceFile;
BaseEvent::BaseEvent()
: totalTimeDuringLastSession(0),

View File

@@ -175,26 +175,6 @@ class GD_CORE_API BaseEvent {
noExpr;
return noExpr;
};
/**
* \brief Returns the dependencies on source files of the project.
* \note Default implementation returns an empty list of dependencies. This is
* fine for most events that are not related to adding custom user source
* code.
*/
virtual const std::vector<gd::String>& GetSourceFileDependencies() const {
return emptyDependencies;
};
/**
* \brief Returns the name of the source file associated with the event
* \note Default implementation returns an empty string. This is fine for most
* events that are not related to adding custom user source code.
*/
virtual const gd::String& GetAssociatedGDManagedSourceFile(
gd::Project& project) const {
return emptySourceFile;
};
///@}
/** \name Code generation
@@ -327,8 +307,6 @@ class GD_CORE_API BaseEvent {
static gd::EventsList badSubEvents;
static gd::VariablesContainer badLocalVariables;
static std::vector<gd::String> emptyDependencies;
static gd::String emptySourceFile;
};
/**

View File

@@ -141,7 +141,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
"res/function32.png")
.AddParameter("functionParameterName", _("Parameter name"), "number,string,boolean")
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetHidden();
extension
.AddExpression(
@@ -177,7 +178,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
.AddParameter("functionParameterName", _("Parameter name"), "number,string,boolean")
.UseStandardRelationalOperatorParameters(
"number", gd::ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddCondition(
@@ -191,7 +193,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
.AddParameter("functionParameterName", _("Parameter name"), "number,string,boolean")
.UseStandardRelationalOperatorParameters(
"string", gd::ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
}
} // namespace gd

View File

@@ -117,7 +117,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Change the position of the center of _PARAM0_: _PARAM1_ "
"_PARAM2_ (x "
"axis), _PARAM3_ _PARAM4_ (y axis)"),
_("Position/Center"),
_("Position Center"),
"res/actions/position24_black.png",
"res/actions/position_black.png")
.AddParameter("object", _("Object"))
@@ -133,7 +133,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Center X position"),
_("the X position of the center of rotation"),
_("the X position of the center"),
_("Position/Center"),
_("Position Center"),
"res/actions/position24_black.png")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -144,7 +144,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Center Y position"),
_("the Y position of the center of rotation"),
_("the Y position of the center"),
_("Position/Center"),
_("Position Center"),
"res/actions/position24_black.png")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -155,7 +155,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the bounding box (the area encapsulating "
"the object) left position"),
_("the bounding box left position"),
_("Position/Bounding Box"),
_("Position Bounding Box"),
"res/conditions/bounding-box-left_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -166,7 +166,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Bounding box top position"),
_("the bounding box (the area encapsulating the object) top position"),
_("the bounding box top position"),
_("Position/Bounding Box"),
_("Position Bounding Box"),
"res/conditions/bounding-box-top_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -177,7 +177,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the bounding box (the area encapsulating "
"the object) right position"),
_("the bounding box right position"),
_("Position/Bounding Box"),
_("Position Bounding Box"),
"res/conditions/bounding-box-right_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -188,7 +188,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the bounding box (the area encapsulating "
"the object) bottom position"),
_("the bounding box bottom position"),
_("Position/Bounding Box"),
_("Position Bounding Box"),
"res/conditions/bounding-box-bottom_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -199,7 +199,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the bounding box (the area encapsulating "
"the object) center X position"),
_("the bounding box center X position"),
_("Position/Bounding Box"),
_("Position Bounding Box"),
"res/conditions/bounding-box-center_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -210,7 +210,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the bounding box (the area encapsulating "
"the object) center Y position"),
_("the bounding box center Y position"),
_("Position/Bounding Box"),
_("Position Bounding Box"),
"res/conditions/bounding-box-center_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -255,7 +255,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Angle"),
"res/actions/rotate24_black.png",
"res/actions/rotate_black.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angular speed (in degrees per second)"))
.AddCodeOnlyParameter("currentScene", "")
@@ -269,7 +268,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Angle"),
"res/actions/rotate24_black.png",
"res/actions/rotate_black.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angle to rotate towards (in degrees)"))
.AddParameter("expression", _("Angular speed (in degrees per second)"))
@@ -285,7 +283,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Angle"),
"res/actions/rotate24_black.png",
"res/actions/rotate_black.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("X position"))
.AddParameter("expression", _("Y position"))
@@ -304,12 +301,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Movement using forces"),
"res/actions/force24.png",
"res/actions/force.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Speed on X axis (in pixels per second)"))
.AddParameter("expression", _("Speed on Y axis (in pixels per second)"))
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
.SetDefaultValue("0");
.SetDefaultValue("0")
.SetHelpPath("/tutorials/how-to-move-objects/");
obj.AddAction("AddForceAL",
_("Add a force (angle)"),
@@ -321,12 +318,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Movement using forces"),
"res/actions/force24.png",
"res/actions/force.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angle"))
.AddParameter("expression", _("Speed (in pixels per second)"))
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
.SetDefaultValue("0")
.SetHelpPath("/tutorials/how-to-move-objects/")
.MarkAsAdvanced();
obj.AddAction(
@@ -339,13 +336,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Movement using forces"),
"res/actions/force24.png",
"res/actions/force.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("X position"))
.AddParameter("expression", _("Y position"))
.AddParameter("expression", _("Speed (in pixels per second)"))
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
.SetDefaultValue("0")
.SetHelpPath("/tutorials/how-to-move-objects/")
.MarkAsAdvanced();
obj.AddAction(
@@ -360,13 +357,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Movement using forces"),
"res/actions/forceTourne24.png",
"res/actions/forceTourne.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", "X position of the center")
.AddParameter("expression", "Y position of the center")
.AddParameter("expression", "Speed (in Degrees per seconds)")
.AddParameter("expression", "Distance (in pixels)")
.AddParameter("forceMultiplier", "Force multiplier")
.SetHelpPath("/tutorials/how-to-move-objects/")
.SetHidden();
obj.AddAction("Arreter",
@@ -376,8 +373,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Movement using forces"),
"res/actions/arreter24.png",
"res/actions/arreter.png")
.AddParameter("object", _("Object"))
.SetHelpPath("/tutorials/how-to-move-objects/")
.MarkAsAdvanced();
obj.AddAction("Delete",
@@ -418,7 +415,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.MarkAsAdvanced();
obj.AddAction("SetNumberObjectVariable",
_("Change variable value"),
_("Change object variable value"),
_("Modify the number value of an object variable."),
_("the variable _PARAM1_"),
_("Variables"),
@@ -429,10 +426,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectvar", _("Variable"))
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions())
.SetHelpPath("/all-features/variables/object-variables/")
.SetRelevantForLayoutEventsOnly();
obj.AddAction("SetStringObjectVariable",
_("Change text variable"),
_("Change object variable value"),
_("Modify the text of an object variable."),
_("the variable _PARAM1_"),
_("Variables"),
@@ -443,10 +441,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectvar", _("Variable"))
.UseStandardOperatorParameters("string",
ParameterOptions::MakeNewOptions())
.SetHelpPath("/all-features/variables/object-variables/")
.SetRelevantForLayoutEventsOnly();
obj.AddAction("SetBooleanObjectVariable",
_("Change boolean variable"),
_("Change object variable value"),
_("Modify the boolean value of an object variable."),
_("Change the variable _PARAM1_ of _PARAM0_: _PARAM2_"),
_("Variables"),
@@ -458,10 +457,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
// This parameter allows to keep the operand expression
// when the editor switch between variable instructions.
.AddCodeOnlyParameter("yesorno", _("Value"))
.SetHelpPath("/all-features/variables/object-variables/")
.SetRelevantForLayoutEventsOnly();
obj.AddCondition("NumberObjectVariable",
_("Variable value"),
_("Object variable value"),
_("Compare the number value of an object variable."),
_("the variable _PARAM1_"),
_("Variables"),
@@ -472,10 +472,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetHelpPath("/all-features/variables/object-variables/")
.SetRelevantForLayoutEventsOnly();
obj.AddCondition("StringObjectVariable",
_("Text variable"),
_("Object variable value"),
_("Compare the text of an object variable."),
_("the variable _PARAM1_"),
_("Variables"),
@@ -486,10 +487,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"string", ParameterOptions::MakeNewOptions())
.SetHelpPath("/all-features/variables/object-variables/")
.SetRelevantForLayoutEventsOnly();
obj.AddCondition("BooleanObjectVariable",
_("Boolean variable"),
_("Object variable value"),
_("Compare the boolean value of an object variable."),
_("The variable _PARAM1_ of _PARAM0_ is _PARAM2_"),
_("Variables"),
@@ -502,6 +504,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
// This parameter allows to keep the operand expression
// when the editor switch between variable instructions.
.AddCodeOnlyParameter("yesorno", _("Value"))
.SetHelpPath("/all-features/variables/object-variables/")
.SetRelevantForLayoutEventsOnly();
obj.AddAction("ModVarObjet",
@@ -514,6 +517,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.SetHelpPath("/all-features/variables/object-variables/")
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
@@ -528,6 +532,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.SetHelpPath("/all-features/variables/object-variables/")
.UseStandardOperatorParameters("string",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
@@ -544,6 +549,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.AddParameter("trueorfalse", _("New Value:"))
.SetHelpPath("/all-features/variables/object-variables/")
.SetRelevantForFunctionEventsOnly();
obj.AddAction(
@@ -560,6 +566,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.SetHelpPath("/all-features/variables/object-variables/")
.SetRelevantForFunctionEventsOnly();
obj.AddCondition("ObjectVariableChildExists",
@@ -567,24 +574,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Check if the specified child of the object "
"structure variable exists."),
_("Child _PARAM2_ of variable _PARAM1_ of _PARAM0_ exists"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Structure variable"))
.AddParameter("string", _("Name of the child"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced();
obj.AddAction("ObjectVariableRemoveChild",
_("Remove a child"),
_("Remove a child from an object structure variable."),
_("Remove child _PARAM2_ from variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Structure variable"))
.AddParameter("string", _("Child's name"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced();
obj.AddAction("ObjectVariableClearChildren",
@@ -592,11 +601,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Remove all the children from the object array or structure "
"variable."),
_("Clear children from variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array or structure variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced();
obj.AddAction("Cache",
@@ -691,8 +701,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Movement using forces"),
"res/conditions/arret24.png",
"res/conditions/arret.png")
.AddParameter("object", _("Object"))
.SetHelpPath("/tutorials/how-to-move-objects/")
.MarkAsAdvanced();
obj.AddCondition("Vitesse",
@@ -702,10 +712,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Movement using forces"),
"res/conditions/vitesse24.png",
"res/conditions/vitesse.png")
.AddParameter("object", _("Object"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetHelpPath("/tutorials/how-to-move-objects/")
.MarkAsAdvanced();
// Deprecated
@@ -722,6 +732,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angle, in degrees"))
.AddParameter("expression", _("Tolerance, in degrees"))
.SetHelpPath("/tutorials/how-to-move-objects/")
.MarkAsAdvanced();
obj.AddCondition("IsTotalForceAngleAround",
@@ -735,6 +746,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angle, in degrees"))
.AddParameter("expression", _("Tolerance, in degrees"))
.SetHelpPath("/tutorials/how-to-move-objects/")
.MarkAsAdvanced();
obj.AddCondition("VarObjet",
@@ -749,6 +761,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetHelpPath("/all-features/variables/object-variables/")
.SetRelevantForFunctionEventsOnly();
obj.AddCondition("VarObjetTxt",
@@ -763,6 +776,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"string", ParameterOptions::MakeNewOptions())
.SetHelpPath("/all-features/variables/object-variables/")
.SetRelevantForFunctionEventsOnly();
obj.AddCondition("ObjectVariableAsBoolean",
@@ -777,6 +791,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectvar", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true")
.SetHelpPath("/all-features/variables/object-variables/")
.SetRelevantForFunctionEventsOnly();
obj.AddCondition("VarObjetDef",
@@ -793,42 +808,45 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction(
"PushStringToObjectVariable",
_("Add text variable"),
_("Add value to object array 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"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("string", _("Text to add"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced()
.SetRelevantForLayoutEventsOnly();
obj.AddAction("PushNumberToObjectVariable",
_("Add variable array value"),
_("Add value to object array variable"),
_("Adds a number to the end of an object array variable."),
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("expression", _("Number to add"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced()
.SetRelevantForLayoutEventsOnly();
obj.AddAction(
"PushBooleanToObjectVariable",
_("Add boolean variable"),
_("Add value to object array 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"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("trueorfalse", _("Boolean to add"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced()
.SetRelevantForLayoutEventsOnly();
@@ -838,7 +856,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("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"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
@@ -847,6 +865,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.SetParameterLongDescription(_("The content of the object variable will "
"*be copied* and added at the "
"end of the array."))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced()
.SetHidden();
@@ -855,7 +874,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("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"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
@@ -864,6 +883,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.SetParameterLongDescription(_("The content of the object variable will "
"*be copied* and added at the "
"end of the array."))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced();
obj.AddAction(
@@ -871,12 +891,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Add text variable"),
_("Adds a text (string) to the end of an object array variable."),
_("Add text _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("string", _("Text to add"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
@@ -884,12 +905,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Add number variable"),
_("Adds a number to the end of an object array variable."),
_("Add number _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("expression", _("Number to add"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
@@ -898,12 +920,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Add boolean variable"),
_("Adds a boolean to the end of an object array variable."),
_("Add boolean _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("trueorfalse", _("Boolean to add"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
@@ -914,12 +937,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"variable."),
_("Remove variable at index _PARAM2_ from array variable _PARAM1_ of "
"_PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
.AddParameter("expression", _("Index to remove"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced();
obj.AddCondition(
@@ -927,13 +951,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Number of children"),
_("Compare the number of children in an object array variable."),
_("The number of children in the array variable _PARAM1_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced();
obj.AddStrExpression(
@@ -941,40 +966,44 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("First text child"),
_("Get the value of the first element of an object array variable, if "
"it is a text (string) variable."),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"));
.AddParameter("objectvar", _("Array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/");
obj.AddExpression(
"ArrayVariableFirstNumber",
_("First number child"),
_("Get the value of the first element of an object array variable, if "
"it is a number variable."),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"));
.AddParameter("objectvar", _("Array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/");
obj.AddStrExpression(
"ArrayVariableLastString",
_("Last text child"),
_("Get the value of the last element of an object array variable, if "
"it is a text (string) variable."),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"));
.AddParameter("objectvar", _("Array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/");
obj.AddExpression(
"ArrayVariableLastNumber",
_("Last number child"),
_("Get the value of the last element of an object array variable, if "
"it is a number variable."),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"));
.AddParameter("objectvar", _("Array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/");
obj.AddCondition("BehaviorActivated",
_("Behavior activated"),
@@ -1009,12 +1038,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Movement using forces"),
"res/actions/forceVers24.png",
"res/actions/forceVers.png")
.AddParameter("object", _("Object"))
.AddParameter("objectPtr", _("Target Object"))
.AddParameter("expression", _("Speed (in pixels per second)"))
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
.SetDefaultValue("0")
.SetHelpPath("/tutorials/how-to-move-objects/")
.MarkAsAdvanced();
obj.AddAction(
@@ -1029,13 +1058,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Movement using forces"),
"res/actions/forceTourne24.png",
"res/actions/forceTourne.png")
.AddParameter("object", _("Object"))
.AddParameter("objectPtr", _("Rotate around this object"))
.AddParameter("expression", _("Speed (in degrees per second)"))
.AddParameter("expression", _("Distance (in pixels)"))
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
.SetDefaultValue("0")
.SetHelpPath("/tutorials/how-to-move-objects/")
.MarkAsAdvanced();
obj.AddAction("MettreAutour",
@@ -1063,10 +1092,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Movement using forces"),
"res/actions/ecarter24.png",
"res/actions/ecarter.png")
.SetHidden()
.AddParameter("object", _("Object"))
.AddParameter("objectList", "Object 2 (won't move)");
.AddParameter("objectList", "Object 2 (won't move)")
.SetHelpPath("/tutorials/how-to-move-objects/");
// Deprecated action
obj.AddAction("Ecarter",
@@ -1090,7 +1119,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Position"),
"res/actions/ecarter24.png",
"res/actions/ecarter.png")
.AddParameter("object", _("Object"))
.AddParameter("objectList", _("Objects (won't move)"))
.AddParameter("yesorno",
@@ -1099,6 +1127,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"",
true)
.SetDefaultValue("no")
.SetHelpPath("/all-features/collisions/")
.MarkAsSimple();
obj.AddCondition("CollisionPoint",
@@ -1111,6 +1140,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("expression", _("X position of the point"))
.AddParameter("expression", _("Y position of the point"))
.SetHelpPath("/all-features/collisions/")
.MarkAsSimple();
extension
@@ -1142,6 +1172,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("identifier", _("Timer's name"), "objectTimer")
.AddParameter("expression", _("Time in seconds"))
.SetHelpPath("/all-features/timers-and-time/")
.SetHidden();
obj.AddCondition(
@@ -1157,6 +1188,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("identifier", _("Timer's name"), "objectTimer")
.AddParameter("relationalOperator", _("Sign of the test"), "time")
.AddParameter("expression", _("Time in seconds"))
.SetHelpPath("/all-features/timers-and-time/")
.SetManipulatedType("number");
obj.AddCondition("ObjectTimerPaused",
@@ -1168,6 +1200,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/conditions/timerPaused.png")
.AddParameter("object", _("Object"))
.AddParameter("identifier", _("Timer's name"), "objectTimer")
.SetHelpPath("/all-features/timers-and-time/")
.MarkAsAdvanced();
obj.AddAction(
@@ -1180,7 +1213,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/timer24.png",
"res/actions/timer.png")
.AddParameter("object", _("Object"))
.AddParameter("identifier", _("Timer's name"), "objectTimer");
.AddParameter("identifier", _("Timer's name"), "objectTimer")
.SetHelpPath("/all-features/timers-and-time/");
obj.AddAction("PauseObjectTimer",
_("Pause an object timer"),
@@ -1191,6 +1225,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/pauseTimer.png")
.AddParameter("object", _("Object"))
.AddParameter("identifier", _("Timer's name"), "objectTimer")
.SetHelpPath("/all-features/timers-and-time/")
.MarkAsAdvanced();
obj.AddAction("UnPauseObjectTimer",
@@ -1202,6 +1237,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/unPauseTimer.png")
.AddParameter("object", _("Object"))
.AddParameter("identifier", _("Timer's name"), "objectTimer")
.SetHelpPath("/all-features/timers-and-time/")
.MarkAsAdvanced();
obj.AddAction("RemoveObjectTimer",
@@ -1213,6 +1249,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/timer.png")
.AddParameter("object", _("Object"))
.AddParameter("identifier", _("Timer's name"), "objectTimer")
.SetHelpPath("/all-features/timers-and-time/")
.MarkAsAdvanced();
obj.AddExpression("X",
@@ -1241,28 +1278,32 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("X coordinate of the sum of forces"),
_("Movement using forces"),
"res/actions/force.png")
.AddParameter("object", _("Object"));
.AddParameter("object", _("Object"))
.SetHelpPath("/tutorials/how-to-move-objects/");
obj.AddExpression("ForceY",
_("Y coordinate of the sum of forces"),
_("Y coordinate of the sum of forces"),
_("Movement using forces"),
"res/actions/force.png")
.AddParameter("object", _("Object"));
.AddParameter("object", _("Object"))
.SetHelpPath("/tutorials/how-to-move-objects/");
obj.AddExpression("ForceAngle",
_("Angle of the sum of forces"),
_("Angle of the sum of forces (in degrees)"),
_("Movement using forces"),
"res/actions/force.png")
.AddParameter("object", _("Object"));
.AddParameter("object", _("Object"))
.SetHelpPath("/tutorials/how-to-move-objects/");
obj.AddExpression("ForceLength",
_("Length of the sum of forces"),
_("Length of the sum of forces"),
_("Movement using forces"),
"res/actions/force.png")
.AddParameter("object", _("Object"));
.AddParameter("object", _("Object"))
.SetHelpPath("/tutorials/how-to-move-objects/");
obj.AddExpression("Longueur",
_("Length of the sum of forces"),
@@ -1270,6 +1311,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Movement using forces"),
"res/actions/force.png")
.AddParameter("object", _("Object"))
.SetHelpPath("/tutorials/how-to-move-objects/")
.SetHidden();
obj.AddExpression("Width",
@@ -1366,10 +1408,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"VariableChildCount",
_("Number of children"),
_("Number of children in an object array or structure variable"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array or structure variable"));
.AddParameter("objectvar", _("Array or structure variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/");
obj.AddStrExpression("VariableString",
_("Text variable"),
@@ -1378,6 +1421,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.SetHelpPath("/all-features/variables/object-variables/")
.SetRelevantForFunctionEventsOnly();
obj.AddExpression("ObjectTimerElapsedTime",
@@ -1386,7 +1430,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Timers"),
"res/actions/time.png")
.AddParameter("object", _("Object"))
.AddParameter("identifier", _("Timer's name"), "objectTimer");
.AddParameter("identifier", _("Timer's name"), "objectTimer")
.SetHelpPath("/all-features/timers-and-time/");
obj.AddExpression("AngleToObject",
_("Angle between two objects"),
@@ -1606,6 +1651,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/doMove24.png",
"res/actions/doMove.png")
.AddCodeOnlyParameter("currentScene", "")
.SetHelpPath("/tutorials/how-to-move-objects/")
.MarkAsAdvanced();
extension
@@ -1621,6 +1667,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectList", _("Object 2"))
.AddParameter("expression", _("Tolerance, in degrees"))
.AddCodeOnlyParameter("conditionInverted", "")
.SetHelpPath("/tutorials/how-to-move-objects/")
.MarkAsAdvanced();
extension
@@ -1753,6 +1800,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"",
true)
.SetDefaultValue("no")
.SetHelpPath("/all-features/collisions/")
.MarkAsSimple();
extension
@@ -1815,6 +1863,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Scene variable where to store the Y position of the intersection. "
"If no intersection is found, the variable won't be changed."))
.AddCodeOnlyParameter("conditionInverted", "")
.SetHelpPath("/all-features/collisions/")
.MarkAsAdvanced();
extension
@@ -1846,6 +1895,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Scene variable where to store the Y position of the intersection. "
"If no intersection is found, the variable won't be changed."))
.AddCodeOnlyParameter("conditionInverted", "")
.SetHelpPath("/all-features/collisions/")
.MarkAsAdvanced();
extension

View File

@@ -19,7 +19,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTextContainerExtension(
extension
.SetExtensionInformation("TextContainerCapability",
_("Text capability"),
_("Animate objects."),
_("Allows an object to contain a text, usually shown on screen, that can be modified."),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/objects");
@@ -30,7 +30,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTextContainerExtension(
"TextContainerBehavior",
_("Text capability"),
"Text",
_("Access objects text."),
_("Allows an object to contain a text, usually shown on screen, that can be modified."),
"",
"res/conditions/text24_black.png",
"TextContainerBehavior",

View File

@@ -59,47 +59,57 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
// end of compatibility code
extension
.AddCondition("Or",
_("Or"),
_("Check if one of the sub conditions is true"),
_("If one of these conditions is true:"),
"",
"res/conditions/or24_black.png",
"res/conditions/or_black.png")
.SetCanHaveSubInstructions()
.MarkAsAdvanced();
extension
.AddCondition("And",
_("And"),
_("Check if all sub conditions are true"),
_("If all of these conditions are true:"),
"",
"res/conditions/and24_black.png",
"res/conditions/and_black.png")
.AddCondition(
"Or",
_("Or"),
_("Checks if at least one sub-condition is true. If no "
"sub-condition is specified, it will always be false. "
"This is rarely used — multiple events and sub-events are "
"usually a better approach."),
_("If one of these conditions is true:"),
"",
"res/conditions/or24_black.png",
"res/conditions/or_black.png")
.SetCanHaveSubInstructions()
.MarkAsAdvanced();
extension
.AddCondition(
"Not",
_("Not"),
_("Return the contrary of the result of the sub conditions"),
_("Invert the logical result of these conditions:"),
"And",
_("And"),
_("Checks if all sub-conditions are true. If no sub-condition is "
"specified, it will always be false. This is rarely needed, as "
"events already check all conditions before running actions."),
_("If all of these conditions are true:"),
"",
"res/conditions/not24_black.png",
"res/conditions/not_black.png")
"res/conditions/and24_black.png",
"res/conditions/and_black.png")
.SetCanHaveSubInstructions()
.MarkAsAdvanced();
extension.AddCondition(
"Once",
_("Trigger once while true"),
_("Run actions only once, for each time the conditions have been met."),
_("Trigger once"),
"",
"res/conditions/once24.png",
"res/conditions/once.png");
extension
.AddCondition("Not",
_("Not"),
_("Returns the opposite of the sub-condition(s) result. "
"This is rarely needed, as most conditions can be "
"inverted or expressed more simply."),
_("Invert the logical result of these conditions:"),
"",
"res/conditions/not24_black.png",
"res/conditions/not_black.png")
.SetCanHaveSubInstructions()
.MarkAsAdvanced();
extension
.AddCondition("Once",
_("Trigger once while true"),
_("Run actions only once, for each time the conditions "
"have been met."),
_("Trigger once"),
"",
"res/conditions/once24.png",
"res/conditions/once.png")
.SetHelpPath("/all-features/advanced-conditions/trigger-once");
extension
.AddCondition("CompareNumbers",

View File

@@ -28,7 +28,7 @@ BuiltinExtensionsImplementer::ImplementsExternalLayoutsExtension(
.AddAction("CreateObjectsFromExternalLayout",
_("Create objects from an external layout"),
_("Create objects from an external layout."),
_("Create objects from the external layout named _PARAM1_"),
_("Create objects from the external layout named _PARAM1_ at position _PARAM2_;_PARAM3_;_PARAM4_"),
"",
"res/ribbon_default/externallayout32.png",
"res/ribbon_default/externallayout32.png")

View File

@@ -35,7 +35,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsKeyboardExtension(
"res/conditions/keyboard24.png",
"res/conditions/keyboard.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("key", _("Key"));
.AddParameter("key", _("Key to check"))
.SetHidden();
extension
.AddCondition("KeyReleased",
@@ -46,33 +47,32 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsKeyboardExtension(
"res/conditions/keyboard24.png",
"res/conditions/keyboard.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("key", _("Key"));
.AddParameter("key", _("Key to check"))
.SetHidden();
extension
.AddCondition("KeyFromTextPressed",
_("Key pressed (text expression)"),
_("Check if a key, retrieved from the result of the "
"expression, is pressed"),
_("Key pressed"),
_("Check if a key is pressed"),
_("_PARAM1_ key is pressed"),
"",
"res/conditions/keyboard24.png",
"res/conditions/keyboard.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("string", _("Expression generating the key to check"))
.MarkAsAdvanced();
.AddParameter("keyboardKey", _("Key to check"))
.MarkAsSimple();
extension
.AddCondition("KeyFromTextReleased",
_("Key released (text expression)"),
_("Check if a key, retrieved from the result of the "
"expression, was just released"),
_("Key released"),
_("Check if a key was just released"),
_("_PARAM1_ key is released"),
"",
"res/conditions/keyboard24.png",
"res/conditions/keyboard.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("string", _("Expression generating the key to check"))
.MarkAsAdvanced();
.AddParameter("keyboardKey", _("Key to check"))
.MarkAsSimple();
extension
.AddCondition("AnyKeyPressed",

View File

@@ -151,7 +151,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("abs",
_("Absolute value"),
_("Absolute value"),
_("Return the non-negative value by removing the sign. "
"The absolute value of -8 is 8."),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));

View File

@@ -252,7 +252,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
"res/conditions/mouse.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("mouse", _("Button to check"))
.MarkAsSimple();
.MarkAsSimple()
.SetHidden();
// Support for deprecated names:
extension.AddDuplicatedCondition("SourisBouton", "MouseButtonPressed")
@@ -262,49 +263,41 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
.AddCondition("MouseButtonReleased",
_("Mouse button released"),
_("Check if the specified mouse button was released."),
_("_PARAM1_ mouse button was released"),
_("Touch or _PARAM1_ mouse button is released"),
"",
"res/conditions/mouse24.png",
"res/conditions/mouse.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("mouse", _("Button to check"))
.MarkAsSimple();
.MarkAsSimple()
.SetHidden();
extension
.AddCondition(
"MouseButtonFromTextPressed",
_("Mouse button pressed or touch held (text expression)"),
_("Check if a mouse button, retrieved from the result of the "
"expression, is pressed."),
_("_PARAM1_ mouse button is pressed"),
_("Mouse button pressed or touch held"),
_("Check if the specified mouse button is pressed or "
"if a touch is in contact with the screen."),
_("Touch or _PARAM1_ mouse button is down"),
"",
"res/conditions/mouse24.png",
"res/conditions/mouse.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("stringWithSelector",
_("Expression generating the mouse button to check"),
"[\"Left\", \"Right\", \"Middle\"]")
.SetParameterLongDescription(
_("Possible values are Left, Right and Middle."))
.MarkAsAdvanced();
.AddParameter("mouseButton", _("Button to check"))
.MarkAsSimple();
extension
.AddCondition(
"MouseButtonFromTextReleased",
_("Mouse button released (text expression)"),
_("Check if a mouse button, retrieved from the result of the "
"expression, was just released."),
_("_PARAM1_ mouse button is released"),
_("Mouse button released"),
_("Check if the specified mouse button was released."),
_("Touch or _PARAM1_ mouse button is released"),
"",
"res/conditions/mouse24.png",
"res/conditions/mouse.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("stringWithSelector",
_("Expression generating the mouse button to check"),
"[\"Left\", \"Right\", \"Middle\"]")
.SetParameterLongDescription(
_("Possible values are Left, Right and Middle."))
.MarkAsAdvanced();
.AddParameter("mouseButton", _("Button to check"))
.MarkAsSimple();
extension
.AddExpressionAndCondition("number",

View File

@@ -182,7 +182,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
"SceneLoadingProgress",
_("Scene loading progress"),
_("The progress of resources loading in background for a scene (between 0 and 1)."),
_("_PARAM0_ loading progress"),
_("_PARAM1_ loading progress"),
_(""),
"res/actions/hourglass_black.svg")
.SetHelpPath("/all-features/resources-loading")

View File

@@ -43,7 +43,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
.AddCondition("CompareTimer",
_("Value of a scene timer"),
_("Compare the elapsed time of a scene timer. This "
"condition doesn't start the timer."),
"condition doesn't start the timer and will always be "
"false if the timer was not started previously (whatever "
"the comparison being made)."),
_("The timer _PARAM1_ _PARAM2_ _PARAM3_ seconds"),
"",

View File

@@ -33,7 +33,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"",
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("variable", _("Variable"))
.AddParameter("variableOrPropertyOrParameter", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions());
@@ -45,7 +45,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"",
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("variable", _("Variable"))
.AddParameter("variableOrPropertyOrParameter", _("Variable"))
.UseStandardRelationalOperatorParameters(
"string", ParameterOptions::MakeNewOptions());
@@ -58,7 +58,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"",
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("variable", _("Variable"))
.AddParameter("variableOrPropertyOrParameter", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true")
// This parameter allows to keep the operand expression
@@ -73,32 +73,32 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"",
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("variable", _("Variable"))
.AddParameter("variableOrProperty", _("Variable"))
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions());
extension
.AddAction("SetStringVariable",
_("Change text variable"),
_("Change variable value"),
_("Modify the text (string) of a variable."),
_("the variable _PARAM0_"),
"",
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("variable", _("Variable"))
.AddParameter("variableOrProperty", _("Variable"))
.UseStandardOperatorParameters("string",
ParameterOptions::MakeNewOptions());
extension
.AddAction(
"SetBooleanVariable",
_("Change boolean variable"),
_("Change variable value"),
_("Modify the boolean value of a variable."),
_("Change the variable _PARAM0_: _PARAM1_"),
"",
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("variable", _("Variable"))
.AddParameter("variableOrProperty", _("Variable"))
.AddParameter("operator", _("Value"), "boolean")
// This parameter allows to keep the operand expression
// when the editor switch between variable instructions.
@@ -116,6 +116,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
.AddParameter("variable", _("Array variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced();
extension
@@ -129,6 +130,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"res/conditions/var.png")
.AddParameter("variable", _("Variable"))
.AddParameter("string", _("Name of the child"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced();
extension
@@ -142,6 +144,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"res/actions/var.png")
.AddParameter("variable", _("Structure variable"))
.AddParameter("string", _("Child's name"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced();
extension
@@ -154,6 +157,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("variable", _("Structure or array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced();
extension
@@ -170,12 +174,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
.SetParameterLongDescription(
_("The content of the variable will *be copied* and added at the "
"end of the array."))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced();
extension
.AddAction(
"PushString",
_("Add text variable"),
_("Add value to array variable"),
_("Adds a text (string) at the end of a array variable."),
_("Add the value _PARAM1_ to array variable _PARAM0_"),
_("Arrays and structures"),
@@ -183,11 +188,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"res/actions/var.png")
.AddParameter("variable", _("Array variable"))
.AddParameter("string", _("Text to add"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced();
extension
.AddAction("PushNumber",
_("Add variable array value"),
_("Add value to array variable"),
_("Adds a number at the end of an array variable."),
_("Add the value _PARAM1_ to array variable _PARAM0_"),
_("Arrays and structures"),
@@ -195,11 +201,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"res/actions/var.png")
.AddParameter("variable", _("Array variable"))
.AddParameter("expression", _("Number to add"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced();
extension
.AddAction("PushBoolean",
_("Add boolean variable"),
_("Add value to array variable"),
_("Adds a boolean at the end of an array variable."),
_("Add the value _PARAM1_ to array variable _PARAM0_"),
_("Arrays and structures"),
@@ -207,6 +214,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"res/actions/var.png")
.AddParameter("variable", _("Array variable"))
.AddParameter("trueorfalse", _("Boolean to add"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced();
extension
@@ -221,6 +229,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"res/actions/var.png")
.AddParameter("variable", _("Array variable"))
.AddParameter("expression", _("Index to remove"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced();
extension
@@ -231,7 +240,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"it is a text (string)."),
_("Arrays and structures"),
"res/actions/var.png")
.AddParameter("variable", _("Array variable"));
.AddParameter("variable", _("Array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/");
extension
.AddExpression(
@@ -241,7 +251,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"it is a number."),
_("Arrays and structures"),
"res/actions/var.png")
.AddParameter("variable", _("Array variable"));
.AddParameter("variable", _("Array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/");
extension
.AddStrExpression(
@@ -251,7 +262,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"it is a text (string)."),
_("Arrays and structures"),
"res/actions/var.png")
.AddParameter("variable", _("Array variable"));
.AddParameter("variable", _("Array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/");
extension
.AddExpression(
@@ -261,7 +273,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"it is a number."),
_("Arrays and structures"),
"res/actions/var.png")
.AddParameter("variable", _("Array variable"));
.AddParameter("variable", _("Array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/");
// Legacy instructions
@@ -270,26 +283,28 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Number variable"),
_("Compare the number value of a scene variable."),
_("The number of scene variable _PARAM0_"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddCondition("VarSceneTxt",
_("Text variable"),
_("Compare the text (string) of a scene variable."),
_("The text of scene variable _PARAM0_"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"string", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddCondition(
@@ -297,13 +312,14 @@ 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_"),
_("External variables/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")
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddCondition("VariableChildExists",
@@ -311,12 +327,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Check if the specified child of the scene structure "
"variable exists."),
_("Child _PARAM1_ of scene variable _PARAM0_ exists"),
_("External variables/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"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -325,12 +343,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Check if the specified child of the global structure "
"variable exists."),
_("Child _PARAM1_ of global variable _PARAM0_ exists"),
_("External variables/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"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -338,7 +358,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"Variable defined",
"Test if the scene variable exists.",
"Scene variable _PARAM0_ is defined",
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddCodeOnlyParameter("currentScene", "")
@@ -350,13 +370,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Number variable"),
_("Compare the number value of a global variable."),
_("the global variable _PARAM0_"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -364,13 +385,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Text variable"),
_("Compare the text (string) of a global variable."),
_("the text of the global variable _PARAM0_"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"string", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -379,20 +401,21 @@ 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_"),
_("External variables/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")
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddCondition("VarGlobalDef",
"Variable defined",
"Test if a global variable exists.",
"Global variable _PARAM0_ is defined",
_("External variables/Global variables"),
_("External variables Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddCodeOnlyParameter("currentScene", "")
@@ -405,26 +428,28 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Change number variable"),
_("Modify the number value of a scene variable."),
_("the scene variable _PARAM0_"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction("ModVarSceneTxt",
_("Change text variable"),
_("Modify the text (string) of a scene variable."),
_("the text of scene variable _PARAM0_"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardOperatorParameters("string",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction(
@@ -432,12 +457,13 @@ 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_"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.AddParameter("trueorfalse", _("New Value:"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction("ToggleSceneVariableAsBoolean",
@@ -446,24 +472,26 @@ 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_"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction("ModVarGlobal",
_("Change number variable"),
_("Modify the number value of a global variable."),
_("the global variable _PARAM0_"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -471,13 +499,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Change text variable"),
_("Modify the text (string) of a global variable."),
_("the text of global variable _PARAM0_"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardOperatorParameters("string",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -486,12 +515,13 @@ 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_"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.AddParameter("trueorfalse", _("New Value:"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction("ToggleGlobalVariableAsBoolean",
@@ -500,11 +530,12 @@ 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_"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction(
@@ -512,13 +543,15 @@ 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_"),
_("External variables/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"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction(
@@ -526,13 +559,15 @@ 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_"),
_("External variables/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"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction("VariableClearChildren",
@@ -540,11 +575,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Remove all the children from the scene structure or array "
"variable."),
_("Clear children from scene variable _PARAM0_"),
_("External variables/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"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -553,11 +590,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Remove all the children from the global structure or array "
"variable."),
_("Clear children from global variable _PARAM0_"),
_("External variables/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"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -566,7 +605,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_"),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
@@ -574,7 +613,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
.SetParameterLongDescription(
_("The content of the variable will *be copied* and added at the "
"end of the array."))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -583,12 +624,14 @@ 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_"),
_("External variables/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"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -596,12 +639,14 @@ 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_"),
_("External variables/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"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -609,12 +654,14 @@ 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_"),
_("External variables/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"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -624,12 +671,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"variable."),
_("Remove variable at index _PARAM1_ from scene array "
"variable _PARAM0_"),
_("External variables/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"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -638,13 +687,15 @@ 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_"),
_("External variables/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())
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -653,10 +704,12 @@ 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)."),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddExpression(
@@ -664,10 +717,12 @@ 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."),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddStrExpression(
@@ -675,10 +730,12 @@ 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)."),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddExpression(
@@ -686,10 +743,12 @@ 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."),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction(
@@ -697,7 +756,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_"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
@@ -705,7 +764,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
.SetParameterLongDescription(
_("The content of the variable will *be copied* and added at the "
"end of the array."))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -715,12 +776,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"array variable."),
_("Remove variable at index _PARAM1_ from global array "
"variable _PARAM0_"),
_("External variables/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"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -729,12 +792,14 @@ 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_"),
_("External variables/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"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -742,12 +807,14 @@ 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_"),
_("External variables/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"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -755,12 +822,14 @@ 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_"),
_("External variables/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"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -769,13 +838,15 @@ 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_"),
_("External variables/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())
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -783,20 +854,24 @@ 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."),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddExpression("GlobalVariableFirstNumber",
_("First number child"),
_("Value of the first element of a global array "
"variable, if it is a number variable"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddStrExpression(
@@ -804,10 +879,12 @@ 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."),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddExpression(
@@ -815,20 +892,23 @@ 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"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddExpression("GlobalVariableChildCount",
_("Number of children"),
_("Number of children in a global array or "
"structure variable"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array or structure variable"))
.SetRelevantForFunctionEventsOnly();
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddExpression("VariableChildCount",
@@ -837,43 +917,48 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"structure variable"),
_("Arrays and structures"),
"res/actions/var.png")
.AddParameter("variable", _("Array or structure variable"), "AllowUndeclaredVariable");
.AddParameter("variable", _("Array or structure variable"), "AllowUndeclaredVariable")
.SetHelpPath("/all-features/variables/structures-and-arrays/");
extension
.AddExpression("Variable",
_("Number variable"),
_("Number value of a scene variable"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddStrExpression("VariableString",
_("Text variable"),
_("Text of a scene variable"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddExpression("GlobalVariable",
_("Number variable"),
_("Number value of a global variable"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/actions/var.png")
.AddParameter("globalvar", _("Name of the global variable"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddStrExpression("GlobalVariableString",
_("Text variable"),
_("Text of a global variable"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/actions/var.png")
.AddParameter("globalvar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
}
} // namespace gd

View File

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

View File

@@ -174,6 +174,7 @@ public:
virtual const gd::String &GetFullName() const = 0;
virtual const gd::String &GetDescription() const = 0;
virtual const gd::String &GetIconFilename() const = 0;
virtual bool IsPrivate() const = 0;
/**
* \brief Return a reference to a map containing the names of the actions

View File

@@ -46,30 +46,25 @@ ObjectMetadata::ObjectMetadata(const gd::String& extensionNamespace_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon24x24)
: ObjectMetadata(extensionNamespace_,
name_,
fullname_,
description_,
icon24x24,
[]() -> std::unique_ptr<gd::ObjectConfiguration> {
gd::LogFatalError(
"Error: Event-based objects don't have blueprint. "
"This method should not never be called.");
return nullptr;
}) {}
: name(name_),
iconFilename(icon24x24),
extensionNamespace(extensionNamespace_) {
SetFullName(gd::String(fullname_));
SetDescription(gd::String(description_));
}
ObjectMetadata::ObjectMetadata(const gd::String& extensionNamespace_,
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon24x24,
CreateFunPtr createFunPtrP)
: name(name_),
iconFilename(icon24x24),
createFunPtr(createFunPtrP),
extensionNamespace(extensionNamespace_) {
SetFullName(gd::String(fullname_));
SetDescription(gd::String(description_));
CreateFunPtr createFunPtr_)
: ObjectMetadata(extensionNamespace_,
name_,
fullname_,
description_,
icon24x24) {
createFunPtr = createFunPtr_;
}
gd::InstructionMetadata& ObjectMetadata::AddCondition(

View File

@@ -39,6 +39,8 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
/**
* \brief Construct an object metadata, using a "blueprint" object that will
* be copied when a new object is requested.
*
* \note This is used for objects declared in JavaScript extensions.
*/
ObjectMetadata(const gd::String& extensionNamespace_,
const gd::String& name_,
@@ -47,9 +49,9 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
const gd::String& icon24x24_,
std::shared_ptr<gd::ObjectConfiguration> blueprintObject_);
/**
* \brief Construct an object metadata, without "blueprint" object
* \brief Construct an object metadata.
*
* \note This is used by events based objects.
* \note This is used by events based objects ("custom objects").
*/
ObjectMetadata(const gd::String& extensionNamespace_,
const gd::String& name_,
@@ -60,14 +62,17 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
/**
* \brief Construct an object metadata, with a function that will be called
* to instantiate a new object.
*
* \note This is used for objects declared in C++ extensions.
*/
ObjectMetadata(const gd::String& extensionNamespace_,
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon24x24_,
CreateFunPtr createFunPtrP);
ObjectMetadata() : createFunPtr(NULL) {}
CreateFunPtr createFunPtr_);
ObjectMetadata() {}
virtual ~ObjectMetadata(){};
/**
@@ -246,6 +251,11 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
return *this;
}
ObjectMetadata& ResetDefaultBehaviorsJustForTesting() {
defaultBehaviorTypes.clear();
return *this;
}
const gd::String& GetName() const override { return name; }
const gd::String& GetFullName() const override { return fullname; }
const gd::String& GetCategoryFullName() const { return categoryFullName; }
@@ -295,6 +305,22 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
*/
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressions() override { return strExpressionsInfos; };
/**
* Check if the behavior is private - it can't be used outside of its
* extension.
*/
bool IsPrivate() const override { return isPrivate; }
/**
* Set that the behavior is private - it can't be used outside of its
* extension.
*/
ObjectMetadata &SetPrivate() {
isPrivate = true;
return *this;
}
/**
* \brief Set the object to be hidden in the IDE.
*
@@ -339,7 +365,7 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
std::vector<gd::String> includeFiles;
gd::String className;
CreateFunPtr createFunPtr;
CreateFunPtr createFunPtr = nullptr;
private:
gd::String extensionNamespace;
@@ -351,6 +377,7 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
gd::String iconFilename;
gd::String categoryFullName;
std::set<gd::String> defaultBehaviorTypes;
bool isPrivate = false;
bool hidden = false;
bool isRenderedIn3D = false;
gd::String openFullEditorLabel;

View File

@@ -6,6 +6,8 @@
#include "ParameterMetadataTools.h"
#include "GDCore/Events/Expression.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/ObjectsContainersList.h"
@@ -13,8 +15,6 @@
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
#include "InstructionMetadata.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
namespace gd {
const ParameterMetadata ParameterMetadataTools::badParameterMetadata;
@@ -23,42 +23,109 @@ void ParameterMetadataTools::ParametersToObjectsContainer(
const gd::Project& project,
const ParameterMetadataContainer& parameters,
gd::ObjectsContainer& outputObjectsContainer) {
outputObjectsContainer.GetObjects().clear();
// Keep track of all objects and their behaviors names, so we can remove
// those who are in the container but not in the parameters anymore.
std::set<gd::String> allObjectNames;
std::map<gd::String, std::set<gd::String>> allObjectNonDefaultBehaviorNames;
gd::String lastObjectName;
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())) {
outputObjectsContainer.InsertNewObject(
project,
parameter.GetExtraInfo(),
parameter.GetName(),
outputObjectsContainer.GetObjectsCount());
auto &valueTypeMetadata = parameter.GetValueTypeMetadata();
if (valueTypeMetadata.IsObject()) {
const gd::String& objectName = parameter.GetName();
const gd::String& objectType = parameter.GetExtraInfo();
allObjectNames.insert(objectName);
// Check if we can keep the existing object.
if (outputObjectsContainer.HasObjectNamed(objectName)) {
const gd::Object& object = outputObjectsContainer.GetObject(objectName);
if (object.GetType() != objectType) {
// Object type has changed, remove it so it is re-created.
outputObjectsContainer.RemoveObject(objectName);
}
}
if (outputObjectsContainer.HasObjectNamed(objectName)) {
// Keep the existing object, ensure the default behaviors
// are all present (and no more than required by the object type).
// Non default behaviors coming from parameters will be added or removed later.
project.EnsureObjectDefaultBehaviors(outputObjectsContainer.GetObject(objectName));
} else {
// Create a new object (and its default behaviors) if needed.
outputObjectsContainer.InsertNewObject(
project,
objectType,
objectName,
outputObjectsContainer.GetObjectsCount());
}
// Memorize the last object name. 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.
lastObjectName = parameter.GetName();
} else if (gd::ParameterMetadata::IsBehavior(parameter.GetType())) {
lastObjectName = objectName;
} else if (valueTypeMetadata.IsBehavior()) {
if (!lastObjectName.empty()) {
if (outputObjectsContainer.HasObjectNamed(lastObjectName)) {
const gd::Object& object =
outputObjectsContainer.GetObject(lastObjectName);
gd::String behaviorName = parameter.GetName();
const gd::String& behaviorName = parameter.GetName();
const gd::String& behaviorType = parameter.GetExtraInfo();
gd::Object& object = outputObjectsContainer.GetObject(lastObjectName);
allObjectNonDefaultBehaviorNames[lastObjectName].insert(behaviorName);
// Check if we can keep the existing behavior.
if (object.HasBehaviorNamed(behaviorName)) {
if (object.GetBehavior(behaviorName).GetTypeName() !=
behaviorType) {
// Behavior type has changed, remove it so it is re-created.
object.RemoveBehavior(behaviorName);
}
}
if (!object.HasBehaviorNamed(behaviorName)) {
outputObjectsContainer.GetObject(lastObjectName)
.AddNewBehavior(
project, parameter.GetExtraInfo(), behaviorName);
object.AddNewBehavior(
project, parameter.GetExtraInfo(), behaviorName);
}
}
}
}
}
// Remove objects that are not in the parameters anymore.
std::set<gd::String> objectNamesInContainer =
outputObjectsContainer.GetAllObjectNames();
for (const auto& objectName : objectNamesInContainer) {
if (allObjectNames.find(objectName) == allObjectNames.end()) {
outputObjectsContainer.RemoveObject(objectName);
}
}
// Remove behaviors of objects that are not in the parameters anymore.
for (const auto& objectName : allObjectNames) {
if (!outputObjectsContainer.HasObjectNamed(objectName)) {
// Should not happen.
continue;
}
auto& object = outputObjectsContainer.GetObject(objectName);
const auto& allBehaviorNames = allObjectNonDefaultBehaviorNames[objectName];
for (const auto& behaviorName : object.GetAllBehaviorNames()) {
if (object.GetBehavior(behaviorName).IsDefaultBehavior()) {
// Default behaviors are already ensured to be all present
// (and no more than required by the object type).
continue;
}
if (allBehaviorNames.find(behaviorName) == allBehaviorNames.end()) {
object.RemoveBehavior(behaviorName);
}
}
}
}
void ParameterMetadataTools::ForEachParameterMatchingSearch(

View File

@@ -0,0 +1,56 @@
/*
* 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/String.h"
#include "GDCore/Serialization/SerializerElement.h"
namespace gd {
/**
* \brief Contains information about a source file that must be included
* when an extension is used.
*/
class GD_CORE_API SourceFileMetadata {
public:
/**
* Construct a new dependency metadata, though you probably want to call
* `AddSourceFile` on gd::PlatformExtension.
*
* \see gd::PlatformExtension
*/
SourceFileMetadata() {};
SourceFileMetadata& SetResourceName(const gd::String& resourceName_) {
resourceName = resourceName_;
return *this;
};
SourceFileMetadata& SetIncludePosition(const gd::String& includePosition_) {
includePosition = includePosition_;
return *this;
};
const gd::String& GetResourceName() const { return resourceName; };
gd::String& GetResourceName() { return resourceName; };
const gd::String& GetIncludePosition() const { return includePosition; };
void SerializeTo(SerializerElement& element) const {
element.AddChild("resourceName").SetStringValue(resourceName);
element.AddChild("includePosition").SetStringValue(includePosition);
}
void UnserializeFrom(const SerializerElement& element) {
resourceName = element.GetStringAttribute("resourceName");
includePosition = element.GetStringAttribute("includePosition", "last");
}
private:
gd::String resourceName; ///< The name of the resource in the project.
gd::String includePosition = "last"; ///< "first" or "last".
};
} // namespace gd

View File

@@ -74,9 +74,13 @@ ValueTypeMetadata::GetPrimitiveValueType(const gd::String &parameterType) {
const gd::String ValueTypeMetadata::numberValueType = "number";
const gd::String ValueTypeMetadata::booleanValueType = "boolean";
const gd::String ValueTypeMetadata::stringValueType = "string";
const gd::String ValueTypeMetadata::colorValueType = "color";
const gd::String ValueTypeMetadata::choiceValueType = "stringWithSelector";
const gd::String ValueTypeMetadata::stringValueType = "string";
const gd::String ValueTypeMetadata::behaviorValueType = "behavior";
const gd::String ValueTypeMetadata::leaderboardIdValueType = "leaderboardId";
const gd::String ValueTypeMetadata::objectAnimationNameValueType = "objectAnimationName";
const gd::String ValueTypeMetadata::keyboardKeyValueType = "keyboardKey";
const gd::String &ValueTypeMetadata::ConvertPropertyTypeToValueType(
const gd::String &propertyType) {
@@ -88,8 +92,16 @@ const gd::String &ValueTypeMetadata::ConvertPropertyTypeToValueType(
return colorValueType;
} else if (propertyType == "Choice") {
return choiceValueType;
} else if (propertyType == "Behavior") {
return behaviorValueType;
} else if (propertyType == "LeaderboardId") {
return leaderboardIdValueType;
} else if (propertyType == "ObjectAnimationName") {
return objectAnimationNameValueType;
} else if (propertyType == "KeyboardKey") {
return keyboardKeyValueType;
}
// For "String" or default
// For "String", "Resource", "MultilineString" or default
return stringValueType;
};

View File

@@ -129,13 +129,36 @@ class GD_CORE_API ValueTypeMetadata {
}
/**
* \brief Return true if the type of the parameter is a number.
* \brief Return true if the type of the parameter is a variable.
* \note If you had a new type of parameter, also add it in the IDE (
* see EventsFunctionParametersEditor, ParameterRenderingService
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
*/
bool IsVariable() const {
return gd::ValueTypeMetadata::GetPrimitiveValueType(name) == "variable";
return gd::ValueTypeMetadata::IsVariable(name);
}
/**
* \brief Return true if the type of the parameter is a variable.
* \note If you had a new type of parameter, also add it in the IDE (
* see EventsFunctionParametersEditor, ParameterRenderingService
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
*/
static bool IsVariable(const gd::String &type) {
return gd::ValueTypeMetadata::GetPrimitiveValueType(type) == "variable";
}
/**
* \brief Return true if the type of the parameter is a variable and not a
* property or a parameter.
*/
bool IsVariableOnly() const {
return
// Any variable.
name == "variable" ||
// Old, "pre-scoped" variables:
name == "objectvar" || name == "globalvar" ||
name == "scenevar";
}
/**
@@ -202,15 +225,20 @@ class GD_CORE_API ValueTypeMetadata {
parameterType == "functionParameterName" ||
parameterType == "externalLayoutName" ||
parameterType == "leaderboardId" ||
parameterType == "keyboardKey" ||
parameterType == "mouseButton" ||
parameterType == "identifier";
} else if (type == "boolean") {
return parameterType == "yesorno" || parameterType == "trueorfalse";
} else if (type == "variable") {
return
parameterType == "variable" || // Any variable.
// Old, "pre-scoped" variables:
parameterType == "objectvar" || parameterType == "globalvar" ||
parameterType == "scenevar";
// Any variable.
parameterType == "variable" ||
parameterType == "variableOrProperty" ||
parameterType == "variableOrPropertyOrParameter" ||
// Old, "pre-scoped" variables:
parameterType == "objectvar" || parameterType == "globalvar" ||
parameterType == "scenevar";
} else if (type == "resource") {
return parameterType == "fontResource" ||
parameterType == "audioResource" ||
@@ -301,9 +329,13 @@ class GD_CORE_API ValueTypeMetadata {
static const gd::String numberValueType;
static const gd::String booleanValueType;
static const gd::String stringValueType;
static const gd::String colorValueType;
static const gd::String choiceValueType;
static const gd::String stringValueType;
static const gd::String behaviorValueType;
static const gd::String leaderboardIdValueType;
static const gd::String objectAnimationNameValueType;
static const gd::String keyboardKeyValueType;
};
} // namespace gd

View File

@@ -38,12 +38,14 @@ bool Platform::AddExtension(std::shared_ptr<gd::PlatformExtension> extension) {
extensionsLoaded.push_back(extension);
// Load all creation/destruction functions for objects provided by the
// extension
// Load all creation functions for objects provided by the
// extension.
vector<gd::String> objectsTypes = extension->GetExtensionObjectsTypes();
for (std::size_t i = 0; i < objectsTypes.size(); ++i) {
creationFunctionTable[objectsTypes[i]] =
extension->GetObjectCreationFunctionPtr(objectsTypes[i]);
CreateFunPtr createFunPtr = extension->GetObjectCreationFunctionPtr(objectsTypes[i]);
if (createFunPtr != nullptr) {
creationFunctionTable[objectsTypes[i]] = createFunPtr;
}
}
for (const auto& it :
@@ -62,7 +64,9 @@ void Platform::RemoveExtension(const gd::String& name) {
if (extension->GetName() == name) {
vector<gd::String> objectsTypes = extension->GetExtensionObjectsTypes();
for (std::size_t i = 0; i < objectsTypes.size(); ++i) {
creationFunctionTable.erase(objectsTypes[i]);
if (creationFunctionTable.find(objectsTypes[i]) != creationFunctionTable.end()) {
creationFunctionTable.erase(objectsTypes[i]);
}
}
}
}

View File

@@ -18,8 +18,8 @@
#include "GDCore/Extensions/Platform.h"
#include "GDCore/IDE/PlatformManager.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/ObjectConfiguration.h"
#include "GDCore/Project/BehaviorsSharedData.h"
#include "GDCore/Project/ObjectConfiguration.h"
#include "GDCore/Tools/Localization.h"
namespace gd {
@@ -200,11 +200,11 @@ PlatformExtension::AddExpressionAndConditionAndAction(
group,
icon)
: AddStrExpression(name,
fullname,
expressionDescriptionTemplate.FindAndReplace(
"<subject>", descriptionSubject),
group,
icon);
fullname,
expressionDescriptionTemplate.FindAndReplace(
"<subject>", descriptionSubject),
group,
icon);
return MultipleInstructionMetadata::WithExpressionAndConditionAndAction(
expression, condition, action);
@@ -215,6 +215,11 @@ gd::DependencyMetadata& PlatformExtension::AddDependency() {
return extensionDependenciesMetadata.back();
}
gd::SourceFileMetadata& PlatformExtension::AddSourceFile() {
extensionSourceFilesMetadata.push_back(SourceFileMetadata());
return extensionSourceFilesMetadata.back();
}
gd::ObjectMetadata& PlatformExtension::AddObject(
const gd::String& name,
const gd::String& fullname,
@@ -239,12 +244,10 @@ gd::ObjectMetadata& PlatformExtension::AddEventsBasedObject(
const gd::String& description,
const gd::String& icon24x24) {
gd::String nameWithNamespace = GetNameSpace() + name;
objectsInfos[nameWithNamespace] = ObjectMetadata(GetNameSpace(),
nameWithNamespace,
fullname,
description,
icon24x24)
.SetHelpPath(GetHelpPath());
objectsInfos[nameWithNamespace] =
ObjectMetadata(
GetNameSpace(), nameWithNamespace, fullname, description, icon24x24)
.SetHelpPath(GetHelpPath());
return objectsInfos[nameWithNamespace];
}
@@ -348,8 +351,7 @@ gd::BehaviorMetadata& PlatformExtension::GetBehaviorMetadata(
return badBehaviorMetadata;
}
bool PlatformExtension::HasBehavior(
const gd::String& behaviorType) const {
bool PlatformExtension::HasBehavior(const gd::String& behaviorType) const {
return behaviorsInfo.find(behaviorType) != behaviorsInfo.end();
}
@@ -381,7 +383,7 @@ gd::InstructionMetadata& PlatformExtension::AddDuplicatedAction(
auto copiedAction = actionsInfos.find(copiedNameWithNamespace);
if (copiedAction == actionsInfos.end()) {
gd::LogError("Could not find an action with name " +
copiedNameWithNamespace + " to copy.");
copiedNameWithNamespace + " to copy.");
} else {
actionsInfos[newNameWithNamespace] = copiedAction->second;
}
@@ -401,7 +403,7 @@ gd::InstructionMetadata& PlatformExtension::AddDuplicatedCondition(
auto copiedCondition = conditionsInfos.find(copiedNameWithNamespace);
if (copiedCondition == conditionsInfos.end()) {
gd::LogError("Could not find a condition with name " +
copiedNameWithNamespace + " to copy.");
copiedNameWithNamespace + " to copy.");
} else {
conditionsInfos[newNameWithNamespace] = copiedCondition->second;
}
@@ -418,7 +420,7 @@ gd::ExpressionMetadata& PlatformExtension::AddDuplicatedExpression(
auto copiedExpression = expressionsInfos.find(copiedNameWithNamespace);
if (copiedExpression == expressionsInfos.end()) {
gd::LogError("Could not find an expression with name " +
copiedNameWithNamespace + " to copy.");
copiedNameWithNamespace + " to copy.");
} else {
expressionsInfos[newNameWithNamespace] = copiedExpression->second;
}
@@ -435,7 +437,7 @@ gd::ExpressionMetadata& PlatformExtension::AddDuplicatedStrExpression(
auto copiedExpression = strExpressionsInfos.find(copiedNameWithNamespace);
if (copiedExpression == strExpressionsInfos.end()) {
gd::LogError("Could not find a string expression with name " +
copiedNameWithNamespace + " to copy.");
copiedNameWithNamespace + " to copy.");
} else {
strExpressionsInfos[newNameWithNamespace] = copiedExpression->second;
}
@@ -463,10 +465,24 @@ PlatformExtension::GetAllStrExpressions() {
return strExpressionsInfos;
}
const std::vector<gd::DependencyMetadata>&
PlatformExtension::GetAllDependencies() const {
return extensionDependenciesMetadata;
}
std::vector<gd::DependencyMetadata>& PlatformExtension::GetAllDependencies() {
return extensionDependenciesMetadata;
}
const std::vector<gd::SourceFileMetadata>&
PlatformExtension::GetAllSourceFiles() const {
return extensionSourceFilesMetadata;
}
std::vector<gd::SourceFileMetadata>& PlatformExtension::GetAllSourceFiles() {
return extensionSourceFilesMetadata;
}
std::map<gd::String, gd::EventMetadata>& PlatformExtension::GetAllEvents() {
return eventsInfos;
}
@@ -598,37 +614,6 @@ void PlatformExtension::SetNameSpace(gd::String nameSpace_) {
nameSpace = nameSpace_ + GetNamespaceSeparator();
}
std::vector<gd::String> PlatformExtension::GetBuiltinExtensionsNames() {
std::vector<gd::String> builtinExtensions;
builtinExtensions.push_back("Sprite");
builtinExtensions.push_back("BuiltinObject");
builtinExtensions.push_back("BuiltinAudio");
builtinExtensions.push_back("BuiltinMouse");
builtinExtensions.push_back("BuiltinKeyboard");
builtinExtensions.push_back("BuiltinJoystick");
builtinExtensions.push_back("BuiltinTime");
builtinExtensions.push_back("BuiltinFile");
builtinExtensions.push_back("BuiltinVariables");
builtinExtensions.push_back("BuiltinCamera");
builtinExtensions.push_back("BuiltinWindow");
builtinExtensions.push_back("BuiltinNetwork");
builtinExtensions.push_back("BuiltinScene");
builtinExtensions.push_back("BuiltinAdvanced");
builtinExtensions.push_back("BuiltinCommonConversions");
builtinExtensions.push_back("BuiltinStringInstructions");
builtinExtensions.push_back("BuiltinMathematicalTools");
builtinExtensions.push_back("BuiltinExternalLayouts");
builtinExtensions.push_back("BuiltinCommonInstructions");
return builtinExtensions;
}
bool PlatformExtension::IsBuiltin() const {
std::vector<gd::String> builtinExtensions = GetBuiltinExtensionsNames();
return std::find(builtinExtensions.begin(), builtinExtensions.end(), name) !=
builtinExtensions.end();
}
void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
for (std::map<gd::String, gd::InstructionMetadata>::iterator it =
GetAllActions().begin();
@@ -774,41 +759,42 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
}
}
gd::String
PlatformExtension::GetEventsFunctionFullType(const gd::String &extensionName,
const gd::String &functionName) {
const auto &separator = GetNamespaceSeparator();
gd::String PlatformExtension::GetEventsFunctionFullType(
const gd::String& extensionName, const gd::String& functionName) {
const auto& separator = GetNamespaceSeparator();
return extensionName + separator + functionName;
}
gd::String PlatformExtension::GetBehaviorEventsFunctionFullType(
const gd::String &extensionName, const gd::String &behaviorName,
const gd::String &functionName) {
const auto &separator = GetNamespaceSeparator();
const gd::String& extensionName,
const gd::String& behaviorName,
const gd::String& functionName) {
const auto& separator = GetNamespaceSeparator();
return extensionName + separator + behaviorName + separator + functionName;
}
gd::String
PlatformExtension::GetBehaviorFullType(const gd::String &extensionName,
const gd::String &behaviorName) {
const auto &separator = GetNamespaceSeparator();
gd::String PlatformExtension::GetBehaviorFullType(
const gd::String& extensionName, const gd::String& behaviorName) {
const auto& separator = GetNamespaceSeparator();
return extensionName + separator + behaviorName;
}
gd::String PlatformExtension::GetObjectEventsFunctionFullType(
const gd::String &extensionName, const gd::String &objectName,
const gd::String &functionName) {
const auto &separator = GetNamespaceSeparator();
const gd::String& extensionName,
const gd::String& objectName,
const gd::String& functionName) {
const auto& separator = GetNamespaceSeparator();
return extensionName + separator + objectName + separator + functionName;
}
gd::String PlatformExtension::GetObjectFullType(const gd::String &extensionName,
const gd::String &objectName) {
const auto &separator = GetNamespaceSeparator();
gd::String PlatformExtension::GetObjectFullType(const gd::String& extensionName,
const gd::String& objectName) {
const auto& separator = GetNamespaceSeparator();
return extensionName + separator + objectName;
}
gd::String PlatformExtension::GetExtensionFromFullObjectType(const gd::String& type) {
gd::String PlatformExtension::GetExtensionFromFullObjectType(
const gd::String& type) {
const auto separatorIndex =
type.find(PlatformExtension::GetNamespaceSeparator());
if (separatorIndex == std::string::npos) {
@@ -817,7 +803,8 @@ gd::String PlatformExtension::GetExtensionFromFullObjectType(const gd::String& t
return type.substr(0, separatorIndex);
}
gd::String PlatformExtension::GetObjectNameFromFullObjectType(const gd::String& type) {
gd::String PlatformExtension::GetObjectNameFromFullObjectType(
const gd::String& type) {
const auto separatorIndex =
type.find(PlatformExtension::GetNamespaceSeparator());
if (separatorIndex == std::string::npos) {

View File

@@ -17,6 +17,7 @@
#include "GDCore/Extensions/Metadata/EventMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionOrExpressionGroupMetadata.h"
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Metadata/SourceFileMetadata.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/String.h"
#include "GDCore/Tools/VersionPriv.h"
@@ -214,6 +215,7 @@ class GD_CORE_API PlatformExtension {
const gd::String& icon);
gd::DependencyMetadata& AddDependency();
gd::SourceFileMetadata& AddSourceFile();
/**
* \brief Declare a new object as being part of the extension.
@@ -438,12 +440,6 @@ class GD_CORE_API PlatformExtension {
*/
bool IsDeprecated() const { return deprecated; }
/**
* \brief Return true if the extension is a standard extension that cannot be
* deactivated
*/
bool IsBuiltin() const;
/**
* \brief Get the namespace of the extension.
* \note The namespace is simply the name of the extension concatenated with
@@ -552,6 +548,24 @@ class GD_CORE_API PlatformExtension {
*/
std::vector<gd::DependencyMetadata>& GetAllDependencies();
/**
* \brief Return a reference to a vector containing the metadata of all the
* dependencies of the extension.
*/
const std::vector<gd::DependencyMetadata>& GetAllDependencies() const;
/**
* \brief Return a reference to a vector containing the metadata of all the
* dependencies of the extension.
*/
std::vector<gd::SourceFileMetadata>& GetAllSourceFiles();
/**
* \brief Return a reference to a vector containing the metadata of all the
* dependencies of the extension.
*/
const std::vector<gd::SourceFileMetadata>& GetAllSourceFiles() const;
/**
* \brief Return a reference to a map containing the names of the actions,
* related to the object type, and the metadata associated with.
@@ -620,12 +634,6 @@ class GD_CORE_API PlatformExtension {
}
///@}
/**
* \brief Return the name of all the extensions which are considered provided
* by platforms.
*/
static std::vector<gd::String> GetBuiltinExtensionsNames();
/**
* \brief Get the string used to separate the name of the
* instruction/expression and the extension.
@@ -687,6 +695,7 @@ class GD_CORE_API PlatformExtension {
std::map<gd::String, gd::ExpressionMetadata> expressionsInfos;
std::map<gd::String, gd::ExpressionMetadata> strExpressionsInfos;
std::vector<gd::DependencyMetadata> extensionDependenciesMetadata;
std::vector<gd::SourceFileMetadata> extensionSourceFilesMetadata;
std::map<gd::String, gd::EventMetadata> eventsInfos;
std::map<gd::String, gd::PropertyDescriptor> extensionPropertiesMetadata;
std::map<gd::String, InstructionOrExpressionGroupMetadata>

View File

@@ -0,0 +1,18 @@
/*
* 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/CaptureOptions.h"
#include "GDCore/String.h"
using namespace std;
namespace gd {
Screenshot::Screenshot() {}
CaptureOptions::CaptureOptions() {}
} // namespace gd

View File

@@ -0,0 +1,50 @@
#pragma once
#include <memory>
#include <vector>
#include "GDCore/String.h"
namespace gd {
class GD_CORE_API Screenshot {
public:
Screenshot();
virtual ~Screenshot() {};
void SetDelayTimeInSeconds(int delayTimeInMs_) {
delayTimeInMs = delayTimeInMs_;
}
int GetDelayTimeInSeconds() const { return delayTimeInMs; }
void SetSignedUrl(const gd::String& signedUrl_) { signedUrl = signedUrl_; }
const gd::String& GetSignedUrl() const { return signedUrl; }
void SetPublicUrl(const gd::String& publicUrl_) { publicUrl = publicUrl_; }
const gd::String& GetPublicUrl() const { return publicUrl; }
private:
int delayTimeInMs = 0;
gd::String signedUrl;
gd::String publicUrl;
};
class GD_CORE_API CaptureOptions {
public:
CaptureOptions();
virtual ~CaptureOptions() {};
bool IsEmpty() const { return screenshots.empty(); }
void AddScreenshot(const Screenshot& screenshot) {
screenshots.push_back(screenshot);
}
const std::vector<Screenshot>& GetScreenshots() const { return screenshots; }
void ClearScreenshots() { screenshots.clear(); }
private:
std::vector<Screenshot> screenshots;
};
} // namespace gd

View File

@@ -12,7 +12,6 @@
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/SourceFile.h"
DependenciesAnalyzer::DependenciesAnalyzer(const gd::Project& project_,
const gd::Layout& layout_)
@@ -74,16 +73,6 @@ bool DependenciesAnalyzer::Analyze(const gd::EventsList& events) {
}
}
// Search for source files dependencies
std::vector<gd::String> dependencies =
events[i].GetSourceFileDependencies();
sourceFilesDependencies.insert(dependencies.begin(), dependencies.end());
const gd::String& associatedSourceFile =
events[i].GetAssociatedGDManagedSourceFile(const_cast<gd::Project&>(project));
if (!associatedSourceFile.empty())
sourceFilesDependencies.insert(associatedSourceFile);
// Analyze sub events dependencies
if (events[i].CanHaveSubEvents()) {
if (!Analyze(events[i].GetSubEvents())) return false;

View File

@@ -71,14 +71,6 @@ class GD_CORE_API DependenciesAnalyzer {
return externalEventsDependencies;
};
/**
* \brief Return the source files being dependencies of the scene or external
* events passed in the constructor.
*/
const std::set<gd::String>& GetSourceFilesDependencies() const {
return sourceFilesDependencies;
};
private:
/**
* \brief Analyze the dependencies of the events.
@@ -92,7 +84,6 @@ class GD_CORE_API DependenciesAnalyzer {
std::set<gd::String> scenesDependencies;
std::set<gd::String> externalEventsDependencies;
std::set<gd::String> sourceFilesDependencies;
std::vector<gd::String>
parentScenes; ///< Used to check for circular dependencies.
std::vector<gd::String>

View File

@@ -1,41 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/EventsLeaderboardsLister.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
namespace gd {
bool EventsLeaderboardsLister::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
const gd::InstructionMetadata& instrInfo =
isCondition ? MetadataProvider::GetConditionMetadata(
project.GetCurrentPlatform(), instruction.GetType())
: MetadataProvider::GetActionMetadata(
project.GetCurrentPlatform(), instruction.GetType());
for (int i = 0; i < instruction.GetParametersCount() &&
i < instrInfo.GetParametersCount();
++i)
if (instrInfo.GetParameter(i).GetType() == "leaderboardId") {
leaderboardIds.insert(instruction.GetParameter(i).GetPlainString());
}
return false;
}
EventsLeaderboardsLister::~EventsLeaderboardsLister() {}
} // namespace gd

View File

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

View File

@@ -1,49 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/EventsLeaderboardsRenamer.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
namespace gd {
bool EventsLeaderboardsRenamer::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
const gd::InstructionMetadata& instrInfo =
isCondition ? MetadataProvider::GetConditionMetadata(
project.GetCurrentPlatform(), instruction.GetType())
: MetadataProvider::GetActionMetadata(
project.GetCurrentPlatform(), instruction.GetType());
for (int i = 0; i < instruction.GetParametersCount() &&
i < instrInfo.GetParametersCount();
++i) {
const gd::ParameterMetadata parameter = instrInfo.GetParameter(i);
if (parameter.GetType() == "leaderboardId") {
const gd::String leaderboardId =
instruction.GetParameter(i).GetPlainString();
if (leaderboardIdMap.find(leaderboardId) != leaderboardIdMap.end()) {
instruction.SetParameter(i, leaderboardIdMap[leaderboardId]);
}
}
}
return false;
}
EventsLeaderboardsRenamer::~EventsLeaderboardsRenamer() {}
} // namespace gd

View File

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

View File

@@ -0,0 +1,243 @@
/*
* 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/EventsParameterReplacer.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/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/Project/PropertiesContainer.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
namespace gd {
/**
* \brief Go through the nodes and rename parameters.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionParameterReplacer
: public ExpressionParser2NodeWorker {
public:
ExpressionParameterReplacer(
const gd::Platform& platform_,
const gd::ProjectScopedContainers& projectScopedContainers_,
bool isParentTypeAVariable_,
const std::unordered_map<gd::String, gd::String>& oldToNewPropertyNames_)
: hasDoneRenaming(false),
platform(platform_),
projectScopedContainers(projectScopedContainers_),
isParentTypeAVariable(isParentTypeAVariable_),
oldToNewPropertyNames(oldToNewPropertyNames_){};
virtual ~ExpressionParameterReplacer(){};
bool HasDoneRenaming() const { return hasDoneRenaming; }
protected:
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
node.expression->Visit(*this);
}
void OnVisitOperatorNode(OperatorNode& node) override {
node.leftHandSide->Visit(*this);
node.rightHandSide->Visit(*this);
}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
node.factor->Visit(*this);
}
void OnVisitNumberNode(NumberNode& node) override {}
void OnVisitTextNode(TextNode& node) override {}
void OnVisitVariableNode(VariableNode& node) override {
if (isParentTypeAVariable) {
// Do nothing, it's a variable.
if (node.child) node.child->Visit(*this);
return;
}
// The node represents a variable or an object name on which a variable
// will be accessed, or a property with a child.
projectScopedContainers.MatchIdentifierWithName<void>(
// The property name is changed after the refactor operation.
node.name,
[&]() {
// Do nothing, it's an object variable.
if (node.child) node.child->Visit(*this);
}, [&]() {
// Do nothing, it's a variable.
if (node.child) node.child->Visit(*this);
}, [&]() {
// Do nothing, it's a property.
if (node.child) node.child->Visit(*this);
}, [&]() {
// This is a parameter
RenameParameter(node.name);
if (node.child) node.child->Visit(*this);
}, [&]() {
// Do nothing, it's something else.
if (node.child) node.child->Visit(*this);
});
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
bool isGrandParentTypeAVariable = isParentTypeAVariable;
isParentTypeAVariable = false;
node.expression->Visit(*this);
isParentTypeAVariable = isGrandParentTypeAVariable;
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
if (isParentTypeAVariable) {
// Do nothing, it's a variable.
return;
}
projectScopedContainers.MatchIdentifierWithName<void>(
// The property name is changed after the refactor operation
node.identifierName,
[&]() {
// Do nothing, it's an object variable.
}, [&]() {
// Do nothing, it's a variable.
}, [&]() {
// Do nothing, it's a property.
}, [&]() {
// This is a parameter.
RenameParameter(node.identifierName);
}, [&]() {
// Do nothing, it's something else.
});
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
void OnVisitFunctionCallNode(FunctionCallNode &node) override {
bool isGrandParentTypeAVariable = isParentTypeAVariable;
for (auto &parameter : node.parameters) {
const auto &parameterMetadata =
gd::MetadataProvider::GetFunctionCallParameterMetadata(
platform, projectScopedContainers.GetObjectsContainersList(),
node, *parameter);
if (!parameterMetadata) {
continue;
}
const auto &parameterTypeMetadata =
parameterMetadata->GetValueTypeMetadata();
if (gd::EventsParameterReplacer::CanContainParameter(
parameterTypeMetadata)) {
isParentTypeAVariable = parameterTypeMetadata.IsVariableOnly();
parameter->Visit(*this);
}
}
isParentTypeAVariable = isGrandParentTypeAVariable;
}
void OnVisitEmptyNode(EmptyNode& node) override {}
private:
bool hasDoneRenaming;
bool RenameParameter(
gd::String& name) {
if (oldToNewPropertyNames.count(name) >= 1) {
name = oldToNewPropertyNames.find(name)->second;
hasDoneRenaming = true;
return true;
}
return false; // Nothing was changed or done.
}
// Scope:
const gd::Platform& platform;
const gd::ProjectScopedContainers& projectScopedContainers;
// Renaming to do
const std::unordered_map<gd::String, gd::String>& oldToNewPropertyNames;
gd::String objectNameToUseForVariableAccessor;
bool isParentTypeAVariable;
};
bool EventsParameterReplacer::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 (!gd::EventsParameterReplacer::CanContainParameter(
parameterMetadata.GetValueTypeMetadata())) {
return;
}
auto node = parameterValue.GetRootNode();
if (node) {
ExpressionParameterReplacer renamer(
platform, GetProjectScopedContainers(),
parameterMetadata.GetValueTypeMetadata().IsVariableOnly(),
oldToNewPropertyNames);
node->Visit(renamer);
if (renamer.HasDoneRenaming()) {
instruction.SetParameter(
parameterIndex, ExpressionParser2NodePrinter::PrintNode(*node));
}
}
});
return false;
}
bool EventsParameterReplacer::DoVisitEventExpression(
gd::Expression& expression, const gd::ParameterMetadata& metadata) {
if (!gd::EventsParameterReplacer::CanContainParameter(
metadata.GetValueTypeMetadata())) {
return false;
}
auto node = expression.GetRootNode();
if (node) {
ExpressionParameterReplacer renamer(
platform, GetProjectScopedContainers(),
metadata.GetValueTypeMetadata().IsVariableOnly(), oldToNewPropertyNames);
node->Visit(renamer);
if (renamer.HasDoneRenaming()) {
expression = ExpressionParser2NodePrinter::PrintNode(*node);
}
}
return false;
}
bool EventsParameterReplacer::CanContainParameter(
const gd::ValueTypeMetadata &valueTypeMetadata) {
return valueTypeMetadata.IsVariable() || valueTypeMetadata.IsNumber() ||
valueTypeMetadata.IsString();
}
EventsParameterReplacer::~EventsParameterReplacer() {}
} // namespace gd

View File

@@ -0,0 +1,52 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#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 BaseEvent;
class PropertiesContainer;
class EventsList;
class Platform;
} // namespace gd
namespace gd {
/**
* \brief Replace in expressions and in parameters of actions or conditions,
* references to the name of a parameter by another.
*
* \ingroup IDE
*/
class GD_CORE_API EventsParameterReplacer
: public ArbitraryEventsWorkerWithContext {
public:
EventsParameterReplacer(
const gd::Platform &platform_,
const std::unordered_map<gd::String, gd::String> &oldToNewPropertyNames_)
: platform(platform_),
oldToNewPropertyNames(oldToNewPropertyNames_){};
virtual ~EventsParameterReplacer();
static bool CanContainParameter(const gd::ValueTypeMetadata &valueTypeMetadata);
private:
bool DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) override;
bool DoVisitEventExpression(gd::Expression &expression,
const gd::ParameterMetadata &metadata) override;
const gd::Platform &platform;
const std::unordered_map<gd::String, gd::String> &oldToNewPropertyNames;
};
} // namespace gd

View File

@@ -41,6 +41,7 @@ class GD_CORE_API ExpressionPropertyReplacer
const gd::Platform& platform_,
const gd::ProjectScopedContainers& projectScopedContainers_,
const gd::PropertiesContainer& targetPropertiesContainer_,
bool isParentTypeAVariable_,
const std::unordered_map<gd::String, gd::String>& oldToNewPropertyNames_,
const std::unordered_set<gd::String>& removedPropertyNames_)
: hasDoneRenaming(false),
@@ -48,6 +49,7 @@ class GD_CORE_API ExpressionPropertyReplacer
platform(platform_),
projectScopedContainers(projectScopedContainers_),
targetPropertiesContainer(targetPropertiesContainer_),
isParentTypeAVariable(isParentTypeAVariable_),
oldToNewPropertyNames(oldToNewPropertyNames_),
removedPropertyNames(removedPropertyNames_){};
virtual ~ExpressionPropertyReplacer(){};
@@ -69,16 +71,21 @@ class GD_CORE_API ExpressionPropertyReplacer
void OnVisitNumberNode(NumberNode& node) override {}
void OnVisitTextNode(TextNode& node) override {}
void OnVisitVariableNode(VariableNode& node) override {
if (isParentTypeAVariable) {
// Do nothing, it's a variable.
if (node.child) node.child->Visit(*this);
return;
}
auto& propertiesContainersList =
projectScopedContainers.GetPropertiesContainersList();
// The node represents a variable or an object name on which a variable
// will be accessed, or a property with a child.
// Match the potential *new* name of the property, because refactorings are
// done after changes in the variables container.
projectScopedContainers.MatchIdentifierWithName<void>(
GetPotentialNewName(node.name),
// The property name is changed after the refactor operation.
node.name,
[&]() {
// Do nothing, it's an object variable.
if (node.child) node.child->Visit(*this);
@@ -100,16 +107,7 @@ class GD_CORE_API ExpressionPropertyReplacer
// Do nothing, it's a parameter.
if (node.child) node.child->Visit(*this);
}, [&]() {
// This is something else - potentially a deleted property.
// Check if it's coming from the target container with
// properties to replace.
if (propertiesContainersList.HasPropertiesContainer(
targetPropertiesContainer)) {
// The node represents a property, that can come from the target
// (because the target is in the scope), replace or remove it:
RenameOrRemovePropertyOfTargetPropertyContainer(node.name);
}
// Do nothing, it's something else.
if (node.child) node.child->Visit(*this);
});
}
@@ -118,17 +116,24 @@ class GD_CORE_API ExpressionPropertyReplacer
}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
bool isGrandParentTypeAVariable = isParentTypeAVariable;
isParentTypeAVariable = false;
node.expression->Visit(*this);
isParentTypeAVariable = isGrandParentTypeAVariable;
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
if (isParentTypeAVariable) {
// Do nothing, it's a variable.
return;
}
auto& propertiesContainersList =
projectScopedContainers.GetPropertiesContainersList();
// Match the potential *new* name of the property, because refactorings are
// done after changes in the variables container.
projectScopedContainers.MatchIdentifierWithName<void>(
GetPotentialNewName(node.identifierName),
// The property name is changed after the refactor operation
node.identifierName,
[&]() {
// Do nothing, it's an object variable.
}, [&]() {
@@ -145,22 +150,29 @@ class GD_CORE_API ExpressionPropertyReplacer
}, [&]() {
// Do nothing, it's a parameter.
}, [&]() {
// This is something else - potentially a deleted property.
// Check if it's coming from the target container with
// properties to replace.
if (propertiesContainersList.HasPropertiesContainer(
targetPropertiesContainer)) {
// The node represents a property, that can come from the target
// (because the target is in the scope), replace or remove it:
RenameOrRemovePropertyOfTargetPropertyContainer(node.identifierName);
}
// Do nothing, it's something else.
});
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
for (auto& parameter : node.parameters) {
parameter->Visit(*this);
void OnVisitFunctionCallNode(FunctionCallNode &node) override {
bool isGrandParentTypeAVariable = isParentTypeAVariable;
for (auto &parameter : node.parameters) {
const auto &parameterMetadata =
gd::MetadataProvider::GetFunctionCallParameterMetadata(
platform, projectScopedContainers.GetObjectsContainersList(),
node, *parameter);
if (!parameterMetadata) {
continue;
}
const auto &parameterTypeMetadata =
parameterMetadata->GetValueTypeMetadata();
if (gd::EventsPropertyReplacer::CanContainProperty(
parameterTypeMetadata)) {
isParentTypeAVariable = parameterTypeMetadata.IsVariableOnly();
parameter->Visit(*this);
}
}
isParentTypeAVariable = isGrandParentTypeAVariable;
}
void OnVisitEmptyNode(EmptyNode& node) override {}
@@ -168,12 +180,6 @@ class GD_CORE_API ExpressionPropertyReplacer
bool hasDoneRenaming;
bool removedPropertyUsed;
const gd::String& GetPotentialNewName(const gd::String& oldName) {
return oldToNewPropertyNames.count(oldName) >= 1
? oldToNewPropertyNames.find(oldName)->second
: oldName;
}
bool RenameOrRemovePropertyOfTargetPropertyContainer(
gd::String& propertyName) {
if (oldToNewPropertyNames.count(propertyName) >= 1) {
@@ -198,6 +204,7 @@ class GD_CORE_API ExpressionPropertyReplacer
const std::unordered_set<gd::String>& removedPropertyNames;
gd::String objectNameToUseForVariableAccessor;
bool isParentTypeAVariable;
};
bool EventsPropertyReplacer::DoVisitInstruction(gd::Instruction& instruction,
@@ -216,20 +223,16 @@ bool EventsPropertyReplacer::DoVisitInstruction(gd::Instruction& instruction,
const gd::Expression& parameterValue,
size_t parameterIndex,
const gd::String& lastObjectName) {
const gd::String& type = parameterMetadata.GetType();
if (!gd::ParameterMetadata::IsExpression("variable", type) &&
!gd::ParameterMetadata::IsExpression("number", type) &&
!gd::ParameterMetadata::IsExpression("string", type))
return; // Not an expression that can contain properties.
if (!gd::EventsPropertyReplacer::CanContainProperty(
parameterMetadata.GetValueTypeMetadata())) {
return;
}
auto node = parameterValue.GetRootNode();
if (node) {
ExpressionPropertyReplacer renamer(platform,
GetProjectScopedContainers(),
targetPropertiesContainer,
oldToNewPropertyNames,
removedPropertyNames);
ExpressionPropertyReplacer renamer(
platform, GetProjectScopedContainers(), targetPropertiesContainer,
parameterMetadata.GetValueTypeMetadata().IsVariableOnly(),
oldToNewPropertyNames, removedPropertyNames);
node->Visit(renamer);
if (renamer.IsRemovedPropertyUsed()) {
@@ -246,20 +249,16 @@ bool EventsPropertyReplacer::DoVisitInstruction(gd::Instruction& instruction,
bool EventsPropertyReplacer::DoVisitEventExpression(
gd::Expression& expression, const gd::ParameterMetadata& metadata) {
const gd::String& type = metadata.GetType();
if (!gd::ParameterMetadata::IsExpression("variable", type) &&
!gd::ParameterMetadata::IsExpression("number", type) &&
!gd::ParameterMetadata::IsExpression("string", type))
return false; // Not an expression that can contain properties.
if (!gd::EventsPropertyReplacer::CanContainProperty(
metadata.GetValueTypeMetadata())) {
return false;
}
auto node = expression.GetRootNode();
if (node) {
ExpressionPropertyReplacer renamer(platform,
GetProjectScopedContainers(),
targetPropertiesContainer,
oldToNewPropertyNames,
removedPropertyNames);
ExpressionPropertyReplacer renamer(
platform, GetProjectScopedContainers(), targetPropertiesContainer,
metadata.GetValueTypeMetadata().IsVariableOnly(), oldToNewPropertyNames,
removedPropertyNames);
node->Visit(renamer);
if (renamer.IsRemovedPropertyUsed()) {
@@ -272,6 +271,12 @@ bool EventsPropertyReplacer::DoVisitEventExpression(
return false;
}
bool EventsPropertyReplacer::CanContainProperty(
const gd::ValueTypeMetadata &valueTypeMetadata) {
return valueTypeMetadata.IsVariable() || valueTypeMetadata.IsNumber() ||
valueTypeMetadata.IsString();
}
EventsPropertyReplacer::~EventsPropertyReplacer() {}
} // namespace gd

View File

@@ -4,6 +4,7 @@
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <map>
#include <memory>
#include <unordered_map>
@@ -41,6 +42,8 @@ class GD_CORE_API EventsPropertyReplacer
removedPropertyNames(removedPropertyNames_){};
virtual ~EventsPropertyReplacer();
static bool CanContainProperty(const gd::ValueTypeMetadata &valueTypeMetadata);
private:
bool DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) override;

View File

@@ -22,6 +22,7 @@
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
using namespace std;
@@ -51,17 +52,17 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
static bool Rename(const gd::Platform &platform,
const gd::ProjectScopedContainers &projectScopedContainers,
const gd::String &rootType,
gd::ExpressionNode& node,
const gd::String& objectName,
const gd::String& objectNewName) {
if (gd::ExpressionValidator::HasNoErrors(platform, projectScopedContainers, rootType, node)) {
ExpressionObjectRenamer renamer(platform, projectScopedContainers, rootType, objectName, objectNewName);
const gd::String &rootType, gd::ExpressionNode &node,
const gd::String &objectName,
const gd::String &objectNewName) {
if (gd::ExpressionValidator::HasNoErrors(platform, projectScopedContainers,
rootType, node)) {
ExpressionObjectRenamer renamer(platform, projectScopedContainers,
rootType, objectName, objectNewName);
node.Visit(renamer);
return renamer.HasDoneRenaming();
}
return false;
}
@@ -83,7 +84,7 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
void OnVisitVariableNode(VariableNode& node) override {
auto type = gd::ExpressionTypeFinder::GetType(platform, projectScopedContainers, rootType, node);
if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
if (gd::ValueTypeMetadata::IsVariable(type)) {
// Nothing to do (this can't reference an object)
} else {
if (node.name == objectName) {
@@ -119,7 +120,7 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
node.identifierName == objectName) {
hasDoneRenaming = true;
node.identifierName = objectNewName;
} else if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
} else if (gd::ValueTypeMetadata::IsVariable(type)) {
// Nothing to do (this can't reference an object)
} else {
if (node.identifierName == objectName) {
@@ -295,183 +296,114 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
const gd::String rootType;
};
bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& actions,
gd::String oldName,
gd::String newName) {
bool somethingModified = false;
/**
* \brief Replace in expressions and in parameters of actions or conditions,
* references to the name of an object by another.
*
* \ingroup IDE
*/
class GD_CORE_API EventsObjectReplacer
: public ArbitraryEventsWorkerWithContext {
public:
EventsObjectReplacer(const gd::Platform &platform_,
const gd::ObjectsContainer &targetedObjectsContainer_,
const gd::String &oldObjectName_,
const gd::String &newObjectName_)
: platform(platform_),
targetedObjectsContainer(targetedObjectsContainer_),
oldObjectName(oldObjectName_), newObjectName(newObjectName_){};
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.GetParametersCount(); ++pNb) {
// Replace object's name in parameters
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.GetParameter(pNb).GetType())) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
virtual ~EventsObjectReplacer() {}
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
actions[aId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
actions[aId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
}
private:
bool DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) override {
if (&targetedObjectsContainer !=
GetProjectScopedContainers()
.GetObjectsContainersList()
.GetObjectsContainerFromObjectName(oldObjectName)) {
return false;
}
const auto &metadata = isCondition
? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
if (!actions[aId].GetSubInstructions().empty())
somethingModified =
RenameObjectInActions(platform,
projectScopedContainers,
actions[aId].GetSubInstructions(),
oldName,
newName) ||
somethingModified;
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
instruction.GetParameters(), metadata.GetParameters(),
[&](const gd::ParameterMetadata &parameterMetadata,
const gd::Expression &parameterValue, size_t parameterIndex,
const gd::String &lastObjectName) {
if (!gd::EventsObjectReplacer::CanContainObject(
parameterMetadata.GetValueTypeMetadata())) {
return;
}
auto node = parameterValue.GetRootNode();
if (node) {
ExpressionObjectRenamer renamer(
platform, GetProjectScopedContainers(),
parameterMetadata.GetValueTypeMetadata().GetName(),
oldObjectName, newObjectName);
node->Visit(renamer);
if (renamer.HasDoneRenaming()) {
instruction.SetParameter(
parameterIndex,
ExpressionParser2NodePrinter::PrintNode(*node));
}
}
});
return false;
}
return somethingModified;
}
bool EventsRefactorer::RenameObjectInConditions(
const gd::Platform& platform,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& conditions,
gd::String oldName,
gd::String newName) {
bool somethingModified = false;
for (std::size_t cId = 0; cId < conditions.size(); ++cId) {
const gd::InstructionMetadata& instrInfos =
MetadataProvider::GetConditionMetadata(platform,
conditions[cId].GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
// Replace object's name in parameters
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.GetParameter(pNb).GetType())) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
conditions[cId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
conditions[cId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
}
bool DoVisitEventExpression(gd::Expression &expression,
const gd::ParameterMetadata &metadata) override {
if (&targetedObjectsContainer !=
GetProjectScopedContainers()
.GetObjectsContainersList()
.GetObjectsContainerFromObjectName(oldObjectName)) {
return false;
}
if (!gd::EventsObjectReplacer::CanContainObject(
metadata.GetValueTypeMetadata())) {
return false;
}
if (!conditions[cId].GetSubInstructions().empty())
somethingModified =
RenameObjectInConditions(platform,
projectScopedContainers,
conditions[cId].GetSubInstructions(),
oldName,
newName) ||
somethingModified;
}
return somethingModified;
}
bool EventsRefactorer::RenameObjectInEventParameters(
const gd::Platform& platform,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::Expression& expression,
gd::ParameterMetadata parameterMetadata,
gd::String oldName,
gd::String newName) {
bool somethingModified = false;
if (gd::ParameterMetadata::IsObject(parameterMetadata.GetType()) &&
expression.GetPlainString() == oldName)
expression = gd::Expression(newName);
// Replace object's name in expressions
else if (ParameterMetadata::IsExpression("number",
parameterMetadata.GetType())) {
auto node = expression.GetRootNode();
if (node) {
ExpressionObjectRenamer renamer(platform, GetProjectScopedContainers(),
metadata.GetValueTypeMetadata().GetName(),
oldObjectName, newObjectName);
node->Visit(renamer);
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
expression = ExpressionParser2NodePrinter::PrintNode(*node);
if (renamer.HasDoneRenaming()) {
expression = ExpressionParser2NodePrinter::PrintNode(*node);
}
}
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression("string",
parameterMetadata.GetType())) {
auto node = expression.GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
expression = ExpressionParser2NodePrinter::PrintNode(*node);
}
return false;
}
return somethingModified;
}
bool CanContainObject(const gd::ValueTypeMetadata &valueTypeMetadata) {
return valueTypeMetadata.IsObject() || valueTypeMetadata.IsVariable() ||
valueTypeMetadata.IsNumber() || valueTypeMetadata.IsString();
}
const gd::Platform &platform;
const gd::ObjectsContainer &targetedObjectsContainer;
const gd::String &oldObjectName;
const gd::String &newObjectName;
};
void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::EventsList& events,
const gd::ObjectsContainer &targetedObjectsContainer,
gd::String oldName,
gd::String newName) {
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 somethingModified = RenameObjectInConditions(
platform, projectScopedContainers, *conditionsVectors[j], oldName, newName);
}
vector<gd::InstructionsList*> actionsVectors =
events[i].GetAllActionsVectors();
for (std::size_t j = 0; j < actionsVectors.size(); ++j) {
bool somethingModified = RenameObjectInActions(
platform, projectScopedContainers, *actionsVectors[j], oldName, newName);
}
vector<pair<gd::Expression*, gd::ParameterMetadata>>
expressionsWithMetadata = events[i].GetAllExpressionsWithMetadata();
for (std::size_t j = 0; j < expressionsWithMetadata.size(); ++j) {
gd::Expression* expression = expressionsWithMetadata[j].first;
gd::ParameterMetadata parameterMetadata =
expressionsWithMetadata[j].second;
bool somethingModified = RenameObjectInEventParameters(platform,
projectScopedContainers,
*expression,
parameterMetadata,
oldName,
newName);
}
if (events[i].CanHaveSubEvents())
RenameObjectInEvents(platform,
projectScopedContainers,
events[i].GetSubEvents(),
oldName,
newName);
}
gd::EventsObjectReplacer eventsParameterReplacer(platform, targetedObjectsContainer, oldName, newName);
eventsParameterReplacer.Launch(events, projectScopedContainers);
}
bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,

View File

@@ -83,6 +83,7 @@ class GD_CORE_API EventsRefactorer {
static void RenameObjectInEvents(const gd::Platform& platform,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::EventsList& events,
const gd::ObjectsContainer &targetedObjectsContainer,
gd::String oldName,
gd::String newName);
@@ -121,44 +122,6 @@ class GD_CORE_API EventsRefactorer {
virtual ~EventsRefactorer(){};
private:
/**
* Replace all occurrences of an object name by another name in an action
* ( include : objects in parameters and in math/text expressions ).
*
* \return true if something was modified.
*/
static bool RenameObjectInActions(const gd::Platform& platform,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& instructions,
gd::String oldName,
gd::String newName);
/**
* Replace all occurrences of an object name by another name in a condition
* ( include : objects in parameters and in math/text expressions ).
*
* \return true if something was modified.
*/
static bool RenameObjectInConditions(const gd::Platform& platform,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& instructions,
gd::String oldName,
gd::String newName);
/**
* Replace all occurrences of an object name by another name in an expression
* with the specified metadata
* ( include : objects or objects in math/text expressions ).
*
* \return true if something was modified.
*/
static bool RenameObjectInEventParameters(
const gd::Platform& platform,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::Expression& expression,
gd::ParameterMetadata parameterMetadata,
gd::String oldName,
gd::String newName);
/**
* Remove all conditions of the list using an object
*

View File

@@ -71,13 +71,18 @@ bool EventsVariableInstructionTypeSwitcher::DoVisitInstruction(gd::Instruction&
.GetObjectsContainersList()
.GetObjectOrGroupVariablesContainer(lastObjectName);
}
} else if (type == "variableOrProperty") {
variablesContainer =
&GetProjectScopedContainers()
.GetVariablesContainersList()
.GetVariablesContainerFromVariableOrPropertyName(variableName);
} else {
if (GetProjectScopedContainers().GetVariablesContainersList().Has(
variableName)) {
variablesContainer =
&GetProjectScopedContainers()
.GetVariablesContainersList()
.GetVariablesContainerFromVariableName(variableName);
.GetVariablesContainerFromVariableOrPropertyOrParameterName(variableName);
}
}

View File

@@ -122,7 +122,7 @@ class GD_CORE_API ExpressionVariableReplacer
[&]() {
// This is a variable.
if (&projectScopedContainers.GetVariablesContainersList()
.GetVariablesContainerFromVariableName(node.name) ==
.GetVariablesContainerFromVariableOrPropertyOrParameterName(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:
@@ -235,7 +235,7 @@ class GD_CORE_API ExpressionVariableReplacer
[&]() {
// This is a variable.
if (&projectScopedContainers.GetVariablesContainersList()
.GetVariablesContainerFromVariableName(
.GetVariablesContainerFromVariableOrPropertyOrParameterName(
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:

View File

@@ -73,6 +73,7 @@ class GD_CORE_API EventsVariableReplacer
*/
const gd::String targetGroupName;
const VariablesRenamingChangesetNode &variablesRenamingChangesetRoot;
// TODO There is no reason de delete events. This dead code should be removed.
const std::unordered_set<gd::String> &removedVariableNames;
static VariablesContainer nullVariablesContainer;

View File

@@ -0,0 +1,235 @@
#include "ExampleExtensionUsagesFinder.h"
#include "GDCore/Events/Instruction.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/IDE/ProjectBrowserHelper.h"
#include "GDCore/IDE/WholeProjectRefactorer.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
namespace gd {
std::set<gd::String>
ExampleExtensionUsagesFinder::GetUsedExtensions(gd::Project &project) {
ExampleExtensionUsagesFinder worker(project);
gd::ProjectBrowserHelper::ExposeProjectObjects(project, worker);
gd::ProjectBrowserHelper::ExposeProjectEventsWithoutExtensions(project,
worker);
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
e++) {
auto &eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
worker.isStoreExtension =
eventsFunctionsExtension.GetOriginName() == "gdevelop-extension-store";
ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
project, eventsFunctionsExtension, worker);
}
if (!worker.has3DObjects) {
worker.usedExtensions.erase("Scene3D");
}
return worker.usedExtensions;
};
void ExampleExtensionUsagesFinder::AddUsedExtension(
const gd::PlatformExtension &extension) {
usedExtensions.insert(extension.GetName());
}
void ExampleExtensionUsagesFinder::AddUsedBuiltinExtension(
const gd::String &extensionName) {
usedExtensions.insert(extensionName);
}
// Objects scanner
void ExampleExtensionUsagesFinder::DoVisitObject(gd::Object &object) {
auto metadata = gd::MetadataProvider::GetExtensionAndObjectMetadata(
project.GetCurrentPlatform(), object.GetType());
if (metadata.GetMetadata().IsRenderedIn3D()) {
has3DObjects = true;
}
AddUsedExtension(metadata.GetExtension());
};
// Behaviors scanner
void ExampleExtensionUsagesFinder::DoVisitBehavior(gd::Behavior &behavior) {
auto metadata = gd::MetadataProvider::GetExtensionAndBehaviorMetadata(
project.GetCurrentPlatform(), behavior.GetTypeName());
AddUsedExtension(metadata.GetExtension());
};
// Instructions scanner
bool ExampleExtensionUsagesFinder::DoVisitInstruction(
gd::Instruction &instruction, bool isCondition) {
auto metadata =
isCondition ? gd::MetadataProvider::GetExtensionAndConditionMetadata(
project.GetCurrentPlatform(), instruction.GetType())
: gd::MetadataProvider::GetExtensionAndActionMetadata(
project.GetCurrentPlatform(), instruction.GetType());
// Unused event-based objects or events-based behaviors may use object and
// behavior instructions that should not be detected as extension usage.
// The extension of actually used objects and behaviors will be detected on
// scene objects. This is why object or behavior instructions usually don't
// have any import.
// Built-in extensions that are included by default don't declare any include
// files on their instructions either. To still detect their usage, we
// consider that main events and dedicated extensions can't have dead code.
if (!isStoreExtension || !metadata.GetMetadata().GetIncludeFiles().empty()) {
AddUsedExtension(metadata.GetExtension());
}
gd::ParameterMetadataTools::IterateOverParameters(
instruction.GetParameters(), metadata.GetMetadata().GetParameters(),
[this](const gd::ParameterMetadata &parameterMetadata,
const gd::Expression &parameterValue,
const gd::String &lastObjectName) {
const gd::String &parameterType = parameterMetadata.GetType();
if (gd::ParameterMetadata::IsExpression("string", parameterType)) {
rootType = "string";
parameterValue.GetRootNode()->Visit(*this);
} else if (gd::ParameterMetadata::IsExpression("number",
parameterType)) {
rootType = "number";
parameterValue.GetRootNode()->Visit(*this);
} else if (gd::ParameterMetadata::IsExpression("variable",
parameterType))
AddUsedBuiltinExtension("BuiltinVariables");
});
return false;
}
// Expressions scanner
// Ignore literals nodes
void ExampleExtensionUsagesFinder::OnVisitNumberNode(NumberNode &node){};
void ExampleExtensionUsagesFinder::OnVisitTextNode(TextNode &node){};
// Ignore nodes without valid extensions
void ExampleExtensionUsagesFinder::OnVisitEmptyNode(EmptyNode &node){};
void ExampleExtensionUsagesFinder::OnVisitObjectFunctionNameNode(
ObjectFunctionNameNode &node){};
// Visit sub-expressions
void ExampleExtensionUsagesFinder::OnVisitSubExpressionNode(
SubExpressionNode &node) {
node.expression->Visit(*this);
};
void ExampleExtensionUsagesFinder::OnVisitOperatorNode(OperatorNode &node) {
node.leftHandSide->Visit(*this);
node.rightHandSide->Visit(*this);
};
void ExampleExtensionUsagesFinder::OnVisitUnaryOperatorNode(
UnaryOperatorNode &node) {
node.factor->Visit(*this);
};
// Add variable extension and visit sub-expressions on variable nodes
void ExampleExtensionUsagesFinder::OnVisitVariableNode(VariableNode &node) {
AddUsedBuiltinExtension("BuiltinVariables");
auto type = gd::ExpressionTypeFinder::GetType(project.GetCurrentPlatform(),
GetProjectScopedContainers(),
rootType, node);
if (gd::ParameterMetadata::IsExpression("variable", type)) {
// Nothing to do (this can't reference an object)
} else {
GetProjectScopedContainers().MatchIdentifierWithName<void>(
node.name,
[&]() {
// This represents an object.
auto metadata = gd::MetadataProvider::GetExtensionAndObjectMetadata(
project.GetCurrentPlatform(), node.name);
AddUsedExtension(metadata.GetExtension());
},
[&]() {
// This is a variable.
},
[&]() {
// This is a property.
},
[&]() {
// This is a parameter.
},
[&]() {
// This is something else.
});
}
if (node.child)
node.child->Visit(*this);
};
void ExampleExtensionUsagesFinder::OnVisitVariableAccessorNode(
VariableAccessorNode &node) {
AddUsedBuiltinExtension("BuiltinVariables");
if (node.child)
node.child->Visit(*this);
};
void ExampleExtensionUsagesFinder::OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode &node) {
AddUsedBuiltinExtension("BuiltinVariables");
node.expression->Visit(*this);
if (node.child)
node.child->Visit(*this);
};
// Add extensions bound to Objects/Behaviors/Functions
void ExampleExtensionUsagesFinder::OnVisitIdentifierNode(IdentifierNode &node) {
auto type = gd::ExpressionTypeFinder::GetType(project.GetCurrentPlatform(),
GetProjectScopedContainers(),
rootType, node);
if (gd::ParameterMetadata::IsObject(type) ||
GetObjectsContainersList().HasObjectOrGroupNamed(node.identifierName)) {
// An object or object variable is used.
auto metadata = gd::MetadataProvider::GetExtensionAndObjectMetadata(
project.GetCurrentPlatform(), node.identifierName);
AddUsedExtension(metadata.GetExtension());
}
};
void ExampleExtensionUsagesFinder::OnVisitFunctionCallNode(
FunctionCallNode &node) {
// Extensions of non-free functions are already found when scanning objects.
if (!(node.objectName.empty() && node.behaviorName.empty()))
return;
gd::ExtensionAndMetadata<gd::ExpressionMetadata> metadata;
// Try to find a free number expression
metadata = gd::MetadataProvider::GetExtensionAndExpressionMetadata(
project.GetCurrentPlatform(), node.functionName);
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata.GetMetadata())) {
// Try to find a free str expression
metadata = gd::MetadataProvider::GetExtensionAndStrExpressionMetadata(
project.GetCurrentPlatform(), node.functionName);
// No valid expression found, return.
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata.GetMetadata()))
return;
}
// Unused event-based objects or events-based behaviors may use object and
// behavior expressions that should not be detected as extension usage.
// The extension of actually used objects and behaviors will be detected on
// scene objects. This is why object or behavior expressions usually don't
// have any import.
// Built-in extensions that are included by default don't declare any include
// files on their instructions either. To still detect their usage, we
// consider that main events and dedicated extensions can't have dead code.
if (!isStoreExtension || !metadata.GetMetadata().GetIncludeFiles().empty()) {
AddUsedExtension(metadata.GetExtension());
}
};
} // namespace gd

View File

@@ -0,0 +1,77 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <set>
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/SourceFileMetadata.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/String.h"
namespace gd {
class Project;
class Object;
class Behavior;
} // namespace gd
namespace gd {
/**
* @brief List extension usages for generated example web-pages.
*
* Dependency transitivity is not ensured (see UsedExtensionsFinder).
*/
class GD_CORE_API ExampleExtensionUsagesFinder
: public ArbitraryObjectsWorker,
public ArbitraryEventsWorkerWithContext,
public ExpressionParser2NodeWorker {
public:
static std::set<gd::String> GetUsedExtensions(gd::Project &project);
private:
ExampleExtensionUsagesFinder(gd::Project &project_) : project(project_){};
gd::Project &project;
gd::String rootType;
bool isStoreExtension = false;
// Result
std::set<gd::String> usedExtensions;
bool has3DObjects = false;
void AddUsedExtension(const gd::PlatformExtension &extension);
void AddUsedBuiltinExtension(const gd::String &extensionName);
// Object Visitor
void DoVisitObject(gd::Object &object) override;
// Behavior Visitor
void DoVisitBehavior(gd::Behavior &behavior) override;
// Instructions Visitor
bool DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) override;
// Expression Visitor
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;
void OnVisitVariableAccessorNode(VariableAccessorNode &node) override;
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode &node) override;
void OnVisitIdentifierNode(IdentifierNode &node) override;
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode &node) override;
void OnVisitFunctionCallNode(FunctionCallNode &node) override;
void OnVisitEmptyNode(EmptyNode &node) override;
};
}; // namespace gd

View File

@@ -1034,7 +1034,7 @@ class GD_CORE_API ExpressionCompletionFinder
description.SetVariableType(variable.GetType());
description.SetVariableScope(
projectScopedContainers.GetVariablesContainersList()
.GetVariablesContainerFromVariableName(variableName)
.GetVariablesContainerFromVariableOrPropertyOrParameterName(variableName)
.GetSourceType());
completions.push_back(description);
@@ -1066,8 +1066,8 @@ class GD_CORE_API ExpressionCompletionFinder
bool eagerlyCompleteIfExactMatch = false) {
projectScopedContainers.ForEachIdentifierMatchingSearch(
search,
[&](const gd::String& objectName,
const ObjectConfiguration* objectConfiguration) {
[&](const gd::String &objectName,
const ObjectConfiguration *objectConfiguration) {
ExpressionCompletionDescription description(
ExpressionCompletionDescription::Object,
location.GetStartPosition(),
@@ -1077,7 +1077,7 @@ class GD_CORE_API ExpressionCompletionFinder
description.SetType(type);
completions.push_back(description);
},
[&](const gd::String& variableName, const gd::Variable& variable) {
[&](const gd::String &variableName, const gd::Variable &variable) {
ExpressionCompletionDescription description(
ExpressionCompletionDescription::Variable,
location.GetStartPosition(),
@@ -1086,7 +1086,7 @@ class GD_CORE_API ExpressionCompletionFinder
description.SetVariableType(variable.GetType());
description.SetVariableScope(
projectScopedContainers.GetVariablesContainersList()
.GetVariablesContainerFromVariableName(variableName)
.GetVariablesContainerFromVariableOrPropertyOrParameterName(variableName)
.GetSourceType());
completions.push_back(description);
@@ -1095,23 +1095,29 @@ class GD_CORE_API ExpressionCompletionFinder
variable, variableName, location);
}
},
[&](const gd::NamedPropertyDescriptor& property) {
ExpressionCompletionDescription description(
ExpressionCompletionDescription::Property,
location.GetStartPosition(),
location.GetEndPosition());
description.SetCompletion(property.GetName());
description.SetType(property.GetType());
completions.push_back(description);
[&](const gd::NamedPropertyDescriptor &property) {
auto propertyType = gd::ValueTypeMetadata::ConvertPropertyTypeToValueType(
property.GetType());
if (gd::ValueTypeMetadata::IsTypeValue("number", propertyType) ||
gd::ValueTypeMetadata::IsTypeValue("string", propertyType)) {
ExpressionCompletionDescription description(
ExpressionCompletionDescription::Property,
location.GetStartPosition(), location.GetEndPosition());
description.SetCompletion(property.GetName());
description.SetType(property.GetType());
completions.push_back(description);
}
},
[&](const gd::ParameterMetadata& parameter) {
ExpressionCompletionDescription description(
ExpressionCompletionDescription::Parameter,
location.GetStartPosition(),
location.GetEndPosition());
description.SetCompletion(parameter.GetName());
description.SetType(parameter.GetType());
completions.push_back(description);
[&](const gd::ParameterMetadata &parameter) {
if (parameter.GetValueTypeMetadata().IsNumber() ||
parameter.GetValueTypeMetadata().IsString()) {
ExpressionCompletionDescription description(
ExpressionCompletionDescription::Parameter,
location.GetStartPosition(), location.GetEndPosition());
description.SetCompletion(parameter.GetName());
description.SetType(parameter.GetType());
completions.push_back(description);
}
});
}

View File

@@ -68,19 +68,26 @@ size_t GetMaximumParametersNumber(
bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
const gd::IdentifierNode& identifier) {
return ValidateObjectVariableOrVariableOrProperty(identifier.identifierName, identifier.identifierNameLocation, identifier.childIdentifierName, identifier.childIdentifierNameLocation);
}
bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
const gd::String &identifierName,
const gd::ExpressionParserLocation identifierNameLocation,
const gd::String &childIdentifierName,
const gd::ExpressionParserLocation childIdentifierNameLocation) {
auto validateVariableTypeForExpression =
[this, &identifier](gd::Variable::Type type) {
[this, &identifierNameLocation](gd::Variable::Type type) {
// Collections type can't be used directly in expressions, a child
// must be accessed.
if (type == Variable::Structure) {
RaiseTypeError(_("You need to specify the name of the child variable "
"to access. For example: `MyVariable.child`."),
identifier.identifierNameLocation);
identifierNameLocation);
} else if (type == Variable::Array) {
RaiseTypeError(_("You need to specify the name of the child variable "
"to access. For example: `MyVariable[0]`."),
identifier.identifierNameLocation);
identifierNameLocation);
} else {
// Number, string or boolean variables can be used in expressions.
return;
@@ -96,38 +103,41 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
// we consider this node will be of the type required by the parent.
childType = parentType;
return projectScopedContainers.MatchIdentifierWithName<bool>(identifier.identifierName,
return projectScopedContainers.MatchIdentifierWithName<bool>(identifierName,
[&]() {
// This represents an object.
if (identifier.childIdentifierName.empty()) {
if (childIdentifierName.empty()) {
RaiseTypeError(_("An object variable or expression should be entered."),
identifier.identifierNameLocation);
identifierNameLocation);
return true; // We should have found a variable.
}
auto variableExistence = objectsContainersList.HasObjectOrGroupWithVariableNamed(identifier.identifierName, identifier.childIdentifierName);
auto variableExistence =
objectsContainersList.HasObjectOrGroupWithVariableNamed(
identifierName, childIdentifierName);
if (variableExistence == gd::ObjectsContainersList::DoesNotExist) {
RaiseUndeclaredVariableError(_("This variable does not exist on this object or group."),
identifier.childIdentifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
childIdentifierNameLocation, childIdentifierName, identifierName);
return true; // We should have found a variable.
}
else if (variableExistence == gd::ObjectsContainersList::ExistsOnlyOnSomeObjectsOfTheGroup) {
RaiseUndeclaredVariableError(_("This variable only exists on some objects of the group. It must be declared for all objects."),
identifier.childIdentifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
childIdentifierNameLocation, childIdentifierName, identifierName);
return true; // We should have found a variable.
}
else if (variableExistence == gd::ObjectsContainersList::GroupIsEmpty) {
RaiseUndeclaredVariableError(_("This group is empty. Add an object to this group first."),
identifier.identifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
identifierNameLocation, childIdentifierName, identifierName);
return true; // We should have found a variable.
}
auto variableType = objectsContainersList.GetTypeOfObjectOrGroupVariable(identifier.identifierName, identifier.childIdentifierName);
auto variableType = objectsContainersList.GetTypeOfObjectOrGroupVariable(
identifierName, childIdentifierName);
ReadChildTypeFromVariable(variableType);
return true; // We found a variable.
@@ -137,9 +147,9 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
// Try to identify a declared variable with the name (and maybe the child
// variable).
const gd::Variable& variable =
variablesContainersList.Get(identifier.identifierName);
variablesContainersList.Get(identifierName);
if (identifier.childIdentifierName.empty()) {
if (childIdentifierName.empty()) {
// Just the root variable is accessed, check it can be used in an
// expression.
validateVariableTypeForExpression(variable.GetType());
@@ -148,33 +158,38 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
return true; // We found a variable.
} else {
// A child variable is accessed, check it can be used in an expression.
if (!variable.HasChild(identifier.childIdentifierName)) {
if (!variable.HasChild(childIdentifierName)) {
RaiseTypeError(_("No child variable with this name found."),
identifier.childIdentifierNameLocation);
childIdentifierNameLocation);
return true; // We should have found a variable.
}
const gd::Variable& childVariable =
variable.GetChild(identifier.childIdentifierName);
variable.GetChild(childIdentifierName);
ReadChildTypeFromVariable(childVariable.GetType());
return true; // We found a variable.
}
}, [&]() {
// This is a property.
if (!identifier.childIdentifierName.empty()) {
if (!childIdentifierName.empty()) {
RaiseTypeError(_("Accessing a child variable of a property is not possible - just write the property name."),
identifier.childIdentifierNameLocation);
childIdentifierNameLocation);
return true; // We found a property, even if the child is not allowed.
}
const gd::NamedPropertyDescriptor& property = propertiesContainersList.Get(identifier.identifierName).second;
const gd::NamedPropertyDescriptor &property =
propertiesContainersList.Get(identifierName).second;
if (property.GetType() == "Number") {
childType = Type::Number;
childType = Type::Number;
} else if (property.GetType() == "Boolean") {
// Nothing - we don't know the precise type (this could be used a string or as a number)
// Nothing - we don't know the precise type (this could be used a string
// or as a number)
} else if (property.GetType() == "Behavior") {
RaiseTypeError(_("Behaviors can't be used as a value in expressions."),
identifierNameLocation);
} else {
// Assume type is String or equivalent.
childType = Type::String;
@@ -183,14 +198,14 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
return true; // We found a property.
}, [&]() {
// This is a parameter.
if (!identifier.childIdentifierName.empty()) {
if (!childIdentifierName.empty()) {
RaiseTypeError(_("Accessing a child variable of a parameter is not possible - just write the parameter name."),
identifier.childIdentifierNameLocation);
childIdentifierNameLocation);
return true; // We found a parameter, even if the child is not allowed.
}
const auto& parameter = gd::ParameterMetadataTools::Get(parametersVectorsList, identifier.identifierName);
const auto& parameter = gd::ParameterMetadataTools::Get(parametersVectorsList, identifierName);
const auto& valueTypeMetadata = parameter.GetValueTypeMetadata();
if (valueTypeMetadata.IsNumber()) {
childType = Type::Number;
@@ -200,7 +215,7 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
// Nothing - we don't know the precise type (this could be used as a string or as a number).
} else {
RaiseTypeError(_("This parameter is not a string, number or boolean - it can't be used in an expression."),
identifier.identifierNameLocation);
identifierNameLocation);
return true; // We found a parameter, even though the type is incompatible.
}
@@ -445,10 +460,12 @@ const gd::String& ExpressionValidator::TypeToString(Type type) {
case Type::NumberOrString:
return numberOrStringTypeString;
case Type::Variable:
return variableTypeString;
// This function is only used to display errors.
// Users don't care if it's legacy or not or
// if it allows properties and parameters.
case Type::VariableOrProperty:
case Type::VariableOrPropertyOrParameter:
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;
@@ -478,8 +495,11 @@ ExpressionValidator::Type ExpressionValidator::StringToType(
ExpressionValidator::variableTypeString, type)) {
if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
return Type::LegacyVariable;
}
else {
} else if (type == "variableOrProperty") {
return Type::VariableOrProperty;
} else if (type == "variableOrPropertyOrParameter") {
return Type::VariableOrPropertyOrParameter;
} else {
return Type::Variable;
}
}

View File

@@ -14,6 +14,7 @@
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/Project/VariablesContainersList.h"
#include "GDCore/Project/VariablesContainer.h"
namespace gd {
class Expression;
@@ -45,7 +46,9 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
parentType(StringToType(gd::ValueTypeMetadata::GetExpressionPrimitiveValueType(rootType_))),
childType(Type::Unknown),
forbidsUsageOfBracketsBecauseParentIsObject(false),
currentParameterExtraInfo(&extraInfo_) {};
currentParameterExtraInfo(&extraInfo_),
variableObjectName(),
variableObjectNameLocation() {};
virtual ~ExpressionValidator(){};
/**
@@ -200,10 +203,12 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
void OnVisitVariableNode(VariableNode& node) override {
ReportAnyError(node);
if (parentType == Type::Variable) {
if (parentType == Type::Variable ||
parentType == Type::VariableOrProperty ||
parentType == Type::VariableOrPropertyOrParameter) {
childType = parentType;
CheckVariableExistence(node.location, node.name);
CheckVariableExistence(node.location, node.name, node.child != nullptr);
if (node.child) {
node.child->Visit(*this);
}
@@ -213,7 +218,8 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
if (node.child) {
node.child->Visit(*this);
}
} else if (parentType == Type::String || parentType == Type::Number || parentType == Type::NumberOrString) {
} else if (parentType == Type::String || parentType == Type::Number ||
parentType == Type::NumberOrString) {
// The node represents a variable or an object variable in an expression waiting for its *value* to be returned.
childType = parentType;
@@ -225,7 +231,8 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
projectScopedContainers.MatchIdentifierWithName<void>(node.name,
[&]() {
// This represents an object.
variableObjectName = node.name;
variableObjectNameLocation = node.nameLocation;
// While understood by the parser, it's forbidden to use the bracket notation just after
// an object name (`MyObject["MyVariable"]`).
forbidsUsageOfBracketsBecauseParentIsObject = true;
@@ -264,7 +271,13 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
ReportAnyError(node);
// TODO Also check child-variables existence on a path with only VariableAccessor to raise non-fatal errors.
if (!variableObjectName.empty()) {
ValidateObjectVariableOrVariableOrProperty(variableObjectName,
variableObjectNameLocation,
node.name, node.nameLocation);
variableObjectName = "";
}
// In the case we accessed an object variable (`MyObject.MyVariable`),
// brackets can now be used (`MyObject.MyVariable["MyChildVariable"]` is now valid).
forbidsUsageOfBracketsBecauseParentIsObject = false;
@@ -277,6 +290,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
VariableBracketAccessorNode& node) override {
ReportAnyError(node);
variableObjectName = "";
if (forbidsUsageOfBracketsBecauseParentIsObject) {
RaiseError(gd::ExpressionParserError::ErrorType::BracketsNotAllowedForObjects,
_("You can't use the brackets to access an object variable. "
@@ -325,11 +339,12 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
_("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::Variable) {
CheckVariableExistence(node.location, node.identifierName);
}
else if (parentType != Type::Object && parentType != Type::LegacyVariable) {
} else if (parentType == Type::Variable ||
parentType == Type::VariableOrProperty ||
parentType == Type::VariableOrPropertyOrParameter) {
CheckVariableExistence(node.location, node.identifierName, !node.childIdentifierName.empty());
} 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),
@@ -365,13 +380,31 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
childType = Type::Empty;
}
private:
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, LegacyVariable, Object, Empty};
private:
enum Type {
Unknown = 0,
Number,
String,
NumberOrString,
Variable,
LegacyVariable,
Object,
Empty,
VariableOrProperty,
VariableOrPropertyOrParameter
};
Type ValidateFunction(const gd::FunctionCallNode& function);
bool ValidateObjectVariableOrVariableOrProperty(const gd::IdentifierNode& identifier);
bool ValidateObjectVariableOrVariableOrProperty(
const gd::String &identifierName,
const gd::ExpressionParserLocation identifierNameLocation,
const gd::String &childIdentifierName,
const gd::ExpressionParserLocation childIdentifierNameLocation);
void CheckVariableExistence(const ExpressionParserLocation &location, const gd::String& name) {
if (!currentParameterExtraInfo || *currentParameterExtraInfo != "AllowUndeclaredVariable") {
void CheckVariableExistence(const ExpressionParserLocation &location,
const gd::String &name, bool hasChild) {
if (!currentParameterExtraInfo ||
*currentParameterExtraInfo != "AllowUndeclaredVariable") {
projectScopedContainers.MatchIdentifierWithName<void>(
name,
[&]() {
@@ -386,19 +419,28 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
},
[&]() {
// 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);
if (parentType != Type::VariableOrProperty &&
parentType != Type::VariableOrPropertyOrParameter) {
RaiseVariableNameCollisionError(
_("This variable has the same name as a property. Consider "
"renaming one or the other."),
location, name);
} else if (hasChild) {
RaiseMalformedVariableParameter(
_("Properties can't have children."), 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);
if (parentType != Type::VariableOrPropertyOrParameter) {
RaiseVariableNameCollisionError(
_("This variable has the same name as a parameter. Consider "
"renaming one or the other."),
location, name);
} else if (hasChild) {
RaiseMalformedVariableParameter(
_("Properties can't have children."), location, name);
}
},
[&]() {
// This is something else.
@@ -460,6 +502,13 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
message, location, false, variableName, objectName);
}
void RaiseMalformedVariableParameter(const gd::String &message,
const ExpressionParserLocation &location,
const gd::String &variableName) {
RaiseError(gd::ExpressionParserError::ErrorType::MalformedVariableParameter,
message, location, true, variableName, "");
}
void RaiseTypeError(const gd::String &message,
const ExpressionParserLocation &location,
bool isFatal = true) {
@@ -505,6 +554,8 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
Type childType; ///< The type "discovered" down the tree and passed up.
Type parentType; ///< The type "required" by the top of the tree.
bool forbidsUsageOfBracketsBecauseParentIsObject;
gd::String variableObjectName;
gd::ExpressionParserLocation variableObjectNameLocation;
const gd::String *currentParameterExtraInfo;
const gd::Platform &platform;
const gd::ProjectScopedContainers &projectScopedContainers;

View File

@@ -215,7 +215,7 @@ class GD_CORE_API ExpressionVariablePathFinder
if (projectScopedContainers.GetVariablesContainersList().Has(identifier)) {
variablesContainer =
&(projectScopedContainers.GetVariablesContainersList()
.GetVariablesContainerFromVariableName(identifier));
.GetVariablesContainerFromVariableOrPropertyOrParameterName(identifier));
variableName = identifier;
if (childIdentifier) {
childVariableNames.push_back(*childIdentifier);
@@ -223,12 +223,28 @@ class GD_CORE_API ExpressionVariablePathFinder
}
},
[&]() {
// Ignore properties here.
// There is no support for "children" of properties.
// This is a property.
if (parameterType != "objectvar" &&
projectScopedContainers.GetVariablesContainersList().Has(
identifier)) {
variablesContainer =
&(projectScopedContainers.GetVariablesContainersList()
.GetVariablesContainerFromVariableOrPropertyOrParameterName(identifier));
variableName = identifier;
// There is no support for "children" of properties.
}
},
[&]() {
// Ignore parameters here.
// There is no support for "children" of parameters.
// This is a parameter.
if (parameterType != "objectvar" &&
projectScopedContainers.GetVariablesContainersList().Has(
identifier)) {
variablesContainer =
&(projectScopedContainers.GetVariablesContainersList()
.GetVariablesContainerFromVariableOrPropertyOrParameterName(identifier));
variableName = identifier;
// There is no support for "children" of parameters.
}
},
[&]() {
// Ignore unrecognised identifiers here.

View File

@@ -0,0 +1,76 @@
#include "LeaderboardIdRenamer.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/String.h"
namespace gd {
void LeaderboardIdRenamer::DoVisitObject(gd::Object &object) {
for (auto &pair : object.GetConfiguration().GetProperties()) {
auto &propertyName = pair.first;
auto &property = pair.second;
if (property.GetType() == "LeaderboardId") {
auto &leaderboardId = property.GetValue();
allLeaderboardIds.insert(leaderboardId);
if (leaderboardIdMap.find(leaderboardId) != leaderboardIdMap.end()) {
object.GetConfiguration().UpdateProperty(
propertyName, leaderboardIdMap[leaderboardId]);
}
}
}
};
void LeaderboardIdRenamer::DoVisitBehavior(gd::Behavior &behavior) {};
bool LeaderboardIdRenamer::DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) {
const gd::InstructionMetadata &instrInfo =
isCondition ? MetadataProvider::GetConditionMetadata(
project.GetCurrentPlatform(), instruction.GetType())
: MetadataProvider::GetActionMetadata(
project.GetCurrentPlatform(), instruction.GetType());
for (int i = 0; i < instruction.GetParametersCount() &&
i < instrInfo.GetParametersCount();
++i) {
const gd::ParameterMetadata parameter = instrInfo.GetParameter(i);
if (parameter.GetType() != "leaderboardId") {
continue;
}
const gd::String leaderboardIdExpression =
instruction.GetParameter(i).GetPlainString();
if (leaderboardIdExpression[0] != '"' ||
leaderboardIdExpression[leaderboardIdExpression.size() - 1] != '"') {
continue;
}
const gd::String leaderboardId =
leaderboardIdExpression.substr(1, leaderboardIdExpression.size() - 2);
allLeaderboardIds.insert(leaderboardId);
if (leaderboardIdMap.find(leaderboardId) != leaderboardIdMap.end()) {
instruction.SetParameter(i,
"\"" + leaderboardIdMap[leaderboardId] + "\"");
}
}
return false;
}
LeaderboardIdRenamer::~LeaderboardIdRenamer() {}
} // namespace gd

View File

@@ -0,0 +1,50 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <map>
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class Object;
class Behavior;
} // namespace gd
namespace gd {
class GD_CORE_API LeaderboardIdRenamer : public ArbitraryObjectsWorker, public ArbitraryEventsWorker {
public:
LeaderboardIdRenamer(gd::Project& project_): project(project_) {};
virtual ~LeaderboardIdRenamer();
/**
* Set the leaderboard identifiers to be replaced.
*/
void SetLeaderboardIdsToReplace(const std::map<gd::String, gd::String>& leaderboardIdMap_) {
leaderboardIdMap = leaderboardIdMap_;
}
/**
* Return the all the leaderboard identifiers found in the project.
*/
const std::set<gd::String>& GetAllLeaderboardIds() const {
return allLeaderboardIds;
}
private:
bool DoVisitInstruction(gd::Instruction& instruction, bool isCondition) override;
void DoVisitObject(gd::Object& object) override;
void DoVisitBehavior(gd::Behavior& behavior) override;
std::map<gd::String, gd::String> leaderboardIdMap;
std::set<gd::String> allLeaderboardIds;
gd::Project& project;
};
}; // namespace gd

View File

@@ -13,6 +13,18 @@
namespace gd {
void UsedExtensionsResult::AddUsedExtension(const gd::PlatformExtension& extension) {
usedExtensions.insert(extension.GetName());
usedSourceFiles.insert(usedSourceFiles.end(),
extension.GetAllSourceFiles().begin(),
extension.GetAllSourceFiles().end());
}
void UsedExtensionsResult::AddUsedBuiltinExtension(const gd::String& extensionName) {
usedExtensions.insert(extensionName);
}
const UsedExtensionsResult UsedExtensionsFinder::ScanProject(gd::Project& project) {
UsedExtensionsFinder worker(project);
gd::ProjectBrowserHelper::ExposeProjectObjects(project, worker);
@@ -28,9 +40,9 @@ void UsedExtensionsFinder::DoVisitObject(gd::Object &object) {
if (metadata.GetMetadata().IsRenderedIn3D()) {
result.MarkAsHaving3DObjects();
}
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());
result.AddUsedExtension(metadata.GetExtension());
for (auto &&includeFile : metadata.GetMetadata().includeFiles) {
result.GetUsedIncludeFiles().insert(includeFile);
result.AddUsedIncludeFiles(includeFile);
}
};
@@ -39,12 +51,12 @@ void UsedExtensionsFinder::DoVisitObject(gd::Object &object) {
void UsedExtensionsFinder::DoVisitBehavior(gd::Behavior &behavior) {
auto metadata = gd::MetadataProvider::GetExtensionAndBehaviorMetadata(
project.GetCurrentPlatform(), behavior.GetTypeName());
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());
result.AddUsedExtension(metadata.GetExtension());
for (auto &&includeFile : metadata.GetMetadata().includeFiles) {
result.GetUsedIncludeFiles().insert(includeFile);
result.AddUsedIncludeFiles(includeFile);
}
for (auto &&includeFile : metadata.GetMetadata().requiredFiles) {
result.GetUsedRequiredFiles().insert(includeFile);
result.AddUsedRequiredFiles(includeFile);
}
};
@@ -57,9 +69,9 @@ bool UsedExtensionsFinder::DoVisitInstruction(gd::Instruction& instruction,
project.GetCurrentPlatform(), instruction.GetType())
: gd::MetadataProvider::GetExtensionAndActionMetadata(
project.GetCurrentPlatform(), instruction.GetType());
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());
result.AddUsedExtension(metadata.GetExtension());
for (auto&& includeFile : metadata.GetMetadata().GetIncludeFiles()) {
result.GetUsedIncludeFiles().insert(includeFile);
result.AddUsedIncludeFiles(includeFile);
}
gd::ParameterMetadataTools::IterateOverParameters(
@@ -77,7 +89,7 @@ bool UsedExtensionsFinder::DoVisitInstruction(gd::Instruction& instruction,
rootType = "number";
parameterValue.GetRootNode()->Visit(*this);
} else if (gd::ParameterMetadata::IsExpression("variable", parameterType))
result.GetUsedExtensions().insert("BuiltinVariables");
result.AddUsedBuiltinExtension("BuiltinVariables");
});
return false;
@@ -110,7 +122,7 @@ void UsedExtensionsFinder::OnVisitUnaryOperatorNode(UnaryOperatorNode& node) {
// Add variable extension and visit sub-expressions on variable nodes
void UsedExtensionsFinder::OnVisitVariableNode(VariableNode& node) {
result.GetUsedExtensions().insert("BuiltinVariables");
result.AddUsedBuiltinExtension("BuiltinVariables");
auto type = gd::ExpressionTypeFinder::GetType(
project.GetCurrentPlatform(), GetProjectScopedContainers(), rootType, node);
@@ -123,9 +135,9 @@ void UsedExtensionsFinder::OnVisitVariableNode(VariableNode& node) {
// This represents an object.
auto metadata = gd::MetadataProvider::GetExtensionAndObjectMetadata(
project.GetCurrentPlatform(), node.name);
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());
result.AddUsedExtension(metadata.GetExtension());
for (auto &&includeFile : metadata.GetMetadata().includeFiles) {
result.GetUsedIncludeFiles().insert(includeFile);
result.AddUsedIncludeFiles(includeFile);
}
}, [&]() {
// This is a variable.
@@ -143,13 +155,13 @@ void UsedExtensionsFinder::OnVisitVariableNode(VariableNode& node) {
void UsedExtensionsFinder::OnVisitVariableAccessorNode(
VariableAccessorNode& node) {
result.GetUsedExtensions().insert("BuiltinVariables");
result.AddUsedBuiltinExtension("BuiltinVariables");
if (node.child) node.child->Visit(*this);
};
void UsedExtensionsFinder::OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) {
result.GetUsedExtensions().insert("BuiltinVariables");
result.AddUsedBuiltinExtension("BuiltinVariables");
node.expression->Visit(*this);
if (node.child) node.child->Visit(*this);
};
@@ -163,9 +175,9 @@ void UsedExtensionsFinder::OnVisitIdentifierNode(IdentifierNode &node) {
// An object or object variable is used.
auto metadata = gd::MetadataProvider::GetExtensionAndObjectMetadata(
project.GetCurrentPlatform(), node.identifierName);
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());
result.AddUsedExtension(metadata.GetExtension());
for (auto &&includeFile : metadata.GetMetadata().includeFiles) {
result.GetUsedIncludeFiles().insert(includeFile);
result.AddUsedIncludeFiles(includeFile);
}
}
};
@@ -187,9 +199,9 @@ void UsedExtensionsFinder::OnVisitFunctionCallNode(FunctionCallNode& node) {
return;
}
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());
result.AddUsedExtension(metadata.GetExtension());
for (auto&& includeFile : metadata.GetMetadata().GetIncludeFiles()) {
result.GetUsedIncludeFiles().insert(includeFile);
result.AddUsedIncludeFiles(includeFile);
}
};

View File

@@ -9,6 +9,8 @@
#include <set>
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/SourceFileMetadata.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/String.h"
@@ -44,6 +46,10 @@ public:
return usedRequiredFiles;
}
const std::vector<gd::SourceFileMetadata>& GetUsedSourceFiles() const {
return usedSourceFiles;
}
/**
* \brief Return true when at least 1 object uses the 3D renderer.
*/
@@ -51,20 +57,10 @@ public:
return has3DObjects;
}
/**
* The extensions used by the project (or part of it).
*/
std::set<gd::String> &GetUsedExtensions() { return usedExtensions; }
/**
* The include files used at runtime by the project (or part of it).
*/
std::set<gd::String> &GetUsedIncludeFiles() { return usedIncludeFiles; }
/**
* The additional files required at runtime by the project (or part of it).
*/
std::set<gd::String> &GetUsedRequiredFiles() { return usedRequiredFiles; }
void AddUsedExtension(const gd::PlatformExtension& extension);
void AddUsedBuiltinExtension(const gd::String& extensionName);
void AddUsedIncludeFiles(const gd::String& includeFile) { usedIncludeFiles.insert(includeFile); }
void AddUsedRequiredFiles(const gd::String& requiredFile) { usedRequiredFiles.insert(requiredFile); }
void MarkAsHaving3DObjects() {
has3DObjects = true;
@@ -74,6 +70,7 @@ private:
std::set<gd::String> usedExtensions;
std::set<gd::String> usedIncludeFiles;
std::set<gd::String> usedRequiredFiles;
std::vector<gd::SourceFileMetadata> usedSourceFiles;
bool has3DObjects = false;
};

View File

@@ -0,0 +1,157 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "EventsBasedObjectVariantHelper.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/InitialInstancesContainer.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectGroup.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/ObjectsContainersList.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/Variable.h"
#include "GDCore/Project/VariablesContainer.h"
#include "GDCore/String.h"
namespace gd {
void EventsBasedObjectVariantHelper::ComplyVariantsToEventsBasedObject(
const gd::Project &project, gd::EventsBasedObject &eventsBasedObject) {
auto &defaultObjects = eventsBasedObject.GetDefaultVariant().GetObjects();
for (const auto &variant :
eventsBasedObject.GetVariants().GetInternalVector()) {
auto &objects = variant->GetObjects();
// Delete extra objects
for (auto it = objects.GetObjects().begin();
it != objects.GetObjects().end(); ++it) {
const auto &objectName = it->get()->GetName();
if (!defaultObjects.HasObjectNamed(objectName)) {
variant->GetInitialInstances().RemoveInitialInstancesOfObject(
objectName);
// Do it in last because it unalloc objectName.
objects.RemoveObject(objectName);
--it;
}
}
for (const auto &defaultObject : defaultObjects.GetObjects()) {
const auto &objectName = defaultObject->GetName();
const auto &defaultVariables = defaultObject->GetVariables();
const auto &defaultBehaviors = defaultObject->GetAllBehaviorContents();
// Copy missing objects
if (!objects.HasObjectNamed(objectName)) {
objects.InsertObject(*defaultObject,
defaultObjects.GetObjectPosition(objectName));
objects.AddMissingObjectsInRootFolder();
continue;
}
// Change object types
auto &object = objects.GetObject(objectName);
if (object.GetType() != defaultObject->GetType()) {
// Keep a copy of the old object.
auto oldObject = objects.GetObject(objectName);
objects.RemoveObject(objectName);
objects.InsertObject(*defaultObject,
defaultObjects.GetObjectPosition(objectName));
object.CopyWithoutConfiguration(oldObject);
objects.AddMissingObjectsInRootFolder();
}
// Copy missing behaviors
auto &behaviors = object.GetAllBehaviorContents();
for (const auto &pair : defaultBehaviors) {
const auto &behaviorName = pair.first;
const auto &defaultBehavior = pair.second;
if (object.HasBehaviorNamed(behaviorName) &&
object.GetBehavior(behaviorName).GetTypeName() !=
defaultBehavior->GetTypeName()) {
object.RemoveBehavior(behaviorName);
}
if (!object.HasBehaviorNamed(behaviorName)) {
auto *behavior = object.AddNewBehavior(
project, defaultBehavior->GetTypeName(), behaviorName);
gd::SerializerElement element;
defaultBehavior->SerializeTo(element);
behavior->UnserializeFrom(element);
}
}
// Delete extra behaviors
for (auto it = behaviors.begin(); it != behaviors.end(); ++it) {
const auto &behaviorName = it->first;
if (!defaultObject->HasBehaviorNamed(behaviorName)) {
object.RemoveBehavior(behaviorName);
--it;
}
}
// Sort and copy missing variables
auto &variables = object.GetVariables();
for (size_t defaultVariableIndex = 0;
defaultVariableIndex < defaultVariables.Count();
defaultVariableIndex++) {
const auto &variableName =
defaultVariables.GetNameAt(defaultVariableIndex);
const auto &defaultVariable =
defaultVariables.Get(defaultVariableIndex);
auto variableIndex = variables.GetPosition(variableName);
if (variableIndex == gd::String::npos) {
variables.Insert(variableName, defaultVariable, defaultVariableIndex);
} else {
variables.Move(variableIndex, defaultVariableIndex);
}
if (variables.Get(variableName).GetType() != defaultVariable.GetType()) {
variables.Remove(variableName);
variables.Insert(variableName, defaultVariable, defaultVariableIndex);
}
}
// Remove extra variables
auto variableToRemoveCount = variables.Count() - defaultVariables.Count();
for (size_t iteration = 0; iteration < variableToRemoveCount;
iteration++) {
variables.Remove(variables.GetNameAt(variables.Count() - 1));
}
// Remove extra instance variables
variant->GetInitialInstances().IterateOverInstances(
[&objectName,
&defaultVariables](gd::InitialInstance &initialInstance) {
if (initialInstance.GetObjectName() != objectName) {
return false;
}
auto &instanceVariables = initialInstance.GetVariables();
for (size_t instanceVariableIndex = 0;
instanceVariableIndex < instanceVariables.Count();
instanceVariableIndex++) {
const auto &variableName =
defaultVariables.GetNameAt(instanceVariableIndex);
if (!defaultVariables.Has(variableName)) {
instanceVariables.Remove(variableName);
}
}
return false;
});
}
auto &defaultObjectGroups =
eventsBasedObject.GetDefaultVariant().GetObjects().GetObjectGroups();
auto &objectGroups = variant->GetObjects().GetObjectGroups();
auto objectGroupsCount = objectGroups.Count();
// Clear groups
for (size_t index = 0; index < objectGroupsCount; index++) {
objectGroups.Remove(objectGroups.Get(0).GetName());
}
// Copy groups
for (size_t index = 0; index < defaultObjectGroups.Count(); index++) {
objectGroups.Insert(defaultObjectGroups.Get(index), index);
}
}
}
} // namespace gd

View File

@@ -0,0 +1,26 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
namespace gd {
class EventsBasedObject;
class Project;
} // namespace gd
namespace gd {
class GD_CORE_API EventsBasedObjectVariantHelper {
public:
/**
* @brief Apply the changes done on events-based object children to all its
* variants.
*/
static void
ComplyVariantsToEventsBasedObject(const gd::Project &project,
gd::EventsBasedObject &eventsBasedObject);
};
} // namespace gd

View File

@@ -9,7 +9,10 @@
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/EventsBasedObject.h"
//#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/ParameterMetadataContainer.h"
#include "GDCore/Project/PropertiesContainer.h"
#include "GDCore/Project/VariablesContainer.h"
#include "GDCore/Project/EventsFunction.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
@@ -24,15 +27,16 @@ void EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
const gd::EventsFunction& eventsFunction,
gd::ObjectsContainer& outputObjectsContainer) {
// Functions scope for objects is defined according
// to parameters
outputObjectsContainer.GetObjects().clear();
outputObjectsContainer.GetObjectGroups().Clear();
// to parameters.
auto &parameters = eventsFunction.GetParametersForEvents(functionContainer);
gd::ParameterMetadataTools::ParametersToObjectsContainer(
project,
parameters,
outputObjectsContainer);
// TODO: in theory we should ensure stability of the groups across calls
// to this function. BUT groups in functions should probably have never been
// supported, so we're phasing this out in the UI.
outputObjectsContainer.GetObjectGroups() = eventsFunction.GetObjectGroups();
}
@@ -97,25 +101,73 @@ void EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
"for the parent. ");
return;
}
gd::EventsFunctionTools::CopyEventsBasedObjectChildrenToObjectsContainer(
eventsBasedObject, outputObjectsContainer);
}
void EventsFunctionTools::CopyEventsBasedObjectChildrenToObjectsContainer(
const gd::EventsBasedObject& eventsBasedObject,
gd::ObjectsContainer& outputObjectsContainer) {
auto &children = eventsBasedObject.GetObjects().GetObjects();
for (auto &childObject : children) {
auto child = childObject.get();
outputObjectsContainer.InsertObject(
*child, outputObjectsContainer.GetObjectsCount());
void EventsFunctionTools::ParametersToVariablesContainer(
const ParameterMetadataContainer &parameters,
gd::VariablesContainer &outputVariablesContainer) {
if (outputVariablesContainer.GetSourceType() !=
gd::VariablesContainer::SourceType::Parameters) {
throw std::logic_error("Tried to generate a variables container from "
"parameters with the wrong source type.");
}
auto &childrenGroups = eventsBasedObject.GetObjects().GetObjectGroups();
for (size_t index = 0; index < childrenGroups.Count(); ++index) {
auto &childGroup = childrenGroups.Get(index);
outputObjectsContainer.GetObjectGroups().Insert(
childGroup, outputObjectsContainer.GetObjectGroups().Count());
outputVariablesContainer.Clear();
gd::String lastObjectName;
for (std::size_t i = 0; i < parameters.GetParametersCount(); ++i) {
const auto &parameter = parameters.GetParameter(i);
if (parameter.GetName().empty())
continue;
auto &valueTypeMetadata = parameter.GetValueTypeMetadata();
if (valueTypeMetadata.IsNumber()) {
auto &variable = outputVariablesContainer.InsertNew(
parameter.GetName(), outputVariablesContainer.Count());
variable.SetValue(0);
} else if (valueTypeMetadata.IsString()) {
auto &variable = outputVariablesContainer.InsertNew(
parameter.GetName(), outputVariablesContainer.Count());
variable.SetString("");
} else if (valueTypeMetadata.IsBoolean()) {
auto &variable = outputVariablesContainer.InsertNew(
parameter.GetName(), outputVariablesContainer.Count());
variable.SetBool(false);
}
}
}
void EventsFunctionTools::PropertiesToVariablesContainer(
const PropertiesContainer &properties,
gd::VariablesContainer &outputVariablesContainer) {
if (outputVariablesContainer.GetSourceType() !=
gd::VariablesContainer::SourceType::Properties) {
throw std::logic_error("Tried to generate a variables container from "
"properties with the wrong source type.");
}
outputVariablesContainer.Clear();
gd::String lastObjectName;
for (std::size_t i = 0; i < properties.GetCount(); ++i) {
const auto &property = properties.Get(i);
if (property.GetName().empty())
continue;
auto &propertyType = gd::ValueTypeMetadata::GetPrimitiveValueType(
gd::ValueTypeMetadata::ConvertPropertyTypeToValueType(
property.GetType()));
if (propertyType == "number") {
auto &variable = outputVariablesContainer.InsertNew(
property.GetName(), outputVariablesContainer.Count());
variable.SetValue(0);
} else if (propertyType == "string") {
auto &variable = outputVariablesContainer.InsertNew(
property.GetName(), outputVariablesContainer.Count());
variable.SetString("");
} else if (propertyType == "boolean") {
auto &variable = outputVariablesContainer.InsertNew(
property.GetName(), outputVariablesContainer.Count());
variable.SetBool(false);
}
}
}

View File

@@ -12,6 +12,9 @@ namespace gd {
class Project;
class EventsFunctionsContainer;
class ObjectsContainer;
class ParameterMetadataContainer;
class PropertiesContainer;
class VariablesContainer;
class ParameterMetadata;
class EventsFunction;
class EventsBasedBehavior;
@@ -69,8 +72,12 @@ class GD_CORE_API EventsFunctionTools {
const gd::EventsFunction& eventsFunction,
gd::ObjectsContainer& outputObjectsContainer);
static void CopyEventsBasedObjectChildrenToObjectsContainer(
const gd::EventsBasedObject &eventsBasedObject,
gd::ObjectsContainer &outputObjectsContainer);
static void ParametersToVariablesContainer(
const ParameterMetadataContainer &parameters,
gd::VariablesContainer &outputVariablesContainer);
static void PropertiesToVariablesContainer(
const PropertiesContainer &properties,
gd::VariablesContainer &outputVariablesContainer);
};
} // namespace gd

View File

@@ -17,6 +17,8 @@
#include "GDCore/IDE/Project/ResourcesRenamer.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/CustomBehavior.h"
#include "GDCore/Project/CustomObjectConfiguration.h"
#include "GDCore/Project/EventsBasedObjectVariant.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
@@ -60,9 +62,6 @@ void ObjectAssetSerializer::SerializeTo(
element.SetAttribute("version", "");
element.SetIntAttribute("animationsCount", 1);
element.SetIntAttribute("maxFramesCount", 1);
// TODO Find the right object dimensions.
element.SetIntAttribute("width", 0);
element.SetIntAttribute("height", 0);
SerializerElement &authorsElement = element.AddChild("authors");
authorsElement.ConsiderAsArrayOf("author");
SerializerElement &tagsElement = element.AddChild("tags");
@@ -75,6 +74,28 @@ void ObjectAssetSerializer::SerializeTo(
cleanObject->SerializeTo(objectAssetElement.AddChild("object"));
double width = 0;
double height = 0;
if (project.HasEventsBasedObject(object.GetType())) {
SerializerElement &variantsElement =
objectAssetElement.AddChild("variants");
variantsElement.ConsiderAsArrayOf("variant");
const auto *variant = ObjectAssetSerializer::GetVariant(project, object);
if (variant) {
width = variant->GetAreaMaxX() - variant->GetAreaMinX();
height = variant->GetAreaMaxY() - variant->GetAreaMinY();
}
std::unordered_set<gd::String> alreadyUsedVariantIdentifiers;
gd::ObjectAssetSerializer::SerializeUsedVariantsTo(
project, object, variantsElement, alreadyUsedVariantIdentifiers);
}
// TODO Find the right object dimensions when their is no variant.
element.SetIntAttribute("width", width);
element.SetIntAttribute("height", height);
SerializerElement &resourcesElement =
objectAssetElement.AddChild("resources");
resourcesElement.ConsiderAsArrayOf("resource");
@@ -108,4 +129,59 @@ void ObjectAssetSerializer::SerializeTo(
objectAssetElement.AddChild("customization");
customizationElement.ConsiderAsArrayOf("empty");
}
void ObjectAssetSerializer::SerializeUsedVariantsTo(
gd::Project &project, const gd::Object &object,
SerializerElement &variantsElement,
std::unordered_set<gd::String> &alreadyUsedVariantIdentifiers) {
const auto *variant = ObjectAssetSerializer::GetVariant(project, object);
if (!variant) {
return;
}
const auto &variantIdentifier =
object.GetType() + gd::PlatformExtension::GetNamespaceSeparator() +
variant->GetName();
auto insertResult = alreadyUsedVariantIdentifiers.insert(variantIdentifier);
if (!insertResult.second) {
return;
}
SerializerElement &pairElement = variantsElement.AddChild("variant");
pairElement.SetAttribute("objectType", object.GetType());
SerializerElement &variantElement = pairElement.AddChild("variant");
variant->SerializeTo(variantElement);
for (auto &object : variant->GetObjects().GetObjects()) {
gd::ObjectAssetSerializer::SerializeUsedVariantsTo(
project, *object, variantsElement, alreadyUsedVariantIdentifiers);
}
}
const gd::EventsBasedObjectVariant *
ObjectAssetSerializer::GetVariant(gd::Project &project,
const gd::Object &object) {
if (!project.HasEventsBasedObject(object.GetType())) {
return nullptr;
}
const auto &eventsBasedObject =
project.GetEventsBasedObject(object.GetType());
const auto &variants = eventsBasedObject.GetVariants();
const auto *customObjectConfiguration =
dynamic_cast<const gd::CustomObjectConfiguration *>(
&object.GetConfiguration());
const auto &variantName = customObjectConfiguration->GetVariantName();
if (!variants.HasVariantNamed(variantName) &&
(customObjectConfiguration
->IsMarkedAsOverridingEventsBasedObjectChildrenConfiguration() ||
customObjectConfiguration
->IsForcedToOverrideEventsBasedObjectChildrenConfiguration())) {
return nullptr;
}
const auto &variantIdentifier =
object.GetType() + gd::PlatformExtension::GetNamespaceSeparator() +
variantName;
const auto &variant = variants.HasVariantNamed(variantName)
? variants.GetVariant(variantName)
: eventsBasedObject.GetDefaultVariant();
return &variant;
}
} // namespace gd

View File

@@ -6,6 +6,7 @@
#pragma once
#include <map>
#include <vector>
#include <unordered_set>
#include "GDCore/String.h"
@@ -20,6 +21,7 @@ class InitialInstance;
class SerializerElement;
class EffectsContainer;
class AbstractFileSystem;
class EventsBasedObjectVariant;
} // namespace gd
namespace gd {
@@ -52,6 +54,13 @@ private:
ObjectAssetSerializer(){};
static gd::String GetObjectExtensionName(const gd::Object &object);
static void SerializeUsedVariantsTo(
gd::Project &project, const gd::Object &object,
SerializerElement &variantsElement,
std::unordered_set<gd::String> &alreadyUsedVariantIdentifiers);
static const gd::EventsBasedObjectVariant* GetVariant(gd::Project &project, const gd::Object &object);
};
} // namespace gd

View File

@@ -3,9 +3,11 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GroupVariableHelper.h"
#include "ObjectVariableHelper.h"
#include "GDCore/IDE/WholeProjectRefactorer.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/InitialInstancesContainer.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectGroup.h"
#include "GDCore/Project/ObjectsContainer.h"
@@ -16,7 +18,7 @@
namespace gd {
void GroupVariableHelper::FillAnyVariableBetweenObjects(
void ObjectVariableHelper::FillAnyVariableBetweenObjects(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer,
const gd::ObjectGroup &objectGroup) {
@@ -65,7 +67,7 @@ void GroupVariableHelper::FillAnyVariableBetweenObjects(
}
}
gd::VariablesContainer GroupVariableHelper::MergeVariableContainers(
gd::VariablesContainer ObjectVariableHelper::MergeVariableContainers(
const gd::ObjectsContainersList &objectsContainersList,
const gd::ObjectGroup &objectGroup) {
gd::VariablesContainer mergedVariablesContainer;
@@ -113,7 +115,7 @@ gd::VariablesContainer GroupVariableHelper::MergeVariableContainers(
return mergedVariablesContainer;
}
void GroupVariableHelper::FillMissingGroupVariablesToObjects(
void ObjectVariableHelper::FillMissingGroupVariablesToObjects(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer, const gd::ObjectGroup &objectGroup,
const gd::SerializerElement &originalSerializedVariables) {
@@ -145,7 +147,7 @@ void GroupVariableHelper::FillMissingGroupVariablesToObjects(
// TODO Handle position changes for group variables.
// We could try to change the order of object variables in a way that the next
// call to MergeVariableContainers rebuild them in the same order.
void GroupVariableHelper::ApplyChangesToObjects(
void ObjectVariableHelper::ApplyChangesToObjects(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer,
const gd::VariablesContainer &groupVariablesContainer,
@@ -172,6 +174,7 @@ void GroupVariableHelper::ApplyChangesToObjects(
groupVariablesContainer.Get(variableName),
variablesContainer.Count());
}
// TODO Check what happens if 2 variables exchange their names.
for (const auto &pair : changeset.oldToNewVariableNames) {
const gd::String &oldVariableName = pair.first;
const gd::String &newVariableName = pair.second;
@@ -193,4 +196,109 @@ void GroupVariableHelper::ApplyChangesToObjects(
}
}
void ObjectVariableHelper::ApplyChangesToObjectInstances(
gd::VariablesContainer &objectVariablesContainer,
gd::InitialInstancesContainer &initialInstancesContainer,
const gd::String &objectName, const gd::VariablesChangeset &changeset) {
initialInstancesContainer.IterateOverInstances(
[&objectVariablesContainer, &objectName,
&changeset](gd::InitialInstance &instance) {
if (instance.GetObjectName() == objectName) {
auto &destinationVariablesContainer = instance.GetVariables();
for (const gd::String &variableName :
changeset.removedVariableNames) {
destinationVariablesContainer.Remove(variableName);
}
for (const gd::String &variableName : changeset.addedVariableNames) {
// Instance variables may already exist with another type.
if (destinationVariablesContainer.Has(variableName) &&
destinationVariablesContainer.Get(variableName).GetType() !=
objectVariablesContainer.Get(variableName).GetType()) {
destinationVariablesContainer.Remove(variableName);
}
}
// TODO Check what happens if 2 variables exchange their names.
for (const auto &pair : changeset.oldToNewVariableNames) {
const gd::String &oldVariableName = pair.first;
const gd::String &newVariableName = pair.second;
if (destinationVariablesContainer.Has(newVariableName)) {
// It can happens if an instance already had the variable.
destinationVariablesContainer.Remove(oldVariableName);
} else {
destinationVariablesContainer.Rename(oldVariableName,
newVariableName);
}
}
// Apply type changes
for (const gd::String &variableName :
changeset.valueChangedVariableNames) {
if (destinationVariablesContainer.Has(variableName) &&
destinationVariablesContainer.Get(variableName).GetType() !=
objectVariablesContainer.Get(variableName).GetType()) {
destinationVariablesContainer.Remove(variableName);
}
}
}
return false;
});
}
void ObjectVariableHelper::ApplyChangesToVariants(
gd::EventsBasedObject &eventsBasedObject, const gd::String &objectName,
const gd::VariablesChangeset &changeset) {
auto &defaultVariablesContainer = eventsBasedObject.GetDefaultVariant()
.GetObjects()
.GetObject(objectName)
.GetVariables();
for (auto &variant : eventsBasedObject.GetVariants().GetInternalVector()) {
if (!variant->GetObjects().HasObjectNamed(objectName)) {
continue;
}
auto &object = variant->GetObjects().GetObject(objectName);
auto &variablesContainer = object.GetVariables();
for (const gd::String &variableName : changeset.removedVariableNames) {
variablesContainer.Remove(variableName);
}
for (const gd::String &variableName : changeset.addedVariableNames) {
if (variablesContainer.Has(variableName)) {
// It can happens if a child-object already had the variable but it was
// missing in other variant child-object.
continue;
}
variablesContainer.Insert(variableName,
defaultVariablesContainer.Get(variableName),
variablesContainer.Count());
}
// TODO Check what happens if 2 variables exchange their names.
for (const auto &pair : changeset.oldToNewVariableNames) {
const gd::String &oldVariableName = pair.first;
const gd::String &newVariableName = pair.second;
if (variablesContainer.Has(newVariableName)) {
// It can happens if a child-object already had the variable but it was
// missing in other variant child-object.
variablesContainer.Remove(oldVariableName);
} else {
variablesContainer.Rename(oldVariableName, newVariableName);
}
}
// Apply type changes
for (const gd::String &variableName : changeset.valueChangedVariableNames) {
size_t index = variablesContainer.GetPosition(variableName);
if (variablesContainer.Has(variableName) &&
variablesContainer.Get(variableName).GetType() !=
defaultVariablesContainer.Get(variableName).GetType()) {
variablesContainer.Remove(variableName);
variablesContainer.Insert(
variableName, defaultVariablesContainer.Get(variableName), index);
}
}
gd::ObjectVariableHelper::ApplyChangesToObjectInstances(
variablesContainer, variant->GetInitialInstances(), objectName,
changeset);
}
}
} // namespace gd

View File

@@ -8,6 +8,8 @@
#include "GDCore/Project/VariablesContainer.h"
namespace gd {
class EventsBasedObject;
class InitialInstancesContainer;
class ObjectsContainersList;
class ObjectsContainer;
class ObjectGroup;
@@ -22,7 +24,7 @@ namespace gd {
*
* This is used by the object group variable editor.
*/
class GD_CORE_API GroupVariableHelper {
class GD_CORE_API ObjectVariableHelper {
public:
/**
* Copy every variable from every object of the group to the other objects
@@ -52,7 +54,7 @@ public:
* Objects can be added during the group edition and may not necessarily have
* all the variables initially shared by the group.
*
* \see gd::GroupVariableHelper::MergeVariableContainers
* \see gd::ObjectVariableHelper::MergeVariableContainers
*/
static void FillMissingGroupVariablesToObjects(
gd::ObjectsContainer &globalObjectsContainer,
@@ -70,6 +72,22 @@ public:
const gd::VariablesContainer &groupVariablesContainer,
const gd::ObjectGroup &objectGroup,
const gd::VariablesChangeset &changeset);
/**
* @brief Apply the changes done on an object to all its instances.
*/
static void ApplyChangesToObjectInstances(
gd::VariablesContainer &objectVariablesContainer,
gd::InitialInstancesContainer &initialInstancesContainer,
const gd::String &objectName, const gd::VariablesChangeset &changeset);
/**
* @brief Apply the changes done on events-based object child to all its
* variants.
*/
static void ApplyChangesToVariants(gd::EventsBasedObject &eventsBasedObject,
const gd::String &objectName,
const gd::VariablesChangeset &changeset);
};
} // namespace gd
} // namespace gd

View File

@@ -62,6 +62,11 @@ void ArbitraryResourceWorker::ExposeSpine(gd::String& resourceName){
// do.
};
void ArbitraryResourceWorker::ExposeJavaScript(gd::String& resourceName){
// Nothing to do by default - each child class can define here the action to
// do.
};
void ArbitraryResourceWorker::ExposeVideo(gd::String& videoName){
// Nothing to do by default - each child class can define here the action to
// do.
@@ -195,6 +200,10 @@ void ArbitraryResourceWorker::ExposeResourceWithType(
ExposeSpine(resourceName);
return;
}
if (resourceType == "javascript") {
ExposeJavaScript(resourceName);
return;
}
gd::LogError("Unexpected resource type: " + resourceType + " for: " + resourceName);
return;
}
@@ -293,7 +302,7 @@ void ResourceWorkerInObjectsWorker::DoVisitObject(gd::Object &object) {
};
void ResourceWorkerInObjectsWorker::DoVisitBehavior(gd::Behavior &behavior){
// TODO Allow behaviors to expose resources
behavior.ExposeResources(worker);
};
gd::ResourceWorkerInObjectsWorker

View File

@@ -96,7 +96,7 @@ public:
* \brief Expose a 3D model, which is always a reference to a "model3D" resource.
*/
virtual void ExposeModel3D(gd::String &resourceName);
/**
* \brief Expose an atlas, which is always a reference to a "atlas" resource.
*/
@@ -112,6 +112,11 @@ public:
*/
virtual void ExposeVideo(gd::String &videoName);
/**
* \brief Expose a JavaScript file, which is always a reference to a "javascript" resource.
*/
virtual void ExposeJavaScript(gd::String &javaScriptName);
/**
* \brief Expose a bitmap font, which is always a reference to a "bitmapFont" resource.
*/

View File

@@ -38,6 +38,10 @@ void AssetResourcePathCleaner::ExposeVideo(gd::String &videoName) {
ExposeResourceAsFile(videoName);
}
void AssetResourcePathCleaner::ExposeJavaScript(gd::String &javaScriptResourceName) {
ExposeResourceAsFile(javaScriptResourceName);
}
void AssetResourcePathCleaner::ExposeBitmapFont(gd::String &bitmapFontName) {
ExposeResourceAsFile(bitmapFontName);
}

View File

@@ -46,6 +46,7 @@ public:
void ExposeTileset(gd::String &tilesetName) override;
void ExposeVideo(gd::String &videoName) override;
void ExposeBitmapFont(gd::String &bitmapFontName) override;
void ExposeJavaScript(gd::String &javaScriptResourceName) override;
void ExposeFile(gd::String &resource) override;
protected:

View File

@@ -73,6 +73,9 @@ public:
virtual void ExposeVideo(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
virtual void ExposeJavaScript(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
virtual void ExposeBitmapFont(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};

View File

@@ -60,6 +60,7 @@ public:
if (resourceType == "model3D") return allModel3Ds;
if (resourceType == "atlas") return allAtlases;
if (resourceType == "spine") return allSpines;
if (resourceType == "javascript") return allJavaScripts;
return emptyResources;
};
@@ -88,6 +89,9 @@ public:
virtual void ExposeVideo(gd::String& resourceName) override {
allVideos.insert(resourceName);
};
virtual void ExposeJavaScript(gd::String& resourceName) override {
allJavaScripts.insert(resourceName);
};
virtual void ExposeBitmapFont(gd::String& resourceName) override {
allBitmapFonts.insert(resourceName);
};
@@ -114,6 +118,7 @@ public:
std::set<gd::String> allModel3Ds;
std::set<gd::String> allAtlases;
std::set<gd::String> allSpines;
std::set<gd::String> allJavaScripts;
std::set<gd::String> emptyResources;
static const std::vector<gd::String> resourceTypes;

View File

@@ -59,6 +59,9 @@ class ResourcesRenamer : public gd::ArbitraryResourceWorker {
virtual void ExposeVideo(gd::String& videoResourceName) override {
RenameIfNeeded(videoResourceName);
};
virtual void ExposeJavaScript(gd::String& javaScriptResourceName) override {
RenameIfNeeded(javaScriptResourceName);
};
virtual void ExposeBitmapFont(gd::String& bitmapFontName) override {
RenameIfNeeded(bitmapFontName);
};

View File

@@ -74,6 +74,9 @@ private:
void ExposeVideo(gd::String &videoResourceName) override {
AddUsedResource(videoResourceName);
};
void ExposeJavaScript(gd::String &javaScriptResourceName) override {
AddUsedResource(javaScriptResourceName);
};
void ExposeBitmapFont(gd::String &bitmapFontName) override {
AddUsedResource(bitmapFontName);
};

View File

@@ -26,8 +26,24 @@ namespace gd {
void ProjectBrowserHelper::ExposeProjectEvents(
gd::Project &project, gd::ArbitraryEventsWorker &worker) {
// See also gd::Project::ExposeResources for a method that traverses the whole
// project (this time for resources).
// See also gd::ResourceExposer::ExposeWholeProjectResources
// for a method that traverses the whole project (this time for resources).
ExposeProjectEventsWithoutExtensions(project, worker);
// Add events based extensions
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
e++) {
auto &eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(project, eventsFunctionsExtension, worker);
}
}
void ProjectBrowserHelper::ExposeProjectEvents(
gd::Project &project, gd::ArbitraryEventsWorkerWithContext &worker) {
// See also gd::ResourceExposer::ExposeWholeProjectResources
// for a method that traverses the whole project (this time for resources)
// and ExposeProjectEffects (this time for effects).
ExposeProjectEventsWithoutExtensions(project, worker);
@@ -51,6 +67,28 @@ void ProjectBrowserHelper::ExposeProjectEventsWithoutExtensions(
}
}
void ProjectBrowserHelper::ExposeProjectEventsWithoutExtensions(
gd::Project& project, gd::ArbitraryEventsWorkerWithContext& worker) {
// Add layouts events
for (std::size_t s = 0; s < project.GetLayoutsCount(); s++) {
auto &layout = project.GetLayout(s);
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
worker.Launch(layout.GetEvents(), projectScopedContainers);
}
// Add external events events
for (std::size_t s = 0; s < project.GetExternalEventsCount(); s++) {
const auto &externalEvents = project.GetExternalEvents(s);
const gd::String &associatedLayout = externalEvents.GetAssociatedLayout();
if (project.HasLayoutNamed(associatedLayout)) {
auto &layout = project.GetLayout(associatedLayout);
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
worker.Launch(project.GetExternalEvents(s).GetEvents(), projectScopedContainers);
}
}
}
void ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
gd::Project &project, gd::Layout &layout,
gd::ArbitraryEventsWorker &worker) {
@@ -106,48 +144,17 @@ void ProjectBrowserHelper::ExposeLayoutEventsAndDependencies(
}
for (const gd::String& sceneName : dependenciesAnalyzer.GetScenesDependencies()) {
gd::Layout& dependencyLayout = project.GetLayout(sceneName);
worker.Launch(dependencyLayout.GetEvents());
}
}
void ProjectBrowserHelper::ExposeProjectEvents(
gd::Project &project, gd::ArbitraryEventsWorkerWithContext &worker) {
// See also gd::Project::ExposeResources for a method that traverse the whole
// project (this time for resources) and ExposeProjectEffects (this time for
// effects).
// Add layouts events
for (std::size_t s = 0; s < project.GetLayoutsCount(); s++) {
auto &layout = project.GetLayout(s);
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
worker.Launch(layout.GetEvents(), projectScopedContainers);
}
// Add external events events
for (std::size_t s = 0; s < project.GetExternalEventsCount(); s++) {
const auto &externalEvents = project.GetExternalEvents(s);
const gd::String &associatedLayout = externalEvents.GetAssociatedLayout();
if (project.HasLayoutNamed(associatedLayout)) {
auto &layout = project.GetLayout(associatedLayout);
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
worker.Launch(project.GetExternalEvents(s).GetEvents(), projectScopedContainers);
}
}
// Add events based extensions
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
e++) {
auto &eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(project, eventsFunctionsExtension, worker);
}
}
void ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::ArbitraryEventsWorker &worker) {
// Add (free) events functions
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
for (auto &&eventsFunction :
eventsFunctionsExtension.GetEventsFunctions().GetInternalVector()) {
worker.Launch(eventsFunction->GetEvents());
}
@@ -169,12 +176,18 @@ void ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::ArbitraryEventsWorkerWithContext &worker) {
// Add (free) events functions
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
gd::ObjectsContainer parameterObjectsContainer;
for (auto &&eventsFunction :
eventsFunctionsExtension.GetEventsFunctions().GetInternalVector()) {
gd::ObjectsContainer parameterObjectsContainer(
gd::ObjectsContainer::SourceType::Function);
gd::VariablesContainer parameterVariablesContainer(
gd::VariablesContainer::SourceType::Parameters);
gd::VariablesContainer propertyVariablesContainer(
gd::VariablesContainer::SourceType::Properties);
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForFreeEventsFunction(
project, eventsFunctionsExtension, *eventsFunction,
parameterObjectsContainer);
parameterObjectsContainer, parameterVariablesContainer);
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
}
@@ -206,14 +219,32 @@ void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedBehavior &eventsBasedBehavior,
gd::ArbitraryEventsWorkerWithContext &worker) {
gd::VariablesContainer propertyVariablesContainer(
gd::VariablesContainer::SourceType::Properties);
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
project, eventsFunctionsExtension,
eventsBasedBehavior,
propertyVariablesContainer,
worker);
}
void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedBehavior &eventsBasedBehavior,
gd::VariablesContainer &propertyVariablesContainer,
gd::ArbitraryEventsWorkerWithContext &worker) {
auto &behaviorEventsFunctions = eventsBasedBehavior.GetEventsFunctions();
for (auto &&eventsFunction : behaviorEventsFunctions.GetInternalVector()) {
gd::ObjectsContainer parameterObjectsContainers;
gd::ObjectsContainer parameterObjectsContainers(
gd::ObjectsContainer::SourceType::Function);
gd::VariablesContainer parameterVariablesContainer(
gd::VariablesContainer::SourceType::Parameters);
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForBehaviorEventsFunction(
project, eventsFunctionsExtension, eventsBasedBehavior,
*eventsFunction, parameterObjectsContainers);
*eventsFunction, parameterObjectsContainers,
parameterVariablesContainer, propertyVariablesContainer);
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
}
@@ -233,14 +264,31 @@ void ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedObject &eventsBasedObject,
gd::ArbitraryEventsWorkerWithContext &worker) {
gd::VariablesContainer propertyVariablesContainer(
gd::VariablesContainer::SourceType::Properties);
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
project, eventsFunctionsExtension, eventsBasedObject,
propertyVariablesContainer, worker);
}
void ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedObject &eventsBasedObject,
gd::VariablesContainer &propertyVariablesContainer,
gd::ArbitraryEventsWorkerWithContext &worker) {
auto &objectEventsFunctions = eventsBasedObject.GetEventsFunctions();
for (auto &&eventsFunction : objectEventsFunctions.GetInternalVector()) {
gd::ObjectsContainer parameterObjectsContainers;
gd::ObjectsContainer parameterObjectsContainers(
gd::ObjectsContainer::SourceType::Function);
gd::VariablesContainer parameterVariablesContainer(
gd::VariablesContainer::SourceType::Parameters);
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForObjectEventsFunction(
project, eventsFunctionsExtension, eventsBasedObject,
*eventsFunction, parameterObjectsContainers);
*eventsFunction, parameterObjectsContainers,
parameterVariablesContainer, propertyVariablesContainer);
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
}
@@ -266,6 +314,12 @@ void ProjectBrowserHelper::ExposeProjectObjects(
eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) {
auto eventsBasedObject = eventsBasedObjectUniquePtr.get();
worker.Launch(eventsBasedObject->GetObjects());
for (auto &&variantUniquePtr :
eventsBasedObject->GetVariants().GetInternalVector()) {
auto variant = variantUniquePtr.get();
worker.Launch(variant->GetObjects());
}
}
}
};
@@ -284,7 +338,7 @@ void ProjectBrowserHelper::ExposeProjectFunctions(
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
e++) {
auto &eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
worker.Launch(eventsFunctionsExtension);
worker.Launch(eventsFunctionsExtension.GetEventsFunctions());
for (auto &&eventsBasedBehavior :
eventsFunctionsExtension.GetEventsBasedBehaviors()

View File

@@ -19,6 +19,7 @@ class ArbitraryEventsFunctionsWorker;
class ArbitraryObjectsWorker;
class ArbitraryEventBasedBehaviorsWorker;
class ArbitraryBehaviorSharedDataWorker;
class VariablesContainer;
} // namespace gd
namespace gd {
@@ -56,6 +57,15 @@ public:
ExposeProjectEventsWithoutExtensions(gd::Project &project,
gd::ArbitraryEventsWorker &worker);
/**
* \brief Call the specified worker on all events of the project (layout and
* external events) but not events from extensions.
*
* Only use this for stats.
*/
static void ExposeProjectEventsWithoutExtensions(
gd::Project &project, gd::ArbitraryEventsWorkerWithContext &worker);
/**
* \brief Call the specified worker on all events of a layout and
* its external events.
@@ -127,6 +137,20 @@ public:
const gd::EventsBasedBehavior &eventsBasedBehavior,
gd::ArbitraryEventsWorkerWithContext &worker);
/**
* \brief Call the specified worker on all events of the event-based
* behavior.
*
* This should be the preferred way to traverse all the events of an
* event-based behavior.
*/
static void ExposeEventsBasedBehaviorEvents(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedBehavior &eventsBasedBehavior,
gd::VariablesContainer &propertyVariablesContainer,
gd::ArbitraryEventsWorkerWithContext &worker);
/**
* \brief Call the specified worker on all events of the event-based
* object.
@@ -152,6 +176,20 @@ public:
const gd::EventsBasedObject &eventsBasedObject,
gd::ArbitraryEventsWorkerWithContext &worker);
/**
* \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.
*/
static void ExposeEventsBasedObjectEvents(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedObject &eventsBasedObject,
gd::VariablesContainer &propertyVariablesContainer,
gd::ArbitraryEventsWorkerWithContext &worker);
/**
* \brief Call the specified worker on all ObjectContainers of the project
* (global, layouts...)

View File

@@ -63,7 +63,7 @@ void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project &project) {
eventsBasedObject.GetPropertyDescriptors().GetInternalVector().clear();
}
extension.GetEventsBasedBehaviors().Clear();
extension.ClearEventsFunctions();
extension.GetEventsFunctions().ClearEventsFunctions();
}
}

View File

@@ -42,6 +42,9 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
const gd::NamedPropertyDescriptor &property, const gd::String &objectType,
bool isBehavior, bool isSharedProperties) {
auto &propertyName = property.GetName();
const auto &primitiveType = gd::ValueTypeMetadata::GetPrimitiveValueType(
gd::ValueTypeMetadata::ConvertPropertyTypeToValueType(
property.GetType()));
auto &functionsContainer = eventsBasedEntity.GetEventsFunctions();
gd::String capitalizedName = CapitalizeFirstLetter(property.GetName());
gd::String setterName = "Set" + capitalizedName;
@@ -59,9 +62,9 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
property.GetLabel().empty() ? property.GetName() : property.GetLabel();
gd::String descriptionSubject =
(property.GetType() == "Boolean" ? "if " : "the ") +
(primitiveType == "boolean" ? "if " : "the ") +
UnCapitalizeFirstLetter(propertyLabel) +
(isSharedProperties || property.GetType() == "Boolean"
(isSharedProperties || primitiveType == "boolean"
? "."
: " of the object.") +
(property.GetDescription().empty() ? ""
@@ -71,19 +74,7 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
"objects using the behavior."
: "");
gd::String propertyGetterName =
(isSharedProperties ? "SharedProperty" : "Property") + property.GetName();
gd::String getterType =
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
extension.GetName(), eventsBasedEntity.GetName(), propertyGetterName);
gd::String setterType =
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
extension.GetName(), eventsBasedEntity.GetName(),
"Set" + propertyGetterName);
gd::String getterName = capitalizedName;
gd::String numberOrString =
property.GetType() == "Number" ? "Number" : "String";
if (!functionsContainer.HasEventsFunctionNamed(getterName)) {
auto &getter = functionsContainer.InsertNewEventsFunction(
@@ -99,7 +90,7 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
.SetName(legacyExpressionType)
.SetExtraInfo(GetStringifiedExtraInfo(property));
getter.SetFullName(propertyLabel).SetGroup(functionGroupName);
if (property.GetType() == "Boolean") {
if (primitiveType == "boolean") {
getter.SetFunctionType(gd::EventsFunction::Condition)
.SetDescription("Check " + descriptionSubject)
.SetSentence("_PARAM0_ " + UnCapitalizeFirstLetter(propertyLabel));
@@ -112,13 +103,12 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
auto &event =
dynamic_cast<gd::StandardEvent &>(getter.GetEvents().InsertNewEvent(
project, "BuiltinCommonInstructions::Standard", 0));
if (property.GetType() == "Boolean") {
if (primitiveType == "boolean") {
gd::Instruction condition;
condition.SetType(getterType);
condition.AddParameter("Object");
if (isBehavior) {
condition.AddParameter("Behavior");
}
condition.SetType("BooleanVariable");
condition.AddParameter(propertyName);
condition.AddParameter("True");
condition.AddParameter("");
event.GetConditions().Insert(condition, 0);
gd::Instruction action;
@@ -127,6 +117,8 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
event.GetActions().Insert(action, 0);
} else {
gd::Instruction action;
gd::String numberOrString =
primitiveType == "number" ? "Number" : "String";
action.SetType("SetReturn" + numberOrString);
action.AddParameter(property.GetName());
event.GetActions().Insert(action, 0);
@@ -136,7 +128,7 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
if (!functionsContainer.HasEventsFunctionNamed(setterName)) {
auto &setter = functionsContainer.InsertNewEventsFunction(
setterName, functionsContainer.GetEventsFunctionsCount());
if (property.GetType() == "Boolean") {
if (primitiveType == "boolean") {
setter.SetFunctionType(gd::EventsFunction::Action)
.SetFullName(propertyLabel)
.SetGroup(functionGroupName)
@@ -177,26 +169,24 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
setter.SetGetterName(getterName);
}
if (property.GetType() == "Boolean") {
if (primitiveType == "boolean") {
{
auto &event =
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().InsertNewEvent(
project, "BuiltinCommonInstructions::Standard", 0));
gd::Instruction condition;
condition.SetType("GetArgumentAsBoolean");
condition.AddParameter("\"Value\"");
condition.SetType("BooleanVariable");
condition.AddParameter("Value");
condition.AddParameter("True");
condition.AddParameter("");
event.GetConditions().Insert(condition, 0);
gd::Instruction action;
action.SetType(setterType);
action.AddParameter("Object");
if (isBehavior) {
action.AddParameter("Behavior");
action.AddParameter("yes");
} else {
action.AddParameter("yes");
}
action.SetType("SetBooleanVariable");
action.AddParameter(propertyName);
action.AddParameter("True");
action.AddParameter("");
event.GetActions().Insert(action, 0);
}
{
@@ -205,20 +195,17 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
project, "BuiltinCommonInstructions::Standard", 0));
gd::Instruction condition;
condition.SetType("GetArgumentAsBoolean");
condition.AddParameter("\"Value\"");
condition.SetInverted(true);
condition.SetType("BooleanVariable");
condition.AddParameter("Value");
condition.AddParameter("False");
condition.AddParameter("");
event.GetConditions().Insert(condition, 0);
gd::Instruction action;
action.SetType(setterType);
action.AddParameter("Object");
if (isBehavior) {
action.AddParameter("Behavior");
action.AddParameter("no");
} else {
action.AddParameter("no");
}
action.SetType("SetBooleanVariable");
action.AddParameter(propertyName);
action.AddParameter("False");
action.AddParameter("");
event.GetActions().Insert(action, 0);
}
} else {
@@ -227,16 +214,11 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
project, "BuiltinCommonInstructions::Standard", 0));
gd::Instruction action;
action.SetType(setterType);
action.AddParameter("Object");
if (isBehavior) {
action.AddParameter("Behavior");
action.AddParameter("=");
action.AddParameter("Value");
} else {
action.AddParameter("=");
action.AddParameter("Value");
}
action.SetType(primitiveType == "number" ? "SetNumberVariable"
: "SetStringVariable");
action.AddParameter(propertyName);
action.AddParameter("=");
action.AddParameter("Value");
event.GetActions().Insert(action, 0);
}
}
@@ -245,9 +227,11 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
bool PropertyFunctionGenerator::CanGenerateGetterAndSetter(
const gd::AbstractEventsBasedEntity &eventsBasedEntity,
const gd::NamedPropertyDescriptor &property) {
auto &type = property.GetType();
if (type != "Boolean" && type != "Number" && type != "String" &&
type != "Choice" && type != "Color") {
const auto &primitiveType = gd::ValueTypeMetadata::GetPrimitiveValueType(
gd::ValueTypeMetadata::ConvertPropertyTypeToValueType(
property.GetType()));
if (primitiveType != "boolean" && primitiveType != "number" &&
primitiveType != "string") {
return false;
}

View File

@@ -3,8 +3,7 @@
* Copyright 2008-2022 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_PROPERTYFUNCTIONGENERATOR_H
#define GDCORE_PROPERTYFUNCTIONGENERATOR_H
#pragma once
namespace gd {
class String;
@@ -73,5 +72,3 @@ class GD_CORE_API PropertyFunctionGenerator {
};
} // namespace gd
#endif // GDCORE_PROPERTYFUNCTIONGENERATOR_H

View File

@@ -5,21 +5,22 @@
*/
#include "ResourceExposer.h"
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/IDE/ProjectBrowserHelper.h"
#include "GDCore/Project/Effect.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/Effect.h"
#include "GDCore/String.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
namespace gd {
void ResourceExposer::ExposeWholeProjectResources(gd::Project& project, gd::ArbitraryResourceWorker& worker) {
void ResourceExposer::ExposeWholeProjectResources(
gd::Project &project, gd::ArbitraryResourceWorker &worker) {
// See also gd::ProjectBrowserHelper::ExposeProjectEvents for a method that
// traverse the whole project (this time for events) and ExposeProjectEffects
// (this time for effects).
@@ -31,13 +32,11 @@ void ResourceExposer::ExposeWholeProjectResources(gd::Project& project, gd::Arbi
// Expose event resources
auto eventWorker = gd::GetResourceWorkerOnEvents(project, worker);
gd::ProjectBrowserHelper::ExposeProjectEvents(
project, eventWorker);
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventWorker);
// Expose object configuration resources
auto objectWorker = gd::GetResourceWorkerOnObjects(project, worker);
gd::ProjectBrowserHelper::ExposeProjectObjects(
project, objectWorker);
gd::ProjectBrowserHelper::ExposeProjectObjects(project, objectWorker);
// Expose layer effect resources
for (std::size_t layoutIndex = 0; layoutIndex < project.GetLayoutsCount();
@@ -52,28 +51,36 @@ void ResourceExposer::ExposeWholeProjectResources(gd::Project& project, gd::Arbi
for (size_t effectIndex = 0; effectIndex < effects.GetEffectsCount();
effectIndex++) {
auto &effect = effects.GetEffect(effectIndex);
gd::ResourceExposer::ExposeEffectResources(project.GetCurrentPlatform(),
effect, worker);
gd::ResourceExposer::ExposeEffectResources(
project.GetCurrentPlatform(), effect, worker);
}
}
}
// Expose loading screen background image if present
auto& loadingScreen = project.GetLoadingScreen();
auto &loadingScreen = project.GetLoadingScreen();
if (loadingScreen.GetBackgroundImageResourceName() != "")
worker.ExposeImage(loadingScreen.GetBackgroundImageResourceName());
// Expose extension source files
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
e++) {
auto &eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
ExposeExtensionResources(eventsFunctionsExtension, worker);
}
}
void ResourceExposer::ExposeProjectResources(gd::Project& project, gd::ArbitraryResourceWorker& worker) {
void ResourceExposer::ExposeProjectResources(
gd::Project &project, gd::ArbitraryResourceWorker &worker) {
// Expose global objects configuration resources
auto objectWorker = gd::GetResourceWorkerOnObjects(project, worker);
objectWorker.Launch(project.GetObjects());
}
void ResourceExposer::ExposeLayoutResources(
gd::Project &project, gd::Layout &layout,
gd::Project &project,
gd::Layout &layout,
gd::ArbitraryResourceWorker &worker) {
// Expose object configuration resources
auto objectWorker = gd::GetResourceWorkerOnObjects(project, worker);
gd::ProjectBrowserHelper::ExposeLayoutObjects(layout, objectWorker);
@@ -87,15 +94,15 @@ void ResourceExposer::ExposeLayoutResources(
for (size_t effectIndex = 0; effectIndex < effects.GetEffectsCount();
effectIndex++) {
auto &effect = effects.GetEffect(effectIndex);
gd::ResourceExposer::ExposeEffectResources(project.GetCurrentPlatform(),
effect, worker);
gd::ResourceExposer::ExposeEffectResources(
project.GetCurrentPlatform(), effect, worker);
}
}
// Expose event resources
auto eventWorker = gd::GetResourceWorkerOnEvents(project, worker);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndDependencies(project, layout,
eventWorker);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndDependencies(
project, layout, eventWorker);
// Exposed extension event resources
// Note that using resources in extensions is very unlikely and probably not
@@ -103,12 +110,14 @@ void ResourceExposer::ExposeLayoutResources(
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
e++) {
auto &eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
gd::ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(project, eventsFunctionsExtension, eventWorker);
gd::ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
project, eventsFunctionsExtension, eventWorker);
}
}
void ResourceExposer::ExposeEffectResources(
gd::Platform &platform, gd::Effect &effect,
gd::Platform &platform,
gd::Effect &effect,
gd::ArbitraryResourceWorker &worker) {
auto &effectMetadata =
MetadataProvider::GetEffectMetadata(platform, effect.GetEffectType());
@@ -127,11 +136,20 @@ void ResourceExposer::ExposeEffectResources(
worker.ExposeResourceWithType(resourceType,
potentiallyUpdatedResourceName);
if (potentiallyUpdatedResourceName != resourceName) {
effect.SetStringParameter(propertyName, potentiallyUpdatedResourceName);
effect.SetStringParameter(propertyName,
potentiallyUpdatedResourceName);
}
}
}
}
}
} // namespace gd
void ResourceExposer::ExposeExtensionResources(
gd::EventsFunctionsExtension &extension,
gd::ArbitraryResourceWorker &worker) {
for (auto &sourceFile : extension.GetAllSourceFiles()) {
worker.ExposeJavaScript(sourceFile.GetResourceName());
}
}
} // namespace gd

View File

@@ -9,9 +9,10 @@ namespace gd {
class Platform;
class Project;
class ArbitraryResourceWorker;
class EventsFunctionsExtension;
class Effect;
class Layout;
} // namespace gd
} // namespace gd
namespace gd {
@@ -19,7 +20,7 @@ namespace gd {
* \brief
*/
class GD_CORE_API ResourceExposer {
public:
public:
/**
* \brief Called ( e.g. during compilation ) so as to inventory internal
* resources, sometimes update their filename or any other work or resources.
@@ -34,7 +35,7 @@ public:
/**
* @brief Expose only the resources used globally on a project.
*
*
* It doesn't include resources used in layouts.
*/
static void ExposeProjectResources(gd::Project &project,
@@ -42,17 +43,25 @@ public:
/**
* @brief Expose the resources used in a given layout.
*
*
* It doesn't include resources used globally.
*/
static void ExposeLayoutResources(gd::Project &project, gd::Layout &layout,
gd::ArbitraryResourceWorker &worker);
static void ExposeLayoutResources(gd::Project &project,
gd::Layout &layout,
gd::ArbitraryResourceWorker &worker);
/**
* @brief Expose the resources used in a given effect.
*/
static void ExposeEffectResources(gd::Platform &platform, gd::Effect &effect,
static void ExposeEffectResources(gd::Platform &platform,
gd::Effect &effect,
gd::ArbitraryResourceWorker &worker);
/**
* @brief Expose the resources used in an extension.
*/
static void ExposeExtensionResources(gd::EventsFunctionsExtension &extension,
gd::ArbitraryResourceWorker &worker);
};
} // namespace gd
} // namespace gd

View File

@@ -11,7 +11,7 @@
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/DependenciesAnalyzer.h"
#include "GDCore/IDE/GroupVariableHelper.h"
#include "GDCore/IDE/ObjectVariableHelper.h"
#include "GDCore/IDE/EventBasedBehaviorBrowser.h"
#include "GDCore/IDE/EventBasedObjectBrowser.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
@@ -19,6 +19,7 @@
#include "GDCore/IDE/Events/BehaviorTypeRenamer.h"
#include "GDCore/IDE/Events/CustomObjectTypeRenamer.h"
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
#include "GDCore/IDE/Events/EventsParameterReplacer.h"
#include "GDCore/IDE/Events/EventsPropertyReplacer.h"
#include "GDCore/IDE/Events/EventsRefactorer.h"
#include "GDCore/IDE/Events/EventsVariableInstructionTypeSwitcher.h"
@@ -28,6 +29,7 @@
#include "GDCore/IDE/Events/InstructionsParameterMover.h"
#include "GDCore/IDE/Events/InstructionsTypeRenamer.h"
#include "GDCore/IDE/Events/LinkEventTargetRenamer.h"
#include "GDCore/IDE/Events/LeaderboardIdRenamer.h"
#include "GDCore/IDE/Events/ProjectElementRenamer.h"
#include "GDCore/IDE/Project/BehaviorObjectTypeRenamer.h"
#include "GDCore/IDE/Project/BehaviorsSharedDataBehaviorTypeRenamer.h"
@@ -312,9 +314,16 @@ void WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
variablesContainer.SerializeTo(editedSerializedVariables);
variablesContainer.UnserializeFrom(originalSerializedVariables);
// Rename and remove variables
// Rename variables
// Pass an empty set to avoid deletion of actions/conditions or events using
// them.
// While we support refactoring that would remove all references (actions,
// conditions...) it's both a bit dangerous for the user and we would need to
// show the user what will be removed before doing so. For now, just clear the
// removed variables so they don't trigger any refactoring.
std::unordered_set<gd::String> removedVariableNames;
gd::EventsVariableReplacer eventsVariableReplacer(
project.GetCurrentPlatform(), changeset, changeset.removedVariableNames,
project.GetCurrentPlatform(), changeset, removedVariableNames,
variablesContainer);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsVariableReplacer);
@@ -331,9 +340,25 @@ void WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project, eventsVariableInstructionTypeSwitcher);
}
// TODO Apply the refactor to external layouts.
void WholeProjectRefactorer::ApplyRefactoringForObjectVariablesContainer(
gd::Project &project, gd::VariablesContainer &objectVariablesContainer,
gd::InitialInstancesContainer &initialInstancesContainer,
const gd::String &objectName, const gd::VariablesChangeset &changeset,
const gd::SerializerElement &originalSerializedVariables) {
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project, objectVariablesContainer, changeset,
originalSerializedVariables);
gd::ObjectVariableHelper::ApplyChangesToObjectInstances(
objectVariablesContainer, initialInstancesContainer, objectName,
changeset);
}
void WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
gd::Project &project, gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer,
gd::InitialInstancesContainer &initialInstancesContainer,
const gd::VariablesContainer &groupVariablesContainer,
const gd::ObjectGroup &objectGroup,
const gd::VariablesChangeset &changeset,
@@ -353,11 +378,15 @@ void WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
}
auto &object = hasObject ? objectsContainer.GetObject(objectName)
: globalObjectsContainer.GetObject(objectName);
auto &variablesContainer = object.GetVariables();
auto &objectVariablesContainer = object.GetVariables();
gd::ObjectVariableHelper::ApplyChangesToObjectInstances(
objectVariablesContainer, initialInstancesContainer, objectName,
changeset);
gd::EventsVariableReplacer eventsVariableReplacer(
project.GetCurrentPlatform(), changeset,
removedVariableNames, variablesContainer);
removedVariableNames, objectVariablesContainer);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsVariableReplacer);
}
@@ -370,12 +399,12 @@ void WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
eventsVariableReplacer);
// Apply changes to objects.
gd::GroupVariableHelper::FillMissingGroupVariablesToObjects(
gd::ObjectVariableHelper::FillMissingGroupVariablesToObjects(
globalObjectsContainer,
objectsContainer,
objectGroup,
originalSerializedVariables);
gd::GroupVariableHelper::ApplyChangesToObjects(
gd::ObjectVariableHelper::ApplyChangesToObjects(
globalObjectsContainer, objectsContainer, groupVariablesContainer,
objectGroup, changeset);
@@ -598,7 +627,8 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
// instructions after they are renamed.
// Free expressions
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
for (auto &&eventsFunction :
eventsFunctionsExtension.GetEventsFunctions().GetInternalVector()) {
if (eventsFunction->IsExpression()) {
renameEventsFunction(*eventsFunction);
}
@@ -615,7 +645,8 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
}
// Free instructions
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
for (auto &&eventsFunction :
eventsFunctionsExtension.GetEventsFunctions().GetInternalVector()) {
if (eventsFunction->IsAction() || eventsFunction->IsCondition()) {
renameEventsFunction(*eventsFunction);
}
@@ -695,11 +726,12 @@ void WholeProjectRefactorer::RenameEventsFunction(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::String &oldFunctionName, const gd::String &newFunctionName) {
if (!eventsFunctionsExtension.HasEventsFunctionNamed(oldFunctionName))
const auto &eventsFunctions = eventsFunctionsExtension.GetEventsFunctions();
if (!eventsFunctions.HasEventsFunctionNamed(oldFunctionName))
return;
const gd::EventsFunction &eventsFunction =
eventsFunctionsExtension.GetEventsFunction(oldFunctionName);
eventsFunctions.GetEventsFunction(oldFunctionName);
const WholeProjectBrowser wholeProjectExposer;
DoRenameEventsFunction(
@@ -712,7 +744,7 @@ void WholeProjectRefactorer::RenameEventsFunction(
if (eventsFunction.GetFunctionType() ==
gd::EventsFunction::ExpressionAndCondition) {
for (auto &&otherFunction : eventsFunctionsExtension.GetInternalVector()) {
for (auto &&otherFunction : eventsFunctions.GetInternalVector()) {
if (otherFunction->GetFunctionType() ==
gd::EventsFunction::ActionWithOperator &&
otherFunction->GetGetterName() == oldFunctionName) {
@@ -815,16 +847,79 @@ void WholeProjectRefactorer::RenameObjectEventsFunction(
}
}
void WholeProjectRefactorer::RenameParameter(
gd::Project &project, gd::ProjectScopedContainers &projectScopedContainers,
gd::EventsFunction &eventsFunction,
const gd::ObjectsContainer &parameterObjectsContainer,
const gd::String &oldParameterName, const gd::String &newParameterName) {
auto &parameters = eventsFunction.GetParameters();
if (!parameters.HasParameterNamed(oldParameterName))
return;
auto &parameter = parameters.GetParameter(oldParameterName);
if (parameter.GetValueTypeMetadata().IsObject()) {
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
project, projectScopedContainers, eventsFunction,
parameterObjectsContainer, oldParameterName, newParameterName, false);
} else if (parameter.GetValueTypeMetadata().IsBehavior()) {
size_t behaviorParameterIndex = parameters.GetParameterPosition(parameter);
size_t objectParameterIndex =
gd::ParameterMetadataTools::GetObjectParameterIndexFor(
parameters, behaviorParameterIndex);
if (objectParameterIndex == gd::String::npos) {
return;
}
const gd::String &objectName =
parameters.GetParameter(objectParameterIndex).GetName();
gd::EventsBehaviorRenamer behaviorRenamer(project.GetCurrentPlatform(),
objectName, oldParameterName,
newParameterName);
behaviorRenamer.Launch(eventsFunction.GetEvents(), projectScopedContainers);
} else {
// Rename parameter names directly used as an identifier.
std::unordered_map<gd::String, gd::String> oldToNewParameterNames = {
{oldParameterName, newParameterName}};
gd::EventsParameterReplacer eventsParameterReplacer(
project.GetCurrentPlatform(), oldToNewParameterNames);
eventsParameterReplacer.Launch(eventsFunction.GetEvents(),
projectScopedContainers);
// Rename parameter names in legacy expressions and instructions
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "functionParameterName", oldParameterName,
newParameterName);
projectElementRenamer.Launch(eventsFunction.GetEvents(),
projectScopedContainers);
}
}
void WholeProjectRefactorer::ChangeParameterType(
gd::Project &project, gd::ProjectScopedContainers &projectScopedContainers,
gd::EventsFunction &eventsFunction,
const gd::ObjectsContainer &parameterObjectsContainer,
const gd::String &parameterName) {
std::unordered_set<gd::String> typeChangedPropertyNames;
typeChangedPropertyNames.insert(parameterName);
gd::VariablesContainer propertyVariablesContainer(
gd::VariablesContainer::SourceType::Properties);
gd::EventsVariableInstructionTypeSwitcher
eventsVariableInstructionTypeSwitcher(project.GetCurrentPlatform(),
typeChangedPropertyNames,
propertyVariablesContainer);
eventsVariableInstructionTypeSwitcher.Launch(eventsFunction.GetEvents(),
projectScopedContainers);
}
void WholeProjectRefactorer::MoveEventsFunctionParameter(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::String &functionName, std::size_t oldIndex,
std::size_t newIndex) {
if (!eventsFunctionsExtension.HasEventsFunctionNamed(functionName))
const auto &eventsFunctions = eventsFunctionsExtension.GetEventsFunctions();
if (!eventsFunctions.HasEventsFunctionNamed(functionName))
return;
const gd::EventsFunction &eventsFunction =
eventsFunctionsExtension.GetEventsFunction(functionName);
eventsFunctions.GetEventsFunction(functionName);
const gd::String &eventsFunctionType =
gd::PlatformExtension::GetEventsFunctionFullType(
@@ -949,6 +1044,8 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
// Order is important: we first rename the expressions then the
// instructions, to avoid being unable to fetch the metadata (the types of
// parameters) of instructions after they are renamed.
// Rename legacy expressions like: Object.Behavior::PropertyMyPropertyName()
gd::ExpressionsRenamer expressionRenamer =
gd::ExpressionsRenamer(project.GetCurrentPlatform());
expressionRenamer.SetReplacedBehaviorExpression(
@@ -958,14 +1055,16 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
// Rename property names directly used as an identifier.
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
{oldPropertyName, newPropertyName}};
std::unordered_set<gd::String> removedPropertyNames;
gd::EventsPropertyReplacer eventsPropertyReplacer(
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsPropertyReplacer);
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
project, eventsFunctionsExtension, eventsBasedBehavior,
eventsPropertyReplacer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -1020,6 +1119,8 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
// Order is important: we first rename the expressions then the
// instructions, to avoid being unable to fetch the metadata (the types of
// parameters) of instructions after they are renamed.
// Rename legacy expressions like: Object.Behavior::SharedPropertyMyPropertyName()
gd::ExpressionsRenamer expressionRenamer =
gd::ExpressionsRenamer(project.GetCurrentPlatform());
expressionRenamer.SetReplacedBehaviorExpression(
@@ -1029,14 +1130,16 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
EventsBasedBehavior::GetSharedPropertyExpressionName(newPropertyName));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
// Rename property names directly used as an identifier.
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
{oldPropertyName, newPropertyName}};
std::unordered_set<gd::String> removedPropertyNames;
gd::EventsPropertyReplacer eventsPropertyReplacer(
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsPropertyReplacer);
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
project, eventsFunctionsExtension, eventsBasedBehavior,
eventsPropertyReplacer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -1077,6 +1180,8 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
// Order is important: we first rename the expressions then the
// instructions, to avoid being unable to fetch the metadata (the types of
// parameters) of instructions after they are renamed.
// Rename legacy expressions like: Object.PropertyMyPropertyName()
gd::ExpressionsRenamer expressionRenamer =
gd::ExpressionsRenamer(project.GetCurrentPlatform());
expressionRenamer.SetReplacedObjectExpression(
@@ -1086,14 +1191,16 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
EventsBasedObject::GetPropertyExpressionName(newPropertyName));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
// Rename property names directly used as an identifier.
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
{oldPropertyName, newPropertyName}};
std::unordered_set<gd::String> removedPropertyNames;
gd::EventsPropertyReplacer eventsPropertyReplacer(
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsPropertyReplacer);
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
project, eventsFunctionsExtension, eventsBasedObject,
eventsPropertyReplacer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -1116,6 +1223,42 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
gd::ProjectBrowserHelper::ExposeProjectEvents(project, conditionRenamer);
}
void WholeProjectRefactorer::ChangeEventsBasedBehaviorPropertyType(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::String &propertyName) {
std::unordered_set<gd::String> typeChangedPropertyNames;
typeChangedPropertyNames.insert(propertyName);
gd::VariablesContainer propertyVariablesContainer(
gd::VariablesContainer::SourceType::Properties);
gd::EventsVariableInstructionTypeSwitcher
eventsVariableInstructionTypeSwitcher(project.GetCurrentPlatform(),
typeChangedPropertyNames,
propertyVariablesContainer);
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
project, eventsFunctionsExtension, eventsBasedBehavior,
propertyVariablesContainer, eventsVariableInstructionTypeSwitcher);
}
void WholeProjectRefactorer::ChangeEventsBasedObjectPropertyType(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedObject &eventsBasedObject,
const gd::String &propertyName) {
std::unordered_set<gd::String> typeChangedPropertyNames;
typeChangedPropertyNames.insert(propertyName);
gd::VariablesContainer propertyVariablesContainer(
gd::VariablesContainer::SourceType::Properties);
gd::EventsVariableInstructionTypeSwitcher
eventsVariableInstructionTypeSwitcher(project.GetCurrentPlatform(),
typeChangedPropertyNames,
propertyVariablesContainer);
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
project, eventsFunctionsExtension, eventsBasedObject,
propertyVariablesContainer, eventsVariableInstructionTypeSwitcher);
}
void WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
gd::Project &project, gd::Object &object, const gd::String &behaviorType,
const gd::String &behaviorName) {
@@ -1692,6 +1835,15 @@ void WholeProjectRefactorer::BehaviorsAddedToObjectInScene(
void WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
gd::Project &project, gd::Layout &layout, const gd::String &oldName,
const gd::String &newName, bool isObjectGroup) {
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
project, layout, layout.GetObjects(), oldName, newName, isObjectGroup);
}
void WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
gd::Project &project, gd::Layout &layout,
const gd::ObjectsContainer &targetedObjectsContainer,
const gd::String &oldName, const gd::String &newName, bool isObjectGroup) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
@@ -1701,7 +1853,7 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
// Rename object in the current layout
gd::EventsRefactorer::RenameObjectInEvents(
project.GetCurrentPlatform(), projectScopedContainers, layout.GetEvents(),
oldName, newName);
layout.GetObjects(), oldName, newName);
// Object groups can't have instances or be in other groups
if (!isObjectGroup) {
@@ -1718,7 +1870,7 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
auto &externalEvents = project.GetExternalEvents(externalEventsName);
gd::EventsRefactorer::RenameObjectInEvents(
project.GetCurrentPlatform(), projectScopedContainers,
externalEvents.GetEvents(), oldName, newName);
externalEvents.GetEvents(), layout.GetObjects(), oldName, newName);
}
// Rename object in external layouts
@@ -1964,8 +2116,8 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
eventsBasedObject.GetEventsFunctions().GetInternalVector()) {
auto *function = functionUniquePtr.get();
WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
project, projectScopedContainers, *function, oldName, newName,
isObjectGroup);
project, projectScopedContainers, *function,
eventsBasedObject.GetObjects(), oldName, newName, isObjectGroup);
}
// Object groups can't have instances or be in other groups
@@ -1977,16 +2129,37 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
groups[g].RenameObject(oldName, newName);
}
}
for (auto &variant : eventsBasedObject.GetVariants().GetInternalVector()) {
auto &variantObjects = variant->GetObjects();
auto &variantObjectGroups = variantObjects.GetObjectGroups();
if (isObjectGroup) {
if (variantObjectGroups.Has(oldName)) {
variantObjectGroups.Get(oldName).SetName(newName);
}
// Object groups can't have instances or be in other groups
}
else {
if (variantObjects.HasObjectNamed(oldName)) {
variantObjects.GetObject(oldName).SetName(newName);
}
variant->GetInitialInstances().RenameInstancesOfObject(oldName, newName);
for (std::size_t g = 0; g < variantObjectGroups.size(); ++g) {
variantObjectGroups[g].RenameObject(oldName, newName);
}
}
}
}
void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
gd::Project &project,
const gd::ProjectScopedContainers &projectScopedContainers,
gd::EventsFunction &eventsFunction, const gd::String &oldName,
const gd::String &newName, bool isObjectGroup) {
gd::EventsFunction &eventsFunction,
const gd::ObjectsContainer &targetedObjectsContainer,
const gd::String &oldName, const gd::String &newName, bool isObjectGroup) {
gd::EventsRefactorer::RenameObjectInEvents(
project.GetCurrentPlatform(), projectScopedContainers,
eventsFunction.GetEvents(), oldName, newName);
eventsFunction.GetEvents(), targetedObjectsContainer, oldName, newName);
// Object groups can't be in other groups
if (!isObjectGroup) {
@@ -2012,7 +2185,7 @@ void WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
if (layout.GetObjects().HasObjectNamed(oldName))
continue;
ObjectOrGroupRenamedInScene(project, layout, oldName, newName,
ObjectOrGroupRenamedInScene(project, layout, project.GetObjects(), oldName, newName,
isObjectGroup);
}
}
@@ -2144,4 +2317,23 @@ std::vector<gd::String> WholeProjectRefactorer::GetAssociatedExternalEvents(
return results;
}
void WholeProjectRefactorer::RenameLeaderboards(
gd::Project &project,
const std::map<gd::String, gd::String> &leaderboardIdMap) {
gd::LeaderboardIdRenamer leaderboardIdRenamer(project);
leaderboardIdRenamer.SetLeaderboardIdsToReplace(leaderboardIdMap);
gd::ProjectBrowserHelper::ExposeProjectEvents(project, leaderboardIdRenamer);
gd::ProjectBrowserHelper::ExposeProjectObjects(project, leaderboardIdRenamer);
}
std::set<gd::String> WholeProjectRefactorer::FindAllLeaderboardIds(gd::Project &project) {
gd::LeaderboardIdRenamer leaderboardIdRenamer(project);
gd::ProjectBrowserHelper::ExposeProjectEvents(project, leaderboardIdRenamer);
gd::ProjectBrowserHelper::ExposeProjectObjects(project, leaderboardIdRenamer);
return leaderboardIdRenamer.GetAllLeaderboardIds();
}
} // namespace gd

View File

@@ -32,6 +32,7 @@ class UnfilledRequiredBehaviorPropertyProblem;
class ProjectBrowser;
class SerializerElement;
class ProjectScopedContainers;
class InitialInstancesContainer;
struct VariablesRenamingChangesetNode;
} // namespace gd
@@ -80,13 +81,23 @@ class GD_CORE_API WholeProjectRefactorer {
/**
* \brief Refactor the project according to the changes (renaming or deletion)
* made to variables.
* made to global or scene variables.
*/
static void ApplyRefactoringForVariablesContainer(
gd::Project &project, gd::VariablesContainer &variablesContainer,
const gd::VariablesChangeset &changeset,
const gd::SerializerElement &originalSerializedVariables);
/**
* \brief Refactor the project according to the changes (renaming or deletion)
* made to object variables.
*/
static void ApplyRefactoringForObjectVariablesContainer(
gd::Project &project, gd::VariablesContainer &objectVariablesContainer,
gd::InitialInstancesContainer &initialInstancesContainer,
const gd::String &objectName, const gd::VariablesChangeset &changeset,
const gd::SerializerElement &originalSerializedVariables);
/**
* \brief Refactor the project according to the changes (renaming or deletion)
* made to variables of a group.
@@ -94,6 +105,7 @@ class GD_CORE_API WholeProjectRefactorer {
static void ApplyRefactoringForGroupVariablesContainer(
gd::Project &project, gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer,
gd::InitialInstancesContainer &initialInstancesContainer,
const gd::VariablesContainer &groupVariablesContainer,
const gd::ObjectGroup &objectGroup,
const gd::VariablesChangeset &changeset,
@@ -176,6 +188,31 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& oldFunctionName,
const gd::String& newFunctionName);
/**
* \brief Refactor the function **before** a parameter is renamed.
*
* \warning Do the renaming of the specified parameter after calling this.
* This is because the function is expected to have its old name for the
* refactoring.
*/
static void
RenameParameter(gd::Project &project,
gd::ProjectScopedContainers &projectScopedContainers,
gd::EventsFunction &eventsFunction,
const gd::ObjectsContainer &parameterObjectsContainer,
const gd::String &oldParameterName,
const gd::String &newParameterName);
/**
* \brief Refactor the function **after** a parameter has changed of type.
*/
static void
ChangeParameterType(gd::Project &project,
gd::ProjectScopedContainers &projectScopedContainers,
gd::EventsFunction &eventsFunction,
const gd::ObjectsContainer &parameterObjectsContainer,
const gd::String &parameterName);
/**
* \brief Refactor the project **before** an events function parameter
* is moved.
@@ -268,6 +305,26 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& oldPropertyName,
const gd::String& newPropertyName);
/**
* \brief Refactor the project **after** a property of a behavior has
* changed of type.
*/
static void ChangeEventsBasedBehaviorPropertyType(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::String &propertyName);
/**
* \brief Refactor the project **after** a property of an object has
* changed of type.
*/
static void ChangeEventsBasedObjectPropertyType(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedObject &eventsBasedObject,
const gd::String &propertyName);
/**
* \brief Add a behavior to an object and add required behaviors if necessary
* to fill every behavior properties of the added behaviors.
@@ -529,6 +586,7 @@ class GD_CORE_API WholeProjectRefactorer {
gd::Project& project,
const gd::ProjectScopedContainers &projectScopedContainers,
gd::EventsFunction& eventsFunction,
const gd::ObjectsContainer &targetedObjectsContainer,
const gd::String& oldName,
const gd::String& newName,
bool isObjectGroup);
@@ -627,6 +685,18 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String &originLayerName,
const gd::String &targetLayerName);
/**
* \brief Replace the leaderboard ids in the whole project.
*/
static void
RenameLeaderboards(gd::Project &project,
const std::map<gd::String, gd::String> &leaderboardIdMap);
/**
* \brief Find all the leaderboard identifiers in the whole project.
*/
static std::set<gd::String> FindAllLeaderboardIds(gd::Project &project);
/**
* \brief Return the number of instances on the layer named \a layerName and
* all its associated layouts.
@@ -637,6 +707,12 @@ class GD_CORE_API WholeProjectRefactorer {
virtual ~WholeProjectRefactorer(){};
private:
static void ObjectOrGroupRenamedInScene(gd::Project &project,
gd::Layout &scene,
const gd::ObjectsContainer &targetedObjectsContainer,
const gd::String &oldName,
const gd::String &newName,
bool isObjectGroup);
static std::vector<gd::String> GetAssociatedExternalLayouts(
gd::Project& project, gd::Layout& layout);
static std::vector<gd::String>

View File

@@ -23,6 +23,9 @@ void AbstractEventsBasedEntity::SerializeTo(SerializerElement& element) const {
element.SetAttribute("description", description);
element.SetAttribute("name", name);
element.SetAttribute("fullName", fullName);
if (isPrivate) {
element.SetBoolAttribute("private", isPrivate);
}
gd::SerializerElement& eventsFunctionsElement =
element.AddChild("eventsFunctions");
@@ -36,6 +39,7 @@ void AbstractEventsBasedEntity::UnserializeFrom(
description = element.GetStringAttribute("description");
name = element.GetStringAttribute("name");
fullName = element.GetStringAttribute("fullName");
isPrivate = element.GetBoolAttribute("private");
const gd::SerializerElement& eventsFunctionsElement =
element.GetChild("eventsFunctions");

View File

@@ -3,8 +3,7 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_ABSTRACTEVENTSBASEDENTITY_H
#define GDCORE_ABSTRACTEVENTSBASEDENTITY_H
#pragma once
#include <vector>
#include "GDCore/Project/NamedPropertyDescriptor.h"
@@ -40,6 +39,21 @@ class GD_CORE_API AbstractEventsBasedEntity {
*/
AbstractEventsBasedEntity* Clone() const { return new AbstractEventsBasedEntity(*this); };
/**
* \brief Check if the behavior or object is private - it can't be used outside of its
* extension.
*/
bool IsPrivate() const { return isPrivate; }
/**
* \brief Set that the behavior or object is private - it can't be used outside of its
* extension.
*/
AbstractEventsBasedEntity& SetPrivate(bool isPrivate_) {
isPrivate = isPrivate_;
return *this;
}
/**
* \brief Get the description of the behavior or object, that is displayed in the
* editor.
@@ -151,8 +165,7 @@ class GD_CORE_API AbstractEventsBasedEntity {
gd::EventsFunctionsContainer eventsFunctionsContainer;
gd::PropertiesContainer propertyDescriptors;
gd::String extensionName;
bool isPrivate = false;
};
} // namespace gd
#endif // GDCORE_ABSTRACTEVENTSBASEDENTITY_H

View File

@@ -6,6 +6,7 @@
#include "GDCore/Project/BehaviorConfigurationContainer.h"
#include <iostream>
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
namespace gd {
@@ -22,4 +23,48 @@ std::map<gd::String, gd::PropertyDescriptor> BehaviorConfigurationContainer::Get
return nothing;
}
void BehaviorConfigurationContainer::ExposeResources(gd::ArbitraryResourceWorker& worker) {
std::map<gd::String, gd::PropertyDescriptor> properties = GetProperties();
for (auto& property : properties) {
const String& propertyName = property.first;
const gd::PropertyDescriptor& propertyDescriptor = property.second;
if (propertyDescriptor.GetType().LowerCase() == "resource") {
auto& extraInfo = propertyDescriptor.GetExtraInfo();
const gd::String& resourceType = extraInfo.empty() ? "" : extraInfo[0];
const gd::String& oldPropertyValue = propertyDescriptor.GetValue();
gd::String newPropertyValue = oldPropertyValue;
if (resourceType == "image") {
worker.ExposeImage(newPropertyValue);
} else if (resourceType == "audio") {
worker.ExposeAudio(newPropertyValue);
} else if (resourceType == "font") {
worker.ExposeFont(newPropertyValue);
} else if (resourceType == "video") {
worker.ExposeVideo(newPropertyValue);
} else if (resourceType == "json") {
worker.ExposeJson(newPropertyValue);
} else if (resourceType == "tilemap") {
worker.ExposeTilemap(newPropertyValue);
} else if (resourceType == "tileset") {
worker.ExposeTileset(newPropertyValue);
} else if (resourceType == "bitmapFont") {
worker.ExposeBitmapFont(newPropertyValue);
} else if (resourceType == "model3D") {
worker.ExposeModel3D(newPropertyValue);
} else if (resourceType == "atlas") {
worker.ExposeAtlas(newPropertyValue);
} else if (resourceType == "spine") {
worker.ExposeSpine(newPropertyValue);
}
if (newPropertyValue != oldPropertyValue) {
UpdateProperty(propertyName, newPropertyValue);
}
}
}
}
} // namespace gd

View File

@@ -3,8 +3,7 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_BEHAVIORCONFIGURATIONCONTAINER_H
#define GDCORE_BEHAVIORCONFIGURATIONCONTAINER_H
#pragma once
#include <map>
#include <memory>
@@ -19,6 +18,7 @@ class PropertyDescriptor;
class SerializerElement;
class Project;
class Layout;
class ArbitraryResourceWorker;
} // namespace gd
namespace gd {
@@ -158,6 +158,18 @@ class GD_CORE_API BehaviorConfigurationContainer {
return propertiesQuickCustomizationVisibilities;
}
/**
* \brief Called ( e.g. during compilation ) so as to inventory internal
* resources and sometimes update their filename. Implementation example:
* \code
* worker.ExposeImage(myImage);
* worker.ExposeFile(myResourceFile);
* \endcode
*
* \see ArbitraryResourceWorker
*/
void ExposeResources(gd::ArbitraryResourceWorker& worker);
protected:
/**
* \brief Called when the IDE wants to know about the custom properties of the
@@ -209,5 +221,3 @@ class GD_CORE_API BehaviorConfigurationContainer {
};
} // namespace gd
#endif // GDCORE_BEHAVIORCONFIGURATIONCONTAINER_H

View File

@@ -22,15 +22,17 @@ void CustomConfigurationHelper::InitializeContent(
gd::SerializerElement &configurationContent) {
for (auto &&property : properties.GetInternalVector()) {
auto &element = configurationContent.AddChild(property->GetName());
auto propertyType = property->GetType();
if (propertyType == "String" || propertyType == "Choice" ||
propertyType == "Color" || propertyType == "Behavior" ||
propertyType == "Resource") {
const auto &valueType =
gd::ValueTypeMetadata::ConvertPropertyTypeToValueType(
property->GetType());
const auto &primitiveType =
gd::ValueTypeMetadata::GetPrimitiveValueType(valueType);
if (primitiveType == "string" || valueType == "behavior") {
element.SetStringValue(property->GetValue());
} else if (propertyType == "Number") {
} else if (primitiveType == "number") {
element.SetDoubleValue(property->GetValue().To<double>());
} else if (propertyType == "Boolean") {
} else if (primitiveType == "boolean") {
element.SetBoolValue(property->GetValue() == "true");
}
}
@@ -43,23 +45,25 @@ std::map<gd::String, gd::PropertyDescriptor> CustomConfigurationHelper::GetPrope
for (auto &property : properties.GetInternalVector()) {
const auto &propertyName = property->GetName();
const auto &propertyType = property->GetType();
// Copy the property
objectProperties[propertyName] = *property;
auto &newProperty = objectProperties[propertyName];
const auto &valueType =
gd::ValueTypeMetadata::ConvertPropertyTypeToValueType(
property->GetType());
const auto &primitiveType =
gd::ValueTypeMetadata::GetPrimitiveValueType(valueType);
if (configurationContent.HasChild(propertyName)) {
if (propertyType == "String" || propertyType == "Choice" ||
propertyType == "Color" || propertyType == "Behavior" ||
propertyType == "Resource") {
if (primitiveType == "string" || valueType == "behavior") {
newProperty.SetValue(
configurationContent.GetChild(propertyName).GetStringValue());
} else if (propertyType == "Number") {
} else if (primitiveType == "number") {
newProperty.SetValue(gd::String::From(
configurationContent.GetChild(propertyName).GetDoubleValue()));
} else if (propertyType == "Boolean") {
} else if (primitiveType == "boolean") {
newProperty.SetValue(
configurationContent.GetChild(propertyName).GetBoolValue()
? "true"
@@ -85,15 +89,16 @@ bool CustomConfigurationHelper::UpdateProperty(
const auto &property = properties.Get(propertyName);
auto &element = configurationContent.AddChild(propertyName);
const gd::String &propertyType = property.GetType();
if (propertyType == "String" || propertyType == "Choice" ||
propertyType == "Color" || propertyType == "Behavior" ||
propertyType == "Resource") {
const auto &valueType =
gd::ValueTypeMetadata::ConvertPropertyTypeToValueType(property.GetType());
const auto &primitiveType =
gd::ValueTypeMetadata::GetPrimitiveValueType(valueType);
if (primitiveType == "string" || valueType == "behavior") {
element.SetStringValue(newValue);
} else if (propertyType == "Number") {
} else if (primitiveType == "number") {
element.SetDoubleValue(newValue.To<double>());
} else if (propertyType == "Boolean") {
} else if (primitiveType == "boolean") {
element.SetBoolValue(newValue == "1");
}

View File

@@ -19,6 +19,7 @@ using namespace gd;
void CustomObjectConfiguration::Init(const gd::CustomObjectConfiguration& objectConfiguration) {
project = objectConfiguration.project;
variantName = objectConfiguration.variantName;
objectContent = objectConfiguration.objectContent;
animations = objectConfiguration.animations;
isMarkedAsOverridingEventsBasedObjectChildrenConfiguration =
@@ -158,11 +159,14 @@ bool CustomObjectConfiguration::UpdateInitialInstanceProperty(
void CustomObjectConfiguration::DoSerializeTo(SerializerElement& element) const {
element.AddChild("content") = objectContent;
if (!animations.HasNoAnimations()) {
const auto *eventsBasedObject = GetEventsBasedObject();
if (!animations.HasNoAnimations() ||
(eventsBasedObject && eventsBasedObject->IsAnimatable())) {
auto &animatableElement = element.AddChild("animatable");
animations.SerializeTo(animatableElement);
}
element.SetAttribute("variant", variantName);
if (IsOverridingEventsBasedObjectChildrenConfiguration()) {
auto &childrenContentElement = element.AddChild("childrenContent");
for (auto &pair : childObjectConfigurations) {
@@ -182,6 +186,7 @@ void CustomObjectConfiguration::DoUnserializeFrom(Project& project,
animations.UnserializeFrom(animatableElement);
}
variantName = element.GetStringAttribute("variant");
isMarkedAsOverridingEventsBasedObjectChildrenConfiguration =
element.HasChild("childrenContent");
if (isMarkedAsOverridingEventsBasedObjectChildrenConfiguration) {
@@ -202,8 +207,8 @@ void CustomObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker& wor
for (auto& property : properties) {
const String& propertyName = property.first;
const gd::PropertyDescriptor& propertyDescriptor = property.second;
if (propertyDescriptor.GetType() == "resource") {
const gd::PropertyDescriptor &propertyDescriptor = property.second;
if (propertyDescriptor.GetType().LowerCase() == "resource") {
auto& extraInfo = propertyDescriptor.GetExtraInfo();
const gd::String& resourceType = extraInfo.empty() ? "" : extraInfo[0];
const gd::String& oldPropertyValue = propertyDescriptor.GetValue();
@@ -245,9 +250,26 @@ void CustomObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker& wor
}
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
for (auto& childObject : eventsBasedObject.GetObjects().GetObjects()) {
auto &configuration = GetChildObjectConfiguration(childObject->GetName());
configuration.ExposeResources(worker);
if (isMarkedAsOverridingEventsBasedObjectChildrenConfiguration) {
for (auto &childObject : eventsBasedObject.GetObjects().GetObjects()) {
auto &configuration = GetChildObjectConfiguration(childObject->GetName());
configuration.ExposeResources(worker);
}
} else {
if (variantName.empty() ||
!eventsBasedObject.GetVariants().HasVariantNamed(variantName)) {
for (auto &childObject :
eventsBasedObject.GetDefaultVariant().GetObjects().GetObjects()) {
childObject->GetConfiguration().ExposeResources(worker);
}
} else {
for (auto &childObject : eventsBasedObject.GetVariants()
.GetVariant(variantName)
.GetObjects()
.GetObjects()) {
childObject->GetConfiguration().ExposeResources(worker);
}
}
}
}

View File

@@ -29,9 +29,9 @@ namespace gd {
* "resource".
*/
class CustomObjectConfiguration : public gd::ObjectConfiguration {
public:
CustomObjectConfiguration(const Project& project_, const String& type_)
: project(&project_), isMarkedAsOverridingEventsBasedObjectChildrenConfiguration(false) {
public:
CustomObjectConfiguration(const Project &project_, const String &type_)
: project(&project_) {
SetType(type_);
}
std::unique_ptr<gd::ObjectConfiguration> Clone() const override;
@@ -66,6 +66,18 @@ class CustomObjectConfiguration : public gd::ObjectConfiguration {
void ExposeResources(gd::ArbitraryResourceWorker& worker) override;
/**
* \brief Get the name of the events-based object variant used by this custom object.
*/
const gd::String &GetVariantName() const { return variantName; };
/**
* \brief Set the name of the events-based object variant used by this custom object.
*/
void SetVariantName(const gd::String &variantName_) {
variantName = variantName_;
}
bool IsForcedToOverrideEventsBasedObjectChildrenConfiguration() const;
bool IsMarkedAsOverridingEventsBasedObjectChildrenConfiguration() const {
@@ -145,6 +157,7 @@ protected:
gd::SerializerElement objectContent;
std::unordered_set<gd::String> unfoldedChildren;
gd::String variantName = "";
bool isMarkedAsOverridingEventsBasedObjectChildrenConfiguration = false;
mutable std::map<gd::String, std::unique_ptr<gd::ObjectConfiguration>> childObjectConfigurations;

View File

@@ -21,9 +21,6 @@ EventsBasedBehavior::EventsBasedBehavior()
void EventsBasedBehavior::SerializeTo(SerializerElement& element) const {
AbstractEventsBasedEntity::SerializeTo(element);
element.SetAttribute("objectType", objectType);
if (isPrivate) {
element.SetBoolAttribute("private", isPrivate);
}
sharedPropertyDescriptors.SerializeElementsTo(
"propertyDescriptor", element.AddChild("sharedPropertyDescriptors"));
if (quickCustomizationVisibility != QuickCustomization::Visibility::Default) {
@@ -39,7 +36,6 @@ void EventsBasedBehavior::UnserializeFrom(gd::Project& project,
const SerializerElement& element) {
AbstractEventsBasedEntity::UnserializeFrom(project, element);
objectType = element.GetStringAttribute("objectType");
isPrivate = element.GetBoolAttribute("private");
sharedPropertyDescriptors.UnserializeElementsFrom(
"propertyDescriptor", element.GetChild("sharedPropertyDescriptors"));
if (element.HasChild("quickCustomizationVisibility")) {

View File

@@ -3,8 +3,7 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EVENTSBASEDBEHAVIOR_H
#define GDCORE_EVENTSBASEDBEHAVIOR_H
#pragma once
#include <vector>
#include "GDCore/Project/AbstractEventsBasedEntity.h"
@@ -75,17 +74,11 @@ class GD_CORE_API EventsBasedBehavior: public AbstractEventsBasedEntity {
}
/**
* \brief Check if the behavior is private - it can't be used outside of its
* \brief Set that the behavior or object is private - it can't be used outside of its
* extension.
*/
bool IsPrivate() const { return isPrivate; }
/**
* \brief Set that the behavior is private - it can't be used outside of its
* extension.
*/
EventsBasedBehavior& SetPrivate(bool _isPrivate) {
isPrivate = _isPrivate;
EventsBasedBehavior& SetPrivate(bool isPrivate) {
AbstractEventsBasedEntity::SetPrivate(isPrivate);
return *this;
}
@@ -149,11 +142,8 @@ class GD_CORE_API EventsBasedBehavior: public AbstractEventsBasedEntity {
private:
gd::String objectType;
bool isPrivate = false;
gd::PropertiesContainer sharedPropertyDescriptors;
QuickCustomization::Visibility quickCustomizationVisibility;
};
} // namespace gd
#endif // GDCORE_EVENTSBASEDBEHAVIOR_H

View File

@@ -17,18 +17,13 @@ EventsBasedObject::EventsBasedObject()
isAnimatable(false),
isTextContainer(false),
isInnerAreaFollowingParentSize(false),
isUsingLegacyInstancesRenderer(false),
areaMinX(0),
areaMinY(0),
areaMinZ(0),
areaMaxX(64),
areaMaxY(64),
areaMaxZ(64) {
isUsingLegacyInstancesRenderer(false) {
}
EventsBasedObject::~EventsBasedObject() {}
void EventsBasedObject::SerializeTo(SerializerElement& element) const {
void EventsBasedObject::SerializeToExternal(SerializerElement& element) const {
element.SetAttribute("defaultName", defaultName);
if (isRenderedIn3D) {
element.SetBoolAttribute("is3D", true);
@@ -43,20 +38,16 @@ void EventsBasedObject::SerializeTo(SerializerElement& element) const {
element.SetBoolAttribute("isInnerAreaFollowingParentSize", true);
}
element.SetBoolAttribute("isUsingLegacyInstancesRenderer", isUsingLegacyInstancesRenderer);
element.SetIntAttribute("areaMinX", areaMinX);
element.SetIntAttribute("areaMinY", areaMinY);
element.SetIntAttribute("areaMinZ", areaMinZ);
element.SetIntAttribute("areaMaxX", areaMaxX);
element.SetIntAttribute("areaMaxY", areaMaxY);
element.SetIntAttribute("areaMaxZ", areaMaxZ);
// The EventsBasedObjectVariant SerializeTo method override the name.
// AbstractEventsBasedEntity::SerializeTo must be done after.
defaultVariant.SerializeTo(element);
AbstractEventsBasedEntity::SerializeTo(element);
objectsContainer.SerializeObjectsTo(element.AddChild("objects"));
objectsContainer.SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
objectsContainer.GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
}
layers.SerializeLayersTo(element.AddChild("layers"));
initialInstances.SerializeTo(element.AddChild("instances"));
void EventsBasedObject::SerializeTo(SerializerElement& element) const {
SerializeToExternal(element);
variants.SerializeVariantsTo(element.AddChild("variants"));
}
void EventsBasedObject::UnserializeFrom(gd::Project& project,
@@ -67,36 +58,22 @@ void EventsBasedObject::UnserializeFrom(gd::Project& project,
isTextContainer = element.GetBoolAttribute("isTextContainer", false);
isInnerAreaFollowingParentSize =
element.GetBoolAttribute("isInnerAreaFollowingParentSize", false);
areaMinX = element.GetIntAttribute("areaMinX", 0);
areaMinY = element.GetIntAttribute("areaMinY", 0);
areaMinZ = element.GetIntAttribute("areaMinZ", 0);
areaMaxX = element.GetIntAttribute("areaMaxX", 64);
areaMaxY = element.GetIntAttribute("areaMaxY", 64);
areaMaxZ = element.GetIntAttribute("areaMaxZ", 64);
defaultVariant.UnserializeFrom(project, element);
defaultVariant.SetName("");
AbstractEventsBasedEntity::UnserializeFrom(project, element);
objectsContainer.UnserializeObjectsFrom(project, element.GetChild("objects"));
if (element.HasChild("objectsFolderStructure")) {
objectsContainer.UnserializeFoldersFrom(project, element.GetChild("objectsFolderStructure", 0));
}
objectsContainer.AddMissingObjectsInRootFolder();
objectsContainer.GetObjectGroups().UnserializeFrom(
element.GetChild("objectsGroups"));
if (element.HasChild("layers")) {
layers.UnserializeLayersFrom(element.GetChild("layers"));
} else {
layers.Reset();
if (element.HasChild("variants")) {
variants.UnserializeVariantsFrom(project, element.GetChild("variants"));
}
initialInstances.UnserializeFrom(element.GetChild("instances"));
if (element.HasAttribute("isUsingLegacyInstancesRenderer")) {
if (element.HasChild("isUsingLegacyInstancesRenderer")) {
isUsingLegacyInstancesRenderer =
element.GetBoolAttribute("isUsingLegacyInstancesRenderer", false);
}
else {
// Compatibility with GD <= 5.4.212
isUsingLegacyInstancesRenderer = initialInstances.GetInstancesCount() == 0;
isUsingLegacyInstancesRenderer = GetInitialInstances().GetInstancesCount() == 0;
// end of compatibility code
}
}

View File

@@ -7,6 +7,8 @@
#include <vector>
#include "GDCore/Project/AbstractEventsBasedEntity.h"
#include "GDCore/Project/EventsBasedObjectVariant.h"
#include "GDCore/Project/EventsBasedObjectVariantsContainer.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/InitialInstancesContainer.h"
#include "GDCore/Project/LayersContainer.h"
@@ -72,6 +74,15 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
return *this;
}
/**
* \brief Set that the object is private - it can't be used outside of its
* extension.
*/
EventsBasedObject& SetPrivate(bool isPrivate) {
AbstractEventsBasedEntity::SetPrivate(isPrivate);
return *this;
}
/**
* \brief Declare a usage of the 3D renderer.
*/
@@ -153,18 +164,38 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
*/
bool IsTextContainer() const { return isTextContainer; }
/**
* \brief Get the default variant of the custom object.
*/
const gd::EventsBasedObjectVariant& GetDefaultVariant() const { return defaultVariant; }
/**
* \brief Get the default variant of the custom object.
*/
gd::EventsBasedObjectVariant& GetDefaultVariant() { return defaultVariant; }
/**
* \brief Get the variants of the custom object.
*/
const gd::EventsBasedObjectVariantsContainer& GetVariants() const { return variants; }
/**
* \brief Get the variants of the custom object.
*/
gd::EventsBasedObjectVariantsContainer& GetVariants() { return variants; }
/** \name Layers
*/
///@{
/**
* \brief Get the layers of the custom object.
*/
const gd::LayersContainer& GetLayers() const { return layers; }
const gd::LayersContainer& GetLayers() const { return defaultVariant.GetLayers(); }
/**
* \brief Get the layers of the custom object.
*/
gd::LayersContainer& GetLayers() { return layers; }
gd::LayersContainer& GetLayers() { return defaultVariant.GetLayers(); }
///@}
/** \name Child objects
@@ -174,14 +205,14 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
* \brief Get the objects of the custom object.
*/
gd::ObjectsContainer& GetObjects() {
return objectsContainer;
return defaultVariant.GetObjects();
}
/**
* \brief Get the objects of the custom object.
*/
const gd::ObjectsContainer& GetObjects() const {
return objectsContainer;
return defaultVariant.GetObjects();
}
///@}
@@ -192,14 +223,14 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
* \brief Get the instances of the custom object.
*/
gd::InitialInstancesContainer& GetInitialInstances() {
return initialInstances;
return defaultVariant.GetInitialInstances();
}
/**
* \brief Get the instances of the custom object.
*/
const gd::InitialInstancesContainer& GetInitialInstances() const {
return initialInstances;
return defaultVariant.GetInitialInstances();
}
/**
@@ -210,14 +241,14 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
* \see EventsBasedObject::GetInitialInstances
*/
int GetAreaMinX() const {
return areaMinX;
return defaultVariant.GetAreaMinX();
}
/**
* \brief Set the left bound of the custom object.
*/
void SetAreaMinX(int areaMinX_) {
areaMinX = areaMinX_;
void SetAreaMinX(int areaMinX) {
defaultVariant.SetAreaMinX(areaMinX);
}
/**
@@ -228,14 +259,14 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
* \see EventsBasedObject::GetInitialInstances
*/
int GetAreaMinY() const {
return areaMinY;
return defaultVariant.GetAreaMinY();
}
/**
* \brief Set the top bound of the custom object.
*/
void SetAreaMinY(int areaMinY_) {
areaMinY = areaMinY_;
void SetAreaMinY(int areaMinY) {
defaultVariant.SetAreaMinY(areaMinY);
}
/**
@@ -246,14 +277,14 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
* \see EventsBasedObject::GetInitialInstances
*/
int GetAreaMinZ() const {
return areaMinZ;
return defaultVariant.GetAreaMinZ();
}
/**
* \brief Set the min Z bound of the custom object.
*/
void SetAreaMinZ(int areaMinZ_) {
areaMinZ = areaMinZ_;
void SetAreaMinZ(int areaMinZ) {
defaultVariant.SetAreaMinZ(areaMinZ);
}
/**
@@ -264,14 +295,14 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
* \see EventsBasedObject::GetInitialInstances
*/
int GetAreaMaxX() const {
return areaMaxX;
return defaultVariant.GetAreaMaxX();
}
/**
* \brief Set the right bound of the custom object.
*/
void SetAreaMaxX(int areaMaxX_) {
areaMaxX = areaMaxX_;
void SetAreaMaxX(int areaMaxX) {
defaultVariant.SetAreaMaxX(areaMaxX);
}
/**
@@ -282,14 +313,14 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
* \see EventsBasedObject::GetInitialInstances
*/
int GetAreaMaxY() const {
return areaMaxY;
return defaultVariant.GetAreaMaxY();
}
/**
* \brief Set the bottom bound of the custom object.
*/
void SetAreaMaxY(int areaMaxY_) {
areaMaxY = areaMaxY_;
void SetAreaMaxY(int areaMaxY) {
defaultVariant.SetAreaMaxY(areaMaxY);
}
/**
@@ -300,16 +331,22 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
* \see EventsBasedObject::GetInitialInstances
*/
int GetAreaMaxZ() const {
return areaMaxZ;
return defaultVariant.GetAreaMaxZ();
}
/**
* \brief Set the bottom bound of the custom object.
*/
void SetAreaMaxZ(int areaMaxZ_) {
areaMaxZ = areaMaxZ_;
void SetAreaMaxZ(int areaMaxZ) {
defaultVariant.SetAreaMaxZ(areaMaxZ);
}
///@}
/**
* @brief Serialize the events-based object for an extension in an external file.
* Variants are not serialized.
*/
void SerializeToExternal(SerializerElement& element) const;
void SerializeTo(SerializerElement& element) const override;
@@ -323,15 +360,8 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
bool isTextContainer;
bool isInnerAreaFollowingParentSize;
bool isUsingLegacyInstancesRenderer;
gd::InitialInstancesContainer initialInstances;
gd::LayersContainer layers;
gd::ObjectsContainer objectsContainer;
double areaMinX;
double areaMinY;
double areaMinZ;
double areaMaxX;
double areaMaxY;
double areaMaxZ;
gd::EventsBasedObjectVariant defaultVariant;
gd::EventsBasedObjectVariantsContainer variants;
};
} // namespace gd

View File

@@ -0,0 +1,71 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "EventsBasedObjectVariant.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Serialization/SerializerElement.h"
namespace gd {
EventsBasedObjectVariant::EventsBasedObjectVariant()
: areaMinX(0), areaMinY(0), areaMinZ(0), areaMaxX(64), areaMaxY(64),
areaMaxZ(64), objectsContainer(gd::ObjectsContainer::SourceType::Object) {
}
EventsBasedObjectVariant::~EventsBasedObjectVariant() {}
void EventsBasedObjectVariant::SerializeTo(SerializerElement &element) const {
element.SetAttribute("name", name);
if (!GetAssetStoreAssetId().empty() && !GetAssetStoreOriginalName().empty()) {
element.SetAttribute("assetStoreAssetId", GetAssetStoreAssetId());
element.SetAttribute("assetStoreOriginalName", GetAssetStoreOriginalName());
}
element.SetIntAttribute("areaMinX", areaMinX);
element.SetIntAttribute("areaMinY", areaMinY);
element.SetIntAttribute("areaMinZ", areaMinZ);
element.SetIntAttribute("areaMaxX", areaMaxX);
element.SetIntAttribute("areaMaxY", areaMaxY);
element.SetIntAttribute("areaMaxZ", areaMaxZ);
objectsContainer.SerializeObjectsTo(element.AddChild("objects"));
objectsContainer.SerializeFoldersTo(
element.AddChild("objectsFolderStructure"));
objectsContainer.GetObjectGroups().SerializeTo(
element.AddChild("objectsGroups"));
layers.SerializeLayersTo(element.AddChild("layers"));
initialInstances.SerializeTo(element.AddChild("instances"));
}
void EventsBasedObjectVariant::UnserializeFrom(
gd::Project &project, const SerializerElement &element) {
name = element.GetStringAttribute("name");
assetStoreAssetId = element.GetStringAttribute("assetStoreAssetId");
assetStoreOriginalName = element.GetStringAttribute("assetStoreOriginalName");
areaMinX = element.GetIntAttribute("areaMinX", 0);
areaMinY = element.GetIntAttribute("areaMinY", 0);
areaMinZ = element.GetIntAttribute("areaMinZ", 0);
areaMaxX = element.GetIntAttribute("areaMaxX", 64);
areaMaxY = element.GetIntAttribute("areaMaxY", 64);
areaMaxZ = element.GetIntAttribute("areaMaxZ", 64);
objectsContainer.UnserializeObjectsFrom(project, element.GetChild("objects"));
if (element.HasChild("objectsFolderStructure")) {
objectsContainer.UnserializeFoldersFrom(
project, element.GetChild("objectsFolderStructure", 0));
}
objectsContainer.AddMissingObjectsInRootFolder();
objectsContainer.GetObjectGroups().UnserializeFrom(
element.GetChild("objectsGroups"));
if (element.HasChild("layers")) {
layers.UnserializeLayersFrom(element.GetChild("layers"));
} else {
layers.Reset();
}
initialInstances.UnserializeFrom(element.GetChild("instances"));
}
} // namespace gd

View File

@@ -0,0 +1,229 @@
/*
* GDevelop Core
* Copyright 2008-2025 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include "GDCore/Project/InitialInstancesContainer.h"
#include "GDCore/Project/LayersContainer.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/String.h"
#include <vector>
namespace gd {
class SerializerElement;
class Project;
} // namespace gd
namespace gd {
/**
* \brief Represents a variation of style of an events-based object.
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API EventsBasedObjectVariant {
public:
EventsBasedObjectVariant();
virtual ~EventsBasedObjectVariant();
/**
* \brief Return a pointer to a new EventsBasedObjectVariant constructed from
* this one.
*/
EventsBasedObjectVariant *Clone() const {
return new EventsBasedObjectVariant(*this);
};
/**
* \brief Get the name of the variant.
*/
const gd::String &GetName() const { return name; };
/**
* \brief Set the name of the variant.
*/
EventsBasedObjectVariant &SetName(const gd::String &name_) {
name = name_;
return *this;
}
/** \name Layers
*/
///@{
/**
* \brief Get the layers of the variant.
*/
const gd::LayersContainer &GetLayers() const { return layers; }
/**
* \brief Get the layers of the variant.
*/
gd::LayersContainer &GetLayers() { return layers; }
///@}
/** \name Child objects
*/
///@{
/**
* \brief Get the objects of the variant.
*/
gd::ObjectsContainer &GetObjects() { return objectsContainer; }
/**
* \brief Get the objects of the variant.
*/
const gd::ObjectsContainer &GetObjects() const { return objectsContainer; }
///@}
/** \name Instances
*/
///@{
/**
* \brief Get the instances of the variant.
*/
gd::InitialInstancesContainer &GetInitialInstances() {
return initialInstances;
}
/**
* \brief Get the instances of the variant.
*/
const gd::InitialInstancesContainer &GetInitialInstances() const {
return initialInstances;
}
/**
* \brief Get the left bound of the variant.
*
* This is used only if there is any initial instances.
*
* \see EventsBasedObjectVariant::GetInitialInstances
*/
int GetAreaMinX() const { return areaMinX; }
/**
* \brief Set the left bound of the variant.
*/
void SetAreaMinX(int areaMinX_) { areaMinX = areaMinX_; }
/**
* \brief Get the top bound of the variant.
*
* This is used only if there is any initial instances.
*
* \see EventsBasedObjectVariant::GetInitialInstances
*/
int GetAreaMinY() const { return areaMinY; }
/**
* \brief Set the top bound of the variant.
*/
void SetAreaMinY(int areaMinY_) { areaMinY = areaMinY_; }
/**
* \brief Get the min Z bound of the variant.
*
* This is used only if there is any initial instances.
*
* \see EventsBasedObjectVariant::GetInitialInstances
*/
int GetAreaMinZ() const { return areaMinZ; }
/**
* \brief Set the min Z bound of the variant.
*/
void SetAreaMinZ(int areaMinZ_) { areaMinZ = areaMinZ_; }
/**
* \brief Get the right bound of the variant.
*
* This is used only if there is any initial instances.
*
* \see EventsBasedObjectVariant::GetInitialInstances
*/
int GetAreaMaxX() const { return areaMaxX; }
/**
* \brief Set the right bound of the variant.
*/
void SetAreaMaxX(int areaMaxX_) { areaMaxX = areaMaxX_; }
/**
* \brief Get the bottom bound of the variant.
*
* This is used only if there is any initial instances.
*
* \see EventsBasedObjectVariant::GetInitialInstances
*/
int GetAreaMaxY() const { return areaMaxY; }
/**
* \brief Set the bottom bound of the variant.
*/
void SetAreaMaxY(int areaMaxY_) { areaMaxY = areaMaxY_; }
/**
* \brief Get the max Z bound of the variant.
*
* This is used only if there is any initial instances.
*
* \see EventsBasedObjectVariant::GetInitialInstances
*/
int GetAreaMaxZ() const { return areaMaxZ; }
/**
* \brief Set the bottom bound of the variant.
*/
void SetAreaMaxZ(int areaMaxZ_) { areaMaxZ = areaMaxZ_; }
///@}
/** \brief Change the object asset store id of this variant.
*/
void SetAssetStoreAssetId(const gd::String &assetStoreId_) {
assetStoreAssetId = assetStoreId_;
};
/** \brief Return the object asset store id of this variant.
*/
const gd::String &GetAssetStoreAssetId() const { return assetStoreAssetId; };
/** \brief Change the original name of the variant in the asset.
*/
void SetAssetStoreOriginalName(const gd::String &assetStoreOriginalName_) {
assetStoreOriginalName = assetStoreOriginalName_;
};
/** \brief Return the original name of the variant in the asset.
*/
const gd::String &GetAssetStoreOriginalName() const {
return assetStoreOriginalName;
};
void SerializeTo(SerializerElement &element) const;
void UnserializeFrom(gd::Project &project, const SerializerElement &element);
private:
gd::String name;
gd::InitialInstancesContainer initialInstances;
gd::LayersContainer layers;
gd::ObjectsContainer objectsContainer;
double areaMinX;
double areaMinY;
double areaMinZ;
double areaMaxX;
double areaMaxY;
double areaMaxZ;
/**
* The ID of the asset if the object comes from the store.
*/
gd::String assetStoreAssetId;
/**
* The original name of the variant in the asset if the object comes from the
* store.
*/
gd::String assetStoreOriginalName;
};
} // namespace gd

View File

@@ -0,0 +1,160 @@
/*
* 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 <vector>
#include "GDCore/Project/EventsBasedObjectVariant.h"
#include "GDCore/String.h"
#include "GDCore/Tools/SerializableWithNameList.h"
namespace gd {
class SerializerElement;
}
namespace gd {
/**
* \brief Used as a base class for classes that will own events-backed
* variants.
*
* \see gd::EventsBasedObjectVariantContainer
* \ingroup PlatformDefinition
*/
class GD_CORE_API EventsBasedObjectVariantsContainer
: private SerializableWithNameList<gd::EventsBasedObjectVariant> {
public:
EventsBasedObjectVariantsContainer() {}
EventsBasedObjectVariantsContainer(const EventsBasedObjectVariantsContainer &other) {
Init(other);
}
EventsBasedObjectVariantsContainer &operator=(const EventsBasedObjectVariantsContainer &other) {
if (this != &other) {
Init(other);
}
return *this;
}
/** \name Events Functions management
*/
///@{
/**
* \brief Check if the variant with the specified name exists.
*/
bool HasVariantNamed(const gd::String& name) const {
return Has(name);
}
/**
* \brief Get the variant with the specified name.
*
* \warning Trying to access to a not existing variant will result in
* undefined behavior.
*/
gd::EventsBasedObjectVariant& GetVariant(const gd::String& name) {
return Get(name);
}
/**
* \brief Get the variant with the specified name.
*
* \warning Trying to access to a not existing variant will result in
* undefined behavior.
*/
const gd::EventsBasedObjectVariant& GetVariant(const gd::String& name) const {
return Get(name);
}
/**
* \brief Get the variant at the specified index in the list.
*
* \warning Trying to access to a not existing variant will result in
* undefined behavior.
*/
gd::EventsBasedObjectVariant& GetVariant(std::size_t index) {
return Get(index);
}
/**
* \brief Get the variant at the specified index in the list.
*
* \warning Trying to access to a not existing variant will result in
* undefined behavior.
*/
const gd::EventsBasedObjectVariant& GetVariant(std::size_t index) const {
return Get(index);
}
/**
* \brief Return the number of variants.
*/
std::size_t GetVariantsCount() const { return GetCount(); }
gd::EventsBasedObjectVariant& InsertNewVariant(const gd::String& name,
std::size_t position) {
return InsertNew(name, position);
}
gd::EventsBasedObjectVariant& InsertVariant(const gd::EventsBasedObjectVariant& object,
std::size_t position) {
return Insert(object, position);
}
void RemoveVariant(const gd::String& name) { return Remove(name); }
void ClearVariants() { return Clear(); }
void MoveVariant(std::size_t oldIndex, std::size_t newIndex) {
return Move(oldIndex, newIndex);
};
std::size_t GetVariantPosition(const gd::EventsBasedObjectVariant& eventsFunction) {
return GetPosition(eventsFunction);
};
/**
* \brief Provide a raw access to the vector containing the variants.
*/
const std::vector<std::unique_ptr<gd::EventsBasedObjectVariant>>& GetInternalVector()
const {
return elements;
};
/**
* \brief Provide a raw access to the vector containing the variants.
*/
std::vector<std::unique_ptr<gd::EventsBasedObjectVariant>>& GetInternalVector() {
return elements;
};
///@}
/** \name Serialization
*/
///@{
/**
* \brief Serialize events variants.
*/
void SerializeVariantsTo(SerializerElement& element) const {
return SerializeElementsTo("variant", element);
};
/**
* \brief Unserialize the events variants.
*/
void UnserializeVariantsFrom(gd::Project& project,
const SerializerElement& element) {
return UnserializeElementsFrom("variant", project, element);
};
///@}
protected:
/**
* Initialize object using another object. Used by copy-ctor and assign-op.
* Don't forget to update me if members were changed!
*/
void Init(const gd::EventsBasedObjectVariantsContainer& other) {
return SerializableWithNameList<gd::EventsBasedObjectVariant>::Init(other);
};
private:
};
} // namespace gd

View File

@@ -33,6 +33,20 @@ public:
EventsFunctionsContainer(FunctionOwner source_) : owner(source_) {}
EventsFunctionsContainer(const EventsFunctionsContainer &other)
: owner(other.owner) {
Init(other);
}
EventsFunctionsContainer &operator=(const EventsFunctionsContainer &other) {
if (this != &other) {
owner = other.owner;
Init(other);
}
return *this;
}
/**
* \brief Get the source of the function container.
*

View File

@@ -15,14 +15,13 @@
namespace gd {
EventsFunctionsExtension::EventsFunctionsExtension() :
gd::EventsFunctionsContainer(
gd::EventsFunctionsContainer::FunctionOwner::Extension),
eventsFunctionsContainer(gd::EventsFunctionsContainer::FunctionOwner::Extension),
globalVariables(gd::VariablesContainer::SourceType::ExtensionGlobal),
sceneVariables(gd::VariablesContainer::SourceType::ExtensionScene) {}
EventsFunctionsExtension::EventsFunctionsExtension(
const EventsFunctionsExtension& other) :
gd::EventsFunctionsContainer(
eventsFunctionsContainer(
gd::EventsFunctionsContainer::FunctionOwner::Extension) {
Init(other);
}
@@ -48,14 +47,15 @@ void EventsFunctionsExtension::Init(const gd::EventsFunctionsExtension& other) {
previewIconUrl = other.previewIconUrl;
iconUrl = other.iconUrl;
helpPath = other.helpPath;
EventsFunctionsContainer::Init(other);
gdevelopVersion = other.gdevelopVersion;
eventsFunctionsContainer = other.eventsFunctionsContainer;
eventsBasedBehaviors = other.eventsBasedBehaviors;
eventsBasedObjects = other.eventsBasedObjects;
globalVariables = other.GetGlobalVariables();
sceneVariables = other.GetSceneVariables();
}
void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
void EventsFunctionsExtension::SerializeTo(SerializerElement& element, bool isExternal) const {
element.SetAttribute("version", version);
element.SetAttribute("extensionNamespace", extensionNamespace);
element.SetAttribute("shortDescription", shortDescription);
@@ -82,19 +82,38 @@ void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
element.SetAttribute("previewIconUrl", previewIconUrl);
element.SetAttribute("iconUrl", iconUrl);
element.SetAttribute("helpPath", helpPath);
element.SetAttribute("gdevelopVersion", gdevelopVersion);
auto& dependenciesElement = element.AddChild("dependencies");
dependenciesElement.ConsiderAsArray();
for (auto& dependency : dependencies)
SerializeDependencyTo(dependency, dependenciesElement.AddChild(""));
if (!sourceFiles.empty()) {
auto& sourceFilesElement = element.AddChild("sourceFiles");
sourceFilesElement.ConsiderAsArray();
for (auto& sourceFile : sourceFiles)
sourceFile.SerializeTo(sourceFilesElement.AddChild(""));
}
GetGlobalVariables().SerializeTo(element.AddChild("globalVariables"));
GetSceneVariables().SerializeTo(element.AddChild("sceneVariables"));
SerializeEventsFunctionsTo(element.AddChild("eventsFunctions"));
eventsFunctionsContainer.SerializeEventsFunctionsTo(
element.AddChild("eventsFunctions"));
eventsBasedBehaviors.SerializeElementsTo(
"eventsBasedBehavior", element.AddChild("eventsBasedBehaviors"));
eventsBasedObjects.SerializeElementsTo(
"eventsBasedObject", element.AddChild("eventsBasedObjects"));
if (isExternal) {
auto &eventsBasedObjectElement = element.AddChild("eventsBasedObjects");
eventsBasedObjectElement.ConsiderAsArrayOf("eventsBasedObject");
for (const auto &eventsBasedObject :
eventsBasedObjects.GetInternalVector()) {
eventsBasedObject->SerializeToExternal(
eventsBasedObjectElement.AddChild("eventsBasedObject"));
}
} else {
eventsBasedObjects.SerializeElementsTo(
"eventsBasedObject", element.AddChild("eventsBasedObjects"));
}
}
void EventsFunctionsExtension::UnserializeFrom(
@@ -119,6 +138,7 @@ void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
previewIconUrl = element.GetStringAttribute("previewIconUrl");
iconUrl = element.GetStringAttribute("iconUrl");
helpPath = element.GetStringAttribute("helpPath");
gdevelopVersion = element.GetStringAttribute("gdevelopVersion");
if (element.HasChild("origin")) {
gd::String originName =
@@ -159,6 +179,17 @@ void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
dependencies.push_back(
UnserializeDependencyFrom(dependenciesElement.GetChild(i)));
sourceFiles.clear();
if (element.HasChild("sourceFiles")) {
const auto& sourceFilesElement = element.GetChild("sourceFiles");
sourceFilesElement.ConsiderAsArray();
for (size_t i = 0; i < sourceFilesElement.GetChildrenCount(); ++i) {
SourceFileMetadata sourceFile;
sourceFile.UnserializeFrom(sourceFilesElement.GetChild(i));
sourceFiles.push_back(sourceFile);
}
}
globalVariables.UnserializeFrom(element.GetChild("globalVariables"));
sceneVariables.UnserializeFrom(element.GetChild("sceneVariables"));
@@ -166,6 +197,7 @@ void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
// As event based objects can contains objects using CustomBehavior and/or
// CustomObject, this allows them to reference EventBasedBehavior and
// EventBasedObject respectively.
eventsBasedBehaviors.Clear();
auto &behaviorsElement = element.GetChild("eventsBasedBehaviors");
behaviorsElement.ConsiderAsArrayOf("eventsBasedBehavior");
for (std::size_t i = 0; i < behaviorsElement.GetChildrenCount(); ++i) {
@@ -173,6 +205,7 @@ void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
behaviorsElement.GetChild(i).GetStringAttribute("name");
eventsBasedBehaviors.InsertNew(behaviorName, eventsBasedBehaviors.GetCount());
}
eventsBasedObjects.Clear();
auto &objectsElement = element.GetChild("eventsBasedObjects");
objectsElement.ConsiderAsArrayOf("eventsBasedObject");
for (std::size_t i = 0; i < objectsElement.GetChildrenCount(); ++i) {
@@ -185,7 +218,8 @@ void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
void EventsFunctionsExtension::UnserializeExtensionImplementationFrom(
gd::Project& project,
const SerializerElement& element) {
UnserializeEventsFunctionsFrom(project, element.GetChild("eventsFunctions"));
eventsFunctionsContainer.UnserializeEventsFunctionsFrom(
project, element.GetChild("eventsFunctions"));
eventsBasedBehaviors.UnserializeElementsFrom(
"eventsBasedBehavior", project, element.GetChild("eventsBasedBehaviors"));

View File

@@ -8,6 +8,7 @@
#include <vector>
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
#include "GDCore/Extensions/Metadata/SourceFileMetadata.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/EventsFunctionsContainer.h"
@@ -35,7 +36,7 @@ namespace gd {
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
class GD_CORE_API EventsFunctionsExtension {
public:
EventsFunctionsExtension();
EventsFunctionsExtension(const EventsFunctionsExtension&);
@@ -133,6 +134,19 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
return *this;
}
/**
* \brief Get the GDevelop version required by this extension.
*/
const gd::String& GetGDevelopVersion() const { return gdevelopVersion; };
/**
* \brief Set the GDevelop version required by this extension.
*/
EventsFunctionsExtension& SetGDevelopVersion(const gd::String& gdevelopVersion_) {
gdevelopVersion = gdevelopVersion_;
return *this;
}
/**
* \brief Return a reference to the list of the events based behaviors.
*/
@@ -180,6 +194,21 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
return originIdentifier;
}
/**
* \brief Return a reference to the functions of the events based behavior or object.
*/
EventsFunctionsContainer& GetEventsFunctions() {
return eventsFunctionsContainer;
}
/**
* \brief Return a const reference to the functions of the events based
* behavior or object.
*/
const EventsFunctionsContainer& GetEventsFunctions() const {
return eventsFunctionsContainer;
}
/** \name Dependencies
*/
///@{
@@ -257,7 +286,14 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
/**
* \brief Serialize the EventsFunctionsExtension to the specified element
*/
void SerializeTo(gd::SerializerElement& element) const;
void SerializeTo(gd::SerializerElement& element, bool isExternal = false) const;
/**
* \brief Serialize the EventsFunctionsExtension to the specified element
*/
void SerializeToExternal(gd::SerializerElement& element) const {
SerializeTo(element, true);
}
/**
* \brief Load the EventsFunctionsExtension from the specified element.
@@ -289,6 +325,42 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
const gd::String& eventsFunctionName);
///@}
/** \name Source files
*/
///@{
/**
* \brief Adds a new source file.
*/
gd::SourceFileMetadata& AddSourceFile() {
gd::SourceFileMetadata sourceFile;
sourceFiles.push_back(sourceFile);
return sourceFiles.back();
};
/**
* \brief Removes a source file.
*/
void RemoveSourceFileAt(size_t index) {
sourceFiles.erase(sourceFiles.begin() + index);
};
/**
* \brief Returns the list of source files.
*/
std::vector<gd::SourceFileMetadata>& GetAllSourceFiles() {
return sourceFiles;
};
/**
* \brief Returns the list of source files.
*/
const std::vector<gd::SourceFileMetadata>& GetAllSourceFiles() const {
return sourceFiles;
};
///@}
private:
/**
* Initialize object using another object. Used by copy-ctor and assign-op.
@@ -333,10 +405,13 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
gd::String iconUrl;
gd::String helpPath; ///< The relative path to the help for this extension in
///< the documentation (or an absolute URL).
gd::String gdevelopVersion;
gd::SerializableWithNameList<EventsBasedBehavior> eventsBasedBehaviors;
gd::SerializableWithNameList<EventsBasedObject> eventsBasedObjects;
std::vector<gd::DependencyMetadata> dependencies;
std::vector<gd::SourceFileMetadata> sourceFiles;
gd::EventsFunctionsContainer eventsFunctionsContainer;
gd::VariablesContainer globalVariables;
gd::VariablesContainer sceneVariables;
};

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