Compare commits

...

142 Commits

Author SHA1 Message Date
Clément Pasteau
35e9297844 Fix cmake version build 2025-04-04 10:12:34 +02:00
Clément Pasteau
cedb9429c7 Improve languages dialog display (#7528)
Do not show in changelog
2025-04-02 11:28:27 +02:00
github-actions[bot]
d844b4d380 Update extension translations [skip ci] (#7527)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-04-02 10:07:12 +02:00
github-actions[bot]
e4265553e0 Update translations [skip ci] (#7526)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-04-02 09:13:15 +02:00
Florian Rival
2524b0b9d2 Update wording
Don't show in changelog
2025-04-01 18:02:37 +02:00
Florian Rival
20d16b8a57 Add minor improvements to Ask AI
Don't show in changelog
2025-04-01 13:26:14 +02:00
github-actions[bot]
67aa1ce062 Update translations [skip ci] (#7524)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-04-01 10:37:54 +02:00
Florian Rival
1759dda870 Fix formatting 2025-04-01 00:21:01 +02:00
Florian Rival
03dce1d90a Add dialog to report AI message feedback 2025-04-01 00:16:31 +02:00
Florian Rival
4e9556e948 Fix tests and improve wording of tilemaps 2025-03-31 22:53:07 +02:00
D8H
a02b8dcfe0 Add vertical alignement for BitmapText and BBText (#7523) 2025-03-31 21:00:58 +02:00
Florian Rival
416ef44ee1 Improve Ask AI tab
Don't show in changelog
2025-03-31 18:46:48 +02:00
github-actions[bot]
aa90621899 Update translations [skip ci] (#7516)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-31 11:14:33 +02:00
github-actions[bot]
3d3f04f63e Update extension translations [skip ci] (#7521)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-31 10:42:15 +02:00
Clément Pasteau
e1cc21c225 Bump to 5.5.228 (#7515) 2025-03-28 16:47:06 +01:00
github-actions[bot]
9f90bf595e Update translations [skip ci] (#7510)
Co-authored-by: 4ian <1280130+4ian@users.noreply.github.com>
2025-03-28 16:43:58 +01:00
Florian Rival
94d49d8c36 Make variable internal naming consistent and update max height for compact text area fields
Don't show in changelog
2025-03-28 16:34:52 +01:00
github-actions[bot]
1d8c435fe0 Update extension translations [skip ci] (#7514)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-28 15:04:01 +01:00
Clément Pasteau
573eafe777 Fix tab tooltip being stuck when closing tab + improve design (#7513) 2025-03-28 11:33:06 +01:00
Florian Rival
15ff9bedd9 Add "Ask AI" (#7486)
* The "Ask AI" tab allows you to access an AI that is a GDevelop expert. _Think of it as "ChatGPT" but that is trained on GDevelop and knows everything about it._ It can give you advices and guide you through GDevelop, features, extensions and has knowledge of what you use in your game (scenes, objects, behaviors).
  * Unsure how to do something? Ask the AI.
  * Want to get a better understanding of a concept you don't understand? Ask the AI.
  * Have an idea but unsure where to start? Ask the AI.
* The AI gives its answer according to the full knowledge of features, reviewed extensions and game building with GDevelop. It's perfect for beginners or when you want to quickly get an answer without having to search for a long time.
* This is experimental. As with any AI, it can make mistakes or give answers that are wrong or not the best way to do something - you can put a thumb up or thumb down on each answer if you want to report something.
  Feel free to check answers with the members of the community on the forum or on Discord. We'll actively improve the AI according to the results it gives.
* The AI was worked to be concise, efficient and fast. If you have a GDevelop membership (silver, gold, pro) you will have an allowance for free AI request every month. You can unlock more AI requests or get some with a free account with credits.
2025-03-27 15:31:16 +01:00
Clément Pasteau
9431ee7316 Remove useless commits in changelog script (#7511)
Do not show in changelog
2025-03-27 13:58:47 +01:00
Florian Rival
333de61ead Reduce some analytics events frequency (#7512)
Don't show in changelog
2025-03-27 13:19:32 +01:00
Clément Pasteau
1433a5f65c Bump 5.5.227 (#7509)
Do not show in changelog
2025-03-27 10:50:53 +01:00
github-actions[bot]
ab1e566aef Update translations [skip ci] (#7506)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-26 14:54:50 +01:00
Clément Pasteau
1a4f9317d1 Slightly improve guided lessons design on mobile (#7504) 2025-03-26 14:45:58 +01:00
Clément Pasteau
af4a6a9313 Fix "Manage subscription" Profile button not working (#7507) 2025-03-26 14:40:39 +01:00
Florian Rival
5f3066d35a Update physics engine/behavior description (#7505)
Only show in developer changelog
2025-03-25 19:38:11 +01:00
Clément Pasteau
3d4f4c1441 Fix locale import (#7503)
Do not show in changelog
2025-03-25 15:25:51 +01:00
github-actions[bot]
4da5efcff2 Update translations [skip ci] (#7497)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-25 15:00:44 +01:00
Clément Pasteau
dde472fd31 Improve locales import (#7502)
Do not show in changelog
2025-03-25 14:48:42 +01:00
Clément Pasteau
94e8cf2229 Update CrazyGames logo to official version (#7499) 2025-03-24 18:30:24 +01:00
github-actions[bot]
17f1bff1cd Update extension translations [skip ci] (#7498)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-24 18:05:50 +01:00
Clément Pasteau
a0c0c3d7b0 Show possible announcements on Create section (#7496)
Do not show in changelog
2025-03-24 15:08:46 +01:00
github-actions[bot]
41b255fdd9 Update translations [skip ci] (#7490)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2025-03-21 16:37:41 +01:00
D8H
085b425431 Add a deprecation warning on text entry object actions (#7484) 2025-03-21 15:57:11 +01:00
github-actions[bot]
5957738070 Update translations [skip ci] (#7471)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-21 15:44:13 +01:00
Clément Pasteau
7caeae93d6 Fix translation update script (#7489)
Do not show in changelog
2025-03-21 15:23:37 +01:00
Clément Pasteau
ae09ad50ec Automatically translate reviewed extensions and their actions and conditions (#7478) 2025-03-21 15:09:06 +01:00
AlexandreS
495b99356d Add tooltip for tabs (#7482) 2025-03-20 10:27:38 -07:00
D8H
e432a7fa67 Fix extension bug report link (#7483) 2025-03-19 14:58:41 +01:00
AlexandreS
8ba69ce338 Send message to gd.games iframe when soft keyboard opens (#7472) 2025-03-18 09:55:24 -07:00
D8H
767b632db9 Fix the Anchor behavior when the deprecated property is used (#7481) 2025-03-18 17:42:59 +01:00
D8H
49749fbd88 Fix 3D model animations when a negative time scale is used (#7474) 2025-03-14 14:26:06 +01:00
Clément Pasteau
99873e5c76 Fix youtube link (#7470)
Do not show in changelog
2025-03-12 15:41:49 +01:00
github-actions[bot]
3e87e5f76a Update translations [skip ci] (#7467)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2025-03-12 10:00:43 +01:00
Clément Pasteau
be5cc49928 Fix discord role claim & other display issues in the profile (#7468) 2025-03-12 09:48:06 +01:00
Clément Pasteau
4bdf7172a6 Merge pull request #7466 from 4ian/youtube-highlight
Highlight youtube sub in profile
2025-03-11 13:05:39 +01:00
Clément Pasteau
9f9f7824ef Highlight youtube sub in profile 2025-03-11 13:00:10 +01:00
Florian Rival
b24e0b79bd Merge pull request #7465 from 4ian/bump-226
Bump to 5.5.226
2025-03-11 09:44:25 +00:00
Clément Pasteau
827b2cf3d8 Merge pull request #7458 from 4ian/chore/update-translations
[Auto PR] Update translations
2025-03-11 10:43:43 +01:00
ClementPasteau
7a4142a1c9 Update translations [skip ci] 2025-03-11 09:37:46 +00:00
Clément Pasteau
78671abb91 Bump to 5.5.226 2025-03-11 10:37:30 +01:00
Clément Pasteau
11df078b74 Merge pull request #7463 from 4ian/youtube-sub-badge
New badge can be unlocked when subscribing to YouTube channel
2025-03-11 10:30:43 +01:00
Clément Pasteau
9001bfd8e2 Merge pull request #7461 from 4ian/fix-animation-crossfade-switch-problem
fix "is finished" animation condition
2025-03-11 10:26:26 +01:00
Neyl
0d2778c8db Update Model3DRuntimeObject3DRenderer.ts 2025-03-11 09:51:58 +01:00
Neyl
ee98e8a329 Update Model3DRuntimeObject3DRenderer.ts 2025-03-11 09:42:16 +01:00
Clément Pasteau
a2e48fdd6c Fix display on desktop 2025-03-10 18:08:17 +01:00
D8H
187018cdd3 [Spine] Fix "Animation finished" condition (#7464) 2025-03-10 17:57:27 +01:00
Neyl
c7622c3abe Update Model3DRuntimeObject3DRenderer.ts 2025-03-10 16:47:08 +01:00
Clément Pasteau
7dca48b8bd New badge can be unlocked when subscribing to YouTube channel 2025-03-10 16:33:50 +01:00
D8H
e9c625abc6 Automatically rename and delete object instance variables (#7454) 2025-03-10 16:05:39 +01:00
Neyl
71f7b59ab5 nitpicked 2025-03-10 15:10:08 +01:00
Neyl
8630452b89 updated comments 2025-03-10 14:57:57 +01:00
Clément Pasteau
b1a91bdc4c Update player token logic to be fetched on project opening (#7460)
Do not show in changelog
2025-03-10 14:51:33 +01:00
Neyl
638c661138 Update Model3DRuntimeObject3DRenderer.ts 2025-03-10 14:41:03 +01:00
Neyl
5dfd26c6f6 fix animation crossfade issue 2025-03-10 14:39:09 +01:00
D8H
a79e87dc7a Fix 3D sprites being all black (#7459) 2025-03-10 13:06:05 +01:00
ViktorVovk
6490c1c4ad Refactor logic to get file URLs in gdjs.SoundManager (#7433)
Only show in developer changelog

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

View File

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

View File

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

View File

@@ -117,7 +117,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Change the position of the center of _PARAM0_: _PARAM1_ "
"_PARAM2_ (x "
"axis), _PARAM3_ _PARAM4_ (y axis)"),
_("Position/Center"),
_("Position Center"),
"res/actions/position24_black.png",
"res/actions/position_black.png")
.AddParameter("object", _("Object"))
@@ -133,7 +133,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Center X position"),
_("the X position of the center of rotation"),
_("the X position of the center"),
_("Position/Center"),
_("Position Center"),
"res/actions/position24_black.png")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -144,7 +144,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Center Y position"),
_("the Y position of the center of rotation"),
_("the Y position of the center"),
_("Position/Center"),
_("Position Center"),
"res/actions/position24_black.png")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -155,7 +155,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the bounding box (the area encapsulating "
"the object) left position"),
_("the bounding box left position"),
_("Position/Bounding Box"),
_("Position Bounding Box"),
"res/conditions/bounding-box-left_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -166,7 +166,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Bounding box top position"),
_("the bounding box (the area encapsulating the object) top position"),
_("the bounding box top position"),
_("Position/Bounding Box"),
_("Position Bounding Box"),
"res/conditions/bounding-box-top_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -177,7 +177,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the bounding box (the area encapsulating "
"the object) right position"),
_("the bounding box right position"),
_("Position/Bounding Box"),
_("Position Bounding Box"),
"res/conditions/bounding-box-right_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -188,7 +188,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the bounding box (the area encapsulating "
"the object) bottom position"),
_("the bounding box bottom position"),
_("Position/Bounding Box"),
_("Position Bounding Box"),
"res/conditions/bounding-box-bottom_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -199,7 +199,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the bounding box (the area encapsulating "
"the object) center X position"),
_("the bounding box center X position"),
_("Position/Bounding Box"),
_("Position Bounding Box"),
"res/conditions/bounding-box-center_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -210,7 +210,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the bounding box (the area encapsulating "
"the object) center Y position"),
_("the bounding box center Y position"),
_("Position/Bounding Box"),
_("Position Bounding Box"),
"res/conditions/bounding-box-center_black.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number", ParameterOptions::MakeNewOptions());
@@ -415,7 +415,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.MarkAsAdvanced();
obj.AddAction("SetNumberObjectVariable",
_("Change variable value"),
_("Change object variable value"),
_("Modify the number value of an object variable."),
_("the variable _PARAM1_"),
_("Variables"),
@@ -430,7 +430,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.SetRelevantForLayoutEventsOnly();
obj.AddAction("SetStringObjectVariable",
_("Change text variable"),
_("Change object variable value"),
_("Modify the text of an object variable."),
_("the variable _PARAM1_"),
_("Variables"),
@@ -445,7 +445,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.SetRelevantForLayoutEventsOnly();
obj.AddAction("SetBooleanObjectVariable",
_("Change boolean variable"),
_("Change object variable value"),
_("Modify the boolean value of an object variable."),
_("Change the variable _PARAM1_ of _PARAM0_: _PARAM2_"),
_("Variables"),
@@ -461,7 +461,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.SetRelevantForLayoutEventsOnly();
obj.AddCondition("NumberObjectVariable",
_("Variable value"),
_("Object variable value"),
_("Compare the number value of an object variable."),
_("the variable _PARAM1_"),
_("Variables"),
@@ -476,7 +476,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.SetRelevantForLayoutEventsOnly();
obj.AddCondition("StringObjectVariable",
_("Text variable"),
_("Object variable value"),
_("Compare the text of an object variable."),
_("the variable _PARAM1_"),
_("Variables"),
@@ -491,7 +491,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.SetRelevantForLayoutEventsOnly();
obj.AddCondition("BooleanObjectVariable",
_("Boolean variable"),
_("Object variable value"),
_("Compare the boolean value of an object variable."),
_("The variable _PARAM1_ of _PARAM0_ is _PARAM2_"),
_("Variables"),
@@ -574,7 +574,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Check if the specified child of the object "
"structure variable exists."),
_("Child _PARAM2_ of variable _PARAM1_ of _PARAM0_ exists"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("object", _("Object"))
@@ -587,7 +587,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Remove a child"),
_("Remove a child from an object structure variable."),
_("Remove child _PARAM2_ from variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
@@ -601,7 +601,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Remove all the children from the object array or structure "
"variable."),
_("Clear children from variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
@@ -808,10 +808,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction(
"PushStringToObjectVariable",
_("Add text variable"),
_("Add value to object array variable"),
_("Adds a text (string) to the end of an object array variable."),
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
@@ -822,10 +822,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.SetRelevantForLayoutEventsOnly();
obj.AddAction("PushNumberToObjectVariable",
_("Add variable array value"),
_("Add value to object array variable"),
_("Adds a number to the end of an object array variable."),
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
@@ -837,10 +837,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction(
"PushBooleanToObjectVariable",
_("Add boolean variable"),
_("Add value to object array variable"),
_("Adds a boolean to the end of an object array variable."),
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
@@ -856,7 +856,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Add existing variable"),
_("Adds an existing variable to the end of an object array variable."),
_("Add variable _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
@@ -874,7 +874,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Add existing variable"),
_("Adds an existing variable to the end of an object array variable."),
_("Add variable _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
@@ -891,7 +891,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Add text variable"),
_("Adds a text (string) to the end of an object array variable."),
_("Add text _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
@@ -905,7 +905,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Add number variable"),
_("Adds a number to the end of an object array variable."),
_("Add number _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
@@ -920,7 +920,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Add boolean variable"),
_("Adds a boolean to the end of an object array variable."),
_("Add boolean _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
@@ -937,7 +937,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"variable."),
_("Remove variable at index _PARAM2_ from array variable _PARAM1_ of "
"_PARAM0_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
@@ -951,7 +951,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Number of children"),
_("Compare the number of children in an object array variable."),
_("The number of children in the array variable _PARAM1_"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("object", _("Object"))
@@ -966,7 +966,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("First text child"),
_("Get the value of the first element of an object array variable, if "
"it is a text (string) variable."),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
@@ -977,7 +977,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("First number child"),
_("Get the value of the first element of an object array variable, if "
"it is a number variable."),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
@@ -988,7 +988,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Last text child"),
_("Get the value of the last element of an object array variable, if "
"it is a text (string) variable."),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
@@ -999,7 +999,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Last number child"),
_("Get the value of the last element of an object array variable, if "
"it is a number variable."),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array variable"))
@@ -1408,7 +1408,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"VariableChildCount",
_("Number of children"),
_("Number of children in an object array or structure variable"),
_("Variables/Arrays and structures"),
_("Variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Array or structure variable"))

View File

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

View File

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

View File

@@ -79,7 +79,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddAction("SetStringVariable",
_("Change text variable"),
_("Change variable value"),
_("Modify the text (string) of a variable."),
_("the variable _PARAM0_"),
"",
@@ -92,7 +92,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddAction(
"SetBooleanVariable",
_("Change boolean variable"),
_("Change variable value"),
_("Modify the boolean value of a variable."),
_("Change the variable _PARAM0_: _PARAM1_"),
"",
@@ -180,7 +180,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddAction(
"PushString",
_("Add text variable"),
_("Add value to array variable"),
_("Adds a text (string) at the end of a array variable."),
_("Add the value _PARAM1_ to array variable _PARAM0_"),
_("Arrays and structures"),
@@ -193,7 +193,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddAction("PushNumber",
_("Add variable array value"),
_("Add value to array variable"),
_("Adds a number at the end of an array variable."),
_("Add the value _PARAM1_ to array variable _PARAM0_"),
_("Arrays and structures"),
@@ -206,7 +206,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddAction("PushBoolean",
_("Add boolean variable"),
_("Add value to array variable"),
_("Adds a boolean at the end of an array variable."),
_("Add the value _PARAM1_ to array variable _PARAM0_"),
_("Arrays and structures"),
@@ -283,26 +283,28 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Number variable"),
_("Compare the number value of a scene variable."),
_("The number of scene variable _PARAM0_"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddCondition("VarSceneTxt",
_("Text variable"),
_("Compare the text (string) of a scene variable."),
_("The text of scene variable _PARAM0_"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"string", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddCondition(
@@ -310,13 +312,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Boolean variable"),
_("Compare the boolean value of a scene variable."),
_("The boolean value of scene variable _PARAM0_ is _PARAM1_"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true")
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddCondition("VariableChildExists",
@@ -324,13 +327,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Check if the specified child of the scene structure "
"variable exists."),
_("Child _PARAM1_ of scene variable _PARAM0_ exists"),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.AddParameter("string", _("Name of the child"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -339,13 +343,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Check if the specified child of the global structure "
"variable exists."),
_("Child _PARAM1_ of global variable _PARAM0_ exists"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.AddParameter("string", _("Name of the child"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -353,7 +358,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"Variable defined",
"Test if the scene variable exists.",
"Scene variable _PARAM0_ is defined",
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddCodeOnlyParameter("currentScene", "")
@@ -365,13 +370,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Number variable"),
_("Compare the number value of a global variable."),
_("the global variable _PARAM0_"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"number", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -379,13 +385,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Text variable"),
_("Compare the text (string) of a global variable."),
_("the text of the global variable _PARAM0_"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardRelationalOperatorParameters(
"string", ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -394,20 +401,21 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Boolean variable"),
_("Compare the boolean value of a global variable."),
_("The boolean value of global variable _PARAM0_ is _PARAM1_"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true")
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddCondition("VarGlobalDef",
"Variable defined",
"Test if a global variable exists.",
"Global variable _PARAM0_ is defined",
_("External variables/Global variables"),
_("External variables Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddCodeOnlyParameter("currentScene", "")
@@ -420,26 +428,28 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Change number variable"),
_("Modify the number value of a scene variable."),
_("the scene variable _PARAM0_"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction("ModVarSceneTxt",
_("Change text variable"),
_("Modify the text (string) of a scene variable."),
_("the text of scene variable _PARAM0_"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardOperatorParameters("string",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction(
@@ -447,12 +457,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Change boolean variable"),
_("Modify the boolean value of a scene variable."),
_("Set the boolean value of scene variable _PARAM0_ to _PARAM1_"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.AddParameter("trueorfalse", _("New Value:"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction("ToggleSceneVariableAsBoolean",
@@ -461,24 +472,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("If it was true, it will become false, and if it was "
"false it will become true."),
_("Toggle the boolean value of scene variable _PARAM0_"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction("ModVarGlobal",
_("Change number variable"),
_("Modify the number value of a global variable."),
_("the global variable _PARAM0_"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardOperatorParameters("number",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -486,13 +499,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Change text variable"),
_("Modify the text (string) of a global variable."),
_("the text of global variable _PARAM0_"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardOperatorParameters("string",
ParameterOptions::MakeNewOptions())
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -501,12 +515,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Change boolean variable"),
_("Modify the boolean value of a global variable."),
_("Set the boolean value of global variable _PARAM0_ to _PARAM1_"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.AddParameter("trueorfalse", _("New Value:"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction("ToggleGlobalVariableAsBoolean",
@@ -515,11 +530,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("If it was true, it will become false, and if it was "
"false it will become true."),
_("Toggle the boolean value of global variable _PARAM0_"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction(
@@ -527,14 +543,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Remove a child"),
_("Remove a child from a scene structure variable."),
_("Remove child _PARAM1_ from scene structure variable _PARAM0_"),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Structure variable"))
.AddParameter("string", _("Child's name"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction(
@@ -542,14 +559,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Remove a child"),
_("Remove a child from a global structure variable."),
_("Remove child _PARAM1_ from global structure variable _PARAM0_"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Structure variable"))
.AddParameter("string", _("Child's name"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.MarkAsAdvanced()
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction("VariableClearChildren",
@@ -557,12 +575,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Remove all the children from the scene structure or array "
"variable."),
_("Clear children from scene variable _PARAM0_"),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Structure or array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -571,12 +590,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Remove all the children from the global structure or array "
"variable."),
_("Clear children from global variable _PARAM0_"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Structure or array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -585,7 +605,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Adds an existing variable at the end of a scene array "
"variable."),
_("Add variable _PARAM1_ to array variable _PARAM0_"),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
@@ -595,6 +615,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"end of the array."))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -603,13 +624,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Add text variable"),
_("Adds a text (string) at the end of a scene array variable."),
_("Add text _PARAM1_ to array variable _PARAM0_"),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.AddParameter("string", _("Text to add"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -617,13 +639,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Add number variable"),
_("Adds a number at the end of a scene array variable."),
_("Add number _PARAM1_ to array variable _PARAM0_"),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.AddParameter("expression", _("Number to add"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -631,13 +654,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Add boolean variable"),
_("Adds a boolean at the end of a scene array variable."),
_("Add boolean _PARAM1_ to array variable _PARAM0_"),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.AddParameter("trueorfalse", _("Boolean to add"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -647,13 +671,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"variable."),
_("Remove variable at index _PARAM1_ from scene array "
"variable _PARAM0_"),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.AddParameter("expression", _("Index to remove"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -662,7 +687,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Number of children"),
_("Compare the number of children in a scene array variable."),
_("The number of children in the array variable _PARAM0_"),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Array variable"))
@@ -670,6 +695,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"number", ParameterOptions::MakeNewOptions())
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -678,11 +704,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("First text child"),
_("Get the value of the first element of a scene array variable, if "
"it is a text (string)."),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddExpression(
@@ -690,11 +717,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("First number child"),
_("Get the value of the first element of a scene array variable, if "
"it is a number."),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddStrExpression(
@@ -702,11 +730,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Last text child"),
_("Get the value of the last element of a scene array variable, if "
"it is a text (string)."),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddExpression(
@@ -714,11 +743,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Last number child"),
_("Get the value of the last element of a scene array variable, if "
"it is a number."),
_("External variables/Scene variables/Arrays and structures"),
_("External variables Scene variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("scenevar", _("Array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddAction(
@@ -726,7 +756,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Add existing variable"),
_("Adds an existing variable at the end of a global array variable."),
_("Add variable _PARAM1_ to array variable _PARAM0_"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
@@ -736,6 +766,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"end of the array."))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -745,13 +776,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"array variable."),
_("Remove variable at index _PARAM1_ from global array "
"variable _PARAM0_"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.AddParameter("expression", _("Index to remove"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -760,13 +792,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Add text variable"),
_("Adds a text (string) at the end of a global array variable."),
_("Add text _PARAM1_ to array variable _PARAM0_"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.AddParameter("string", _("Text to add"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -774,13 +807,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Add number variable"),
_("Adds a number at the end of a global array variable."),
_("Add number _PARAM1_ to array variable _PARAM0_"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.AddParameter("expression", _("Number to add"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -788,13 +822,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Add boolean variable"),
_("Adds a boolean at the end of a global array variable."),
_("Add boolean _PARAM1_ to array variable _PARAM0_"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.AddParameter("trueorfalse", _("Boolean to add"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -803,7 +838,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Number of children"),
_("Compare the number of children in a global array variable."),
_("The number of children of the array variable _PARAM0_"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Array variable"))
@@ -811,6 +846,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"number", ParameterOptions::MakeNewOptions())
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly()
.SetHidden()
.MarkAsAdvanced();
extension
@@ -818,22 +854,24 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("First text child"),
_("Value of the first element of a global array "
"variable, if it is a text (string) variable."),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddExpression("GlobalVariableFirstNumber",
_("First number child"),
_("Value of the first element of a global array "
"variable, if it is a number variable"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddStrExpression(
@@ -841,11 +879,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Last text child"),
_("Value of the last element of a global array variable, if "
"it is a text (string) variable."),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddExpression(
@@ -853,21 +892,23 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Last number child"),
_("Value of the last element of a global array variable, if "
"it is a number variable"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array variable"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddExpression("GlobalVariableChildCount",
_("Number of children"),
_("Number of children in a global array or "
"structure variable"),
_("External variables/Global variables/Arrays and structures"),
_("External variables Global variables Arrays and structures"),
"res/actions/var.png")
.AddParameter("globalvar", _("Array or structure variable"))
.SetHelpPath("/all-features/variables/structures-and-arrays/")
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddExpression("VariableChildCount",
@@ -883,37 +924,41 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
.AddExpression("Variable",
_("Number variable"),
_("Number value of a scene variable"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddStrExpression("VariableString",
_("Text variable"),
_("Text of a scene variable"),
_("External variables/Scene variables"),
_("External variables Scene variables"),
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddExpression("GlobalVariable",
_("Number variable"),
_("Number value of a global variable"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/actions/var.png")
.AddParameter("globalvar", _("Name of the global variable"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
extension
.AddStrExpression("GlobalVariableString",
_("Text variable"),
_("Text of a global variable"),
_("External variables/Global variables"),
_("External variables Global variables"),
"res/actions/var.png")
.AddParameter("globalvar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
.SetRelevantForFunctionEventsOnly()
.SetHidden();
}
} // namespace gd

View File

@@ -101,7 +101,7 @@ const gd::String &ValueTypeMetadata::ConvertPropertyTypeToValueType(
} else if (propertyType == "KeyboardKey") {
return keyboardKeyValueType;
}
// For "String", "Resource" or default
// For "String", "Resource", "MultilineString" or default
return stringValueType;
};

View File

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

View File

@@ -13,11 +13,11 @@
#include "GDCore/CommonTools.h"
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
#include "GDCore/Extensions/Metadata/SourceFileMetadata.h"
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
#include "GDCore/Extensions/Metadata/EventMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionOrExpressionGroupMetadata.h"
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Metadata/SourceFileMetadata.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/String.h"
#include "GDCore/Tools/VersionPriv.h"
@@ -440,12 +440,6 @@ class GD_CORE_API PlatformExtension {
*/
bool IsDeprecated() const { return deprecated; }
/**
* \brief Return true if the extension is a standard extension that cannot be
* deactivated
*/
bool IsBuiltin() const;
/**
* \brief Get the namespace of the extension.
* \note The namespace is simply the name of the extension concatenated with
@@ -640,12 +634,6 @@ class GD_CORE_API PlatformExtension {
}
///@}
/**
* \brief Return the name of all the extensions which are considered provided
* by platforms.
*/
static std::vector<gd::String> GetBuiltinExtensionsNames();
/**
* \brief Get the string used to separate the name of the
* instruction/expression and the extension.

View File

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

View File

@@ -3,9 +3,10 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GroupVariableHelper.h"
#include "ObjectVariableHelper.h"
#include "GDCore/IDE/WholeProjectRefactorer.h"
#include "GDCore/Project/InitialInstancesContainer.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectGroup.h"
#include "GDCore/Project/ObjectsContainer.h"
@@ -16,7 +17,7 @@
namespace gd {
void GroupVariableHelper::FillAnyVariableBetweenObjects(
void ObjectVariableHelper::FillAnyVariableBetweenObjects(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer,
const gd::ObjectGroup &objectGroup) {
@@ -65,7 +66,7 @@ void GroupVariableHelper::FillAnyVariableBetweenObjects(
}
}
gd::VariablesContainer GroupVariableHelper::MergeVariableContainers(
gd::VariablesContainer ObjectVariableHelper::MergeVariableContainers(
const gd::ObjectsContainersList &objectsContainersList,
const gd::ObjectGroup &objectGroup) {
gd::VariablesContainer mergedVariablesContainer;
@@ -113,7 +114,7 @@ gd::VariablesContainer GroupVariableHelper::MergeVariableContainers(
return mergedVariablesContainer;
}
void GroupVariableHelper::FillMissingGroupVariablesToObjects(
void ObjectVariableHelper::FillMissingGroupVariablesToObjects(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer, const gd::ObjectGroup &objectGroup,
const gd::SerializerElement &originalSerializedVariables) {
@@ -145,7 +146,7 @@ void GroupVariableHelper::FillMissingGroupVariablesToObjects(
// TODO Handle position changes for group variables.
// We could try to change the order of object variables in a way that the next
// call to MergeVariableContainers rebuild them in the same order.
void GroupVariableHelper::ApplyChangesToObjects(
void ObjectVariableHelper::ApplyChangesToObjects(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer,
const gd::VariablesContainer &groupVariablesContainer,
@@ -193,4 +194,48 @@ void GroupVariableHelper::ApplyChangesToObjects(
}
}
void ObjectVariableHelper::ApplyChangesToObjectInstances(
gd::VariablesContainer &objectVariablesContainer,
gd::InitialInstancesContainer &initialInstancesContainer,
const gd::String &objectName, const gd::VariablesChangeset &changeset) {
initialInstancesContainer.IterateOverInstances(
[&objectVariablesContainer, &objectName,
&changeset](gd::InitialInstance &instance) {
if (instance.GetObjectName() == objectName) {
auto &destinationVariablesContainer = instance.GetVariables();
for (const gd::String &variableName :
changeset.removedVariableNames) {
destinationVariablesContainer.Remove(variableName);
}
for (const gd::String &variableName : changeset.addedVariableNames) {
// Instance variables may already exist with another type.
if (destinationVariablesContainer.Has(variableName) &&
destinationVariablesContainer.Get(variableName).GetType() !=
objectVariablesContainer.Get(variableName).GetType()) {
destinationVariablesContainer.Remove(variableName);
}
}
for (const auto &pair : changeset.oldToNewVariableNames) {
const gd::String &oldVariableName = pair.first;
const gd::String &newVariableName = pair.second;
if (destinationVariablesContainer.Has(newVariableName)) {
// It can happens if an instance already had the variable.
destinationVariablesContainer.Remove(oldVariableName);
} else {
destinationVariablesContainer.Rename(oldVariableName,
newVariableName);
}
}
// Apply type changes
for (const gd::String &variableName :
changeset.valueChangedVariableNames) {
if (destinationVariablesContainer.Has(variableName) &&
destinationVariablesContainer.Get(variableName).GetType() !=
objectVariablesContainer.Get(variableName).GetType()) {
destinationVariablesContainer.Remove(variableName);
}
}
}
});
}
} // namespace gd

View File

@@ -8,6 +8,7 @@
#include "GDCore/Project/VariablesContainer.h"
namespace gd {
class InitialInstancesContainer;
class ObjectsContainersList;
class ObjectsContainer;
class ObjectGroup;
@@ -22,7 +23,7 @@ namespace gd {
*
* This is used by the object group variable editor.
*/
class GD_CORE_API GroupVariableHelper {
class GD_CORE_API ObjectVariableHelper {
public:
/**
* Copy every variable from every object of the group to the other objects
@@ -70,6 +71,17 @@ public:
const gd::VariablesContainer &groupVariablesContainer,
const gd::ObjectGroup &objectGroup,
const gd::VariablesChangeset &changeset);
static void ApplyChangesToObjectInstances(
gd::VariablesContainer &objectVariablesContainer,
gd::InitialInstancesContainer &initialInstancesContainer,
const gd::String &objectName, const gd::VariablesChangeset &changeset);
private:
static void ApplyChangesToVariableContainer(
const gd::VariablesContainer &originalVariablesContainer,
gd::VariablesContainer &destinationVariablesContainer,
const gd::VariablesChangeset &changeset, bool shouldApplyValueChanges);
};
} // namespace gd
} // namespace gd

View File

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

View File

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

View File

@@ -11,7 +11,7 @@
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/DependenciesAnalyzer.h"
#include "GDCore/IDE/GroupVariableHelper.h"
#include "GDCore/IDE/ObjectVariableHelper.h"
#include "GDCore/IDE/EventBasedBehaviorBrowser.h"
#include "GDCore/IDE/EventBasedObjectBrowser.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
@@ -314,9 +314,16 @@ void WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
variablesContainer.SerializeTo(editedSerializedVariables);
variablesContainer.UnserializeFrom(originalSerializedVariables);
// Rename and remove variables
// Rename variables
// Pass an empty set to avoid deletion of actions/conditions or events using
// them.
// While we support refactoring that would remove all references (actions,
// conditions...) it's both a bit dangerous for the user and we would need to
// show the user what will be removed before doing so. For now, just clear the
// removed variables so they don't trigger any refactoring.
std::unordered_set<gd::String> removedVariableNames;
gd::EventsVariableReplacer eventsVariableReplacer(
project.GetCurrentPlatform(), changeset, changeset.removedVariableNames,
project.GetCurrentPlatform(), changeset, removedVariableNames,
variablesContainer);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsVariableReplacer);
@@ -333,9 +340,25 @@ void WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project, eventsVariableInstructionTypeSwitcher);
}
// TODO Apply the refactor to external layouts.
void WholeProjectRefactorer::ApplyRefactoringForObjectVariablesContainer(
gd::Project &project, gd::VariablesContainer &objectVariablesContainer,
gd::InitialInstancesContainer &initialInstancesContainer,
const gd::String &objectName, const gd::VariablesChangeset &changeset,
const gd::SerializerElement &originalSerializedVariables) {
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project, objectVariablesContainer, changeset,
originalSerializedVariables);
gd::ObjectVariableHelper::ApplyChangesToObjectInstances(
objectVariablesContainer, initialInstancesContainer, objectName,
changeset);
}
void WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
gd::Project &project, gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer,
gd::InitialInstancesContainer &initialInstancesContainer,
const gd::VariablesContainer &groupVariablesContainer,
const gd::ObjectGroup &objectGroup,
const gd::VariablesChangeset &changeset,
@@ -355,11 +378,15 @@ void WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
}
auto &object = hasObject ? objectsContainer.GetObject(objectName)
: globalObjectsContainer.GetObject(objectName);
auto &variablesContainer = object.GetVariables();
auto &objectVariablesContainer = object.GetVariables();
gd::ObjectVariableHelper::ApplyChangesToObjectInstances(
objectVariablesContainer, initialInstancesContainer, objectName,
changeset);
gd::EventsVariableReplacer eventsVariableReplacer(
project.GetCurrentPlatform(), changeset,
removedVariableNames, variablesContainer);
removedVariableNames, objectVariablesContainer);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsVariableReplacer);
}
@@ -372,12 +399,12 @@ void WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
eventsVariableReplacer);
// Apply changes to objects.
gd::GroupVariableHelper::FillMissingGroupVariablesToObjects(
gd::ObjectVariableHelper::FillMissingGroupVariablesToObjects(
globalObjectsContainer,
objectsContainer,
objectGroup,
originalSerializedVariables);
gd::GroupVariableHelper::ApplyChangesToObjects(
gd::ObjectVariableHelper::ApplyChangesToObjects(
globalObjectsContainer, objectsContainer, groupVariablesContainer,
objectGroup, changeset);

View File

@@ -32,6 +32,7 @@ class UnfilledRequiredBehaviorPropertyProblem;
class ProjectBrowser;
class SerializerElement;
class ProjectScopedContainers;
class InitialInstancesContainer;
struct VariablesRenamingChangesetNode;
} // namespace gd
@@ -80,13 +81,23 @@ class GD_CORE_API WholeProjectRefactorer {
/**
* \brief Refactor the project according to the changes (renaming or deletion)
* made to variables.
* made to global or scene variables.
*/
static void ApplyRefactoringForVariablesContainer(
gd::Project &project, gd::VariablesContainer &variablesContainer,
const gd::VariablesChangeset &changeset,
const gd::SerializerElement &originalSerializedVariables);
/**
* \brief Refactor the project according to the changes (renaming or deletion)
* made to object variables.
*/
static void ApplyRefactoringForObjectVariablesContainer(
gd::Project &project, gd::VariablesContainer &objectVariablesContainer,
gd::InitialInstancesContainer &initialInstancesContainer,
const gd::String &objectName, const gd::VariablesChangeset &changeset,
const gd::SerializerElement &originalSerializedVariables);
/**
* \brief Refactor the project according to the changes (renaming or deletion)
* made to variables of a group.
@@ -94,6 +105,7 @@ class GD_CORE_API WholeProjectRefactorer {
static void ApplyRefactoringForGroupVariablesContainer(
gd::Project &project, gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer,
gd::InitialInstancesContainer &initialInstancesContainer,
const gd::VariablesContainer &groupVariablesContainer,
const gd::ObjectGroup &objectGroup,
const gd::VariablesChangeset &changeset,

View File

@@ -47,6 +47,7 @@ void EventsFunctionsExtension::Init(const gd::EventsFunctionsExtension& other) {
previewIconUrl = other.previewIconUrl;
iconUrl = other.iconUrl;
helpPath = other.helpPath;
gdevelopVersion = other.gdevelopVersion;
eventsFunctionsContainer = other.eventsFunctionsContainer;
eventsBasedBehaviors = other.eventsBasedBehaviors;
eventsBasedObjects = other.eventsBasedObjects;
@@ -81,6 +82,7 @@ void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
element.SetAttribute("previewIconUrl", previewIconUrl);
element.SetAttribute("iconUrl", iconUrl);
element.SetAttribute("helpPath", helpPath);
element.SetAttribute("gdevelopVersion", gdevelopVersion);
auto& dependenciesElement = element.AddChild("dependencies");
dependenciesElement.ConsiderAsArray();
for (auto& dependency : dependencies)
@@ -126,6 +128,7 @@ void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
previewIconUrl = element.GetStringAttribute("previewIconUrl");
iconUrl = element.GetStringAttribute("iconUrl");
helpPath = element.GetStringAttribute("helpPath");
gdevelopVersion = element.GetStringAttribute("gdevelopVersion");
if (element.HasChild("origin")) {
gd::String originName =

View File

@@ -134,6 +134,19 @@ class GD_CORE_API EventsFunctionsExtension {
return *this;
}
/**
* \brief Get the GDevelop version required by this extension.
*/
const gd::String& GetGDevelopVersion() const { return gdevelopVersion; };
/**
* \brief Set the GDevelop version required by this extension.
*/
EventsFunctionsExtension& SetGDevelopVersion(const gd::String& gdevelopVersion_) {
gdevelopVersion = gdevelopVersion_;
return *this;
}
/**
* \brief Return a reference to the list of the events based behaviors.
*/
@@ -385,6 +398,7 @@ class GD_CORE_API EventsFunctionsExtension {
gd::String iconUrl;
gd::String helpPath; ///< The relative path to the help for this extension in
///< the documentation (or an absolute URL).
gd::String gdevelopVersion;
gd::SerializableWithNameList<EventsBasedBehavior> eventsBasedBehaviors;
gd::SerializableWithNameList<EventsBasedObject> eventsBasedObjects;
std::vector<gd::DependencyMetadata> dependencies;

View File

@@ -41,6 +41,11 @@ void InitialInstancesContainer::IterateOverInstances(
for (auto& instance : initialInstances) func(instance);
}
void InitialInstancesContainer::IterateOverInstances(
const std::function< void(gd::InitialInstance &) >& func) {
for (auto& instance : initialInstances) func(instance);
}
void InitialInstancesContainer::IterateOverInstancesWithZOrdering(
gd::InitialInstanceFunctor& func, const gd::String& layerName) {
std::vector<std::reference_wrapper<gd::InitialInstance>> sortedInstances;

View File

@@ -87,6 +87,13 @@ class GD_CORE_API InitialInstancesContainer {
*/
void IterateOverInstances(InitialInstanceFunctor &func);
/**
* \brief Apply \a func to each instance of the container.
* \see InitialInstanceFunctor
*/
void IterateOverInstances(
const std::function< void(gd::InitialInstance &) >& func);
/**
* Get the instances on the specified layer,
* sort them regarding their Z order and then apply \a func on them.

View File

@@ -6,6 +6,7 @@
#if defined(EMSCRIPTEN)
#include <emscripten.h>
#include "GDCore/String.h"
namespace gd {
@@ -31,5 +32,10 @@ gd::String GetTranslation(const char* str) { // TODO: Inline?
str);
return gd::String(translatedStr); // TODO: Is copying necessary?
}
gd::String GetTranslation(const gd::String& str) {
return GetTranslation(str.c_str());
}
} // namespace gd
#endif

View File

@@ -8,10 +8,10 @@
/** @file
* Provide a way to mark strings to be translated.
*
*
* Strings to be translated in GDevelop Core codebase
* are marked with the underscore macro, for example: _("Hello World").
*
*
* The macro is then defined to be using the translation function
* of the underlying platform (Emscripten for GDevelop 5).
*/
@@ -26,8 +26,10 @@
#endif
namespace gd {
gd::String GetTranslation(const gd::String& str);
gd::String GetTranslation(const char* str);
}
} // namespace gd
#define _(s) gd::GetTranslation(u8##s)

View File

@@ -116,14 +116,11 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
REQUIRE(setterEvent.GetConditions().size() == 0);
REQUIRE(setterEvent.GetActions().size() == 1);
auto &setterAction = setterEvent.GetActions().at(0);
REQUIRE(
setterAction.GetType() ==
"MyEventsExtension::MyEventsBasedBehavior::SetPropertyMovementAngle");
REQUIRE(setterAction.GetParametersCount() == 4);
REQUIRE(setterAction.GetParameter(0).GetPlainString() == "Object");
REQUIRE(setterAction.GetParameter(1).GetPlainString() == "Behavior");
REQUIRE(setterAction.GetParameter(2).GetPlainString() == "=");
REQUIRE(setterAction.GetParameter(3).GetPlainString() == "Value");
REQUIRE(setterAction.GetType() == "SetNumberVariable");
REQUIRE(setterAction.GetParametersCount() == 3);
REQUIRE(setterAction.GetParameter(0).GetPlainString() == "MovementAngle");
REQUIRE(setterAction.GetParameter(1).GetPlainString() == "=");
REQUIRE(setterAction.GetParameter(2).GetPlainString() == "Value");
}
}
@@ -206,12 +203,12 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
REQUIRE(getterEvent.GetActions().size() == 1);
auto &getterCondition = getterEvent.GetConditions().at(0);
REQUIRE(getterCondition.GetType() ==
"MyEventsExtension::MyEventsBasedBehavior::PropertyRotate");
REQUIRE(getterCondition.GetType() == "BooleanVariable");
REQUIRE(!getterCondition.IsInverted());
REQUIRE(getterCondition.GetParametersCount() == 2);
REQUIRE(getterCondition.GetParameter(0).GetPlainString() == "Object");
REQUIRE(getterCondition.GetParameter(1).GetPlainString() == "Behavior");
REQUIRE(getterCondition.GetParametersCount() == 3);
REQUIRE(getterCondition.GetParameter(0).GetPlainString() == "Rotate");
REQUIRE(getterCondition.GetParameter(1).GetPlainString() == "True");
REQUIRE(getterCondition.GetParameter(2).GetPlainString() == "");
auto &getterAction = getterEvent.GetActions().at(0);
REQUIRE(getterAction.GetType() == "SetReturnBoolean");
@@ -257,19 +254,19 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
REQUIRE(setterNoEvent.GetActions().size() == 1);
auto &setterNoCondition = setterNoEvent.GetConditions().at(0);
REQUIRE(setterNoCondition.GetType() == "GetArgumentAsBoolean");
REQUIRE(setterNoCondition.IsInverted());
REQUIRE(setterNoCondition.GetParametersCount() == 1);
REQUIRE(setterNoCondition.GetParameter(0).GetPlainString() ==
"\"Value\"");
REQUIRE(setterNoCondition.GetType() == "BooleanVariable");
REQUIRE(!setterNoCondition.IsInverted());
REQUIRE(setterNoCondition.GetParametersCount() == 3);
REQUIRE(setterNoCondition.GetParameter(0).GetPlainString() == "Value");
REQUIRE(setterNoCondition.GetParameter(1).GetPlainString() == "False");
REQUIRE(setterNoCondition.GetParameter(2).GetPlainString() == "");
auto &setterNoAction = setterNoEvent.GetActions().at(0);
REQUIRE(setterNoAction.GetType() ==
"MyEventsExtension::MyEventsBasedBehavior::SetPropertyRotate");
REQUIRE(setterNoAction.GetType() == "SetBooleanVariable");
REQUIRE(setterNoAction.GetParametersCount() == 3);
REQUIRE(setterNoAction.GetParameter(0).GetPlainString() == "Object");
REQUIRE(setterNoAction.GetParameter(1).GetPlainString() == "Behavior");
REQUIRE(setterNoAction.GetParameter(2).GetPlainString() == "no");
REQUIRE(setterNoAction.GetParameter(0).GetPlainString() == "Rotate");
REQUIRE(setterNoAction.GetParameter(1).GetPlainString() == "False");
REQUIRE(setterNoAction.GetParameter(2).GetPlainString() == "");
auto &setterYesEvent =
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().GetEvent(1));
@@ -277,19 +274,19 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
REQUIRE(setterYesEvent.GetActions().size() == 1);
auto &setterYesCondition = setterYesEvent.GetConditions().at(0);
REQUIRE(setterYesCondition.GetType() == "GetArgumentAsBoolean");
REQUIRE(setterYesCondition.GetType() == "BooleanVariable");
REQUIRE(!setterYesCondition.IsInverted());
REQUIRE(setterYesCondition.GetParametersCount() == 1);
REQUIRE(setterYesCondition.GetParameter(0).GetPlainString() ==
"\"Value\"");
REQUIRE(setterYesCondition.GetParametersCount() == 3);
REQUIRE(setterYesCondition.GetParameter(0).GetPlainString() == "Value");
REQUIRE(setterYesCondition.GetParameter(1).GetPlainString() == "True");
REQUIRE(setterYesCondition.GetParameter(2).GetPlainString() == "");
auto &setterYesAction = setterYesEvent.GetActions().at(0);
REQUIRE(setterYesAction.GetType() ==
"MyEventsExtension::MyEventsBasedBehavior::SetPropertyRotate");
REQUIRE(setterYesAction.GetType() == "SetBooleanVariable");
REQUIRE(setterYesAction.GetParametersCount() == 3);
REQUIRE(setterYesAction.GetParameter(0).GetPlainString() == "Object");
REQUIRE(setterYesAction.GetParameter(1).GetPlainString() == "Behavior");
REQUIRE(setterYesAction.GetParameter(2).GetPlainString() == "yes");
REQUIRE(setterYesAction.GetParameter(0).GetPlainString() == "Rotate");
REQUIRE(setterYesAction.GetParameter(1).GetPlainString() == "True");
REQUIRE(setterYesAction.GetParameter(2).GetPlainString() == "");
}
}
SECTION("Can generate functions for a number property in an object") {
@@ -366,11 +363,9 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
REQUIRE(setterEvent.GetConditions().size() == 0);
REQUIRE(setterEvent.GetActions().size() == 1);
auto &setterAction = setterEvent.GetActions().at(0);
REQUIRE(
setterAction.GetType() ==
"MyEventsExtension::MyEventsBasedObject::SetPropertyMovementAngle");
REQUIRE(setterAction.GetType() == "SetNumberVariable");
REQUIRE(setterAction.GetParametersCount() == 3);
REQUIRE(setterAction.GetParameter(0).GetPlainString() == "Object");
REQUIRE(setterAction.GetParameter(0).GetPlainString() == "MovementAngle");
REQUIRE(setterAction.GetParameter(1).GetPlainString() == "=");
REQUIRE(setterAction.GetParameter(2).GetPlainString() == "Value");
}
@@ -454,11 +449,12 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
REQUIRE(getterEvent.GetActions().size() == 1);
auto &getterCondition = getterEvent.GetConditions().at(0);
REQUIRE(getterCondition.GetType() ==
"MyEventsExtension::MyEventsBasedObject::PropertyRotate");
REQUIRE(getterCondition.GetType() == "BooleanVariable");
REQUIRE(!getterCondition.IsInverted());
REQUIRE(getterCondition.GetParametersCount() == 1);
REQUIRE(getterCondition.GetParameter(0).GetPlainString() == "Object");
REQUIRE(getterCondition.GetParametersCount() == 3);
REQUIRE(getterCondition.GetParameter(0).GetPlainString() == "Rotate");
REQUIRE(getterCondition.GetParameter(1).GetPlainString() == "True");
REQUIRE(getterCondition.GetParameter(2).GetPlainString() == "");
auto &getterAction = getterEvent.GetActions().at(0);
REQUIRE(getterAction.GetType() == "SetReturnBoolean");
@@ -500,18 +496,19 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
REQUIRE(setterNoEvent.GetActions().size() == 1);
auto &setterNoCondition = setterNoEvent.GetConditions().at(0);
REQUIRE(setterNoCondition.GetType() == "GetArgumentAsBoolean");
REQUIRE(setterNoCondition.IsInverted());
REQUIRE(setterNoCondition.GetParametersCount() == 1);
REQUIRE(setterNoCondition.GetParameter(0).GetPlainString() ==
"\"Value\"");
REQUIRE(setterNoCondition.GetType() == "BooleanVariable");
REQUIRE(!setterNoCondition.IsInverted());
REQUIRE(setterNoCondition.GetParametersCount() == 3);
REQUIRE(setterNoCondition.GetParameter(0).GetPlainString() == "Value");
REQUIRE(setterNoCondition.GetParameter(1).GetPlainString() == "False");
REQUIRE(setterNoCondition.GetParameter(2).GetPlainString() == "");
auto &setterNoAction = setterNoEvent.GetActions().at(0);
REQUIRE(setterNoAction.GetType() ==
"MyEventsExtension::MyEventsBasedObject::SetPropertyRotate");
REQUIRE(setterNoAction.GetParametersCount() == 2);
REQUIRE(setterNoAction.GetParameter(0).GetPlainString() == "Object");
REQUIRE(setterNoAction.GetParameter(1).GetPlainString() == "no");
REQUIRE(setterNoAction.GetType() == "SetBooleanVariable");
REQUIRE(setterNoAction.GetParametersCount() == 3);
REQUIRE(setterNoAction.GetParameter(0).GetPlainString() == "Rotate");
REQUIRE(setterNoAction.GetParameter(1).GetPlainString() == "False");
REQUIRE(setterNoAction.GetParameter(2).GetPlainString() == "");
auto &setterYesEvent =
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().GetEvent(1));
@@ -519,18 +516,19 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
REQUIRE(setterYesEvent.GetActions().size() == 1);
auto &setterYesCondition = setterYesEvent.GetConditions().at(0);
REQUIRE(setterYesCondition.GetType() == "GetArgumentAsBoolean");
REQUIRE(setterYesCondition.GetType() == "BooleanVariable");
REQUIRE(!setterYesCondition.IsInverted());
REQUIRE(setterYesCondition.GetParametersCount() == 1);
REQUIRE(setterYesCondition.GetParameter(0).GetPlainString() ==
"\"Value\"");
REQUIRE(setterYesCondition.GetParametersCount() == 3);
REQUIRE(setterYesCondition.GetParameter(0).GetPlainString() == "Value");
REQUIRE(setterYesCondition.GetParameter(1).GetPlainString() == "True");
REQUIRE(setterYesCondition.GetParameter(2).GetPlainString() == "");
auto &setterYesAction = setterYesEvent.GetActions().at(0);
REQUIRE(setterYesAction.GetType() ==
"MyEventsExtension::MyEventsBasedObject::SetPropertyRotate");
REQUIRE(setterYesAction.GetParametersCount() == 2);
REQUIRE(setterYesAction.GetParameter(0).GetPlainString() == "Object");
REQUIRE(setterYesAction.GetParameter(1).GetPlainString() == "yes");
REQUIRE(setterYesAction.GetType() == "SetBooleanVariable");
REQUIRE(setterYesAction.GetParametersCount() == 3);
REQUIRE(setterYesAction.GetParameter(0).GetPlainString() == "Rotate");
REQUIRE(setterYesAction.GetParameter(1).GetPlainString() == "True");
REQUIRE(setterYesAction.GetParameter(2).GetPlainString() == "");
}
}
@@ -588,9 +586,11 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
REQUIRE(setterEvent.GetConditions().size() == 0);
REQUIRE(setterEvent.GetActions().size() == 1);
auto &setterAction = setterEvent.GetActions().at(0);
REQUIRE(setterAction.GetType() ==
"MyEventsExtension::MyEventsBasedBehavior::"
"SetSharedPropertyMovementAngle");
REQUIRE(setterAction.GetType() == "SetNumberVariable");
REQUIRE(setterAction.GetParametersCount() == 3);
REQUIRE(setterAction.GetParameter(0).GetPlainString() == "MovementAngle");
REQUIRE(setterAction.GetParameter(1).GetPlainString() == "=");
REQUIRE(setterAction.GetParameter(2).GetPlainString() == "Value");
}
}

View File

@@ -19,7 +19,7 @@
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/GroupVariableHelper.h"
#include "GDCore/IDE/ObjectVariableHelper.h"
#include "GDCore/IDE/WholeProjectRefactorer.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
@@ -760,33 +760,33 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
// Check the first layout is updated.
{
REQUIRE(event.GetActions().GetCount() == 19);
REQUIRE(event.GetActions().GetCount() == 40);
// clang-format off
// All the actions using the removed variables are gone.
REQUIRE(event.GetActions()[0].GetParameter(0).GetPlainString() == "1 + MySceneVariable2");
REQUIRE(event.GetActions()[1].GetParameter(0).GetPlainString() == "1 + Object2.MyObjectVariable");
REQUIRE(event.GetActions()[2].GetParameter(0).GetPlainString() == "1 + Object2.MyObjectStructureVariable.MyChild");
REQUIRE(event.GetActions()[3].GetParameter(0).GetPlainString() == "1 + MySceneStructureVariable2.MyChild");
REQUIRE(event.GetActions()[4].GetParameter(0).GetPlainString() == "1 + MyGlobalVariable2");
REQUIRE(event.GetActions()[5].GetParameter(0).GetPlainString() == "1 + MyGlobalStructureVariable2.MyChild");
REQUIRE(event.GetActions()[6].GetParameter(0).GetPlainString() == "1 + MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object2, MyObjectVariable, Object2, MyObjectVariable)");
REQUIRE(event.GetActions()[7].GetParameter(0).GetPlainString() == "1 + MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object2, MyObjectStructureVariable.MyChild, Object2, MyObjectStructureVariable.MyChild)");
REQUIRE(event.GetActions()[8].GetParameter(0).GetPlainString() == "1 + Object2.GetObjectVariableAsNumber(MyObjectVariable)");
REQUIRE(event.GetActions()[9].GetParameter(0).GetPlainString() == "1 + Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild)");
REQUIRE(event.GetActions()[10].GetParameter(0).GetPlainString() == "1 + Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild.GrandChild)");
REQUIRE(event.GetActions()[11].GetParameter(0).GetPlainString() == "1 + MyExtension::GetGlobalVariableAsNumber(MyGlobalVariable2)");
REQUIRE(event.GetActions()[12].GetParameter(0).GetPlainString() == "1 + MyExtension::GetVariableAsNumber(MySceneVariable2)");
REQUIRE(event.GetActions()[13].GetParameter(0).GetPlainString() == "1 + MyExtension::GetVariableAsNumber(SharedVariableName)");
REQUIRE(event.GetActions()[14].GetParameter(0).GetPlainString() == "1 + MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable2.MyChild)");
REQUIRE(event.GetActions()[15].GetParameter(0).GetPlainString() == "1 + MyExtension::GetVariableAsNumber(MySceneStructureVariable2.MyChild)");
REQUIRE(event.GetActions()[16].GetParameter(0).GetPlainString() == "1 + MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable2.MyChild.GrandChild)");
REQUIRE(event.GetActions()[17].GetParameter(0).GetPlainString() == "1 + MyExtension::GetVariableAsNumber(MySceneStructureVariable2.MyChild.GrandChild)");
// All the actions using the removed variables are kept.
REQUIRE(event.GetActions()[1].GetParameter(0).GetPlainString() == "1 + MySceneVariable2");
REQUIRE(event.GetActions()[3].GetParameter(0).GetPlainString() == "1 + Object2.MyObjectVariable");
REQUIRE(event.GetActions()[5].GetParameter(0).GetPlainString() == "1 + Object2.MyObjectStructureVariable.MyChild");
REQUIRE(event.GetActions()[7].GetParameter(0).GetPlainString() == "1 + MySceneStructureVariable2.MyChild");
REQUIRE(event.GetActions()[9].GetParameter(0).GetPlainString() == "1 + MyGlobalVariable2");
REQUIRE(event.GetActions()[11].GetParameter(0).GetPlainString() == "1 + MyGlobalStructureVariable2.MyChild");
REQUIRE(event.GetActions()[13].GetParameter(0).GetPlainString() == "1 + MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object2, MyObjectVariable, Object2, MyObjectVariable)");
REQUIRE(event.GetActions()[15].GetParameter(0).GetPlainString() == "1 + MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object2, MyObjectStructureVariable.MyChild, Object2, MyObjectStructureVariable.MyChild)");
REQUIRE(event.GetActions()[17].GetParameter(0).GetPlainString() == "1 + Object2.GetObjectVariableAsNumber(MyObjectVariable)");
REQUIRE(event.GetActions()[19].GetParameter(0).GetPlainString() == "1 + Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild)");
REQUIRE(event.GetActions()[21].GetParameter(0).GetPlainString() == "1 + Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild.GrandChild)");
REQUIRE(event.GetActions()[23].GetParameter(0).GetPlainString() == "1 + MyExtension::GetGlobalVariableAsNumber(MyGlobalVariable2)");
REQUIRE(event.GetActions()[26].GetParameter(0).GetPlainString() == "1 + MyExtension::GetVariableAsNumber(MySceneVariable2)");
REQUIRE(event.GetActions()[27].GetParameter(0).GetPlainString() == "1 + MyExtension::GetVariableAsNumber(SharedVariableName)");
REQUIRE(event.GetActions()[29].GetParameter(0).GetPlainString() == "1 + MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable2.MyChild)");
REQUIRE(event.GetActions()[31].GetParameter(0).GetPlainString() == "1 + MyExtension::GetVariableAsNumber(MySceneStructureVariable2.MyChild)");
REQUIRE(event.GetActions()[33].GetParameter(0).GetPlainString() == "1 + MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable2.MyChild.GrandChild)");
REQUIRE(event.GetActions()[35].GetParameter(0).GetPlainString() == "1 + MyExtension::GetVariableAsNumber(MySceneStructureVariable2.MyChild.GrandChild)");
REQUIRE(event.GetActions()[18].GetParameter(0).GetPlainString() == "MySceneVariable2");
REQUIRE(event.GetActions()[18].GetParameter(1).GetPlainString() == "MyGlobalVariable2");
REQUIRE(event.GetActions()[18].GetParameter(2).GetPlainString() == "Object2");
REQUIRE(event.GetActions()[18].GetParameter(3).GetPlainString() == "MyObjectVariable");
REQUIRE(event.GetActions()[39].GetParameter(0).GetPlainString() == "MySceneVariable2");
REQUIRE(event.GetActions()[39].GetParameter(1).GetPlainString() == "MyGlobalVariable2");
REQUIRE(event.GetActions()[39].GetParameter(2).GetPlainString() == "Object2");
REQUIRE(event.GetActions()[39].GetParameter(3).GetPlainString() == "MyObjectVariable");
// clang-format on
}
@@ -1021,6 +1021,140 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
"MyVariable.MyRenamedChild");
}
SECTION("Can rename an object variable") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &scene = project.InsertNewLayout("Scene", 0);
auto &object = scene.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object", 0);
object.GetVariables().InsertNew("MyVariable").SetValue(123);
auto &instance = scene.GetInitialInstances().InsertNewInitialInstance();
instance.SetObjectName("Object");
instance.GetVariables().InsertNew("MyVariable").SetValue(456);
gd::StandardEvent &event =
dynamic_cast<gd::StandardEvent &>(scene.GetEvents().InsertNewEvent(
project, "BuiltinCommonInstructions::Standard"));
{
gd::Instruction action;
action.SetType("SetNumberObjectVariable");
action.SetParametersCount(4);
action.SetParameter(0, gd::Expression("Object"));
action.SetParameter(1, gd::Expression("MyVariable"));
action.SetParameter(2, gd::Expression("="));
action.SetParameter(3, gd::Expression("Object.MyVariable"));
event.GetActions().Insert(action);
}
// Do the changes and launch the refactoring.
object.GetVariables().ResetPersistentUuid();
gd::SerializerElement originalSerializedVariables;
object.GetVariables().SerializeTo(originalSerializedVariables);
object.GetVariables().Rename("MyVariable", "MyRenamedVariable");
auto changeset =
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
originalSerializedVariables, object.GetVariables());
REQUIRE(changeset.oldToNewVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForObjectVariablesContainer(
project, object.GetVariables(), scene.GetInitialInstances(),
object.GetName(), changeset, originalSerializedVariables);
REQUIRE(event.GetActions()[0].GetParameter(1).GetPlainString() ==
"MyRenamedVariable");
REQUIRE(event.GetActions()[0].GetParameter(3).GetPlainString() ==
"Object.MyRenamedVariable");
REQUIRE(instance.GetVariables().Get("MyRenamedVariable").GetValue() == 456);
}
SECTION("Can delete an object variable") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &scene = project.InsertNewLayout("Scene", 0);
auto &object = scene.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object", 0);
object.GetVariables().InsertNew("MyVariable").SetValue(123);
auto &instance = scene.GetInitialInstances().InsertNewInitialInstance();
instance.SetObjectName("Object");
instance.GetVariables().InsertNew("MyVariable").SetValue(456);
gd::StandardEvent &event =
dynamic_cast<gd::StandardEvent &>(scene.GetEvents().InsertNewEvent(
project, "BuiltinCommonInstructions::Standard"));
{
gd::Instruction action;
action.SetType("SetNumberObjectVariable");
action.SetParametersCount(4);
action.SetParameter(0, gd::Expression("Object"));
action.SetParameter(1, gd::Expression("MyVariable"));
action.SetParameter(2, gd::Expression("="));
action.SetParameter(3, gd::Expression("Object.MyVariable"));
event.GetActions().Insert(action);
}
// Do the changes and launch the refactoring.
object.GetVariables().ResetPersistentUuid();
gd::SerializerElement originalSerializedVariables;
object.GetVariables().SerializeTo(originalSerializedVariables);
object.GetVariables().Remove("MyVariable");
auto changeset =
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
originalSerializedVariables, object.GetVariables());
REQUIRE(changeset.removedVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForObjectVariablesContainer(
project, object.GetVariables(), scene.GetInitialInstances(),
object.GetName(), changeset, originalSerializedVariables);
// Events are untouched
REQUIRE(scene.GetEvents().size() == 1);
REQUIRE(event.GetActions().size() == 1);
REQUIRE(event.GetActions()[0].GetParameter(1).GetPlainString() ==
"MyVariable");
REQUIRE(event.GetActions()[0].GetParameter(3).GetPlainString() ==
"Object.MyVariable");
// Instance variables are removed
REQUIRE(!instance.GetVariables().Has("MyVariable"));
}
SECTION("Can add an object variable") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &scene = project.InsertNewLayout("Scene", 0);
auto &object = scene.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object", 0);
auto &instance = scene.GetInitialInstances().InsertNewInitialInstance();
instance.SetObjectName("Object");
// Do the changes and launch the refactoring.
object.GetVariables().ResetPersistentUuid();
gd::SerializerElement originalSerializedVariables;
object.GetVariables().SerializeTo(originalSerializedVariables);
object.GetVariables().InsertNew("MyVariable").SetValue(123);
auto changeset =
gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
originalSerializedVariables, object.GetVariables());
REQUIRE(changeset.addedVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project, object.GetVariables(), changeset, originalSerializedVariables);
// Instance variables are NOT added
REQUIRE(!instance.GetVariables().Has("MyVariable"));
}
SECTION("Can rename an object child variable") {
gd::Project project;
gd::Platform platform;
@@ -1062,8 +1196,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.modifiedVariables.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project, object.GetVariables(), changeset, originalSerializedVariables);
gd::WholeProjectRefactorer::ApplyRefactoringForObjectVariablesContainer(
project, object.GetVariables(), scene.GetInitialInstances(),
object.GetName(), changeset, originalSerializedVariables);
REQUIRE(event.GetActions()[0].GetParameter(1).GetPlainString() ==
"MyVariable.MyRenamedChild");
@@ -1112,8 +1247,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.modifiedVariables.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project, object.GetVariables(), changeset, originalSerializedVariables);
gd::WholeProjectRefactorer::ApplyRefactoringForObjectVariablesContainer(
project, object.GetVariables(), scene.GetInitialInstances(),
object.GetName(), changeset, originalSerializedVariables);
REQUIRE(event.GetActions()[0].GetParameter(3).GetPlainString() ==
"MyVariable.MyRenamedChild");
@@ -1161,8 +1297,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.modifiedVariables.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project, object.GetVariables(), changeset, originalSerializedVariables);
gd::WholeProjectRefactorer::ApplyRefactoringForObjectVariablesContainer(
project, object.GetVariables(), scene.GetInitialInstances(),
object.GetName(), changeset, originalSerializedVariables);
REQUIRE(event.GetActions()[0].GetParameter(3).GetPlainString() ==
"MyVariable.MyChild.MyRenamedGrandChild");
@@ -1896,8 +2033,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.typeChangedVariableNames.find("MyObjectVariable") !=
changeset.typeChangedVariableNames.end());
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project, object.GetVariables(), changeset, originalSerializedVariables);
gd::WholeProjectRefactorer::ApplyRefactoringForObjectVariablesContainer(
project, object.GetVariables(), scene.GetInitialInstances(),
object.GetName(), changeset, originalSerializedVariables);
// Check the the action has changed to follow the variable type.
REQUIRE(event.GetActions()[0].GetType() == "SetStringObjectVariable");
@@ -1947,8 +2085,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.typeChangedVariableNames.find("MyObjectVariable") !=
changeset.typeChangedVariableNames.end());
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project, object.GetVariables(), changeset, originalSerializedVariables);
gd::WholeProjectRefactorer::ApplyRefactoringForObjectVariablesContainer(
project, object.GetVariables(), scene.GetInitialInstances(),
object.GetName(), changeset, originalSerializedVariables);
// Check the the action has changed to follow the variable type.
REQUIRE(event.GetActions()[0].GetType() == "SetStringObjectVariable");
@@ -1977,7 +2116,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Count() == 1);
@@ -2009,7 +2148,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Count() == 1);
@@ -2029,7 +2168,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Count() == 0);
@@ -2050,7 +2189,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Count() == 0);
@@ -2075,7 +2214,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Has("MyGroupVariable"));
@@ -2094,8 +2233,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.valueChangedVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
REQUIRE(object.GetVariables().Get("MyGroupVariable").GetValue() == 456);
REQUIRE(otherObject.GetVariables().Get("MyGroupVariable").GetValue() ==
@@ -2121,7 +2261,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Has("MyGroupVariable"));
@@ -2140,8 +2280,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.valueChangedVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
REQUIRE(object.GetVariables().Get("MyGroupVariable").GetValue() == 456);
REQUIRE(otherObject.GetVariables().Get("MyGroupVariable").GetValue() ==
@@ -2167,7 +2308,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Has("MyGroupVariable"));
@@ -2188,8 +2329,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.valueChangedVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
REQUIRE(object.GetVariables().Get("MyGroupVariable").GetValue() == 111);
REQUIRE(otherObject.GetVariables().Get("MyGroupVariable").GetValue() ==
@@ -2215,7 +2357,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Has("MyGroupVariable"));
@@ -2236,8 +2378,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.valueChangedVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
REQUIRE(object.GetVariables().Get("MyGroupVariable").GetValue() == 0);
REQUIRE(otherObject.GetVariables().Get("MyGroupVariable").GetValue() ==
@@ -2263,7 +2406,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Has("MyGroupVariable"));
@@ -2282,8 +2425,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.valueChangedVariableNames.size() == 0);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
REQUIRE(object.GetVariables().Get("MyGroupVariable").GetValue() == 111);
REQUIRE(otherObject.GetVariables().Get("MyGroupVariable").GetValue() ==
@@ -2318,7 +2462,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Count() == 1);
@@ -2336,8 +2480,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
originalSerializedVariables, groupVariables);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
REQUIRE(newObject.GetVariables().Count() == 2);
REQUIRE(newObject.GetVariables().Get("MyGroupVariable").GetValue() == 123);
@@ -2369,7 +2514,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Has("MyGroupVariable"));
@@ -2390,8 +2535,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.valueChangedVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
REQUIRE(object.GetVariables()
.Get("MyGroupVariable")
@@ -2428,7 +2574,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Has("MyGroupVariable"));
@@ -2448,8 +2594,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.valueChangedVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
REQUIRE(object.GetVariables()
.Get("MyGroupVariable")
@@ -2486,7 +2633,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Has("MyGroupVariable"));
@@ -2506,8 +2653,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.valueChangedVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
REQUIRE(object.GetVariables()
.Get("MyGroupVariable")
@@ -2558,7 +2706,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Has("MyGroupVariable"));
@@ -2579,8 +2727,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.valueChangedVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
REQUIRE(object.GetVariables()
.Get("MyGroupVariable")
@@ -2613,11 +2762,14 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto &group = scene.GetObjects().GetObjectGroups().InsertNew("Group");
group.AddObject("Object");
group.AddObject("OtherObject");
auto &instance = scene.GetInitialInstances().InsertNewInitialInstance();
instance.SetObjectName("Object");
instance.GetVariables().InsertNew("MyGroupVariable").SetValue(456);
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Has("MyGroupVariable"));
@@ -2635,11 +2787,13 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.removedVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
REQUIRE(!object.GetVariables().Has("MyGroupVariable"));
REQUIRE(!otherObject.GetVariables().Has("MyGroupVariable"));
REQUIRE(!instance.GetVariables().Has("MyGroupVariable"));
}
SECTION("Can add a group variable") {
@@ -2659,7 +2813,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Count() == 0);
@@ -2677,8 +2831,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.addedVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
REQUIRE(object.GetVariables().Get("MyGroupVariable").GetValue() == 456);
REQUIRE(otherObject.GetVariables().Get("MyGroupVariable").GetValue() ==
@@ -2704,7 +2859,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Count() == 0);
@@ -2722,8 +2877,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.addedVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
// The variable kept its original value.
REQUIRE(object.GetVariables().Count() == 1);
@@ -2749,6 +2905,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto &group = scene.GetObjects().GetObjectGroups().InsertNew("Group");
group.AddObject("Object");
group.AddObject("OtherObject");
auto &instance = scene.GetInitialInstances().InsertNewInitialInstance();
instance.SetObjectName("Object");
instance.GetVariables().InsertNew("MyGroupVariable").SetValue(456);
gd::StandardEvent &event =
dynamic_cast<gd::StandardEvent &>(scene.GetEvents().InsertNewEvent(
@@ -2787,7 +2946,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Has("MyGroupVariable"));
@@ -2806,8 +2965,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.oldToNewVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
REQUIRE(object.GetVariables().Count() == 1);
REQUIRE(object.GetVariables().Get("MyRenamedGroupVariable").GetValue() == 123);
@@ -2830,6 +2990,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
"MyRenamedGroupVariable");
REQUIRE(event.GetActions()[2].GetParameter(3).GetPlainString() ==
"OtherObject.MyRenamedGroupVariable");
REQUIRE(instance.GetVariables().Get("MyRenamedGroupVariable").GetValue() == 456);
}
SECTION("Can rename a group variable when one of the object already has it") {
@@ -2887,7 +3048,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Has("MyGroupVariable"));
@@ -2906,8 +3067,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.oldToNewVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
// The variable kept its original value.
REQUIRE(object.GetVariables().Count() == 1);
@@ -2992,7 +3154,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Has("MyGroupVariable"));
@@ -3016,8 +3178,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.modifiedVariables.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
REQUIRE(event.GetActions()[0].GetParameter(1).GetPlainString() ==
"MyGroupVariable.MyRenamedChild");
@@ -3067,7 +3230,7 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, scene);
gd::VariablesContainer groupVariables =
gd::GroupVariableHelper::MergeVariableContainers(
gd::ObjectVariableHelper::MergeVariableContainers(
projectScopedContainers.GetObjectsContainersList(), group);
REQUIRE(groupVariables.Has("MyGroupVariable"));
@@ -3086,8 +3249,9 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
REQUIRE(changeset.oldToNewVariableNames.size() == 1);
gd::WholeProjectRefactorer::ApplyRefactoringForGroupVariablesContainer(
project, project.GetObjects(), scene.GetObjects(), groupVariables,
group, changeset, originalSerializedVariables);
project, project.GetObjects(), scene.GetObjects(),
scene.GetInitialInstances(), groupVariables, group, changeset,
originalSerializedVariables);
REQUIRE(event.GetActions()[0].GetParameter(1).GetPlainString() ==
"MyGroupVariable");

View File

@@ -1,15 +1,4 @@
namespace gdjs {
export interface Object3DDataContent {
width: float;
height: float;
depth: float;
}
/** Base parameters for {@link gdjs.RuntimeObject3D} */
export interface Object3DData extends ObjectData {
/** The base parameters of the RuntimeObject3D */
content: Object3DDataContent;
}
const getValidDimensionValue = (value: float | undefined) =>
value === undefined ? 100 : value <= 0 ? 1 : value;
@@ -35,11 +24,8 @@ namespace gdjs {
*/
export abstract class RuntimeObject3D
extends gdjs.RuntimeObject
implements
gdjs.Resizable,
gdjs.Scalable,
gdjs.Flippable,
gdjs.Base3DHandler {
implements gdjs.Resizable, gdjs.Scalable, gdjs.Flippable, gdjs.Base3DHandler
{
/**
* Position on the Z axis.
*/
@@ -84,7 +70,7 @@ namespace gdjs {
constructor(
instanceContainer: gdjs.RuntimeInstanceContainer,
objectData: Object3DData
objectData: gdjs.Object3DData
) {
super(instanceContainer, objectData);
// TODO Should 0 be replaced by 0.01 instead of using the default value?

View File

@@ -117,6 +117,17 @@ namespace gdjs {
getUnrotatedAABBMaxZ(): number;
}
export interface Object3DDataContent {
width: float;
height: float;
depth: float;
}
/** Base parameters for {@link gdjs.RuntimeObject3D} */
export interface Object3DData extends ObjectData {
/** The base parameters of the RuntimeObject3D */
content: Object3DDataContent;
}
export namespace Base3DHandler {
export const is3D = (
object: gdjs.RuntimeObject
@@ -131,7 +142,8 @@ namespace gdjs {
*/
export class Base3DBehavior
extends gdjs.RuntimeBehavior
implements Base3DHandler {
implements Base3DHandler
{
private object: gdjs.RuntimeObject & Base3DHandler;
constructor(

View File

@@ -3,31 +3,31 @@ namespace gdjs {
export interface Cube3DObjectData extends Object3DData {
/** The base parameters of the Cube3D object */
content: Object3DDataContent & {
enableTextureTransparency: boolean;
facesOrientation: 'Y' | 'Z';
enableTextureTransparency: boolean | undefined;
facesOrientation: 'Y' | 'Z' | undefined;
frontFaceResourceName: string;
backFaceResourceName: string;
backFaceUpThroughWhichAxisRotation: 'X' | 'Y';
backFaceUpThroughWhichAxisRotation: 'X' | 'Y' | undefined;
leftFaceResourceName: string;
rightFaceResourceName: string;
topFaceResourceName: string;
bottomFaceResourceName: string;
frontFaceResourceRepeat: boolean;
backFaceResourceRepeat: boolean;
leftFaceResourceRepeat: boolean;
rightFaceResourceRepeat: boolean;
topFaceResourceRepeat: boolean;
bottomFaceResourceRepeat: boolean;
frontFaceResourceRepeat: boolean | undefined;
backFaceResourceRepeat: boolean | undefined;
leftFaceResourceRepeat: boolean | undefined;
rightFaceResourceRepeat: boolean | undefined;
topFaceResourceRepeat: boolean | undefined;
bottomFaceResourceRepeat: boolean | undefined;
frontFaceVisible: boolean;
backFaceVisible: boolean;
leftFaceVisible: boolean;
rightFaceVisible: boolean;
topFaceVisible: boolean;
bottomFaceVisible: boolean;
tint: string | undefined;
materialType: 'Basic' | 'StandardWithoutMetalness';
};
}
type FaceName = 'front' | 'back' | 'left' | 'right' | 'top' | 'bottom';
const faceNameToBitmaskIndex = {
front: 0,
@@ -45,6 +45,7 @@ namespace gdjs {
trfb: integer;
frn: [string, string, string, string, string, string];
mt: number;
tint: string;
};
type Cube3DObjectNetworkSyncData = Object3DNetworkSyncData &
@@ -67,10 +68,11 @@ namespace gdjs {
string,
string,
string,
string
string,
];
_materialType: gdjs.Cube3DRuntimeObject.MaterialType =
gdjs.Cube3DRuntimeObject.MaterialType.Basic;
_tint: string;
constructor(
instanceContainer: gdjs.RuntimeInstanceContainer,
@@ -117,6 +119,9 @@ namespace gdjs {
objectData.content.topFaceResourceName,
objectData.content.bottomFaceResourceName,
];
this._tint = objectData.content.tint || '255;255;255';
this._materialType = this._convertMaterialType(
objectData.content.materialType
);
@@ -134,7 +139,7 @@ namespace gdjs {
* Sets the visibility of a face of the 3D box.
*
* @param faceName - The name of the face to set visibility for.
* @param value - The visibility value to set.
* @param enable - The visibility value to set.
*/
setFaceVisibility(faceName: FaceName, enable: boolean) {
const faceIndex = faceNameToBitmaskIndex[faceName];
@@ -157,7 +162,7 @@ namespace gdjs {
* Sets the texture repeat of a face of the 3D box.
*
* @param faceName - The name of the face to set visibility for.
* @param value - The visibility value to set.
* @param enable - The visibility value to set.
*/
setRepeatTextureOnFace(faceName: FaceName, enable: boolean) {
const faceIndex = faceNameToBitmaskIndex[faceName];
@@ -203,11 +208,22 @@ namespace gdjs {
if (this._faceResourceNames[faceIndex] === resourceName) {
return;
}
this._faceResourceNames[faceIndex] = resourceName;
this._renderer.updateFace(faceIndex);
}
setColor(tint: string): void {
if (this._tint === tint) {
return;
}
this._tint = tint;
this._renderer.updateTint();
}
getColor(): string {
return this._tint;
}
/** @internal */
getFaceAtIndexResourceName(faceIndex: integer): string {
return this._faceResourceNames[faceIndex];
@@ -291,6 +307,10 @@ namespace gdjs {
newObjectData.content.frontFaceResourceName
);
}
if (oldObjectData.content.tint !== newObjectData.content.tint) {
this.setColor(newObjectData.content.tint || '255;255;255');
}
if (
oldObjectData.content.backFaceResourceName !==
newObjectData.content.backFaceResourceName
@@ -342,7 +362,7 @@ namespace gdjs {
) {
this.setRepeatTextureOnFace(
'front',
newObjectData.content.frontFaceResourceRepeat
newObjectData.content.frontFaceResourceRepeat || false
);
}
if (
@@ -351,7 +371,7 @@ namespace gdjs {
) {
this.setRepeatTextureOnFace(
'back',
newObjectData.content.backFaceResourceRepeat
newObjectData.content.backFaceResourceRepeat || false
);
}
if (
@@ -360,7 +380,7 @@ namespace gdjs {
) {
this.setRepeatTextureOnFace(
'left',
newObjectData.content.leftFaceResourceRepeat
newObjectData.content.leftFaceResourceRepeat || false
);
}
if (
@@ -369,7 +389,7 @@ namespace gdjs {
) {
this.setRepeatTextureOnFace(
'right',
newObjectData.content.rightFaceResourceRepeat
newObjectData.content.rightFaceResourceRepeat || false
);
}
if (
@@ -378,7 +398,7 @@ namespace gdjs {
) {
this.setRepeatTextureOnFace(
'top',
newObjectData.content.topFaceResourceRepeat
newObjectData.content.topFaceResourceRepeat || false
);
}
if (
@@ -387,7 +407,7 @@ namespace gdjs {
) {
this.setRepeatTextureOnFace(
'bottom',
newObjectData.content.bottomFaceResourceRepeat
newObjectData.content.bottomFaceResourceRepeat || false
);
}
if (
@@ -395,14 +415,14 @@ namespace gdjs {
newObjectData.content.backFaceUpThroughWhichAxisRotation
) {
this.setBackFaceUpThroughWhichAxisRotation(
newObjectData.content.backFaceUpThroughWhichAxisRotation
newObjectData.content.backFaceUpThroughWhichAxisRotation || 'X'
);
}
if (
oldObjectData.content.facesOrientation !==
newObjectData.content.facesOrientation
) {
this.setFacesOrientation(newObjectData.content.facesOrientation);
this.setFacesOrientation(newObjectData.content.facesOrientation || 'Y');
}
if (
oldObjectData.content.materialType !==
@@ -423,6 +443,7 @@ namespace gdjs {
vfb: this._visibleFacesBitmask,
trfb: this._textureRepeatFacesBitmask,
frn: this._faceResourceNames,
tint: this._tint,
};
}
@@ -476,6 +497,12 @@ namespace gdjs {
}
}
}
if (networkSyncData.tint !== undefined) {
if (this._tint !== networkSyncData.tint) {
this._tint = networkSyncData.tint;
this._renderer.updateTint();
}
}
}
/**

View File

@@ -62,6 +62,7 @@ namespace gdjs {
forceBasicMaterial:
runtimeObject._materialType ===
gdjs.Cube3DRuntimeObject.MaterialType.Basic,
vertexColors: true,
});
};
@@ -74,15 +75,13 @@ namespace gdjs {
instanceContainer: gdjs.RuntimeInstanceContainer
) {
const geometry = new THREE.BoxGeometry(1, 1, 1);
// TODO (3D) - feature: support color instead of texture?
const materials = [
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[0]),
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[1]),
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[2]),
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[3]),
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[4]),
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[5]),
];
const materials: THREE.Material[] = new Array(6)
.fill(0)
.map((_, index) =>
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[index])
);
const boxMesh = new THREE.Mesh(geometry, materials);
super(runtimeObject, instanceContainer, boxMesh);
@@ -92,6 +91,28 @@ namespace gdjs {
this.updateSize();
this.updatePosition();
this.updateRotation();
this.updateTint();
}
updateTint() {
const tints: number[] = [];
const normalizedTint = gdjs
.rgbOrHexToRGBColor(this._cube3DRuntimeObject.getColor())
.map((component) => component / 255);
for (
let i = 0;
i < this._boxMesh.geometry.attributes.position.count;
i++
) {
tints.push(...normalizedTint);
}
this._boxMesh.geometry.setAttribute(
'color',
new THREE.BufferAttribute(new Float32Array(tints), 3)
);
}
updateFace(faceIndex: integer) {
@@ -121,13 +142,11 @@ namespace gdjs {
*/
updateTextureUvMapping(faceIndex?: number) {
// @ts-ignore - position is stored as a Float32BufferAttribute
const pos: THREE.BufferAttribute = this._boxMesh.geometry.getAttribute(
'position'
);
const pos: THREE.BufferAttribute =
this._boxMesh.geometry.getAttribute('position');
// @ts-ignore - uv is stored as a Float32BufferAttribute
const uvMapping: THREE.BufferAttribute = this._boxMesh.geometry.getAttribute(
'uv'
);
const uvMapping: THREE.BufferAttribute =
this._boxMesh.geometry.getAttribute('uv');
const startIndex =
faceIndex === undefined ? 0 : faceIndexToMaterialIndex[faceIndex] * 4;
const endIndex =
@@ -149,9 +168,10 @@ namespace gdjs {
continue;
}
const shouldRepeatTexture = this._cube3DRuntimeObject.shouldRepeatTextureOnFaceAtIndex(
materialIndexToFaceIndex[materialIndex]
);
const shouldRepeatTexture =
this._cube3DRuntimeObject.shouldRepeatTextureOnFaceAtIndex(
materialIndexToFaceIndex[materialIndex]
);
const shouldOrientateFacesTowardsY =
this._cube3DRuntimeObject.getFacesOrientation() === 'Y';
@@ -180,12 +200,10 @@ namespace gdjs {
if (shouldOrientateFacesTowardsY) {
[x, y] = noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
} else {
[
x,
y,
] = noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
[x, y] =
noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
}
}
break;
@@ -211,12 +229,10 @@ namespace gdjs {
if (shouldOrientateFacesTowardsY) {
[x, y] = noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
} else {
[
x,
y,
] = noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
[x, y] =
noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
x = -x;
y = -y;
}

View File

@@ -1,21 +1,11 @@
namespace gdjs {
export interface Object3DDataContent {
width: float;
height: float;
depth: float;
}
/** Base parameters for {@link gdjs.RuntimeObject3D} */
export interface Object3DData extends ObjectData {
/** The base parameters of the RuntimeObject3D */
content: Object3DDataContent;
}
/**
* Base class for 3D custom objects.
*/
export class CustomRuntimeObject3D
extends gdjs.CustomRuntimeObject
implements gdjs.Base3DHandler {
implements gdjs.Base3DHandler
{
/**
* Position on the Z axis.
*/
@@ -41,13 +31,13 @@ namespace gdjs {
constructor(
parent: gdjs.RuntimeInstanceContainer,
objectData: Object3DData & CustomObjectConfiguration
objectData: gdjs.Object3DData & gdjs.CustomObjectConfiguration
) {
super(parent, objectData);
this._renderer.reinitialize(this, parent);
}
protected _createRender() {
protected override _createRender() {
const parent = this._runtimeScene;
return new gdjs.CustomRuntimeObject3DRenderer(
this,
@@ -56,21 +46,23 @@ namespace gdjs {
);
}
protected _reinitializeRenderer(): void {
protected override _reinitializeRenderer(): void {
this.getRenderer().reinitialize(this, this.getParent());
}
getRenderer(): gdjs.CustomRuntimeObject3DRenderer {
override getRenderer(): gdjs.CustomRuntimeObject3DRenderer {
return super.getRenderer() as gdjs.CustomRuntimeObject3DRenderer;
}
get3DRendererObject() {
override get3DRendererObject() {
// It can't be null because Three.js is always loaded
// when a custom 3D object is used.
return this.getRenderer().get3DRendererObject()!;
}
extraInitializationFromInitialInstance(initialInstanceData: InstanceData) {
override extraInitializationFromInitialInstance(
initialInstanceData: InstanceData
) {
super.extraInitializationFromInitialInstance(initialInstanceData);
if (initialInstanceData.depth !== undefined) {
this.setDepth(initialInstanceData.depth);
@@ -292,7 +284,7 @@ namespace gdjs {
return this._maxZ - this._minZ;
}
_updateUntransformedHitBoxes(): void {
override _updateUntransformedHitBoxes(): void {
super._updateUntransformedHitBoxes();
let minZ = Number.MAX_VALUE;

View File

@@ -6,7 +6,8 @@ namespace gdjs {
* The renderer for a {@link gdjs.CustomRuntimeObject3D} using Three.js.
*/
export class CustomRuntimeObject3DRenderer
implements gdjs.RuntimeInstanceContainerRenderer {
implements gdjs.RuntimeInstanceContainerRenderer
{
_object: gdjs.CustomRuntimeObject3D;
_instanceContainer: gdjs.CustomRuntimeObjectInstanceContainer;
_isContainerDirty: boolean = true;
@@ -139,16 +140,16 @@ namespace gdjs {
imageManager: gdjs.PixiImageManager
): ThreeAnimationFrameTextureManager {
if (!imageManager._threeAnimationFrameTextureManager) {
imageManager._threeAnimationFrameTextureManager = new ThreeAnimationFrameTextureManager(
imageManager
);
imageManager._threeAnimationFrameTextureManager =
new ThreeAnimationFrameTextureManager(imageManager);
}
return imageManager._threeAnimationFrameTextureManager;
}
}
class ThreeAnimationFrameTextureManager
implements gdjs.AnimationFrameTextureManager<THREE.Material> {
implements gdjs.AnimationFrameTextureManager<THREE.Material>
{
private _imageManager: gdjs.PixiImageManager;
constructor(imageManager: gdjs.PixiImageManager) {
@@ -159,20 +160,21 @@ namespace gdjs {
return this._imageManager.getThreeMaterial(imageName, {
useTransparentTexture: true,
forceBasicMaterial: true,
vertexColors: false,
});
}
getAnimationFrameWidth(material: THREE.Material) {
const map = (material as
| THREE.MeshBasicMaterial
| THREE.MeshStandardMaterial).map;
const map = (
material as THREE.MeshBasicMaterial | THREE.MeshStandardMaterial
).map;
return map ? map.image.width : 0;
}
getAnimationFrameHeight(material: THREE.Material) {
const map = (material as
| THREE.MeshBasicMaterial
| THREE.MeshStandardMaterial).map;
const map = (
material as THREE.MeshBasicMaterial | THREE.MeshStandardMaterial
).map;
return map ? map.image.height : 0;
}
}

View File

@@ -69,7 +69,7 @@ module.exports = {
_('Center Z position'),
_('the Z position of the center of rotation'),
_('the Z position of the center'),
_('Position/Center'),
_('Position Center'),
'res/conditions/3d_box.svg'
)
.addParameter('object', _('3D object'), '', false)
@@ -800,6 +800,20 @@ module.exports = {
.markAsSimple()
.setHidden()
.setFunctionName('hasAnimationEnded');
object
.addScopedAction(
'SetCrossfadeDuration',
_('Set crossfade duration'),
_('Set the crossfade duration when switching to a new animation.'),
_('Set crossfade duration of _PARAM0_ to _PARAM1_ seconds'),
_('Animations and images'),
'res/conditions/animation24.png',
'res/conditions/animation.png'
)
.addParameter('object', _('3D model'), 'Model3DObject', false)
.addParameter('number', _('Crossfade duration (in seconds)'), '', false)
.setFunctionName('setCrossfadeDuration');
}
const Cube3DObject = new gd.ObjectJsImplementation();
@@ -822,7 +836,8 @@ module.exports = {
propertyName === 'bottomFaceResourceName' ||
propertyName === 'backFaceUpThroughWhichAxisRotation' ||
propertyName === 'facesOrientation' ||
propertyName === 'materialType'
propertyName === 'materialType' ||
propertyName === 'tint'
) {
objectContent[propertyName] = newValue;
return true;
@@ -902,6 +917,12 @@ module.exports = {
.setLabel(_('Depth'))
.setMeasurementUnit(gd.MeasurementUnit.getPixel())
.setGroup(_('Default size'));
objectProperties
.getOrCreate('tint')
.setValue(objectContent.tint || '255;255;255')
.setType('Color')
.setLabel(_('Tint'))
.setGroup(_('Texture'));
objectProperties
.getOrCreate('frontFaceResourceName')
@@ -1092,6 +1113,7 @@ module.exports = {
topFaceResourceRepeat: false,
bottomFaceResourceRepeat: false,
materialType: 'Basic',
tint: '255;255;255',
};
Cube3DObject.updateInitialInstanceProperty = function (
@@ -1568,6 +1590,21 @@ module.exports = {
.addParameter('imageResource', _('Image'), '', false)
.setFunctionName('setFaceResourceName');
object
.addScopedAction(
'SetTint',
_('Tint color'),
_('Change the tint of the cube.'),
_('Change the tint of _PARAM0_ to _PARAM1_'),
_('Effects'),
'res/actions/color24.png',
'res/actions/color.png'
)
.addParameter('object', _('3D Cube'), 'Cube3DObject', false)
.addParameter('color', _('Tint'), '', false)
.getCodeExtraInformation()
.setFunctionName('setColor');
extension
.addExpressionAndConditionAndAction(
'number',
@@ -2062,6 +2099,10 @@ module.exports = {
3: [1, 0],
};
/**
* @param {*} objectConfiguration
* @returns {string | null}
*/
const getFirstVisibleFaceResourceName = (objectConfiguration) => {
const object = gd.castObject(
objectConfiguration,
@@ -2090,25 +2131,44 @@ module.exports = {
return null;
};
/** @type {THREE.MeshBasicMaterial | null} */
let transparentMaterial = null;
/**
* @returns {THREE.MeshBasicMaterial}
*/
const getTransparentMaterial = () => {
if (!transparentMaterial)
transparentMaterial = new THREE.MeshBasicMaterial({
transparent: true,
opacity: 0,
// Set the alpha test to to ensure the faces behind are rendered
// (no "back face culling" that would still be done if alphaTest is not set).
alphaTest: 1,
});
return transparentMaterial;
if (transparentMaterial) {
return transparentMaterial;
}
const newTransparentMaterial = new THREE.MeshBasicMaterial({
transparent: true,
opacity: 0,
// Set the alpha test to to ensure the faces behind are rendered
// (no "back face culling" that would still be done if alphaTest is not set).
alphaTest: 1,
});
transparentMaterial = newTransparentMaterial;
return newTransparentMaterial;
};
class RenderedCube3DObject2DInstance extends RenderedInstance {
/** @type {number} */
_defaultWidth;
/** @type {number} */
_defaultHeight;
/** @type {number} */
_defaultDepth;
/** @type {number} */
_centerX = 0;
/** @type {number} */
_centerY = 0;
/**
* The name of the resource that is rendered.
* If no face is visible, this will be null.
* @type {string | null | undefined}
*/
_renderedResourceName = undefined;
_renderFallbackObject = false;
constructor(
project,
@@ -2124,11 +2184,6 @@ module.exports = {
pixiContainer,
pixiResourcesLoader
);
// Name of the resource that is rendered.
// If no face is visible, this will be null.
this._renderedResourceName = undefined;
const object = gd.castObject(
this._associatedObjectConfiguration,
gd.ObjectJsImplementation
@@ -2145,7 +2200,6 @@ module.exports = {
this._pixiObject.addChild(this._pixiTexturedObject);
this._pixiObject.addChild(this._pixiFallbackObject);
this._pixiContainer.addChild(this._pixiObject);
this._renderFallbackObject = false;
this.updateTexture();
}
@@ -2160,9 +2214,10 @@ module.exports = {
}
static getThumbnail(project, resourcesLoader, objectConfiguration) {
const textureResourceName = RenderedCube3DObject2DInstance._getResourceNameToDisplay(
objectConfiguration
);
const textureResourceName =
RenderedCube3DObject2DInstance._getResourceNameToDisplay(
objectConfiguration
);
if (textureResourceName) {
return resourcesLoader.getResourceFullUrl(
project,
@@ -2174,18 +2229,20 @@ module.exports = {
}
updateTextureIfNeeded() {
const textureName = RenderedCube3DObject2DInstance._getResourceNameToDisplay(
this._associatedObjectConfiguration
);
const textureName =
RenderedCube3DObject2DInstance._getResourceNameToDisplay(
this._associatedObjectConfiguration
);
if (textureName === this._renderedResourceName) return;
this.updateTexture();
}
updateTexture() {
const textureName = RenderedCube3DObject2DInstance._getResourceNameToDisplay(
this._associatedObjectConfiguration
);
const textureName =
RenderedCube3DObject2DInstance._getResourceNameToDisplay(
this._associatedObjectConfiguration
);
if (!textureName) {
this._renderFallbackObject = true;
@@ -2308,6 +2365,17 @@ module.exports = {
}
class RenderedCube3DObject3DInstance extends Rendered3DInstance {
_defaultWidth = 1;
_defaultHeight = 1;
_defaultDepth = 1;
_faceResourceNames = new Array(6).fill(null);
_faceVisibilities = new Array(6).fill(null);
_shouldRepeatTextureOnFace = new Array(6).fill(null);
_facesOrientation = 'Y';
_backFaceUpThroughWhichAxisRotation = 'X';
_shouldUseTransparentTexture = false;
_tint = '';
constructor(
project,
instance,
@@ -2324,21 +2392,9 @@ module.exports = {
threeGroup,
pixiResourcesLoader
);
this._defaultWidth = 1;
this._defaultHeight = 1;
this._defaultDepth = 1;
this._pixiObject = new PIXI.Graphics();
this._pixiContainer.addChild(this._pixiObject);
this._faceResourceNames = new Array(6).fill(null);
this._faceVisibilities = new Array(6).fill(null);
this._shouldRepeatTextureOnFace = new Array(6).fill(null);
this._facesOrientation = 'Y';
this._backFaceUpThroughWhichAxisRotation = 'X';
this._shouldUseTransparentTexture = false;
const geometry = new THREE.BoxGeometry(1, 1, 1);
const materials = [
getTransparentMaterial(),
@@ -2357,8 +2413,9 @@ module.exports = {
async _updateThreeObjectMaterials() {
const getFaceMaterial = async (project, faceIndex) => {
if (!this._faceVisibilities[faceIndex])
if (!this._faceVisibilities[faceIndex]) {
return getTransparentMaterial();
}
return await this._pixiResourcesLoader.getThreeMaterial(
project,
@@ -2389,11 +2446,35 @@ module.exports = {
this._updateTextureUvMapping();
}
_updateTint() {
const tints = [];
const normalizedTint = objectsRenderingService
.hexNumberToRGBArray(
objectsRenderingService.rgbOrHexToHexNumber(this._tint)
)
.map((component) => component / 255);
for (
let i = 0;
i < this._threeObject.geometry.attributes.position.count;
i++
) {
tints.push(...normalizedTint);
}
this._threeObject.geometry.setAttribute(
'color',
new THREE.BufferAttribute(new Float32Array(tints), 3)
);
}
static _getResourceNameToDisplay(objectConfiguration) {
return getFirstVisibleFaceResourceName(objectConfiguration);
}
updateThreeObject() {
/** @type {gdjs.Cube3DObjectData} */
//@ts-ignore This works because the properties are set to `content` in JavaScript.
const object = gd.castObject(
this._associatedObjectConfiguration,
gd.ObjectJsImplementation
@@ -2421,13 +2502,19 @@ module.exports = {
let materialsDirty = false;
let uvMappingDirty = false;
let tintDirty = false;
const shouldUseTransparentTexture =
object.content.enableTextureTransparency;
object.content.enableTextureTransparency || false;
if (this._shouldUseTransparentTexture !== shouldUseTransparentTexture) {
this._shouldUseTransparentTexture = shouldUseTransparentTexture;
materialsDirty = true;
}
const tint = object.content.tint || '255;255;255';
if (this._tint !== tint) {
this._tint = tint;
tintDirty = true;
}
const faceResourceNames = [
object.content.frontFaceResourceName,
@@ -2471,12 +2558,12 @@ module.exports = {
}
const shouldRepeatTextureOnFace = [
object.content.frontFaceResourceRepeat,
object.content.backFaceResourceRepeat,
object.content.leftFaceResourceRepeat,
object.content.rightFaceResourceRepeat,
object.content.topFaceResourceRepeat,
object.content.bottomFaceResourceRepeat,
object.content.frontFaceResourceRepeat || false,
object.content.backFaceResourceRepeat || false,
object.content.leftFaceResourceRepeat || false,
object.content.rightFaceResourceRepeat || false,
object.content.topFaceResourceRepeat || false,
object.content.bottomFaceResourceRepeat || false,
];
if (
this._shouldRepeatTextureOnFace[0] !== shouldRepeatTextureOnFace[0] ||
@@ -2491,16 +2578,17 @@ module.exports = {
}
const backFaceUpThroughWhichAxisRotation =
object.content.backFaceUpThroughWhichAxisRotation;
object.content.backFaceUpThroughWhichAxisRotation || 'X';
if (
backFaceUpThroughWhichAxisRotation !==
this._backFaceUpThroughWhichAxisRotation
) {
this._backFaceUpThroughWhichAxisRotation = backFaceUpThroughWhichAxisRotation;
this._backFaceUpThroughWhichAxisRotation =
backFaceUpThroughWhichAxisRotation;
uvMappingDirty = true;
}
const facesOrientation = object.content.facesOrientation;
const facesOrientation = object.content.facesOrientation || 'Y';
if (facesOrientation !== this._facesOrientation) {
this._facesOrientation = facesOrientation;
uvMappingDirty = true;
@@ -2520,6 +2608,7 @@ module.exports = {
if (materialsDirty) this._updateThreeObjectMaterials();
if (uvMappingDirty) this._updateTextureUvMapping();
if (tintDirty) this._updateTint();
}
/**
@@ -2529,11 +2618,11 @@ module.exports = {
* for the method to work.
*/
_updateTextureUvMapping() {
/** @type {THREE.BufferAttribute} */
// @ts-ignore - position is stored as a Float32BufferAttribute
/** @type {THREE.BufferAttribute} */
const pos = this._threeObject.geometry.getAttribute('position');
// @ts-ignore - uv is stored as a Float32BufferAttribute
/** @type {THREE.BufferAttribute} */
// @ts-ignore - uv is stored as a Float32BufferAttribute
const uvMapping = this._threeObject.geometry.getAttribute('uv');
const startIndex = 0;
const endIndex = 23;
@@ -2552,9 +2641,10 @@ module.exports = {
continue;
}
const shouldRepeatTexture = this._shouldRepeatTextureOnFace[
materialIndexToFaceIndex[materialIndex]
];
const shouldRepeatTexture =
this._shouldRepeatTextureOnFace[
materialIndexToFaceIndex[materialIndex]
];
const shouldOrientateFacesTowardsY = this._facesOrientation === 'Y';
@@ -2589,16 +2679,13 @@ module.exports = {
}
} else {
if (shouldOrientateFacesTowardsY) {
[x, y] = noRepeatTextureVertexIndexToUvMapping[
vertexIndex % 4
];
[x, y] =
noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
} else {
[
x,
y,
] = noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
[x, y] =
noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
}
}
break;
@@ -2628,16 +2715,13 @@ module.exports = {
}
} else {
if (shouldOrientateFacesTowardsY) {
[x, y] = noRepeatTextureVertexIndexToUvMapping[
vertexIndex % 4
];
[x, y] =
noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
} else {
[
x,
y,
] = noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
[x, y] =
noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
vertexIndex % 4
];
x = -x;
y = -y;
}
@@ -2786,6 +2870,19 @@ module.exports = {
const epsilon = 1 / (1 << 16);
class Model3DRendered2DInstance extends RenderedInstance {
/** @type {number} */
_defaultWidth;
/** @type {number} */
_defaultHeight;
/** @type {number} */
_defaultDepth;
/** @type {[number, number, number] | null} */
_originPoint;
/** @type {[number, number, number] | null} */
_centerPoint;
/** @type {[number, number, number]} */
_modelOriginPoint = [0, 0, 0];
constructor(
@@ -3028,10 +3125,15 @@ module.exports = {
}
}
/**
* @param {[number, number, number] | null} point1
* @param {[number, number, number] | null} point2
* @returns {boolean}
*/
const isSamePoint = (point1, point2) => {
if (!point1 && !point2) return true;
if (point1 && !point2) return false;
if (!point1 && point2) return false;
if (!!point1 !== !!point2) return false;
// At this point || or && doesn't matter and the type checking prefer ||.
if (!point1 || !point2) return true;
return (
point1[0] === point2[0] &&
point1[1] === point2[1] &&
@@ -3039,6 +3141,10 @@ module.exports = {
);
};
/**
* @param {string} location
* @returns {[number, number, number] | null}
*/
const getPointForLocation = (location) => {
switch (location) {
case 'ModelOrigin':
@@ -3057,8 +3163,27 @@ module.exports = {
};
class Model3DRendered3DInstance extends Rendered3DInstance {
_defaultWidth = 1;
_defaultHeight = 1;
_defaultDepth = 1;
_originalWidth = 1;
_originalHeight = 1;
_originalDepth = 1;
_rotationX = 0;
_rotationY = 0;
_rotationZ = 0;
_keepAspectRatio = false;
/** @type {[number, number, number] | null} */
_originPoint = null;
/** @type {[number, number, number] | null} */
_centerPoint = null;
/** @type {[number, number, number]} */
_modelOriginPoint = [0, 0, 0];
/** @type {THREE.Object3D | null} */
_clonedModel3D = null;
constructor(
project,
instance,
@@ -3076,29 +3201,12 @@ module.exports = {
pixiResourcesLoader
);
this._defaultWidth = 1;
this._defaultHeight = 1;
this._defaultDepth = 1;
this._originalWidth = 1;
this._originalHeight = 1;
this._originalDepth = 1;
this._rotationX = 0;
this._rotationY = 0;
this._rotationZ = 0;
this._keepAspectRatio = false;
this._originPoint = null;
this._centerPoint = null;
this._pixiObject = new PIXI.Graphics();
this._pixiContainer.addChild(this._pixiObject);
this._threeObject = new THREE.Group();
this._threeObject.rotation.order = 'ZYX';
this._threeGroup.add(this._threeObject);
this._threeModelGroup = null;
this._clonedModel3D = null;
}
getOriginX() {
@@ -3140,27 +3248,30 @@ module.exports = {
}
_updateDefaultTransformation() {
if (!this._clonedModel3D) return; // Model is not ready - nothing to do.
if (!this._clonedModel3D) {
// Model is not ready - nothing to do.
return;
}
if (this._threeModelGroup) {
// Remove any previous container as we will recreate it just below
this._threeObject.clear();
}
// This group hold the rotation defined by properties.
// Always restart from a new group to avoid miscomputing bounding boxes/sizes.
this._threeModelGroup = new THREE.Group();
this._threeModelGroup.rotation.order = 'ZYX';
this._threeModelGroup.add(this._clonedModel3D);
const threeModelGroup = new THREE.Group();
this._threeModelGroup = threeModelGroup;
threeModelGroup.rotation.order = 'ZYX';
threeModelGroup.add(this._clonedModel3D);
this._threeModelGroup.rotation.set(
threeModelGroup.rotation.set(
(this._rotationX * Math.PI) / 180,
(this._rotationY * Math.PI) / 180,
(this._rotationZ * Math.PI) / 180
);
this._threeModelGroup.updateMatrixWorld(true);
const boundingBox = new THREE.Box3().setFromObject(
this._threeModelGroup
);
threeModelGroup.updateMatrixWorld(true);
const boundingBox = new THREE.Box3().setFromObject(threeModelGroup);
const shouldKeepModelOrigin = !this._originPoint;
if (shouldKeepModelOrigin) {
@@ -3187,7 +3298,7 @@ module.exports = {
// Center the model.
const centerPoint = this._centerPoint;
if (centerPoint) {
this._threeModelGroup.position.set(
threeModelGroup.position.set(
-(boundingBox.min.x + modelWidth * centerPoint[0]),
// The model is flipped on Y axis.
-(boundingBox.min.y + modelHeight * (1 - centerPoint[1])),
@@ -3196,8 +3307,8 @@ module.exports = {
}
// Rotate the model.
this._threeModelGroup.scale.set(1, 1, 1);
this._threeModelGroup.rotation.set(
threeModelGroup.scale.set(1, 1, 1);
threeModelGroup.rotation.set(
(this._rotationX * Math.PI) / 180,
(this._rotationY * Math.PI) / 180,
(this._rotationZ * Math.PI) / 180
@@ -3212,8 +3323,8 @@ module.exports = {
// Flip on Y because the Y axis is on the opposite side of direct basis.
// It avoids models to be like a mirror refection.
scaleMatrix.makeScale(scaleX, -scaleY, scaleZ);
this._threeModelGroup.updateMatrix();
this._threeModelGroup.applyMatrix4(scaleMatrix);
threeModelGroup.updateMatrix();
threeModelGroup.applyMatrix4(scaleMatrix);
if (this._keepAspectRatio) {
// Reduce the object dimensions to keep aspect ratio.
@@ -3280,7 +3391,7 @@ module.exports = {
this._defaultDepth = this._originalDepth;
}
this._threeObject.add(this._threeModelGroup);
this._threeObject.add(threeModelGroup);
}
updateThreeObject() {

View File

@@ -23,7 +23,7 @@ Model3DObjectConfiguration::Model3DObjectConfiguration()
: width(100), height(100), depth(100), rotationX(0), rotationY(0),
rotationZ(0), modelResourceName(""), materialType("StandardWithoutMetalness"),
originLocation("ModelOrigin"), centerLocation("ModelOrigin"),
keepAspectRatio(true) {}
keepAspectRatio(true), crossfadeDuration(0.1f) {}
bool Model3DObjectConfiguration::UpdateProperty(const gd::String &propertyName,
const gd::String &newValue) {
@@ -71,6 +71,10 @@ bool Model3DObjectConfiguration::UpdateProperty(const gd::String &propertyName,
keepAspectRatio = newValue == "1";
return true;
}
if(propertyName == "crossfadeDuration") {
crossfadeDuration = newValue.To<double>();
return true;
}
return false;
}
@@ -167,6 +171,13 @@ Model3DObjectConfiguration::GetProperties() const {
.SetGroup(_("Points"))
.SetAdvanced(true);
objectProperties["crossfadeDuration"]
.SetValue(gd::String::From(crossfadeDuration))
.SetType("number")
.SetLabel(_("Crossfade duration"))
.SetGroup(_("Animations"))
.SetMeasurementUnit(gd::MeasurementUnit::GetSecond());
return objectProperties;
}
@@ -198,6 +209,7 @@ void Model3DObjectConfiguration::DoUnserializeFrom(
originLocation = content.GetStringAttribute("originLocation");
centerLocation = content.GetStringAttribute("centerLocation");
keepAspectRatio = content.GetBoolAttribute("keepAspectRatio");
crossfadeDuration = content.GetDoubleAttribute("crossfadeDuration");
RemoveAllAnimations();
auto &animationsElement = content.GetChild("animations");
@@ -226,6 +238,7 @@ void Model3DObjectConfiguration::DoSerializeTo(
content.SetAttribute("originLocation", originLocation);
content.SetAttribute("centerLocation", centerLocation);
content.SetAttribute("keepAspectRatio", keepAspectRatio);
content.SetAttribute("crossfadeDuration", crossfadeDuration);
auto &animationsElement = content.AddChild("animations");
animationsElement.ConsiderAsArrayOf("animation");

View File

@@ -152,6 +152,7 @@ public:
double GetRotationX() const { return rotationX; };
double GetRotationY() const { return rotationY; };
double GetRotationZ() const { return rotationZ; };
double GetCrossfadeDuration() const { return crossfadeDuration; };
const gd::String& GetModelResourceName() const { return modelResourceName; };
const gd::String& GetMaterialType() const { return materialType; };
@@ -173,6 +174,7 @@ private:
double rotationX;
double rotationY;
double rotationZ;
double crossfadeDuration;
gd::String modelResourceName;
gd::String materialType;

View File

@@ -9,6 +9,7 @@ namespace gdjs {
ai: integer;
ass: float;
ap: boolean;
cfd: float;
};
type Model3DObjectNetworkSyncData = Object3DNetworkSyncData &
@@ -36,6 +37,7 @@ namespace gdjs {
| 'BottomCenterZ'
| 'BottomCenterY';
animations: Model3DAnimation[];
crossfadeDuration: float;
};
}
@@ -63,7 +65,8 @@ namespace gdjs {
*/
export class Model3DRuntimeObject
extends gdjs.RuntimeObject3D
implements gdjs.Animatable {
implements gdjs.Animatable
{
_renderer: gdjs.Model3DRuntimeObjectRenderer;
_modelResourceName: string;
@@ -97,6 +100,7 @@ namespace gdjs {
_currentAnimationIndex: integer = 0;
_animationSpeedScale: float = 1;
_animationPaused: boolean = false;
_crossfadeDuration: float = 0;
constructor(
instanceContainer: gdjs.RuntimeInstanceContainer,
@@ -121,6 +125,8 @@ namespace gdjs {
this.onModelChanged(objectData);
this._crossfadeDuration = objectData.content.crossfadeDuration || 0;
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
this.onCreated();
}
@@ -202,6 +208,7 @@ namespace gdjs {
ai: this._currentAnimationIndex,
ass: this._animationSpeedScale,
ap: this._animationPaused,
cfd: this._crossfadeDuration,
};
}
@@ -233,6 +240,9 @@ namespace gdjs {
networkSyncData.ap ? this.pauseAnimation() : this.resumeAnimation();
}
}
if (networkSyncData.cfd !== undefined) {
this._crossfadeDuration = networkSyncData.cfd;
}
}
_reloadModel(objectData: Model3DObjectData) {
@@ -275,7 +285,7 @@ namespace gdjs {
update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
const elapsedTime = this.getElapsedTime() / 1000;
this._renderer.updateAnimation(elapsedTime * this._animationSpeedScale);
this._renderer.updateAnimation(elapsedTime);
}
/**
@@ -348,6 +358,11 @@ namespace gdjs {
return this._renderer.hasAnimationEnded();
}
setCrossfadeDuration(duration: number): void {
if (this._crossfadeDuration === duration) return;
this._crossfadeDuration = duration;
}
isAnimationPaused() {
return this._animationPaused;
}
@@ -368,6 +383,7 @@ namespace gdjs {
setAnimationSpeedScale(ratio: float): void {
this._animationSpeedScale = ratio;
this._renderer.setAnimationTimeScale(ratio);
}
getAnimationElapsedTime(): float {

View File

@@ -359,7 +359,6 @@ namespace gdjs {
}
playAnimation(animationName: string, shouldLoop: boolean) {
this._animationMixer.stopAllAction();
const clip = THREE.AnimationClip.findByName(
this._originalModel.animations,
animationName
@@ -370,12 +369,27 @@ namespace gdjs {
);
return;
}
const previousAction = this._action;
this._action = this._animationMixer.clipAction(clip);
// Reset the animation and play it from the start.
// `clipAction` always gives back the same action for a given animation
// and its likely to be in a finished or at least started state.
this._action.reset();
this._action.setLoop(
shouldLoop ? THREE.LoopRepeat : THREE.LoopOnce,
Number.POSITIVE_INFINITY
);
this._action.clampWhenFinished = true;
this._action.timeScale =
this._model3DRuntimeObject.getAnimationSpeedScale();
if (previousAction && previousAction !== this._action) {
this._action.crossFadeFrom(
previousAction,
this._model3DRuntimeObject._crossfadeDuration,
false
);
}
this._action.play();
// Make sure the first frame is displayed.
this._animationMixer.update(0);
@@ -391,6 +405,12 @@ namespace gdjs {
}
}
setAnimationTimeScale(timeScale: float): void {
if (this._action) {
this._action.timeScale = timeScale;
}
}
getAnimationDuration(animationName: string): float {
const clip = THREE.AnimationClip.findByName(
this._originalModel.animations,

View File

@@ -38,7 +38,7 @@ module.exports = {
.setName('Consent Cordova plugin')
.setDependencyType('cordova')
.setExportName('cordova-plugin-consent')
.setVersion('3.0.0-alpha.8')
.setVersion('3.0.0-alpha.9')
.onlyIfOtherDependencyIsExported('AdMob Cordova plugin');
extension
@@ -93,6 +93,68 @@ module.exports = {
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.setTestMode');
extension
.addAction(
'PreventAdmobAutoInitialization',
_('Prevent AdMob auto initialization'),
_(
'Prevent AdMob from initializing automatically. You will need to call "Initialize AdMob" action manually.\n' +
'This is useful if you want to control when the consent dialog will be shown (for example, after the user has accepted your game terms).'
),
_('Prevent AdMob auto initialization'),
'',
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.preventAdmobAutoInitialization');
extension
.addAction(
'InitializeAdmob',
_('Initialize AdMob manually'),
_(
'Initialize AdMob manually. This will trigger the consent dialog if needed, and then load the ads.\n' +
'Use this action if you have disabled the auto init and want to control when the consent dialog will be shown.'
),
_('Initialize AdMob'),
'',
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.initializeAdmob');
extension
.addCondition(
'AdmobInitializing',
_('AdMob initializing'),
_('Check if AdMob is initializing.'),
_('AdMob is initializing'),
'',
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.isAdmobInitializing');
extension
.addCondition(
'AdmobInitialized',
_('AdMob initialized'),
_('Check if AdMob has been initialized.'),
_('AdMob has been initialized'),
'',
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.isAdmobInitialized');
// App Open
extension
.addCondition(

View File

@@ -1,6 +1,7 @@
namespace gdjs {
declare var admob: any;
declare var cordova: any;
declare var consent: any;
export namespace adMob {
const logger = new gdjs.Logger('AdMob');
@@ -108,26 +109,119 @@ namespace gdjs {
let rewardedVideoRewardReceived = false; // Becomes true when the video is closed and the reward is received.
let rewardedVideoErrored = false; // Becomes true when the video fails to load.
let npaValue = '0'; // TODO: expose an API to change this and also an automatic way using the consent SDK.
let npaValue = '0'; // 0 means that the user has consented to personalized ads, 1 means that the user has not consented to personalized ads.
let setupTimeoutId: NodeJS.Timeout | null = null;
const askForConsentAndInitializeAdmob = async () => {
if (admobStarted) {
logger.warn('AdMob is already started.');
return;
}
if (isStarting) {
logger.warn('AdMob is already starting.');
return;
}
try {
logger.info('Starting AdMob.');
isStarting = true;
if (cordova.platformId === 'ios') {
try {
/*
trackingStatus:
0 = notDetermined
1 = restricted
2 = denied
3 = authorized
*/
let trackingStatus = await consent.trackingAuthorizationStatus();
// If tracking is not determined, we ask the user for tracking authorization.
if (trackingStatus === 0) {
trackingStatus = await consent.requestTrackingAuthorization();
}
// If tracking is restricted or denied, we set npaValue to 1.
if (trackingStatus === 1 || trackingStatus === 2) {
npaValue = '1';
}
// otherwise, we set npaValue to 0.
npaValue = '0';
} catch (error) {
logger.error(
'Error while asking for tracking authorization, continuing:',
error
);
}
}
try {
// ConsentStatus:
// Unknown = 0,
// Required = 1,
// NotRequired = 2,
// Obtained = 3,
const consentStatus = await consent.getConsentStatus();
if (consentStatus === consent.ConsentStatus.Required) {
await consent.requestInfoUpdate();
}
await consent.loadAndShowIfRequired();
} catch (error) {
logger.error('Error while asking for consent, continuing:', error);
}
// We should be looking at canRequestAds to know if we can request ads or not.
// But as we want to be able to test ads in debug or if the consent didn't work,
// we ignore this value for now.
// const canRequestAds = await consent.canRequestAds();
if (true) {
await admob.start();
logger.info('AdMob successfully started.');
isStarting = false;
admobStarted = true;
}
} catch (error) {
logger.error('Error while starting AdMob:', error);
isStarting = false;
admobStarted = false;
}
};
// Admob initialization listener
document.addEventListener(
'deviceready',
async () => {
// Obtain user consent ?
logger.info('Starting AdMob.');
isStarting = true;
await admob.start();
logger.info('AdMob successfully started.');
isStarting = false;
admobStarted = true;
setupTimeoutId = setTimeout(async () => {
isStarting = false; // Reset to false, as it will be set to true in askForConsentAndInitializeAdmob.
await askForConsentAndInitializeAdmob();
// Wait a bit before starting admob, to avoid the consent appearing too soon.
}, 2000);
},
false
);
export const preventAdmobAutoInitialization = () => {
if (setupTimeoutId) {
isStarting = false;
clearTimeout(setupTimeoutId);
setupTimeoutId = null;
}
};
export const initializeAdmob = async () => {
preventAdmobAutoInitialization();
await askForConsentAndInitializeAdmob();
};
export const isAdmobInitialized = () => admobStarted;
export const isAdmobInitializing = () => isStarting;
/**
* Helper to know if we are on mobile and admob is correctly initialized.
*/
@@ -334,6 +428,7 @@ namespace gdjs {
position: atTop ? 'top' : 'bottom',
size: bannerRequestedAdSizeType,
offset: 0,
npa: npaValue,
});
banner.on('load', () => {

View File

@@ -1,10 +1,10 @@
namespace gdjs {
/**
* Tools to manipulate the game window positioning and
* interactions with the operating system.
* @author arthuro555
*/
export namespace evtTools {
/**
* Tools to manipulate the game window positioning and
* interactions with the operating system.
* @author arthuro555
*/
export namespace advancedWindow {
const getElectronBrowserWindow = (runtimeScene: gdjs.RuntimeScene) => {
try {

View File

@@ -20,25 +20,41 @@ namespace gdjs {
}
export class AnchorRuntimeBehavior extends gdjs.RuntimeBehavior {
_relativeToOriginalWindowSize: any;
// Configuration
_relativeToOriginalWindowSize: boolean;
_leftEdgeAnchor: HorizontalAnchor;
_rightEdgeAnchor: HorizontalAnchor;
_topEdgeAnchor: any;
_bottomEdgeAnchor: any;
_invalidDistances: boolean = true;
_leftEdgeDistance: number = 0;
_rightEdgeDistance: number = 0;
_topEdgeDistance: number = 0;
_bottomEdgeDistance: number = 0;
_topEdgeAnchor: VerticalAnchor;
_bottomEdgeAnchor: VerticalAnchor;
_useLegacyBottomAndRightAnchors: boolean = false;
// State
_hasJustBeenCreated: boolean = true;
_leftEdgeDistance: float = 0;
_rightEdgeDistance: float = 0;
_topEdgeDistance: float = 0;
_bottomEdgeDistance: float = 0;
_oldDrawableX: float = 0;
_oldDrawableY: float = 0;
_oldWidth: float = 0;
_oldHeight: float = 0;
_parentOldMinX: float = 0;
_parentOldMinY: float = 0;
_parentOldMaxX: float = 0;
_parentOldMaxY: float = 0;
constructor(
instanceContainer: gdjs.RuntimeInstanceContainer,
behaviorData,
owner: gdjs.RuntimeObject
) {
super(instanceContainer, behaviorData, owner);
this._relativeToOriginalWindowSize = !!behaviorData.relativeToOriginalWindowSize;
this._relativeToOriginalWindowSize =
!!behaviorData.relativeToOriginalWindowSize;
this._leftEdgeAnchor = behaviorData.leftEdgeAnchor;
this._rightEdgeAnchor = behaviorData.rightEdgeAnchor;
this._topEdgeAnchor = behaviorData.topEdgeAnchor;
@@ -80,266 +96,307 @@ namespace gdjs {
return true;
}
onActivate() {
this._invalidDistances = true;
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
const objectHasMoved =
this._oldDrawableX !== this.owner.getDrawableX() ||
this._oldDrawableY !== this.owner.getDrawableY() ||
this._oldWidth !== this.owner.getWidth() ||
this._oldHeight !== this.owner.getHeight();
if (objectHasMoved) {
this._updateAnchorDistances(instanceContainer);
}
const parentHasResized =
this._parentOldMinX !== instanceContainer.getUnrotatedViewportMinX() ||
this._parentOldMinY !== instanceContainer.getUnrotatedViewportMinY() ||
this._parentOldMaxX !== instanceContainer.getUnrotatedViewportMaxX() ||
this._parentOldMaxY !== instanceContainer.getUnrotatedViewportMaxY();
if (parentHasResized) {
this._followAnchor(instanceContainer);
}
}
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
private _updateAnchorDistances(
instanceContainer: gdjs.RuntimeInstanceContainer
) {
const workingPoint: FloatPoint = gdjs.staticArray(
gdjs.AnchorRuntimeBehavior.prototype.doStepPreEvents
) as FloatPoint;
let parentMinX = instanceContainer.getUnrotatedViewportMinX();
let parentMinY = instanceContainer.getUnrotatedViewportMinY();
let parentMaxX = instanceContainer.getUnrotatedViewportMaxX();
let parentMaxY = instanceContainer.getUnrotatedViewportMaxY();
let parentCenterX = (parentMaxX + parentMinX) / 2;
let parentCenterY = (parentMaxY + parentMinY) / 2;
let parentWidth = parentMaxX - parentMinX;
let parentHeight = parentMaxY - parentMinY;
const layer = instanceContainer.getLayer(this.owner.getLayer());
if (this._invalidDistances) {
let parentMinX = this._parentOldMinX;
let parentMinY = this._parentOldMinY;
let parentMaxX = this._parentOldMaxX;
let parentMaxY = this._parentOldMaxY;
if (this._hasJustBeenCreated) {
if (this._relativeToOriginalWindowSize) {
parentMinX = instanceContainer.getInitialUnrotatedViewportMinX();
parentMinY = instanceContainer.getInitialUnrotatedViewportMinY();
parentMaxX = instanceContainer.getInitialUnrotatedViewportMaxX();
parentMaxY = instanceContainer.getInitialUnrotatedViewportMaxY();
parentCenterX = (parentMaxX + parentMinX) / 2;
parentCenterY = (parentMaxY + parentMinY) / 2;
parentWidth = parentMaxX - parentMinX;
parentHeight = parentMaxY - parentMinY;
} else {
parentMinX = instanceContainer.getUnrotatedViewportMinX();
parentMinY = instanceContainer.getUnrotatedViewportMinY();
parentMaxX = instanceContainer.getUnrotatedViewportMaxX();
parentMaxY = instanceContainer.getUnrotatedViewportMaxY();
}
}
const parentCenterX = (parentMaxX + parentMinX) / 2;
const parentCenterY = (parentMaxY + parentMinY) / 2;
const parentWidth = parentMaxX - parentMinX;
const parentHeight = parentMaxY - parentMinY;
//Calculate the distances from the window's bounds.
const topLeftPixel = this._relativeToOriginalWindowSize
? [this.owner.getDrawableX(), this.owner.getDrawableY()]
: this._convertInverseCoords(
instanceContainer,
layer,
this.owner.getDrawableX(),
this.owner.getDrawableY(),
workingPoint
);
//Calculate the distances from the window's bounds.
const topLeftPixel = this._relativeToOriginalWindowSize
? [this.owner.getDrawableX(), this.owner.getDrawableY()]
: this._convertInverseCoords(
instanceContainer,
layer,
this.owner.getDrawableX(),
this.owner.getDrawableY(),
workingPoint
);
// Left edge
if (this._leftEdgeAnchor === HorizontalAnchor.WindowLeft) {
this._leftEdgeDistance = topLeftPixel[0] - parentMinX;
} else if (this._leftEdgeAnchor === HorizontalAnchor.WindowRight) {
this._leftEdgeDistance = topLeftPixel[0] - parentMaxX;
} else if (this._leftEdgeAnchor === HorizontalAnchor.Proportional) {
this._leftEdgeDistance = (topLeftPixel[0] - parentMinX) / parentWidth;
} else if (this._leftEdgeAnchor === HorizontalAnchor.WindowCenter) {
this._leftEdgeDistance = topLeftPixel[0] - parentCenterX;
// Left edge
if (this._leftEdgeAnchor === HorizontalAnchor.WindowLeft) {
this._leftEdgeDistance = topLeftPixel[0] - parentMinX;
} else if (this._leftEdgeAnchor === HorizontalAnchor.WindowRight) {
this._leftEdgeDistance = topLeftPixel[0] - parentMaxX;
} else if (this._leftEdgeAnchor === HorizontalAnchor.Proportional) {
this._leftEdgeDistance = (topLeftPixel[0] - parentMinX) / parentWidth;
} else if (this._leftEdgeAnchor === HorizontalAnchor.WindowCenter) {
this._leftEdgeDistance = topLeftPixel[0] - parentCenterX;
}
// Top edge
if (this._topEdgeAnchor === VerticalAnchor.WindowTop) {
this._topEdgeDistance = topLeftPixel[1] - parentMinY;
} else if (this._topEdgeAnchor === VerticalAnchor.WindowBottom) {
this._topEdgeDistance = topLeftPixel[1] - parentMaxY;
} else if (this._topEdgeAnchor === VerticalAnchor.Proportional) {
this._topEdgeDistance = (topLeftPixel[1] - parentMinY) / parentHeight;
} else if (this._topEdgeAnchor === VerticalAnchor.WindowCenter) {
this._topEdgeDistance = topLeftPixel[1] - parentCenterY;
}
// It's fine to reuse workingPoint as topLeftPixel is no longer used.
const bottomRightPixel = this._relativeToOriginalWindowSize
? [
this.owner.getDrawableX() + this.owner.getWidth(),
this.owner.getDrawableY() + this.owner.getHeight(),
]
: this._convertInverseCoords(
instanceContainer,
layer,
this.owner.getDrawableX() + this.owner.getWidth(),
this.owner.getDrawableY() + this.owner.getHeight(),
workingPoint
);
// Right edge
if (this._rightEdgeAnchor === HorizontalAnchor.WindowLeft) {
this._rightEdgeDistance = bottomRightPixel[0] - parentMinX;
} else if (this._rightEdgeAnchor === HorizontalAnchor.WindowRight) {
this._rightEdgeDistance = bottomRightPixel[0] - parentMaxX;
} else if (this._rightEdgeAnchor === HorizontalAnchor.Proportional) {
this._rightEdgeDistance =
(bottomRightPixel[0] - parentMinX) / parentWidth;
} else if (this._rightEdgeAnchor === HorizontalAnchor.WindowCenter) {
this._rightEdgeDistance = bottomRightPixel[0] - parentCenterX;
}
// Bottom edge
if (this._bottomEdgeAnchor === VerticalAnchor.WindowTop) {
this._bottomEdgeDistance = bottomRightPixel[1] - parentMinY;
} else if (this._bottomEdgeAnchor === VerticalAnchor.WindowBottom) {
this._bottomEdgeDistance = bottomRightPixel[1] - parentMaxY;
} else if (this._bottomEdgeAnchor === VerticalAnchor.Proportional) {
this._bottomEdgeDistance =
(bottomRightPixel[1] - parentMinY) / parentHeight;
} else if (this._bottomEdgeAnchor === VerticalAnchor.WindowCenter) {
this._bottomEdgeDistance = bottomRightPixel[1] - parentCenterY;
}
this._hasJustBeenCreated = false;
}
private _followAnchor(instanceContainer: gdjs.RuntimeInstanceContainer) {
const workingPoint: FloatPoint = gdjs.staticArray(
gdjs.AnchorRuntimeBehavior.prototype.doStepPreEvents
) as FloatPoint;
const layer = instanceContainer.getLayer(this.owner.getLayer());
let parentMinX = instanceContainer.getUnrotatedViewportMinX();
let parentMinY = instanceContainer.getUnrotatedViewportMinY();
let parentMaxX = instanceContainer.getUnrotatedViewportMaxX();
let parentMaxY = instanceContainer.getUnrotatedViewportMaxY();
const parentCenterX = (parentMaxX + parentMinX) / 2;
const parentCenterY = (parentMaxY + parentMinY) / 2;
const parentWidth = parentMaxX - parentMinX;
const parentHeight = parentMaxY - parentMinY;
//Move and resize the object if needed
let leftPixel = 0;
let topPixel = 0;
let rightPixel = 0;
let bottomPixel = 0;
// Left edge
if (this._leftEdgeAnchor === HorizontalAnchor.WindowLeft) {
leftPixel = parentMinX + this._leftEdgeDistance;
} else if (this._leftEdgeAnchor === HorizontalAnchor.WindowRight) {
leftPixel = parentMaxX + this._leftEdgeDistance;
} else if (this._leftEdgeAnchor === HorizontalAnchor.Proportional) {
leftPixel = parentMinX + this._leftEdgeDistance * parentWidth;
} else if (this._leftEdgeAnchor === HorizontalAnchor.WindowCenter) {
leftPixel = parentCenterX + this._leftEdgeDistance;
}
// Top edge
if (this._topEdgeAnchor === VerticalAnchor.WindowTop) {
topPixel = parentMinY + this._topEdgeDistance;
} else if (this._topEdgeAnchor === VerticalAnchor.WindowBottom) {
topPixel = parentMaxY + this._topEdgeDistance;
} else if (this._topEdgeAnchor === VerticalAnchor.Proportional) {
topPixel = parentMinY + this._topEdgeDistance * parentHeight;
} else if (this._topEdgeAnchor === VerticalAnchor.WindowCenter) {
topPixel = parentCenterY + this._topEdgeDistance;
}
// Right edge
if (this._rightEdgeAnchor === HorizontalAnchor.WindowLeft) {
rightPixel = parentMinX + this._rightEdgeDistance;
} else if (this._rightEdgeAnchor === HorizontalAnchor.WindowRight) {
rightPixel = parentMaxX + this._rightEdgeDistance;
} else if (this._rightEdgeAnchor === HorizontalAnchor.Proportional) {
rightPixel = parentMinX + this._rightEdgeDistance * parentWidth;
} else if (this._rightEdgeAnchor === HorizontalAnchor.WindowCenter) {
rightPixel = parentCenterX + this._rightEdgeDistance;
}
// Bottom edge
if (this._bottomEdgeAnchor === VerticalAnchor.WindowTop) {
bottomPixel = parentMinY + this._bottomEdgeDistance;
} else if (this._bottomEdgeAnchor === VerticalAnchor.WindowBottom) {
bottomPixel = parentMaxY + this._bottomEdgeDistance;
} else if (this._bottomEdgeAnchor === VerticalAnchor.Proportional) {
bottomPixel = parentMinY + this._bottomEdgeDistance * parentHeight;
} else if (this._bottomEdgeAnchor === VerticalAnchor.WindowCenter) {
bottomPixel = parentCenterY + this._bottomEdgeDistance;
}
// It's fine to reuse workingPoint as topLeftPixel is no longer used.
const topLeftCoord = this._convertCoords(
instanceContainer,
layer,
leftPixel,
topPixel,
workingPoint
);
let left = topLeftCoord[0];
let top = topLeftCoord[1];
const bottomRightCoord = this._convertCoords(
instanceContainer,
layer,
rightPixel,
bottomPixel,
workingPoint
);
const right = bottomRightCoord[0];
const bottom = bottomRightCoord[1];
// Compatibility with GD <= 5.0.133
if (this._useLegacyBottomAndRightAnchors) {
//Move and resize the object according to the anchors
if (this._rightEdgeAnchor !== HorizontalAnchor.None) {
this.owner.setWidth(right - left);
}
// Top edge
if (this._topEdgeAnchor === VerticalAnchor.WindowTop) {
this._topEdgeDistance = topLeftPixel[1] - parentMinY;
} else if (this._topEdgeAnchor === VerticalAnchor.WindowBottom) {
this._topEdgeDistance = topLeftPixel[1] - parentMaxY;
} else if (this._topEdgeAnchor === VerticalAnchor.Proportional) {
this._topEdgeDistance = (topLeftPixel[1] - parentMinY) / parentHeight;
} else if (this._topEdgeAnchor === VerticalAnchor.WindowCenter) {
this._topEdgeDistance = topLeftPixel[1] - parentCenterY;
if (this._bottomEdgeAnchor !== VerticalAnchor.None) {
this.owner.setHeight(bottom - top);
}
// It's fine to reuse workingPoint as topLeftPixel is no longer used.
const bottomRightPixel = this._relativeToOriginalWindowSize
? [
this.owner.getDrawableX() + this.owner.getWidth(),
this.owner.getDrawableY() + this.owner.getHeight(),
]
: this._convertInverseCoords(
instanceContainer,
layer,
this.owner.getDrawableX() + this.owner.getWidth(),
this.owner.getDrawableY() + this.owner.getHeight(),
workingPoint
);
// Right edge
if (this._rightEdgeAnchor === HorizontalAnchor.WindowLeft) {
this._rightEdgeDistance = bottomRightPixel[0] - parentMinX;
} else if (this._rightEdgeAnchor === HorizontalAnchor.WindowRight) {
this._rightEdgeDistance = bottomRightPixel[0] - parentMaxX;
} else if (this._rightEdgeAnchor === HorizontalAnchor.Proportional) {
this._rightEdgeDistance =
(bottomRightPixel[0] - parentMinX) / parentWidth;
} else if (this._rightEdgeAnchor === HorizontalAnchor.WindowCenter) {
this._rightEdgeDistance = bottomRightPixel[0] - parentCenterX;
if (this._leftEdgeAnchor !== HorizontalAnchor.None) {
this.owner.setX(left + this.owner.getX() - this.owner.getDrawableX());
}
// Bottom edge
if (this._bottomEdgeAnchor === VerticalAnchor.WindowTop) {
this._bottomEdgeDistance = bottomRightPixel[1] - parentMinY;
} else if (this._bottomEdgeAnchor === VerticalAnchor.WindowBottom) {
this._bottomEdgeDistance = bottomRightPixel[1] - parentMaxY;
} else if (this._bottomEdgeAnchor === VerticalAnchor.Proportional) {
this._bottomEdgeDistance =
(bottomRightPixel[1] - parentMinY) / parentHeight;
} else if (this._bottomEdgeAnchor === VerticalAnchor.WindowCenter) {
this._bottomEdgeDistance = bottomRightPixel[1] - parentCenterY;
if (this._topEdgeAnchor !== VerticalAnchor.None) {
this.owner.setY(top + this.owner.getY() - this.owner.getDrawableY());
}
this._invalidDistances = false;
} else {
//Move and resize the object if needed
let leftPixel = 0;
let topPixel = 0;
let rightPixel = 0;
let bottomPixel = 0;
// Left edge
if (this._leftEdgeAnchor === HorizontalAnchor.WindowLeft) {
leftPixel = parentMinX + this._leftEdgeDistance;
} else if (this._leftEdgeAnchor === HorizontalAnchor.WindowRight) {
leftPixel = parentMaxX + this._leftEdgeDistance;
} else if (this._leftEdgeAnchor === HorizontalAnchor.Proportional) {
leftPixel = parentMinX + this._leftEdgeDistance * parentWidth;
} else if (this._leftEdgeAnchor === HorizontalAnchor.WindowCenter) {
leftPixel = parentCenterX + this._leftEdgeDistance;
}
// Top edge
if (this._topEdgeAnchor === VerticalAnchor.WindowTop) {
topPixel = parentMinY + this._topEdgeDistance;
} else if (this._topEdgeAnchor === VerticalAnchor.WindowBottom) {
topPixel = parentMaxY + this._topEdgeDistance;
} else if (this._topEdgeAnchor === VerticalAnchor.Proportional) {
topPixel = parentMinY + this._topEdgeDistance * parentHeight;
} else if (this._topEdgeAnchor === VerticalAnchor.WindowCenter) {
topPixel = parentCenterY + this._topEdgeDistance;
}
// Right edge
if (this._rightEdgeAnchor === HorizontalAnchor.WindowLeft) {
rightPixel = parentMinX + this._rightEdgeDistance;
} else if (this._rightEdgeAnchor === HorizontalAnchor.WindowRight) {
rightPixel = parentMaxX + this._rightEdgeDistance;
} else if (this._rightEdgeAnchor === HorizontalAnchor.Proportional) {
rightPixel = parentMinX + this._rightEdgeDistance * parentWidth;
} else if (this._rightEdgeAnchor === HorizontalAnchor.WindowCenter) {
rightPixel = parentCenterX + this._rightEdgeDistance;
}
// Bottom edge
if (this._bottomEdgeAnchor === VerticalAnchor.WindowTop) {
bottomPixel = parentMinY + this._bottomEdgeDistance;
} else if (this._bottomEdgeAnchor === VerticalAnchor.WindowBottom) {
bottomPixel = parentMaxY + this._bottomEdgeDistance;
} else if (this._bottomEdgeAnchor === VerticalAnchor.Proportional) {
bottomPixel = parentMinY + this._bottomEdgeDistance * parentHeight;
} else if (this._bottomEdgeAnchor === VerticalAnchor.WindowCenter) {
bottomPixel = parentCenterY + this._bottomEdgeDistance;
}
// It's fine to reuse workingPoint as topLeftPixel is no longer used.
const topLeftCoord = this._convertCoords(
instanceContainer,
layer,
leftPixel,
topPixel,
workingPoint
);
let left = topLeftCoord[0];
let top = topLeftCoord[1];
const bottomRightCoord = this._convertCoords(
instanceContainer,
layer,
rightPixel,
bottomPixel,
workingPoint
);
const right = bottomRightCoord[0];
const bottom = bottomRightCoord[1];
// Compatibility with GD <= 5.0.133
if (this._useLegacyBottomAndRightAnchors) {
//Move and resize the object according to the anchors
if (this._rightEdgeAnchor !== HorizontalAnchor.None) {
this.owner.setWidth(right - left);
}
if (this._bottomEdgeAnchor !== VerticalAnchor.None) {
this.owner.setHeight(bottom - top);
}
}
// End of compatibility code
else {
// Resize if right and left anchors are set
if (
this._rightEdgeAnchor !== HorizontalAnchor.None &&
this._leftEdgeAnchor !== HorizontalAnchor.None
) {
const width = right - left;
this.owner.setX(
this.owner.getX() === this.owner.getDrawableX()
? left
: // It uses the position of the origin relatively to the object
// size to apply it with the new size.
// This is the same as doing:
// lerp(left, right, (this.owner.getX() - this.owner.getDrawableX() / this.owner.getWidth())
// But, the division is done at the end to avoid rounding errors.
left +
((this.owner.getX() - this.owner.getDrawableX()) * width) /
this.owner.getWidth()
);
this.owner.setWidth(width);
} else {
if (this._leftEdgeAnchor !== HorizontalAnchor.None) {
this.owner.setX(
left + this.owner.getX() - this.owner.getDrawableX()
);
}
if (this._rightEdgeAnchor !== HorizontalAnchor.None) {
this.owner.setX(
right +
this.owner.getX() -
this.owner.getDrawableX() -
this.owner.getWidth()
);
}
}
// Resize if top and bottom anchors are set
if (
this._bottomEdgeAnchor !== VerticalAnchor.None &&
this._topEdgeAnchor !== VerticalAnchor.None
) {
const height = bottom - top;
this.owner.setY(
this.owner.getY() === this.owner.getDrawableY()
? top
: top +
((this.owner.getY() - this.owner.getDrawableY()) * height) /
this.owner.getHeight()
);
this.owner.setHeight(height);
} else {
if (this._topEdgeAnchor !== VerticalAnchor.None) {
this.owner.setY(
top + this.owner.getY() - this.owner.getDrawableY()
);
}
}
// End of compatibility code
else {
// Resize if right and left anchors are set
if (
this._rightEdgeAnchor !== HorizontalAnchor.None &&
this._leftEdgeAnchor !== HorizontalAnchor.None
) {
const width = right - left;
this.owner.setX(
this.owner.getX() === this.owner.getDrawableX()
? left
: // It uses the position of the origin relatively to the object
// size to apply it with the new size.
// This is the same as doing:
// lerp(left, right, (this.owner.getX() - this.owner.getDrawableX() / this.owner.getWidth())
// But, the division is done at the end to avoid rounding errors.
left +
((this.owner.getX() - this.owner.getDrawableX()) * width) /
this.owner.getWidth()
);
this.owner.setWidth(width);
} else {
if (this._leftEdgeAnchor !== HorizontalAnchor.None) {
this.owner.setX(
left + this.owner.getX() - this.owner.getDrawableX()
);
}
if (this._rightEdgeAnchor !== HorizontalAnchor.None) {
this.owner.setX(
right +
this.owner.getX() -
this.owner.getDrawableX() -
this.owner.getWidth()
);
}
}
// Resize if top and bottom anchors are set
if (
this._bottomEdgeAnchor !== VerticalAnchor.None &&
this._topEdgeAnchor !== VerticalAnchor.None
) {
const height = bottom - top;
if (this._bottomEdgeAnchor !== VerticalAnchor.None) {
this.owner.setY(
this.owner.getY() === this.owner.getDrawableY()
? top
: top +
((this.owner.getY() - this.owner.getDrawableY()) * height) /
this.owner.getHeight()
bottom +
this.owner.getY() -
this.owner.getDrawableY() -
this.owner.getHeight()
);
this.owner.setHeight(height);
} else {
if (this._topEdgeAnchor !== VerticalAnchor.None) {
this.owner.setY(
top + this.owner.getY() - this.owner.getDrawableY()
);
}
if (this._bottomEdgeAnchor !== VerticalAnchor.None) {
this.owner.setY(
bottom +
this.owner.getY() -
this.owner.getDrawableY() -
this.owner.getHeight()
);
}
}
}
}
this._oldDrawableX = this.owner.getDrawableX();
this._oldDrawableY = this.owner.getDrawableY();
this._oldWidth = this.owner.getWidth();
this._oldHeight = this.owner.getHeight();
this._parentOldMinX = instanceContainer.getUnrotatedViewportMinX();
this._parentOldMinY = instanceContainer.getUnrotatedViewportMinY();
this._parentOldMaxX = instanceContainer.getUnrotatedViewportMaxX();
this._parentOldMaxY = instanceContainer.getUnrotatedViewportMaxY();
}
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}

View File

@@ -54,7 +54,7 @@ module.exports = {
objectProperties
.getOrCreate('text')
.setValue(objectContent.text)
.setType('textarea')
.setType('multilinestring')
.setLabel(_('BBCode text'));
objectProperties
@@ -81,6 +81,19 @@ module.exports = {
.setLabel(_('Base alignment'))
.setGroup(_('Appearance'));
if (!objectContent.verticalTextAlignment) {
objectContent.verticalTextAlignment = 'top';
}
objectProperties
.getOrCreate('verticalTextAlignment')
.setValue(objectContent.verticalTextAlignment)
.setType('choice')
.addExtraInfo('top')
.addExtraInfo('center')
.addExtraInfo('bottom')
.setLabel(_('Vertical alignment'))
.setGroup(_('Appearance'));
objectProperties
.getOrCreate('fontFamily')
.setValue(objectContent.fontFamily)
@@ -89,13 +102,6 @@ module.exports = {
.setLabel(_('Font'))
.setGroup(_('Font'));
objectProperties
.getOrCreate('wordWrap')
.setValue(objectContent.wordWrap ? 'true' : 'false')
.setType('boolean')
.setLabel(_('Word wrapping'))
.setGroup(_('Appearance'));
objectProperties
.getOrCreate('visible')
.setValue(objectContent.visible ? 'true' : 'false')
@@ -106,15 +112,14 @@ module.exports = {
return objectProperties;
};
objectBBText.content = {
text:
'[b]bold[/b] [i]italic[/i] [size=15]smaller[/size] [font=times]times[/font] font\n[spacing=12]spaced out[/spacing]\n[outline=yellow]outlined[/outline] [shadow=red]DropShadow[/shadow] ',
text: '[b]bold[/b] [i]italic[/i] [size=15]smaller[/size] [font=times]times[/font] font\n[spacing=12]spaced out[/spacing]\n[outline=yellow]outlined[/outline] [shadow=red]DropShadow[/shadow] ',
opacity: 255,
fontSize: 20,
visible: true,
color: '0;0;0',
fontFamily: 'Arial',
align: 'left',
wordWrap: true,
verticalTextAlignment: 'top',
};
objectBBText.updateInitialInstanceProperty = function (
@@ -193,9 +198,10 @@ module.exports = {
parameterType === 'string' ||
parameterType === 'stringWithSelector'
) {
const parameterOptions = gd.ParameterOptions.makeNewOptions().setDescription(
property.paramLabel
);
const parameterOptions =
gd.ParameterOptions.makeNewOptions().setDescription(
property.paramLabel
);
if (property.options) {
parameterOptions.setTypeExtraInfo(
stringifyOptions(property.options)
@@ -245,9 +251,10 @@ module.exports = {
parameterType === 'number' ||
parameterType === 'stringWithSelector'
) {
const parameterOptions = gd.ParameterOptions.makeNewOptions().setDescription(
property.paramLabel
);
const parameterOptions =
gd.ParameterOptions.makeNewOptions().setDescription(
property.paramLabel
);
if (property.options) {
parameterOptions.setTypeExtraInfo(
stringifyOptions(property.options)
@@ -370,19 +377,6 @@ module.exports = {
expressionLabel: _('Get the text alignment'),
expressionDescription: _('Get the text alignment'),
},
{
functionName: 'WordWrap',
iconPath: 'res/actions/scaleWidth24_black.png',
type: 'boolean',
instructionLabel: _('Word wrap'),
paramLabel: _('Word wrap'),
conditionDescription: _('Check if word wrap is enabled.'),
conditionSentence: _('Word wrap is enabled'),
actionDescription: _('Set word wrap'),
actionSentence: _('Activate word wrap for _PARAM0_: _PARAM1_'),
expressionLabel: '',
expressionDescription: '',
},
{
functionName: 'WrappingWidth',
iconPath: 'res/actions/scaleWidth24_black.png',
@@ -404,6 +398,35 @@ module.exports = {
addSettersAndGettersToObject(object, setterAndGetterProperties, 'BBText');
object
.addCondition(
'IsWordWrap',
_('Word wrapping'),
_('Check if word wrapping is enabled.'),
_('_PARAM0_ word wrapping is enabled'),
'',
'res/conditions/wordWrap24_black.png',
'res/conditions/wordWrap_black.png'
)
.addParameter('object', 'BBText', 'BBText', false)
.getCodeExtraInformation()
.setFunctionName('isWrapping');
object
.addAction(
'SetWordWrap',
_('Word wrapping'),
_('De/activate word wrapping.'),
_('Activate word wrapping of _PARAM0_: _PARAM1_'),
'',
'res/actions/wordWrap24_black.png',
'res/actions/wordWrap_black.png'
)
.addParameter('object', 'BBText', 'BBText', false)
.addParameter('yesorno', _('Activate word wrapping'), '', false)
.getCodeExtraInformation()
.setFunctionName('setWrapping');
object
.addAction(
`SetFontFamily2`,
@@ -501,7 +524,6 @@ module.exports = {
fontSize: '24px',
fill: '#cccccc',
tagStyle: 'bbcode',
wordWrap: true,
wordWrapWidth: 250, // This value is the default wrapping width of the runtime object.
align: 'left',
},
@@ -573,11 +595,18 @@ module.exports = {
});
}
const wordWrap = object.content.wordWrap;
const wordWrap = this._instance.hasCustomSize();
if (wordWrap !== this._pixiObject._style.wordWrap) {
this._pixiObject._style.wordWrap = wordWrap;
this._pixiObject.dirty = true;
}
if (this._instance.hasCustomSize()) {
const customWidth = this.getCustomWidth();
if (this._pixiObject._style.wordWrapWidth !== customWidth) {
this._pixiObject._style.wordWrapWidth = customWidth;
this._pixiObject.dirty = true;
}
}
const align = object.content.align;
if (align !== this._pixiObject._style.align) {
@@ -585,25 +614,42 @@ module.exports = {
this._pixiObject.dirty = true;
}
this._pixiObject.position.x =
this._instance.getX() + this._pixiObject.width / 2;
if (this._instance.hasCustomSize()) {
const alignmentX =
object.content.align === 'right'
? 1
: object.content.align === 'center'
? 0.5
: 0;
const width = this.getCustomWidth();
// A vector from the custom size center to the renderer center.
const centerToCenterX =
(width - this._pixiObject.width) * (alignmentX - 0.5);
this._pixiObject.position.x = this._instance.getX() + width / 2;
this._pixiObject.anchor.x =
0.5 - centerToCenterX / this._pixiObject.width;
} else {
this._pixiObject.position.x =
this._instance.getX() + this._pixiObject.width / 2;
this._pixiObject.anchor.x = 0.5;
}
const alignmentY =
object.content.verticalTextAlignment === 'bottom'
? 1
: object.content.verticalTextAlignment === 'center'
? 0.5
: 0;
this._pixiObject.position.y =
this._instance.getY() + this._pixiObject.height / 2;
this._instance.getY() + this._pixiObject.height * (0.5 - alignmentY);
this._pixiObject.anchor.y = 0.5;
this._pixiObject.rotation = RenderedInstance.toRad(
this._instance.getAngle()
);
if (this._instance.hasCustomSize() && this._pixiObject) {
const customWidth = this.getCustomWidth();
if (
this._pixiObject &&
this._pixiObject._style.wordWrapWidth !== customWidth
) {
this._pixiObject._style.wordWrapWidth = customWidth;
this._pixiObject.dirty = true;
}
}
// Do not hide completely an object so it can still be manipulated
const alphaForDisplay = Math.max(
this._instance.getOpacity() / 255,
@@ -625,6 +671,19 @@ module.exports = {
getDefaultHeight() {
return this._pixiObject.height;
}
getOriginY() {
const object = gd.castObject(
this._associatedObjectConfiguration,
gd.ObjectJsImplementation
);
const height = this.getHeight();
return object.content.verticalTextAlignment === 'bottom'
? height
: object.content.verticalTextAlignment === 'center'
? height / 2
: 0;
}
}
objectsRenderingService.registerInstanceRenderer(

View File

@@ -29,9 +29,9 @@ namespace gdjs {
runtimeObject._color[2]
),
tagStyle: 'bbcode',
wordWrap: runtimeObject._wordWrap,
wordWrap: runtimeObject._wrapping,
wordWrapWidth: runtimeObject._wrappingWidth,
align: runtimeObject._align as PIXI.TextStyleAlign | undefined,
align: runtimeObject._textAlign as PIXI.TextStyleAlign | undefined,
},
});
instanceContainer
@@ -39,10 +39,7 @@ namespace gdjs {
.getRenderer()
.addRendererObject(this._pixiObject, runtimeObject.getZOrder());
// Set the anchor in the center, so that the object rotates around
// its center
this._pixiObject.anchor.x = 0.5;
this._pixiObject.anchor.y = 0.5;
this.updateAlignment();
this.updateText();
this.updatePosition();
this.updateAngle();
@@ -55,7 +52,7 @@ namespace gdjs {
updateWordWrap(): void {
//@ts-ignore Private member usage.
this._pixiObject._style.wordWrap = this._object._wordWrap;
this._pixiObject._style.wordWrap = this._object._wrapping;
this._pixiObject.dirty = true;
this.updatePosition();
}
@@ -84,7 +81,7 @@ namespace gdjs {
updateAlignment(): void {
//@ts-ignore Private member usage.
this._pixiObject._style.align = this._object._align;
this._pixiObject._style.align = this._object._textAlign;
this._pixiObject.dirty = true;
}
@@ -106,9 +103,38 @@ namespace gdjs {
}
updatePosition(): void {
this._pixiObject.position.x = this._object.x + this._pixiObject.width / 2;
if (this._object.isWrapping()) {
const alignmentX =
this._object._textAlign === 'right'
? 1
: this._object._textAlign === 'center'
? 0.5
: 0;
const width = this._object.getWrappingWidth();
// A vector from the custom size center to the renderer center.
const centerToCenterX =
(width - this._pixiObject.width) * (alignmentX - 0.5);
this._pixiObject.position.x = this._object.x + width / 2;
this._pixiObject.anchor.x =
0.5 - centerToCenterX / this._pixiObject.width;
} else {
this._pixiObject.position.x =
this._object.x + this._pixiObject.width / 2;
this._pixiObject.anchor.x = 0.5;
}
const alignmentY =
this._object._verticalTextAlignment === 'bottom'
? 1
: this._object._verticalTextAlignment === 'center'
? 0.5
: 0;
this._pixiObject.position.y =
this._object.y + this._pixiObject.height / 2;
this._object.y + this._pixiObject.height * (0.5 - alignmentY);
this._pixiObject.anchor.y = 0.5;
}
updateAngle(): void {

View File

@@ -19,6 +19,7 @@ namespace gdjs {
wordWrap: boolean;
/** Alignment of the text: "left", "center" or "right" */
align: 'left' | 'center' | 'right';
verticalTextAlignment: 'top' | 'center' | 'bottom';
};
};
export type BBTextObjectData = ObjectData & BBTextObjectDataType;
@@ -32,6 +33,7 @@ namespace gdjs {
wwrap: boolean;
wwidth: float;
align: string;
vta: string;
hidden: boolean;
};
@@ -43,7 +45,8 @@ namespace gdjs {
*/
export class BBTextRuntimeObject
extends gdjs.RuntimeObject
implements gdjs.OpacityHandler {
implements gdjs.OpacityHandler
{
_opacity: float;
_text: string;
@@ -51,13 +54,14 @@ namespace gdjs {
/** color in format [r, g, b], where each component is in the range [0, 255] */
_color: integer[];
_fontFamily: string;
_fontSize: number;
_fontSize: float;
_wordWrap: boolean;
_wrapping: boolean = false;
_wrappingWidth: float = 250;
// This value is the default wrapping width of the runtime object.
_align: string;
_textAlign: string;
_verticalTextAlignment: string;
_renderer: gdjs.BBTextRuntimeObjectRenderer;
// While this should rather be exposed as a property for all objects, honor the "visible"
@@ -80,24 +84,26 @@ namespace gdjs {
this._fontFamily = objectData.content.fontFamily;
// @ts-ignore - parseFloat should not be required, but GDevelop 5.0 beta 92 and below were storing it as a string.
this._fontSize = parseFloat(objectData.content.fontSize);
this._wordWrap = objectData.content.wordWrap;
this._align = objectData.content.align;
this._textAlign = objectData.content.align;
this._verticalTextAlignment =
objectData.content.verticalTextAlignment || 'top';
this.hidden = !objectData.content.visible;
this._renderer = new gdjs.BBTextRuntimeObjectRenderer(
this,
instanceContainer
);
this.hidden = !objectData.content.visible;
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
this.onCreated();
}
getRendererObject() {
override getRendererObject() {
return this._renderer.getRendererObject();
}
// @ts-ignore
updateFromObjectData(
override updateFromObjectData(
oldObjectData: BBTextObjectDataType,
newObjectData: BBTextObjectDataType
): boolean {
@@ -123,15 +129,23 @@ namespace gdjs {
this.setFontSize(newObjectData.content.fontSize);
}
if (oldObjectData.content.wordWrap !== newObjectData.content.wordWrap) {
this.setWordWrap(newObjectData.content.wordWrap);
this.setWrapping(newObjectData.content.wordWrap);
}
if (oldObjectData.content.align !== newObjectData.content.align) {
this.setAlignment(newObjectData.content.align);
this.setTextAlignment(newObjectData.content.align);
}
if (
oldObjectData.content.verticalTextAlignment !==
newObjectData.content.verticalTextAlignment
) {
this.setVerticalTextAlignment(
newObjectData.content.verticalTextAlignment
);
}
return true;
}
getNetworkSyncData(): BBTextObjectNetworkSyncData {
override getNetworkSyncData(): BBTextObjectNetworkSyncData {
return {
...super.getNetworkSyncData(),
text: this._text,
@@ -139,14 +153,15 @@ namespace gdjs {
c: this._color,
ff: this._fontFamily,
fs: this._fontSize,
wwrap: this._wordWrap,
wwrap: this._wrapping,
wwidth: this._wrappingWidth,
align: this._align,
align: this._textAlign,
vta: this._verticalTextAlignment,
hidden: this.hidden,
};
}
updateFromNetworkSyncData(
override updateFromNetworkSyncData(
networkSyncData: BBTextObjectNetworkSyncData
): void {
super.updateFromNetworkSyncData(networkSyncData);
@@ -166,26 +181,29 @@ namespace gdjs {
if (this._fontSize !== undefined) {
this.setFontSize(networkSyncData.fs);
}
if (this._wordWrap !== undefined) {
this.setWordWrap(networkSyncData.wwrap);
if (this._wrapping !== undefined) {
this.setWrapping(networkSyncData.wwrap);
}
if (this._wrappingWidth !== undefined) {
this.setWrappingWidth(networkSyncData.wwidth);
}
if (this._align !== undefined) {
this.setAlignment(networkSyncData.align);
if (this._textAlign !== undefined) {
this.setTextAlignment(networkSyncData.align);
}
if (this._verticalTextAlignment !== undefined) {
this.setVerticalTextAlignment(networkSyncData.vta);
}
if (this.hidden !== undefined) {
this.hide(networkSyncData.hidden);
}
}
/**
* Initialize the extra parameters that could be set for an instance.
*/
extraInitializationFromInitialInstance(initialInstanceData: InstanceData) {
override extraInitializationFromInitialInstance(
initialInstanceData: InstanceData
) {
if (initialInstanceData.customSize) {
this.setWrappingWidth(initialInstanceData.width);
this.setWrapping(true);
} else {
this.setWrappingWidth(
// This value is the default wrapping width of the runtime object.
@@ -197,7 +215,7 @@ namespace gdjs {
}
}
onDestroyed(): void {
override onDestroyed(): void {
super.onDestroyed();
this._renderer.destroy();
}
@@ -205,7 +223,7 @@ namespace gdjs {
/**
* Set the markup text to display.
*/
setBBText(text): void {
setBBText(text: string): void {
this._text = text;
this._renderer.updateText();
this.invalidateHitboxes();
@@ -218,7 +236,7 @@ namespace gdjs {
return this._text;
}
setColor(rgbColorString): void {
setColor(rgbColorString: string): void {
this._color = gdjs.rgbOrHexToRGBColor(rgbColorString);
this._renderer.updateColor();
}
@@ -231,7 +249,7 @@ namespace gdjs {
return this._color[0] + ';' + this._color[1] + ';' + this._color[2];
}
setFontSize(fontSize): void {
setFontSize(fontSize: float): void {
this._fontSize = fontSize;
this._renderer.updateFontSize();
}
@@ -240,47 +258,66 @@ namespace gdjs {
return this._fontSize;
}
setFontFamily(fontFamily): void {
setFontFamily(fontFamily: string): void {
this._fontFamily = fontFamily;
this._renderer.updateFontFamily();
}
getFontFamily() {
getFontFamily(): string {
return this._fontFamily;
}
setAlignment(align): void {
this._align = align;
/**
* @deprecated Use `setTextAlignment` instead
*/
setAlignment(align: string): void {
this.setTextAlignment(align);
}
setTextAlignment(align: string): void {
this._textAlign = align;
this._renderer.updateAlignment();
}
getAlignment() {
return this._align;
/**
* @deprecated Use `getTextAlignment` instead
*/
getAlignment(): string {
return this.getTextAlignment();
}
getTextAlignment(): string {
return this._textAlign;
}
/**
* Set object position on X axis.
* @param x The new position X of the object.
* Set the text alignment on Y axis for multiline text objects.
* @param alignment The text alignment.
*/
setX(x: float): void {
setVerticalTextAlignment(alignment: string): void {
this._verticalTextAlignment = alignment;
this._renderer.updatePosition();
}
/**
* Get the text alignment on Y axis of text object.
* @return The text alignment.
*/
getVerticalTextAlignment(): string {
return this._verticalTextAlignment;
}
override setX(x: float): void {
super.setX(x);
this._renderer.updatePosition();
}
/**
* Set object position on Y axis.
* @param y The new position Y of the object.
*/
setY(y: float): void {
override setY(y: float): void {
super.setY(y);
this._renderer.updatePosition();
}
/**
* Set the angle of the object.
* @param angle The new angle of the object.
*/
setAngle(angle: float): void {
override setAngle(angle: float): void {
super.setAngle(angle);
this._renderer.updateAngle();
}
@@ -326,31 +363,36 @@ namespace gdjs {
return this._wrappingWidth;
}
setWordWrap(wordWrap: boolean): void {
if (this._wordWrap === wordWrap) return;
setWrapping(wordWrap: boolean): void {
if (this._wrapping === wordWrap) return;
this._wordWrap = wordWrap;
this._wrapping = wordWrap;
this._renderer.updateWordWrap();
this.invalidateHitboxes();
}
getWordWrap() {
return this._wordWrap;
isWrapping() {
return this._wrapping;
}
/**
* Get the width of the object.
*/
getWidth(): float {
override getWidth(): float {
return this._renderer.getWidth();
}
/**
* Get the height of the object.
*/
getHeight(): float {
override getHeight(): float {
return this._renderer.getHeight();
}
override getDrawableY(): float {
return (
this.getY() -
(this._verticalTextAlignment === 'center'
? this.getHeight() / 2
: this._verticalTextAlignment === 'bottom'
? this.getHeight()
: 0)
);
}
}
// @ts-ignore
gdjs.registerObject('BBText::BBText', gdjs.BBTextRuntimeObject);

View File

@@ -54,7 +54,7 @@ module.exports = {
objectProperties
.getOrCreate('text')
.setValue(objectContent.text)
.setType('textarea')
.setType('multilinestring')
.setLabel(_('Text'));
objectProperties
@@ -67,6 +67,19 @@ module.exports = {
.setLabel(_('Alignment'))
.setGroup(_('Appearance'));
if (!objectContent.verticalTextAlignment) {
objectContent.verticalTextAlignment = 'top';
}
objectProperties
.getOrCreate('verticalTextAlignment')
.setValue(objectContent.verticalTextAlignment)
.setType('choice')
.addExtraInfo('top')
.addExtraInfo('center')
.addExtraInfo('bottom')
.setLabel(_('Vertical alignment'))
.setGroup(_('Appearance'));
objectProperties
.getOrCreate('bitmapFontResourceName')
.setValue(objectContent.bitmapFontResourceName)
@@ -97,18 +110,10 @@ module.exports = {
.setLabel(_('Font tint'))
.setGroup(_('Font'));
objectProperties
.getOrCreate('wordWrap')
.setValue(objectContent.wordWrap ? 'true' : 'false')
.setType('boolean')
.setLabel(_('Word wrapping'))
.setGroup(_('Appearance'));
return objectProperties;
};
bitmapTextObject.content = {
text:
'This text use the default bitmap font.\nUse a custom Bitmap Font to create your own texts.',
text: 'This text use the default bitmap font.\nUse a custom Bitmap Font to create your own texts.',
opacity: 255,
scale: 1,
fontSize: 20,
@@ -116,7 +121,7 @@ module.exports = {
bitmapFontResourceName: '',
textureAtlasResourceName: '',
align: 'left',
wordWrap: true,
verticalTextAlignment: 'top',
};
bitmapTextObject.updateInitialInstanceProperty = function (
@@ -342,7 +347,7 @@ module.exports = {
_('Alignment ("left", "right" or "center")')
)
)
.setFunctionName('getAlignment');
.setFunctionName('getTextAlignment');
object
.addAction(
@@ -362,36 +367,36 @@ module.exports = {
false
)
.getCodeExtraInformation()
.setFunctionName('setAlignment');
.setFunctionName('setTextAlignment');
object
.addCondition(
'WordWrap',
_('Word wrap'),
_('Check if word wrap is enabled.'),
_('_PARAM0_ word wrap is enabled'),
_('Word wrapping'),
_('Check if word wrapping is enabled.'),
_('_PARAM0_ word wrapping is enabled'),
'',
'res/conditions/wordWrap24_black.png',
'res/conditions/wordWrap_black.png'
)
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
.getCodeExtraInformation()
.setFunctionName('getWordWrap');
.setFunctionName('isWrapping');
object
.addAction(
'SetWordWrap',
_('Word wrap'),
_('Word wrapping'),
_('De/activate word wrapping.'),
_('Activate word wrap of _PARAM0_: _PARAM1_'),
_('Activate word wrapping of _PARAM0_: _PARAM1_'),
'',
'res/actions/wordWrap24_black.png',
'res/actions/wordWrap_black.png'
)
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
.addParameter('yesorno', _('Activate word wrap'), '', false)
.addParameter('yesorno', _('Activate word wrapping'), '', false)
.getCodeExtraInformation()
.setFunctionName('setWordWrap');
.setFunctionName('setWrapping');
object
.addExpressionAndConditionAndAction(
@@ -665,9 +670,8 @@ module.exports = {
this._pixiObject.align = align;
const color = object.content.tint;
this._pixiObject.tint = objectsRenderingService.rgbOrHexToHexNumber(
color
);
this._pixiObject.tint =
objectsRenderingService.rgbOrHexToHexNumber(color);
const scale = object.content.scale;
this._pixiObject.scale.set(scale);
@@ -706,20 +710,46 @@ module.exports = {
}
// Set up the wrapping width if enabled.
const wordWrap = object.content.wordWrap;
if (wordWrap && this._instance.hasCustomSize()) {
this._pixiObject.maxWidth =
this.getCustomWidth() / this._pixiObject.scale.x;
this._pixiObject.dirty = true;
} else {
this._pixiObject.maxWidth = 0;
const oldMaxWidth = this._pixiObject.maxWidth;
this._pixiObject.maxWidth = this._instance.hasCustomSize()
? this.getCustomWidth() / this._pixiObject.scale.x
: 0;
if (oldMaxWidth !== this._pixiObject.maxWidth) {
this._pixiObject.dirty = true;
}
this._pixiObject.position.x =
this._instance.getX() + (this._pixiObject.textWidth * scale) / 2;
if (this._instance.hasCustomSize()) {
const alignmentX =
object.content.align === 'right'
? 1
: object.content.align === 'center'
? 0.5
: 0;
const width = this.getCustomWidth();
// A vector from the custom size center to the renderer center.
const centerToCenterX =
(width - this._pixiObject.width) * (alignmentX - 0.5);
this._pixiObject.position.x = this._instance.getX() + width / 2;
this._pixiObject.anchor.x =
0.5 - centerToCenterX / this._pixiObject.width;
} else {
this._pixiObject.position.x =
this._instance.getX() + this._pixiObject.width / 2;
this._pixiObject.anchor.x = 0.5;
}
const alignmentY =
object.content.verticalTextAlignment === 'bottom'
? 1
: object.content.verticalTextAlignment === 'center'
? 0.5
: 0;
this._pixiObject.position.y =
this._instance.getY() + (this._pixiObject.textHeight * scale) / 2;
this._instance.getY() + this._pixiObject.height * (0.5 - alignmentY);
this._pixiObject.anchor.y = 0.5;
this._pixiObject.rotation = RenderedInstance.toRad(
this._instance.getAngle()
);
@@ -740,19 +770,26 @@ module.exports = {
releaseBitmapFont(fontName);
}
/**
* Return the width of the instance, when it's not resized.
*/
getDefaultWidth() {
return this._pixiObject.width;
}
/**
* Return the height of the instance, when it's not resized.
*/
getDefaultHeight() {
return this._pixiObject.height;
}
getOriginY() {
const object = gd.castObject(
this._associatedObjectConfiguration,
gd.ObjectJsImplementation
);
const height = this.getHeight();
return object.content.verticalTextAlignment === 'bottom'
? height
: object.content.verticalTextAlignment === 'center'
? height / 2
: 0;
}
}
objectsRenderingService.registerInstanceRenderer(

View File

@@ -35,13 +35,6 @@ namespace gdjs {
.getRenderer()
.addRendererObject(this._pixiObject, runtimeObject.getZOrder());
// Set the anchor in the center, so that the object rotates around
// its center.
// @ts-ignore
this._pixiObject.anchor.x = 0.5;
// @ts-ignore
this._pixiObject.anchor.y = 0.5;
this.updateAlignment();
this.updateTextContent();
this.updateAngle();
@@ -130,7 +123,7 @@ namespace gdjs {
}
updateWrappingWidth(): void {
if (this._object._wordWrap) {
if (this._object._wrapping) {
this._pixiObject.maxWidth =
this._object._wrappingWidth / this._object._scaleX;
this._pixiObject.dirty = true;
@@ -148,13 +141,43 @@ namespace gdjs {
updateAlignment(): void {
// @ts-ignore - assume align is always a valid value.
this._pixiObject.align = this._object._align;
this._pixiObject.align = this._object._textAlign;
this.updatePosition();
}
updatePosition(): void {
this._pixiObject.position.x = this._object.x + this.getWidth() / 2;
this._pixiObject.position.y = this._object.y + this.getHeight() / 2;
if (this._object.isWrapping()) {
const alignmentX =
this._object._textAlign === 'right'
? 1
: this._object._textAlign === 'center'
? 0.5
: 0;
const width = this._object.getWrappingWidth();
// A vector from the custom size center to the renderer center.
const centerToCenterX =
(width - this._pixiObject.width) * (alignmentX - 0.5);
this._pixiObject.position.x = this._object.x + width / 2;
this._pixiObject.anchor.x =
0.5 - centerToCenterX / this._pixiObject.width;
} else {
this._pixiObject.position.x =
this._object.x + this._pixiObject.width / 2;
this._pixiObject.anchor.x = 0.5;
}
const alignmentY =
this._object._verticalTextAlignment === 'bottom'
? 1
: this._object._verticalTextAlignment === 'center'
? 0.5
: 0;
this._pixiObject.position.y =
this._object.y + this._pixiObject.height * (0.5 - alignmentY);
this._pixiObject.anchor.y = 0.5;
}
updateAngle(): void {
@@ -173,5 +196,6 @@ namespace gdjs {
return this._pixiObject.textHeight * this.getScale();
}
}
export const BitmapTextRuntimeObjectRenderer = BitmapTextRuntimeObjectPixiRenderer;
export const BitmapTextRuntimeObjectRenderer =
BitmapTextRuntimeObjectPixiRenderer;
}

View File

@@ -15,12 +15,11 @@ namespace gdjs {
textureAtlasResourceName: string;
/** The scale of the text. */
scale: float;
/** Activate word wrap if set to true. */
wordWrap: boolean;
/** Wrapping with from custom size properties. */
wrappingWidth: float;
/** Alignment of the text. */
align: 'left' | 'center' | 'right';
verticalTextAlignment: 'top' | 'center' | 'bottom';
};
};
export type BitmapTextObjectData = ObjectData & BitmapTextObjectDataType;
@@ -35,6 +34,7 @@ namespace gdjs {
wwrap: boolean;
wwidth: float;
align: string;
vta: string;
};
export type BitmapTextObjectNetworkSyncData = ObjectNetworkSyncData &
@@ -52,7 +52,8 @@ namespace gdjs {
*/
export class BitmapTextRuntimeObject
extends gdjs.RuntimeObject
implements gdjs.TextContainer, gdjs.OpacityHandler, gdjs.Scalable {
implements gdjs.TextContainer, gdjs.OpacityHandler, gdjs.Scalable
{
_opacity: float;
_text: string;
/** color in format [r, g, b], where each component is in the range [0, 255] */
@@ -61,9 +62,10 @@ namespace gdjs {
_textureAtlasResourceName: string;
_scaleX: number;
_scaleY: number;
_wordWrap: boolean;
_wrapping: boolean = false;
_wrappingWidth: float;
_align: string;
_textAlign: string;
_verticalTextAlignment: string;
_renderer: gdjs.BitmapTextRuntimeObjectPixiRenderer;
@@ -86,9 +88,10 @@ namespace gdjs {
objectData.content.textureAtlasResourceName; // texture file used with fnt/xml (bitmap font file)
this._scaleX = objectData.content.scale;
this._scaleY = objectData.content.scale;
this._wordWrap = objectData.content.wordWrap;
this._wrappingWidth = 0;
this._align = objectData.content.align;
this._textAlign = objectData.content.align;
this._verticalTextAlignment =
objectData.content.verticalTextAlignment || 'top';
this._renderer = new gdjs.BitmapTextRuntimeObjectRenderer(
this,
@@ -99,12 +102,12 @@ namespace gdjs {
this.onCreated();
}
getRendererObject() {
override getRendererObject() {
return this._renderer.getRendererObject();
}
// @ts-ignore
updateFromObjectData(
override updateFromObjectData(
oldObjectData: BitmapTextObjectDataType,
newObjectData: BitmapTextObjectDataType
): boolean {
@@ -137,17 +140,22 @@ namespace gdjs {
if (oldObjectData.content.scale !== newObjectData.content.scale) {
this.setScale(newObjectData.content.scale);
}
if (oldObjectData.content.wordWrap !== newObjectData.content.wordWrap) {
this.setWordWrap(newObjectData.content.wordWrap);
}
if (oldObjectData.content.align !== newObjectData.content.align) {
this.setAlignment(newObjectData.content.align);
this.setTextAlignment(newObjectData.content.align);
}
if (
oldObjectData.content.verticalTextAlignment !==
newObjectData.content.verticalTextAlignment
) {
this.setVerticalTextAlignment(
newObjectData.content.verticalTextAlignment
);
}
return true;
}
getNetworkSyncData(): BitmapTextObjectNetworkSyncData {
override getNetworkSyncData(): BitmapTextObjectNetworkSyncData {
return {
...super.getNetworkSyncData(),
text: this._text,
@@ -156,13 +164,14 @@ namespace gdjs {
bfrn: this._bitmapFontResourceName,
tarn: this._textureAtlasResourceName,
scale: this.getScale(),
wwrap: this._wordWrap,
wwrap: this._wrapping,
wwidth: this._wrappingWidth,
align: this._align,
align: this._textAlign,
vta: this._verticalTextAlignment,
};
}
updateFromNetworkSyncData(
override updateFromNetworkSyncData(
networkSyncData: BitmapTextObjectNetworkSyncData
): void {
super.updateFromNetworkSyncData(networkSyncData);
@@ -185,30 +194,36 @@ namespace gdjs {
if (this._scaleX !== undefined) {
this.setScale(networkSyncData.scale);
}
if (this._wordWrap !== undefined) {
this.setWordWrap(networkSyncData.wwrap);
if (this._wrapping !== undefined) {
this.setWrapping(networkSyncData.wwrap);
}
if (this._wrappingWidth !== undefined) {
this.setWrappingWidth(networkSyncData.wwidth);
}
if (this._align !== undefined) {
this.setAlignment(networkSyncData.align);
if (this._textAlign !== undefined) {
this.setTextAlignment(networkSyncData.align);
}
if (this._verticalTextAlignment !== undefined) {
this.setVerticalTextAlignment(networkSyncData.vta);
}
}
/**
* Initialize the extra parameters that could be set for an instance.
*/
extraInitializationFromInitialInstance(initialInstanceData: InstanceData) {
override extraInitializationFromInitialInstance(
initialInstanceData: InstanceData
) {
if (initialInstanceData.customSize) {
this.setWrappingWidth(initialInstanceData.width);
this.setWrapping(true);
}
if (initialInstanceData.opacity !== undefined) {
this.setOpacity(initialInstanceData.opacity);
}
}
onDestroyed(): void {
override onDestroyed(): void {
super.onDestroyed();
this._renderer.onDestroy();
}
@@ -313,38 +328,43 @@ namespace gdjs {
return this._textureAtlasResourceName;
}
setAlignment(align: string): void {
this._align = align;
setTextAlignment(align: string): void {
this._textAlign = align;
this._renderer.updateAlignment();
}
getAlignment(): string {
return this._align;
getTextAlignment(): string {
return this._textAlign;
}
/**
* Set object position on X axis.
* @param x The new position X of the object.
* Set the text alignment on Y axis for multiline text objects.
* @param alignment The text alignment.
*/
setX(x: float): void {
setVerticalTextAlignment(alignment: string): void {
this._verticalTextAlignment = alignment;
this._renderer.updatePosition();
}
/**
* Get the text alignment on Y axis of text object.
* @return The text alignment.
*/
getVerticalTextAlignment(): string {
return this._verticalTextAlignment;
}
override setX(x: float): void {
super.setX(x);
this._renderer.updatePosition();
}
/**
* Set object position on Y axis.
* @param y The new position Y of the object.
*/
setY(y: float): void {
override setY(y: float): void {
super.setY(y);
this._renderer.updatePosition();
}
/**
* Set the angle of the object.
* @param angle The new angle of the object.
*/
setAngle(angle: float): void {
override setAngle(angle: float): void {
super.setAngle(angle);
this._renderer.updateAngle();
}
@@ -388,29 +408,34 @@ namespace gdjs {
return this._wrappingWidth;
}
setWordWrap(wordWrap: boolean): void {
this._wordWrap = wordWrap;
setWrapping(wordWrap: boolean): void {
this._wrapping = wordWrap;
this._renderer.updateWrappingWidth();
this.invalidateHitboxes();
}
getWordWrap(): boolean {
return this._wordWrap;
isWrapping(): boolean {
return this._wrapping;
}
/**
* Get the width of the object.
*/
getWidth(): float {
override getWidth(): float {
return this._renderer.getWidth();
}
/**
* Get the height of the object.
*/
getHeight(): float {
override getHeight(): float {
return this._renderer.getHeight();
}
override getDrawableY(): float {
return (
this.getY() -
(this._verticalTextAlignment === 'center'
? this.getHeight() / 2
: this._verticalTextAlignment === 'bottom'
? this.getHeight()
: 0)
);
}
}
gdjs.registerObject(
'BitmapText::BitmapTextObject',

View File

@@ -249,13 +249,16 @@ namespace gdjs {
(clipTextEnd === 0 || clipTextEnd !== dialogueText.length)
) {
pauseScrolling = true;
setTimeout(function () {
pauseScrolling = false;
commandCalls.splice(index, 1);
if (gdjs.dialogueTree.getVariable('debug')) {
logger.info('CMD:', call);
}
}, parseInt(call.params[1], 10));
setTimeout(
function () {
pauseScrolling = false;
commandCalls.splice(index, 1);
if (gdjs.dialogueTree.getVariable('debug')) {
logger.info('CMD:', call);
}
},
parseInt(call.params[1], 10)
);
}
if (call.cmd === command) {
commandParameters = call.params;

View File

@@ -157,9 +157,8 @@ namespace gdjs {
if (!instanceContainer.touchDraggableManagers[touchId]) {
//Create the shared manager if necessary.
// @ts-ignore
instanceContainer.touchDraggableManagers[
touchId
] = new DraggableManager(instanceContainer, touchId);
instanceContainer.touchDraggableManagers[touchId] =
new DraggableManager(instanceContainer, touchId);
}
// @ts-ignore
return instanceContainer.touchDraggableManagers[touchId];

View File

@@ -22,7 +22,8 @@ namespace gdjs {
parameterName: string,
value: number
) {
const adjustmentFilter = (filter as unknown) as PIXI.filters.AdjustmentFilter;
const adjustmentFilter =
filter as unknown as PIXI.filters.AdjustmentFilter;
if (parameterName === 'gamma') {
adjustmentFilter.gamma = value;
} else if (parameterName === 'saturation') {
@@ -42,7 +43,8 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const adjustmentFilter = (filter as unknown) as PIXI.filters.AdjustmentFilter;
const adjustmentFilter =
filter as unknown as PIXI.filters.AdjustmentFilter;
if (parameterName === 'gamma') {
return adjustmentFilter.gamma;
}
@@ -88,7 +90,8 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): AdjustmentFilterNetworkSyncData {
const adjustmentFilter = (filter as unknown) as PIXI.filters.AdjustmentFilter;
const adjustmentFilter =
filter as unknown as PIXI.filters.AdjustmentFilter;
return {
ga: adjustmentFilter.gamma,
sa: adjustmentFilter.saturation,
@@ -104,7 +107,8 @@ namespace gdjs {
filter: PIXI.Filter,
data: AdjustmentFilterNetworkSyncData
): void {
const adjustmentFilter = (filter as unknown) as PIXI.filters.AdjustmentFilter;
const adjustmentFilter =
filter as unknown as PIXI.filters.AdjustmentFilter;
adjustmentFilter.gamma = data.ga;
adjustmentFilter.saturation = data.sa;
adjustmentFilter.contrast = data.co;

View File

@@ -20,7 +20,8 @@ namespace gdjs {
parameterName: string,
value: number
) {
const advancedBloomFilter = (filter as unknown) as PIXI.filters.AdvancedBloomFilter;
const advancedBloomFilter =
filter as unknown as PIXI.filters.AdvancedBloomFilter;
if (parameterName === 'threshold') {
advancedBloomFilter.threshold = value;
} else if (parameterName === 'bloomScale') {
@@ -36,7 +37,8 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const advancedBloomFilter = (filter as unknown) as PIXI.filters.AdvancedBloomFilter;
const advancedBloomFilter =
filter as unknown as PIXI.filters.AdvancedBloomFilter;
if (parameterName === 'threshold') {
return advancedBloomFilter.threshold;
}
@@ -78,7 +80,8 @@ namespace gdjs {
getNetworkSyncData(
filter: PIXI.Filter
): AdvancedBloomFilterNetworkSyncData {
const advancedBloomFilter = (filter as unknown) as PIXI.filters.AdvancedBloomFilter;
const advancedBloomFilter =
filter as unknown as PIXI.filters.AdvancedBloomFilter;
return {
th: advancedBloomFilter.threshold,
bs: advancedBloomFilter.bloomScale,
@@ -92,7 +95,8 @@ namespace gdjs {
filter: PIXI.Filter,
syncData: AdvancedBloomFilterNetworkSyncData
) {
const advancedBloomFilter = (filter as unknown) as PIXI.filters.AdvancedBloomFilter;
const advancedBloomFilter =
filter as unknown as PIXI.filters.AdvancedBloomFilter;
advancedBloomFilter.threshold = syncData.th;
advancedBloomFilter.bloomScale = syncData.bs;
advancedBloomFilter.brightness = syncData.bn;

View File

@@ -15,13 +15,13 @@ namespace gdjs {
parameterName: string,
value: number
) {
const asciiFilter = (filter as unknown) as PIXI.filters.AsciiFilter;
const asciiFilter = filter as unknown as PIXI.filters.AsciiFilter;
if (parameterName === 'size') {
asciiFilter.size = value;
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const asciiFilter = (filter as unknown) as PIXI.filters.AsciiFilter;
const asciiFilter = filter as unknown as PIXI.filters.AsciiFilter;
if (parameterName === 'size') {
return asciiFilter.size;
}
@@ -46,14 +46,14 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): AsciiFilterNetworkSyncData {
const asciiFilter = (filter as unknown) as PIXI.filters.AsciiFilter;
const asciiFilter = filter as unknown as PIXI.filters.AsciiFilter;
return { size: asciiFilter.size };
}
updateFromNetworkSyncData(
filter: PIXI.Filter,
data: AsciiFilterNetworkSyncData
) {
const asciiFilter = (filter as unknown) as PIXI.filters.AsciiFilter;
const asciiFilter = filter as unknown as PIXI.filters.AsciiFilter;
asciiFilter.size = data.size;
}
})()

View File

@@ -25,7 +25,7 @@ namespace gdjs {
parameterName: string,
value: number
) {
const bevelFilter = (filter as unknown) as PIXI.filters.BevelFilter &
const bevelFilter = filter as unknown as PIXI.filters.BevelFilter &
BevelFilterExtra;
if (parameterName === 'rotation') {
bevelFilter.rotation = value;
@@ -40,7 +40,7 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const bevelFilter = (filter as unknown) as PIXI.filters.BevelFilter &
const bevelFilter = filter as unknown as PIXI.filters.BevelFilter &
BevelFilterExtra;
if (parameterName === 'rotation') {
return bevelFilter.rotation;
@@ -64,7 +64,7 @@ namespace gdjs {
parameterName: string,
value: string
) {
const bevelFilter = (filter as unknown) as PIXI.filters.BevelFilter &
const bevelFilter = filter as unknown as PIXI.filters.BevelFilter &
BevelFilterExtra;
if (parameterName === 'lightColor') {
bevelFilter.lightColor = gdjs.rgbOrHexStringToNumber(value);
@@ -78,7 +78,7 @@ namespace gdjs {
parameterName: string,
value: number
): void {
const bevelFilter = (filter as unknown) as PIXI.filters.BevelFilter &
const bevelFilter = filter as unknown as PIXI.filters.BevelFilter &
BevelFilterExtra;
if (parameterName === 'lightColor') {
bevelFilter.lightColor = value;
@@ -88,7 +88,7 @@ namespace gdjs {
}
}
getColorParameter(filter: PIXI.Filter, parameterName: string): number {
const bevelFilter = (filter as unknown) as PIXI.filters.BevelFilter;
const bevelFilter = filter as unknown as PIXI.filters.BevelFilter;
if (parameterName === 'lightColor') {
return bevelFilter.lightColor;
}
@@ -103,7 +103,7 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): BevelFilterNetworkSyncData {
const bevelFilter = (filter as unknown) as PIXI.filters.BevelFilter &
const bevelFilter = filter as unknown as PIXI.filters.BevelFilter &
BevelFilterExtra;
return {
r: bevelFilter.rotation,
@@ -119,7 +119,7 @@ namespace gdjs {
filter: PIXI.Filter,
data: BevelFilterNetworkSyncData
) {
const bevelFilter = (filter as unknown) as PIXI.filters.BevelFilter &
const bevelFilter = filter as unknown as PIXI.filters.BevelFilter &
BevelFilterExtra;
bevelFilter.rotation = data.r;
bevelFilter.thickness = data.t;

View File

@@ -16,14 +16,14 @@ namespace gdjs {
parameterName: string,
value: number
) {
const colorMatrix = (filter as unknown) as PIXI.ColorMatrixFilter;
const colorMatrix = filter as unknown as PIXI.ColorMatrixFilter;
if (parameterName !== 'opacity') {
return;
}
colorMatrix.alpha = gdjs.PixiFiltersTools.clampValue(value, 0, 1);
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const colorMatrix = (filter as unknown) as PIXI.ColorMatrixFilter;
const colorMatrix = filter as unknown as PIXI.ColorMatrixFilter;
if (parameterName === 'opacity') {
return colorMatrix.alpha;
}
@@ -50,14 +50,14 @@ namespace gdjs {
getNetworkSyncData(
filter: PIXI.Filter
): BlackAndWhiteFilterNetworkSyncData {
const colorMatrix = (filter as unknown) as PIXI.ColorMatrixFilter;
const colorMatrix = filter as unknown as PIXI.ColorMatrixFilter;
return { a: colorMatrix.alpha };
}
updateFromNetworkSyncData(
filter: PIXI.Filter,
data: BlackAndWhiteFilterNetworkSyncData
) {
const colorMatrix = (filter as unknown) as PIXI.ColorMatrixFilter;
const colorMatrix = filter as unknown as PIXI.ColorMatrixFilter;
colorMatrix.alpha = data.a;
}
})()

View File

@@ -16,7 +16,7 @@ namespace gdjs {
parameterName: string,
value: number
) {
const blendingModeFilter = (filter as unknown) as PIXI.AlphaFilter;
const blendingModeFilter = filter as unknown as PIXI.AlphaFilter;
if (parameterName === 'alpha') {
blendingModeFilter.alpha = value;
} else if (parameterName === 'blendmode') {
@@ -24,7 +24,7 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const blendingModeFilter = (filter as unknown) as PIXI.AlphaFilter;
const blendingModeFilter = filter as unknown as PIXI.AlphaFilter;
if (parameterName === 'alpha') {
return blendingModeFilter.alpha;
}
@@ -54,7 +54,7 @@ namespace gdjs {
getNetworkSyncData(
filter: PIXI.Filter
): BlendingModeFilterNetworkSyncData {
const blendingModeFilter = (filter as unknown) as PIXI.AlphaFilter;
const blendingModeFilter = filter as unknown as PIXI.AlphaFilter;
return {
a: blendingModeFilter.alpha,
bm: blendingModeFilter.blendMode,
@@ -64,7 +64,7 @@ namespace gdjs {
filter: PIXI.Filter,
data: BlendingModeFilterNetworkSyncData
) {
const blendingModeFilter = (filter as unknown) as PIXI.AlphaFilter;
const blendingModeFilter = filter as unknown as PIXI.AlphaFilter;
blendingModeFilter.alpha = data.a;
blendingModeFilter.blendMode = data.bm;
}

View File

@@ -20,7 +20,7 @@ namespace gdjs {
parameterName: string,
value: number
) {
const brightnessFilter = (filter as unknown) as PIXI.ColorMatrixFilter &
const brightnessFilter = filter as unknown as PIXI.ColorMatrixFilter &
BrightnessFilterExtra;
if (parameterName !== 'brightness') {
return;
@@ -30,7 +30,7 @@ namespace gdjs {
brightnessFilter.brightness(brightness, false);
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const brightnessFilter = (filter as unknown) as PIXI.ColorMatrixFilter &
const brightnessFilter = filter as unknown as PIXI.ColorMatrixFilter &
BrightnessFilterExtra;
if (parameterName === 'brightness') {
return brightnessFilter.__brightness;
@@ -56,7 +56,7 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): BrightnessFilterNetworkSyncData {
const brightnessFilter = (filter as unknown) as PIXI.ColorMatrixFilter &
const brightnessFilter = filter as unknown as PIXI.ColorMatrixFilter &
BrightnessFilterExtra;
return { b: brightnessFilter.__brightness };
}
@@ -64,7 +64,7 @@ namespace gdjs {
filter: PIXI.Filter,
data: BrightnessFilterNetworkSyncData
) {
const brightnessFilter = (filter as unknown) as PIXI.ColorMatrixFilter &
const brightnessFilter = filter as unknown as PIXI.ColorMatrixFilter &
BrightnessFilterExtra;
brightnessFilter.__brightness = data.b;
brightnessFilter.brightness(data.b, false);

View File

@@ -18,7 +18,8 @@ namespace gdjs {
parameterName: string,
value: number
) {
const bulgePinchFilter = (filter as unknown) as PIXI.filters.BulgePinchFilter;
const bulgePinchFilter =
filter as unknown as PIXI.filters.BulgePinchFilter;
if (parameterName === 'centerX') {
bulgePinchFilter.center[0] = value;
} else if (parameterName === 'centerY') {
@@ -34,7 +35,8 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const bulgePinchFilter = (filter as unknown) as PIXI.filters.BulgePinchFilter;
const bulgePinchFilter =
filter as unknown as PIXI.filters.BulgePinchFilter;
if (parameterName === 'centerX') {
return bulgePinchFilter.center[0];
}
@@ -68,7 +70,8 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): BulgePinchFilterNetworkSyncData {
const bulgePinchFilter = (filter as unknown) as PIXI.filters.BulgePinchFilter;
const bulgePinchFilter =
filter as unknown as PIXI.filters.BulgePinchFilter;
return {
cx: bulgePinchFilter.center[0],
cy: bulgePinchFilter.center[1],
@@ -80,7 +83,8 @@ namespace gdjs {
filter: PIXI.Filter,
data: BulgePinchFilterNetworkSyncData
) {
const bulgePinchFilter = (filter as unknown) as PIXI.filters.BulgePinchFilter;
const bulgePinchFilter =
filter as unknown as PIXI.filters.BulgePinchFilter;
bulgePinchFilter.center[0] = data.cx;
bulgePinchFilter.center[1] = data.cy;
bulgePinchFilter.radius = data.r;

View File

@@ -29,7 +29,7 @@ namespace gdjs {
parameterName: string,
value: number
) {
const colorMapFilter = (filter as unknown) as PIXI.filters.ColorMapFilter;
const colorMapFilter = filter as unknown as PIXI.filters.ColorMapFilter;
if (parameterName === 'mix') {
colorMapFilter.mix = gdjs.PixiFiltersTools.clampValue(
value / 100,
@@ -39,7 +39,7 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const colorMapFilter = (filter as unknown) as PIXI.filters.ColorMapFilter;
const colorMapFilter = filter as unknown as PIXI.filters.ColorMapFilter;
if (parameterName === 'mix') {
return colorMapFilter.mix;
}
@@ -63,20 +63,20 @@ namespace gdjs {
parameterName: string,
value: boolean
) {
const colorMapFilter = (filter as unknown) as PIXI.filters.ColorMapFilter;
const colorMapFilter = filter as unknown as PIXI.filters.ColorMapFilter;
if (parameterName === 'nearest') {
colorMapFilter.nearest = value;
}
}
getNetworkSyncData(filter: PIXI.Filter): ColorMapFilterNetworkSyncData {
const colorMapFilter = (filter as unknown) as PIXI.filters.ColorMapFilter;
const colorMapFilter = filter as unknown as PIXI.filters.ColorMapFilter;
return { mix: colorMapFilter.mix, near: colorMapFilter.nearest };
}
updateFromNetworkSyncData(
filter: PIXI.Filter,
data: ColorMapFilterNetworkSyncData
) {
const colorMapFilter = (filter as unknown) as PIXI.filters.ColorMapFilter;
const colorMapFilter = filter as unknown as PIXI.filters.ColorMapFilter;
colorMapFilter.mix = data.mix;
colorMapFilter.nearest = data.near;
}

View File

@@ -23,15 +23,17 @@ namespace gdjs {
parameterName: string,
value: number
) {
const colorReplaceFilter = (filter as unknown) as PIXI.filters.ColorReplaceFilter &
ColorReplaceFilterExtra;
const colorReplaceFilter =
filter as unknown as PIXI.filters.ColorReplaceFilter &
ColorReplaceFilterExtra;
if (parameterName === 'epsilon') {
colorReplaceFilter.epsilon = value;
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const colorReplaceFilter = (filter as unknown) as PIXI.filters.ColorReplaceFilter &
ColorReplaceFilterExtra;
const colorReplaceFilter =
filter as unknown as PIXI.filters.ColorReplaceFilter &
ColorReplaceFilterExtra;
if (parameterName === 'epsilon') {
return colorReplaceFilter.epsilon;
}
@@ -42,8 +44,9 @@ namespace gdjs {
parameterName: string,
value: string
) {
const colorReplaceFilter = (filter as unknown) as PIXI.filters.ColorReplaceFilter &
ColorReplaceFilterExtra;
const colorReplaceFilter =
filter as unknown as PIXI.filters.ColorReplaceFilter &
ColorReplaceFilterExtra;
if (parameterName === 'originalColor') {
colorReplaceFilter.originalColor = gdjs.rgbOrHexStringToNumber(value);
} else if (parameterName === 'newColor') {
@@ -55,8 +58,9 @@ namespace gdjs {
parameterName: string,
value: number
): void {
const colorReplaceFilter = (filter as unknown) as PIXI.filters.ColorReplaceFilter &
ColorReplaceFilterExtra;
const colorReplaceFilter =
filter as unknown as PIXI.filters.ColorReplaceFilter &
ColorReplaceFilterExtra;
if (parameterName === 'originalColor') {
colorReplaceFilter.originalColor = value;
} else if (parameterName === 'newColor') {
@@ -64,8 +68,9 @@ namespace gdjs {
}
}
getColorParameter(filter: PIXI.Filter, parameterName: string): number {
const colorReplaceFilter = (filter as unknown) as PIXI.filters.ColorReplaceFilter &
ColorReplaceFilterExtra;
const colorReplaceFilter =
filter as unknown as PIXI.filters.ColorReplaceFilter &
ColorReplaceFilterExtra;
if (parameterName === 'originalColor') {
return colorReplaceFilter.originalColor;
} else if (parameterName === 'newColor') {
@@ -81,8 +86,9 @@ namespace gdjs {
getNetworkSyncData(
filter: PIXI.Filter
): ColorReplaceFilterNetworkSyncData {
const colorReplaceFilter = (filter as unknown) as PIXI.filters.ColorReplaceFilter &
ColorReplaceFilterExtra;
const colorReplaceFilter =
filter as unknown as PIXI.filters.ColorReplaceFilter &
ColorReplaceFilterExtra;
return {
e: colorReplaceFilter.epsilon,
oc: colorReplaceFilter.originalColor,
@@ -93,8 +99,9 @@ namespace gdjs {
filter: PIXI.Filter,
data: ColorReplaceFilterNetworkSyncData
) {
const colorReplaceFilter = (filter as unknown) as PIXI.filters.ColorReplaceFilter &
ColorReplaceFilterExtra;
const colorReplaceFilter =
filter as unknown as PIXI.filters.ColorReplaceFilter &
ColorReplaceFilterExtra;
colorReplaceFilter.epsilon = data.e;
colorReplaceFilter.originalColor = data.oc;
colorReplaceFilter.newColor = data.nc;

View File

@@ -23,13 +23,13 @@ namespace gdjs {
new (class extends gdjs.PixiFiltersTools.PixiFilterCreator {
makePIXIFilter(layer, effectData) {
const filter = new PIXI.filters.CRTFilter();
const crtFilter = (filter as unknown) as PIXI.filters.CRTFilter &
const crtFilter = filter as unknown as PIXI.filters.CRTFilter &
CRTFilterExtra;
crtFilter._animationTimer = 0;
return crtFilter;
}
updatePreRender(filter: PIXI.Filter, target: EffectsTarget) {
const crtFilter = (filter as unknown) as PIXI.filters.CRTFilter &
const crtFilter = filter as unknown as PIXI.filters.CRTFilter &
CRTFilterExtra;
if (crtFilter.animationSpeed !== 0) {
// Multiply by 10 so that the default value is a sensible speed
@@ -49,7 +49,7 @@ namespace gdjs {
parameterName: string,
value: number
) {
const crtFilter = (filter as unknown) as PIXI.filters.CRTFilter &
const crtFilter = filter as unknown as PIXI.filters.CRTFilter &
CRTFilterExtra;
if (parameterName === 'lineWidth') {
crtFilter.lineWidth = value;
@@ -76,7 +76,7 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const crtFilter = (filter as unknown) as PIXI.filters.CRTFilter &
const crtFilter = filter as unknown as PIXI.filters.CRTFilter &
CRTFilterExtra;
if (parameterName === 'lineWidth') {
return crtFilter.lineWidth;
@@ -131,13 +131,13 @@ namespace gdjs {
parameterName: string,
value: boolean
) {
const crtFilter = (filter as unknown) as PIXI.filters.CRTFilter;
const crtFilter = filter as unknown as PIXI.filters.CRTFilter;
if (parameterName === 'verticalLine') {
crtFilter.verticalLine = value;
}
}
getNetworkSyncData(filter: PIXI.Filter): CRTFilterNetworkSyncData {
const crtFilter = (filter as unknown) as PIXI.filters.CRTFilter &
const crtFilter = filter as unknown as PIXI.filters.CRTFilter &
CRTFilterExtra;
return {
lw: crtFilter.lineWidth,
@@ -158,7 +158,7 @@ namespace gdjs {
filter: PIXI.Filter,
data: CRTFilterNetworkSyncData
) {
const crtFilter = (filter as unknown) as PIXI.filters.CRTFilter &
const crtFilter = filter as unknown as PIXI.filters.CRTFilter &
CRTFilterExtra;
crtFilter.lineWidth = data.lw;
crtFilter.lineContrast = data.lc;

View File

@@ -25,7 +25,7 @@ namespace gdjs {
parameterName: string,
value: number
) {
const displacementFilter = (filter as unknown) as PIXI.DisplacementFilter;
const displacementFilter = filter as unknown as PIXI.DisplacementFilter;
if (parameterName === 'scaleX') {
displacementFilter.scale.x = value;
}
@@ -34,7 +34,7 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const displacementFilter = (filter as unknown) as PIXI.DisplacementFilter;
const displacementFilter = filter as unknown as PIXI.DisplacementFilter;
if (parameterName === 'scaleX') {
return displacementFilter.scale.x;
}
@@ -64,7 +64,7 @@ namespace gdjs {
getNetworkSyncData(
filter: PIXI.Filter
): DisplacementFilterNetworkSyncData {
const displacementFilter = (filter as unknown) as PIXI.DisplacementFilter;
const displacementFilter = filter as unknown as PIXI.DisplacementFilter;
return {
sx: displacementFilter.scale.x,
sy: displacementFilter.scale.y,
@@ -74,7 +74,7 @@ namespace gdjs {
filter: PIXI.Filter,
data: DisplacementFilterNetworkSyncData
) {
const displacementFilter = (filter as unknown) as PIXI.DisplacementFilter;
const displacementFilter = filter as unknown as PIXI.DisplacementFilter;
displacementFilter.scale.x = data.sx;
displacementFilter.scale.y = data.sy;
}

View File

@@ -16,7 +16,7 @@ namespace gdjs {
parameterName: string,
value: number
) {
const dotFilter = (filter as unknown) as PIXI.filters.DotFilter;
const dotFilter = filter as unknown as PIXI.filters.DotFilter;
if (parameterName === 'scale') {
dotFilter.scale = value;
} else if (parameterName === 'angle') {
@@ -24,7 +24,7 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const dotFilter = (filter as unknown) as PIXI.filters.DotFilter;
const dotFilter = filter as unknown as PIXI.filters.DotFilter;
if (parameterName === 'scale') {
return dotFilter.scale;
}
@@ -52,14 +52,14 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): DotFilterNetworkSyncData {
const dotFilter = (filter as unknown) as PIXI.filters.DotFilter;
const dotFilter = filter as unknown as PIXI.filters.DotFilter;
return { s: dotFilter.scale, a: dotFilter.angle };
}
updateFromNetworkSyncData(
filter: PIXI.Filter,
data: DotFilterNetworkSyncData
) {
const dotFilter = (filter as unknown) as PIXI.filters.DotFilter;
const dotFilter = filter as unknown as PIXI.filters.DotFilter;
dotFilter.scale = data.s;
dotFilter.angle = data.a;
}

View File

@@ -22,7 +22,8 @@ namespace gdjs {
parameterName: string,
value: number
) {
const dropShadowFilter = (filter as unknown) as PIXI.filters.DropShadowFilter;
const dropShadowFilter =
filter as unknown as PIXI.filters.DropShadowFilter;
if (parameterName === 'blur') {
dropShadowFilter.blur = value;
} else if (parameterName === 'quality') {
@@ -38,7 +39,8 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const dropShadowFilter = (filter as unknown) as PIXI.filters.DropShadowFilter;
const dropShadowFilter =
filter as unknown as PIXI.filters.DropShadowFilter;
if (parameterName === 'blur') {
return dropShadowFilter.blur;
}
@@ -64,7 +66,8 @@ namespace gdjs {
parameterName: string,
value: string
) {
const dropShadowFilter = (filter as unknown) as PIXI.filters.DropShadowFilter;
const dropShadowFilter =
filter as unknown as PIXI.filters.DropShadowFilter;
if (parameterName === 'color') {
dropShadowFilter.color = gdjs.rgbOrHexStringToNumber(value);
}
@@ -74,13 +77,15 @@ namespace gdjs {
parameterName: string,
value: number
): void {
const dropShadowFilter = (filter as unknown) as PIXI.filters.DropShadowFilter;
const dropShadowFilter =
filter as unknown as PIXI.filters.DropShadowFilter;
if (parameterName === 'color') {
dropShadowFilter.color = value;
}
}
getColorParameter(filter: PIXI.Filter, parameterName: string): number {
const dropShadowFilter = (filter as unknown) as PIXI.filters.DropShadowFilter;
const dropShadowFilter =
filter as unknown as PIXI.filters.DropShadowFilter;
if (parameterName === 'color') {
return dropShadowFilter.color;
}
@@ -91,13 +96,15 @@ namespace gdjs {
parameterName: string,
value: boolean
) {
const dropShadowFilter = (filter as unknown) as PIXI.filters.DropShadowFilter;
const dropShadowFilter =
filter as unknown as PIXI.filters.DropShadowFilter;
if (parameterName === 'shadowOnly') {
dropShadowFilter.shadowOnly = value;
}
}
getNetworkSyncData(filter: PIXI.Filter): DropShadowFilterNetworkSyncData {
const dropShadowFilter = (filter as unknown) as PIXI.filters.DropShadowFilter;
const dropShadowFilter =
filter as unknown as PIXI.filters.DropShadowFilter;
return {
b: dropShadowFilter.blur,
q: dropShadowFilter.quality,
@@ -113,7 +120,8 @@ namespace gdjs {
filter: PIXI.Filter,
data: DropShadowFilterNetworkSyncData
) {
const dropShadowFilter = (filter as unknown) as PIXI.filters.DropShadowFilter;
const dropShadowFilter =
filter as unknown as PIXI.filters.DropShadowFilter;
dropShadowFilter.blur = data.b;
dropShadowFilter.quality = data.q;
dropShadowFilter.alpha = data.a;

View File

@@ -24,13 +24,13 @@ namespace gdjs {
new (class extends gdjs.PixiFiltersTools.PixiFilterCreator {
makePIXIFilter(layer, effectData) {
const filter = new PIXI.filters.GlitchFilter();
const glitchFilter = (filter as unknown) as PIXI.filters.GlitchFilter &
const glitchFilter = filter as unknown as PIXI.filters.GlitchFilter &
GlitchFilterExtra;
glitchFilter._animationTimer = 0;
return glitchFilter;
}
updatePreRender(filter: PIXI.Filter, target: EffectsTarget) {
const glitchFilter = (filter as unknown) as PIXI.filters.GlitchFilter &
const glitchFilter = filter as unknown as PIXI.filters.GlitchFilter &
GlitchFilterExtra;
if (glitchFilter.animationFrequency !== 0) {
glitchFilter._animationTimer += target.getElapsedTime() / 1000;
@@ -48,7 +48,7 @@ namespace gdjs {
parameterName: string,
value: number
) {
const glitchFilter = (filter as unknown) as PIXI.filters.GlitchFilter &
const glitchFilter = filter as unknown as PIXI.filters.GlitchFilter &
GlitchFilterExtra;
if (parameterName === 'slices') {
glitchFilter.slices = value;
@@ -79,7 +79,7 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const glitchFilter = (filter as unknown) as PIXI.filters.GlitchFilter &
const glitchFilter = filter as unknown as PIXI.filters.GlitchFilter &
GlitchFilterExtra;
if (parameterName === 'slices') {
return glitchFilter.slices;
@@ -140,14 +140,14 @@ namespace gdjs {
parameterName: string,
value: boolean
) {
const glitchFilter = (filter as unknown) as PIXI.filters.GlitchFilter &
const glitchFilter = filter as unknown as PIXI.filters.GlitchFilter &
GlitchFilterExtra;
if (parameterName === 'average') {
glitchFilter.average = value;
}
}
getNetworkSyncData(filter: PIXI.Filter): GlitchFilterNetworkSyncData {
const glitchFilter = (filter as unknown) as PIXI.filters.GlitchFilter &
const glitchFilter = filter as unknown as PIXI.filters.GlitchFilter &
GlitchFilterExtra;
return {
s: glitchFilter.slices,
@@ -170,7 +170,7 @@ namespace gdjs {
filter: PIXI.Filter,
data: GlitchFilterNetworkSyncData
) {
const glitchFilter = (filter as unknown) as PIXI.filters.GlitchFilter &
const glitchFilter = filter as unknown as PIXI.filters.GlitchFilter &
GlitchFilterExtra;
glitchFilter.slices = data.s;
glitchFilter.offset = data.o;

View File

@@ -21,7 +21,7 @@ namespace gdjs {
parameterName: string,
value: number
) {
const glowFilter = (filter as unknown) as PIXI.filters.GlowFilter &
const glowFilter = filter as unknown as PIXI.filters.GlowFilter &
GlowFilterExtra;
if (parameterName === 'innerStrength') {
glowFilter.innerStrength = value;
@@ -32,7 +32,7 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const glowFilter = (filter as unknown) as PIXI.filters.GlowFilter &
const glowFilter = filter as unknown as PIXI.filters.GlowFilter &
GlowFilterExtra;
if (parameterName === 'innerStrength') {
return glowFilter.innerStrength;
@@ -50,7 +50,7 @@ namespace gdjs {
parameterName: string,
value: string
) {
const glowFilter = (filter as unknown) as PIXI.filters.GlowFilter &
const glowFilter = filter as unknown as PIXI.filters.GlowFilter &
GlowFilterExtra;
if (parameterName === 'color') {
glowFilter.color = gdjs.rgbOrHexStringToNumber(value);
@@ -61,14 +61,14 @@ namespace gdjs {
parameterName: string,
value: number
): void {
const glowFilter = (filter as unknown) as PIXI.filters.GlowFilter &
const glowFilter = filter as unknown as PIXI.filters.GlowFilter &
GlowFilterExtra;
if (parameterName === 'color') {
glowFilter.color = value;
}
}
getColorParameter(filter: PIXI.Filter, parameterName: string): number {
const glowFilter = (filter as unknown) as PIXI.filters.GlowFilter &
const glowFilter = filter as unknown as PIXI.filters.GlowFilter &
GlowFilterExtra;
if (parameterName === 'color') {
return glowFilter.color;
@@ -81,7 +81,7 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): GlowFilterNetworkSyncData {
const glowFilter = (filter as unknown) as PIXI.filters.GlowFilter &
const glowFilter = filter as unknown as PIXI.filters.GlowFilter &
GlowFilterExtra;
return {
is: glowFilter.innerStrength,
@@ -94,7 +94,7 @@ namespace gdjs {
filter: PIXI.Filter,
data: GlowFilterNetworkSyncData
): void {
const glowFilter = (filter as unknown) as PIXI.filters.GlowFilter &
const glowFilter = filter as unknown as PIXI.filters.GlowFilter &
GlowFilterExtra;
glowFilter.innerStrength = data.is;
glowFilter.outerStrength = data.os;

View File

@@ -24,7 +24,7 @@ namespace gdjs {
return godrayFilter;
}
updatePreRender(filter: PIXI.Filter, target: EffectsTarget) {
const godrayFilter = (filter as unknown) as PIXI.filters.GodrayFilter &
const godrayFilter = filter as unknown as PIXI.filters.GodrayFilter &
GodrayFilterExtra;
if (godrayFilter.animationSpeed !== 0) {
godrayFilter.time +=
@@ -36,7 +36,7 @@ namespace gdjs {
parameterName: string,
value: number
) {
const godrayFilter = (filter as unknown) as PIXI.filters.GodrayFilter &
const godrayFilter = filter as unknown as PIXI.filters.GodrayFilter &
GodrayFilterExtra;
if (parameterName === 'lacunarity') {
godrayFilter.lacunarity = value;
@@ -57,7 +57,7 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const godrayFilter = (filter as unknown) as PIXI.filters.GodrayFilter &
const godrayFilter = filter as unknown as PIXI.filters.GodrayFilter &
GodrayFilterExtra;
if (parameterName === 'lacunarity') {
return godrayFilter.lacunarity;
@@ -103,14 +103,14 @@ namespace gdjs {
parameterName: string,
value: boolean
) {
const godrayFilter = (filter as unknown) as PIXI.filters.GodrayFilter &
const godrayFilter = filter as unknown as PIXI.filters.GodrayFilter &
GodrayFilterExtra;
if (parameterName === 'parallel') {
godrayFilter.parallel = value;
}
}
getNetworkSyncData(filter: PIXI.Filter): GodrayFilterNetworkSyncData {
const godrayFilter = (filter as unknown) as PIXI.filters.GodrayFilter &
const godrayFilter = filter as unknown as PIXI.filters.GodrayFilter &
GodrayFilterExtra;
return {
la: godrayFilter.lacunarity,
@@ -128,7 +128,7 @@ namespace gdjs {
filter: PIXI.Filter,
data: GodrayFilterNetworkSyncData
) {
const godrayFilter = (filter as unknown) as PIXI.filters.GodrayFilter &
const godrayFilter = filter as unknown as PIXI.filters.GodrayFilter &
GodrayFilterExtra;
godrayFilter.lacunarity = data.la;
godrayFilter.angle = data.a;

View File

@@ -18,7 +18,8 @@ namespace gdjs {
parameterName: string,
value: number
) {
const kawaseBlurFilter = (filter as unknown) as PIXI.filters.KawaseBlurFilter;
const kawaseBlurFilter =
filter as unknown as PIXI.filters.KawaseBlurFilter;
if (parameterName === 'pixelizeX') {
kawaseBlurFilter.pixelSize[0] = value;
} else if (parameterName === 'pixelizeY') {
@@ -30,7 +31,8 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const kawaseBlurFilter = (filter as unknown) as PIXI.filters.KawaseBlurFilter;
const kawaseBlurFilter =
filter as unknown as PIXI.filters.KawaseBlurFilter;
if (parameterName === 'pixelizeX') {
return kawaseBlurFilter.pixelSize[0];
}
@@ -64,7 +66,8 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): KawaseBlurFilterNetworkSyncData {
const kawaseBlurFilter = (filter as unknown) as PIXI.filters.KawaseBlurFilter;
const kawaseBlurFilter =
filter as unknown as PIXI.filters.KawaseBlurFilter;
return {
px: kawaseBlurFilter.pixelSize[0],
py: kawaseBlurFilter.pixelSize[1],
@@ -76,7 +79,8 @@ namespace gdjs {
filter: PIXI.Filter,
data: KawaseBlurFilterNetworkSyncData
) {
const kawaseBlurFilter = (filter as unknown) as PIXI.filters.KawaseBlurFilter;
const kawaseBlurFilter =
filter as unknown as PIXI.filters.KawaseBlurFilter;
kawaseBlurFilter.pixelSize[0] = data.px;
kawaseBlurFilter.pixelSize[1] = data.py;
kawaseBlurFilter.blur = data.b;

View File

@@ -15,13 +15,13 @@ namespace gdjs {
parameterName: string,
value: number
) {
const noiseFilter = (filter as unknown) as PIXI.NoiseFilter;
const noiseFilter = filter as unknown as PIXI.NoiseFilter;
if (parameterName === 'noise') {
noiseFilter.noise = gdjs.PixiFiltersTools.clampValue(value, 0, 1);
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const noiseFilter = (filter as unknown) as PIXI.NoiseFilter;
const noiseFilter = filter as unknown as PIXI.NoiseFilter;
if (parameterName === 'noise') {
return noiseFilter.noise;
}
@@ -46,14 +46,14 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): NoiseFilterNetworkSyncData {
const noiseFilter = (filter as unknown) as PIXI.NoiseFilter;
const noiseFilter = filter as unknown as PIXI.NoiseFilter;
return { n: noiseFilter.noise };
}
updateFromNetworkSyncData(
filter: PIXI.Filter,
data: NoiseFilterNetworkSyncData
) {
const noiseFilter = (filter as unknown) as PIXI.NoiseFilter;
const noiseFilter = filter as unknown as PIXI.NoiseFilter;
noiseFilter.noise = data.n;
}
})()

View File

@@ -20,13 +20,13 @@ namespace gdjs {
new (class extends gdjs.PixiFiltersTools.PixiFilterCreator {
makePIXIFilter(layer, effectData) {
const filter = new PIXI.filters.OldFilmFilter();
const oldFilmFilter = (filter as unknown) as PIXI.filters.OldFilmFilter &
const oldFilmFilter = filter as unknown as PIXI.filters.OldFilmFilter &
OldFilmFilterExtra;
oldFilmFilter._animationTimer = 0;
return oldFilmFilter;
}
updatePreRender(filter: PIXI.Filter, target: EffectsTarget) {
const oldFilmFilter = (filter as unknown) as PIXI.filters.OldFilmFilter &
const oldFilmFilter = filter as unknown as PIXI.filters.OldFilmFilter &
OldFilmFilterExtra;
if (oldFilmFilter.animationFrequency !== 0) {
oldFilmFilter._animationTimer += target.getElapsedTime() / 1000;
@@ -44,7 +44,7 @@ namespace gdjs {
parameterName: string,
value: number
) {
const oldFilmFilter = (filter as unknown) as PIXI.filters.OldFilmFilter &
const oldFilmFilter = filter as unknown as PIXI.filters.OldFilmFilter &
OldFilmFilterExtra;
if (parameterName === 'sepia') {
oldFilmFilter.sepia = value;
@@ -69,7 +69,7 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const oldFilmFilter = (filter as unknown) as PIXI.filters.OldFilmFilter &
const oldFilmFilter = filter as unknown as PIXI.filters.OldFilmFilter &
OldFilmFilterExtra;
if (parameterName === 'sepia') {
return oldFilmFilter.sepia;
@@ -122,7 +122,7 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): OldFilmFilterNetworkSyncData {
const oldFilmFilter = (filter as unknown) as PIXI.filters.OldFilmFilter &
const oldFilmFilter = filter as unknown as PIXI.filters.OldFilmFilter &
OldFilmFilterExtra;
return {
se: oldFilmFilter.sepia,
@@ -141,7 +141,7 @@ namespace gdjs {
filter: PIXI.Filter,
data: OldFilmFilterNetworkSyncData
) {
const oldFilmFilter = (filter as unknown) as PIXI.filters.OldFilmFilter &
const oldFilmFilter = filter as unknown as PIXI.filters.OldFilmFilter &
OldFilmFilterExtra;
oldFilmFilter.sepia = data.se;
oldFilmFilter.noise = data.n;

View File

@@ -17,7 +17,7 @@ namespace gdjs {
parameterName: string,
value: number
) {
const outlineFilter = (filter as unknown) as PIXI.filters.OutlineFilter;
const outlineFilter = filter as unknown as PIXI.filters.OutlineFilter;
if (parameterName === 'thickness') {
outlineFilter.thickness = value;
} else if (parameterName === 'padding') {
@@ -25,7 +25,7 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const outlineFilter = (filter as unknown) as PIXI.filters.OutlineFilter;
const outlineFilter = filter as unknown as PIXI.filters.OutlineFilter;
if (parameterName === 'thickness') {
return outlineFilter.thickness;
}
@@ -39,7 +39,7 @@ namespace gdjs {
parameterName: string,
value: string
) {
const outlineFilter = (filter as unknown) as PIXI.filters.OutlineFilter;
const outlineFilter = filter as unknown as PIXI.filters.OutlineFilter;
if (parameterName === 'color') {
outlineFilter.color = gdjs.rgbOrHexStringToNumber(value);
}
@@ -49,13 +49,13 @@ namespace gdjs {
parameterName: string,
value: number
): void {
const outlineFilter = (filter as unknown) as PIXI.filters.OutlineFilter;
const outlineFilter = filter as unknown as PIXI.filters.OutlineFilter;
if (parameterName === 'color') {
outlineFilter.color = value;
}
}
getColorParameter(filter: PIXI.Filter, parameterName: string): number {
const outlineFilter = (filter as unknown) as PIXI.filters.OutlineFilter;
const outlineFilter = filter as unknown as PIXI.filters.OutlineFilter;
if (parameterName === 'color') {
return outlineFilter.color;
}
@@ -67,7 +67,7 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): OutlineFilterNetworkSyncData {
const outlineFilter = (filter as unknown) as PIXI.filters.OutlineFilter;
const outlineFilter = filter as unknown as PIXI.filters.OutlineFilter;
return {
t: outlineFilter.thickness,
p: outlineFilter.padding,
@@ -78,7 +78,7 @@ namespace gdjs {
filter: PIXI.Filter,
data: OutlineFilterNetworkSyncData
) {
const outlineFilter = (filter as unknown) as PIXI.filters.OutlineFilter;
const outlineFilter = filter as unknown as PIXI.filters.OutlineFilter;
outlineFilter.thickness = data.t;
outlineFilter.padding = data.p;
outlineFilter.color = data.c;

View File

@@ -21,15 +21,17 @@ namespace gdjs {
parameterName: string,
value: number
) {
const pixelateFilter = (filter as unknown) as PIXI.filters.PixelateFilter &
PixelateFilterExtra;
const pixelateFilter =
filter as unknown as PIXI.filters.PixelateFilter &
PixelateFilterExtra;
if (parameterName === 'size') {
pixelateFilter.size = value;
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const pixelateFilter = (filter as unknown) as PIXI.filters.PixelateFilter &
PixelateFilterExtra;
const pixelateFilter =
filter as unknown as PIXI.filters.PixelateFilter &
PixelateFilterExtra;
if (parameterName === 'size') {
return pixelateFilter.size;
}
@@ -54,16 +56,18 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): PixelateFilterNetworkSyncData {
const pixelateFilter = (filter as unknown) as PIXI.filters.PixelateFilter &
PixelateFilterExtra;
const pixelateFilter =
filter as unknown as PIXI.filters.PixelateFilter &
PixelateFilterExtra;
return { s: pixelateFilter.size };
}
updateFromNetworkSyncData(
filter: PIXI.Filter,
data: PixelateFilterNetworkSyncData
) {
const pixelateFilter = (filter as unknown) as PIXI.filters.PixelateFilter &
PixelateFilterExtra;
const pixelateFilter =
filter as unknown as PIXI.filters.PixelateFilter &
PixelateFilterExtra;
pixelateFilter.size = data.s;
}
})()

View File

@@ -1,26 +1,32 @@
declare namespace PIXI.filters {
export class DropShadowFilter extends PIXI.Filter {
constructor(options?: DropShadowFilterOptions);
/** @deprecated */
rotation: number;
/** @deprecated */
distance: number;
offset: PIXI.Point;
alpha: number;
blur: number;
color: number;
distance: number;
kernels: number[];
pixelSize: number | number[] | PIXI.Point;
quality: number;
rotation: number;
shadowOnly: boolean;
}
export interface DropShadowFilterOptions {
/** @deprecated */
rotation?: number;
/** @deprecated */
distance?: number;
offset: PIXI.Point;
alpha?: number;
blur?: number;
color?: number;
distance?: number;
kernels?: number[];
pixelSize?: number | number[] | PIXI.Point;
quality?: number;
resolution?: number;
rotation?: number;
shadowOnly?: boolean;
}
}

View File

@@ -20,8 +20,9 @@ namespace gdjs {
return radialBlurFilter;
}
updatePreRender(filter: PIXI.Filter, target: EffectsTarget) {
const radialBlurFilter = (filter as unknown) as PIXI.filters.RadialBlurFilter &
RadialBlurFilterExtra;
const radialBlurFilter =
filter as unknown as PIXI.filters.RadialBlurFilter &
RadialBlurFilterExtra;
radialBlurFilter.center[0] = Math.round(
radialBlurFilter._centerX * target.getWidth()
);
@@ -34,8 +35,9 @@ namespace gdjs {
parameterName: string,
value: number
) {
const radialBlurFilter = (filter as unknown) as PIXI.filters.RadialBlurFilter &
RadialBlurFilterExtra;
const radialBlurFilter =
filter as unknown as PIXI.filters.RadialBlurFilter &
RadialBlurFilterExtra;
if (parameterName === 'radius') {
radialBlurFilter.radius = value < 0 ? -1 : value;
} else if (parameterName === 'angle') {
@@ -55,8 +57,9 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const radialBlurFilter = (filter as unknown) as PIXI.filters.RadialBlurFilter &
RadialBlurFilterExtra;
const radialBlurFilter =
filter as unknown as PIXI.filters.RadialBlurFilter &
RadialBlurFilterExtra;
if (parameterName === 'radius') {
radialBlurFilter.radius;
}
@@ -96,8 +99,9 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): RadialBlurFilterNetworkSyncData {
const radialBlurFilter = (filter as unknown) as PIXI.filters.RadialBlurFilter &
RadialBlurFilterExtra;
const radialBlurFilter =
filter as unknown as PIXI.filters.RadialBlurFilter &
RadialBlurFilterExtra;
return {
r: radialBlurFilter.radius,
a: radialBlurFilter.angle,
@@ -111,8 +115,9 @@ namespace gdjs {
filter: PIXI.Filter,
data: RadialBlurFilterNetworkSyncData
) {
const radialBlurFilter = (filter as unknown) as PIXI.filters.RadialBlurFilter &
RadialBlurFilterExtra;
const radialBlurFilter =
filter as unknown as PIXI.filters.RadialBlurFilter &
RadialBlurFilterExtra;
radialBlurFilter.radius = data.r;
radialBlurFilter.angle = data.a;
radialBlurFilter.kernelSize = data.ks;

View File

@@ -40,8 +40,9 @@ namespace gdjs {
return reflectionFilter;
}
updatePreRender(filter: PIXI.Filter, target: EffectsTarget) {
const reflectionFilter = (filter as unknown) as PIXI.filters.ReflectionFilter &
ReflectionFilterExtra;
const reflectionFilter =
filter as unknown as PIXI.filters.ReflectionFilter &
ReflectionFilterExtra;
if (reflectionFilter.animationSpeed !== 0) {
reflectionFilter.time +=
(target.getElapsedTime() / 1000) * reflectionFilter.animationSpeed;
@@ -52,8 +53,9 @@ namespace gdjs {
parameterName: string,
value: number
) {
const reflectionFilter = (filter as unknown) as PIXI.filters.ReflectionFilter &
ReflectionFilterExtra;
const reflectionFilter =
filter as unknown as PIXI.filters.ReflectionFilter &
ReflectionFilterExtra;
if (parameterName === 'boundary') {
reflectionFilter.boundary = value;
}
@@ -80,8 +82,9 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const reflectionFilter = (filter as unknown) as PIXI.filters.ReflectionFilter &
ReflectionFilterExtra;
const reflectionFilter =
filter as unknown as PIXI.filters.ReflectionFilter &
ReflectionFilterExtra;
if (parameterName === 'boundary') {
return reflectionFilter.boundary;
}
@@ -126,15 +129,17 @@ namespace gdjs {
parameterName: string,
value: boolean
) {
const reflectionFilter = (filter as unknown) as PIXI.filters.ReflectionFilter &
ReflectionFilterExtra;
const reflectionFilter =
filter as unknown as PIXI.filters.ReflectionFilter &
ReflectionFilterExtra;
if (parameterName === 'mirror') {
reflectionFilter.mirror = value;
}
}
getNetworkSyncData(filter: PIXI.Filter): ReflectionFilterNetworkSyncData {
const reflectionFilter = (filter as unknown) as PIXI.filters.ReflectionFilter &
ReflectionFilterExtra;
const reflectionFilter =
filter as unknown as PIXI.filters.ReflectionFilter &
ReflectionFilterExtra;
return {
b: reflectionFilter.boundary,
ams: reflectionFilter.amplitude[0],
@@ -151,8 +156,9 @@ namespace gdjs {
filter: PIXI.Filter,
data: ReflectionFilterNetworkSyncData
) {
const reflectionFilter = (filter as unknown) as PIXI.filters.ReflectionFilter &
ReflectionFilterExtra;
const reflectionFilter =
filter as unknown as PIXI.filters.ReflectionFilter &
ReflectionFilterExtra;
reflectionFilter.boundary = data.b;
reflectionFilter.amplitude[0] = data.ams;
reflectionFilter.amplitude[1] = data.ame;

View File

@@ -20,7 +20,7 @@ namespace gdjs {
parameterName: string,
value: number
) {
const rgbSplitFilter = (filter as unknown) as PIXI.filters.RGBSplitFilter;
const rgbSplitFilter = filter as unknown as PIXI.filters.RGBSplitFilter;
if (parameterName === 'redX') {
rgbSplitFilter.red.x = value;
} else if (parameterName === 'redY') {
@@ -36,7 +36,7 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const rgbSplitFilter = (filter as unknown) as PIXI.filters.RGBSplitFilter;
const rgbSplitFilter = filter as unknown as PIXI.filters.RGBSplitFilter;
if (parameterName === 'redX') {
return rgbSplitFilter.red.x;
}
@@ -76,7 +76,7 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): RGBSplitFilterNetworkSyncData {
const rgbSplitFilter = (filter as unknown) as PIXI.filters.RGBSplitFilter;
const rgbSplitFilter = filter as unknown as PIXI.filters.RGBSplitFilter;
return {
rX: rgbSplitFilter.red.x,
rY: rgbSplitFilter.red.y,
@@ -90,7 +90,7 @@ namespace gdjs {
filter: PIXI.Filter,
data: RGBSplitFilterNetworkSyncData
) {
const rgbSplitFilter = (filter as unknown) as PIXI.filters.RGBSplitFilter;
const rgbSplitFilter = filter as unknown as PIXI.filters.RGBSplitFilter;
rgbSplitFilter.red.x = data.rX;
rgbSplitFilter.red.y = data.rY;
rgbSplitFilter.green.x = data.gX;

View File

@@ -16,7 +16,7 @@ namespace gdjs {
parameterName: string,
value: number
) {
const colorMatrixFilter = (filter as unknown) as PIXI.ColorMatrixFilter;
const colorMatrixFilter = filter as unknown as PIXI.ColorMatrixFilter;
if (parameterName === 'opacity') {
colorMatrixFilter.alpha = gdjs.PixiFiltersTools.clampValue(
value,
@@ -26,7 +26,7 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const colorMatrixFilter = (filter as unknown) as PIXI.ColorMatrixFilter;
const colorMatrixFilter = filter as unknown as PIXI.ColorMatrixFilter;
if (parameterName === 'opacity') {
return colorMatrixFilter.alpha;
}
@@ -51,14 +51,14 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): SepiaFilterNetworkSyncData {
const colorMatrixFilter = (filter as unknown) as PIXI.ColorMatrixFilter;
const colorMatrixFilter = filter as unknown as PIXI.ColorMatrixFilter;
return { a: colorMatrixFilter.alpha };
}
updateFromNetworkSyncData(
filter: PIXI.Filter,
data: SepiaFilterNetworkSyncData
) {
const colorMatrixFilter = (filter as unknown) as PIXI.ColorMatrixFilter;
const colorMatrixFilter = filter as unknown as PIXI.ColorMatrixFilter;
colorMatrixFilter.alpha = data.a;
}
})()

View File

@@ -22,8 +22,9 @@ namespace gdjs {
return shockwaveFilter;
}
updatePreRender(filter: PIXI.Filter, target: EffectsTarget) {
const shockwaveFilter = (filter as unknown) as PIXI.filters.ShockwaveFilter &
ShockwaveFilterExtra;
const shockwaveFilter =
filter as unknown as PIXI.filters.ShockwaveFilter &
ShockwaveFilterExtra;
if (shockwaveFilter.speed !== 0) {
shockwaveFilter.time += target.getElapsedTime() / 1000;
}

View File

@@ -16,7 +16,8 @@ namespace gdjs {
parameterName: string,
value: number
) {
const tiltShiftFilter = (filter as unknown) as PIXI.filters.TiltShiftFilter;
const tiltShiftFilter =
filter as unknown as PIXI.filters.TiltShiftFilter;
if (parameterName === 'blur') {
tiltShiftFilter.blur = value;
} else if (parameterName === 'gradientBlur') {
@@ -24,7 +25,8 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const tiltShiftFilter = (filter as unknown) as PIXI.filters.TiltShiftFilter;
const tiltShiftFilter =
filter as unknown as PIXI.filters.TiltShiftFilter;
if (parameterName === 'blur') {
return tiltShiftFilter.blur;
}
@@ -52,14 +54,16 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): TiltShiftFilterNetworkSyncData {
const tiltShiftFilter = (filter as unknown) as PIXI.filters.TiltShiftFilter;
const tiltShiftFilter =
filter as unknown as PIXI.filters.TiltShiftFilter;
return { b: tiltShiftFilter.blur, gb: tiltShiftFilter.gradientBlur };
}
updateFromNetworkSyncData(
filter: PIXI.Filter,
data: TiltShiftFilterNetworkSyncData
) {
const tiltShiftFilter = (filter as unknown) as PIXI.filters.TiltShiftFilter;
const tiltShiftFilter =
filter as unknown as PIXI.filters.TiltShiftFilter;
tiltShiftFilter.blur = data.b;
tiltShiftFilter.gradientBlur = data.gb;
}

View File

@@ -20,7 +20,7 @@ namespace gdjs {
return twistFilter;
}
updatePreRender(filter: PIXI.Filter, target: EffectsTarget) {
const twistFilter = (filter as unknown) as PIXI.filters.TwistFilter &
const twistFilter = filter as unknown as PIXI.filters.TwistFilter &
TwistFilterExtra;
twistFilter.offset.x = Math.round(
twistFilter._offsetX * target.getWidth()
@@ -34,7 +34,7 @@ namespace gdjs {
parameterName: string,
value: number
) {
const twistFilter = (filter as unknown) as PIXI.filters.TwistFilter &
const twistFilter = filter as unknown as PIXI.filters.TwistFilter &
TwistFilterExtra;
if (parameterName === 'radius') {
twistFilter.radius = value;
@@ -49,7 +49,7 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const twistFilter = (filter as unknown) as PIXI.filters.TwistFilter &
const twistFilter = filter as unknown as PIXI.filters.TwistFilter &
TwistFilterExtra;
if (parameterName === 'radius') {
return twistFilter.radius;
@@ -87,7 +87,7 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): TwistFilterNetworkSyncData {
const twistFilter = (filter as unknown) as PIXI.filters.TwistFilter &
const twistFilter = filter as unknown as PIXI.filters.TwistFilter &
TwistFilterExtra;
return {
r: twistFilter.radius,
@@ -101,7 +101,7 @@ namespace gdjs {
filter: PIXI.Filter,
data: TwistFilterNetworkSyncData
) {
const twistFilter = (filter as unknown) as PIXI.filters.TwistFilter &
const twistFilter = filter as unknown as PIXI.filters.TwistFilter &
TwistFilterExtra;
twistFilter.radius = data.r;
twistFilter.angle = data.a;

View File

@@ -19,8 +19,9 @@ namespace gdjs {
return zoomBlurFilter;
}
updatePreRender(filter: PIXI.Filter, target: EffectsTarget) {
const zoomBlurFilter = (filter as unknown) as PIXI.filters.ZoomBlurFilter &
ZoomBlurFilterExtra;
const zoomBlurFilter =
filter as unknown as PIXI.filters.ZoomBlurFilter &
ZoomBlurFilterExtra;
zoomBlurFilter.center[0] = Math.round(
zoomBlurFilter._centerX * target.getWidth()
);
@@ -33,8 +34,9 @@ namespace gdjs {
parameterName: string,
value: number
) {
const zoomBlurFilter = (filter as unknown) as PIXI.filters.ZoomBlurFilter &
ZoomBlurFilterExtra;
const zoomBlurFilter =
filter as unknown as PIXI.filters.ZoomBlurFilter &
ZoomBlurFilterExtra;
if (parameterName === 'centerX') {
zoomBlurFilter._centerX = value;
} else if (parameterName === 'centerY') {
@@ -52,8 +54,9 @@ namespace gdjs {
}
}
getDoubleParameter(filter: PIXI.Filter, parameterName: string): number {
const zoomBlurFilter = (filter as unknown) as PIXI.filters.ZoomBlurFilter &
ZoomBlurFilterExtra;
const zoomBlurFilter =
filter as unknown as PIXI.filters.ZoomBlurFilter &
ZoomBlurFilterExtra;
if (parameterName === 'centerX') {
return zoomBlurFilter._centerX;
}
@@ -90,8 +93,9 @@ namespace gdjs {
value: boolean
) {}
getNetworkSyncData(filter: PIXI.Filter): ZoomBlurFilterNetworkSyncData {
const zoomBlurFilter = (filter as unknown) as PIXI.filters.ZoomBlurFilter &
ZoomBlurFilterExtra;
const zoomBlurFilter =
filter as unknown as PIXI.filters.ZoomBlurFilter &
ZoomBlurFilterExtra;
return {
cx: zoomBlurFilter._centerX,
cy: zoomBlurFilter._centerY,
@@ -104,8 +108,9 @@ namespace gdjs {
filter: PIXI.Filter,
data: ZoomBlurFilterNetworkSyncData
) {
const zoomBlurFilter = (filter as unknown) as PIXI.filters.ZoomBlurFilter &
ZoomBlurFilterExtra;
const zoomBlurFilter =
filter as unknown as PIXI.filters.ZoomBlurFilter &
ZoomBlurFilterExtra;
zoomBlurFilter._centerX = data.cx;
zoomBlurFilter._centerY = data.cy;
zoomBlurFilter.innerRadius = data.ir;

View File

@@ -50,12 +50,12 @@ namespace gdjs {
// `effectData.booleanParameters.someBoolean`
logger.info(
'The PIXI texture found for the Dummy Effect (not actually used):',
(layer
.getRuntimeScene()
.getGame()
.getImageManager() as gdjs.PixiImageManager).getPIXITexture(
effectData.stringParameters.someImage
)
(
layer
.getRuntimeScene()
.getGame()
.getImageManager() as gdjs.PixiImageManager
).getPIXITexture(effectData.stringParameters.someImage)
);
return filter;
}

View File

@@ -148,17 +148,22 @@ namespace gdjs {
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoading = true;
FBInstant.getInterstitialAdAsync(adPlacementId)
.then(function (interstitial) {
gdjs.evtTools.facebookInstantGames._preloadedInterstitial = interstitial;
gdjs.evtTools.facebookInstantGames._preloadedInterstitial =
interstitial;
return interstitial.loadAsync();
})
.then(function () {
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoading = false;
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoaded = true;
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoading =
false;
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoaded =
true;
logger.info('Facebook Instant Games interstitial preloaded.');
})
.catch(function (err) {
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoading = false;
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoaded = false;
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoading =
false;
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoaded =
false;
logger.error('Interstitial failed to preload: ' + err.message);
errorVariable.setString(err.message || 'Unknown error');
});
@@ -181,7 +186,8 @@ namespace gdjs {
errorVariable.setString(err.message || 'Unknown error');
})
.then(function () {
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoaded = false;
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoaded =
false;
});
};
@@ -199,20 +205,26 @@ namespace gdjs {
) {
return;
}
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoading = true;
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoading =
true;
FBInstant.getRewardedVideoAsync(adPlacementId)
.then(function (rewardedVideo) {
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideo = rewardedVideo;
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideo =
rewardedVideo;
return rewardedVideo.loadAsync();
})
.then(function () {
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoading = false;
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoaded = true;
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoading =
false;
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoaded =
true;
logger.info('Facebook Instant Games rewarded video preloaded.');
})
.catch(function (err) {
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoading = false;
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoaded = false;
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoading =
false;
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoaded =
false;
logger.error('Rewarded video failed to preload: ' + err.message);
errorVariable.setString(err.message || 'Unknown error');
});
@@ -235,7 +247,8 @@ namespace gdjs {
errorVariable.setString(err.message || 'Unknown error');
})
.then(function () {
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoaded = false;
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoaded =
false;
});
};

View File

@@ -4528,7 +4528,8 @@ declare namespace firebase.auth {
* @hidden
*/
class RecaptchaVerifier_Instance
implements firebase.auth.ApplicationVerifier {
implements firebase.auth.ApplicationVerifier
{
constructor(
container: any | string,
parameters?: Object | null,
@@ -9509,9 +9510,9 @@ declare namespace firebase.firestore {
* `exists` property will always be true and `data()` will never return
* 'undefined'.
*/
export class QueryDocumentSnapshot<T = DocumentData> extends DocumentSnapshot<
T
> {
export class QueryDocumentSnapshot<
T = DocumentData,
> extends DocumentSnapshot<T> {
private constructor();
/**

View File

@@ -146,8 +146,8 @@ namespace gdjs {
? 'endAt'
: 'endBefore'
: includeSelf
? 'startAt'
: 'startAfter'
? 'startAt'
: 'startAfter'
](value)
);
};

View File

@@ -10,7 +10,8 @@ namespace gdjs {
* Set the interval between auto-config updates.
*/
export const setAutoUpdateInterval = (interval: integer) => {
firebase.remoteConfig().settings.minimumFetchIntervalMillis = interval;
firebase.remoteConfig().settings.minimumFetchIntervalMillis =
interval;
};
/**

View File

@@ -37,7 +37,7 @@ module.exports = {
extension
.registerProperty('FirebaseConfig')
.setLabel(_('Firebase configuration string'))
.setType('textarea');
.setType('multilinestring');
/* ====== ANALYTICS ====== */
extension
@@ -422,7 +422,7 @@ module.exports = {
_('Is the user email address verified'),
_('Checks if the email address of the user got verified.'),
_('The email of the user is verified'),
_('Authentication/User Management'),
_('Authentication User Management'),
'JsPlatform/Extensions/firebase.png',
'JsPlatform/Extensions/firebase.png'
)
@@ -440,7 +440,7 @@ module.exports = {
'GetUserEmail',
_('User email address'),
_('Return the user email address.'),
_('Authentication/User Management'),
_('Authentication User Management'),
'JsPlatform/Extensions/firebase.png'
)
.getCodeExtraInformation()
@@ -457,7 +457,7 @@ module.exports = {
'GetAccountCreationTime',
_('Accounts creation time'),
_('Return the accounts creation time.'),
_('Authentication/User Management'),
_('Authentication User Management'),
'JsPlatform/Extensions/firebase.png'
)
.getCodeExtraInformation()
@@ -474,7 +474,7 @@ module.exports = {
'GetLastLoginTime',
_('User last login time'),
_('Return the user last login time.'),
_('Authentication/User Management'),
_('Authentication User Management'),
'JsPlatform/Extensions/firebase.png'
)
.getCodeExtraInformation()
@@ -491,7 +491,7 @@ module.exports = {
'GetUserDisplayName',
_('User display name'),
_('Return the user display name.'),
_('Authentication/User Management'),
_('Authentication User Management'),
'JsPlatform/Extensions/firebase.png'
)
.getCodeExtraInformation()
@@ -508,7 +508,7 @@ module.exports = {
'GetPhoneNumber',
_('User phone number'),
_('Return the user phone number.'),
_('Authentication/User Management'),
_('Authentication User Management'),
'JsPlatform/Extensions/firebase.png'
)
.getCodeExtraInformation()
@@ -528,7 +528,7 @@ module.exports = {
'Return the user Unique IDentifier. Use that to link data to an ' +
'user instead of the name or email.'
),
_('Authentication/User Management'),
_('Authentication User Management'),
'JsPlatform/Extensions/firebase.png'
)
.getCodeExtraInformation()
@@ -545,7 +545,7 @@ module.exports = {
'GetTenantID',
_('User tenant ID'),
_('Return the user tenant ID. For advanced usage only.'),
_('Authentication/User Management'),
_('Authentication User Management'),
'JsPlatform/Extensions/firebase.png'
)
.getCodeExtraInformation()
@@ -562,7 +562,7 @@ module.exports = {
'GetRefreshToken',
_('User refresh token'),
_('Return the user refresh token. For advanced usage only.'),
_('Authentication/User Management'),
_('Authentication User Management'),
'JsPlatform/Extensions/firebase.png'
)
.getCodeExtraInformation()
@@ -579,7 +579,7 @@ module.exports = {
'GetPhotoURL',
_('Profile picture URL'),
_('Gets an URL to the user profile picture.'),
_('Authentication/User Management'),
_('Authentication User Management'),
'JsPlatform/Extensions/firebase.png'
)
.getCodeExtraInformation()
@@ -597,7 +597,7 @@ module.exports = {
_('Send a password reset email'),
_('Send a password reset link per email.'),
_('Send a password reset email'),
_('Authentication/User Management'),
_('Authentication User Management'),
'JsPlatform/Extensions/firebase.png',
'JsPlatform/Extensions/firebase.png'
)
@@ -619,7 +619,7 @@ module.exports = {
_('Send a verification email'),
_('Send a link per email to verify the user email.'),
_('Send a verification email'),
_('Authentication/User Management'),
_('Authentication User Management'),
'JsPlatform/Extensions/firebase.png',
'JsPlatform/Extensions/firebase.png'
)
@@ -638,7 +638,7 @@ module.exports = {
_('Display name'),
_('Sets the user display name.'),
_("Set the user's display name to _PARAM0_"),
_('Authentication/User Management'),
_('Authentication User Management'),
'JsPlatform/Extensions/firebase.png',
'JsPlatform/Extensions/firebase.png'
)
@@ -658,7 +658,7 @@ module.exports = {
_('Profile picture'),
_('Change the user profile picture URL to a new one.'),
_("Change the user's profile picture URL to _PARAM0_"),
_('Authentication/User Management'),
_('Authentication User Management'),
'JsPlatform/Extensions/firebase.png',
'JsPlatform/Extensions/firebase.png'
)
@@ -684,7 +684,7 @@ module.exports = {
_(
"Change the user's email to _PARAM0_ and store result in _PARAM4_ (send verification email: _PARAM3_)"
),
_('Authentication/User Management/Advanced'),
_('Authentication User Management Advanced'),
'JsPlatform/Extensions/firebase.png',
'JsPlatform/Extensions/firebase.png'
)
@@ -725,7 +725,7 @@ module.exports = {
_(
"Change the user's email to _PARAM0_ and store result in _PARAM2_ (send verification email: _PARAM1_)"
),
_('Authentication/User Management/Advanced'),
_('Authentication User Management Advanced'),
'JsPlatform/Extensions/firebase.png',
'JsPlatform/Extensions/firebase.png'
)
@@ -764,7 +764,7 @@ module.exports = {
'Change the user password to _PARAM2_ and store result in ' +
'_PARAM4_ (send verification email: _PARAM3_)'
),
_('Authentication/User Management/Advanced'),
_('Authentication User Management Advanced'),
'JsPlatform/Extensions/firebase.png',
'JsPlatform/Extensions/firebase.png'
)
@@ -806,7 +806,7 @@ module.exports = {
'Change the user password to _PARAM0_ and store result in ' +
'_PARAM2_ (send verification email: _PARAM1_)'
),
_('Authentication/User Management/Advanced'),
_('Authentication User Management Advanced'),
'JsPlatform/Extensions/firebase.png',
'JsPlatform/Extensions/firebase.png'
)
@@ -842,7 +842,7 @@ module.exports = {
'Deletes the user account.'
),
_('Delete the user account and store result in _PARAM2_'),
_('Authentication/User Management/Advanced'),
_('Authentication User Management Advanced'),
'JsPlatform/Extensions/firebase.png',
'JsPlatform/Extensions/firebase.png'
)
@@ -873,7 +873,7 @@ module.exports = {
'This is the same as "Delete the user account" but reauthenticates via an external provider.'
),
_('Delete the user account and store result in _PARAM0_'),
_('Authentication/User Management/Advanced'),
_('Authentication User Management Advanced'),
'JsPlatform/Extensions/firebase.png',
'JsPlatform/Extensions/firebase.png'
)

View File

@@ -519,9 +519,9 @@ describeIfOnline('Firebase extension end-to-end tests', function () {
// Delete the temporary namespace to not bloat the DB
after(async () =>
(
await firebase.firestore().collection(namespace).get()
).forEach(({ ref }) => ref.delete())
(await firebase.firestore().collection(namespace).get()).forEach(
({ ref }) => ref.delete()
)
);
});

View File

@@ -189,6 +189,7 @@ declare type ObjectsRenderingService = {
objectConfiguration: gd.ObjectConfiguration
) => string;
rgbOrHexToHexNumber: (value: string) => number;
hexNumberToRGBArray: (value: number) => [number, number, number];
registerClearCache: (clearCache: (_: any) => void) => void;
};

View File

@@ -223,9 +223,8 @@ namespace gdjs {
let _leaderboardViewIframeLoading: boolean = false;
let _leaderboardViewIframeLoaded: boolean = false;
let _errorTimeoutId: NodeJS.Timeout | null = null;
let _leaderboardMessageListener:
| ((event: MessageEvent) => void)
| null = null;
let _leaderboardMessageListener: ((event: MessageEvent) => void) | null =
null;
const _loaderContainer: HTMLDivElement = document.createElement('div');
_loaderContainer.style.backgroundColor = '#000000';
@@ -319,9 +318,8 @@ namespace gdjs {
};
let leaderboardEntryCreationUrl = `${baseUrl}/game/${gdjs.projectData.properties.projectUuid}/leaderboard/${leaderboardId}/entry`;
if (authenticatedPlayerData) {
headers[
'Authorization'
] = `player-game-token ${authenticatedPlayerData.playerToken}`;
headers['Authorization'] =
`player-game-token ${authenticatedPlayerData.playerToken}`;
leaderboardEntryCreationUrl += `?playerId=${authenticatedPlayerData.playerId}`;
} else {
// In case playerName is empty, the backend will generate a random name.
@@ -397,10 +395,8 @@ namespace gdjs {
new ScoreSavingState());
try {
const {
closeSaving,
closeSavingWithError,
} = scoreSavingState.startSaving({ playerName, score });
const { closeSaving, closeSavingWithError } =
scoreSavingState.startSaving({ playerName, score });
try {
const leaderboardEntry = await saveScore({
@@ -443,10 +439,8 @@ namespace gdjs {
new ScoreSavingState());
try {
const {
closeSaving,
closeSavingWithError,
} = scoreSavingState.startSaving({ playerId, score });
const { closeSaving, closeSavingWithError } =
scoreSavingState.startSaving({ playerId, score });
try {
const leaderboardEntryId = await saveScore({
@@ -866,9 +860,8 @@ namespace gdjs {
resetLeaderboardDisplayErrorTimeout(runtimeScene);
_leaderboardViewIframe = computeLeaderboardDisplayingIframe(
targetUrl
);
_leaderboardViewIframe =
computeLeaderboardDisplayingIframe(targetUrl);
if (typeof window !== 'undefined') {
_leaderboardMessageListener = (event: MessageEvent) => {
receiveMessageFromLeaderboardView(

View File

@@ -235,7 +235,8 @@ module.exports = {
class RenderedLightObjectInstance extends RenderedInstance {
_radius = 0;
_color = 0;
_radiusGraphics = null;
/** @type {PIXI.Graphics} The circle to show the radius of the light */
_radiusGraphics;
constructor(
project,
@@ -259,7 +260,6 @@ module.exports = {
lightIconSprite.anchor.x = 0.5;
lightIconSprite.anchor.y = 0.5;
// The circle to show the radius of the light.
this._radiusGraphics = new PIXI.Graphics();
this._pixiObject = new PIXI.Container();

View File

@@ -18,9 +18,8 @@ namespace gdjs {
if (!instanceContainer._lightObstaclesManager) {
// Create the shared manager if necessary.
// @ts-ignore
instanceContainer._lightObstaclesManager = new gdjs.LightObstaclesManager(
instanceContainer
);
instanceContainer._lightObstaclesManager =
new gdjs.LightObstaclesManager(instanceContainer);
}
// @ts-ignore
return instanceContainer._lightObstaclesManager;
@@ -70,9 +69,8 @@ namespace gdjs {
searchArea.maxX = x + radius;
// @ts-ignore
searchArea.maxY = y + radius;
const nearbyObstacles: gdjs.BehaviorRBushAABB<
gdjs.LightObstacleRuntimeBehavior
>[] = this._obstacleRBush.search(searchArea);
const nearbyObstacles: gdjs.BehaviorRBushAABB<gdjs.LightObstacleRuntimeBehavior>[] =
this._obstacleRBush.search(searchArea);
result.length = 0;
nearbyObstacles.forEach((nearbyObstacle) =>
result.push(nearbyObstacle.behavior)
@@ -85,9 +83,8 @@ namespace gdjs {
_oldY: float = 0;
_oldWidth: float = 0;
_oldHeight: float = 0;
currentRBushAABB: gdjs.BehaviorRBushAABB<
LightObstacleRuntimeBehavior
> | null = null;
currentRBushAABB: gdjs.BehaviorRBushAABB<LightObstacleRuntimeBehavior> | null =
null;
_manager: any;
_registeredInManager: boolean = false;

View File

@@ -197,11 +197,11 @@ namespace gdjs {
const texture = this._object.getTexture();
this._texture =
texture !== ''
? (this._instanceContainer
.getGame()
.getImageManager() as gdjs.PixiImageManager).getPIXITexture(
texture
)
? (
this._instanceContainer
.getGame()
.getImageManager() as gdjs.PixiImageManager
).getPIXITexture(texture)
: null;
}
@@ -466,35 +466,38 @@ namespace gdjs {
const xdiff = flattenVertices[i][0] - this._object.x;
const ydiff = flattenVertices[i][1] - this._object.y;
const angle = Math.atan2(ydiff, xdiff);
const closestVertex = LightRuntimeObjectPixiRenderer._computeClosestIntersectionPoint(
this._object,
angle,
obstaclePolygons,
boundingSquareHalfDiag
);
const closestVertex =
LightRuntimeObjectPixiRenderer._computeClosestIntersectionPoint(
this._object,
angle,
obstaclePolygons,
boundingSquareHalfDiag
);
if (closestVertex) {
closestVertices.push({ vertex: closestVertex, angle: angle });
}
// TODO: Check whether we need to raycast these two extra rays or not.
const closestVertexOffsetLeft = LightRuntimeObjectPixiRenderer._computeClosestIntersectionPoint(
this._object,
angle + 0.0001,
obstaclePolygons,
boundingSquareHalfDiag
);
const closestVertexOffsetLeft =
LightRuntimeObjectPixiRenderer._computeClosestIntersectionPoint(
this._object,
angle + 0.0001,
obstaclePolygons,
boundingSquareHalfDiag
);
if (closestVertexOffsetLeft) {
closestVertices.push({
vertex: closestVertexOffsetLeft,
angle: angle + 0.0001,
});
}
const closestVertexOffsetRight = LightRuntimeObjectPixiRenderer._computeClosestIntersectionPoint(
this._object,
angle - 0.0001,
obstaclePolygons,
boundingSquareHalfDiag
);
const closestVertexOffsetRight =
LightRuntimeObjectPixiRenderer._computeClosestIntersectionPoint(
this._object,
angle - 0.0001,
obstaclePolygons,
boundingSquareHalfDiag
);
if (closestVertexOffsetRight) {
closestVertices.push({
vertex: closestVertexOffsetRight,

View File

@@ -47,9 +47,8 @@ namespace gdjs {
this._color = gdjs.rgbOrHexToRGBColor(lightObjectData.content.color);
this._debugMode = lightObjectData.content.debugMode;
this._texture = lightObjectData.content.texture;
this._obstaclesManager = gdjs.LightObstaclesManager.getManager(
runtimeScene
);
this._obstaclesManager =
gdjs.LightObstaclesManager.getManager(runtimeScene);
this._renderer = new gdjs.LightRuntimeObjectRenderer(this, runtimeScene);
this._instanceContainer = runtimeScene;

View File

@@ -194,12 +194,11 @@ namespace gdjs {
export namespace evtTools {
export namespace linkedObjects {
gdjs.registerObjectDeletedFromSceneCallback(function (
instanceContainer,
obj
) {
LinksManager.getManager(instanceContainer).removeAllLinksOf(obj);
});
gdjs.registerObjectDeletedFromSceneCallback(
function (instanceContainer, obj) {
LinksManager.getManager(instanceContainer).removeAllLinksOf(obj);
}
);
export const linkObjects = function (
instanceContainer: gdjs.RuntimeInstanceContainer,
@@ -245,9 +244,10 @@ namespace gdjs {
if (obj === null) {
return false;
}
const linkedObjectMap = LinksManager.getManager(
instanceContainer
)._getMapOfObjectsLinkedWith(obj);
const linkedObjectMap =
LinksManager.getManager(instanceContainer)._getMapOfObjectsLinkedWith(
obj
);
let pickedSomething = false;
for (const contextObjectName in objectsLists.items) {

View File

@@ -31,6 +31,128 @@ module.exports = {
.addInstructionOrExpressionGroupMetadata(_('Multiplayer'))
.setIcon('JsPlatform/Extensions/multiplayer.svg');
extension
.addAction(
'QuickJoinLobby',
_('Join the next available lobby'),
_(
'Join the next available lobby. The player will join the game instantly if this is possible.'
),
_('Join the next available lobby'),
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
.addCodeOnlyParameter('currentScene', '')
.addParameter(
'yesorno',
_('Display loader while searching for a lobby.'),
'',
true
)
.setDefaultValue('yes')
.addParameter(
'yesorno',
_('Display game lobbies if no lobby can be joined directly.'),
'',
true
)
.setDefaultValue('yes')
.setHelpPath('/all-features/multiplayer')
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayer.authenticateAndQuickJoinLobby');
extension
.addCondition(
'IsSearchingForLobbyToJoin',
_('Is searching for a lobby to join'),
_('Is searching for a lobby to join.'),
_('Is searching for a lobby to join'),
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
.addCodeOnlyParameter('currentScene', '')
.setHelpPath('/all-features/multiplayer')
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayer.isSearchingForLobbyToJoin');
extension
.addCondition(
'QuickJoinJustFailed',
_('Quick join failed to join a lobby'),
_('Quick join failed to join a lobby.'),
_('Quick join failed to join a lobby'),
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
.addCodeOnlyParameter('currentScene', '')
.setHelpPath('/all-features/multiplayer')
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayer.hasQuickJoinJustFailed');
extension
.addStrExpression(
'QuickJoinFailureReason',
_('Quick join action failure reason'),
_(
"Returns the reason why the Quick join action failed. It can either be 'FULL' if all lobbies were occupied, 'NOT_ENOUGH_PLAYERS' if the lobby's configuration requires more than 1 player to start the game and no other players were available. It can also take the value 'UNKNOWN'."
),
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayer.getQuickJoinFailureReason');
extension
.addAction(
'OpenGameLobbies',

View File

@@ -149,18 +149,16 @@ namespace gdjs {
let lastSceneSyncTimestamp = 0;
let lastSentSceneSyncData: LayoutNetworkSyncData | null = null;
let numberOfForcedSceneUpdates = 0;
let lastReceivedSceneSyncDataUpdates = new SavedSyncDataUpdates<
LayoutNetworkSyncData
>();
let lastReceivedSceneSyncDataUpdates =
new SavedSyncDataUpdates<LayoutNetworkSyncData>();
// The number of times per second the game data should be synchronized.
const gameSyncDataSyncRate = 1;
let lastGameSyncTimestamp = 0;
let lastSentGameSyncData: GameNetworkSyncData | null = null;
let numberOfForcedGameUpdates = 0;
let lastReceivedGameSyncDataUpdates = new SavedSyncDataUpdates<
GameNetworkSyncData
>();
let lastReceivedGameSyncDataUpdates =
new SavedSyncDataUpdates<GameNetworkSyncData>();
// Send heartbeat messages from host to players, ensuring their connection is still alive,
// measure the ping, and send other useful info.
@@ -261,9 +259,8 @@ namespace gdjs {
_lastClockReceivedByInstanceByScene[sceneNetworkId] = {};
}
_lastClockReceivedByInstanceByScene[sceneNetworkId][
instanceNetworkId
] = clock;
_lastClockReceivedByInstanceByScene[sceneNetworkId][instanceNetworkId] =
clock;
};
/**
@@ -407,7 +404,8 @@ namespace gdjs {
};
const changeInstanceOwnerMessageNamePrefix = '#changeInstanceOwner';
const changeInstanceOwnerMessageNameRegex = /#changeInstanceOwner#owner_(\d+)#object_(.+)#instance_(.+)/;
const changeInstanceOwnerMessageNameRegex =
/#changeInstanceOwner#owner_(\d+)#object_(.+)#instance_(.+)/;
const createChangeInstanceOwnerMessage = ({
objectOwner,
objectName,
@@ -446,15 +444,15 @@ namespace gdjs {
};
};
const instanceOwnerChangedMessageNamePrefix = '#instanceOwnerChanged';
const instanceOwnerChangedMessageNameRegex = /#instanceOwnerChanged#owner_(\d+)#object_(.+)#instance_(.+)/;
const createInstanceOwnerChangedMessageNameFromChangeInstanceOwnerMessage = (
messageName: string
): string => {
return messageName.replace(
changeInstanceOwnerMessageNamePrefix,
instanceOwnerChangedMessageNamePrefix
);
};
const instanceOwnerChangedMessageNameRegex =
/#instanceOwnerChanged#owner_(\d+)#object_(.+)#instance_(.+)/;
const createInstanceOwnerChangedMessageNameFromChangeInstanceOwnerMessage =
(messageName: string): string => {
return messageName.replace(
changeInstanceOwnerMessageNamePrefix,
instanceOwnerChangedMessageNamePrefix
);
};
const handleChangeInstanceOwnerMessagesReceived = (
runtimeScene: gdjs.RuntimeScene
) => {
@@ -524,7 +522,8 @@ namespace gdjs {
return;
}
const currentPlayerObjectOwnership = behavior.getPlayerObjectOwnership();
const currentPlayerObjectOwnership =
behavior.getPlayerObjectOwnership();
// Change is coherent if:
const ownershipChangeIsCoherent =
// the object is changing ownership from the same owner the host knew about,
@@ -550,9 +549,10 @@ namespace gdjs {
);
behavior.playerNumber = newOwner;
const instanceOwnerChangedMessageName = createInstanceOwnerChangedMessageNameFromChangeInstanceOwnerMessage(
messageName
);
const instanceOwnerChangedMessageName =
createInstanceOwnerChangedMessageNameFromChangeInstanceOwnerMessage(
messageName
);
debugLogger.info(
`Sending acknowledgment of ownership change of object ${objectName} from ${previousOwner} to ${newOwner} with instance network ID ${instanceNetworkId} to ${messageSender}.`
@@ -594,7 +594,8 @@ namespace gdjs {
};
const updateInstanceMessageNamePrefix = '#updateInstance';
const updateInstanceMessageNameRegex = /#updateInstance#owner_(\d+)#object_(.+)#instance_(.+)#scene_(.+)/;
const updateInstanceMessageNameRegex =
/#updateInstance#owner_(\d+)#object_(.+)#instance_(.+)#scene_(.+)/;
const createUpdateInstanceMessage = ({
objectOwner,
objectName,
@@ -757,7 +758,8 @@ namespace gdjs {
};
const changeVariableOwnerMessageNamePrefix = '#changeVariableOwner';
const changeVariableOwnerMessageNameRegex = /#changeVariableOwner#owner_(\d+)#variable_(.+)/;
const changeVariableOwnerMessageNameRegex =
/#changeVariableOwner#owner_(\d+)#variable_(.+)/;
const createChangeVariableOwnerMessage = ({
variableOwner,
variableNetworkId,
@@ -782,15 +784,15 @@ namespace gdjs {
};
};
const variableOwnerChangedMessageNamePrefix = '#variableOwnerChanged';
const variableOwnerChangedMessageNameRegex = /#variableOwnerChanged#owner_(\d+)#variable_(.+)/;
const createVariableOwnerChangedMessageNameFromChangeVariableOwnerMessage = (
messageName: string
): string => {
return messageName.replace(
changeVariableOwnerMessageNamePrefix,
variableOwnerChangedMessageNamePrefix
);
};
const variableOwnerChangedMessageNameRegex =
/#variableOwnerChanged#owner_(\d+)#variable_(.+)/;
const createVariableOwnerChangedMessageNameFromChangeVariableOwnerMessage =
(messageName: string): string => {
return messageName.replace(
changeVariableOwnerMessageNamePrefix,
variableOwnerChangedMessageNamePrefix
);
};
const handleChangeVariableOwnerMessagesReceived = (
runtimeScene: gdjs.RuntimeScene
) => {
@@ -885,9 +887,10 @@ namespace gdjs {
);
variable.setPlayerOwnership(newOwner);
const variableOwnerChangedMessageName = createVariableOwnerChangedMessageNameFromChangeVariableOwnerMessage(
messageName
);
const variableOwnerChangedMessageName =
createVariableOwnerChangedMessageNameFromChangeVariableOwnerMessage(
messageName
);
debugLogger.info(
`Sending acknowledgment of ownership change of variable with ID ${variableNetworkId} from ${previousOwner} to ${newOwner} to ${messageSender}.`
@@ -1081,9 +1084,10 @@ namespace gdjs {
changeInstanceOwnerMessageNamePrefix
)
) {
const matches = changeInstanceOwnerMessageNameRegex.exec(
originalMessageName
);
const matches =
changeInstanceOwnerMessageNameRegex.exec(
originalMessageName
);
if (!matches) {
// This should not happen, if it does, remove the acknowledgment and return.
delete expectedMessageAcknowledgements[
@@ -1146,9 +1150,10 @@ namespace gdjs {
changeVariableOwnerMessageNamePrefix
)
) {
const matches = changeVariableOwnerMessageNameRegex.exec(
originalMessageName
);
const matches =
changeVariableOwnerMessageNameRegex.exec(
originalMessageName
);
if (!matches) {
// This should not happen, if it does, remove the acknowledgment and return.
delete expectedMessageAcknowledgements[
@@ -1229,7 +1234,8 @@ namespace gdjs {
};
const destroyInstanceMessageNamePrefix = '#destroyInstance';
const destroyInstanceMessageNameRegex = /#destroyInstance#owner_(\d+)#object_(.+)#instance_(.+)#scene_(.+)/;
const destroyInstanceMessageNameRegex =
/#destroyInstance#owner_(\d+)#object_(.+)#instance_(.+)#scene_(.+)/;
const createDestroyInstanceMessage = ({
objectOwner,
objectName,
@@ -1250,7 +1256,8 @@ namespace gdjs {
};
};
const instanceDestroyedMessageNamePrefix = '#instanceDestroyed';
const instanceDestroyedMessageNameRegex = /#instanceDestroyed#owner_(\d+)#object_(.+)#instance_(.+)/;
const instanceDestroyedMessageNameRegex =
/#instanceDestroyed#owner_(\d+)#object_(.+)#instance_(.+)/;
const createInstanceDestroyedMessageNameFromDestroyInstanceMessage = (
messageName: string
): string => {
@@ -1315,9 +1322,10 @@ namespace gdjs {
instanceNetworkId,
});
const instanceDestroyedMessageName = createInstanceDestroyedMessageNameFromDestroyInstanceMessage(
messageName
);
const instanceDestroyedMessageName =
createInstanceDestroyedMessageNameFromDestroyInstanceMessage(
messageName
);
if (!instance) {
debugLogger.info(
@@ -1420,9 +1428,8 @@ namespace gdjs {
userMessageData,
senderPlayerNumber: currentPlayerNumber,
});
const acknowledgmentMessageName = createAcknowledgeCustomMessageNameFromCustomMessage(
messageName
);
const acknowledgmentMessageName =
createAcknowledgeCustomMessageNameFromCustomMessage(messageName);
addExpectedMessageAcknowledgement({
originalMessageName: messageName,
originalData: messageData,
@@ -1441,9 +1448,8 @@ namespace gdjs {
// If we are the host, we can consider this messaged as received
// and add it to the list of custom messages to process on top of the messages received.
if (gdjs.multiplayer.isCurrentPlayerHost()) {
const messagesList = gdjs.multiplayerPeerJsHelper.getOrCreateMessagesList(
messageName
);
const messagesList =
gdjs.multiplayerPeerJsHelper.getOrCreateMessagesList(messageName);
messagesList.pushMessage(
messageData,
gdjs.multiplayerPeerJsHelper.getCurrentId()
@@ -1467,9 +1473,8 @@ namespace gdjs {
};
const hasCustomMessageBeenReceived = (userMessageName: string) => {
const customMessageName = getCustomMessageNameFromUserMessageName(
userMessageName
);
const customMessageName =
getCustomMessageNameFromUserMessageName(userMessageName);
const p2pMessagesMap = gdjs.multiplayerPeerJsHelper.getAllMessagesMap();
const messagesList = p2pMessagesMap.get(customMessageName);
if (!messagesList) return; // No message received.
@@ -1499,9 +1504,8 @@ namespace gdjs {
};
const getCustomMessageData = (userMessageName: string) => {
const customMessageName = getCustomMessageNameFromUserMessageName(
userMessageName
);
const customMessageName =
getCustomMessageNameFromUserMessageName(userMessageName);
const p2pMessagesMap = gdjs.multiplayerPeerJsHelper.getAllMessagesMap();
const messagesList = p2pMessagesMap.get(customMessageName);
if (!messagesList) return; // No message received.
@@ -1531,9 +1535,8 @@ namespace gdjs {
};
const getCustomMessageSender = (userMessageName: string): number => {
const customMessageName = getCustomMessageNameFromUserMessageName(
userMessageName
);
const customMessageName =
getCustomMessageNameFromUserMessageName(userMessageName);
const p2pMessagesMap = gdjs.multiplayerPeerJsHelper.getAllMessagesMap();
const messagesList = p2pMessagesMap.get(customMessageName);
if (!messagesList) return 0;
@@ -1593,9 +1596,8 @@ namespace gdjs {
return;
}
const acknowledgmentMessageName = createAcknowledgeCustomMessageNameFromCustomMessage(
messageName
);
const acknowledgmentMessageName =
createAcknowledgeCustomMessageNameFromCustomMessage(messageName);
debugLogger.info(
`Sending acknowledgment of custom message ${messageName} to ${messageSender}.`
);
@@ -1681,9 +1683,8 @@ namespace gdjs {
return;
}
const isSceneSyncDataDifferent = isSceneDifferentFromLastSync(
sceneNetworkSyncData
);
const isSceneSyncDataDifferent =
isSceneDifferentFromLastSync(sceneNetworkSyncData);
const shouldSyncScene =
!hasSceneBeenSyncedRecently() ||
isSceneSyncDataDifferent ||
@@ -1845,9 +1846,8 @@ namespace gdjs {
return;
}
const isGameSyncDataDifferent = isGameDifferentFromLastSync(
gameNetworkSyncData
);
const isGameSyncDataDifferent =
isGameDifferentFromLastSync(gameNetworkSyncData);
const shouldSyncGame =
!hasGameBeenSyncedRecently() ||
isGameSyncDataDifferent ||
@@ -1945,12 +1945,12 @@ namespace gdjs {
};
const heartbeatMessageNamePrefix = '#heartbeat';
const heartbeastMessageRegex = /#heartbeat#(.+)/;
const heartbeatMessageRegex = /#heartbeat#(.+)/;
const createHeartbeatMessage = (): {
messageName: string;
messageData: any;
} => {
// If we create the heartbeat meassage, we are the host,
// If we create the heartbeat message, we are the host.
// Ensure our player number is correctly set when the first heartbeat is sent.
_playersInfo[gdjs.multiplayer.getCurrentPlayerNumber()] = {
ping: 0, // we are the host, so we don't need to compute the ping.
@@ -2028,7 +2028,7 @@ namespace gdjs {
messages.forEach((message) => {
const messageData = message.getData();
const messageSender = message.getSender();
const matches = heartbeastMessageRegex.exec(messageName);
const matches = heartbeatMessageRegex.exec(messageName);
if (!matches) {
return;
}
@@ -2039,10 +2039,11 @@ namespace gdjs {
// If we are not the host, save what the host told us about the other players info
// and respond with a heartbeat immediately, informing the host of our playerId and username.
if (!gdjs.multiplayer.isCurrentPlayerHost()) {
const currentPlayerNumber = gdjs.multiplayer.getCurrentPlayerNumber();
const currentlyKnownPlayerNumbers = Object.keys(
_playersInfo
).map((playerNumber) => parseInt(playerNumber, 10));
const currentPlayerNumber =
gdjs.multiplayer.getCurrentPlayerNumber();
const currentlyKnownPlayerNumbers = Object.keys(_playersInfo).map(
(playerNumber) => parseInt(playerNumber, 10)
);
const receivedPlayerNumbers = Object.keys(
messageData.playersInfo
).map((playerNumber) => parseInt(playerNumber, 10));
@@ -2061,18 +2062,19 @@ namespace gdjs {
);
_playerNumbersWhoJustJoined.push(...newPlayerNumbers);
// Or players who have disconnected.
const playerNumbersWhoHaveDisconnected = currentlyKnownPlayerNumbers.filter(
(playerNumber) => !receivedPlayerNumbers.includes(playerNumber)
);
const playerNumbersWhoHaveDisconnected =
currentlyKnownPlayerNumbers.filter(
(playerNumber) =>
!receivedPlayerNumbers.includes(playerNumber)
);
_playerNumbersWhoJustLeft.push(
...playerNumbersWhoHaveDisconnected
);
for (const playerNumber of playerNumbersWhoHaveDisconnected) {
// Temporarily save the username in another variable to be used for the notification,
// as we're deleting its playerInfo just after.
_temporaryPlayerNumberToUsername[
playerNumber
] = getPlayerUsername(playerNumber);
_temporaryPlayerNumberToUsername[playerNumber] =
getPlayerUsername(playerNumber);
}
}
@@ -2188,14 +2190,14 @@ namespace gdjs {
_playerNumbersWhoJustLeft.push(playerNumber);
// Temporarily save the username in another variable to be used for the notification,
// as we're deleting its playerInfo just after.
_temporaryPlayerNumberToUsername[playerNumber] = getPlayerUsername(
playerNumber
);
_temporaryPlayerNumberToUsername[playerNumber] =
getPlayerUsername(playerNumber);
clearPlayerTempData(playerNumber);
// If Host has disconnected, either switch host or stop the game.
if (peerId && peerId === gdjs.multiplayer.hostPeerId) {
const shouldEndLobbyGame = gdjs.multiplayer.shouldEndLobbyWhenHostLeaves();
const shouldEndLobbyGame =
gdjs.multiplayer.shouldEndLobbyWhenHostLeaves();
if (shouldEndLobbyGame) {
logger.info('Host has disconnected, ending the game.');
@@ -2243,7 +2245,8 @@ namespace gdjs {
peerId: string;
}[] = [];
const justDisconnectedPeers = gdjs.multiplayerPeerJsHelper.getJustDisconnectedPeers();
const justDisconnectedPeers =
gdjs.multiplayerPeerJsHelper.getJustDisconnectedPeers();
if (justDisconnectedPeers.length) {
for (const disconnectedPeer of justDisconnectedPeers) {
const disconnectedPlayerNumber =
@@ -2273,7 +2276,8 @@ namespace gdjs {
behavior &&
behavior.getPlayerObjectOwnership() === playerNumber
) {
const actionOnPlayerDisconnect = behavior.getActionOnPlayerDisconnect();
const actionOnPlayerDisconnect =
behavior.getActionOnPlayerDisconnect();
if (actionOnPlayerDisconnect === 'DestroyObject') {
// No need to remove the ownership, as the destroy message will be sent to all players.
instance.deleteFromScene(runtimeScene);

View File

@@ -78,9 +78,10 @@ namespace gdjs {
return;
}
const variableName = currentSceneVariables.getVariableNameInContainerByLoopingThroughAllVariables(
variable
);
const variableName =
currentSceneVariables.getVariableNameInContainerByLoopingThroughAllVariables(
variable
);
if (!variableName) {
logger.error('Variable is being synchronized but has no name.');
@@ -98,9 +99,10 @@ namespace gdjs {
// TODO: prevent returning a networkID if this is not a root variable.
const variableName = runtimeGameVariables.getVariableNameInContainerByLoopingThroughAllVariables(
variable
);
const variableName =
runtimeGameVariables.getVariableNameInContainerByLoopingThroughAllVariables(
variable
);
if (!variableName) {
logger.error('Variable is being synchronized but has no name.');
return;
@@ -171,9 +173,8 @@ namespace gdjs {
return;
}
const { type: variableType } = getVariableTypeAndNameFromNetworkId(
variableNetworkId
);
const { type: variableType } =
getVariableTypeAndNameFromNetworkId(variableNetworkId);
debugLogger.info(
`Adding variable to be synchronized: ${variableNetworkId} (type: ${variableType}) from owner ${previousVariablePlayerNumber} to ${newVariablePlayerNumber}.`
@@ -220,21 +221,20 @@ namespace gdjs {
for (const variableNetworkId in variableOwnershipChangesToSyncAtEndOfFrame) {
const variableData =
variableOwnershipChangesToSyncAtEndOfFrame[variableNetworkId];
const {
messageName,
messageData,
} = gdjs.multiplayerMessageManager.createChangeVariableOwnerMessage({
variableNetworkId,
variableOwner: variableData.previousVariableOwner,
newVariableOwner: variableData.newVariableOwner,
});
const { messageName, messageData } =
gdjs.multiplayerMessageManager.createChangeVariableOwnerMessage({
variableNetworkId,
variableOwner: variableData.previousVariableOwner,
newVariableOwner: variableData.newVariableOwner,
});
// Before sending the change owner message, if we are becoming the new owner,
// we want to ensure this message is acknowledged, by everyone we're connected to.
if (variableData.newVariableOwner === currentPlayerNumber) {
const otherPeerIds = gdjs.multiplayerPeerJsHelper.getAllPeers();
const variableOwnerChangedMessageName = gdjs.multiplayerMessageManager.createVariableOwnerChangedMessageNameFromChangeVariableOwnerMessage(
messageName
);
const variableOwnerChangedMessageName =
gdjs.multiplayerMessageManager.createVariableOwnerChangedMessageNameFromChangeVariableOwnerMessage(
messageName
);
gdjs.multiplayerMessageManager.addExpectedMessageAcknowledgement({
originalMessageName: messageName,
originalData: messageData,

View File

@@ -1,6 +1,7 @@
namespace gdjs {
const logger = new gdjs.Logger('Multiplayer');
export namespace multiplayerComponents {
const loaderContainerId = 'loader-container';
const lobbiesRootContainerId = 'lobbies-root-container';
const lobbiesFrameContainerId = 'lobbies-frame-container';
const lobbiesCloseContainerId = 'lobbies-close-container';
@@ -117,6 +118,66 @@ namespace gdjs {
return lobbiesIframe;
};
export const displayLoader = (
runtimeScene: gdjs.RuntimeScene,
yesOrNo: boolean
) => {
const domElementContainer = getDomElementContainer(runtimeScene);
if (!domElementContainer) {
return;
}
if (yesOrNo) {
const loaderContainer: HTMLDivElement = document.createElement('div');
loaderContainer.id = loaderContainerId;
loaderContainer.style.backgroundColor = '#000000';
loaderContainer.style.display = 'flex';
loaderContainer.style.height = '100%';
loaderContainer.style.width = '100%';
loaderContainer.style.justifyContent = 'center';
loaderContainer.style.alignItems = 'center';
loaderContainer.style.position = 'relative';
loaderContainer.style.zIndex = '2';
const loader = document.createElement('img');
loader.setAttribute('width', '50px');
loader.setAttribute(
'src',
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CjxjaXJjbGUgb3BhY2l0eT0nMC4yNScgY3g9IjEyIiBjeT0iMTIiIHI9IjEwIiBzdHJva2U9IiNGRkZGRkYiIHN0cm9rZS13aWR0aD0iNCI+PC9jaXJjbGU+CjxwYXRoIG9wYWNpdHk9JzAuNzUnIGZpbGw9IiNGRkZGRkYiIGQ9Ik00IDEyYTggOCAwIDAxOC04VjBDNS4zNzMgMCAwIDUuMzczIDAgMTJoNHptMiA1LjI5MUE3Ljk2MiA3Ljk2MiAwIDAxNCAxMkgwYzAgMy4wNDIgMS4xMzUgNS44MjQgMyA3LjkzOGwzLTIuNjQ3eiI+PC9wYXRoPgo8L3N2Zz4='
);
try {
loader.animate(
[{ transform: 'rotate(0deg)' }, { transform: 'rotate(359deg)' }],
{
duration: 3000,
iterations: Infinity,
}
);
} catch {
logger.warn('Animation not supported, loader will be fixed.');
}
loaderContainer.appendChild(loader);
if (
domElementContainer.children &&
domElementContainer.children.length > 0
) {
domElementContainer.insertBefore(
loaderContainer,
domElementContainer.children[0]
);
} else {
domElementContainer.appendChild(loaderContainer);
}
} else {
const loaderContainer = domElementContainer.querySelector(
`#${loaderContainerId}`
);
if (!loaderContainer) return;
try {
domElementContainer.removeChild(loaderContainer);
} catch {}
}
};
/**
* Creates a DOM element that will contain the loader or a message if the game is not registered,
* and adds it to the dom container.
@@ -562,8 +623,8 @@ namespace gdjs {
type === 'success'
? '#0E062D'
: type === 'warning'
? '#FFA500'
: '#FF0000';
? '#FFA500'
: '#FF0000';
// Space the notifications vertically, based on how many there are.
divContainer.style.top = `${12 + notificationContainerIds.length * 32}px`;
divContainer.style.right = '16px';

View File

@@ -130,7 +130,8 @@ namespace gdjs {
}
private _hasObjectBeenSyncedWithinMaxRate() {
const objectMaxSyncRate = gdjs.multiplayer.getObjectsSynchronizationRate();
const objectMaxSyncRate =
gdjs.multiplayer.getObjectsSynchronizationRate();
return (
getTimeNow() - this._lastObjectSyncTimestamp < 1000 / objectMaxSyncRate
);
@@ -287,8 +288,8 @@ namespace gdjs {
// )}`
// );
const areBasicObjectNetworkSyncDataDifferent = this._isBasicObjectNetworkSyncDataDifferentFromLastSync(
{
const areBasicObjectNetworkSyncDataDifferent =
this._isBasicObjectNetworkSyncDataDifferentFromLastSync({
x: objectNetworkSyncData.x,
y: objectNetworkSyncData.y,
z: objectNetworkSyncData.z,
@@ -299,8 +300,7 @@ namespace gdjs {
if: objectNetworkSyncData.if,
pfx: objectNetworkSyncData.pfx,
pfy: objectNetworkSyncData.pfy,
}
);
});
const shouldSyncObjectBasicInfo =
!this._hasObjectBasicInfoBeenSyncedRecently() ||
areBasicObjectNetworkSyncDataDifferent ||
@@ -348,16 +348,14 @@ namespace gdjs {
return;
}
const {
messageName: updateMessageName,
messageData: updateMessageData,
} = gdjs.multiplayerMessageManager.createUpdateInstanceMessage({
objectOwner: this.playerNumber,
objectName,
instanceNetworkId,
objectNetworkSyncData,
sceneNetworkId,
});
const { messageName: updateMessageName, messageData: updateMessageData } =
gdjs.multiplayerMessageManager.createUpdateInstanceMessage({
objectOwner: this.playerNumber,
objectName,
instanceNetworkId,
objectNetworkSyncData,
sceneNetworkId,
});
this._sendDataToPeersWithIncreasedClock(
updateMessageName,
updateMessageData
@@ -440,16 +438,14 @@ namespace gdjs {
}
// Ensure we send a final update before the object is destroyed, if it had a networkId.
const {
messageName: updateMessageName,
messageData: updateMessageData,
} = gdjs.multiplayerMessageManager.createUpdateInstanceMessage({
objectOwner: this.playerNumber,
objectName,
instanceNetworkId,
objectNetworkSyncData: this.owner.getNetworkSyncData(),
sceneNetworkId,
});
const { messageName: updateMessageName, messageData: updateMessageData } =
gdjs.multiplayerMessageManager.createUpdateInstanceMessage({
objectOwner: this.playerNumber,
objectName,
instanceNetworkId,
objectNetworkSyncData: this.owner.getNetworkSyncData(),
sceneNetworkId,
});
this._sendDataToPeersWithIncreasedClock(
updateMessageName,
updateMessageData
@@ -470,9 +466,10 @@ namespace gdjs {
instanceNetworkId,
sceneNetworkId,
});
const destroyedMessageName = gdjs.multiplayerMessageManager.createInstanceDestroyedMessageNameFromDestroyInstanceMessage(
destroyMessageName
);
const destroyedMessageName =
gdjs.multiplayerMessageManager.createInstanceDestroyedMessageNameFromDestroyInstanceMessage(
destroyMessageName
);
gdjs.multiplayerMessageManager.addExpectedMessageAcknowledgement({
originalMessageName: destroyMessageName,
originalData: {
@@ -552,18 +549,16 @@ namespace gdjs {
// When changing the ownership of an object with a networkId, we send a message to the host to ensure it is aware of the change,
// and can either accept it and broadcast it to other players, or reject it and do nothing with it.
// We expect an acknowledgment from the host, if not, we will retry and eventually revert the ownership.
const {
messageName,
messageData,
} = gdjs.multiplayerMessageManager.createChangeInstanceOwnerMessage({
objectOwner: previousObjectPlayerNumber,
objectName,
instanceNetworkId,
newObjectOwner: newObjectPlayerNumber,
instanceX: this.owner.getX(),
instanceY: this.owner.getY(),
sceneNetworkId,
});
const { messageName, messageData } =
gdjs.multiplayerMessageManager.createChangeInstanceOwnerMessage({
objectOwner: previousObjectPlayerNumber,
objectName,
instanceNetworkId,
newObjectOwner: newObjectPlayerNumber,
instanceX: this.owner.getX(),
instanceY: this.owner.getY(),
sceneNetworkId,
});
// Before sending the changeOwner message, if we are becoming the new owner,
// we want to ensure this message is acknowledged, by everyone we're connected to.
// If we are the host, we are connected to everyone, so we expect an acknowledgment from everyone.
@@ -571,9 +566,10 @@ namespace gdjs {
// In both cases, this represents the list of peers the current user is connected to.
if (newObjectPlayerNumber === currentPlayerNumber) {
const otherPeerIds = gdjs.multiplayerPeerJsHelper.getAllPeers();
const changeOwnerAcknowledgedMessageName = gdjs.multiplayerMessageManager.createInstanceOwnerChangedMessageNameFromChangeInstanceOwnerMessage(
messageName
);
const changeOwnerAcknowledgedMessageName =
gdjs.multiplayerMessageManager.createInstanceOwnerChangedMessageNameFromChangeInstanceOwnerMessage(
messageName
);
gdjs.multiplayerMessageManager.addExpectedMessageAcknowledgement({
originalMessageName: messageName,
originalData: {
@@ -583,7 +579,8 @@ namespace gdjs {
expectedMessageName: changeOwnerAcknowledgedMessageName,
otherPeerIds,
// If we are not the host, we should revert the ownership if the host does not acknowledge the change.
shouldCancelMessageIfTimesOut: !gdjs.multiplayer.isCurrentPlayerHost(),
shouldCancelMessageIfTimesOut:
!gdjs.multiplayer.isCurrentPlayerHost(),
});
}

View File

@@ -17,6 +17,17 @@ namespace gdjs {
}[];
};
type Lobby = {
id: string;
status: 'waiting' | 'starting' | 'playing' | 'migrating' | 'migrated';
};
type QuickJoinLobbyResponse =
| { status: 'join-game'; lobby: Lobby }
| { status: 'join-lobby'; lobby: Lobby }
| { status: 'not-enough-players' }
| { status: 'full' };
const getTimeNow =
window.performance && typeof window.performance.now === 'function'
? window.performance.now.bind(window.performance)
@@ -90,6 +101,12 @@ namespace gdjs {
let _hasLobbyGameJustStarted = false;
export let _isLobbyGameRunning = false;
let _hasLobbyGameJustEnded = false;
let _quickJoinLobbyJustFailed = false;
let _quickJoinLobbyFailureReason:
| 'FULL'
| 'NOT_ENOUGH_PLAYERS'
| 'UNKNOWN'
| null = null;
let _lobbyId: string | null = null;
let _connectionId: string | null = null;
@@ -98,6 +115,13 @@ namespace gdjs {
let _lobbyChangeHostRequestInitiatedAt: number | null = null;
let _isChangingHost = false;
let _lobbyNewHostPickedAt: number | null = null;
let _actionAfterJoiningLobby:
| 'OPEN_LOBBY_PAGE'
| 'JOIN_GAME'
| 'START_GAME'
| null = null;
let _isQuickJoiningOrStartingAGame = false;
let _lastQuickJoinRequestDoneAt: number | null = null;
// Communication methods.
let _lobbiesMessageCallback: ((event: MessageEvent) => void) | null = null;
@@ -206,6 +230,7 @@ namespace gdjs {
_hasLobbyGameJustStarted = false;
_hasLobbyGameJustEnded = false;
_quickJoinLobbyJustFailed = false;
});
const getLobbiesWindowUrl = ({
@@ -253,6 +278,11 @@ namespace gdjs {
if (playerToken) {
url.searchParams.set('playerToken', playerToken);
}
const platformInfo = runtimeGame.getPlatformInfo();
url.searchParams.set(
'scm',
platformInfo.supportedCompressionMethods.join(',')
);
// Increment this value when a new feature is introduced so we can
// adapt the interface of the lobbies.
url.searchParams.set('multiplayerVersion', '2');
@@ -362,7 +392,8 @@ namespace gdjs {
};
const handleLeavingPlayer = (runtimeScene: gdjs.RuntimeScene) => {
const lastestPlayerWhoJustLeft = gdjs.multiplayerMessageManager.getLatestPlayerWhoJustLeft();
const lastestPlayerWhoJustLeft =
gdjs.multiplayerMessageManager.getLatestPlayerWhoJustLeft();
if (lastestPlayerWhoJustLeft) {
const playerUsername = getPlayerUsername(lastestPlayerWhoJustLeft);
gdjs.multiplayerComponents.displayPlayerLeftNotification(
@@ -386,7 +417,8 @@ namespace gdjs {
};
const handleJoiningPlayer = (runtimeScene: gdjs.RuntimeScene) => {
const lastestPlayerWhoJustJoined = gdjs.multiplayerMessageManager.getLatestPlayerWhoJustJoined();
const lastestPlayerWhoJustJoined =
gdjs.multiplayerMessageManager.getLatestPlayerWhoJustJoined();
if (lastestPlayerWhoJustJoined) {
const playerUsername = getPlayerUsername(lastestPlayerWhoJustJoined);
gdjs.multiplayerComponents.displayPlayerJoinedNotification(
@@ -592,8 +624,16 @@ namespace gdjs {
logger.error('Malformed message received');
return;
}
handlePeerIdEvent({ peerId, compressionMethod });
const retryData = { times: 2, delayInMs: 500 };
try {
gdjs.evtTools.network.retryIfFailed(retryData, async () => {
handlePeerIdEvent({ peerId, compressionMethod });
});
} catch (error) {
logger.error(
`Handling peerId message from websocket failed (after {${retryData.times}} times with a delay of ${retryData.delayInMs}ms). Not trying anymore.`
);
}
break;
}
}
@@ -616,9 +656,8 @@ namespace gdjs {
return;
}
const lobbiesIframe = gdjs.multiplayerComponents.getLobbiesIframe(
runtimeScene
);
const lobbiesIframe =
gdjs.multiplayerComponents.getLobbiesIframe(runtimeScene);
if (!lobbiesIframe || !lobbiesIframe.contentWindow) {
return;
@@ -634,6 +673,17 @@ namespace gdjs {
};
};
const onPeerUnavailable = (runtimeScene: gdjs.RuntimeScene) => {
gdjs.multiplayerComponents.displayConnectionErrorNotification(
runtimeScene
);
handleLeaveLobbyEvent();
_actionAfterJoiningLobby = null;
_quickJoinLobbyFailureReason = null;
if (_isQuickJoiningOrStartingAGame)
onLobbyQuickJoinFinished(runtimeScene);
};
const handleConnectionIdReceived = function ({
runtimeScene,
connectionId,
@@ -679,10 +729,13 @@ namespace gdjs {
brokerServerConfig.port,
brokerServerConfig.path,
brokerServerConfig.key,
brokerServerConfig.secure
brokerServerConfig.secure,
{ onPeerUnavailable: () => onPeerUnavailable(runtimeScene) }
);
} else {
gdjs.multiplayerPeerJsHelper.useDefaultBrokerServer();
gdjs.multiplayerPeerJsHelper.useDefaultBrokerServer({
onPeerUnavailable: () => onPeerUnavailable(runtimeScene),
});
}
_connectionId = connectionId;
@@ -690,10 +743,31 @@ namespace gdjs {
// We save the lobbyId here as this is the moment when the player is really connected to the lobby.
_lobbyId = lobbyId;
if (_actionAfterJoiningLobby === 'OPEN_LOBBY_PAGE') {
openLobbiesWindow(runtimeScene);
onLobbyQuickJoinFinished(runtimeScene);
return;
} else if (_actionAfterJoiningLobby === 'JOIN_GAME') {
handleJoinGameMessage();
return;
} else if (_actionAfterJoiningLobby === 'START_GAME') {
const retryData = { times: 2, delayInMs: 500 };
try {
gdjs.evtTools.network.retryIfFailed(retryData, async () => {
sendPeerId();
handleStartGameMessage();
});
} catch (error) {
logger.error(
`Sending of peerId message from websocket failed (after {${retryData.times}} times with a delay of ${retryData.delayInMs}ms). Not trying anymore.`
);
}
return;
}
// Then we inform the lobbies window that the player has joined.
const lobbiesIframe = gdjs.multiplayerComponents.getLobbiesIframe(
runtimeScene
);
const lobbiesIframe =
gdjs.multiplayerComponents.getLobbiesIframe(runtimeScene);
if (!lobbiesIframe || !lobbiesIframe.contentWindow) {
logger.error(
@@ -742,9 +816,8 @@ namespace gdjs {
// If the player is in the lobby, tell the lobbies window that the lobby has been updated,
// as well as the player position.
const lobbiesIframe = gdjs.multiplayerComponents.getLobbiesIframe(
runtimeScene
);
const lobbiesIframe =
gdjs.multiplayerComponents.getLobbiesIframe(runtimeScene);
if (!lobbiesIframe || !lobbiesIframe.contentWindow) {
return;
@@ -776,9 +849,8 @@ namespace gdjs {
}
// Just pass along the message to the iframe so that it can display the countdown.
const lobbiesIframe = gdjs.multiplayerComponents.getLobbiesIframe(
runtimeScene
);
const lobbiesIframe =
gdjs.multiplayerComponents.getLobbiesIframe(runtimeScene);
if (!lobbiesIframe || !lobbiesIframe.contentWindow) {
logger.info('The lobbies iframe is not opened, not sending message.');
@@ -818,6 +890,8 @@ namespace gdjs {
}),
dev: isUsingGDevelopDevelopmentEnvironment,
});
// TODO: if 404, there's chance that it means the lobby is now closed. Display a message
// to the player?
} catch (error) {
logger.error('Error while sending heartbeat, retrying:', error);
try {
@@ -873,6 +947,8 @@ namespace gdjs {
logger.info('Lobby game has started.');
// In case we're joining an existing lobby, read the saved messages to catch-up with the game state.
gdjs.multiplayerMessageManager.handleSavedUpdateMessages(runtimeScene);
if (_isQuickJoiningOrStartingAGame)
onLobbyQuickJoinFinished(runtimeScene);
_isReadyToSendOrReceiveGameUpdateMessages = true;
_hasLobbyGameJustStarted = true;
_isLobbyGameRunning = true;
@@ -926,7 +1002,7 @@ namespace gdjs {
logger.error(
'No peerId found, the player does not seem connected to the broker server.'
);
return;
throw new Error('Missing player peerId.');
}
if (currentPeerId === peerId) {
@@ -990,10 +1066,15 @@ namespace gdjs {
const handleJoinGameMessage = function () {
if (!_websocket) {
logger.error(
'No connection to send the start countdown message. Are you connected to a lobby?'
'No connection to send the join game message. Are you connected to a lobby?'
);
return;
}
// TODO: When the message is sent, it is expected to then receive a "peerId" message
// from the websocket. This "peerId" message might not be sent for different reasons.
// Should there be a security that checks if the "peerId" message has been received
// in the next 10s or something more global that checks the lobby status after the player
// has committed to open a connection with it?
_websocket.send(
JSON.stringify({
@@ -1199,13 +1280,15 @@ namespace gdjs {
);
// First look for players who left during the migration.
const playerNumbersConnectedBeforeMigration = gdjs.multiplayerMessageManager
.getConnectedPlayers()
.map((player) => player.playerNumber);
const playerNumbersWhoLeftDuringMigration = playerNumbersConnectedBeforeMigration.filter(
(playerNumberBeforeMigration) =>
!expectedNewOtherPlayerNumbers.includes(playerNumberBeforeMigration)
);
const playerNumbersConnectedBeforeMigration =
gdjs.multiplayerMessageManager
.getConnectedPlayers()
.map((player) => player.playerNumber);
const playerNumbersWhoLeftDuringMigration =
playerNumbersConnectedBeforeMigration.filter(
(playerNumberBeforeMigration) =>
!expectedNewOtherPlayerNumbers.includes(playerNumberBeforeMigration)
);
playerNumbersWhoLeftDuringMigration.map((playerNumberWhoLeft) => {
logger.info(
`Player ${playerNumberWhoLeft} left during the host migration. Marking as disconnected.`
@@ -1217,13 +1300,14 @@ namespace gdjs {
});
// Then check if all expected players are connected.
const playerNumbersWhoDidNotConnect = expectedNewOtherPlayerNumbers.filter(
(otherPlayerNumber) =>
otherPlayerNumber !== playerNumber && // We don't look for ourselves
!gdjs.multiplayerMessageManager.hasReceivedHeartbeatFromPlayer(
otherPlayerNumber
)
);
const playerNumbersWhoDidNotConnect =
expectedNewOtherPlayerNumbers.filter(
(otherPlayerNumber) =>
otherPlayerNumber !== playerNumber && // We don't look for ourselves
!gdjs.multiplayerMessageManager.hasReceivedHeartbeatFromPlayer(
otherPlayerNumber
)
);
if (playerNumbersWhoDidNotConnect.length === 0) {
logger.info('All expected players are connected. Resuming the game.');
@@ -1388,7 +1472,7 @@ namespace gdjs {
logger.error(
"No peerId found, the player doesn't seem connected to the broker server."
);
return;
throw new Error('Missing player peerId.');
}
_websocket.send(
@@ -1433,7 +1517,7 @@ namespace gdjs {
if (!event.data.lobbyId) {
throw new Error('Malformed message.');
}
_actionAfterJoiningLobby = null;
handleJoinLobbyEvent(runtimeScene, event.data.lobbyId);
break;
}
@@ -1469,9 +1553,8 @@ namespace gdjs {
};
const sendSessionInformation = (runtimeScene: gdjs.RuntimeScene) => {
const lobbiesIframe = gdjs.multiplayerComponents.getLobbiesIframe(
runtimeScene
);
const lobbiesIframe =
gdjs.multiplayerComponents.getLobbiesIframe(runtimeScene);
if (!lobbiesIframe || !lobbiesIframe.contentWindow) {
// Cannot send the message if the iframe is not opened.
return;
@@ -1519,6 +1602,159 @@ namespace gdjs {
);
};
const onLobbyQuickJoinFinished = (runtimeScene: gdjs.RuntimeScene) => {
_isQuickJoiningOrStartingAGame = false;
_actionAfterJoiningLobby = null;
gdjs.multiplayerComponents.displayLoader(runtimeScene, false);
};
const quickJoinLobby = async (
runtimeScene: gdjs.RuntimeScene,
displayLoader: boolean,
openLobbiesPageIfFailure: boolean
) => {
if (_isQuickJoiningOrStartingAGame) return;
const _gameId = gdjs.projectData.properties.projectUuid;
if (!_gameId) {
handleLobbiesError(
runtimeScene,
'The game ID is missing, the quick join lobby action cannot continue.'
);
return;
}
_quickJoinLobbyFailureReason = null;
_isQuickJoiningOrStartingAGame = true;
if (displayLoader) {
gdjs.multiplayerComponents.displayLoader(runtimeScene, true);
}
const quickJoinLobbyRelativeUrl = `/play/game/${_gameId}/public-lobby/action/quick-join`;
const platformInfo = runtimeScene.getGame().getPlatformInfo();
try {
const quickJoinLobbyResponse: QuickJoinLobbyResponse =
await gdjs.evtTools.network.retryIfFailed({ times: 2 }, () =>
fetchAsPlayer({
relativeUrl: quickJoinLobbyRelativeUrl,
method: 'POST',
dev: isUsingGDevelopDevelopmentEnvironment,
body: JSON.stringify({
isPreview: runtimeScene.getGame().isPreview(),
gameVersion: runtimeScene.getGame().getGameData().properties
.version,
supportedCompressionMethods:
platformInfo.supportedCompressionMethods,
}),
})
);
if (
quickJoinLobbyResponse.status === 'full' ||
quickJoinLobbyResponse.status === 'not-enough-players'
) {
_quickJoinLobbyJustFailed = true;
_quickJoinLobbyFailureReason =
quickJoinLobbyResponse.status === 'full'
? 'FULL'
: 'NOT_ENOUGH_PLAYERS';
onLobbyQuickJoinFinished(runtimeScene);
if (openLobbiesPageIfFailure) {
openLobbiesWindow(runtimeScene);
}
return;
}
if (quickJoinLobbyResponse.status === 'join-game') {
if (quickJoinLobbyResponse.lobby.status === 'waiting') {
_actionAfterJoiningLobby = 'START_GAME';
} else if (quickJoinLobbyResponse.lobby.status === 'playing') {
_actionAfterJoiningLobby = 'JOIN_GAME';
} else {
throw new Error(
`Lobby in wrong status: ${quickJoinLobbyResponse.status}`
);
}
} else {
if (_connectionId) {
// Already connected to a lobby.
onLobbyQuickJoinFinished(runtimeScene);
openLobbiesWindow(runtimeScene);
return;
} else {
_actionAfterJoiningLobby = 'OPEN_LOBBY_PAGE';
}
}
handleJoinLobbyEvent(runtimeScene, quickJoinLobbyResponse.lobby.id);
} catch (error) {
logger.error('An error occurred while joining a lobby:', error);
_quickJoinLobbyJustFailed = true;
_quickJoinLobbyFailureReason = 'UNKNOWN';
onLobbyQuickJoinFinished(runtimeScene);
if (openLobbiesPageIfFailure) {
openLobbiesWindow(runtimeScene);
}
}
};
export const authenticateAndQuickJoinLobby = async (
runtimeScene: gdjs.RuntimeScene,
displayLoader: boolean,
openLobbiesPageIfFailure: boolean
) => {
const requestDoneAt = Date.now();
if (_lastQuickJoinRequestDoneAt) {
if (requestDoneAt - _lastQuickJoinRequestDoneAt < 500) {
_lastQuickJoinRequestDoneAt = requestDoneAt;
logger.warn(
'Last request to quick join a lobby was sent too little time ago. Ignoring this one.'
);
return;
}
} else {
_lastQuickJoinRequestDoneAt = requestDoneAt;
}
const playerId = gdjs.playerAuthentication.getUserId();
const playerToken = gdjs.playerAuthentication.getUserToken();
if (!playerId || !playerToken) {
_isWaitingForLogin = true;
const { status } =
await gdjs.playerAuthentication.openAuthenticationWindow(runtimeScene)
.promise;
_isWaitingForLogin = false;
if (status === 'logged') {
await quickJoinLobby(
runtimeScene,
displayLoader,
openLobbiesPageIfFailure
);
}
return;
}
await quickJoinLobby(
runtimeScene,
displayLoader,
openLobbiesPageIfFailure
);
};
export const isSearchingForLobbyToJoin = (
runtimeScene: gdjs.RuntimeScene
) => {
return _isQuickJoiningOrStartingAGame;
};
export const hasQuickJoinJustFailed = (runtimeScene: gdjs.RuntimeScene) => {
return _quickJoinLobbyJustFailed;
};
export const getQuickJoinFailureReason = () => {
return _quickJoinLobbyFailureReason;
};
/**
* Action to display the lobbies window to the user.
*/
@@ -1567,11 +1803,9 @@ namespace gdjs {
const playerToken = gdjs.playerAuthentication.getUserToken();
if (!playerId || !playerToken) {
_isWaitingForLogin = true;
const {
status,
} = await gdjs.playerAuthentication.openAuthenticationWindow(
runtimeScene
).promise;
const { status } =
await gdjs.playerAuthentication.openAuthenticationWindow(runtimeScene)
.promise;
_isWaitingForLogin = false;
if (status === 'logged') {
@@ -1640,9 +1874,8 @@ namespace gdjs {
export const isLobbiesWindowOpen = function (
runtimeScene: gdjs.RuntimeScene
): boolean {
const lobbiesRootContainer = gdjs.multiplayerComponents.getLobbiesRootContainer(
runtimeScene
);
const lobbiesRootContainer =
gdjs.multiplayerComponents.getLobbiesRootContainer(runtimeScene);
return !!lobbiesRootContainer;
};

View File

@@ -11,6 +11,10 @@ namespace gdjs {
data: Uint8Array | string;
};
type PeerJSInitOptions = {
onPeerUnavailable?: () => void;
};
export type CompressionMethod = 'none' | 'cs:gzip' | 'cs:deflate';
/**
@@ -100,6 +104,8 @@ namespace gdjs {
*/
let ready = false;
let _peerIdToConnectToOnceReady: string | null = null;
/**
* List of IDs of peers that just disconnected.
*/
@@ -228,6 +234,14 @@ namespace gdjs {
return newMessagesList;
};
const _onReady = () => {
ready = true;
if (_peerIdToConnectToOnceReady) {
connect(_peerIdToConnectToOnceReady);
_peerIdToConnectToOnceReady = null;
}
};
/**
* Internal function called when a connection with a remote peer is initiated.
* @param connection The DataConnection of the peer
@@ -289,14 +303,28 @@ namespace gdjs {
* Internal function called to initialize PeerJS after it
* has been configured.
*/
const loadPeerJS = () => {
const initializePeerJS = (initOptions: PeerJSInitOptions = {}) => {
if (peer !== null) return;
peer = new Peer(peerConfig);
peer.on('open', () => {
ready = true;
_onReady();
});
peer.on('error', (errorMessage) => {
logger.error('PeerJS error:', errorMessage);
peer.on('error', (error) => {
// TODO: Support other error types listed in https://peerjs.com/docs/#peeron-error
if (
initOptions.onPeerUnavailable &&
// @ts-ignore - PeerJS adds `type` on errors, but it doesn't show in their TS types.
error.type === 'peer-unavailable'
) {
logger.error('Peer is unavailable.');
initOptions.onPeerUnavailable();
} else {
logger.error(
// @ts-ignore - PeerJS adds `type` on errors, but it doesn't show in their TS types.
`PeerJS error (${error.type || 'unknown'}):`,
error
);
}
});
peer.on('connection', (connection) => {
connection.on('open', () => {
@@ -306,17 +334,21 @@ namespace gdjs {
});
peer.on('close', () => {
peer = null;
loadPeerJS();
initializePeerJS(initOptions);
});
peer.on('disconnected', peer.reconnect);
};
export const useDefaultBrokerServer = initializePeerJS;
/**
* Connects to another p2p client.
* @param id - The other client's ID.
*/
export const connect = (id: string) => {
if (peer === null) return;
if (peer === null || !ready) {
_peerIdToConnectToOnceReady = id;
return;
}
const connection = peer.connect(id);
connection.on('open', () => {
_onConnect(connection);
@@ -365,13 +397,15 @@ namespace gdjs {
* @param path The path (part of the url after the host) to the broker server.
* @param key Optional password to connect to the broker server.
* @param ssl Use ssl?
* @param peerJSInitOptions @see PeerJSInitOptions
*/
export const useCustomBrokerServer = (
host: string,
port: number,
path: string,
key: string,
ssl: boolean
ssl: boolean,
peerJSInitOptions: PeerJSInitOptions = {}
) => {
Object.assign(peerConfig, {
host,
@@ -381,11 +415,9 @@ namespace gdjs {
// All servers have "peerjs" as default key
key: key.length === 0 ? 'peerjs' : key,
});
loadPeerJS();
initializePeerJS(peerJSInitOptions);
};
export const useDefaultBrokerServer = loadPeerJS;
/**
* Adds an ICE server candidate, and removes the default ones provided by PeerJs. Must be called before connecting to a broker.
* @param urls The URL of the STUN/TURN server.
@@ -422,8 +454,8 @@ namespace gdjs {
* @see Peer.id
*/
export const getCurrentId = (): string => {
if (peer == undefined) return '';
return peer.id || '';
if (peer === null) return '';
return peer.id;
};
/**

View File

@@ -4,7 +4,7 @@
*/
declare class EventEmitter<
EventTypes extends EventEmitter.ValidEventTypes = string | symbol,
Context extends any = any
Context extends any = any,
> {
static prefixed: string | boolean;
@@ -87,7 +87,7 @@ declare namespace EventEmitter {
export interface EventEmitterStatic {
new <
EventTypes extends ValidEventTypes = string | symbol,
Context = any
Context = any,
>(): EventEmitter<EventTypes, Context>;
}
@@ -110,13 +110,13 @@ declare namespace EventEmitter {
[K in keyof T]: T[K] extends (...args: any[]) => void
? Parameters<T[K]>
: T[K] extends any[]
? T[K]
: any[];
? T[K]
: any[];
};
export type EventListener<
T extends ValidEventTypes,
K extends EventNames<T>
K extends EventNames<T>,
> = T extends string | symbol
? (...args: any[]) => void
: (
@@ -125,7 +125,7 @@ declare namespace EventEmitter {
export type EventArgs<
T extends ValidEventTypes,
K extends EventNames<T>
K extends EventNames<T>,
> = Parameters<EventListener<T, K>>;
export const EventEmitter: EventEmitterStatic;
@@ -170,9 +170,7 @@ declare namespace Peer {
validateId(id: string): boolean;
pack: any;
unpack: any;
chunk(
blob: Blob
): {
chunk(blob: Blob): {
__peerData: number;
n: number;
total: number;
@@ -267,7 +265,7 @@ declare namespace Peer {
};
abstract class BaseConnection<
T extends EventEmitter.ValidEventTypes,
TT
TT,
> extends EventEmitter<T & BaseConnectionEvents> {
readonly peer: string;
provider: Peer<TT>;

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