Compare commits

...

237 Commits

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

Only show in developer changelog
2024-10-13 17:39:54 +02:00
github-actions[bot]
0a85fd3814 Update translations [skip ci] (#7038)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-10-11 15:00:20 +02:00
Clément Pasteau
fe15b6d30b Update CSP (#7042)
Do not show in changelog
2024-10-11 14:59:59 +02:00
Florian Rival
f3c3559518 Fix warning 2024-10-11 14:56:36 +02:00
D8H
a403b1343b Fix extraction of 3D custom objects and prevent extracting 2D+3D custom objects (#7040) 2024-10-11 13:42:06 +02:00
D8H
83dba6c21e Allow to open the custom object editor from objects drop-down menu (#7039) 2024-10-11 12:45:23 +02:00
Florian Rival
7a4aea6557 Fix extension not regenerated after extracting instances to a custom object 2024-10-11 11:12:52 +02:00
AlexandreS
82a6abacb4 Suggest starter tilemaps when creating a tilemap from scratch (#7035) 2024-10-11 10:52:47 +02:00
AlexandreS
f60613cc64 Use user limits to determine if version history feature can be used (#7036)
Don't show in changelog
2024-10-11 10:47:32 +02:00
github-actions[bot]
274aedb3d9 Update translations [skip ci] (#7032)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-10-11 10:20:02 +02:00
D8H
efb31c3caf Fix text wrapping issue in the editor when used as a custom object child (#7034) 2024-10-11 09:05:36 +02:00
D8H
6781c0fd6e Add a drop-down menu action to extract instances as custom objects (#7030) 2024-10-10 20:13:42 +02:00
D8H
e9781133e1 Fix events refactoring when duplicating custom behaviors or custom objects (#7005) 2024-10-10 19:48:31 +02:00
Florian Rival
8972e0e3a6 Bump version (#7033) 2024-10-10 16:54:55 +02:00
Aurélien Vivet
4c76a5979b Add a new in-app tutorial explaining how to use a Tilemap (#6989) 2024-10-10 16:36:32 +02:00
D8H
484a0daec4 Show the tolerance in the sentence of "Is object turned toward" condition (#7022) 2024-10-10 16:25:38 +02:00
AlexandreS
de432c1bf2 Add a "Tilemap" filter in the Asset Store (#7031) 2024-10-10 16:15:18 +02:00
github-actions[bot]
8c7dcc1c23 Update translations [skip ci] (#7015)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-10-10 14:56:12 +02:00
AlexandreS
39648af248 Add margin between socials and donate link in profile (#7029)
Don't show in changelog
2024-10-10 10:21:15 +02:00
AlexandreS
5c7bbf5293 Add error callback to tilemap texture parsing (#7027)
To prevent crashes in the preview
2024-10-10 10:19:26 +02:00
Florian Rival
9d97b9d0eb Fix exception 't.bind is not a function' when a resource has an empty file (#7028) 2024-10-09 15:06:28 +02:00
AlexandreS
b39b12864f Add context menu options to duplicate instruction parameter or behavior property (#7026) 2024-10-08 15:50:28 +02:00
D8H
2c3dbbbbde Fix an exception when a touch is ended and then started in the same frame at runtime (#7025) 2024-10-08 11:45:40 +02:00
Clément Pasteau
72cc60bae9 Remove searchbar from Learn page. (#7024)
* As it does not return relevant results, it is thought best to remove it for now.
2024-10-07 18:16:16 +02:00
AlexandreS
c03e94849b Handle line breaks in font resource lines in resource store (#7023)
Don't show in changelog
2024-10-07 18:06:19 +02:00
AlexandreS
80daaf5e5b Fix Teach tab missing education resources button (#7021) 2024-10-07 17:25:04 +02:00
D8H
cb457cfd04 Fix the action to change the animation elapsed time for sprites and 3d models (#7020) 2024-10-07 17:18:40 +02:00
D8H
0a55aa631b Disable the "support us" dialog during an in-app tutorial (#7019) 2024-10-07 15:44:02 +02:00
AlexandreS
8e104f9ae4 Fix text input focus messing with the input manager (#7013) 2024-10-07 12:41:10 +02:00
D8H
a90b9a27e9 [Physics2] Avoid an exception when the object position is not finite (#7017) 2024-10-07 11:11:36 +02:00
D8H
6321e82f63 [Physics2] Forbid negative damping values (#7016) 2024-10-04 18:06:12 +02:00
AlexandreS
05fc63ab1b Fix ghost hitboxes on tilemap when tiles are flipped (#6990) 2024-10-04 17:25:34 +02:00
AlexandreS
85a6a21934 Do not display guided lesson tooltip if an error boundary is displayed (#7014)
Don't show in changelog
2024-10-04 17:23:28 +02:00
Clément Pasteau
a9741e7b42 Handle internal navigation for promotions (#7012)
Do not show in changelog
2024-10-04 17:22:56 +02:00
github-actions[bot]
23afe7b71c Update translations [skip ci] (#7011)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-10-04 17:22:22 +02:00
AlexandreS
85757e6d98 Rework asset store display when looking for a font or an audio (#7009)
The asset store is not available anymore when looking for other types of resource (image, 3D models, spine).
2024-10-04 15:56:50 +02:00
github-actions[bot]
524ca4dbb3 Update translations [skip ci] (#7002)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-10-03 17:40:13 +02:00
Aurélien Vivet
55cf710ef5 Add GitHub url to community tab (#7008) 2024-10-03 17:39:11 +02:00
Clément Pasteau
eee7e7f04c Remove most titles from home for a cleaner UI (#7010)
Do not show in changelog
2024-10-03 17:38:20 +02:00
Clément Pasteau
ecd984e08b Allow opening any homepage tab from url (#7007)
Do not show in changelog
2024-10-03 17:15:16 +02:00
D8H
d0a7fbbd02 Fix a regression on existing external tile map collision mask (#7004)
- Don't show in changelog
2024-10-02 14:44:07 +02:00
D8H
2a2c930b74 Add vertical alignment property for text object (#6975)
- Fix proportional anchors on custom object children
2024-10-02 11:17:48 +02:00
D8H
f6cb203029 Allow to filter external tile map collision per layer (#6998) 2024-10-02 10:14:52 +02:00
Florian Rival
fe743bbe57 Fix usage of libGD.js in Node 2024-09-30 19:06:24 +02:00
D8H
78c31408d4 Add a comment about anchor calculus (#6976)
- Don't show in changelog
2024-09-30 18:50:13 +02:00
github-actions[bot]
75a038344a Update translations [skip ci] (#7000)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-09-30 14:58:05 +02:00
Clément Pasteau
f0567b674c Fix example thumbnails (#7001) 2024-09-30 14:43:00 +02:00
Clément Pasteau
9b85f35856 Fix typo (#6999) 2024-09-30 08:40:38 +02:00
github-actions[bot]
f4568febf2 Update translations [skip ci] (#6995)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-09-30 08:14:52 +02:00
Clément Pasteau
de7f60b693 Bump to 5.4.214 (#6993) 2024-09-28 19:22:46 +02:00
Florian Rival
3a595b200e Update README [skip ci] [ci skip]
Don't show in changelog
2024-09-28 11:47:27 +02:00
AlexandreS
431b5929e8 Fine tune teach section display (#6994)
Don't show in changelog
2024-09-27 15:15:27 +02:00
github-actions[bot]
ec2e82cee5 Update translations [skip ci] (#6992)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2024-09-27 12:37:48 +02:00
Florian Rival
76517f1a2a Adapt margins in objects panel 2024-09-27 11:27:19 +02:00
Florian Rival
43f5bd1c0e Allow to edit object properties, behaviors, variables and effects directly from the properties panel (#6898)
* When an object is selected (or when "Edit object" button is clicked in the properties panel after choosing an instance), the properties panel will show the properties of the object.
* This allows for fast edition of most elements of an object: appearance, properties, but also behaviors, variables and effects. Most workflow and iterations on your game should be faster, from adapting the appearance of a text to tweaking behaviors and updating the preview to check the result in realtime.
2024-09-27 10:56:39 +02:00
github-actions[bot]
7198a22ae2 Update translations [skip ci] (#6964)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-09-26 10:43:31 +02:00
AlexandreS
46c52905f6 Add context menu to move Sprite object animation in list (#6987) 2024-09-25 17:28:58 +02:00
AlexandreS
40954bf497 Fix some crashes happening in preview (#6988) 2024-09-25 17:26:01 +02:00
Clément Pasteau
02c06ac6e7 Fix iOS automatic exports when using admob (#6986)
* internal ios deployment-target was conflicting between the plugins used, when admob was used in the project, preventing to build the app
2024-09-25 09:52:19 +02:00
AlexandreS
1fa3f59a77 Add possibility to paint tilemap with a rectangle selection from the tileset (#6977) 2024-09-23 17:37:20 +02:00
Clément Pasteau
cc371273ce Improve Quick Customization flow (#6978)
* Simplify the number of objects suggested for replacing
* Simplify the number of behavior properties suggested for tweaking
* New section to update the in-game title
* Simplify publication at the end of the flow
2024-09-23 15:07:31 +02:00
AlexandreS
364ec2ecfb Fix crashes in Preview due to ill-formed color values (#6980)
- Make color parsing from string more robust (issues when setting colors in Sprite, BBText, Particle emitter and effects with colors)
- Allow use of hex strings and shorthand hex strings in color fields
- Remove UI glitch when switching effect type and both effects have parameters with identical names
2024-09-23 09:21:37 +02:00
D8H
0d36a27b87 Fix anchor behavior when the object has a custom origin (#6970) 2024-09-18 13:54:10 +02:00
D8H
6d597a430b Always show custom objects in the extension editor (#6974) 2024-09-18 13:21:04 +02:00
Clément Pasteau
27b71b08e5 Fix instance selection rectangle not being flipped properly (#6971) 2024-09-18 09:51:08 +02:00
AlexandreS
82158f7073 Fix DismissableTutorialMessage stories typing (#6972)
Do not show in changelog
2024-09-18 09:50:35 +02:00
AlexandreS
8ba352d4ba Fix min width on right container (#6969)
Don't show in changelog
2024-09-17 17:35:48 +02:00
D8H
6cda5d08be Fix missing flippingZ accessors (#6968)
- Don't show in changelog
2024-09-17 16:00:14 +02:00
D8H
1a3a27b73b Fix custom object flipping (#6967)
Do not show in changelog
2024-09-17 15:15:25 +02:00
918 changed files with 44913 additions and 21160 deletions

View File

@@ -176,6 +176,7 @@ jobs:
# Build the WebAssembly library only (so that it's cached on a S3 and easy to re-use).
build-gdevelop_js-wasm-only:
resource_class: medium+ # Compilation time decrease linearly with the number of CPUs, but not linking (so "large" does not speedup total build time).
docker:
- image: cimg/node:16.13
@@ -232,10 +233,83 @@ jobs:
name: Deploy to S3 (latest)
command: aws s3 sync Binaries/embuild/GDevelop.js s3://gdevelop-gdevelop.js/$(git rev-parse --abbrev-ref HEAD)/latest/
# Build the WebAssembly library with clang-tidy and memory sanitizers.
build-gdevelop_js-debug-sanitizers-and-extra-checks:
resource_class: xlarge # Total time decrease linearly with the number of CPUs.
docker:
- image: cimg/node:16.13
working_directory: ~/GDevelop
steps:
- checkout
- aws-cli/setup
# System dependencies (for Emscripten)
- run:
name: Install dependencies for Emscripten
command: sudo apt-get update && sudo apt install cmake
- run:
name: Install dependencies for clang-tidy v19
command: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 19 && sudo apt install clang-tidy-19
- run:
name: Install Python3 dependencies for Emscripten
command: sudo apt install python-is-python3 python3-distutils -y
- run:
name: Install Emscripten (for GDevelop.js)
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 3.1.21 && ./emsdk activate 3.1.21 && cd ..
# GDevelop.js dependencies
- restore_cache:
keys:
- gdevelop.js-linux-nodejs-dependencies-{{ checksum "GDevelop.js/package-lock.json" }}
# fallback to using the latest cache if no exact match is found
- gdevelop.js-linux-nodejs-dependencies-
- run:
name: Install GDevelop.js dependencies and build it
command: cd GDevelop.js && npm install && cd ..
# Build GDevelop.js
- run:
name: Build GDevelop.js ('debug-sanitizers' variant)
command: cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build -- --variant=debug-sanitizers
- run:
name: Run clang-tidy
command: cd GDevelop.js && npm run lint
- run:
name: Run tests
command: cd GDevelop.js && npm run test -- --maxWorkers=4
# Upload artifacts (CircleCI)
- store_artifacts:
path: Binaries/embuild/GDevelop.js
# Upload artifacts (AWS)
- run:
name: Deploy to S3 (specific commit)
command: aws s3 sync Binaries/embuild/GDevelop.js s3://gdevelop-gdevelop.js/$(git rev-parse --abbrev-ref HEAD)/variant/debug-sanitizers/commit/$(git rev-parse HEAD)/
workflows:
builds:
gdevelop_js-wasm:
jobs:
- build-gdevelop_js-wasm-only
gdevelop_js-wasm-extra-checks:
jobs:
- build-gdevelop_js-debug-sanitizers-and-extra-checks:
# Extra checks are resource intensive so don't all run them.
filters:
branches:
only:
- master
- /experimental-build.*/
builds:
jobs:
- build-macos:
filters:
branches:

4
.clang-tidy Normal file
View File

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

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

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

View File

@@ -69,12 +69,18 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# uninitialized variables or other hard to debug bugs.
add_compile_options(
-Wall
-Wextra
-Wuninitialized
-Wconditional-uninitialized
-Wno-unknown-warning-option
-Wno-reorder-ctor
-Wno-reorder
-Wno-unused-parameter
-Wno-pessimizing-move
-Wno-unused-variable
-Wno-unused-variable # Not a good style, but not a risk
-Wno-unused-private-field
-Wno-ignored-qualifiers # Not a risk
-Wno-sign-compare # Not a big risk
# Make as much warnings considered as errors as possible (only one for now).
-Werror=return-stack-address

View File

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

View File

@@ -14,10 +14,10 @@
namespace gd {
/**
* \brief
* \brief
*/
class GD_CORE_API ProjectDiagnostic {
public:
public:
enum ErrorType {
UndeclaredVariable,
MissingBehavior,
@@ -25,12 +25,17 @@ public:
MismatchedObjectType,
};
ProjectDiagnostic(ErrorType type_, const gd::String &message_,
ProjectDiagnostic(ErrorType type_,
const gd::String &message_,
const gd::String &actualValue_,
const gd::String &expectedValue_, const gd::String &objectName_ = "")
: type(type_), message(message_), actualValue(actualValue_), expectedValue(expectedValue_),
objectName(objectName_){};
virtual ~ProjectDiagnostic(){};
const gd::String &expectedValue_,
const gd::String &objectName_ = "")
: type(type_),
message(message_),
actualValue(actualValue_),
expectedValue(expectedValue_),
objectName(objectName_) {};
virtual ~ProjectDiagnostic() {};
ErrorType GetType() const { return type; };
const gd::String &GetMessage() const { return message; }
@@ -38,7 +43,7 @@ public:
const gd::String &GetActualValue() const { return actualValue; }
const gd::String &GetExpectedValue() const { return expectedValue; }
private:
private:
ErrorType type;
gd::String message;
gd::String objectName;
@@ -47,12 +52,12 @@ private:
};
/**
* \brief
* \brief
*/
class GD_CORE_API DiagnosticReport {
public:
DiagnosticReport(){};
virtual ~DiagnosticReport(){};
public:
DiagnosticReport() {};
virtual ~DiagnosticReport() {};
void Add(const gd::ProjectDiagnostic &projectDiagnostic) {
projectDiagnostics.push_back(
@@ -67,32 +72,39 @@ public:
const gd::String &GetSceneName() const { return sceneName; }
void SetSceneName(const gd::String &sceneName_) {
sceneName = sceneName_;
void SetSceneName(const gd::String &sceneName_) { sceneName = sceneName_; }
void LogAllDiagnostics() {
for (auto &diagnostic : projectDiagnostics) {
std::cout << diagnostic->GetMessage()
<< "(object: " << diagnostic->GetObjectName()
<< ", actual value: " << diagnostic->GetActualValue()
<< ", expected value: " << diagnostic->GetExpectedValue() << ")"
<< std::endl;
}
}
private:
private:
std::vector<std::unique_ptr<gd::ProjectDiagnostic>> projectDiagnostics;
gd::String sceneName;
};
/**
* \brief
* \brief
*/
class GD_CORE_API WholeProjectDiagnosticReport {
public:
WholeProjectDiagnosticReport(){};
virtual ~WholeProjectDiagnosticReport(){};
public:
WholeProjectDiagnosticReport() {};
virtual ~WholeProjectDiagnosticReport() {};
const DiagnosticReport &Get(std::size_t index) const {
return *diagnosticReports[index].get();
};
void Clear() {
diagnosticReports.clear();
};
void Clear() { diagnosticReports.clear(); };
DiagnosticReport& AddNewDiagnosticReportForScene(const gd::String &sceneName) {
DiagnosticReport &AddNewDiagnosticReportForScene(
const gd::String &sceneName) {
auto diagnosticReport = gd::make_unique<gd::DiagnosticReport>();
diagnosticReport->SetSceneName(sceneName);
diagnosticReports.push_back(std::move(diagnosticReport));
@@ -102,7 +114,7 @@ public:
std::size_t Count() const { return diagnosticReports.size(); };
bool HasAnyIssue() {
for (auto& diagnosticReport : diagnosticReports) {
for (auto &diagnosticReport : diagnosticReports) {
if (diagnosticReport->Count() > 0) {
return true;
}
@@ -110,8 +122,8 @@ public:
return false;
}
private:
private:
std::vector<std::unique_ptr<gd::DiagnosticReport>> diagnosticReports;
};
} // namespace gd
} // namespace gd

View File

@@ -345,14 +345,14 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::UnknownObject, "",
objectInParameter, "");
diagnosticReport->Add(projectDiagnostic);
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
return "/* Unknown object - skipped. */";
} else if (!expectedObjectType.empty() &&
actualObjectType != expectedObjectType) {
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::MismatchedObjectType, "",
actualObjectType, expectedObjectType, objectInParameter);
diagnosticReport->Add(projectDiagnostic);
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
return "/* Mismatched object type - skipped. */";
}
}
@@ -509,7 +509,7 @@ void EventsCodeGenerator::CheckBehaviorParameters(
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::MissingBehavior, "",
actualBehaviorType, expectedBehaviorType, lastObjectName);
diagnosticReport->Add(projectDiagnostic);
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
}
}
});
@@ -567,14 +567,14 @@ gd::String EventsCodeGenerator::GenerateActionCode(
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::UnknownObject, "",
objectInParameter, "");
diagnosticReport->Add(projectDiagnostic);
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
return "/* Unknown object - skipped. */";
} else if (!expectedObjectType.empty() &&
actualObjectType != expectedObjectType) {
gd::ProjectDiagnostic projectDiagnostic(
gd::ProjectDiagnostic::ErrorType::MismatchedObjectType, "",
actualObjectType, expectedObjectType, objectInParameter);
diagnosticReport->Add(projectDiagnostic);
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
return "/* Mismatched object type - skipped. */";
}
}

View File

@@ -36,8 +36,8 @@ struct GD_CORE_API ExpressionParserLocation {
private:
bool isValid;
size_t startPosition;
size_t endPosition;
size_t startPosition = 0;
size_t endPosition = 0;
};
/**

View File

@@ -1768,6 +1768,22 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression",
_("Angle of tolerance, in degrees (0: minimum tolerance)"))
.AddCodeOnlyParameter("conditionInverted", "")
.SetHidden()
.MarkAsAdvanced();
extension
.AddCondition("IsTurnedTowardObject",
_("An object is turned toward another"),
_("Check if an object is turned toward another"),
_("_PARAM0_ is turned toward _PARAM1_ ± _PARAM2_°"),
_("Angle"),
"res/conditions/estTourne24.png",
"res/conditions/estTourne.png")
.AddParameter("objectList", _("Name of the object"))
.AddParameter("objectList", _("Name of the second object"))
.AddParameter("expression",
_("Angle of tolerance, in degrees (0: minimum tolerance)"))
.AddCodeOnlyParameter("conditionInverted", "")
.MarkAsAdvanced();
extension

View File

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

View File

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

View File

@@ -47,19 +47,11 @@ void SpriteObject::DoSerializeTo(gd::SerializerElement& element) const {
std::map<gd::String, gd::PropertyDescriptor> SpriteObject::GetProperties()
const {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[_("Animate even if hidden or far from the screen")]
.SetValue(updateIfNotVisible ? "true" : "false")
.SetType("Boolean");
properties["PLEASE_ALSO_SHOW_EDIT_BUTTON_THANKS"].SetValue("");
return properties;
}
bool SpriteObject::UpdateProperty(const gd::String& name,
const gd::String& value) {
if (name == _("Animate even if hidden or far from the screen"))
updateIfNotVisible = value == "1";
return true;
}

View File

@@ -37,8 +37,7 @@ BehaviorMetadata::BehaviorMetadata(
className(className_),
iconFilename(icon24x24),
instance(instance_),
sharedDatasInstance(sharedDatasInstance_),
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {
sharedDatasInstance(sharedDatasInstance_) {
SetFullName(gd::String(fullname_));
SetDescription(gd::String(description_));
SetDefaultName(gd::String(defaultName_));

View File

@@ -307,6 +307,15 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
return *this;
}
BehaviorMetadata &SetOpenFullEditorLabel(const gd::String& label) {
openFullEditorLabel = label;
return *this;
}
const gd::String& GetOpenFullEditorLabel() const {
return openFullEditorLabel;
}
/**
* \brief Return the associated gd::Behavior, handling behavior contents.
*
@@ -384,7 +393,8 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
mutable std::vector<gd::String> requiredBehaviors;
bool isPrivate = false;
bool isHidden = false;
QuickCustomization::Visibility quickCustomizationVisibility;
gd::String openFullEditorLabel;
QuickCustomization::Visibility quickCustomizationVisibility = QuickCustomization::Visibility::Default;
// TODO: Nitpicking: convert these to std::unique_ptr to clarify ownership.
std::shared_ptr<gd::Behavior> instance;

View File

@@ -185,10 +185,10 @@ class GD_CORE_API EffectMetadata {
gd::String fullname;
gd::String description;
std::vector<gd::String> includeFiles;
bool isMarkedAsNotWorkingForObjects;
bool isMarkedAsOnlyWorkingFor2D;
bool isMarkedAsOnlyWorkingFor3D;
bool isMarkedAsUnique;
bool isMarkedAsNotWorkingForObjects = false;
bool isMarkedAsOnlyWorkingFor2D = false;
bool isMarkedAsOnlyWorkingFor3D = false;
bool isMarkedAsUnique = false;
std::map<gd::String, gd::PropertyDescriptor> properties;
};

View File

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

View File

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

View File

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

View File

@@ -54,7 +54,7 @@ ObjectMetadata::ObjectMetadata(const gd::String& extensionNamespace_,
[]() -> std::unique_ptr<gd::ObjectConfiguration> {
gd::LogFatalError(
"Error: Event-based objects don't have blueprint. "
"This method should not never be called.");
"This method should never be called.");
return nullptr;
}) {}

View File

@@ -246,6 +246,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; }
@@ -323,6 +328,15 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
*/
bool IsRenderedIn3D() const { return isRenderedIn3D; }
ObjectMetadata &SetOpenFullEditorLabel(const gd::String& label) {
openFullEditorLabel = label;
return *this;
}
const gd::String& GetOpenFullEditorLabel() const {
return openFullEditorLabel;
}
std::map<gd::String, gd::InstructionMetadata> conditionsInfos;
std::map<gd::String, gd::InstructionMetadata> actionsInfos;
std::map<gd::String, gd::ExpressionMetadata> expressionsInfos;
@@ -344,6 +358,7 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
std::set<gd::String> defaultBehaviorTypes;
bool hidden = false;
bool isRenderedIn3D = false;
gd::String openFullEditorLabel;
std::shared_ptr<gd::ObjectConfiguration>
blueprintObject; ///< The "blueprint" object to be copied when a new

View File

@@ -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,7 +23,10 @@ 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) {
@@ -31,34 +34,97 @@ void ParameterMetadataTools::ParametersToObjectsContainer(
if (parameter.GetName().empty()) continue;
if (gd::ParameterMetadata::IsObject(parameter.GetType())) {
outputObjectsContainer.InsertNewObject(
project,
parameter.GetExtraInfo(),
parameter.GetName(),
outputObjectsContainer.GetObjectsCount());
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();
lastObjectName = objectName;
} else if (gd::ParameterMetadata::IsBehavior(parameter.GetType())) {
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

@@ -53,27 +53,32 @@ const gd::String &ValueTypeMetadata::GetExpressionPrimitiveValueType(
const gd::String &
ValueTypeMetadata::GetPrimitiveValueType(const gd::String &parameterType) {
if (parameterType == "variable" ||
gd::ValueTypeMetadata::IsTypeExpression("variable", parameterType)) {
return ValueTypeMetadata::variableType;
if (parameterType == "number" ||
gd::ValueTypeMetadata::IsTypeValue("number", parameterType)) {
return ValueTypeMetadata::numberType;
}
if (parameterType == "boolean" || parameterType == "yesorno" ||
parameterType == "trueorfalse") {
return ValueTypeMetadata::booleanType;
}
// These 2 types are not strings from the code generator point of view,
// but it is for event-based extensions.
if (parameterType == "key" || parameterType == "mouse") {
if (parameterType == "string" ||
gd::ValueTypeMetadata::IsTypeValue("string", parameterType)) {
return ValueTypeMetadata::stringType;
}
return GetExpressionPrimitiveValueType(parameterType);
if (parameterType == "variable" ||
gd::ValueTypeMetadata::IsTypeValue("variable", parameterType)) {
return ValueTypeMetadata::variableType;
}
if (parameterType == "boolean" ||
gd::ValueTypeMetadata::IsTypeValue("boolean", parameterType)) {
return ValueTypeMetadata::booleanType;
}
return parameterType;
}
const gd::String ValueTypeMetadata::numberValueType = "number";
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::ConvertPropertyTypeToValueType(
const gd::String &propertyType) {
@@ -85,6 +90,10 @@ 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;
}
// For "String" or default
return stringValueType;

View File

@@ -111,21 +111,21 @@ class GD_CORE_API ValueTypeMetadata {
* given type.
*/
bool IsNumber() const {
return gd::ValueTypeMetadata::IsTypeExpression("number", name);
return gd::ValueTypeMetadata::IsTypeValue("number", name);
}
/**
* \brief Return true if the type is a string.
*/
bool IsString() const {
return gd::ValueTypeMetadata::IsTypeExpression("string", name);
return gd::ValueTypeMetadata::IsTypeValue("string", name);
}
/**
* \brief Return true if the type is a boolean.
*/
bool IsBoolean() const {
return gd::ValueTypeMetadata::IsTypeExpression("boolean", name);
return gd::ValueTypeMetadata::IsTypeValue("boolean", name);
}
/**
@@ -135,7 +135,17 @@ class GD_CORE_API ValueTypeMetadata {
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
*/
bool IsVariable() const {
return gd::ValueTypeMetadata::IsTypeExpression("variable", name);
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";
}
/**
@@ -175,7 +185,9 @@ class GD_CORE_API ValueTypeMetadata {
}
/**
* \brief Return true if the type is an expression of the given type.
* \brief Return true if the type is an expression of the given type from the
* caller point of view.
*
* \note If you are adding a new type of parameter, also add it in the IDE (
* see EventsFunctionParametersEditor, ParameterRenderingService
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
@@ -186,6 +198,7 @@ class GD_CORE_API ValueTypeMetadata {
return parameterType == "number" || parameterType == "expression" ||
parameterType == "camera" || parameterType == "forceMultiplier";
} else if (type == "string") {
// "key" and "mouse" are not mapped her, see GetPrimitiveValueType.
return parameterType == "string" || parameterType == "layer" ||
parameterType == "color" || parameterType == "file" ||
parameterType == "stringWithSelector" ||
@@ -227,6 +240,26 @@ class GD_CORE_API ValueTypeMetadata {
return false;
}
/**
* \brief Return true if the type is a value of the given primitive type from
* the function events point of view
*/
static bool IsTypeValue(const gd::String &type,
const gd::String &parameterType) {
if (gd::ValueTypeMetadata::IsTypeExpression(type, parameterType)) {
return true;
}
// These 2 parameter types are not strings from the outside of a function as
// the generator add quote around a text, but from the events inside of the
// function the parameter is a string.
//
// See EventsCodeGenerator::GenerateParameterCodes
if (type == "string") {
return parameterType == "key" || parameterType == "mouse";
}
return false;
}
/**
* \brief Return the expression type from the parameter type.
* Declinations of "number" and "string" types (like "forceMultiplier" or
@@ -278,9 +311,11 @@ 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;
};
} // namespace gd

View File

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

View File

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

View File

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

View File

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

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

View File

@@ -67,7 +67,7 @@ public:
* \brief Do nothing.
*/
void ExposeObjects(gd::Project &project,
gd::ArbitraryObjectsWorker &worker) const override;
gd::ArbitraryObjectsWorker &worker) const override {};
/**
* \brief Call the specified worker on the event-based behavior.
@@ -80,7 +80,7 @@ public:
* \brief Do nothing.
*/
void ExposeBehaviorSharedDatas(gd::Project &project,
gd::ArbitraryBehaviorSharedDataWorker &worker) const override;
gd::ArbitraryBehaviorSharedDataWorker &worker) const override {};
private:
const gd::EventsFunctionsExtension &eventsFunctionsExtension;

View File

@@ -0,0 +1,37 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "EventBasedObjectBrowser.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Project/ArbitraryEventBasedBehaviorsWorker.h"
#include "GDCore/IDE/Project/ArbitraryEventsFunctionsWorker.h"
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/IDE/Project/ArbitraryBehaviorSharedDataWorker.h"
#include "GDCore/IDE/ProjectBrowserHelper.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
namespace gd {
void EventBasedObjectBrowser::ExposeEvents(
gd::Project &project, gd::ArbitraryEventsWorker &worker) const {
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
project, eventsBasedObject, worker);
}
void EventBasedObjectBrowser::ExposeEvents(
gd::Project &project, gd::ArbitraryEventsWorkerWithContext &worker) const {
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
project, eventsFunctionsExtension, eventsBasedObject, worker);
}
void EventBasedObjectBrowser::ExposeFunctions(
gd::Project &project, gd::ArbitraryEventsFunctionsWorker &worker) const {
worker.Launch(eventsBasedObject.GetEventsFunctions());
}
} // namespace gd

View File

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

View File

@@ -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.IsVariable();
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().IsVariable(),
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().IsVariable(), 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.IsVariable();
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().IsVariable(),
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().IsVariable(), 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

@@ -337,19 +337,19 @@ struct GD_CORE_API ExpressionCompletionDescription {
private:
CompletionKind completionKind;
gd::Variable::Type variableType;
gd::VariablesContainer::SourceType variableScope;
gd::Variable::Type variableType = gd::Variable::Unknown;
gd::VariablesContainer::SourceType variableScope = gd::VariablesContainer::Unknown;
gd::String type;
gd::String prefix;
gd::String completion;
size_t replacementStartPosition;
size_t replacementEndPosition;
size_t replacementStartPosition = 0;
size_t replacementEndPosition = 0;
gd::String objectName;
gd::String behaviorName;
bool isExact;
bool isLastParameter;
const gd::ParameterMetadata* parameterMetadata;
const gd::ObjectConfiguration* objectConfiguration;
bool isExact = false;
bool isLastParameter = false;
const gd::ParameterMetadata* parameterMetadata = &badParameterMetadata;
const gd::ObjectConfiguration* objectConfiguration = &badObjectConfiguration;
static const gd::ParameterMetadata badParameterMetadata;
static const gd::ObjectConfiguration badObjectConfiguration;
@@ -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(),
@@ -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

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

View File

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

View File

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

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;
@@ -42,10 +43,12 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
const gd::String &extraInfo_ = "")
: platform(platform_),
projectScopedContainers(projectScopedContainers_),
parentType(StringToType(gd::ParameterMetadata::GetExpressionValueType(rootType_))),
parentType(StringToType(gd::ValueTypeMetadata::GetExpressionPrimitiveValueType(rootType_))),
childType(Type::Unknown),
forbidsUsageOfBracketsBecauseParentIsObject(false),
currentParameterExtraInfo(&extraInfo_) {};
currentParameterExtraInfo(&extraInfo_),
variableObjectName(),
variableObjectNameLocation() {};
virtual ~ExpressionValidator(){};
/**
@@ -225,7 +228,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 +268,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 +287,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. "
@@ -369,6 +380,11 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, LegacyVariable, Object, Empty};
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") {
@@ -505,6 +521,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

@@ -74,8 +74,8 @@ class GD_CORE_API ExpressionsParameterMover
const gd::Platform &platform;
gd::String functionName;
std::size_t oldIndex;
std::size_t newIndex;
std::size_t oldIndex = 0;
std::size_t newIndex = 0;
gd::String behaviorType;
gd::String objectType;
};

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

@@ -24,15 +24,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,26 +98,6 @@ 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());
}
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());
}
}
} // namespace gd

View File

@@ -68,9 +68,5 @@ class GD_CORE_API EventsFunctionTools {
const gd::EventsBasedObject& eventsBasedObject,
const gd::EventsFunction& eventsFunction,
gd::ObjectsContainer& outputObjectsContainer);
static void CopyEventsBasedObjectChildrenToObjectsContainer(
const gd::EventsBasedObject &eventsBasedObject,
gd::ObjectsContainer &outputObjectsContainer);
};
} // namespace gd

View File

@@ -4,6 +4,7 @@
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Extensions/Platform.h"
namespace gd {

View File

@@ -293,7 +293,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

@@ -170,7 +170,8 @@ void ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
gd::ArbitraryEventsWorkerWithContext &worker) {
// Add (free) events functions
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
gd::ObjectsContainer parameterObjectsContainer;
gd::ObjectsContainer parameterObjectsContainer(
gd::ObjectsContainer::SourceType::Function);
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForFreeEventsFunction(
project, eventsFunctionsExtension, *eventsFunction,
@@ -209,7 +210,8 @@ void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
auto &behaviorEventsFunctions = eventsBasedBehavior.GetEventsFunctions();
for (auto &&eventsFunction : behaviorEventsFunctions.GetInternalVector()) {
gd::ObjectsContainer parameterObjectsContainers;
gd::ObjectsContainer parameterObjectsContainers(
gd::ObjectsContainer::SourceType::Function);
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForBehaviorEventsFunction(
project, eventsFunctionsExtension, eventsBasedBehavior,
@@ -236,7 +238,8 @@ void ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
auto &objectEventsFunctions = eventsBasedObject.GetEventsFunctions();
for (auto &&eventsFunction : objectEventsFunctions.GetInternalVector()) {
gd::ObjectsContainer parameterObjectsContainers;
gd::ObjectsContainer parameterObjectsContainers(
gd::ObjectsContainer::SourceType::Function);
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForObjectEventsFunction(
project, eventsFunctionsExtension, eventsBasedObject,

View File

@@ -247,7 +247,7 @@ bool PropertyFunctionGenerator::CanGenerateGetterAndSetter(
const gd::NamedPropertyDescriptor &property) {
auto &type = property.GetType();
if (type != "Boolean" && type != "Number" && type != "String" &&
type != "Choice" && type != "Color") {
type != "Choice" && type != "Color" && type != "LeaderboardId") {
return false;
}

View File

@@ -6,17 +6,9 @@
#include "ResourceExposer.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/EventsFunctionTools.h"
#include "GDCore/IDE/Project/ArbitraryBehaviorSharedDataWorker.h"
#include "GDCore/IDE/Project/ArbitraryEventBasedBehaviorsWorker.h"
#include "GDCore/IDE/Project/ArbitraryEventsFunctionsWorker.h"
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/IDE/ProjectBrowserHelper.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/Effect.h"
@@ -24,7 +16,6 @@
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
#include "GDCore/IDE/Events/UsedExtensionsFinder.h"
namespace gd {

View File

@@ -13,11 +13,13 @@
#include "GDCore/IDE/DependenciesAnalyzer.h"
#include "GDCore/IDE/GroupVariableHelper.h"
#include "GDCore/IDE/EventBasedBehaviorBrowser.h"
#include "GDCore/IDE/EventBasedObjectBrowser.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Events/BehaviorParametersFiller.h"
#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"
@@ -27,12 +29,8 @@
#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/EventsFunctionTools.h"
#include "GDCore/IDE/Project/ArbitraryBehaviorSharedDataWorker.h"
#include "GDCore/IDE/Project/ArbitraryEventBasedBehaviorsWorker.h"
#include "GDCore/IDE/Project/ArbitraryEventsFunctionsWorker.h"
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/IDE/Project/BehaviorObjectTypeRenamer.h"
#include "GDCore/IDE/Project/BehaviorsSharedDataBehaviorTypeRenamer.h"
#include "GDCore/IDE/Project/FunctionParameterBehaviorTypeRenamer.h"
@@ -415,20 +413,32 @@ void WholeProjectRefactorer::UpdateExtensionNameInEventsBasedBehavior(
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::String &sourceExtensionName) {
const EventBasedBehaviorBrowser eventBasedBehaviorExposer(
const EventBasedBehaviorBrowser eventBasedBehaviorBrowser(
eventsFunctionsExtension, eventsBasedBehavior);
WholeProjectRefactorer::RenameEventsFunctionsExtension(
project, eventsFunctionsExtension, sourceExtensionName,
eventsFunctionsExtension.GetName(), eventBasedBehaviorExposer);
eventsFunctionsExtension.GetName(), eventBasedBehaviorBrowser);
}
void WholeProjectRefactorer::UpdateExtensionNameInEventsBasedObject(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedObject &eventsBasedObject,
const gd::String &sourceExtensionName) {
const EventBasedObjectBrowser eventBasedObjectBrowser(
eventsFunctionsExtension, eventsBasedObject);
WholeProjectRefactorer::RenameEventsFunctionsExtension(
project, eventsFunctionsExtension, sourceExtensionName,
eventsFunctionsExtension.GetName(), eventBasedObjectBrowser);
}
void WholeProjectRefactorer::RenameEventsFunctionsExtension(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::String &oldName, const gd::String &newName) {
const WholeProjectBrowser wholeProjectExposer;
const WholeProjectBrowser wholeProjectBrowser;
RenameEventsFunctionsExtension(project, eventsFunctionsExtension, oldName,
newName, wholeProjectExposer);
newName, wholeProjectBrowser);
}
void WholeProjectRefactorer::RenameEventsFunctionsExtension(
@@ -807,6 +817,51 @@ 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::MoveEventsFunctionParameter(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
@@ -941,6 +996,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(
@@ -950,14 +1007,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,
@@ -1012,6 +1071,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(
@@ -1021,14 +1082,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,
@@ -1069,6 +1132,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(
@@ -1078,14 +1143,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,
@@ -1312,6 +1379,19 @@ bool WholeProjectRefactorer::FixInvalidRequiredBehaviorProperties(
return !invalidRequiredBehaviorProblems.empty();
}
void WholeProjectRefactorer::UpdateBehaviorNameInEventsBasedBehavior(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::String &sourceBehaviorName) {
const EventBasedBehaviorBrowser eventBasedBehaviorExposer(
eventsFunctionsExtension, eventsBasedBehavior);
WholeProjectRefactorer::RenameEventsBasedBehavior(
project, eventsFunctionsExtension, eventsBasedBehavior,
sourceBehaviorName, eventsBasedBehavior.GetName(),
eventBasedBehaviorExposer);
}
void WholeProjectRefactorer::RenameEventsBasedBehavior(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
@@ -1324,10 +1404,22 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
return;
}
auto &eventsBasedBehavior = eventsBasedBehaviors.Get(oldBehaviorName);
const WholeProjectBrowser projectBrowser;
WholeProjectRefactorer::RenameEventsBasedBehavior(
project, eventsFunctionsExtension, eventsBasedBehavior, oldBehaviorName,
newBehaviorName, projectBrowser);
}
void WholeProjectRefactorer::RenameEventsBasedBehavior(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::String &oldBehaviorName,
const gd::String &newBehaviorName,
const gd::ProjectBrowser &projectBrowser) {
auto renameBehaviorEventsFunction =
[&project, &eventsFunctionsExtension, &oldBehaviorName,
&newBehaviorName](const gd::EventsFunction &eventsFunction) {
&newBehaviorName, &projectBrowser](const gd::EventsFunction &eventsFunction) {
if (eventsFunction.IsExpression()) {
// Nothing to do, expressions are not including the name of the
// behavior
@@ -1341,12 +1433,12 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(), newBehaviorName,
eventsFunction.GetName()));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, renamer);
projectBrowser.ExposeEvents(project, renamer);
}
};
auto renameBehaviorProperty = [&project, &eventsFunctionsExtension,
&oldBehaviorName, &newBehaviorName](
&oldBehaviorName, &newBehaviorName, &projectBrowser](
const gd::NamedPropertyDescriptor
&property) {
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
@@ -1357,7 +1449,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(), newBehaviorName,
EventsBasedBehavior::GetPropertyActionName(property.GetName())));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer);
projectBrowser.ExposeEvents(project, actionRenamer);
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -1367,7 +1459,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(), newBehaviorName,
EventsBasedBehavior::GetPropertyConditionName(property.GetName())));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, conditionRenamer);
projectBrowser.ExposeEvents(project, conditionRenamer);
// Nothing to do for expression, expressions are not including the name of
// the behavior
@@ -1375,7 +1467,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
auto renameBehaviorSharedProperty =
[&project, &eventsFunctionsExtension, &oldBehaviorName,
&newBehaviorName](const gd::NamedPropertyDescriptor &property) {
&newBehaviorName, &projectBrowser](const gd::NamedPropertyDescriptor &property) {
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
@@ -1386,7 +1478,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
eventsFunctionsExtension.GetName(), newBehaviorName,
EventsBasedBehavior::GetSharedPropertyActionName(
property.GetName())));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer);
projectBrowser.ExposeEvents(project, actionRenamer);
gd::InstructionsTypeRenamer conditionRenamer =
gd::InstructionsTypeRenamer(
@@ -1399,8 +1491,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
eventsFunctionsExtension.GetName(), newBehaviorName,
EventsBasedBehavior::GetSharedPropertyConditionName(
property.GetName())));
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
conditionRenamer);
projectBrowser.ExposeEvents(project, conditionRenamer);
// Nothing to do for expression, expressions are not including the name
// of the behavior
@@ -1435,13 +1526,25 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
renameBehaviorSharedProperty(*property);
}
const WholeProjectBrowser wholeProjectExposer;
DoRenameBehavior(project,
gd::PlatformExtension::GetBehaviorFullType(
eventsFunctionsExtension.GetName(), oldBehaviorName),
gd::PlatformExtension::GetBehaviorFullType(
eventsFunctionsExtension.GetName(), newBehaviorName),
wholeProjectExposer);
projectBrowser);
}
void WholeProjectRefactorer::UpdateObjectNameInEventsBasedObject(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedObject &eventsBasedObject,
const gd::String &sourceObjectName) {
const EventBasedObjectBrowser eventBasedObjectBrowser(
eventsFunctionsExtension, eventsBasedObject);
WholeProjectRefactorer::RenameEventsBasedObject(
project, eventsFunctionsExtension, eventsBasedObject,
sourceObjectName, eventsBasedObject.GetName(),
eventBasedObjectBrowser);
}
void WholeProjectRefactorer::RenameEventsBasedObject(
@@ -1455,10 +1558,21 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
return;
}
auto &eventsBasedObject = eventsBasedObjects.Get(oldObjectName);
const WholeProjectBrowser projectBrowser;
WholeProjectRefactorer::RenameEventsBasedObject(
project, eventsFunctionsExtension, eventsBasedObject, oldObjectName,
newObjectName, projectBrowser);
}
void WholeProjectRefactorer::RenameEventsBasedObject(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedObject &eventsBasedObject,
const gd::String &oldObjectName, const gd::String &newObjectName,
const gd::ProjectBrowser &projectBrowser) {
auto renameObjectEventsFunction =
[&project, &eventsFunctionsExtension, &oldObjectName,
&newObjectName](const gd::EventsFunction &eventsFunction) {
[&project, &eventsFunctionsExtension, &oldObjectName, &newObjectName,
&projectBrowser](const gd::EventsFunction &eventsFunction) {
if (eventsFunction.IsExpression()) {
// Nothing to do, expressions are not including the name of the
// object
@@ -1472,12 +1586,12 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(), newObjectName,
eventsFunction.GetName()));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, renamer);
projectBrowser.ExposeEvents(project, renamer);
}
};
auto renameObjectProperty = [&project, &eventsFunctionsExtension,
&oldObjectName, &newObjectName](
&oldObjectName, &newObjectName, &projectBrowser](
const gd::NamedPropertyDescriptor &property) {
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -1487,7 +1601,7 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(), newObjectName,
EventsBasedObject::GetPropertyActionName(property.GetName())));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer);
projectBrowser.ExposeEvents(project, actionRenamer);
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -1497,7 +1611,7 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(), newObjectName,
EventsBasedObject::GetPropertyConditionName(property.GetName())));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, conditionRenamer);
projectBrowser.ExposeEvents(project, conditionRenamer);
// Nothing to do for expression, expressions are not including the name of
// the object
@@ -1528,13 +1642,12 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
renameObjectProperty(*property);
}
const WholeProjectBrowser wholeProjectExposer;
DoRenameObject(project,
gd::PlatformExtension::GetObjectFullType(
eventsFunctionsExtension.GetName(), oldObjectName),
gd::PlatformExtension::GetObjectFullType(
eventsFunctionsExtension.GetName(), newObjectName),
wholeProjectExposer);
projectBrowser);
}
void WholeProjectRefactorer::DoRenameEventsFunction(
@@ -1638,6 +1751,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;
@@ -1647,7 +1769,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) {
@@ -1664,7 +1786,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
@@ -1910,8 +2032,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
@@ -1928,11 +2050,12 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
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) {
@@ -1958,7 +2081,7 @@ void WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
if (layout.GetObjects().HasObjectNamed(oldName))
continue;
ObjectOrGroupRenamedInScene(project, layout, oldName, newName,
ObjectOrGroupRenamedInScene(project, layout, project.GetObjects(), oldName, newName,
isObjectGroup);
}
}
@@ -2090,4 +2213,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

@@ -27,14 +27,7 @@ class ObjectsContainer;
class VariablesContainer;
class EventsBasedBehavior;
class EventsBasedObject;
class ArbitraryEventsWorker;
class ArbitraryObjectsWorker;
class ArbitraryEventsFunctionsWorker;
class ArbitraryEventsWorkerWithContext;
class ArbitraryEventBasedBehaviorsWorker;
class ArbitraryBehaviorSharedDataWorker;
class Behavior;
class BehaviorMetadata;
class UnfilledRequiredBehaviorPropertyProblem;
class ProjectBrowser;
class SerializerElement;
@@ -121,14 +114,24 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& newName);
/**
* \brief Refactor behavior events after the extension was placed in a new
* \brief Refactor behavior events after the behavior has been placed in a new
* extension.
*/
static void UpdateExtensionNameInEventsBasedBehavior(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
gd::EventsBasedBehavior& eventsBasedBehavior,
const gd::String& sourceExtensionName);
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::String &sourceExtensionName);
/**
* \brief Refactor object events after the object has been placed in a new
* extension.
*/
static void UpdateExtensionNameInEventsBasedObject(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedObject &eventsBasedObject,
const gd::String &sourceExtensionName);
/**
* \brief Refactor the project **before** an events function is renamed.
@@ -173,6 +176,21 @@ 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 project **before** an events function parameter
* is moved.
@@ -324,6 +342,16 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& oldBehaviorName,
const gd::String& newBehaviorName);
/**
* \brief Refactor events-based behavior events after the events-based
* behavior has been duplicated.
*/
static void UpdateBehaviorNameInEventsBasedBehavior(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::String &sourceBehaviorName);
/**
* \brief Refactor the project **before** an object is renamed.
*
@@ -337,6 +365,16 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& oldObjectName,
const gd::String& newObjectName);
/**
* \brief Refactor events-based object events after the events-based object
* has been duplicated.
*/
static void UpdateObjectNameInEventsBasedObject(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
gd::EventsBasedObject &eventsBasedObject,
const gd::String &sourceObjectName);
/**
* \brief Refactor the project after a layout is renamed.
*/
@@ -506,6 +544,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);
@@ -604,6 +643,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.
@@ -614,6 +665,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>
@@ -654,6 +711,35 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& newName,
const gd::ProjectBrowser& projectBrowser);
/**
* \brief Refactor the project **before** a behavior is renamed.
*
* \warning Do the renaming of the specified behavior after calling this.
* This is because the behavior is expected to have its old name for the
* refactoring.
*/
static void RenameEventsBasedBehavior(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::String &oldBehaviorName,
const gd::String &newBehaviorName,
const gd::ProjectBrowser &projectBrowser);
/**
* \brief Refactor the project **before** an object is renamed.
*
* \warning Do the renaming of the specified object after calling this.
* This is because the object is expected to have its old name for the
* refactoring.
*/
static void RenameEventsBasedObject(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedObject &eventsBasedObject,
const gd::String &oldObjectName, const gd::String &newObjectName,
const gd::ProjectBrowser &projectBrowser);
static void FindDependentBehaviorNames(
const gd::Project& project,
const gd::Object& object,

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,13 +3,14 @@
* 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>
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Project/QuickCustomization.h"
#include "GDCore/Project/QuickCustomizationVisibilitiesContainer.h"
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/String.h"
namespace gd {
@@ -17,6 +18,7 @@ class PropertyDescriptor;
class SerializerElement;
class Project;
class Layout;
class ArbitraryResourceWorker;
} // namespace gd
namespace gd {
@@ -32,12 +34,21 @@ namespace gd {
*/
class GD_CORE_API BehaviorConfigurationContainer {
public:
BehaviorConfigurationContainer() : folded(false), quickCustomizationVisibility(QuickCustomization::Visibility::Default){};
BehaviorConfigurationContainer()
: folded(false),
quickCustomizationVisibility(QuickCustomization::Visibility::Default),
propertiesQuickCustomizationVisibilities() {};
BehaviorConfigurationContainer(const gd::String& name_,
const gd::String& type_)
: name(name_), type(type_), folded(false), quickCustomizationVisibility(QuickCustomization::Visibility::Default){};
: name(name_),
type(type_),
folded(false),
quickCustomizationVisibility(QuickCustomization::Visibility::Default),
propertiesQuickCustomizationVisibilities() {};
virtual ~BehaviorConfigurationContainer();
virtual BehaviorConfigurationContainer* Clone() const { return new BehaviorConfigurationContainer(*this); }
virtual BehaviorConfigurationContainer* Clone() const {
return new BehaviorConfigurationContainer(*this);
}
/**
* \brief Return the name identifying the behavior
@@ -68,7 +79,6 @@ class GD_CORE_API BehaviorConfigurationContainer {
*/
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
/**
* \brief Called when the IDE wants to update a custom property of the
* behavior
@@ -84,9 +94,7 @@ class GD_CORE_API BehaviorConfigurationContainer {
* \brief Called to initialize the content with the default properties
* for the behavior.
*/
virtual void InitializeContent() {
InitializeContent(content);
};
virtual void InitializeContent() { InitializeContent(content); };
/**
* \brief Serialize the behavior content.
@@ -115,15 +123,54 @@ class GD_CORE_API BehaviorConfigurationContainer {
*/
bool IsFolded() const { return folded; }
void SetQuickCustomizationVisibility(QuickCustomization::Visibility visibility) {
/**
* @brief Set if the whole behavior should be visible or not in the Quick
* Customization.
*/
void SetQuickCustomizationVisibility(
QuickCustomization::Visibility visibility) {
quickCustomizationVisibility = visibility;
}
/**
* @brief Get if the whole behavior should be visible or not in the Quick
* Customization.
*/
QuickCustomization::Visibility GetQuickCustomizationVisibility() const {
return quickCustomizationVisibility;
}
protected:
/**
* @brief Get the map of properties and their visibility in the Quick
* Customization.
*/
QuickCustomizationVisibilitiesContainer&
GetPropertiesQuickCustomizationVisibilities() {
return propertiesQuickCustomizationVisibilities;
}
/**
* @brief Get the map of properties and their visibility in the Quick
* Customization.
*/
const QuickCustomizationVisibilitiesContainer&
GetPropertiesQuickCustomizationVisibilities() const {
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
* behavior.
@@ -159,7 +206,7 @@ protected:
* \brief Called to initialize the content with the default properties
* for the behavior.
*/
virtual void InitializeContent(gd::SerializerElement& behaviorContent){};
virtual void InitializeContent(gd::SerializerElement& behaviorContent) {};
private:
gd::String name; ///< Name of the behavior
@@ -169,8 +216,8 @@ protected:
gd::SerializerElement content; // Storage for the behavior properties
bool folded;
QuickCustomization::Visibility quickCustomizationVisibility;
QuickCustomizationVisibilitiesContainer
propertiesQuickCustomizationVisibilities;
};
} // namespace gd
#endif // GDCORE_BEHAVIORCONFIGURATIONCONTAINER_H

View File

@@ -26,7 +26,7 @@ void CustomConfigurationHelper::InitializeContent(
if (propertyType == "String" || propertyType == "Choice" ||
propertyType == "Color" || propertyType == "Behavior" ||
propertyType == "Resource") {
propertyType == "Resource" || propertyType == "LeaderboardId") {
element.SetStringValue(property->GetValue());
} else if (propertyType == "Number") {
element.SetDoubleValue(property->GetValue().To<double>());
@@ -53,7 +53,7 @@ std::map<gd::String, gd::PropertyDescriptor> CustomConfigurationHelper::GetPrope
if (configurationContent.HasChild(propertyName)) {
if (propertyType == "String" || propertyType == "Choice" ||
propertyType == "Color" || propertyType == "Behavior" ||
propertyType == "Resource") {
propertyType == "Resource" || propertyType == "LeaderboardId") {
newProperty.SetValue(
configurationContent.GetChild(propertyName).GetStringValue());
} else if (propertyType == "Number") {
@@ -89,7 +89,7 @@ bool CustomConfigurationHelper::UpdateProperty(
if (propertyType == "String" || propertyType == "Choice" ||
propertyType == "Color" || propertyType == "Behavior" ||
propertyType == "Resource") {
propertyType == "Resource" || propertyType == "LeaderboardId") {
element.SetStringValue(newValue);
} else if (propertyType == "Number") {
element.SetDoubleValue(newValue.To<double>());

View File

@@ -72,7 +72,7 @@ gd::ObjectConfiguration &CustomObjectConfiguration::GetChildObjectConfiguration(
}
if (!eventsBasedObject->GetObjects().HasObjectNamed(objectName)) {
gd::LogError("Tried to get the configuration of a child-object:" + objectName
gd::LogError("Tried to get the configuration of a child-object: " + objectName
+ " that doesn't exist in the event-based object: " + GetType());
return badObjectConfiguration;
}
@@ -158,7 +158,9 @@ 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);
}
@@ -202,8 +204,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();

View File

@@ -9,6 +9,7 @@
#include <map>
#include <memory>
#include <unordered_set>
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/EventsBasedObject.h"
@@ -109,6 +110,27 @@ class CustomObjectConfiguration : public gd::ObjectConfiguration {
static const gd::CustomObjectConfiguration::EdgeAnchor
GetEdgeAnchorFromString(const gd::String &value);
/**
* Check if a child object properties must be displayed as folded in the editor.
* This is only useful when the object can override its children configuration (which
* is something being deprecated).
*/
bool IsChildObjectFolded(const gd::String& childName) const {
return unfoldedChildren.find(childName) == unfoldedChildren.end();
}
/**
* Set if a child object properties must be displayed as folded in the editor.
* This is only useful when the object can override its children configuration (which
* is something being deprecated).
*/
void SetChildObjectFolded(const gd::String& childName, bool folded) {
if (!folded)
unfoldedChildren.insert(childName);
else
unfoldedChildren.erase(childName);
}
protected:
void DoSerializeTo(SerializerElement& element) const override;
void DoUnserializeFrom(Project& project, const SerializerElement& element) override;
@@ -118,11 +140,12 @@ protected:
bool IsOverridingEventsBasedObjectChildrenConfiguration() const;
const Project* project; ///< The project is used to get the
///< EventBasedObject from the fullType.
const Project* project = nullptr; ///< The project is used to get the
///< EventBasedObject from the fullType.
gd::SerializerElement objectContent;
bool isMarkedAsOverridingEventsBasedObjectChildrenConfiguration;
std::unordered_set<gd::String> unfoldedChildren;
bool isMarkedAsOverridingEventsBasedObjectChildrenConfiguration = false;
mutable std::map<gd::String, std::unique_ptr<gd::ObjectConfiguration>> childObjectConfigurations;
static gd::ObjectConfiguration badObjectConfiguration;

View File

@@ -12,6 +12,7 @@ namespace gd {
void Effect::SerializeTo(SerializerElement& element) const {
element.SetAttribute("name", GetName());
element.SetAttribute("effectType", GetEffectType());
if (IsFolded()) element.SetBoolAttribute("folded", true);
SerializerElement& doubleParametersElement =
element.AddChild("doubleParameters");
@@ -41,6 +42,7 @@ void Effect::UnserializeFrom(const SerializerElement& element) {
"effectName"
// end of compatibility code
));
SetFolded(element.GetBoolAttribute("folded", false));
doubleParameters.clear();
const SerializerElement& doubleParametersElement =

View File

@@ -23,7 +23,8 @@ EventsBasedObject::EventsBasedObject()
areaMinZ(0),
areaMaxX(64),
areaMaxY(64),
areaMaxZ(64) {
areaMaxZ(64),
objectsContainer(gd::ObjectsContainer::SourceType::Object) {
}
EventsBasedObject::~EventsBasedObject() {}
@@ -90,7 +91,7 @@ void EventsBasedObject::UnserializeFrom(gd::Project& project,
}
initialInstances.UnserializeFrom(element.GetChild("instances"));
if (element.HasAttribute("isUsingLegacyInstancesRenderer")) {
if (element.HasChild("isUsingLegacyInstancesRenderer")) {
isUsingLegacyInstancesRenderer =
element.GetBoolAttribute("isUsingLegacyInstancesRenderer", false);
}

View File

@@ -10,6 +10,7 @@
#include "EventsFunction.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/MakeUnique.h"
#include "GDCore/Extensions/PlatformExtension.h"
namespace gd {
@@ -98,8 +99,11 @@ void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
void EventsFunctionsExtension::UnserializeFrom(
gd::Project& project, const SerializerElement& element) {
UnserializeExtensionDeclarationFrom(project, element);
UnserializeExtensionImplementationFrom(project, element);
// Unserialize first the "declaration" (everything but objects content)
// so that objects can be then unserialized in proper order (they can depend
// on each others)
UnserializeExtensionDeclarationFrom(project, element);
UnserializeExtensionImplementationFrom(project, element);
}
void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
@@ -162,6 +166,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) {
@@ -169,6 +174,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,11 +191,93 @@ void EventsFunctionsExtension::UnserializeExtensionImplementationFrom(
eventsBasedBehaviors.UnserializeElementsFrom(
"eventsBasedBehavior", project, element.GetChild("eventsBasedBehaviors"));
// It's important to load the objects without erasing them first as each object
// might reference other objects, and so need to know if a custom object exists
// in the project or not.
eventsBasedObjects.ProgressivelyUnserializeElementsFrom(
"eventsBasedObject", project, element.GetChild("eventsBasedObjects"));
auto &eventsBasedObjectsElement = element.GetChild("eventsBasedObjects");
eventsBasedObjectsElement.ConsiderAsArrayOf("eventsBasedObject");
for (gd::String &eventsBasedObjectName :
GetUnserializingOrderEventsBasedObjectNames(eventsBasedObjectsElement)) {
size_t extensionIndex = eventsBasedObjects.GetPosition(
eventsBasedObjects.Get(eventsBasedObjectName));
const SerializerElement &eventsBasedObjectElement =
eventsBasedObjectsElement.GetChild(extensionIndex);
eventsBasedObjects.at(extensionIndex)
.UnserializeFrom(project, eventsBasedObjectElement);
}
}
std::vector<gd::String>
EventsFunctionsExtension::GetUnserializingOrderEventsBasedObjectNames(
const gd::SerializerElement &eventsBasedObjectsElement) {
// Child-objects need the event-based objects they use to be loaded completely
// before they are unserialized.
// At the beginning, everything is yet to be loaded.
std::vector<gd::String> remainingEventsBasedObjectNames(
eventsBasedObjects.size());
for (std::size_t i = 0; i < eventsBasedObjects.size(); ++i) {
remainingEventsBasedObjectNames[i] = eventsBasedObjects.at(i).GetName();
}
// Helper allowing to find if an object depends on at least one other object from
// the extension that is not loaded yet.
auto &extensionName = name;
auto isDependentFromRemainingEventsBasedObjects =
[&remainingEventsBasedObjectNames,
&extensionName](const gd::SerializerElement &eventsBasedObjectElement) {
auto &objectsElement = eventsBasedObjectElement.GetChild("objects");
objectsElement.ConsiderAsArrayOf("object");
for (std::size_t objectIndex = 0;
objectIndex < objectsElement.GetChildrenCount(); ++objectIndex) {
const gd::String &objectType =
objectsElement.GetChild(objectIndex).GetStringAttribute("type");
gd::String usedExtensionName =
PlatformExtension::GetExtensionFromFullObjectType(objectType);
if (usedExtensionName != extensionName) {
// The object comes from another extension: the project is already responsible
// for loading extensions in the proper order.
continue;
}
gd::String eventsBasedObjectName =
gd::PlatformExtension::GetObjectNameFromFullObjectType(
objectType);
if (std::find(remainingEventsBasedObjectNames.begin(),
remainingEventsBasedObjectNames.end(),
eventsBasedObjectName) !=
remainingEventsBasedObjectNames.end()) {
return true;
}
}
return false;
};
// Find the order of loading so that the objects are loaded when all the objects
// they depend on are already loaded.
std::vector<gd::String> loadOrderEventsBasedObjectNames;
bool foundAnyEventsBasedObject = true;
while (foundAnyEventsBasedObject) {
foundAnyEventsBasedObject = false;
for (std::size_t i = 0; i < remainingEventsBasedObjectNames.size(); ++i) {
auto eventsBasedObjectName = remainingEventsBasedObjectNames[i];
size_t extensionIndex = eventsBasedObjects.GetPosition(
eventsBasedObjects.Get(eventsBasedObjectName));
const SerializerElement &eventsBasedObjectElement =
eventsBasedObjectsElement.GetChild(extensionIndex);
if (!isDependentFromRemainingEventsBasedObjects(
eventsBasedObjectElement)) {
loadOrderEventsBasedObjectNames.push_back(eventsBasedObjectName);
remainingEventsBasedObjectNames.erase(
remainingEventsBasedObjectNames.begin() + i);
i--;
foundAnyEventsBasedObject = true;
}
}
}
return loadOrderEventsBasedObjectNames;
}
bool EventsFunctionsExtension::IsExtensionLifecycleEventsFunction(

View File

@@ -314,6 +314,9 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
return dependency;
}
std::vector<gd::String> GetUnserializingOrderEventsBasedObjectNames(
const gd::SerializerElement &eventsBasedObjectsElement);
gd::String version;
gd::String extensionNamespace;
gd::String shortDescription;

View File

@@ -7,7 +7,7 @@
namespace gd {
ExternalEvents::ExternalEvents() : lastChangeTimeStamp(0) {
ExternalEvents::ExternalEvents() {
// ctor
}
@@ -24,14 +24,12 @@ ExternalEvents& ExternalEvents::operator=(const ExternalEvents& rhs) {
void ExternalEvents::Init(const ExternalEvents& externalEvents) {
name = externalEvents.GetName();
associatedScene = externalEvents.GetAssociatedLayout();
lastChangeTimeStamp = externalEvents.GetLastChangeTimeStamp();
events = externalEvents.events;
}
void ExternalEvents::SerializeTo(SerializerElement& element) const {
element.SetAttribute("name", name);
element.SetAttribute("associatedLayout", associatedScene);
element.SetAttribute("lastChangeTimeStamp", (int)lastChangeTimeStamp);
gd::EventsListSerialization::SerializeEventsTo(events,
element.AddChild("events"));
}
@@ -41,8 +39,6 @@ void ExternalEvents::UnserializeFrom(gd::Project& project,
name = element.GetStringAttribute("name", "", "Name");
associatedScene =
element.GetStringAttribute("associatedLayout", "", "AssociatedScene");
lastChangeTimeStamp =
element.GetIntAttribute("lastChangeTimeStamp", 0, "LastChangeTimeStamp");
gd::EventsListSerialization::UnserializeEventsFrom(
project, events, element.GetChild("events", 0, "Events"));
}

View File

@@ -67,24 +67,6 @@ class GD_CORE_API ExternalEvents {
associatedScene = name_;
};
/**
* Get the latest time of the build.
* Used when the IDE found that the external events can be compiled separately
* from scene's events.
*
* \todo This is specific to GD C++ Platform
*/
time_t GetLastChangeTimeStamp() const { return lastChangeTimeStamp; };
/**
* Change the latest time of the build of the external events.
*
* \todo This is specific to GD C++ Platform
*/
void SetLastChangeTimeStamp(time_t newTimeStamp) {
lastChangeTimeStamp = newTimeStamp;
};
/**
* \brief Get the events.
*/
@@ -109,7 +91,6 @@ class GD_CORE_API ExternalEvents {
private:
gd::String name;
gd::String associatedScene;
time_t lastChangeTimeStamp; ///< Time of the last build
gd::EventsList events; ///< List of events
/**
@@ -119,19 +100,6 @@ class GD_CORE_API ExternalEvents {
void Init(const ExternalEvents& externalEvents);
};
/**
* \brief Functor testing ExternalEvents' name
*/
struct ExternalEventsHasName
: public std::binary_function<std::unique_ptr<gd::ExternalEvents>,
gd::String,
bool> {
bool operator()(const std::unique_ptr<gd::ExternalEvents>& externalEvents,
gd::String name) const {
return externalEvents->GetName() == name;
}
};
} // namespace gd
#endif // GDCORE_EXTERNALEVENTS_H

View File

@@ -163,6 +163,20 @@ bool InitialInstancesContainer::HasInstancesOfObject(
});
}
bool InitialInstancesContainer::IsInstancesCountOfObjectGreaterThan(
const gd::String &objectName, const std::size_t minInstanceCount) const {
std::size_t count = 0;
for (const gd::InitialInstance &instance : initialInstances) {
if (instance.GetObjectName() == objectName) {
count++;
if (count > minInstanceCount) {
return true;
}
}
}
return false;
}
void InitialInstancesContainer::Create(
const InitialInstancesContainer& source) {
try {

View File

@@ -153,6 +153,13 @@ class GD_CORE_API InitialInstancesContainer {
*/
bool HasInstancesOfObject(const gd::String &objectName) const;
/**
* \brief Return true if there is at least N instances of the given object.
*/
bool
IsInstancesCountOfObjectGreaterThan(const gd::String &objectName,
const std::size_t minInstanceCount) const;
/**
* \brief Remove all instances
*/

View File

@@ -15,6 +15,7 @@ Camera Layer::badCamera;
Layer::Layer()
: renderingType(""),
defaultCameraBehavior("top-left-anchored-if-never-moved"),
isVisible(true),
isLocked(false),
isLightingLayer(false),
@@ -40,6 +41,9 @@ void Layer::SerializeTo(SerializerElement& element) const {
element.SetAttribute("name", GetName());
element.SetAttribute("renderingType", GetRenderingType());
element.SetAttribute("cameraType", GetCameraType());
if (GetDefaultCameraBehavior() != "top-left-anchored-if-never-moved") {
element.SetAttribute("defaultCameraBehavior", GetDefaultCameraBehavior());
}
element.SetAttribute("visibility", GetVisibility());
element.SetAttribute("isLocked", IsLocked());
element.SetAttribute("isLightingLayer", IsLightingLayer());
@@ -80,6 +84,7 @@ void Layer::UnserializeFrom(const SerializerElement& element) {
SetName(element.GetStringAttribute("name", "", "Name"));
SetRenderingType(element.GetStringAttribute("renderingType", ""));
SetCameraType(element.GetStringAttribute("cameraType", "perspective"));
SetDefaultCameraBehavior(element.GetStringAttribute("defaultCameraBehavior", "top-left-anchored-if-never-moved"));
SetVisibility(element.GetBoolAttribute("visibility", true, "Visibility"));
SetLocked(element.GetBoolAttribute("isLocked", false));
SetLightingLayer(element.GetBoolAttribute("isLightingLayer", false));

View File

@@ -109,6 +109,12 @@ class GD_CORE_API Layer {
renderingType = renderingType_;
}
const gd::String& GetDefaultCameraBehavior() const { return defaultCameraBehavior; }
void SetDefaultCameraBehavior(const gd::String& defaultCameraBehavior_) {
defaultCameraBehavior = defaultCameraBehavior_;
}
const gd::String& GetCameraType() const { return cameraType; }
void SetCameraType(const gd::String& cameraType_) {
@@ -275,6 +281,7 @@ class GD_CORE_API Layer {
gd::String name; ///< The name of the layer
gd::String renderingType; ///< The rendering type: "" (empty), "2d", "3d" or
///< "2d+3d".
gd::String defaultCameraBehavior;
gd::String cameraType;
bool isVisible; ///< True if the layer is visible
bool isLocked; ///< True if the layer is locked

View File

@@ -24,10 +24,11 @@
#include "GDCore/Project/ObjectGroup.h"
#include "GDCore/Project/ObjectGroupsContainer.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/QuickCustomization.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
#include "GDCore/Tools/PolymorphicClone.h"
#include "GDCore/Tools/Log.h"
#include "GDCore/Tools/PolymorphicClone.h"
using namespace std;
@@ -35,7 +36,10 @@ namespace gd {
gd::BehaviorsSharedData Layout::badBehaviorSharedData("", "");
Layout::Layout(const Layout& other) { Init(other); }
Layout::Layout(const Layout &other)
: objectsContainer(gd::ObjectsContainer::SourceType::Scene) {
Init(other);
}
Layout& Layout::operator=(const Layout& other) {
if (this != &other) Init(other);
@@ -43,7 +47,7 @@ Layout& Layout::operator=(const Layout& other) {
return *this;
}
Layout::~Layout(){};
Layout::~Layout() {};
Layout::Layout()
: backgroundColorR(209),
@@ -52,9 +56,8 @@ Layout::Layout()
stopSoundsOnStartup(true),
standardSortMethod(true),
disableInputWhenNotFocused(true),
variables(gd::VariablesContainer::SourceType::Scene)
{
}
variables(gd::VariablesContainer::SourceType::Scene),
objectsContainer(gd::ObjectsContainer::SourceType::Scene) {}
void Layout::SetName(const gd::String& name_) {
name = name_;
@@ -102,7 +105,9 @@ const gd::Layer& Layout::GetLayer(const gd::String& name) const {
return layers.GetLayer(name);
}
gd::Layer& Layout::GetLayer(std::size_t index) { return layers.GetLayer(index); }
gd::Layer& Layout::GetLayer(std::size_t index) {
return layers.GetLayer(index);
}
const gd::Layer& Layout::GetLayer(std::size_t index) const {
return layers.GetLayer(index);
@@ -125,9 +130,7 @@ void Layout::InsertLayer(const gd::Layer& layer, std::size_t position) {
layers.InsertLayer(layer, position);
}
void Layout::RemoveLayer(const gd::String& name) {
layers.RemoveLayer(name);
}
void Layout::RemoveLayer(const gd::String& name) { layers.RemoveLayer(name); }
void Layout::SwapLayers(std::size_t firstLayerIndex,
std::size_t secondLayerIndex) {
@@ -153,7 +156,7 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
allBehaviorsNames.push_back(behavior.GetName());
}
}
auto &globalObjects = project.GetObjects();
auto& globalObjects = project.GetObjects();
for (std::size_t i = 0; i < globalObjects.GetObjectsCount(); ++i) {
std::vector<gd::String> objectBehaviors =
globalObjects.GetObject(i).GetAllBehaviorNames();
@@ -173,7 +176,8 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
if (behaviorsSharedData.find(name) != behaviorsSharedData.end()) continue;
auto sharedData = CreateBehaviorsSharedData(project, name, allBehaviorsTypes[i]);
auto sharedData =
CreateBehaviorsSharedData(project, name, allBehaviorsTypes[i]);
if (sharedData) {
behaviorsSharedData[name] = std::move(sharedData);
}
@@ -196,37 +200,39 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
}
std::unique_ptr<gd::BehaviorsSharedData> Layout::CreateBehaviorsSharedData(
gd::Project& project, const gd::String& name, const gd::String& behaviorsType) {
if (project.HasEventsBasedBehavior(behaviorsType)) {
auto sharedData =
gd::make_unique<gd::CustomBehaviorsSharedData>(name, project, behaviorsType);
sharedData->InitializeContent();
return std::move(sharedData);
}
const gd::BehaviorMetadata& behaviorMetadata =
gd::MetadataProvider::GetBehaviorMetadata(
project.GetCurrentPlatform(),
behaviorsType);
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
gd::LogWarning("Tried to create a behavior shared data with an unknown type: " +
behaviorsType + " on object " + GetName() + "!");
gd::Project& project,
const gd::String& name,
const gd::String& behaviorsType) {
if (project.HasEventsBasedBehavior(behaviorsType)) {
auto sharedData = gd::make_unique<gd::CustomBehaviorsSharedData>(
name, project, behaviorsType);
sharedData->InitializeContent();
return std::move(sharedData);
}
const gd::BehaviorMetadata& behaviorMetadata =
gd::MetadataProvider::GetBehaviorMetadata(project.GetCurrentPlatform(),
behaviorsType);
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
gd::LogWarning(
"Tried to create a behavior shared data with an unknown type: " +
behaviorsType + " on object " + GetName() + "!");
// It's probably an events-based behavior that was removed.
// Create a custom behavior shared data to preserve the properties values.
auto sharedData =
gd::make_unique<gd::CustomBehaviorsSharedData>(name, project, behaviorsType);
sharedData->InitializeContent();
return std::move(sharedData);
}
gd::BehaviorsSharedData* behaviorsSharedDataBluePrint =
behaviorMetadata.GetSharedDataInstance();
if (!behaviorsSharedDataBluePrint) return nullptr;
auto sharedData = behaviorsSharedDataBluePrint->Clone();
sharedData->SetName(name);
sharedData->SetTypeName(behaviorsType);
auto sharedData = gd::make_unique<gd::CustomBehaviorsSharedData>(
name, project, behaviorsType);
sharedData->InitializeContent();
return std::unique_ptr<gd::BehaviorsSharedData>(sharedData);
return std::move(sharedData);
}
gd::BehaviorsSharedData* behaviorsSharedDataBluePrint =
behaviorMetadata.GetSharedDataInstance();
if (!behaviorsSharedDataBluePrint) return nullptr;
auto sharedData = behaviorsSharedDataBluePrint->Clone();
sharedData->SetName(name);
sharedData->SetTypeName(behaviorsType);
sharedData->InitializeContent();
return std::unique_ptr<gd::BehaviorsSharedData>(sharedData);
}
void Layout::SerializeTo(SerializerElement& element) const {
@@ -243,11 +249,13 @@ void Layout::SerializeTo(SerializerElement& element) const {
editorSettings.SerializeTo(element.AddChild("uiSettings"));
objectsContainer.GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
objectsContainer.GetObjectGroups().SerializeTo(
element.AddChild("objectsGroups"));
GetVariables().SerializeTo(element.AddChild("variables"));
GetInitialInstances().SerializeTo(element.AddChild("instances"));
objectsContainer.SerializeObjectsTo(element.AddChild("objects"));
objectsContainer.SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
objectsContainer.SerializeFoldersTo(
element.AddChild("objectsFolderStructure"));
gd::EventsListSerialization::SerializeEventsTo(events,
element.AddChild("events"));
@@ -257,15 +265,33 @@ void Layout::SerializeTo(SerializerElement& element) const {
element.AddChild("behaviorsSharedData");
behaviorDatasElement.ConsiderAsArrayOf("behaviorSharedData");
for (const auto& it : behaviorsSharedData) {
const gd::BehaviorsSharedData& sharedData = *it.second;
SerializerElement& dataElement =
behaviorDatasElement.AddChild("behaviorSharedData");
it.second->SerializeTo(dataElement);
sharedData.SerializeTo(dataElement);
dataElement.RemoveChild("type"); // The content can contain type or name
// properties, remove them.
dataElement.RemoveChild("name");
dataElement.SetAttribute("type", it.second->GetTypeName());
dataElement.SetAttribute("name", it.second->GetName());
dataElement.SetAttribute("type", sharedData.GetTypeName());
dataElement.SetAttribute("name", sharedData.GetName());
// Handle Quick Customization info.
dataElement.RemoveChild("propertiesQuickCustomizationVisibilities");
const QuickCustomizationVisibilitiesContainer&
propertiesQuickCustomizationVisibilities =
sharedData.GetPropertiesQuickCustomizationVisibilities();
if (!propertiesQuickCustomizationVisibilities.IsEmpty()) {
propertiesQuickCustomizationVisibilities.SerializeTo(
dataElement.AddChild("propertiesQuickCustomizationVisibilities"));
}
const QuickCustomization::Visibility visibility =
sharedData.GetQuickCustomizationVisibility();
if (visibility != QuickCustomization::Visibility::Default) {
dataElement.SetAttribute(
"quickCustomizationVisibility",
QuickCustomization::VisibilityAsString(visibility));
}
}
}
@@ -289,9 +315,11 @@ void Layout::UnserializeFrom(gd::Project& project,
gd::EventsListSerialization::UnserializeEventsFrom(
project, GetEvents(), element.GetChild("events", 0, "Events"));
objectsContainer.UnserializeObjectsFrom(project, element.GetChild("objects", 0, "Objets"));
objectsContainer.UnserializeObjectsFrom(
project, element.GetChild("objects", 0, "Objets"));
if (element.HasChild("objectsFolderStructure")) {
objectsContainer.UnserializeFoldersFrom(project, element.GetChild("objectsFolderStructure", 0));
objectsContainer.UnserializeFoldersFrom(
project, element.GetChild("objectsFolderStructure", 0));
}
objectsContainer.AddMissingObjectsInRootFolder();
@@ -321,7 +349,6 @@ void Layout::UnserializeFrom(gd::Project& project,
"Behavior"); // Compatibility with GD <= 4
gd::String name = sharedDataElement.GetStringAttribute("name", "", "Name");
auto sharedData = CreateBehaviorsSharedData(project, name, type);
if (sharedData) {
// Compatibility with GD <= 4.0.98
@@ -336,6 +363,21 @@ void Layout::UnserializeFrom(gd::Project& project,
else {
sharedData->UnserializeFrom(sharedDataElement);
}
// Handle Quick Customization info.
if (sharedDataElement.HasChild(
"propertiesQuickCustomizationVisibilities")) {
sharedData->GetPropertiesQuickCustomizationVisibilities()
.UnserializeFrom(sharedDataElement.GetChild(
"propertiesQuickCustomizationVisibilities"));
}
if (sharedDataElement.HasChild("quickCustomizationVisibility")) {
sharedData->SetQuickCustomizationVisibility(
QuickCustomization::StringAsVisibility(
sharedDataElement.GetStringAttribute(
"quickCustomizationVisibility")));
}
behaviorsSharedData[name] = std::move(sharedData);
}
}
@@ -390,8 +432,9 @@ gd::String GD_CORE_API GetTypeOfObject(const gd::ObjectsContainer& project,
type = project.GetObject(name).GetType();
// Search in groups.
// Currently, a group is considered as the "intersection" of all of its objects.
// Search "groups is the intersection of its objects" in the codebase.
// Currently, a group is considered as the "intersection" of all of its
// objects. Search "groups is the intersection of its objects" in the
// codebase.
else if (searchInGroups) {
for (std::size_t i = 0; i < layout.GetObjectGroups().size(); ++i) {
if (layout.GetObjectGroups()[i].GetName() == name) {
@@ -448,11 +491,12 @@ gd::String GD_CORE_API GetTypeOfObject(const gd::ObjectsContainer& project,
return type;
}
void GD_CORE_API FilterBehaviorNamesFromObject(
const gd::Object &object, const gd::String &behaviorType,
std::vector<gd::String> &behaviorNames) {
void GD_CORE_API
FilterBehaviorNamesFromObject(const gd::Object& object,
const gd::String& behaviorType,
std::vector<gd::String>& behaviorNames) {
for (size_t i = 0; i < behaviorNames.size();) {
auto &behaviorName = behaviorNames[i];
auto& behaviorName = behaviorNames[i];
if (!object.HasBehaviorNamed(behaviorName) ||
object.GetBehavior(behaviorName).GetTypeName() != behaviorType) {
behaviorNames.erase(behaviorNames.begin() + i);
@@ -462,19 +506,21 @@ void GD_CORE_API FilterBehaviorNamesFromObject(
}
}
std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
const gd::ObjectsContainer &project, const gd::ObjectsContainer &layout,
const gd::String &objectOrGroupName, const gd::String &behaviorType,
bool searchInGroups) {
std::vector<gd::String> GD_CORE_API
GetBehaviorNamesInObjectOrGroup(const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
const gd::String& objectOrGroupName,
const gd::String& behaviorType,
bool searchInGroups) {
// Search in objects.
if (layout.HasObjectNamed(objectOrGroupName)) {
auto &object = layout.GetObject(objectOrGroupName);
auto& object = layout.GetObject(objectOrGroupName);
auto behaviorNames = object.GetAllBehaviorNames();
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
return behaviorNames;
}
if (project.HasObjectNamed(objectOrGroupName)) {
auto &object = project.GetObject(objectOrGroupName);
auto& object = project.GetObject(objectOrGroupName);
auto behaviorNames = object.GetAllBehaviorNames();
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
return behaviorNames;
@@ -486,9 +532,10 @@ std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
}
// Search in groups.
// Currently, a group is considered as the "intersection" of all of its objects.
// Search "groups is the intersection of its objects" in the codebase.
const gd::ObjectsContainer *container;
// Currently, a group is considered as the "intersection" of all of its
// objects. Search "groups is the intersection of its objects" in the
// codebase.
const gd::ObjectsContainer* container;
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
container = &layout;
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
@@ -497,7 +544,7 @@ std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
std::vector<gd::String> behaviorNames;
return behaviorNames;
}
const vector<gd::String> &groupsObjects =
const vector<gd::String>& groupsObjects =
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
// Empty groups don't contain any behavior.
@@ -510,15 +557,15 @@ std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
auto behaviorNames = GetBehaviorNamesInObjectOrGroup(
project, layout, groupsObjects[0], behaviorType, false);
for (size_t i = 1; i < groupsObjects.size(); i++) {
auto &objectName = groupsObjects[i];
auto& objectName = groupsObjects[i];
if (layout.HasObjectNamed(objectName)) {
auto &object = layout.GetObject(objectName);
auto& object = layout.GetObject(objectName);
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
return behaviorNames;
}
if (project.HasObjectNamed(objectName)) {
auto &object = project.GetObject(objectName);
auto& object = project.GetObject(objectName);
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
return behaviorNames;
}
@@ -529,10 +576,10 @@ std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
return behaviorNames;
}
bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
const gd::ObjectsContainer &layout,
const gd::String &objectOrGroupName,
const gd::String &behaviorName,
bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
const gd::String& objectOrGroupName,
const gd::String& behaviorName,
bool searchInGroups) {
// Search in objects.
if (layout.HasObjectNamed(objectOrGroupName)) {
@@ -547,9 +594,10 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
}
// Search in groups.
// Currently, a group is considered as the "intersection" of all of its objects.
// Search "groups is the intersection of its objects" in the codebase.
const gd::ObjectsContainer *container;
// Currently, a group is considered as the "intersection" of all of its
// objects. Search "groups is the intersection of its objects" in the
// codebase.
const gd::ObjectsContainer* container;
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
container = &layout;
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
@@ -557,7 +605,7 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
} else {
return false;
}
const vector<gd::String> &groupsObjects =
const vector<gd::String>& groupsObjects =
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
// Empty groups don't contain any behavior.
@@ -566,9 +614,9 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
}
// Check that all objects have the behavior.
for (auto &&object : groupsObjects) {
if (!HasBehaviorInObjectOrGroup(project, layout, object, behaviorName,
false)) {
for (auto&& object : groupsObjects) {
if (!HasBehaviorInObjectOrGroup(
project, layout, object, behaviorName, false)) {
return false;
}
}
@@ -576,18 +624,18 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
}
bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::String objectOrGroupName,
gd::String behaviorName,
bool searchInGroups) {
const gd::ObjectsContainer& layout,
gd::String objectOrGroupName,
gd::String behaviorName,
bool searchInGroups) {
// Search in objects.
if (layout.HasObjectNamed(objectOrGroupName)) {
auto &object = layout.GetObject(objectOrGroupName);
auto& object = layout.GetObject(objectOrGroupName);
return object.HasBehaviorNamed(behaviorName) &&
object.GetBehavior(behaviorName).IsDefaultBehavior();
}
if (project.HasObjectNamed(objectOrGroupName)) {
auto &object = project.GetObject(objectOrGroupName);
auto& object = project.GetObject(objectOrGroupName);
return object.HasBehaviorNamed(behaviorName) &&
object.GetBehavior(behaviorName).IsDefaultBehavior();
}
@@ -597,9 +645,10 @@ bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
}
// Search in groups.
// Currently, a group is considered as the "intersection" of all of its objects.
// Search "groups is the intersection of its objects" in the codebase.
const gd::ObjectsContainer *container;
// Currently, a group is considered as the "intersection" of all of its
// objects. Search "groups is the intersection of its objects" in the
// codebase.
const gd::ObjectsContainer* container;
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
container = &layout;
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
@@ -607,7 +656,7 @@ bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
} else {
return false;
}
const vector<gd::String> &groupsObjects =
const vector<gd::String>& groupsObjects =
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
// Empty groups don't contain any behavior.
@@ -616,30 +665,32 @@ bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
}
// Check that all objects have the same type.
for (auto &&object : groupsObjects) {
if (!IsDefaultBehavior(project, layout, object, behaviorName,
false)) {
for (auto&& object : groupsObjects) {
if (!IsDefaultBehavior(project, layout, object, behaviorName, false)) {
return false;
}
}
return true;
}
gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
const gd::String& objectOrGroupName,
const gd::String& behaviorName,
bool searchInGroups) {
gd::String GD_CORE_API
GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
const gd::String& objectOrGroupName,
const gd::String& behaviorName,
bool searchInGroups) {
// Search in objects.
if (layout.HasObjectNamed(objectOrGroupName)) {
auto &object = layout.GetObject(objectOrGroupName);
return object.HasBehaviorNamed(behaviorName) ?
object.GetBehavior(behaviorName).GetTypeName() : "";
auto& object = layout.GetObject(objectOrGroupName);
return object.HasBehaviorNamed(behaviorName)
? object.GetBehavior(behaviorName).GetTypeName()
: "";
}
if (project.HasObjectNamed(objectOrGroupName)) {
auto &object = project.GetObject(objectOrGroupName);
return object.HasBehaviorNamed(behaviorName) ?
object.GetBehavior(behaviorName).GetTypeName() : "";
auto& object = project.GetObject(objectOrGroupName);
return object.HasBehaviorNamed(behaviorName)
? object.GetBehavior(behaviorName).GetTypeName()
: "";
}
if (!searchInGroups) {
@@ -647,9 +698,10 @@ gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContain
}
// Search in groups.
// Currently, a group is considered as the "intersection" of all of its objects.
// Search "groups is the intersection of its objects" in the codebase.
const gd::ObjectsContainer *container;
// Currently, a group is considered as the "intersection" of all of its
// objects. Search "groups is the intersection of its objects" in the
// codebase.
const gd::ObjectsContainer* container;
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
container = &layout;
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
@@ -657,7 +709,7 @@ gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContain
} else {
return "";
}
const vector<gd::String> &groupsObjects =
const vector<gd::String>& groupsObjects =
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
// Empty groups don't contain any behavior.
@@ -668,9 +720,9 @@ gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContain
// Check that all objects have the behavior with the same type.
auto behaviorType = GetTypeOfBehaviorInObjectOrGroup(
project, layout, groupsObjects[0], behaviorName, false);
for (auto &&object : groupsObjects) {
if (GetTypeOfBehaviorInObjectOrGroup(project, layout, object, behaviorName,
false) != behaviorType) {
for (auto&& object : groupsObjects) {
if (GetTypeOfBehaviorInObjectOrGroup(
project, layout, object, behaviorName, false) != behaviorType) {
return "";
}
}
@@ -682,14 +734,14 @@ gd::String GD_CORE_API GetTypeOfBehavior(const gd::ObjectsContainer& project,
gd::String name,
bool searchInGroups) {
for (std::size_t i = 0; i < layout.GetObjectsCount(); ++i) {
const auto &object = layout.GetObject(i);
const auto& object = layout.GetObject(i);
if (object.HasBehaviorNamed(name)) {
return object.GetBehavior(name).GetTypeName();
}
}
for (std::size_t i = 0; i < project.GetObjectsCount(); ++i) {
const auto &object = project.GetObject(i);
const auto& object = project.GetObject(i);
if (object.HasBehaviorNamed(name)) {
return object.GetBehavior(name).GetTypeName();
}
@@ -726,8 +778,9 @@ GetBehaviorsOfObject(const gd::ObjectsContainer& project,
}
// Search in groups
// Currently, a group is considered as the "intersection" of all of its objects.
// Search "groups is the intersection of its objects" in the codebase.
// Currently, a group is considered as the "intersection" of all of its
// objects. Search "groups is the intersection of its objects" in the
// codebase.
if (searchInGroups) {
for (std::size_t i = 0; i < layout.GetObjectGroups().size(); ++i) {
if (layout.GetObjectGroups()[i].GetName() == name) {

View File

@@ -369,9 +369,9 @@ class GD_CORE_API Layout {
private:
gd::String name; ///< Scene name
gd::String mangledName; ///< The scene name mangled by SceneNameMangler
unsigned int backgroundColorR; ///< Background color Red component
unsigned int backgroundColorG; ///< Background color Green component
unsigned int backgroundColorB; ///< Background color Blue component
unsigned int backgroundColorR = 0; ///< Background color Red component
unsigned int backgroundColorG = 0; ///< Background color Green component
unsigned int backgroundColorB = 0; ///< Background color Blue component
gd::String title; ///< Title displayed in the window
gd::VariablesContainer variables; ///< Variables list
gd::ObjectsContainer objectsContainer;
@@ -379,12 +379,12 @@ class GD_CORE_API Layout {
gd::LayersContainer layers;
std::map<gd::String, std::unique_ptr<gd::BehaviorsSharedData>>
behaviorsSharedData; ///< Initial shared datas of behaviors
bool stopSoundsOnStartup; ///< True to make the scene stop all sounds at
///< startup.
bool standardSortMethod; ///< True to sort objects using standard sort.
bool disableInputWhenNotFocused; /// If set to true, the input must be
/// disabled when the window do not have the
/// focus.
bool stopSoundsOnStartup = true; ///< True to make the scene stop all sounds at
///< startup.
bool standardSortMethod = true; ///< True to sort objects using standard sort.
bool disableInputWhenNotFocused = true; /// If set to true, the input must be
/// disabled when the window do not have the
/// focus.
static gd::BehaviorsSharedData
badBehaviorSharedData; ///< Null object, returned when
///< GetBehaviorSharedData can not find the

View File

@@ -12,8 +12,9 @@
#include "GDCore/Project/CustomBehavior.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Project/QuickCustomization.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/Log.h"
#include "GDCore/Tools/UUID/UUID.h"
@@ -27,8 +28,8 @@ Object::Object(const gd::String& name_,
: name(name_),
configuration(std::move(configuration_)),
objectVariables(gd::VariablesContainer::SourceType::Object) {
SetType(type_);
}
SetType(type_);
}
Object::Object(const gd::String& name_,
const gd::String& type_,
@@ -36,8 +37,8 @@ Object::Object(const gd::String& name_,
: name(name_),
configuration(configuration_),
objectVariables(gd::VariablesContainer::SourceType::Object) {
SetType(type_);
}
SetType(type_);
}
void Object::Init(const gd::Object& object) {
persistentUuid = object.persistentUuid;
@@ -54,9 +55,7 @@ void Object::Init(const gd::Object& object) {
configuration = object.configuration->Clone();
}
gd::ObjectConfiguration& Object::GetConfiguration() {
return *configuration;
}
gd::ObjectConfiguration& Object::GetConfiguration() { return *configuration; }
const gd::ObjectConfiguration& Object::GetConfiguration() const {
return *configuration;
@@ -77,8 +76,7 @@ bool Object::RenameBehavior(const gd::String& name, const gd::String& newName) {
behaviors.find(newName) != behaviors.end())
return false;
std::unique_ptr<Behavior> aut =
std::move(behaviors.find(name)->second);
std::unique_ptr<Behavior> aut = std::move(behaviors.find(name)->second);
behaviors.erase(name);
behaviors[newName] = std::move(aut);
behaviors[newName]->SetName(newName);
@@ -99,10 +97,10 @@ bool Object::HasBehaviorNamed(const gd::String& name) const {
}
gd::Behavior* Object::AddNewBehavior(const gd::Project& project,
const gd::String& type,
const gd::String& name) {
auto initializeAndAdd =
[this, &name](std::unique_ptr<gd::Behavior> behavior) {
const gd::String& type,
const gd::String& name) {
auto initializeAndAdd = [this,
&name](std::unique_ptr<gd::Behavior> behavior) {
behavior->InitializeContent();
this->behaviors[name] = std::move(behavior);
return this->behaviors[name].get();
@@ -111,18 +109,17 @@ gd::Behavior* Object::AddNewBehavior(const gd::Project& project,
if (project.HasEventsBasedBehavior(type)) {
return initializeAndAdd(
gd::make_unique<CustomBehavior>(name, project, type));
}
else {
} else {
const gd::BehaviorMetadata& behaviorMetadata =
gd::MetadataProvider::GetBehaviorMetadata(project.GetCurrentPlatform(),
type);
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
gd::LogWarning("Tried to create a behavior with an unknown type: " + type
+ " on object " + GetName() + "!");
// It's probably an events-based behavior that was removed.
// Create a custom behavior to preserve the properties values.
return initializeAndAdd(
gd::make_unique<CustomBehavior>(name, project, type));
gd::LogWarning("Tried to create a behavior with an unknown type: " +
type + " on object " + GetName() + "!");
// It's probably an events-based behavior that was removed.
// Create a custom behavior to preserve the properties values.
return initializeAndAdd(
gd::make_unique<CustomBehavior>(name, project, type));
}
std::unique_ptr<gd::Behavior> behavior(behaviorMetadata.Get().Clone());
behavior->SetName(name);
@@ -196,6 +193,23 @@ void Object::UnserializeFrom(gd::Project& project,
else {
behavior->UnserializeFrom(behaviorElement);
}
bool isFolded = behaviorElement.GetBoolAttribute("isFolded", false);
behavior->SetFolded(isFolded);
// Handle Quick Customization info.
if (behaviorElement.HasChild(
"propertiesQuickCustomizationVisibilities")) {
behavior->GetPropertiesQuickCustomizationVisibilities().UnserializeFrom(
behaviorElement.GetChild(
"propertiesQuickCustomizationVisibilities"));
}
if (behaviorElement.HasChild("quickCustomizationVisibility")) {
behavior->SetQuickCustomizationVisibility(
QuickCustomization::StringAsVisibility(
behaviorElement.GetStringAttribute(
"quickCustomizationVisibility")));
}
}
}
@@ -217,8 +231,8 @@ void Object::SerializeTo(SerializerElement& element) const {
std::vector<gd::String> allBehaviors = GetAllBehaviorNames();
for (std::size_t i = 0; i < allBehaviors.size(); ++i) {
const gd::Behavior& behavior = GetBehavior(allBehaviors[i]);
// Default behaviors are added at the object creation according to metadata.
// They don't need to be serialized.
// Default behaviors are added at the object creation according to
// metadata. They don't need to be serialized.
if (behavior.IsDefaultBehavior()) {
continue;
}
@@ -228,8 +242,27 @@ void Object::SerializeTo(SerializerElement& element) const {
behaviorElement.RemoveChild("type"); // The content can contain type or
// name properties, remove them.
behaviorElement.RemoveChild("name");
behaviorElement.RemoveChild("isFolded");
behaviorElement.SetAttribute("type", behavior.GetTypeName());
behaviorElement.SetAttribute("name", behavior.GetName());
if (behavior.IsFolded()) behaviorElement.SetAttribute("isFolded", true);
// Handle Quick Customization info.
behaviorElement.RemoveChild("propertiesQuickCustomizationVisibilities");
const QuickCustomizationVisibilitiesContainer&
propertiesQuickCustomizationVisibilities =
behavior.GetPropertiesQuickCustomizationVisibilities();
if (!propertiesQuickCustomizationVisibilities.IsEmpty()) {
propertiesQuickCustomizationVisibilities.SerializeTo(
behaviorElement.AddChild("propertiesQuickCustomizationVisibilities"));
}
const QuickCustomization::Visibility visibility =
behavior.GetQuickCustomizationVisibility();
if (visibility != QuickCustomization::Visibility::Default) {
behaviorElement.SetAttribute(
"quickCustomizationVisibility",
QuickCustomization::VisibilityAsString(visibility));
}
}
configuration->SerializeTo(element);

View File

@@ -193,7 +193,7 @@ class GD_CORE_API ObjectFolderOrObject {
static gd::ObjectFolderOrObject badObjectFolderOrObject;
gd::ObjectFolderOrObject*
parent; // nullptr if root folder, points to the parent folder otherwise.
parent = nullptr; // nullptr if root folder, points to the parent folder otherwise.
QuickCustomization::Visibility quickCustomizationVisibility;
// Representing an object:

View File

@@ -20,8 +20,8 @@ namespace gd {
/**
* \brief Represents an object group.
*
* Objects groups do not really contains objects : They are just used in events,
* so as to create events which can be applied to several objects.
* Objects groups do not really contains objects: they are just used in events,
* to create events which can be applied to several objects.
*
* \ingroup PlatformDefinition
*/

View File

@@ -16,7 +16,9 @@
namespace gd {
ObjectsContainer::ObjectsContainer() {
ObjectsContainer::ObjectsContainer(
const ObjectsContainer::SourceType sourceType_)
: sourceType(sourceType_) {
rootFolder = gd::make_unique<gd::ObjectFolderOrObject>("__ROOT");
}
@@ -34,6 +36,7 @@ ObjectsContainer& ObjectsContainer::operator=(
}
void ObjectsContainer::Init(const gd::ObjectsContainer& other) {
sourceType = other.sourceType;
initialObjects = gd::Clone(other.initialObjects);
objectGroups = other.objectGroups;
// The objects folders are not copied.
@@ -205,6 +208,14 @@ void ObjectsContainer::MoveObjectFolderOrObjectToAnotherContainerInFolder(
objectFolderOrObject, newParentFolder, newPosition);
}
std::set<gd::String> ObjectsContainer::GetAllObjectNames() const {
std::set<gd::String> names;
for (const auto& object : initialObjects) {
names.insert(object->GetName());
}
return names;
}
std::vector<const ObjectFolderOrObject*>
ObjectsContainer::GetAllObjectFolderOrObjects() const {
std::vector<const ObjectFolderOrObject*> results;

View File

@@ -3,10 +3,11 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_OBJECTSCONTAINER_H
#define GDCORE_OBJECTSCONTAINER_H
#pragma once
#include <memory>
#include <vector>
#include <set>
#include "GDCore/String.h"
#include "GDCore/Project/ObjectGroupsContainer.h"
#include "GDCore/Project/ObjectFolderOrObject.h"
@@ -35,15 +36,25 @@ namespace gd {
*/
class GD_CORE_API ObjectsContainer {
public:
enum SourceType {
Unknown,
Global,
Scene,
Object,
Function,
};
/**
* \brief Default constructor creating a container without any objects.
* \brief Constructor creating a container without any objects.
*/
ObjectsContainer();
ObjectsContainer(const SourceType sourceType);
virtual ~ObjectsContainer();
ObjectsContainer(const ObjectsContainer&);
ObjectsContainer& operator=(const ObjectsContainer& rhs);
SourceType GetSourceType() const { return sourceType; }
/** \name Objects management
* Members functions related to objects management.
*/
@@ -57,7 +68,7 @@ class GD_CORE_API ObjectsContainer {
/**
* \brief Return a reference to the object called \a name.
*/
Object& GetObject(const gd::String& name);
gd::Object& GetObject(const gd::String& name);
/**
* \brief Return a reference to the object called \a name.
@@ -68,7 +79,7 @@ class GD_CORE_API ObjectsContainer {
* \brief Return a reference to the object at position \a index in the objects
* list
*/
Object& GetObject(std::size_t index);
gd::Object& GetObject(std::size_t index);
/**
* \brief Return a reference to the object at position \a index in the objects
@@ -168,6 +179,8 @@ class GD_CORE_API ObjectsContainer {
const std::vector<std::unique_ptr<gd::Object> >& GetObjects() const {
return initialObjects;
}
std::set<gd::String> GetAllObjectNames() const;
///@}
/**
@@ -232,6 +245,7 @@ class GD_CORE_API ObjectsContainer {
gd::ObjectGroupsContainer objectGroups;
private:
SourceType sourceType = Unknown;
std::unique_ptr<gd::ObjectFolderOrObject> rootFolder;
/**
@@ -242,5 +256,3 @@ class GD_CORE_API ObjectsContainer {
};
} // namespace gd
#endif // GDCORE_OBJECTSCONTAINER_H

View File

@@ -416,7 +416,8 @@ gd::String ObjectsContainersList::GetTypeOfObject(
return "";
}
if (objectsContainers.size() == 1) {
gd::ObjectsContainer emptyObjectsContainer;
gd::ObjectsContainer emptyObjectsContainer(
gd::ObjectsContainer::SourceType::Unknown);
return gd::GetTypeOfObject(emptyObjectsContainer, *objectsContainers[0],
objectName, true);
}
@@ -439,7 +440,8 @@ bool ObjectsContainersList::HasBehaviorInObjectOrGroup(
return false;
}
if (objectsContainers.size() == 1) {
gd::ObjectsContainer emptyObjectsContainer;
gd::ObjectsContainer emptyObjectsContainer(
gd::ObjectsContainer::SourceType::Unknown);
return gd::HasBehaviorInObjectOrGroup(
emptyObjectsContainer, *objectsContainers[0], objectOrGroupName,
behaviorName, true);
@@ -468,7 +470,8 @@ gd::String ObjectsContainersList::GetTypeOfBehaviorInObjectOrGroup(
return "";
}
if (objectsContainers.size() == 1) {
gd::ObjectsContainer emptyObjectsContainer;
gd::ObjectsContainer emptyObjectsContainer(
gd::ObjectsContainer::SourceType::Unknown);
return gd::GetTypeOfBehaviorInObjectOrGroup(
emptyObjectsContainer, *objectsContainers[0], objectOrGroupName,
behaviorName, searchInGroups);
@@ -495,7 +498,8 @@ gd::String ObjectsContainersList::GetTypeOfBehavior(
return "";
}
if (objectsContainers.size() == 1) {
gd::ObjectsContainer emptyObjectsContainer;
gd::ObjectsContainer emptyObjectsContainer(
gd::ObjectsContainer::SourceType::Unknown);
return gd::GetTypeOfBehavior(emptyObjectsContainer, *objectsContainers[0],
behaviorName, searchInGroups);
}
@@ -521,7 +525,8 @@ std::vector<gd::String> ObjectsContainersList::GetBehaviorsOfObject(
return behaviors;
}
if (objectsContainers.size() == 1) {
gd::ObjectsContainer emptyObjectsContainer;
gd::ObjectsContainer emptyObjectsContainer(
gd::ObjectsContainer::SourceType::Unknown);
return gd::GetBehaviorsOfObject(emptyObjectsContainer,
*objectsContainers[0], objectName,
searchInGroups);
@@ -530,6 +535,33 @@ std::vector<gd::String> ObjectsContainersList::GetBehaviorsOfObject(
*objectsContainers[0], *objectsContainers[1], objectName, searchInGroups);
}
std::vector<gd::String> ObjectsContainersList::GetBehaviorNamesInObjectOrGroup(
const gd::String &objectOrGroupName, const gd::String &behaviorType, bool searchInGroups) const {
if (objectsContainers.size() > 2) {
// TODO: rework forwarded methods so they can work with any number of
// containers.
gd::LogFatalError(
"ObjectsContainersList::GetBehaviorNamesInObjectOrGroup called with objectsContainers "
"not being exactly 2. This is a logical error and will crash.");
}
if (objectsContainers.size() == 0) {
gd::LogWarning("ObjectsContainersList::GetBehaviorNamesInObjectOrGroup called without any "
"objectsContainer");
std::vector<gd::String> behaviors;
return behaviors;
}
if (objectsContainers.size() == 1) {
gd::ObjectsContainer emptyObjectsContainer(
gd::ObjectsContainer::SourceType::Unknown);
return gd::GetBehaviorNamesInObjectOrGroup(emptyObjectsContainer,
*objectsContainers[0], objectOrGroupName, behaviorType,
searchInGroups);
}
return gd::GetBehaviorNamesInObjectOrGroup(
*objectsContainers[0], *objectsContainers[1], objectOrGroupName, behaviorType, searchInGroups);
}
std::vector<gd::String> ObjectsContainersList::GetAnimationNamesOfObject(
const gd::String &objectOrGroupName) const {
std::vector<gd::String> animationNames;
@@ -589,6 +621,28 @@ std::vector<gd::String> ObjectsContainersList::GetAnimationNamesOfObject(
return animationNames;
}
const ObjectsContainer *
ObjectsContainersList::GetObjectsContainerFromObjectName(
const gd::String &objectOrGroupName) const {
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
++it) {
if ((*it)->HasObjectNamed(objectOrGroupName) ||
(*it)->GetObjectGroups().Has(objectOrGroupName)) {
return *it;
}
}
return nullptr;
}
const gd::ObjectsContainer::SourceType
ObjectsContainersList::GetObjectsContainerSourceType(
const gd::String &objectOrGroupName) const {
const auto *objectsContainer =
GetObjectsContainerFromObjectName(objectOrGroupName);
return objectsContainer ? objectsContainer->GetSourceType()
: gd::ObjectsContainer::SourceType::Unknown;
}
const gd::ObjectsContainer &
ObjectsContainersList::GetObjectsContainer(std::size_t index) const {
return *objectsContainers[index];

View File

@@ -2,12 +2,12 @@
#include <vector>
#include "Variable.h"
#include "GDCore/Project/ObjectsContainer.h"
namespace gd {
class String;
class Project;
class Layout;
class ObjectsContainer;
class VariablesContainer;
class Object;
class ObjectConfiguration;
@@ -50,6 +50,11 @@ class GD_CORE_API ObjectsContainersList {
*/
bool HasObjectOrGroupNamed(const gd::String& name) const;
/**
* \brief Check if the specified object exists ignoring groups.
*/
bool HasObjectNamed(const gd::String& name) const;
enum VariableExistence {
DoesNotExist,
Exists,
@@ -128,6 +133,18 @@ class GD_CORE_API ObjectsContainersList {
std::vector<gd::String> GetBehaviorsOfObject(
const gd::String& objectName, bool searchInGroups = true) const;
/**
* \brief Get behaviors of an object/group of a given behavior type.
* \note The behaviors of a group are the behaviors which are found in common
* when looking all the objects of the group.
*
* @return Vector containing names of behaviors
*/
std::vector<gd::String>
GetBehaviorNamesInObjectOrGroup(const gd::String &objectOrGroupName,
const gd::String &behaviorType,
bool searchInGroups = true) const;
/**
* \brief Get the animation names of an object/group.
* \note The animation names of a group are the animation names common to
@@ -173,8 +190,28 @@ class GD_CORE_API ObjectsContainersList {
std::function<void(const gd::String& variableName,
const gd::Variable& variable)> fn) const;
/**
* \brief Return the source type of the container for the specified object or
* group of objects.
*/
const gd::ObjectsContainer::SourceType GetObjectsContainerSourceType(
const gd::String& objectOrGroupName) const;
/**
* Get the objects container for for the specified object or group of objects.
*/
const ObjectsContainer *
GetObjectsContainerFromObjectName(const gd::String &objectOrGroupName) const;
/**
* \brief Return a the objects container at position \a index.
*
* \warning The returned `ObjectsContainer` may contain cloned objects (in the case of
* `ProjectScopedContainers::MakeNewProjectScopedContainersForEventsBasedObject`)
* or "fake" objects used by events like parameters. They must not be used to
* edit the objects.
* Search for "ProjectScopedContainers wrongly containing temporary objects containers or objects"
* in the codebase.
*/
const gd::ObjectsContainer &GetObjectsContainer(std::size_t index) const;
@@ -188,8 +225,6 @@ class GD_CORE_API ObjectsContainersList {
ObjectsContainersList(){};
private:
bool HasObjectNamed(const gd::String& name) const;
const gd::Object* GetObject(const gd::String& name) const;
bool HasObjectWithVariableNamed(const gd::String& objectName,

View File

@@ -71,23 +71,22 @@ Project::Project()
isPlayableWithKeyboard(false),
isPlayableWithGamepad(false),
isPlayableWithMobile(false),
currentPlatform(NULL),
currentPlatform(nullptr),
gdMajorVersion(gd::VersionWrapper::Major()),
gdMinorVersion(gd::VersionWrapper::Minor()),
gdBuildVersion(gd::VersionWrapper::Build()),
variables(gd::VariablesContainer::SourceType::Global) {}
variables(gd::VariablesContainer::SourceType::Global),
objectsContainer(gd::ObjectsContainer::SourceType::Global) {}
Project::~Project() {}
void Project::ResetProjectUuid() { projectUuid = UUID::MakeUuid4(); }
std::unique_ptr<gd::Object> Project::CreateObject(
const gd::String& objectType, const gd::String& name) const {
std::unique_ptr<gd::Object> object = gd::make_unique<Object>(
name, objectType, CreateObjectConfiguration(objectType));
void Project::EnsureObjectDefaultBehaviors(gd::Object& object) const {
auto& platform = GetCurrentPlatform();
auto& project = *this;
auto& objectType = object.GetType();
auto addDefaultBehavior = [&platform, &project, &object, &objectType](
const gd::String& behaviorType) {
auto& behaviorMetadata =
@@ -97,17 +96,47 @@ std::unique_ptr<gd::Object> Project::CreateObject(
" has an unknown default behavior: " + behaviorType);
return;
}
auto* behavior = object->AddNewBehavior(
project, behaviorType, behaviorMetadata.GetDefaultName());
behavior->SetDefaultBehavior(true);
const gd::String& behaviorName = behaviorMetadata.GetDefaultName();
// Check if we can keep a behavior that would have been already set up on the object.
if (object.HasBehaviorNamed(behaviorName)) {
const auto& behavior = object.GetBehavior(behaviorName);
if (!behavior.IsDefaultBehavior() || behavior.GetTypeName() != behaviorType) {
// Behavior type has changed, remove it so it is re-created.
object.RemoveBehavior(behaviorName);
}
}
if (!object.HasBehaviorNamed(behaviorName)) {
auto* behavior = object.AddNewBehavior(
project, behaviorType, behaviorName);
behavior->SetDefaultBehavior(true);
}
};
auto &objectMetadata =
gd::MetadataProvider::GetObjectMetadata(platform, objectType);
if (!MetadataProvider::IsBadObjectMetadata(objectMetadata)) {
for (auto &behaviorType : objectMetadata.GetDefaultBehaviors()) {
// Add all default behaviors.
const auto& defaultBehaviorTypes = objectMetadata.GetDefaultBehaviors();
for (auto &behaviorType : defaultBehaviorTypes) {
addDefaultBehavior(behaviorType);
}
// Ensure there are no default behaviors that would not be required left on the object.
for (const auto& behaviorName : object.GetAllBehaviorNames()) {
auto& behavior = object.GetBehavior(behaviorName);
if (!behavior.IsDefaultBehavior()) {
// Non default behaviors are not handled by this function.
continue;
}
if (defaultBehaviorTypes.find(behavior.GetTypeName()) == defaultBehaviorTypes.end()) {
object.RemoveBehavior(behaviorName);
}
}
}
// During project deserialization, event-based object metadata are not yet
// generated. Default behaviors will be added by
@@ -115,6 +144,14 @@ std::unique_ptr<gd::Object> Project::CreateObject(
else if (!project.HasEventsBasedObject(objectType)) {
gd::LogWarning("Object: " + name + " has an unknown type: " + objectType);
}
}
std::unique_ptr<gd::Object> Project::CreateObject(
const gd::String& objectType, const gd::String& name) const {
std::unique_ptr<gd::Object> object = gd::make_unique<Object>(
name, objectType, CreateObjectConfiguration(objectType));
EnsureObjectDefaultBehaviors(*object);
return std::move(object);
}
@@ -827,34 +864,7 @@ void Project::UnserializeFrom(const SerializerElement& element) {
eventsFunctionsExtensions.clear();
const SerializerElement& eventsFunctionsExtensionsElement =
element.GetChild("eventsFunctionsExtensions");
eventsFunctionsExtensionsElement.ConsiderAsArrayOf(
"eventsFunctionsExtension");
// First, only unserialize behaviors and objects names.
// As event based objects can contains CustomObject and Custom Object,
// this allows them to reference EventBasedBehavior and EventBasedObject
// respectively.
for (std::size_t i = 0;
i < eventsFunctionsExtensionsElement.GetChildrenCount();
++i) {
const SerializerElement& eventsFunctionsExtensionElement =
eventsFunctionsExtensionsElement.GetChild(i);
gd::EventsFunctionsExtension& newEventsFunctionsExtension =
InsertNewEventsFunctionsExtension("",
GetEventsFunctionsExtensionsCount());
newEventsFunctionsExtension.UnserializeExtensionDeclarationFrom(
*this, eventsFunctionsExtensionElement);
}
// Then unserialize functions, behaviors and objects content.
for (std::size_t i = 0;
i < eventsFunctionsExtensionsElement.GetChildrenCount();
++i) {
const SerializerElement& eventsFunctionsExtensionElement =
eventsFunctionsExtensionsElement.GetChild(i);
eventsFunctionsExtensions.at(i)->UnserializeExtensionImplementationFrom(
*this, eventsFunctionsExtensionElement);
}
UnserializeAndInsertExtensionsFrom(eventsFunctionsExtensionsElement);
objectsContainer.GetObjectGroups().UnserializeFrom(
element.GetChild("objectsGroups", 0, "ObjectGroups"));
@@ -922,6 +932,120 @@ void Project::UnserializeFrom(const SerializerElement& element) {
}
}
void Project::UnserializeAndInsertExtensionsFrom(
const gd::SerializerElement &eventsFunctionsExtensionsElement) {
eventsFunctionsExtensionsElement.ConsiderAsArrayOf(
"eventsFunctionsExtension");
// First, only unserialize behaviors and objects names.
// As event based objects can contains custom behaviors and custom objects,
// this allows them to reference EventBasedBehavior and EventBasedObject
// respectively.
for (std::size_t i = 0;
i < eventsFunctionsExtensionsElement.GetChildrenCount();
++i) {
const SerializerElement& eventsFunctionsExtensionElement =
eventsFunctionsExtensionsElement.GetChild(i);
const gd::String& name = eventsFunctionsExtensionElement.GetStringAttribute("name");
gd::EventsFunctionsExtension& eventsFunctionsExtension =
HasEventsFunctionsExtensionNamed(name)
? GetEventsFunctionsExtension(name)
: InsertNewEventsFunctionsExtension(
name, GetEventsFunctionsExtensionsCount());
eventsFunctionsExtension.UnserializeExtensionDeclarationFrom(
*this, eventsFunctionsExtensionElement);
}
// Then unserialize functions, behaviors and objects content.
for (gd::String &extensionName :
GetUnserializingOrderExtensionNames(eventsFunctionsExtensionsElement)) {
size_t extensionIndex = GetEventsFunctionsExtensionPosition(extensionName);
const SerializerElement &eventsFunctionsExtensionElement =
eventsFunctionsExtensionsElement.GetChild(extensionIndex);
eventsFunctionsExtensions.at(extensionIndex)
->UnserializeExtensionImplementationFrom(
*this, eventsFunctionsExtensionElement);
}
}
std::vector<gd::String> Project::GetUnserializingOrderExtensionNames(
const gd::SerializerElement &eventsFunctionsExtensionsElement) {
// Some extension have custom objects, which have child objects coming from other extension.
// These child objects must be loaded completely before the parent custom obejct can be unserialized.
// This implies: an order on the extension unserialization (and no cycles).
// At the beginning, everything is yet to be loaded.
std::vector<gd::String> remainingExtensionNames(
eventsFunctionsExtensions.size());
for (std::size_t i = 0; i < eventsFunctionsExtensions.size(); ++i) {
remainingExtensionNames[i] = eventsFunctionsExtensions.at(i)->GetName();
}
// Helper allowing to find if an extension has an object that depends on
// at least one other object from another extension that is not loaded yet.
auto isDependentFromRemainingExtensions =
[&remainingExtensionNames](
const gd::SerializerElement &eventsFunctionsExtensionElement) {
auto &eventsBasedObjectsElement =
eventsFunctionsExtensionElement.GetChild("eventsBasedObjects");
eventsBasedObjectsElement.ConsiderAsArrayOf("eventsBasedObject");
for (std::size_t eventsBasedObjectsIndex = 0;
eventsBasedObjectsIndex <
eventsBasedObjectsElement.GetChildrenCount();
++eventsBasedObjectsIndex) {
auto &objectsElement =
eventsBasedObjectsElement.GetChild(eventsBasedObjectsIndex)
.GetChild("objects");
objectsElement.ConsiderAsArrayOf("object");
for (std::size_t objectIndex = 0;
objectIndex < objectsElement.GetChildrenCount(); ++objectIndex) {
const gd::String &objectType =
objectsElement.GetChild(objectIndex).GetStringAttribute("type");
gd::String extensionName =
eventsFunctionsExtensionElement.GetStringAttribute("name");
gd::String usedExtensionName =
gd::PlatformExtension::GetExtensionFromFullObjectType(objectType);
if (usedExtensionName != extensionName &&
std::find(remainingExtensionNames.begin(),
remainingExtensionNames.end(),
usedExtensionName) != remainingExtensionNames.end()) {
return true;
}
}
}
return false;
};
// Find the order of loading so that the extensions are loaded when all the other
// extensions they depend on are already loaded.
std::vector<gd::String> loadOrderExtensionNames;
bool foundAnyExtension = true;
while (foundAnyExtension) {
foundAnyExtension = false;
for (std::size_t i = 0; i < remainingExtensionNames.size(); ++i) {
auto extensionName = remainingExtensionNames[i];
size_t extensionIndex =
GetEventsFunctionsExtensionPosition(extensionName);
const SerializerElement &eventsFunctionsExtensionElement =
eventsFunctionsExtensionsElement.GetChild(extensionIndex);
if (!isDependentFromRemainingExtensions(
eventsFunctionsExtensionElement)) {
loadOrderExtensionNames.push_back(extensionName);
remainingExtensionNames.erase(remainingExtensionNames.begin() + i);
i--;
foundAnyExtension = true;
}
}
}
return loadOrderExtensionNames;
}
void Project::SerializeTo(SerializerElement& element) const {
SerializerElement& versionElement = element.AddChild("gdVersion");
versionElement.SetAttribute("major", gd::VersionWrapper::Major());
@@ -1151,7 +1275,10 @@ gd::SourceFile& Project::InsertNewSourceFile(const gd::String& name,
return newlyInsertedSourceFile;
}
Project::Project(const Project& other) { Init(other); }
Project::Project(const Project &other)
: objectsContainer(gd::ObjectsContainer::SourceType::Global) {
Init(other);
}
Project& Project::operator=(const Project& other) {
if (this != &other) Init(other);

View File

@@ -523,13 +523,7 @@ class GD_CORE_API Project {
std::unique_ptr<gd::Object> CreateObject(const gd::String& type,
const gd::String& name) const;
/**
* Create an object configuration of the given type.
*
* \param type The type of the object
*/
std::unique_ptr<gd::ObjectConfiguration> CreateObjectConfiguration(
const gd::String& type) const;
void EnsureObjectDefaultBehaviors(gd::Object& object) const;
/**
* Create an event of the given type.
@@ -899,6 +893,16 @@ class GD_CORE_API Project {
const EventsFunctionsExtension& eventsFunctionExtension,
std::size_t position);
/**
* \brief Unserialize and insert in the project the extensions.
*
* Unserialization is done in two passe to allow dependencies between extensions.
*
* \note If an extension with the same name already exists, it will be overwritten.
*/
void UnserializeAndInsertExtensionsFrom(
const gd::SerializerElement& eventsFunctionsExtensionsElement);
/**
* \brief Delete the events functions extension named "name".
*/
@@ -990,16 +994,12 @@ class GD_CORE_API Project {
/**
* \brief return the objects of the project.
*/
gd::ObjectsContainer& GetObjects() {
return objectsContainer;
}
gd::ObjectsContainer& GetObjects() { return objectsContainer; }
/**
* \brief Return the objects of the project.
*/
const gd::ObjectsContainer& GetObjects() const {
return objectsContainer;
}
const gd::ObjectsContainer& GetObjects() const { return objectsContainer; }
///@}
/** \name Identifier names
@@ -1080,32 +1080,53 @@ class GD_CORE_API Project {
*/
void Init(const gd::Project& project);
gd::String name; ///< Game name
gd::String description; ///< Game description
gd::String version; ///< Game version number (used for some exports)
unsigned int windowWidth; ///< Window default width
unsigned int windowHeight; ///< Window default height
int maxFPS; ///< Maximum Frame Per Seconds, -1 for unlimited
unsigned int minFPS; ///< Minimum Frame Per Seconds ( slow down game if FPS
///< are below this number )
bool verticalSync; ///< If true, must activate vertical synchronization.
/**
* @brief Get the project extensions names in the order they have to be
* unserialized.
*
* Child-objects need the event-based objects they use to be loaded completely
* before they are unserialized.
*/
std::vector<gd::String> GetUnserializingOrderExtensionNames(
const gd::SerializerElement& eventsFunctionsExtensionsElement);
/**
* Create an object configuration of the given type.
*
* \param type The type of the object
*/
std::unique_ptr<gd::ObjectConfiguration> CreateObjectConfiguration(
const gd::String& type) const;
gd::String name; ///< Game name
gd::String description; ///< Game description
gd::String version; ///< Game version number (used for some exports)
unsigned int windowWidth = 0; ///< Window default width
unsigned int windowHeight = 0; ///< Window default height
int maxFPS = 0; ///< Maximum Frame Per Seconds, -1 for unlimited
unsigned int minFPS = 0; ///< Minimum Frame Per Seconds ( slow down game if
///< FPS are below this number )
bool verticalSync =
false; ///< If true, must activate vertical synchronization.
gd::String scaleMode;
bool pixelsRounding; ///< If true, the rendering should stop pixel
///< interpolation of rendered objects.
bool adaptGameResolutionAtRuntime; ///< Should the game resolution be adapted
///< to the window size at runtime
bool pixelsRounding = false; ///< If true, the rendering should stop pixel
///< interpolation of rendered objects.
bool adaptGameResolutionAtRuntime =
true; ///< Should the game resolution be adapted
///< to the window size at runtime
gd::String
sizeOnStartupMode; ///< How to adapt the game size to the screen. Can be
///< "adaptWidth", "adaptHeight" or empty
gd::String antialiasingMode;
bool isAntialisingEnabledOnMobile;
bool isAntialisingEnabledOnMobile = false;
gd::String projectUuid; ///< UUID useful to identify the game in online
///< services or database that would require it.
bool useDeprecatedZeroAsDefaultZOrder; ///< If true, objects created from
///< events will have 0 as Z order,
///< instead of the highest Z order
///< found on the layer at the scene
///< startup.
bool useDeprecatedZeroAsDefaultZOrder =
false; ///< If true, objects created from
///< events will have 0 as Z order,
///< instead of the highest Z order
///< found on the layer at the scene
///< startup.
std::vector<std::unique_ptr<gd::Layout> > scenes; ///< List of all scenes
gd::VariablesContainer variables; ///< Initial global variables
gd::ObjectsContainer objectsContainer;
@@ -1118,7 +1139,8 @@ class GD_CORE_API Project {
std::vector<gd::Platform*>
platforms; ///< Pointers to the platforms this project supports.
gd::String firstLayout;
bool useExternalSourceFiles; ///< True if game used external source files.
bool useExternalSourceFiles =
false; ///< True if game used external source files.
std::vector<std::unique_ptr<gd::SourceFile> >
externalSourceFiles; ///< List of external source files used.
gd::String author; ///< Game author name, for publishing purpose.
@@ -1127,35 +1149,40 @@ class GD_CORE_API Project {
std::vector<gd::String>
authorUsernames; ///< Game author usernames, from GDevelop users DB.
std::vector<gd::String> categories; ///< Game categories
bool isPlayableWithKeyboard; ///< The project is playable with a keyboard.
bool isPlayableWithGamepad; ///< The project is playable with a gamepad.
bool isPlayableWithMobile; ///< The project is playable on a mobile.
gd::String packageName; ///< Game package name
bool isPlayableWithKeyboard =
false; ///< The project is playable with a keyboard.
bool isPlayableWithGamepad =
false; ///< The project is playable with a gamepad.
bool isPlayableWithMobile = false; ///< The project is playable on a mobile.
gd::String packageName; ///< Game package name
gd::String templateSlug; ///< The slug of the template from which the game is
///< created.
gd::String orientation; ///< Lock game orientation (on mobile devices).
///< "default", "landscape" or "portrait".
bool
folderProject; ///< True if folder project, false if single file project.
bool folderProject =
false; ///< True if folder project, false if single file project.
gd::String
projectFile; ///< Path to the project file - when editing a local file.
gd::String latestCompilationDirectory;
gd::Platform*
currentPlatform; ///< The platform being used to edit the project.
gd::Platform* currentPlatform =
nullptr; ///< The platform being used to edit the project.
gd::PlatformSpecificAssets platformSpecificAssets;
gd::LoadingScreen loadingScreen;
gd::Watermark watermark;
std::vector<std::unique_ptr<gd::ExternalEvents> >
externalEvents; ///< List of all externals events
ExtensionProperties
extensionProperties; ///< The properties of the extensions.
extensionProperties; ///< The properties of the extensions.
gd::WholeProjectDiagnosticReport wholeProjectDiagnosticReport;
mutable unsigned int gdMajorVersion; ///< The GD major version used the last
///< time the project was saved.
mutable unsigned int gdMinorVersion; ///< The GD minor version used the last
///< time the project was saved.
mutable unsigned int gdBuildVersion; ///< The GD build version used the last
///< time the project was saved.
mutable unsigned int gdMajorVersion =
0; ///< The GD major version used the last
///< time the project was saved.
mutable unsigned int gdMinorVersion =
0; ///< The GD minor version used the last
///< time the project was saved.
mutable unsigned int gdBuildVersion =
0; ///< The GD build version used the last
///< time the project was saved.
};
} // namespace gd

View File

@@ -4,12 +4,55 @@
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Events/Event.h"
#include "GDCore/Extensions/PlatformExtension.h"
namespace gd {
ProjectScopedContainers
ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(
const gd::Project &project, const gd::Layout &layout) {
ProjectScopedContainers projectScopedContainers(
ObjectsContainersList::MakeNewObjectsContainersListForProjectAndLayout(
project, layout),
VariablesContainersList::
MakeNewVariablesContainersListForProjectAndLayout(project, layout),
&project.GetVariables(), &layout.GetVariables(),
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
return projectScopedContainers;
}
ProjectScopedContainers
ProjectScopedContainers::MakeNewProjectScopedContainersForProject(
const gd::Project &project) {
ProjectScopedContainers projectScopedContainers(
ObjectsContainersList::MakeNewObjectsContainersListForProject(project),
VariablesContainersList::MakeNewVariablesContainersListForProject(
project),
&project.GetVariables(), nullptr,
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
return projectScopedContainers;
}
ProjectScopedContainers
ProjectScopedContainers::MakeNewProjectScopedContainersFor(
const gd::ObjectsContainer &globalObjectsContainers,
const gd::ObjectsContainer &objectsContainers) {
ProjectScopedContainers projectScopedContainers(
ObjectsContainersList::MakeNewObjectsContainersListForContainers(
globalObjectsContainers, objectsContainers),
VariablesContainersList::MakeNewEmptyVariablesContainersList(),
nullptr, nullptr,
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
return projectScopedContainers;
};
ProjectScopedContainers
ProjectScopedContainers::MakeNewProjectScopedContainersForEventsFunctionsExtension(
const gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension) {
@@ -18,6 +61,8 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForEventsFunctionsExtensi
ObjectsContainersList::MakeNewEmptyObjectsContainersList(),
VariablesContainersList::
MakeNewVariablesContainersListForEventsFunctionsExtension(eventsFunctionsExtension),
&eventsFunctionsExtension.GetGlobalVariables(),
&eventsFunctionsExtension.GetSceneVariables(),
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
return projectScopedContainers;
@@ -37,6 +82,8 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForFreeEventsFunction(
parameterObjectsContainer),
VariablesContainersList::
MakeNewVariablesContainersListForEventsFunctionsExtension(eventsFunctionsExtension),
&eventsFunctionsExtension.GetGlobalVariables(),
&eventsFunctionsExtension.GetSceneVariables(),
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
projectScopedContainers.AddParameters(
@@ -63,6 +110,8 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForBehaviorEventsFunction
parameterObjectsContainer),
VariablesContainersList::
MakeNewVariablesContainersListForEventsFunctionsExtension(eventsFunctionsExtension),
&eventsFunctionsExtension.GetGlobalVariables(),
&eventsFunctionsExtension.GetSceneVariables(),
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
projectScopedContainers.AddPropertiesContainer(
@@ -87,11 +136,14 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForObjectEventsFunction(
project, eventsBasedObject, eventsFunction, parameterObjectsContainer);
ProjectScopedContainers projectScopedContainers(
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
ObjectsContainersList::MakeNewObjectsContainersListForContainers(
eventsBasedObject.GetObjects(),
parameterObjectsContainer),
VariablesContainersList::
MakeNewVariablesContainersListForEventsFunctionsExtension(
eventsFunctionsExtension),
&eventsFunctionsExtension.GetGlobalVariables(),
&eventsFunctionsExtension.GetSceneVariables(),
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
projectScopedContainers.AddPropertiesContainer(
@@ -109,22 +161,34 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForEventsBasedObject(
const gd::EventsBasedObject &eventsBasedObject,
gd::ObjectsContainer &outputObjectsContainer) {
// TODO: We should avoid to use a single `outputObjectsContainer` and instead
// use multiple, stable objects container pointed by the `ProjectScopedContainers`
// created below.
// Search for "ProjectScopedContainers wrongly containing temporary objects containers or objects"
// in the codebase.
outputObjectsContainer.GetObjects().clear();
outputObjectsContainer.GetObjectGroups().Clear();
// This object named "Object" represents the parent and is used by events.
// TODO: Use a dedicated `ObjectsContainer` with only this "Object" and check in
// the codebase that this container is not assumed as a
// "globalObjectsContainer".
// Search for "ProjectScopedContainers wrongly containing temporary objects containers or objects"
// in the codebase.
outputObjectsContainer.InsertNewObject(
project,
gd::PlatformExtension::GetObjectFullType(
eventsFunctionsExtension.GetName(), eventsBasedObject.GetName()),
"Object", outputObjectsContainer.GetObjectsCount());
gd::EventsFunctionTools::CopyEventsBasedObjectChildrenToObjectsContainer(
eventsBasedObject, outputObjectsContainer);
ProjectScopedContainers projectScopedContainers(
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
outputObjectsContainer),
ObjectsContainersList::MakeNewObjectsContainersListForContainers(
eventsBasedObject.GetObjects(), outputObjectsContainer),
VariablesContainersList::
MakeNewVariablesContainersListForEventsFunctionsExtension(
eventsFunctionsExtension),
&eventsFunctionsExtension.GetGlobalVariables(),
&eventsFunctionsExtension.GetSceneVariables(),
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
projectScopedContainers.AddPropertiesContainer(

View File

@@ -5,13 +5,11 @@
#include "ObjectsContainersList.h"
#include "PropertiesContainersList.h"
#include "VariablesContainersList.h"
#include "VariablesContainer.h"
namespace gd {
class Project;
class ObjectsContainer;
class ObjectsContainersList;
class VariablesContainersList;
class PropertiesContainersList;
class NamedPropertyDescriptor;
class ParameterMetadataContainer;
class BaseEvent;
@@ -19,7 +17,7 @@ class EventsFunctionsExtension;
class EventsFunction;
class EventsBasedBehavior;
class EventsBasedObject;
} // namespace gd
} // namespace gd
namespace gd {
@@ -38,51 +36,29 @@ class ProjectScopedContainers {
ProjectScopedContainers(
const gd::ObjectsContainersList &objectsContainersList_,
const gd::VariablesContainersList &variablesContainersList_,
const gd::VariablesContainer *legacyGlobalVariables_,
const gd::VariablesContainer *legacySceneVariables_,
const gd::PropertiesContainersList &propertiesContainersList_)
: objectsContainersList(objectsContainersList_),
variablesContainersList(variablesContainersList_),
legacyGlobalVariables(legacyGlobalVariables_),
legacySceneVariables(legacySceneVariables_),
propertiesContainersList(propertiesContainersList_){};
virtual ~ProjectScopedContainers(){};
static ProjectScopedContainers
MakeNewProjectScopedContainersForProjectAndLayout(const gd::Project &project,
const gd::Layout &layout) {
ProjectScopedContainers projectScopedContainers(
ObjectsContainersList::MakeNewObjectsContainersListForProjectAndLayout(
project, layout),
VariablesContainersList::
MakeNewVariablesContainersListForProjectAndLayout(project, layout),
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
return projectScopedContainers;
}
const gd::Layout &layout);
static ProjectScopedContainers
MakeNewProjectScopedContainersForProject(const gd::Project &project) {
ProjectScopedContainers projectScopedContainers(
ObjectsContainersList::MakeNewObjectsContainersListForProject(
project),
VariablesContainersList::
MakeNewVariablesContainersListForProject(project),
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
return projectScopedContainers;
}
MakeNewProjectScopedContainersForProject(const gd::Project &project);
/**
* @deprecated Use another method for an explicit context instead.
*/
static ProjectScopedContainers MakeNewProjectScopedContainersFor(
const gd::ObjectsContainer &globalObjectsContainers,
const gd::ObjectsContainer &objectsContainers) {
ProjectScopedContainers projectScopedContainers(
ObjectsContainersList::MakeNewObjectsContainersListForContainers(
globalObjectsContainers, objectsContainers),
VariablesContainersList::MakeNewEmptyVariablesContainersList(),
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
return projectScopedContainers;
};
const gd::ObjectsContainer &objectsContainers);
static ProjectScopedContainers
MakeNewProjectScopedContainersForEventsFunctionsExtension(
@@ -221,6 +197,24 @@ class ProjectScopedContainers {
return variablesContainersList;
};
/**
* @brief Return the global variables of the current scene or the current
* extension. It allows legacy "globalvar" parameters to accept extension
* variables.
*/
const gd::VariablesContainer *GetLegacyGlobalVariables() const {
return legacyGlobalVariables;
};
/**
* @brief Return the scene variables of the current scene or the current
* extension. It allows legacy "scenevar" parameters to accept extension
* variables.
*/
const gd::VariablesContainer *GetLegacySceneVariables() const {
return legacySceneVariables;
};
const gd::PropertiesContainersList &GetPropertiesContainersList() const {
return propertiesContainersList;
};
@@ -231,11 +225,14 @@ class ProjectScopedContainers {
/** Do not use - should be private but accessible to let Emscripten create a
* temporary. */
ProjectScopedContainers(){};
ProjectScopedContainers()
: legacyGlobalVariables(nullptr), legacySceneVariables(nullptr){};
private:
private:
gd::ObjectsContainersList objectsContainersList;
gd::VariablesContainersList variablesContainersList;
const gd::VariablesContainer *legacyGlobalVariables;
const gd::VariablesContainer *legacySceneVariables;
gd::PropertiesContainersList propertiesContainersList;
std::vector<const ParameterMetadataContainer *> parametersVectorsList;
};

View File

@@ -1,16 +1,37 @@
#pragma once
#include "GDCore/String.h"
namespace gd {
class QuickCustomization {
public:
enum Visibility {
/** Visibility based on the parent or editor heuristics (probably visible). */
/** Visibility based on the parent or editor heuristics (probably visible).
*/
Default,
/** Visible in the quick customization editor. */
Visible,
/** Not visible in the quick customization editor. */
Hidden
};
static Visibility StringAsVisibility(const gd::String& str) {
if (str == "visible")
return Visibility::Visible;
else if (str == "hidden")
return Visibility::Hidden;
return Visibility::Default;
}
static gd::String VisibilityAsString(Visibility visibility) {
if (visibility == Visibility::Visible)
return "visible";
else if (visibility == Visibility::Hidden)
return "hidden";
return "default";
}
};
} // namespace gd

View File

@@ -0,0 +1,58 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Project/QuickCustomizationVisibilitiesContainer.h"
#include <algorithm>
#include <iostream>
#include "GDCore/Project/QuickCustomization.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
#include "GDCore/Tools/UUID/UUID.h"
using namespace std;
namespace gd {
QuickCustomizationVisibilitiesContainer::
QuickCustomizationVisibilitiesContainer() {}
bool QuickCustomizationVisibilitiesContainer::IsEmpty() const {
return visibilities.empty();
}
void QuickCustomizationVisibilitiesContainer::Set(
const gd::String& name, QuickCustomization::Visibility visibility) {
visibilities[name] = visibility;
}
QuickCustomization::Visibility QuickCustomizationVisibilitiesContainer::Get(
const gd::String& name) const {
auto it = visibilities.find(name);
if (it != visibilities.end()) return it->second;
return QuickCustomization::Visibility::Default;
}
void QuickCustomizationVisibilitiesContainer::SerializeTo(
SerializerElement& element) const {
for (auto& visibility : visibilities) {
element.SetStringAttribute(
visibility.first,
QuickCustomization::VisibilityAsString(visibility.second));
}
}
void QuickCustomizationVisibilitiesContainer::UnserializeFrom(
const SerializerElement& element) {
visibilities.clear();
for (auto& child : element.GetAllChildren()) {
visibilities[child.first] =
QuickCustomization::StringAsVisibility(child.second->GetStringValue());
}
}
} // namespace gd

View File

@@ -0,0 +1,29 @@
#pragma once
#include <memory>
#include <vector>
#include "GDCore/Project/QuickCustomization.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
namespace gd {
class QuickCustomizationVisibilitiesContainer {
public:
QuickCustomizationVisibilitiesContainer();
void Set(const gd::String& name, QuickCustomization::Visibility visibility);
QuickCustomization::Visibility Get(const gd::String& name) const;
bool IsEmpty() const;
void SerializeTo(SerializerElement& element) const;
void UnserializeFrom(const SerializerElement& element);
private:
std::map<gd::String, QuickCustomization::Visibility> visibilities;
};
} // namespace gd

View File

@@ -173,9 +173,6 @@ std::map<gd::String, gd::PropertyDescriptor> ImageResource::GetProperties()
properties[_("Smooth the image")]
.SetValue(smooth ? "true" : "false")
.SetType("Boolean");
properties[_("Always loaded in memory")]
.SetValue(alwaysLoaded ? "true" : "false")
.SetType("Boolean");
return properties;
}
@@ -184,8 +181,6 @@ bool ImageResource::UpdateProperty(const gd::String& name,
const gd::String& value) {
if (name == _("Smooth the image"))
smooth = value == "1";
else if (name == _("Always loaded in memory"))
alwaysLoaded = value == "1";
return true;
}
@@ -569,14 +564,12 @@ void ImageResource::SetFile(const gd::String& newFile) {
}
void ImageResource::UnserializeFrom(const SerializerElement& element) {
alwaysLoaded = element.GetBoolAttribute("alwaysLoaded");
smooth = element.GetBoolAttribute("smoothed");
SetUserAdded(element.GetBoolAttribute("userAdded"));
SetFile(element.GetStringAttribute("file"));
}
void ImageResource::SerializeTo(SerializerElement& element) const {
element.SetAttribute("alwaysLoaded", alwaysLoaded);
element.SetAttribute("smoothed", smooth);
element.SetAttribute("userAdded", IsUserAdded());
element.SetAttribute("file", GetFile());

View File

@@ -152,8 +152,8 @@ class GD_CORE_API Resource {
gd::String metadata;
gd::String originName;
gd::String originIdentifier;
bool userAdded; ///< True if the resource was added by the user, and not
///< automatically by GDevelop.
bool userAdded = false; ///< True if the resource was added by the user, and not
///< automatically by GDevelop.
static gd::String badStr;
};
@@ -166,7 +166,7 @@ class GD_CORE_API Resource {
*/
class GD_CORE_API ImageResource : public Resource {
public:
ImageResource() : Resource(), smooth(true), alwaysLoaded(false) {
ImageResource() : Resource(), smooth(true) {
SetKind("image");
};
virtual ~ImageResource(){};
@@ -210,7 +210,6 @@ class GD_CORE_API ImageResource : public Resource {
void SetSmooth(bool enable = true) { smooth = enable; }
bool smooth; ///< True if smoothing filter is applied
bool alwaysLoaded; ///< True if the image must always be loaded in memory.
private:
gd::String file;
};

View File

@@ -33,7 +33,7 @@ class GD_CORE_API Variable {
Unknown,
/** Used when objects of a group have different types for a variable. */
MixedTypes,
// Primitive types
String,
Number,
@@ -393,11 +393,11 @@ class GD_CORE_API Variable {
*/
static Type StringAsType(const gd::String& str);
bool folded;
bool folded = false;
mutable Type type;
mutable gd::String str;
mutable double value;
mutable bool boolVal;
mutable bool boolVal = false;
mutable bool hasMixedValues;
mutable std::map<gd::String, std::shared_ptr<Variable>>
children; ///< Children, when the variable is considered as a structure.

View File

@@ -187,7 +187,7 @@ class GD_CORE_API VariablesContainer {
///@}
private:
SourceType sourceType;
SourceType sourceType = Unknown;
std::vector<std::pair<gd::String, std::shared_ptr<gd::Variable>>> variables;
mutable gd::String persistentUuid; ///< A persistent random version 4 UUID,
///< useful for computing changesets.

View File

@@ -456,13 +456,13 @@ class GD_CORE_API SerializerElement {
*/
void Init(const gd::SerializerElement &other);
bool valueUndefined; ///< If true, the element does not have a value.
bool valueUndefined = true; ///< If true, the element does not have a value.
SerializerValue elementValue;
std::map<gd::String, SerializerValue> attributes;
std::vector<std::pair<gd::String, std::shared_ptr<SerializerElement> > >
children;
mutable bool isArray; ///< true if element is considered as an array
mutable bool isArray = false; ///< true if element is considered as an array
mutable gd::String arrayOf; ///< The name of the children (was useful for XML
///< parsed elements).
mutable gd::String deprecatedArrayOf; ///< Alternate name for children

View File

@@ -0,0 +1,2 @@
# Disable all checks in this folder.
Checks: '-*'

View File

@@ -4,6 +4,8 @@
* This project is released under the MIT License.
*/
// NOLINTBEGIN
#include "GDCore/String.h"
#include <algorithm>
@@ -825,3 +827,5 @@ bool GD_CORE_API CaseInsensitiveEquiv( const String &lhs, const String &rhs, boo
}
}
// NOLINTEND

View File

@@ -4,6 +4,8 @@
* This project is released under the MIT License.
*/
// NOLINTBEGIN
#ifndef GDCORE_UTF8_STRING_H
#define GDCORE_UTF8_STRING_H
@@ -898,3 +900,5 @@ namespace std
* In Unicode, uppercasing/lowercasing strings to compare them in a case-insensitive way is not recommended.
* That's why the function gd::CaseInsensitiveEquiv exists to compare two strings in a case-insensitive way.
*/
// NOLINTEND

View File

@@ -2,6 +2,7 @@
#define GD_CORE_POLYMORPHICCLONE_H
#include <memory>
#include <vector>
namespace gd {

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