Compare commits

...

187 Commits

Author SHA1 Message Date
Florian Rival
98d0d5102e Bump newIDE version 2018-12-20 22:05:25 +00:00
Florian Rival
47818846e7 Fix Jfxr not opening 2018-12-20 21:56:27 +00:00
Florian Rival
8276eda243 Bump newIDE version 2018-12-20 17:51:36 +00:00
Todor Imreorov
ca2e00bd91 Add input for setting FPS for animation playback speed (#814) 2018-12-20 16:08:44 +00:00
Franco Maciel
6177b0197e Don't load AdMob ads if already loading/showing (#817) 2018-12-19 15:20:04 +00:00
Florian Rival
fb65b56cb7 Remove Submit Your Example button from web-app 2018-12-18 08:46:26 +00:00
Todor Imreorov
6f780f79e9 Add field to change time between frames to AnimationPreview (#811) 2018-12-18 08:44:29 +00:00
Florian Rival
d31f0793d5 Set default time between frames to 0.08 2018-12-18 08:14:20 +00:00
Todor Imreorov
88c88ad1eb Add menu item to remove all resources with invalid paths (#812) 2018-12-17 21:25:39 +00:00
Franco Maciel
4202e2672d Add actions to set Sprite size in pixels (#808) 2018-12-17 16:45:47 +00:00
Florian Rival
f29cc503bf Fix version number not properly applied to Android/Cordova builds
Fix #804
2018-12-16 13:58:26 +00:00
Florian Rival
1aa81949ce Fix AdMob extension not loaded in web-app 2018-12-16 12:56:30 +00:00
Florian Rival
4593f09131 Fix empty menu options shown in scene editor context menu 2018-12-16 12:49:47 +00:00
Florian Rival
782ea0e0af Fix right click in CodeEditor that could trigger the event context menu 2018-12-16 12:42:17 +00:00
Florian Rival
8e893e660b Add hint text on ObjectSelector 2018-12-16 12:28:51 +00:00
Florian Rival
384346c54e Fix horizontal scrollbar displayed in events + prettify EventsSheet.css 2018-12-16 12:25:04 +00:00
Florian Rival
df3920cce3 Fix link to help page for mouse action/conditions 2018-12-16 12:17:29 +00:00
Florian Rival
6e9ff4b682 Bump newIDE version 2018-12-11 21:26:07 +00:00
Todor Imreorov
df161c48fd Fix Piskel loading (#795)
Fix #792
2018-12-11 21:21:11 +00:00
Florian Rival
ee6a337e71 Bump the GDJS version used for web-app 2018-12-11 00:23:20 +00:00
Florian Rival
d5146a0c65 Bump newIDE version 2018-12-10 23:37:13 +00:00
Florian Rival
eae4683c4f Add plane-and-clouds and bouncing-ball-and-rope examples 2018-12-10 23:34:28 +00:00
Florian Rival
dec96a2f3a Add condition to check if Facebook Instant Games ads are supported 2018-12-10 23:22:44 +00:00
Florian Rival
9610eeb6e5 Add support for interstitial and reward video in Facebook Instant Games 2018-12-10 23:12:03 +00:00
Todor Imreorov
213cd0a8c7 Add options to locate/open/copy path of a resource in ResourcesList 2018-12-10 20:59:28 +00:00
Todor Imreorov
8a117c1813 Add support for Piskel layers (+scan/remove unused font/audio) (#731)
* Layers are stored as resource metadata (for single frame) or Direction metadata (for more than one frame). If metadata is detected, use it to load the frames with layers
* Add options to scan for fonts and remove unused audio and fonts.
2018-12-05 16:32:10 +00:00
Franco Maciel
73ff10bb1f Fix issue with draggable behavior when object is deleted while dragging (#779) 2018-12-01 15:40:39 +00:00
Franco Maciel
300efbbd5c Update forces pre-events, fixing issues like offsets in positioning (#776) 2018-11-30 19:18:30 +00:00
Florian Rival
2e240643a2 Make access to variables 50% faster 2018-11-28 23:12:07 +00:00
Florian Rival
aa16e90aac Fix potential memory corruption with JsCodeEvent (in GDevelop.js) 2018-11-28 22:15:58 +00:00
Florian Rival
137ffc2b84 Optimize and rename clearing to multiplier in gdjs.Force 2018-11-28 21:41:11 +00:00
Florian Rival
34b460e968 Fix typo 2018-11-28 21:41:11 +00:00
Florian Rival
30cb0bcfb3 Add forceMultiplier parameter type and add specific field for it in parameters 2018-11-28 21:41:11 +00:00
Florian Rival
1b7a667c79 Improve description of opacity and other actions/conditions 2018-11-25 19:55:20 +01:00
Florian Rival
9a4655eefc Improve conditions/actions to explain that opacity is in 0-255 range 2018-11-25 19:48:46 +01:00
Florian Rival
ca9a0d3d37 Prevent time between frames to be set too low or to 0 in SpriteEditor 2018-11-25 19:38:29 +01:00
Florian Rival
10d8d6c4a8 Make explicit when scene variables are being used in conditions/actions 2018-11-25 19:24:30 +01:00
Florian Rival
a7f4da8e40 Merge branch 'master' of github.com:4ian/GDevelop 2018-11-25 14:21:21 +01:00
Wend1go
40b3c688d1 Add 400% zoom option to scene editor (#768)
Ideal for pixelart games with 16x16px sprites
2018-11-25 14:15:52 +01:00
Florian Rival
fc340b9477 Add ColorExpressionField 2018-11-23 17:59:39 +00:00
Florian Rival
cc810b3e9f Fix empty icons in Cordova config.xml resulting in build failure 2018-11-21 22:25:06 +00:00
Florian Rival
7d165660a5 Fix rendering of ShapePainterRuntimeObject with absolute coordinates when far from camera
Fix #750
2018-11-21 00:31:37 +00:00
Florian Rival
8d35bbbfdf Update package-lock for electron-app 2018-11-19 23:47:28 +00:00
Florian Rival
8ebff3c15e Bump newIDE version 2018-11-19 23:41:03 +00:00
Florian Rival
a00fff9376 Upgrade to Electron 3.0.9 (#754) 2018-11-19 23:39:08 +00:00
Florian Rival
32f56f3366 Fix typo 2018-11-19 09:36:34 +00:00
Florian Rival
09eab9eb46 Fix ShapePainter hitboxes/aabb not updated when moved 2018-11-17 19:10:57 +00:00
Florian Rival
9fe379d073 Make games exported on Android fullscreen 2018-11-17 15:07:19 +00:00
Florian Rival
f21fbd9871 Fix typo 2018-11-15 10:52:22 +00:00
Oneoeigh
f38dfd1211 Improving wording in README.md (#743)
Slight changes to make it easier to understand
2018-11-14 00:30:10 +00:00
Florian Rival
eefc656d49 Add support for adding filter to icons on themes 2018-11-14 00:12:16 +00:00
Florian Rival
1490b34650 Update link to download libGD.js 2018-11-13 23:54:24 +00:00
Florian Rival
ff496c65a5 Merge pull request #742 from 4ian/feature/font-resource
Rework fonts loading
2018-11-13 23:33:18 +00:00
Florian Rival
e9a3e801f7 Update gdjs.FontManager to support files for Cocos2d-JS 2018-11-13 23:24:49 +00:00
Florian Rival
4f8401ab1a Update PixiResourcesLoader to handle font resource in editor 2018-11-13 22:45:38 +00:00
Florian Rival
871b01124f Refactor ResourcesInUseHelper and TextObject for exposing fonts 2018-11-13 22:13:40 +00:00
Florian Rival
45d2844d8b Add FontResource and rework loading to ensure all fonts are properly loaded
* Add FontManager to the game engine, used to load and get access to loaded fonts.
* Use fontfaceobserver library to detect when a font is loaded.
* Add FontResource as a resource, like AudioResource.
* Update the TextEditor to use a selector for fonts.
* Refactor ResourceSelector floating label text
2018-11-12 23:45:01 +00:00
Florian Rival
566517320d Increase benchmarks timeout to avoid timeout on CI 2018-11-11 22:08:34 +00:00
Florian Rival
15773bca85 Fix unserialization of metadata of Direction 2018-11-11 21:10:42 +00:00
Florian Rival
a48d7017ea Bump newIDE version 2018-11-08 22:15:09 +00:00
Florian Rival
7d1f52ded4 Fix tests broken since AdMobObject extension was removed 2018-11-05 18:58:32 +00:00
Florian Rival
569adc1500 Fix ReosurcesMergingHelper wrongly modifing extensions of files having filename conflicts during export 2018-11-05 18:52:23 +00:00
Florian Rival
e6eb193e8e Add Get/SetMetadata to Sprite's Direction 2018-11-05 16:36:54 +00:00
Florian Rival
b8c63dade1 Add jfxr-editor to the list of git ignored folder 2018-11-05 16:36:11 +00:00
Todor Imreorov
82f92d36f1 Replace Jsfx by Jfxr sound effects generator (#716)
Jfxr yields better results and has a better interface
2018-11-03 21:40:15 +00:00
Florian Rival
6b17c1febd Add new example for the AdMob extension 2018-10-31 23:45:10 +00:00
Florian Rival
95882d1289 Remove AdMobObject extension (replaced by AdMob extension) 2018-10-31 23:11:04 +00:00
Florian Rival
70340bba7f Fix typo and floating label 2018-10-31 22:05:55 +00:00
Florian Rival
c809be9a07 Fix cordova version for AdMob extension 2018-10-31 22:05:37 +00:00
Franco Maciel
cc7b0f524e Add a new AdMob extension (#702)
* Add AdMob application ID to the project
* Export AdMob application ID with Cordova
* Switch to cordova-plugin-admob-free
* Add banners and interstitials support
2018-10-31 00:08:43 +00:00
Florian Rival
a61784bb6c Add validation for function parameters names 2018-10-28 06:41:09 -07:00
Florian Rival
3f92fc2ee5 Add support for key and mouse parameters in functions 2018-10-28 06:41:09 -07:00
Florian Rival
a4c08305c7 Improve UI of function parameters 2018-10-28 06:41:09 -07:00
Florian Rival
067798ff2c Fix EventsSheet toolbar buttons when navigating between functions 2018-10-28 06:41:09 -07:00
Florian Rival
7a838fc8f9 Refactor GDJS benchmarks 2018-10-28 06:41:09 -07:00
Florian Rival
e669190ca2 Add commented lines that can be uncomment to display debug draw 2018-10-28 06:41:09 -07:00
Florian Rival
b84bb8630a Improve accuracy/performance of various computations and add benchmarks
Add tests for gdjs.Force
Add tests for gdjs.Layer
2018-10-28 06:41:09 -07:00
Florian Rival
fb849be246 Fix AABB computation for rotate objects
AABB was not properly computed for rotated objects or objects
with a non default center/origin. This could create issues while checking
collisions and for behaviors/logic relying on spatial hashing (platformer,
pathfinding).

* Add benchmark to compare the speed of the implementation for non rotated object
(simple/faster) and for rotated objects (always exact but 12-15% slower).
* Add a method to render AABB of objects to ease debugging.
* Also add a test game.
* Add tests for AABB
* Add tests for getHitboxes for gdjs.SpriteRuntimeObject
2018-10-28 06:41:09 -07:00
Florian Rival
382aa0f086 Bump newIDE version 2018-10-22 22:43:31 +01:00
Florian Rival
303873974c Improve grammar/wording/typos in SubscriptionDetails 2018-10-22 22:18:47 +01:00
Florian Rival
9f0ec46064 Fix GetArgumentAsString (and fix test game using it) 2018-10-22 22:03:32 +01:00
Wend1go
9b2fa5d080 Fix typos/grammer (#710) (#713)
Thanks to @ValiantCuriosity (See #710)
2018-10-22 21:38:57 +01:00
Florian Rival
93611d8642 Bump newIDE version 2018-10-21 21:29:29 +01:00
Florian Rival
a0f15817ca Ensure functions are shown in Project Manager when they are some (even if option deactivated in preferences) 2018-10-21 21:29:00 +01:00
Florian Rival
6323aefb6b Ensure user is asked to close the project and switch to use native dialog 2018-10-21 21:19:37 +01:00
Florian Rival
6bdc0f3961 Bump newIDE version 2018-10-21 19:10:25 +01:00
Florian Rival
905a459ea2 Handle proper generation of functions using functions (two passes extensions generation) 2018-10-21 19:10:05 +01:00
Florian Rival
eb67604ca6 Update information about examples 2018-10-21 16:14:48 +01:00
Florian Rival
63077c7cef Update examples for functions 2018-10-21 16:12:11 +01:00
Florian Rival
2fed5b9a8b Fix error reporting in import-XXX.js scripts 2018-10-21 15:49:55 +01:00
Florian Rival
88b4b3860b Fix jsfx not loading when electron app is built, due to ES modules loading restrictions with file protocol 2018-10-21 15:46:47 +01:00
Florian Rival
e295efac7f Fix issue where jsfx wasn't properly loaded 2018-10-21 12:35:19 +01:00
Florian Rival
c5554d05fd Fix import-jsfx-editor and add jsfx sources to .gitignore 2018-10-20 20:29:21 +01:00
Florian Rival
6a163a59ca Merge pull request #695 from blurymind/master
Add jsfx sound effects editor
2018-10-20 20:24:56 +01:00
Florian Rival
9f5b63bad9 Fix object creation in functions and add space-shooter-with-functions example 2018-10-20 18:29:36 +01:00
Florian Rival
35aa78ea35 Fix long action/condition words not breaking properly 2018-10-20 16:31:01 +01:00
Todor Imreorov
82442fe618 expose background color in modalWindow, add option to wait for dom...
...to load before showing the window
2018-10-19 19:01:11 +01:00
Florian Rival
9dabcbd1f1 Update Level Editor example for web-app 2018-10-18 23:32:49 +01:00
Florian Rival
7f0fce5f6d Update Level Editor example to use functions 2018-10-18 23:28:14 +01:00
Florian Rival
90baf3cdb5 Add support for events functions on the web-app (BrowserS3EventsFunctionWriter) 2018-10-18 23:19:41 +01:00
Florian Rival
cccbb0e61b Fix Flow in ProjectManager 2018-10-18 22:39:25 +01:00
Florian Rival
702f1b529f Make ProjectManager display if errors occurred in functions generation 2018-10-18 22:28:09 +01:00
Florian Rival
fcc9740a77 Improve typing and remove muiThemeable in ProjectManager 2018-10-18 21:30:02 +01:00
Florian Rival
094bdb60f6 Merge branch 'master' of github.com:4ian/GDevelop 2018-10-18 21:12:57 +01:00
Florian Rival
215044cafe Avoid potential non-stopping re-rendering of events with height 0 2018-10-18 21:12:10 +01:00
Todor Imreorov
4d0185de9d fix flow, apply review notes, cleanup
should pass flow test now
2018-10-18 18:01:41 +01:00
Florian Rival
557f1da2c1 Add 3 examples 2018-10-17 23:54:10 +01:00
Todor Imreorov
becddeab9f jsfx and path editor- get rid of global variable, use parameters
This commit minimizes the use of global variables in jsfx-main and the patheditor
2018-10-17 21:08:17 +01:00
Todor Imreorov
ec6628baba apply review notes wip 2018-10-16 20:22:08 +01:00
Florian Rival
3289285a37 Fix missing support for Escape key in GDJS 2018-10-15 21:15:20 +01:00
Todor Imreorov
c4047702ed tweak jsfx window
size, notes, ui
2018-10-15 19:27:29 +01:00
Todor Imreorov
3c21e33928 Refactor code to use new html5 src es-module option
- also further clean up code and apply @4ian's advice
- loading is now much more robust
- setting and getting metatags is much more robust now

more on the new es-modules option in browsers:
https://jakearchibald.com/2017/es-modules-in-browsers/
2018-10-15 19:05:45 +01:00
Todor Imreorov
25f5550666 more cleanup 2018-10-13 22:00:21 +01:00
Todor Imreorov
2b7caf5fac further cleanup 2018-10-13 21:49:49 +01:00
Todor Imreorov
29f7525290 clean up 2018-10-13 21:43:55 +01:00
Todor Imreorov
80aa1ebec8 Add jsfx sound effects editor, refactor some of piskel's code to
make it easier to reuse
2018-10-13 21:29:20 +01:00
Florian Rival
af7f13c0b8 Add Get/SetMetadata on gd::Resource 2018-10-11 23:39:48 +01:00
Florian Rival
4e71030103 Implement move/delete events functions and clean up various things 2018-10-09 23:06:19 +01:00
Florian Rival
b3b7f181fa Merge pull request #678 from 4ian/feature/events-function-extension
Events functions
2018-10-09 08:58:34 +01:00
Florian Rival
4138f5f4aa Fix compilation of EventStoreDialog 2018-10-09 01:00:00 +01:00
Florian Rival
f302989b9d Fix compilation for GDC++ Runtime 2018-10-09 00:54:12 +01:00
Florian Rival
0f7c2c43cf Fix tests 2018-10-09 00:47:56 +01:00
Florian Rival
04b37bebf7 Update TODO 2018-10-09 00:40:24 +01:00
Florian Rival
a12d999e7b Fix flow 2018-10-09 00:32:37 +01:00
Florian Rival
cad23ed67c Update libGD.js and clean a bunch of TODOs 2018-10-09 00:24:52 +01:00
Florian Rival
f059728fdb Add Help and allow to activate Events Functions from preferences
Move EventsFunction related files and add documentation too
2018-10-09 00:06:37 +01:00
Florian Rival
545676b1f2 Allow user to select types of objects for functions + update parameters design 2018-10-08 22:21:38 +01:00
Florian Rival
48d99457e5 Add refactoring of the project when renaming expression events function 2018-10-08 22:21:38 +01:00
Florian Rival
c2c961f1d4 Fix bad call to gd.Project.validateObjectName 2018-10-08 22:21:38 +01:00
Florian Rival
04131e1795 Remove useless console.log 2018-10-08 22:21:37 +01:00
Florian Rival
53a5dc1742 Add action to set function return value and expressions to get arguments
Also fix unselection of an event function in IDE
2018-10-08 22:21:37 +01:00
Florian Rival
a790be3c37 Fix TrueFalseField not formatting parameter value properly 2018-10-08 22:21:37 +01:00
Florian Rival
6772fecc2e Add test game for events functions 2018-10-08 22:21:37 +01:00
Florian Rival
3244cbd8ad Add refactoring of the project when renaming events function / extension 2018-10-08 22:21:37 +01:00
Florian Rival
066f2b0fea Unload Events Functions Extensions when closing a project 2018-10-08 22:21:37 +01:00
Florian Rival
f370b8b78b Add gdjs.objectsListsToArray and OptionsEditorDialog for EventsFunctionsExtensionEditor 2018-10-08 22:21:37 +01:00
Florian Rival
e24daa4dc3 [WIP] Allow to select event function type and improve editor 2018-10-08 22:21:37 +01:00
Florian Rival
f889c9fc0a [WIP] Add LocalEventsFunctionWriter for functions JS files generation and EventsFunctionConfigurationEditor 2018-10-08 22:21:36 +01:00
Florian Rival
cdc374df9c Use UI/Background instead of material-ui's Paper component 2018-10-08 22:21:36 +01:00
Florian Rival
d60efd2394 [WIP] Add search in EventsFunctionsList 2018-10-08 22:21:36 +01:00
Florian Rival
d448ffb8f2 [WIP] Add EventsFunctionsExtensionEditor 2018-10-08 22:21:36 +01:00
Florian Rival
eb31be67ed [WIP] Adding EventsFunctionsExtensions support to newIDE 2018-10-08 22:21:36 +01:00
Florian Rival
23b4e2c026 Add EventsFunction and EventsFunctionsExtension 2018-10-08 22:21:36 +01:00
Florian Rival
1381ead3b4 [WIP] Add typing to EventsTree 2018-10-08 22:21:35 +01:00
Florian Rival
5377708093 [WIP] Make InstructionEditor and EventsSheet use gd.ObjectsContainer 2018-10-08 22:21:35 +01:00
Florian Rival
e7afebf722 [WIP] Make ObjectSelector and EventsSearcher use gd.ObjectsContainer 2018-10-08 22:21:35 +01:00
Florian Rival
7915d3ba59 [WIP] Make layout/project optional for ParameterFields and add flow typing 2018-10-08 22:21:35 +01:00
Todor Imreorov
c11cc80488 Add button to rotate the selected instances in InstancesEditor (SceneEditor) (#691) 2018-10-08 20:05:28 +01:00
Lizard-13
a33b421de4 Expose particles rotation speed option (#688) 2018-10-05 17:56:44 +01:00
Florian Rival
852d91b745 Update --feature-request.md 2018-10-03 13:09:52 +01:00
Todor Imreorov
df78d5e096 Add a command to invert conditions to the event sheet context menu (#686) 2018-10-03 00:16:15 +01:00
Florian Rival
7718132510 Add support for submenu in ContextMenu of web-app 2018-10-02 22:58:27 +01:00
Todor Imreorov
af00760d3e Add 'other' menu item to EventSheet's context menu (#684) 2018-10-02 22:12:02 +01:00
Todor Imreorov
c88c05f737 Add event, subevent and comment commands in EventsSheet's context menu (#681) 2018-09-30 18:51:10 -04:00
zachThePerson
e3b446cee0 Fix CopyRuntimeToGD.bat when using path with spaces (#673) 2018-09-28 07:42:00 -07:00
Florian Rival
721c31adc9 Simplify SceneEditor _onSelectInstances method 2018-09-28 07:39:46 -07:00
Todor Imreorov
e5c4580483 Fix selection of instances on hidden layers (#671)
Fix #661
2018-09-28 07:24:15 -07:00
Todor Imreorov
4c0d46ae2c Snap position of objects to the grid when inserted (#662) 2018-09-26 19:19:09 -07:00
Florian Rival
d05f2b9674 Add flow typing for SceneEditor and History 2018-09-23 11:13:22 -07:00
Lizard-13
566540133d Add word wrapping for Text Object (#658) 2018-09-23 11:45:18 +01:00
Todor Imreorov
45533cf163 Add "Add Instance of [...]" menu option in SceneEditor (#656) 2018-09-22 16:32:22 +01:00
Florian Rival
ad83d7d08f Merge pull request #654 from 4ian/optimization/avoid-update-project-manager-tabs
Avoid updates in project manager and tabs when they are not visible
2018-09-22 13:12:51 +01:00
Florian Rival
d755e10368 Fix Travis badge in README 2018-09-20 16:59:14 +01:00
Florian Rival
6543544dc1 Avoid updates in project manager and tabs when they are not visible 2018-09-20 00:30:24 +01:00
Florian Rival
6cd9e4b4d9 Merge pull request #650 from 4ian/feature/drop-instance-from-objects-list
* Add support for creating instances by dropping objects from objects list
* Update React to 16.5.1
* Use pointer events instead of mouse events when possible for better touch compatibility.
2018-09-19 23:39:18 +01:00
Florian Rival
b5b90cc838 Reduce distance before dragging list items 2018-09-19 00:06:03 +01:00
Florian Rival
c4be6f6522 Fix highlighted objects not cleared after deleting instances 2018-09-19 00:06:03 +01:00
Florian Rival
fd3698f590 Enable higlighting of a selection of multiple instances (=multiple objects) 2018-09-19 00:06:03 +01:00
Florian Rival
0fdbe19641 Improve compatibility with touch screen of CollisionMasksPreview and PointsPreview 2018-09-19 00:06:03 +01:00
Florian Rival
48e1d04fb6 Update react-dom to 16.5.1 2018-09-19 00:06:03 +01:00
Florian Rival
677478b4a2 Fix selection clearing not updating properties editor 2018-09-19 00:06:03 +01:00
Florian Rival
fc3826d472 Upgrade to React 16.5.1 2018-09-19 00:06:02 +01:00
Florian Rival
d135447e00 Remove dead code and fix typos 2018-09-19 00:06:02 +01:00
Todor Imreorov
856d7cdb46 Highlight the selected object when an instance is selected from the scene editor (#651) 2018-09-19 00:06:02 +01:00
Florian Rival
c2151149d4 Add support for creating instances by dropping objects from objects list 2018-09-19 00:06:02 +01:00
Florian Rival
9de604bd50 Fix action to open URL 2018-09-18 23:55:42 +01:00
Florian Rival
a4899cf030 Fix "Edit Object"/"Delete" options available even without selection 2018-09-16 23:56:29 +01:00
Florian Rival
483090dd32 Fix "Edit Object" in SceneEditor 2018-09-16 23:45:06 +01:00
Florian Rival
0e4304f3d7 Merge branch 'master' of github.com:4ian/GDevelop 2018-09-16 23:43:24 +01:00
Todor Imreorov
9050bfbc6f Add ''Edit Object" and "Delete" options to context menu (#648)
This will make it easier to edit the object of the selected instance in the instances editor, without having to find it in a long list of objects.
2018-09-16 17:35:17 +01:00
Todor Imreorov
32869c0588 Fix error in InstancesEditor (#646)
Fix #645
2018-09-16 11:38:58 +01:00
Florian Rival
f7f08f762d Rename ObjectGroupsList/ObjectGroupEditor to fix typo 2018-09-16 02:14:24 +01:00
Kenny
b19ffb93e0 Add "No Grid snap" keyboard Shortcut (#640)
When alt is pressed, objects can be moved without snapping to the grid.
2018-09-14 14:54:29 +01:00
Todor Imreorov
63a06a4bad Add options to scan for new image resources or remove unused images (#634)
Also add the use of relative paths to name imported/created resources.
2018-09-13 23:24:19 +01:00
Todor Imreorov
12efa6641c Improve cloneAndBuild batch script (#638)
Check if GDevelop electron-app is already built. If it is already built, the script will skip the "npm install" step and will start GDevelop much faster.
2018-09-13 22:08:47 +01:00
Wend1go
edfe915ae5 Add PanelSprite JavaScript function annotations (#637) 2018-09-12 14:19:05 +01:00
Wend1go
2e1509a16b Add DestroyOutsideBehavior JavaScript function annotations (#636) 2018-09-12 14:04:53 +01:00
571 changed files with 58658 additions and 3913 deletions

View File

@@ -1,7 +1,7 @@
---
name: "\U0001F4A1Feature request"
about: Suggest an idea for this project AFTER discussing about it on the Discord or
Forum first.
Forum first. We'll create a card for it on the roadmap.
---
@@ -10,6 +10,8 @@ BEFORE opening a new feature request, please make sure that you:
* There is not already a suggestion about it in the issues or in the roadmap: https://trello.com/b/qf0lM7k8/gdevelop-roadmap
* Consider commenting on the roadmap if something is important for you
AFTER opening the feature request, the issue will be closed by a maintainer (@4ian or someone else) and a card will be added in the roadmap if it's relevant and does not exist yet :)
## Description
Is your feature request **related to a problem**? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 951 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -370,8 +370,8 @@
<Unit filename="GDCore/IDE/Events/ExpressionsCorrectnessTesting.h" />
<Unit filename="GDCore/IDE/ExtensionsLoader.cpp" />
<Unit filename="GDCore/IDE/ExtensionsLoader.h" />
<Unit filename="GDCore/IDE/Project/ImagesUsedInventorizer.cpp" />
<Unit filename="GDCore/IDE/Project/ImagesUsedInventorizer.h" />
<Unit filename="GDCore/IDE/Project/ResourcesInUseHelper.cpp" />
<Unit filename="GDCore/IDE/Project/ResourcesInUseHelper.h" />
<Unit filename="GDCore/Extensions/Metadata/MetadataProvider.cpp" />
<Unit filename="GDCore/Extensions/Metadata/MetadataProvider.h" />
<Unit filename="GDCore/IDE/PlatformLoader.cpp" />

View File

@@ -643,6 +643,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
argOutput += (parameter == "yes" || parameter == "oui") ? GenerateTrue()
: GenerateFalse();
} else if (metadata.type == "trueorfalse") {
// This is duplicated in AdvancedExtension.cpp for GDJS
argOutput += (parameter == "True" || parameter == "Vrai") ? GenerateTrue()
: GenerateFalse();
}

View File

@@ -15,38 +15,18 @@
#include "GDCore/String.h"
namespace gd {
class EventsList;
}
namespace gd {
class MainFrameWrapper;
}
namespace gd {
class Project;
}
namespace gd {
class Layout;
}
namespace gd {
class EventsCodeGenerator;
}
namespace gd {
class EventsCodeGenerationContext;
}
namespace gd {
class Platform;
}
class wxWindow;
namespace gd {
class EventsEditorItemsAreas;
}
namespace gd {
class EventsEditorSelection;
}
namespace gd {
class SerializerElement;
}
namespace gd {
class Instruction;
}
class wxWindow;
class wxDC;
namespace gd {

View File

@@ -450,9 +450,7 @@ bool ExpressionParser::ParseMathExpression(const gd::Platform& platform,
parameters[i],
instructionInfos.parameters[i],
functionNameEnd))
return false; // TODO : Boarf, param<61>tres optionels sont rajout<75>s
// et <20>valu<6C>s : Probl<62>me avec les calques par
// exemple ( Au minimum, il faut "" )
return false;
}
} else {
firstErrorPos = functionNameEnd;

View File

@@ -32,6 +32,62 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
"res/conditions/toujours.png")
.AddCodeOnlyParameter("conditionInverted", "")
.MarkAsAdvanced();
extension
.AddAction(
"SetReturnNumber",
_("Set number return value"),
_("Set the return value of the events function to the specified "
"number (to be used with \"Expression\" functions)."),
_("Set return value to number _PARAM0_"),
_("Functions"),
"res/function24.png",
"res/function16.png")
.AddParameter("expression", "The number to be returned")
.MarkAsAdvanced();
extension
.AddAction(
"SetReturnString",
_("Set text return value"),
_("Set the return value of the events function to the specified text "
"(to be used with \"String Expression\" functions)."),
_("Set return value to text _PARAM0_"),
_("Functions"),
"res/function24.png",
"res/function16.png")
.AddParameter("expression", "The text to be returned")
.MarkAsAdvanced();
extension
.AddAction("SetReturnBoolean",
_("Set condition return value"),
_("Set the return value of the Condition events function to "
"either true (condition will pass) or false."),
_("Set return value of the condition to _PARAM0_"),
_("Functions"),
"res/function24.png",
"res/function16.png")
.AddParameter("trueorfalse", "Should the condition be true or false?")
.MarkAsAdvanced();
extension
.AddExpression(
"GetArgumentAsNumber",
_("Get function parameter value"),
_("Get function parameter (also called \"argument\") value"),
_("Functions"),
"res/function16.png")
.AddParameter("string", "Parameter name");
extension
.AddStrExpression(
"GetArgumentAsString",
_("Get function parameter text"),
_("Get function parameter (also called \"argument\") text "),
_("Functions"),
"res/function16.png")
.AddParameter("string", "Parameter name");
#endif
}

View File

@@ -257,7 +257,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
.AddAction("PlaySound",
_("Play a sound"),
_("Play a sound."),
_("Play the sound _PARAM1_, vol.: _PARAM3_, loop: _PARAM2_)"),
_("Play the sound _PARAM1_, vol.: _PARAM3_, loop: _PARAM2_"),
_("Audio"),
"res/actions/son24.png",
"res/actions/son.png")
@@ -276,7 +276,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
.AddAction("PlayMusic",
_("Play a music file"),
_("Play a music file."),
_("Play the music _PARAM1_, vol.: _PARAM3_, loop: _PARAM2_)"),
_("Play the music _PARAM1_, vol.: _PARAM3_, loop: _PARAM2_"),
_("Audio"),
"res/actions/music24.png",
"res/actions/music.png")

View File

@@ -180,7 +180,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Add a force"),
_("Add a force to an object. The object will move according to "
"all of the forces it has."),
_("Add to _PARAM0_ a force of _PARAM1_ p/s on X axis and "
_("Add to _PARAM0_ _PARAM3_ force of _PARAM1_ p/s on X axis and "
"_PARAM2_ p/s on Y axis"),
_("Movement"),
"res/actions/force24.png",
@@ -189,14 +189,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Speed on X axis (in pixels per second)"))
.AddParameter("expression", _("Speed on Y axis (in pixels per second)"))
.AddParameter("expression", _("Damping (Default: 0)"));
.AddParameter("forceMultiplier", _("Force multiplier"));
obj.AddAction("AddForceAL",
_("Add a force (angle)"),
_("Add a force to an object. The object will move according to "
"all of the forces it has. This action creates the force "
"using the specified angle and length."),
_("Add to _PARAM0_ a force, angle: _PARAM1_ degrees and "
_("Add to _PARAM0_ _PARAM3_ force, angle: _PARAM1_ degrees and "
"length: _PARAM2_ pixels"),
_("Movement"),
"res/actions/force24.png",
@@ -205,14 +205,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angle"))
.AddParameter("expression", _("Speed (in pixels per second)"))
.AddParameter("expression", _("Damping (Default: 0)"))
.AddParameter("forceMultiplier", _("Force multiplier"))
.MarkAsAdvanced();
obj.AddAction(
"AddForceVersPos",
_("Add a force to move toward a position"),
_("Add a force to an object to make it move toward a position."),
_("Move _PARAM0_ to _PARAM1_;_PARAM2_ with a force of _PARAM3_ "
_("Move _PARAM0_ to _PARAM1_;_PARAM2_ with _PARAM4_ force of _PARAM3_ "
"pixels"),
_("Movement"),
"res/actions/force24.png",
@@ -222,7 +222,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression", _("X position"))
.AddParameter("expression", _("Y position"))
.AddParameter("expression", _("Speed (in pixels per second)"))
.AddParameter("expression", _("Damping (Default: 0)"))
.AddParameter("forceMultiplier", _("Force multiplier"))
.MarkAsAdvanced();
obj.AddAction(
@@ -243,13 +243,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression", _("Y position of the center"))
.AddParameter("expression", _("Speed (in Degrees per seconds)"))
.AddParameter("expression", _("Distance (in pixels)"))
.AddParameter("expression", _("Damping (Default: 0)"))
.AddParameter("forceMultiplier", _("Force multiplier"))
.SetHidden();
obj.AddAction("Arreter",
_("Stop the object"),
_("Stop the object by deleting all of its forces."),
_("Stop the object _PARAM0_"),
_("Stop object _PARAM0_"),
_("Movement"),
"res/actions/arreter24.png",
"res/actions/arreter.png")
@@ -272,7 +272,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction("ChangePlan",
_("Z order"),
_("Modify the Z-order of an object"),
_("Do _PARAM1__PARAM2_ to z-Order of _PARAM0_"),
_("Do _PARAM1__PARAM2_ to Z-order of _PARAM0_"),
_("Z order"),
"res/actions/planicon24.png",
"res/actions/planicon.png")
@@ -554,7 +554,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction("AddForceVers",
_("Add a force to move toward an object"),
_("Add a force to an object to make it move toward another."),
_("Move _PARAM0_ to _PARAM1_ with a force of _PARAM2_ pixels"),
_("Move _PARAM0_ to _PARAM1_ with _PARAM3_ force of _PARAM2_ pixels"),
_("Movement"),
"res/actions/forceVers24.png",
"res/actions/forceVers.png")
@@ -562,7 +562,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectPtr", _("Target Object"))
.AddParameter("expression", _("Speed (in pixels per second)"))
.AddParameter("expression", _("Damping (Default: 0)"))
.AddParameter("forceMultiplier", _("Force multiplier"))
.MarkAsAdvanced();
obj.AddAction(
@@ -582,7 +582,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectPtr", _("Rotate around this object"))
.AddParameter("expression", _("Speed (in degrees per second)"))
.AddParameter("expression", _("Distance (in pixels)"))
.AddParameter("expression", _("Damping (Default: 0)"))
.AddParameter("forceMultiplier", _("Force multiplier"))
.MarkAsAdvanced();
obj.AddAction("MettreAutour",
@@ -878,7 +878,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Objects"),
"res/actions/create24.png",
"res/actions/create.png")
.AddCodeOnlyParameter("currentScene", "")
.AddCodeOnlyParameter("objectsContext", "")
.AddParameter("objectListWithoutPicking", _("Object to create"))
.AddParameter("expression", _("X position"))
.AddParameter("expression", _("Y position"))
@@ -896,7 +896,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Objects"),
"res/actions/create24.png",
"res/actions/create.png")
.AddCodeOnlyParameter("currentScene", "")
.AddCodeOnlyParameter("objectsContext", "")
.AddParameter(
"objectListWithoutPicking",
_("Groups containing objects that can be created by the action"))
@@ -916,7 +916,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Objects"),
"res/actions/add24.png",
"res/actions/add.png")
.AddCodeOnlyParameter("currentScene", "")
.AddCodeOnlyParameter("objectsContext", "")
.AddParameter("objectList", _("Object"))
.MarkAsAdvanced();

View File

@@ -174,6 +174,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
"res/actions/launchFile24.png",
"res/actions/launchFile.png")
.AddParameter("string", _("URL (or filename)"))
.AddCodeOnlyParameter("currentScene", "")
.MarkAsAdvanced();
extension

View File

@@ -18,7 +18,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
_("Built-in extension that enables the use of a mouse"),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/events/mouse-touch");
.SetExtensionHelpPath("/all-features/mouse-touch");
#if defined(GD_IDE_ONLY)
extension

View File

@@ -89,7 +89,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
.AddAction("Scene",
_("Change the scene"),
_("Stop this scene and start the specified one instead."),
_("Change for scene _PARAM1_"),
_("Change to scene _PARAM1_"),
_("Scene"),
"res/actions/replaceScene24.png",
"res/actions/replaceScene.png")

View File

@@ -15,7 +15,7 @@ using namespace std;
namespace gd {
Direction::Direction() : loop(false), timeBetweenFrame(1) {}
Direction::Direction() : loop(false), timeBetweenFrame(0.08) {}
Direction::~Direction(){};
@@ -75,6 +75,11 @@ void Direction::UnserializeFrom(const gd::SerializerElement& element) {
SetTimeBetweenFrames(
element.GetDoubleAttribute("timeBetweenFrames", 1, "tempsEntre"));
SetLoop(element.GetBoolAttribute("looping", false, "boucle"));
#if defined(GD_IDE_ONLY)
SetMetadata(element.HasAttribute("metadata") || element.HasChild("metadata")
? element.GetStringAttribute("metadata")
: "");
#endif
const gd::SerializerElement& spritesElement =
element.GetChild("sprites", 0, "Sprites");
@@ -182,6 +187,7 @@ void SaveSpritesDirection(const vector<Sprite>& sprites,
void Direction::SerializeTo(gd::SerializerElement& element) const {
element.SetAttribute("looping", IsLooping());
element.SetAttribute("timeBetweenFrames", GetTimeBetweenFrames());
if (!GetMetadata().empty()) element.SetAttribute("metadata", GetMetadata());
SaveSpritesDirection(sprites, element.AddChild("sprites"));
}
#endif

View File

@@ -6,17 +6,16 @@
#ifndef GDCORE_DIRECTION_H
#define GDCORE_DIRECTION_H
#include <vector>
#include "GDCore/String.h"
namespace gd {
class Sprite;
}
namespace gd {
class SerializerElement;
}
namespace gd {
/**
* \brief Class defining a direction of an Animation.
* \brief Class defining a direction (set of frames) of an Animation.
*
* \see SpriteObject
* \see Animation
@@ -32,78 +31,101 @@ class GD_CORE_API Direction {
virtual ~Direction();
/**
* Return true if sprites looping is activated
* \brief Return true if sprites looping is activated
*/
inline bool IsLooping() const { return loop; }
/**
* Set if the sprites must be looping or not.
* \brief Set if the sprites must be looping or not.
*/
void SetLoop(bool loop_);
/**
* Get the time between each sprite
* \brief Get the time between each sprite
*/
inline float GetTimeBetweenFrames() const { return timeBetweenFrame; }
/**
* Set the time between each sprite
* \brief Set the time between each sprite
*
* \param time Time between each sprite, in seconds.
*/
void SetTimeBetweenFrames(float time);
/**
* Return a reference to a sprite of the direction.
* \brief Return a reference to a sprite of the direction.
*
* \param nb The index of the sprite to be accessed. Bound checking is not
* made. \return A reference to the sprite.
* made.
*
* \return A reference to the sprite.
*/
const Sprite& GetSprite(std::size_t nb) const;
/**
* Return a reference to a sprite of the direction.
* \brief Return a reference to a sprite of the direction.
*
* \param nb The index of the sprite to be accessed. Bound checking is not
* made. \return A reference to the sprite.
* made.
*
* \return A reference to the sprite.
*/
Sprite& GetSprite(std::size_t nb);
/**
* Check if the direction contains sprites.
* \brief Check if the direction contains sprites.
*
* \return true if the direction does not have any sprite.
*/
bool HasNoSprites() const;
/**
* Return the number of sprite used in the direction
* \brief Return the number of sprite used in the direction
*
* \return The number of sprite used in the direction
*/
std::size_t GetSpritesCount() const;
/**
* Remove the sprite at the specified position.
* \brief Remove the sprite at the specified position.
*
* Bound-checking is made.
*/
void RemoveSprite(std::size_t index);
/**
* Clear the direction from all of its sprites
* \brief Clear the direction from all of its sprites
*/
void RemoveAllSprites();
/**
* Add a new sprite at the end of the list.
* \brief Add a new sprite at the end of the list.
*/
void AddSprite(const Sprite& sprite);
/**
* Swap the position of two sprites
* \brief Swap the position of two sprites
*/
void SwapSprites(std::size_t firstSpriteIndex, std::size_t secondSpriteIndex);
/**
* Change the position of the specified sprite.
* \brief Change the position of the specified sprite.
*/
void MoveSprite(std::size_t oldIndex, std::size_t newIndex);
#if defined(GD_IDE_ONLY)
/**
* \brief Set the metadata (any string) associated to the Direction.
* \note Can be used by external editors to store extra information.
*/
virtual void SetMetadata(const gd::String& metadata_) { metadata = metadata_; }
/**
* \brief Return the (optional) metadata associated to the Direction.
*/
virtual const gd::String& GetMetadata() const { return metadata; }
#endif
void UnserializeFrom(const gd::SerializerElement& element);
#if defined(GD_IDE_ONLY)
void SerializeTo(gd::SerializerElement& element) const;
@@ -113,6 +135,9 @@ class GD_CORE_API Direction {
bool loop; ///< true if the animation must loop.
float timeBetweenFrame; ///< The time between each sprite of the animation.
std::vector<Sprite> sprites; ///< The sprites of the direction.
#if defined(GD_IDE_ONLY)
gd::String metadata;
#endif
};
} // namespace gd

View File

@@ -17,7 +17,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
extension
.SetExtensionInformation("Sprite",
_("Sprite"),
_("Sprite are animated object which can be used for most elements of a game."),
_("Sprite are animated object which can be used "
"for most elements of a game."),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/objects/sprite");
@@ -30,8 +31,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
#if defined(GD_IDE_ONLY)
obj.AddAction("Opacity",
_("Change object's opacity"),
_("Change the opacity of an object."),
_("Change Sprite opacity"),
_("Change the opacity of a Sprite. 0 is fully transparent, 255 "
"is opaque (default)."),
_("Do _PARAM1__PARAM2_ to the opacity of _PARAM0_"),
_("Visibility"),
"res/actions/opacity24.png",
@@ -39,7 +41,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.AddParameter("expression", _("Value (between 0 and 255)"))
.MarkAsSimple()
.SetManipulatedType("number");
@@ -198,6 +200,34 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddAction("ChangeWidth",
_("Width"),
_("Change the width of a Sprite object."),
_("Do _PARAM1__PARAM2_ to the width of _PARAM0_"),
_("Size"),
"res/actions/scale24.png",
"res/actions/scale.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddAction("ChangeHeight",
_("Height"),
_("Change the height of a Sprite object."),
_("Do _PARAM1__PARAM2_ to the height of _PARAM0_"),
_("Size"),
"res/actions/scale24.png",
"res/actions/scale.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddCondition(
"Animation",
_("Current animation"),
@@ -309,8 +339,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
obj.AddCondition("Opacity",
_("Opacity"),
_("Compare the opacity of an object, between 0 (fully "
"transparent) to 255 (opaque)"),
_("Compare the opacity of a Sprite, between 0 (fully "
"transparent) to 255 (opaque)."),
_("The opacity of _PARAM0_ is _PARAM1__PARAM2_"),
_("Visibility"),
"res/conditions/opacity24.png",

View File

@@ -23,9 +23,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
#if defined(GD_IDE_ONLY)
extension
.AddCondition("VarScene",
_("Value of a variable"),
_("Value of a scene variable"),
_("Compare the value of a scene variable."),
_("Variable _PARAM0_ is _PARAM1__PARAM2_"),
_("Scene variable _PARAM0_ is _PARAM1__PARAM2_"),
_("Variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
@@ -36,9 +36,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddCondition("VarSceneTxt",
_("Text of a variable"),
_("Text of a scene variable"),
_("Compare the text of a scene variable."),
_("The text of variable _PARAM0_ is _PARAM1__PARAM2_"),
_("The text of scene variable _PARAM0_ is _PARAM1__PARAM2_"),
_("Variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
@@ -51,8 +51,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
.AddCondition(
"VariableChildExists",
_("Child existence"),
_("Return true if the specified child of the variable exists."),
_("Child _PARAM1_ of variable _PARAM0_ exists"),
_("Return true if the specified child of the scene variable exists."),
_("Child _PARAM1_ of scene variable _PARAM0_ exists"),
_("Variables/Structures"),
"res/conditions/var24.png",
"res/conditions/var.png")
@@ -76,8 +76,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddCondition("VarSceneDef",
_("Test if a scene variable is defined"),
_("Test if the scene variable exist."),
_("Variable _PARAM0_ is defined"),
_("Test if the scene variable exists."),
_("Scene variable _PARAM0_ is defined"),
_("Variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
@@ -129,9 +129,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddAction("ModVarScene",
_("Value of a variable"),
_("Value of a scene variable"),
_("Modify the value of a scene variable."),
_("Do _PARAM1__PARAM2_ to variable _PARAM0_"),
_("Do _PARAM1__PARAM2_ to scene variable _PARAM0_"),
_("Variables"),
"res/actions/var24.png",
"res/actions/var.png")
@@ -142,9 +142,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddAction("ModVarSceneTxt",
_("String of a variable"),
_("String of a scene variable"),
_("Modify the text of a scene variable."),
_("Do _PARAM1__PARAM2_ to the text of variable _PARAM0_"),
_("Do _PARAM1__PARAM2_ to the text of scene variable _PARAM0_"),
_("Variables"),
"res/actions/var24.png",
"res/actions/var.png")
@@ -185,8 +185,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddAction("VariableRemoveChild",
_("Remove a child"),
_("Remove a child from a variable."),
_("Remove child _PARAM1_ from variable _PARAM0_"),
_("Remove a child from a scene variable."),
_("Remove child _PARAM1_ from scene variable _PARAM0_"),
_("Variables/Structure"),
"res/actions/var24.png",
"res/actions/var.png")
@@ -208,9 +208,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddAction("VariableClearChildren",
_("Clear variable"),
_("Remove all the children from the variable."),
_("Clear children from variable _PARAM0_"),
_("Clear scene variable"),
_("Remove all the children from the scene variable."),
_("Clear children from scene variable _PARAM0_"),
_("Variables/Structure"),
"res/actions/var24.png",
"res/actions/var.png")
@@ -230,7 +230,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddExpression("GlobalVariableChildCount",
_("Global variable number of children"),
_("Number of children of a global variable"),
_("Get the number of children of a global variable"),
_("Variables"),
"res/actions/var.png")
@@ -238,7 +238,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddExpression("VariableChildCount",
_("Scene variable number of children"),
_("Number of children of a scene variable"),
_("Get the number of children of a scene variable"),
_("Variables"),
"res/actions/var.png")
@@ -246,15 +246,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddExpression("Variable",
_("Scene variables"),
_("Scene variables"),
_("Value of a scene variable"),
_("Value of a scene variable"),
_("Variables"),
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"));
extension
.AddStrExpression("VariableString",
_("Scene variables"),
_("Text of a scene variable"),
_("Text of a scene variable"),
_("Variables"),
"res/actions/var.png")
@@ -262,15 +262,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
extension
.AddExpression("GlobalVariable",
_("Global variables"),
_("Global variable"),
_("Value of a global variable"),
_("Value of a global variable"),
_("Variables"),
"res/actions/var.png")
.AddParameter("globalvar", _("Name of the global variable"));
extension
.AddStrExpression("GlobalVariableString",
_("Global variables"),
_("Text of a global variable"),
_("Text of a global variable"),
_("Variables"),
"res/actions/var.png")

View File

@@ -10,6 +10,7 @@
#include <algorithm>
#include "GDCore/CommonTools.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "InstructionMetadata.h"
namespace gd {
@@ -81,4 +82,23 @@ InstructionMetadata& InstructionMetadata::AddCodeOnlyParameter(
return *this;
}
void ParameterMetadata::SerializeTo(SerializerElement& element) const {
element.SetAttribute("type", type);
element.SetAttribute("supplementaryInformation", supplementaryInformation);
element.SetAttribute("optional", optional);
element.SetAttribute("description", description);
element.SetAttribute("codeOnly", codeOnly);
element.SetAttribute("defaultValue", defaultValue);
element.SetAttribute("name", name);
}
void ParameterMetadata::UnserializeFrom(const SerializerElement& element) {
type = element.GetStringAttribute("type");
supplementaryInformation = element.GetStringAttribute("supplementaryInformation");
optional = element.GetBoolAttribute("optional");
description = element.GetStringAttribute("description");
codeOnly = element.GetBoolAttribute("codeOnly");
defaultValue = element.GetStringAttribute("defaultValue");
name = element.GetStringAttribute("name");
}
} // namespace gd

View File

@@ -22,6 +22,7 @@ class Project;
class Layout;
class EventsCodeGenerator;
class EventsCodeGenerationContext;
class SerializerElement;
} // namespace gd
namespace gd {
@@ -53,17 +54,19 @@ class GD_CORE_API ParameterMetadata {
/**
* \brief Return the name of the parameter.
*
*
* Name is optional, and won't be filled for most parameters of extensions.
* It is useful when generating a function from events, where parameters must be named.
* It is useful when generating a function from events, where parameters must
* be named.
*/
const gd::String &GetName() const { return name; }
/**
* \brief Set the name of the parameter.
*
*
* Name is optional, and won't be filled for most parameters of extensions.
* It is useful when generating a function from events, where parameters must be named.
* It is useful when generating a function from events, where parameters must
* be named.
*/
ParameterMetadata &SetName(const gd::String &name_) {
name = name_;
@@ -158,7 +161,8 @@ class GD_CORE_API ParameterMetadata {
static bool IsExpression(const gd::String &type,
const gd::String &parameterType) {
if (type == "number") {
return parameterType == "expression" || parameterType == "camera";
return parameterType == "expression" || parameterType == "camera" ||
parameterType == "forceMultiplier";
} else if (type == "string") {
return parameterType == "string" || parameterType == "layer" ||
parameterType == "color" || parameterType == "file" ||
@@ -167,6 +171,20 @@ class GD_CORE_API ParameterMetadata {
return false;
}
/** \name Serialization
*/
///@{
/**
* \brief Serialize the ParameterMetadata to the specified element
*/
void SerializeTo(gd::SerializerElement &element) const;
/**
* \brief Load the ParameterMetadata from the specified element
*/
void UnserializeFrom(const gd::SerializerElement &element);
///@}
// TODO: Deprecated public fields. Any direct using should be moved to
// getter/setter.
gd::String type; ///< Parameter type
@@ -178,8 +196,9 @@ class GD_CORE_API ParameterMetadata {
///< i.e. must not be shown in editor
gd::String defaultValue; ///< Used as a default value in editor or if an
///< optional parameter is empty.
private:
gd::String name; ///< The name of the parameter to be used in code generation. Optional.
private:
gd::String name; ///< The name of the parameter to be used in code
///< generation. Optional.
};
/**
@@ -204,6 +223,7 @@ class GD_CORE_API InstructionMetadata {
const gd::String &GetDescription() const { return description; }
const gd::String &GetSentence() const { return sentence; }
const gd::String &GetGroup() const { return group; }
ParameterMetadata &GetParameter(size_t i) { return parameters[i]; }
const ParameterMetadata &GetParameter(size_t i) const {
return parameters[i];
}

View File

@@ -15,6 +15,7 @@ void ParameterMetadataTools::ParametersToObjectsContainer(
gd::Project& project,
const std::vector<gd::ParameterMetadata>& parameters,
gd::ObjectsContainer& outputObjectsContainer) {
outputObjectsContainer.GetObjects().clear();
for (std::size_t i = 0; i < parameters.size(); ++i) {
const auto& parameter = parameters[i];
if (parameter.GetName().empty()) continue;

View File

@@ -25,16 +25,16 @@ Platform::Platform() {}
Platform::~Platform() {}
bool Platform::AddExtension(std::shared_ptr<gd::PlatformExtension> extension) {
std::cout << extension->GetName();
bool loaded = false;
for (std::size_t i = 0; i < extensionsLoaded.size(); ++i) {
if (extensionsLoaded[i]->GetName() == extension->GetName()) {
std::cout << "(replacing existing extension)" << std::endl;
extensionsLoaded[i] = extension;
loaded = true;
}
if (!extension) return false;
std::cout << "Loading " << extension->GetName() << "...";
if (IsExtensionLoaded(extension->GetName())) {
std::cout << " (replacing existing extension)";
RemoveExtension(extension->GetName());
}
if (!loaded) extensionsLoaded.push_back(extension);
std::cout << std::endl;
extensionsLoaded.push_back(extension);
// Load all creation/destruction functions for objects provided by the
// extension
@@ -44,10 +44,30 @@ bool Platform::AddExtension(std::shared_ptr<gd::PlatformExtension> extension) {
extension->GetObjectCreationFunctionPtr(objectsTypes[i]);
}
std::cout << ", ";
return true;
}
void Platform::RemoveExtension(const gd::String& name) {
// Unload all creation/destruction functions for objects provided by the
// extension
for (std::size_t i = 0; i < extensionsLoaded.size(); ++i) {
auto& extension = extensionsLoaded[i];
if (extension->GetName() == name) {
vector<gd::String> objectsTypes = extension->GetExtensionObjectsTypes();
for (std::size_t i = 0; i < objectsTypes.size(); ++i) {
creationFunctionTable.erase(objectsTypes[i]);
}
}
}
extensionsLoaded.erase(remove_if(extensionsLoaded.begin(),
extensionsLoaded.end(),
[&name](std::shared_ptr<PlatformExtension> extension) {
return extension->GetName() == name;
}),
extensionsLoaded.end());
}
bool Platform::IsExtensionLoaded(const gd::String& name) const {
for (std::size_t i = 0; i < extensionsLoaded.size(); ++i) {
if (extensionsLoaded[i]->GetName() == name) return true;

View File

@@ -27,7 +27,8 @@ class LayoutEditorCanvas;
class ProjectExporter;
} // namespace gd
typedef std::function<std::unique_ptr<gd::Object>(gd::String name)> CreateFunPtr;
typedef std::function<std::unique_ptr<gd::Object>(gd::String name)>
CreateFunPtr;
#undef CreateEvent
@@ -85,7 +86,7 @@ class GD_CORE_API Platform {
virtual gd::String GetExtensionCreateFunctionName() { return ""; }
/**
* \brief Add an extension to the manager.
* \brief Add an extension to the platform.
* \note This method is virtual and can be redefined by platforms if they want
* to do special work when an extension is loaded. \see gd::ExtensionsLoader
*/
@@ -111,6 +112,13 @@ class GD_CORE_API Platform {
return extensionsLoaded;
};
/**
* \brief Remove an extension from the platform.
*
* Events, objects, behaviors provided by the extension won't be available
* anymore.
*/
virtual void RemoveExtension(const gd::String& name);
///@}
/** \name Factory method

View File

@@ -388,7 +388,7 @@ void PlatformExtension::SetNameSpace(gd::String nameSpace_) {
return;
}
nameSpace = nameSpace_ + "::";
nameSpace = nameSpace_ + GetNamespaceSeparator();
}
std::vector<gd::String> PlatformExtension::GetBuiltinExtensionsNames() {

View File

@@ -432,6 +432,12 @@ class GD_CORE_API PlatformExtension {
*/
static std::vector<gd::String> GetBuiltinExtensionsNames();
/**
* \brief Get the string used to separate the name of the
* instruction/expression and the extension.
*/
static gd::String GetNamespaceSeparator() { return "::"; }
private:
/**
* Set the namespace ( the String each actions/conditions/expressions start

View File

@@ -1505,7 +1505,8 @@ void EditExpressionDialog::OnAddPropBtClick(wxCommandEvent& event) {
.parameters[i]
.supplementaryInformation);
if (dialog.DeduceBehavior() || dialog.ShowModal() == 1)
behaviorStr = dialog.GetChosenBehavior() + "::";
behaviorStr = dialog.GetChosenBehavior() +
gd::PlatformExtension::GetNamespaceSeparator();
} else {
if (!parametersStr.empty()) parametersStr += ",";
parametersStr += ShowParameterDialog(

View File

@@ -782,7 +782,8 @@ void EditStrExpressionDialog::OnAddPropBtClick(wxCommandEvent& event) {
.parameters[i]
.supplementaryInformation);
if (dialog.DeduceBehavior() || dialog.ShowModal() == 1)
behaviorStr = dialog.GetChosenBehavior() + "::";
behaviorStr = dialog.GetChosenBehavior() +
gd::PlatformExtension::GetNamespaceSeparator();
} else {
if (!parametersStr.empty()) parametersStr += ",";
parametersStr += ShowParameterDialog(

View File

@@ -7,6 +7,8 @@
#include "EventStoreDialog.h"
#include <ctime>
#include <sstream>
#include "GDCore/Project/Project.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/CommonTools.h"
#include "GDCore/IDE/Events/EventsRefactorer.h"
#include "GDCore/IDE/wxTools/SafeYield.h"

View File

@@ -41,7 +41,7 @@
#include "GDCore/IDE/Dialogs/DndResourcesEditor.h"
#include "GDCore/IDE/Dialogs/PropertyDescriptor.h"
#include "GDCore/IDE/Dialogs/ResourceLibraryDialog.h"
#include "GDCore/IDE/Project/ImagesUsedInventorizer.h"
#include "GDCore/IDE/Project/ResourcesInUseHelper.h"
#include "GDCore/IDE/Project/ProjectResourcesAdder.h"
#include "GDCore/IDE/wxTools/FileProperty.h"
#include "GDCore/IDE/wxTools/SkinHelper.h"
@@ -1332,7 +1332,7 @@ void ResourcesEditor::Refresh() {
void ResourcesEditor::OnDeleteUnusedFiles(wxCommandEvent& event) {
std::vector<gd::String> unusedImages =
gd::ProjectResourcesAdder::GetAllUselessImages(project);
gd::ProjectResourcesAdder::GetAllUseless(project, "image");
// Construct corresponding wxArrayString with unused images
wxArrayString imagesNotUsed;

View File

@@ -12,8 +12,8 @@
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Events/EventsList.h"
using namespace std;
@@ -103,6 +103,8 @@ class CallbacksForRenamingObject : public gd::ParserCallbacks {
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression) {
// TODO: Add support for renaming in sub expressions. This is not working
// as the parser does not handle change made to the expression.
gd::String newExpression;
CallbacksForRenamingObject callbacks(newExpression, oldName, newName);
@@ -111,7 +113,7 @@ class CallbacksForRenamingObject : public gd::ParserCallbacks {
if (!parser.ParseMathExpression(platform, project, layout, callbacks))
return false;
expression = gd::Expression(newExpression);
expression = gd::Expression(newExpression); // This change won't be picked up by the parser
return true;
}
@@ -119,6 +121,8 @@ class CallbacksForRenamingObject : public gd::ParserCallbacks {
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression) {
// TODO: Add support for renaming in sub expressions. This is not working
// as the parser does not handle change made to the expression.
gd::String newExpression;
CallbacksForRenamingObject callbacks(newExpression, oldName, newName);
@@ -127,7 +131,7 @@ class CallbacksForRenamingObject : public gd::ParserCallbacks {
if (!parser.ParseStringExpression(platform, project, layout, callbacks))
return false;
expression = gd::Expression(newExpression);
expression = gd::Expression(newExpression); // This change won't be picked up by the parser
return true;
}
@@ -201,8 +205,8 @@ class CallbacksForRemovingObject : public gd::ParserCallbacks {
};
bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
gd::Project& project,
gd::Layout& layout,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& actions,
gd::String oldName,
gd::String newName) {
@@ -265,8 +269,8 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
bool EventsRefactorer::RenameObjectInConditions(
const gd::Platform& platform,
gd::Project& project,
gd::Layout& layout,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& conditions,
gd::String oldName,
gd::String newName) {
@@ -325,8 +329,8 @@ bool EventsRefactorer::RenameObjectInConditions(
}
void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
gd::Project& project,
gd::Layout& layout,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String oldName,
gd::String newName) {
@@ -362,8 +366,8 @@ void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
}
bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
gd::Project& project,
gd::Layout& layout,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& actions,
gd::String name) {
bool somethingModified = false;
@@ -426,8 +430,8 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
bool EventsRefactorer::RemoveObjectInConditions(
const gd::Platform& platform,
gd::Project& project,
gd::Layout& layout,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& conditions,
gd::String name) {
bool somethingModified = false;
@@ -489,8 +493,8 @@ bool EventsRefactorer::RemoveObjectInConditions(
}
void EventsRefactorer::RemoveObjectInEvents(const gd::Platform& platform,
gd::Project& project,
gd::Layout& layout,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String name) {
for (std::size_t i = 0; i < events.size(); ++i) {
@@ -520,8 +524,8 @@ void EventsRefactorer::RemoveObjectInEvents(const gd::Platform& platform,
}
}
void EventsRefactorer::ReplaceStringInEvents(gd::Project& project,
gd::Layout& layout,
void EventsRefactorer::ReplaceStringInEvents(gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String toReplace,
gd::String newString,
@@ -590,8 +594,8 @@ gd::String ReplaceAllOccurencesCaseUnsensitive(gd::String context,
return context;
}
bool EventsRefactorer::ReplaceStringInActions(gd::Project& project,
gd::Layout& layout,
bool EventsRefactorer::ReplaceStringInActions(gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& actions,
gd::String toReplace,
gd::String newString,
@@ -632,8 +636,8 @@ bool EventsRefactorer::ReplaceStringInActions(gd::Project& project,
}
bool EventsRefactorer::ReplaceStringInConditions(
gd::Project& project,
gd::Layout& layout,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& conditions,
gd::String toReplace,
gd::String newString,
@@ -675,8 +679,8 @@ bool EventsRefactorer::ReplaceStringInConditions(
}
vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
gd::Project& project,
gd::Layout& layout,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String search,
bool matchCase,
@@ -734,8 +738,8 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
return results;
}
bool EventsRefactorer::SearchStringInActions(gd::Project& project,
gd::Layout& layout,
bool EventsRefactorer::SearchStringInActions(gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& actions,
gd::String search,
bool matchCase) {
@@ -766,8 +770,8 @@ bool EventsRefactorer::SearchStringInActions(gd::Project& project,
}
bool EventsRefactorer::SearchStringInConditions(
gd::Project& project,
gd::Layout& layout,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& conditions,
gd::String search,
bool matchCase) {

View File

@@ -11,9 +11,8 @@
#include "GDCore/String.h"
namespace gd {
class EventsList;
class Layout;
class ObjectsContainer;
class Platform;
class Project;
class ExternalEvents;
class BaseEvent;
class Instruction;
@@ -77,8 +76,8 @@ class GD_CORE_API EventsRefactorer {
* events ).
*/
static void RenameObjectInEvents(const gd::Platform& platform,
gd::Project& project,
gd::Layout& layout,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String oldName,
gd::String newName);
@@ -87,8 +86,8 @@ class GD_CORE_API EventsRefactorer {
* Remove all actions or conditions using an object
*/
static void RemoveObjectInEvents(const gd::Platform& platform,
gd::Project& project,
gd::Layout& layout,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String name);
@@ -98,8 +97,8 @@ class GD_CORE_API EventsRefactorer {
* \return A vector containing EventsSearchResult objects filled with events
* containing the string
*/
static std::vector<EventsSearchResult> SearchInEvents(gd::Project& project,
gd::Layout& layout,
static std::vector<EventsSearchResult> SearchInEvents(gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String search,
bool matchCase,
@@ -109,8 +108,8 @@ class GD_CORE_API EventsRefactorer {
/**
* Replace all occurrences of a gd::String in events
*/
static void ReplaceStringInEvents(gd::Project& project,
gd::Layout& layout,
static void ReplaceStringInEvents(gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String toReplace,
gd::String newString,
@@ -128,8 +127,8 @@ class GD_CORE_API EventsRefactorer {
* \return true if something was modified.
*/
static bool RenameObjectInActions(const gd::Platform& platform,
gd::Project& project,
gd::Layout& layout,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& instructions,
gd::String oldName,
gd::String newName);
@@ -141,8 +140,8 @@ class GD_CORE_API EventsRefactorer {
* \return true if something was modified.
*/
static bool RenameObjectInConditions(const gd::Platform& platform,
gd::Project& project,
gd::Layout& layout,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& instructions,
gd::String oldName,
gd::String newName);
@@ -153,8 +152,8 @@ class GD_CORE_API EventsRefactorer {
* \return true if something was modified.
*/
static bool RemoveObjectInConditions(const gd::Platform& platform,
gd::Project& project,
gd::Layout& layout,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& conditions,
gd::String name);
@@ -164,8 +163,8 @@ class GD_CORE_API EventsRefactorer {
* \return true if something was modified.
*/
static bool RemoveObjectInActions(const gd::Platform& platform,
gd::Project& project,
gd::Layout& layout,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& conditions,
gd::String name);
@@ -174,8 +173,8 @@ class GD_CORE_API EventsRefactorer {
*
* \return true if something was modified.
*/
static bool ReplaceStringInConditions(gd::Project& project,
gd::Layout& layout,
static bool ReplaceStringInConditions(gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& conditions,
gd::String toReplace,
gd::String newString,
@@ -186,20 +185,20 @@ class GD_CORE_API EventsRefactorer {
*
* \return true if something was modified.
*/
static bool ReplaceStringInActions(gd::Project& project,
gd::Layout& layout,
static bool ReplaceStringInActions(gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& conditions,
gd::String toReplace,
gd::String newString,
bool matchCase);
static bool SearchStringInActions(gd::Project& project,
gd::Layout& layout,
static bool SearchStringInActions(gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& actions,
gd::String search,
bool matchCase);
static bool SearchStringInConditions(gd::Project& project,
gd::Layout& layout,
static bool SearchStringInConditions(gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& conditions,
gd::String search,
bool matchCase);

View File

@@ -4,7 +4,6 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/EventsTypesLister.h"
#include <iostream>
#include <map>
#include <memory>
#include <vector>

View File

@@ -5,7 +5,6 @@
*/
#ifndef EventsTypesLister_H
#define EventsTypesLister_H
#include <iostream>
#include <map>
#include <memory>
#include <vector>

View File

@@ -0,0 +1,51 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/ExpressionsRenamer.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
namespace gd {
bool ExpressionsRenamer::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
auto& metadata = isCondition ? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
for (std::size_t pNb = 0; pNb < metadata.parameters.size() &&
pNb < instruction.GetParametersCount();
++pNb) {
// Replace object's name in parameters
if (gd::ParameterMetadata::IsExpression("number",
metadata.parameters[pNb].type) ||
gd::ParameterMetadata::IsExpression("string",
metadata.parameters[pNb].type)) {
// This raw replacement is theorically too broad and a ExpressionParser
// should be used instead with callbacks to rename only the function. But
// as ExpressionsRenamer is only used for renaming EventsFunction, which
// have namespaces (i.e: Extension::MyFunction), it's safe enough to do
// this raw search/replace.
instruction.SetParameter(
pNb,
instruction.GetParameter(pNb).GetPlainString().FindAndReplace(
oldType, newType));
}
}
return false;
}
ExpressionsRenamer::~ExpressionsRenamer() {}
} // namespace gd

View File

@@ -0,0 +1,52 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef ExpressionsRenamer_H
#define ExpressionsRenamer_H
#include <map>
#include <memory>
#include <vector>
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class BaseEvent;
class Platform;
class EventsList;
} // namespace gd
namespace gd {
/**
* \brief Replace in expressions, in parameters of actions or conditions, calls
* to a function by another function.
*
* \note The replacement is done by making a raw search/replace in parameters
* that are expecting expressions or string expressions. Consequently, to avoid
* unwanted renaming, be sure to only use ExpressionsRenamer for expression
* calls that have an obvious name (in particular, make sure they have a
* namespace: Extension::Expression).
*
* \ingroup IDE
*/
class GD_CORE_API ExpressionsRenamer : public ArbitraryEventsWorker {
public:
ExpressionsRenamer(const gd::Platform& platform_,
const gd::String& oldType_,
const gd::String& newType_)
: platform(platform_), oldType(oldType_), newType(newType_){};
virtual ~ExpressionsRenamer();
private:
bool DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) override;
const gd::Platform& platform;
gd::String oldType;
gd::String newType;
};
} // namespace gd
#endif // ExpressionsRenamer_H

View File

@@ -0,0 +1,29 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/InstructionsTypeRenamer.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
namespace gd {
bool InstructionsTypeRenamer::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
if (instruction.GetType() == oldType) {
instruction.SetType(newType);
}
return false;
}
InstructionsTypeRenamer::~InstructionsTypeRenamer() {}
} // namespace gd

View File

@@ -0,0 +1,46 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef InstructionsTypeRenamer_H
#define InstructionsTypeRenamer_H
#include <map>
#include <memory>
#include <vector>
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class BaseEvent;
class Project;
class EventsList;
} // namespace gd
namespace gd {
/**
* \brief Replace in events all instructions of the specified type
* by another type.
*
* \ingroup IDE
*/
class GD_CORE_API InstructionsTypeRenamer : public ArbitraryEventsWorker {
public:
InstructionsTypeRenamer(const gd::Project& project_,
const gd::String& oldType_,
const gd::String& newType_)
: project(project_), oldType(oldType_), newType(newType_){};
virtual ~InstructionsTypeRenamer();
private:
bool DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) override;
const gd::Project& project;
gd::String oldType;
gd::String newType;
};
} // namespace gd
#endif // InstructionsTypeRenamer_H

View File

@@ -21,7 +21,7 @@ using namespace std;
namespace gd {
void ArbitraryResourceWorker::ExposeImage(gd::String& imageName){
// Nothing to do, the image is a referece to a resource that
// Nothing to do, the image is a reference to a resource that
// is already exposed.
};
@@ -40,6 +40,21 @@ void ArbitraryResourceWorker::ExposeAudio(gd::String& audioName) {
ExposeFile(audioName);
};
void ArbitraryResourceWorker::ExposeFont(gd::String& fontName) {
for (auto resources : GetResources()) {
if (!resources) continue;
if (resources->HasResource(fontName) &&
resources->GetResource(fontName).GetKind() == "font") {
// Nothing to do, the font is a reference to a resource that
// is already exposed.
return;
}
}
ExposeFile(fontName);
};
void ArbitraryResourceWorker::ExposeResources(
gd::ResourcesManager* resourcesManager) {
if (!resourcesManager) return;

View File

@@ -34,7 +34,7 @@ namespace gd {
* sometimes update them.
*
* \see ResourcesMergingHelper
* \see gd::ImagesUsedInventorizer
* \see gd::ResourcesInUseHelper
*
* \see gd::LaunchResourceWorkerOnEvents
*
@@ -64,6 +64,12 @@ class GD_CORE_API ArbitraryResourceWorker {
*/
virtual void ExposeAudio(gd::String &audioName);
/**
* \brief Expose a font, which is either a reference to a "font" resource,
* or a filename if no resource with this name exists.
*/
virtual void ExposeFont(gd::String &fontName);
/**
* \brief Expose a shader.
* \warn Currently unsupported.

View File

@@ -1,52 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#ifndef IMAGESUSEDINVENTORIZER_H
#define IMAGESUSEDINVENTORIZER_H
#include <set>
#include <vector>
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/String.h"
namespace gd {
/**
* \brief Class used to track all images used in a game.
*
* Usage example:
\code
gd::ImagesUsedInventorizer inventorizer;
project.ExposeResources(inventorizer);
//Get a set with the name of all images in the project:
std::set<gd::String> & usedImages = inventorizer.GetAllUsedImages();
\endcode
*
* \ingroup IDE
*/
class ImagesUsedInventorizer : public gd::ArbitraryResourceWorker {
public:
ImagesUsedInventorizer() : gd::ArbitraryResourceWorker(){};
virtual ~ImagesUsedInventorizer(){};
std::set<gd::String>& GetAllUsedImages() { return allUsedImages; };
virtual void ExposeFile(gd::String& resource){
/*Don't care, we just list images*/};
virtual void ExposeImage(gd::String& imageName) {
allUsedImages.insert(imageName);
};
protected:
std::set<gd::String> allUsedImages;
};
} // namespace gd
#endif // IMAGESUSEDINVENTORIZER_H
#endif

View File

@@ -5,7 +5,7 @@
*/
#include "ProjectResourcesAdder.h"
#include "GDCore/CommonTools.h"
#include "GDCore/IDE/Project/ImagesUsedInventorizer.h"
#include "GDCore/IDE/Project/ResourcesInUseHelper.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/Log.h"
@@ -14,51 +14,52 @@ using namespace std;
namespace gd {
bool ProjectResourcesAdder::AddAllMissingImages(gd::Project& project) {
gd::ImagesUsedInventorizer inventorizer;
project.ExposeResources(inventorizer);
std::set<gd::String>& allImages = inventorizer.GetAllUsedImages();
bool ProjectResourcesAdder::AddAllMissing(gd::Project& project,
const gd::String& resourceType) {
// Search for resources used in the project
gd::ResourcesInUseHelper resourcesInUse;
project.ExposeResources(resourcesInUse);
ResourcesManager& resourcesManager = project.GetResourcesManager();
for (std::set<gd::String>::const_iterator it = allImages.begin();
it != allImages.end();
++it) {
if (!resourcesManager.HasResource(*it)) {
std::cout << "Adding missing resource \"" << *it << "\"to the project.";
resourcesManager.AddResource(*it, /*filename=*/*it, "image");
for (auto& resourceName : resourcesInUse.GetAll(resourceType)) {
if (!resourcesManager.HasResource(resourceName)) {
std::cout << "Adding missing resource \"" << resourceName
<< "\"to the project." << std::endl;
resourcesManager.AddResource(
resourceName, /*filename=*/resourceName, resourceType);
}
}
return true;
}
std::vector<gd::String> ProjectResourcesAdder::GetAllUselessImages(
gd::Project& project) {
std::vector<gd::String> ProjectResourcesAdder::GetAllUseless(
gd::Project& project, const gd::String& resourceType) {
std::vector<gd::String> unusedResources;
// Search for resources used in the project
gd::ResourcesInUseHelper resourcesInUse;
project.ExposeResources(resourcesInUse);
std::set<gd::String>& usedResources = resourcesInUse.GetAll(resourceType);
// Search for used images
gd::ImagesUsedInventorizer inventorizer;
project.ExposeResources(inventorizer);
std::set<gd::String>& usedImages = inventorizer.GetAllUsedImages();
// Search all images resources not used
// Search all resources not used
std::vector<gd::String> resources =
project.GetResourcesManager().GetAllResourceNames();
for (std::size_t i = 0; i < resources.size(); i++) {
if (project.GetResourcesManager().GetResource(resources[i]).GetKind() !=
"image")
resourceType)
continue;
if (usedImages.find(resources[i]) == usedImages.end())
if (usedResources.find(resources[i]) == usedResources.end())
unusedResources.push_back(resources[i]);
}
return unusedResources;
}
void ProjectResourcesAdder::RemoveAllUselessImages(gd::Project& project) {
std::vector<gd::String> unusedResources = GetAllUselessImages(project);
void ProjectResourcesAdder::RemoveAllUseless(gd::Project& project,
const gd::String& resourceType) {
std::vector<gd::String> unusedResources =
GetAllUseless(project, resourceType);
for (std::size_t i = 0; i < unusedResources.size(); ++i) {
project.GetResourcesManager().RemoveResource(unusedResources[i]);

View File

@@ -21,38 +21,35 @@ namespace gd {
class GD_CORE_API ProjectResourcesAdder {
public:
/**
* \brief Update the project so that all missing images are added, with an
* \brief Update the project so that all missing resources are added, with an
* filename that is equal to the missing resource name.
*
* \param project The project to be updated.
* \param resourceType The type of the resource the be searched
*
* \return true if no error happened
*/
static bool AddAllMissingImages(gd::Project& project);
static bool AddAllMissing(gd::Project& project, const gd::String & resourceType);
/**
* \brief Find all resources that are
* not used in the project.
*
* \note For now, only images resources can be tracked and marked
* as not used.
* \brief Find all resources of the specified kind that are
* not used by the project.
*
* \param project The project to be crawled.
* \param resourceType The type of the resource the be searched
*
* \return A vector containing the name of all unused resources
*/
static std::vector<gd::String> GetAllUselessImages(gd::Project& project);
static std::vector<gd::String> GetAllUseless(gd::Project& project, const gd::String & resourceType);
/**
* \brief Remove all resources that are not used
* in the project.
*
* \note For now, only images resources can be tracked and marked
* as not used.
* \brief Remove all resources of the specified kind that are not used
* by the project.
*
* \param project The project to be crawled.
* \param resourceType The type of the resource the be searched
*/
static void RemoveAllUselessImages(gd::Project& project);
static void RemoveAllUseless(gd::Project& project, const gd::String & resourceType);
};
} // namespace gd

View File

@@ -0,0 +1,72 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#ifndef IMAGESUSEDINVENTORIZER_H
#define IMAGESUSEDINVENTORIZER_H
#include <set>
#include <vector>
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/String.h"
namespace gd {
/**
* \brief Class used to track all resources used by a game,
* or a part of it (like a gd::Object).
*
* Usage example:
\code
gd::ResourcesInUseHelper resourcesInUse;
project.ExposeResources(resourcesInUse);
//Get a set with the name of all images in the project:
std::set<gd::String> & usedImages = resourcesInUse.GetAllImages();
\endcode
*
* \ingroup IDE
*/
class ResourcesInUseHelper : public gd::ArbitraryResourceWorker {
public:
ResourcesInUseHelper() : gd::ArbitraryResourceWorker(){};
virtual ~ResourcesInUseHelper(){};
std::set<gd::String>& GetAllImages() { return GetAll("image"); };
std::set<gd::String>& GetAllFonts() { return GetAll("font"); };
std::set<gd::String>& GetAllAudios() { return GetAll("audio"); };
std::set<gd::String>& GetAll(const gd::String& resourceType) {
return resourceType == "image"
? allImages
: (resourceType == "audio"
? allAudios
: (resourceType == "font") ? allFonts : emptyResources);
};
virtual void ExposeFile(gd::String& resource) override{
/*Don't care, we just list resource names*/
};
virtual void ExposeImage(gd::String& imageResourceName) override {
allImages.insert(imageResourceName);
};
virtual void ExposeAudio(gd::String& audioResourceName) override {
allAudios.insert(audioResourceName);
};
virtual void ExposeFont(gd::String& fontResourceName) override {
allFonts.insert(fontResourceName);
};
protected:
std::set<gd::String> allImages;
std::set<gd::String> allAudios;
std::set<gd::String> allFonts;
std::set<gd::String> emptyResources;
};
} // namespace gd
#endif // IMAGESUSEDINVENTORIZER_H
#endif

View File

@@ -49,11 +49,25 @@ void ResourcesMergingHelper::SetNewFilename(gd::String oldFilename,
gd::String newFilename) {
if (oldFilenames.find(oldFilename) != oldFilenames.end()) return;
// Make sure that the new filename is not already used.
gd::String finalFilename = gd::NewNameGenerator::Generate(
newFilename, [this](const gd::String& name) {
return newFilenames.find(name) != newFilenames.end();
});
// Extract baseName and extension from the new filename
size_t extensionPos = newFilename.find_last_of(".");
gd::String extension =
extensionPos != gd::String::npos
? newFilename.substr(extensionPos, newFilename.length())
: "";
gd::String baseName = newFilename.substr(0, extensionPos);
// Make sure that the new filename is not already used. Generate a
// new filename while there is a collision.
// Preserving extension is important.
gd::String finalFilename =
gd::NewNameGenerator::Generate(
baseName,
[this, extension](const gd::String& newBaseName) {
return newFilenames.find(newBaseName + extension) !=
newFilenames.end();
}) +
extension;
oldFilenames[oldFilename] = finalFilename;
newFilenames[finalFilename] = oldFilename;

View File

@@ -18,8 +18,10 @@ class AbstractFileSystem;
namespace gd {
/**
* \brief ResourcesMergingHelper is used (mainly during compilation) so
* as to inventory resources and change their filenames
* \brief ResourcesMergingHelper is used (mainly during export)
* to list resources and generate new filenames, to allow them to be all copied
* in a single directory (potentially changing the filename to avoid conflicts,
* but preserving extensions).
*
* \see ArbitraryResourceWorker
*
@@ -82,9 +84,9 @@ class GD_CORE_API ResourcesMergingHelper : public ArbitraryResourceWorker {
///< baseDirectory, will be preserved in
///< filenames.
bool preserveAbsoluteFilenames; ///< If set to true, the filenames which are
///< absolute ( C:\MyFile.png ) will not be
///< transformed into their filenames (
///< MyFile.png ).
///< absolute (C:\MyFile.png will not be
///< transformed into a relative filename
///< (MyFile.png).
gd::AbstractFileSystem&
fs; ///< The gd::AbstractFileSystem used to manipulate files.
};

View File

@@ -4,8 +4,13 @@
* reserved. This project is released under the MIT License.
*/
#include "WholeProjectRefactorer.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/DependenciesAnalyzer.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Events/EventsRefactorer.h"
#include "GDCore/IDE/Events/ExpressionsRenamer.h"
#include "GDCore/IDE/Events/InstructionsTypeRenamer.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/Project/ExternalLayout.h"
#include "GDCore/Project/InitialInstancesContainer.h"
@@ -16,6 +21,105 @@
namespace gd {
void WholeProjectRefactorer::ExposeProjectEvents(
gd::Project& project, gd::ArbitraryEventsWorker& worker) {
// See also gd::Project::ExposeResources for a method that traverse the whole
// project (this time for resources).
// Add layouts resources
for (std::size_t s = 0; s < project.GetLayoutsCount(); s++) {
worker.Launch(project.GetLayout(s).GetEvents());
}
// Add external events resources
for (std::size_t s = 0; s < project.GetExternalEventsCount(); s++) {
worker.Launch(project.GetExternalEvents(s).GetEvents());
}
// Add events functions extensions resources
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
e++) {
auto& eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
for (auto&& eventsFunction : eventsFunctionsExtension.GetEventsFunctions()) {
worker.Launch(eventsFunction->GetEvents());
}
}
}
void WholeProjectRefactorer::RenameEventsFunctionsExtension(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::String& oldName,
const gd::String& newName) {
auto renameEventsFunction =
[&project, &oldName, &newName](const gd::EventsFunction& eventsFunction) {
auto separator = gd::PlatformExtension::GetNamespaceSeparator();
gd::String oldType = oldName + separator + eventsFunction.GetName();
gd::String newType = newName + separator + eventsFunction.GetName();
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
gd::InstructionsTypeRenamer renamer =
gd::InstructionsTypeRenamer(project, oldType, newType);
ExposeProjectEvents(project, renamer);
} else if (eventsFunction.GetFunctionType() ==
gd::EventsFunction::Expression ||
eventsFunction.GetFunctionType() ==
gd::EventsFunction::StringExpression) {
gd::ExpressionsRenamer renamer = gd::ExpressionsRenamer(
project.GetCurrentPlatform(), oldType, newType);
ExposeProjectEvents(project, renamer);
}
};
// Order is important: we first rename the expressions then the instructions,
// to avoid being unable to fetch the metadata (the types of parameters) of
// instructions after they are renamed.
for (auto&& eventsFunction : eventsFunctionsExtension.GetEventsFunctions()) {
if (eventsFunction->GetFunctionType() == gd::EventsFunction::Expression ||
eventsFunction->GetFunctionType() ==
gd::EventsFunction::StringExpression) {
renameEventsFunction(*eventsFunction);
}
}
for (auto&& eventsFunction : eventsFunctionsExtension.GetEventsFunctions()) {
if (eventsFunction->GetFunctionType() == gd::EventsFunction::Action ||
eventsFunction->GetFunctionType() == gd::EventsFunction::Condition) {
renameEventsFunction(*eventsFunction);
}
}
}
/**
* \brief Refactor the project after an events function is renamed
*/
void WholeProjectRefactorer::RenameEventsFunction(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::String& oldFunctionName,
const gd::String& newFunctionName) {
if (!eventsFunctionsExtension.HasEventsFunctionNamed(oldFunctionName)) return;
const gd::EventsFunction& eventsFunction =
eventsFunctionsExtension.GetEventsFunction(oldFunctionName);
auto separator = gd::PlatformExtension::GetNamespaceSeparator();
gd::String oldType =
eventsFunctionsExtension.GetName() + separator + oldFunctionName;
gd::String newType =
eventsFunctionsExtension.GetName() + separator + newFunctionName;
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
gd::InstructionsTypeRenamer renamer =
gd::InstructionsTypeRenamer(project, oldType, newType);
ExposeProjectEvents(project, renamer);
} else if (eventsFunction.GetFunctionType() ==
gd::EventsFunction::Expression ||
eventsFunction.GetFunctionType() ==
gd::EventsFunction::StringExpression) {
gd::ExpressionsRenamer renamer =
gd::ExpressionsRenamer(project.GetCurrentPlatform(), oldType, newType);
ExposeProjectEvents(project, renamer);
}
}
void WholeProjectRefactorer::ObjectRemovedInLayout(gd::Project& project,
gd::Layout& layout,
const gd::String& objectName,

View File

@@ -8,22 +8,51 @@
#include <vector>
namespace gd {
class Project;
}
namespace gd {
class Layout;
}
namespace gd {
class String;
}
class EventsFunctionsExtension;
class ArbitraryEventsWorker;
} // namespace gd
namespace gd {
/**
* \brief Tool functions to do refactoring on the whole project after
* changes like deletion or renaming of an object.
*/
*
* \TODO Ideally ObjectRenamedInLayout, ObjectRemovedInLayout,
* GlobalObjectRenamed, GlobalObjectRemoved would be implemented using
* ExposeProjectEvents.
**/
class GD_CORE_API WholeProjectRefactorer {
public:
/**
* \brief Call the specified worker on all events of the project (layout,
* external events, events functions...)
*
* This should be the preferred way to traverse all the events of a project.
*/
static void ExposeProjectEvents(gd::Project& project,
gd::ArbitraryEventsWorker& worker);
/**
* \brief Refactor the project after an events function extension is renamed
*/
static void RenameEventsFunctionsExtension(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::String& oldName,
const gd::String& newName);
/**
* \brief Refactor the project after an events function is renamed
*/
static void RenameEventsFunction(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::String& oldFunctionName,
const gd::String& newFunctionName);
/**
* \brief Refactor the project after an object is renamed in a layout
*

View File

@@ -0,0 +1,69 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#include "EventsFunction.h"
#include <vector>
#include "GDCore/Serialization/SerializerElement.h"
namespace gd {
EventsFunction::EventsFunction() : functionType(Action) {}
void EventsFunction::SerializeTo(SerializerElement& element) const {
element.SetAttribute("name", name);
element.SetAttribute("fullName", fullName);
element.SetAttribute("description", description);
element.SetAttribute("sentence", sentence);
events.SerializeTo(element.AddChild("events"));
gd::String functionTypeStr = "Action";
if (functionType == Condition)
functionTypeStr = "Condition";
else if (functionType == Expression)
functionTypeStr = "Expression";
else if (functionType == StringExpression)
functionTypeStr = "StringExpression";
element.SetAttribute("functionType", functionTypeStr);
gd::SerializerElement& parametersElement = element.AddChild("parameters");
parametersElement.ConsiderAsArrayOf("parameter");
for (const auto& parameter : parameters) {
parameter.SerializeTo(parametersElement.AddChild("parameter"));
}
}
void EventsFunction::UnserializeFrom(gd::Project& project,
const SerializerElement& element) {
name = element.GetStringAttribute("name");
fullName = element.GetStringAttribute("fullName");
description = element.GetStringAttribute("description");
sentence = element.GetStringAttribute("sentence");
events.UnserializeFrom(project, element.GetChild("events"));
gd::String functionTypeStr = element.GetStringAttribute("functionType");
if (functionTypeStr == "Condition")
functionType = Condition;
else if (functionTypeStr == "Expression")
functionType = Expression;
else if (functionTypeStr == "StringExpression")
functionType = StringExpression;
else
functionType = Action;
const gd::SerializerElement& parametersElement =
element.GetChild("parameters");
parameters.clear();
parametersElement.ConsiderAsArrayOf("parameter");
for (std::size_t i = 0; i < parametersElement.GetChildrenCount(); ++i) {
ParameterMetadata parameter;
parameter.UnserializeFrom(parametersElement.GetChild(i));
parameters.push_back(parameter);
}
}
} // namespace gd
#endif

View File

@@ -0,0 +1,172 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#ifndef GDCORE_EVENTSFUNCTION_H
#define GDCORE_EVENTSFUNCTION_H
#include <vector>
#include "GDCore/Events/EventsList.h"
#include "GDCore/String.h"
// TODO: In theory (for separation of concerns between Project and
// extensions/events), this include should be removed and gd::ParameterMetadata
// replaced by a new gd::EventsFunctionParameter class.
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
namespace gd {
class SerializerElement;
class Project;
} // namespace gd
namespace gd {
/**
* \brief Events that can be generated as a stand-alone function, and used
* as a condition, action or expression.
*
* \note The code generation can be done using gd::EventsCodeGenerator
*
* \note The conversion to an extension is not in GDCore and should be done
* by the IDE (see EventsFunctionsExtensionsLoader)
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API EventsFunction {
public:
EventsFunction();
virtual ~EventsFunction(){};
/**
* \brief Return a pointer to a new EventsFunction constructed from
* this one.
*/
EventsFunction* Clone() const { return new EventsFunction(*this); };
/**
* \brief Get the description of the function, that is displayed in the
* editor.
*/
const gd::String& GetDescription() const { return description; };
/**
* \brief Set the description of the function, to be displayed in the editor.
*/
EventsFunction& SetDescription(const gd::String& description_) {
description = description_;
return *this;
}
/**
* \brief Get the name of the function, to be used for the
* action/condition/expression name.
*/
const gd::String& GetName() const { return name; };
/**
* \brief Set the name of the function, to be used for the
* action/condition/expression name.
*/
EventsFunction& SetName(const gd::String& name_) {
name = name_;
return *this;
}
/**
* \brief Get the name of the function, that is displayed in the editor.
*/
const gd::String& GetFullName() const { return fullName; };
/**
* \brief Set the name of the function, to be displayed in the editor.
*/
EventsFunction& SetFullName(const gd::String& fullName_) {
fullName = fullName_;
return *this;
}
/**
* \brief Get the sentence of the function, that is used for the
* condition/action in the Events Editor.
*/
const gd::String& GetSentence() const { return sentence; };
/**
* \brief Set the sentence of the function, to be used for the
* condition/action in the Events Editor.
*/
EventsFunction& SetSentence(const gd::String& sentence_) {
sentence = sentence_;
return *this;
}
enum FunctionType { Action, Condition, Expression, StringExpression };
/**
* \brief Set the type of the function
*/
EventsFunction& SetFunctionType(FunctionType type) {
functionType = type;
return *this;
};
/**
* \brief Get the type of the function
*/
FunctionType GetFunctionType() const { return functionType; };
/**
* \brief Return the events.
*/
const gd::EventsList& GetEvents() const { return events; };
/**
* \brief Return the events.
*/
gd::EventsList& GetEvents() { return events; };
/**
* \brief Return the parameters of the function.
*
* \note During code/extension generation, new parameters are added
* to the generated function, like "runtimeScene" and "eventsFunctionContext".
* This should be transparent to the user.
*/
const std::vector<gd::ParameterMetadata>& GetParameters() const {
return parameters;
};
/**
* \brief Return the parameters.
*/
std::vector<gd::ParameterMetadata>& GetParameters() { return parameters; };
/** \name Serialization
*/
///@{
/**
* \brief Serialize the EventsFunction to the specified element
*/
void SerializeTo(gd::SerializerElement& element) const;
/**
* \brief Load the EventsFunction from the specified element
*/
void UnserializeFrom(gd::Project& project,
const gd::SerializerElement& element);
///@}
private:
gd::String name;
gd::String fullName;
gd::String description;
gd::String sentence;
gd::EventsList events;
FunctionType functionType;
std::vector<gd::ParameterMetadata> parameters;
};
} // namespace gd
#endif // GDCORE_EVENTSFUNCTION_H
#endif

View File

@@ -0,0 +1,161 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#include "EventsFunctionsExtension.h"
#include "EventsFunction.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/MakeUnique.h"
#include "GDCore/Tools/PolymorphicClone.h"
namespace gd {
EventsFunctionsExtension::EventsFunctionsExtension() {}
EventsFunctionsExtension::EventsFunctionsExtension(
const EventsFunctionsExtension& other) {
Init(other);
}
EventsFunctionsExtension& EventsFunctionsExtension::operator=(
const EventsFunctionsExtension& other) {
if (this != &other) Init(other);
return *this;
}
void EventsFunctionsExtension::Init(const gd::EventsFunctionsExtension& other) {
version = other.version;
extensionNamespace = other.extensionNamespace;
description = other.description;
name = other.name;
fullName = other.fullName;
eventsFunctions = gd::Clone(other.eventsFunctions);
}
void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
element.SetAttribute("version", version);
element.SetAttribute("extensionNamespace", extensionNamespace);
element.SetAttribute("description", description);
element.SetAttribute("name", name);
element.SetAttribute("fullName", fullName);
gd::SerializerElement& eventsFunctionsElement =
element.AddChild("eventsFunctions");
eventsFunctionsElement.ConsiderAsArrayOf("eventsFunction");
for (const auto& eventsFunction : eventsFunctions) {
eventsFunction->SerializeTo(
eventsFunctionsElement.AddChild("eventsFunction"));
}
}
void EventsFunctionsExtension::UnserializeFrom(
gd::Project& project, const SerializerElement& element) {
version = element.GetStringAttribute("version");
extensionNamespace = element.GetStringAttribute("extensionNamespace");
description = element.GetStringAttribute("description");
name = element.GetStringAttribute("name");
fullName = element.GetStringAttribute("fullName");
const gd::SerializerElement& eventsFunctionsElement =
element.GetChild("eventsFunctions");
eventsFunctions.clear();
eventsFunctionsElement.ConsiderAsArrayOf("eventsFunction");
for (std::size_t i = 0; i < eventsFunctionsElement.GetChildrenCount(); ++i) {
gd::EventsFunction& newEventsFunction =
InsertNewEventsFunction("", GetEventsFunctionsCount());
newEventsFunction.UnserializeFrom(project,
eventsFunctionsElement.GetChild(i));
}
}
bool EventsFunctionsExtension::HasEventsFunctionNamed(
const gd::String& name) const {
return find_if(eventsFunctions.begin(),
eventsFunctions.end(),
[&name](const std::unique_ptr<gd::EventsFunction>& function) {
return function->GetName() == name;
}) != eventsFunctions.end();
}
std::size_t EventsFunctionsExtension::GetEventsFunctionsCount() const {
return eventsFunctions.size();
}
gd::EventsFunction& EventsFunctionsExtension::InsertNewEventsFunction(
const gd::String& name, std::size_t position) {
gd::EventsFunction& newEventsFunction = *(*(eventsFunctions.insert(
position < eventsFunctions.size() ? eventsFunctions.begin() + position
: eventsFunctions.end(),
std::unique_ptr<gd::EventsFunction>(new EventsFunction()))));
newEventsFunction.SetName(name);
return newEventsFunction;
}
gd::EventsFunction& EventsFunctionsExtension::InsertEventsFunction(
const gd::EventsFunction& object, std::size_t position) {
gd::EventsFunction& newEventsFunction = *(*(eventsFunctions.insert(
position < eventsFunctions.size() ? eventsFunctions.begin() + position
: eventsFunctions.end(),
std::unique_ptr<gd::EventsFunction>(new EventsFunction(object)))));
return newEventsFunction;
}
void EventsFunctionsExtension::MoveEventsFunction(std::size_t oldIndex,
std::size_t newIndex) {
if (oldIndex >= eventsFunctions.size() || newIndex >= eventsFunctions.size())
return;
std::unique_ptr<gd::EventsFunction> object =
std::move(eventsFunctions[oldIndex]);
eventsFunctions.erase(eventsFunctions.begin() + oldIndex);
eventsFunctions.insert(eventsFunctions.begin() + newIndex, std::move(object));
}
void EventsFunctionsExtension::RemoveEventsFunction(const gd::String& name) {
std::vector<std::unique_ptr<gd::EventsFunction> >::iterator object =
find_if(eventsFunctions.begin(),
eventsFunctions.end(),
[&name](const std::unique_ptr<gd::EventsFunction>& function) {
return function->GetName() == name;
});
if (object == eventsFunctions.end()) return;
eventsFunctions.erase(object);
}
gd::EventsFunction& EventsFunctionsExtension::GetEventsFunction(
const gd::String& name) {
return *(
*find_if(eventsFunctions.begin(),
eventsFunctions.end(),
[&name](const std::unique_ptr<gd::EventsFunction>& function) {
return function->GetName() == name;
}));
}
const gd::EventsFunction& EventsFunctionsExtension::GetEventsFunction(
const gd::String& name) const {
return *(
*find_if(eventsFunctions.begin(),
eventsFunctions.end(),
[&name](const std::unique_ptr<gd::EventsFunction>& function) {
return function->GetName() == name;
}));
}
gd::EventsFunction& EventsFunctionsExtension::GetEventsFunction(std::size_t index) {
return *eventsFunctions[index];
}
const gd::EventsFunction& EventsFunctionsExtension::GetEventsFunction(std::size_t index) const {
return *eventsFunctions[index];
}
} // namespace gd
#endif

View File

@@ -0,0 +1,172 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#ifndef GDCORE_EVENTSFUNCTIONEXTENSION_H
#define GDCORE_EVENTSFUNCTIONEXTENSION_H
#include <vector>
#include "GDCore/Project/EventsFunction.h"
#include "GDCore/String.h"
namespace gd {
class SerializerElement;
class Project;
} // namespace gd
namespace gd {
/**
* \brief Hold a list of Events Functions (gd::EventsFunction).
*
* Events functions can be generated as stand-alone functions, and
* converted to actions/conditions/expressions.
* Similarly, a gd::EventsFunctionsExtension can be converted to
* an extension.
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API EventsFunctionsExtension {
public:
EventsFunctionsExtension();
EventsFunctionsExtension(const EventsFunctionsExtension&);
EventsFunctionsExtension& operator=(const EventsFunctionsExtension& rhs);
virtual ~EventsFunctionsExtension(){};
/**
* \brief Return a pointer to a new EventsFunctionsExtension constructed from
* this one.
*/
EventsFunctionsExtension* Clone() const {
return new EventsFunctionsExtension(*this);
};
const gd::String& GetVersion() const { return version; };
EventsFunctionsExtension& SetVersion(const gd::String& version_) {
version = version_;
return *this;
}
const gd::String& GetNamespace() const { return extensionNamespace; };
EventsFunctionsExtension& SetNamespace(const gd::String& namespace_) {
extensionNamespace = namespace_;
return *this;
}
const gd::String& GetDescription() const { return description; };
EventsFunctionsExtension& SetDescription(const gd::String& description_) {
description = description_;
return *this;
}
const gd::String& GetName() const { return name; };
EventsFunctionsExtension& SetName(const gd::String& name_) {
name = name_;
return *this;
}
const gd::String& GetFullName() const { return fullName; };
EventsFunctionsExtension& SetFullName(const gd::String& fullName_) {
fullName = fullName_;
return *this;
}
/**
* \brief Check if the function with the specified name exists.
*/
bool HasEventsFunctionNamed(const gd::String& name) const;
/**
* \brief Get the function with the specified name.
*
* \warning Trying to access to a not existing function will result in
* undefined behavior.
*/
gd::EventsFunction& GetEventsFunction(const gd::String& name);
/**
* \brief Get the function with the specified name.
*
* \warning Trying to access to a not existing function will result in
* undefined behavior.
*/
const gd::EventsFunction& GetEventsFunction(const gd::String& name) const;
/**
* \brief Get the function at the specified index in the list.
*
* \warning Trying to access to a not existing function will result in
* undefined behavior.
*/
gd::EventsFunction& GetEventsFunction(std::size_t index);
/**
* \brief Get the function at the specified index in the list.
*
* \warning Trying to access to a not existing function will result in
* undefined behavior.
*/
const gd::EventsFunction& GetEventsFunction(std::size_t index) const;
/**
* \brief Return the number of functions.
*/
std::size_t GetEventsFunctionsCount() const;
gd::EventsFunction& InsertNewEventsFunction(const gd::String& name,
std::size_t position);
gd::EventsFunction& InsertEventsFunction(const gd::EventsFunction& object,
std::size_t position);
void RemoveEventsFunction(const gd::String& name);
void MoveEventsFunction(std::size_t oldIndex, std::size_t newIndex);
/**
* \brief Provide a raw access to the vector containing the functions.
*/
const std::vector<std::unique_ptr<gd::EventsFunction>>& GetEventsFunctions()
const {
return eventsFunctions;
};
/**
* \brief Provide a raw access to the vector containing the functions.
*/
std::vector<std::unique_ptr<gd::EventsFunction>>& GetEventsFunctions() {
return eventsFunctions;
};
/** \name Serialization
*/
///@{
/**
* \brief Serialize the EventsFunctionsExtension to the specified element
*/
void SerializeTo(gd::SerializerElement& element) const;
/**
* \brief Load the EventsFunctionsExtension from the specified element
*/
void UnserializeFrom(gd::Project& project,
const gd::SerializerElement& element);
///@}
private:
/**
* Initialize object using another object. Used by copy-ctor and assign-op.
* Don't forget to update me if members were changed!
*/
void Init(const gd::EventsFunctionsExtension& other);
gd::String version;
gd::String extensionNamespace;
gd::String description;
gd::String name;
gd::String fullName;
std::vector<std::unique_ptr<gd::EventsFunction>> eventsFunctions;
};
} // namespace gd
#endif // GDCORE_EVENTSFUNCTIONEXTENSION_H
#endif

View File

@@ -16,28 +16,16 @@
namespace gd {
class PropertyDescriptor;
}
namespace gd {
class Project;
}
namespace gd {
class Layout;
}
namespace gd {
class MainFrameWrapper;
}
namespace gd {
class ArbitraryResourceWorker;
}
namespace gd {
class InitialInstance;
}
class SerializerElement;
} // namespace gd
namespace sf {
class RenderTarget;
}
namespace sf {
class SerializerElement;
}
class wxWindow;
class wxBitmap;
@@ -77,7 +65,10 @@ class GD_CORE_API Object {
/**
* Must return a pointer to a copy of the object. A such method is needed to
* do polymorphic copies. Just redefine this method in your derived object
* class like this: \code return new MyObject(*this); \endcode
* class like this:
* \code
* return gd::make_unique<MyObject>(*this);
* \endcode
*/
virtual std::unique_ptr<gd::Object> Clone() const {
return gd::make_unique<gd::Object>(*this);

View File

@@ -10,8 +10,6 @@
#include "GDCore/String.h"
namespace gd {
class SerializerElement;
}
namespace gd {
class ArbitraryResourceWorker;
}

View File

@@ -22,6 +22,7 @@
#include "GDCore/IDE/PlatformManager.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/IDE/wxTools/SafeYield.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/ChangesNotifier.h"
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/Project/ExternalLayout.h"
@@ -64,6 +65,7 @@ Project::Project()
version("1.0.0"),
packageName("com.example.gamename"),
orientation("landscape"),
adMobAppId(""),
folderProject(false),
#endif
windowWidth(800),
@@ -434,6 +436,104 @@ void Project::RemoveExternalLayout(const gd::String& name) {
externalLayouts.erase(externalLayout);
}
#if defined(GD_IDE_ONLY)
void Project::SwapEventsFunctionsExtensions(std::size_t first,
std::size_t second) {
if (first >= eventsFunctionsExtensions.size() ||
second >= eventsFunctionsExtensions.size())
return;
std::iter_swap(eventsFunctionsExtensions.begin() + first,
eventsFunctionsExtensions.begin() + second);
}
bool Project::HasEventsFunctionsExtensionNamed(const gd::String& name) const {
return (
find_if(
eventsFunctionsExtensions.begin(),
eventsFunctionsExtensions.end(),
[&name](
const std::unique_ptr<gd::EventsFunctionsExtension>& extension) {
return extension->GetName() == name;
}) != eventsFunctionsExtensions.end());
}
gd::EventsFunctionsExtension& Project::GetEventsFunctionsExtension(
const gd::String& name) {
return *(*find_if(
eventsFunctionsExtensions.begin(),
eventsFunctionsExtensions.end(),
[&name](const std::unique_ptr<gd::EventsFunctionsExtension>& extension) {
return extension->GetName() == name;
}));
}
const gd::EventsFunctionsExtension& Project::GetEventsFunctionsExtension(
const gd::String& name) const {
return *(*find_if(
eventsFunctionsExtensions.begin(),
eventsFunctionsExtensions.end(),
[&name](const std::unique_ptr<gd::EventsFunctionsExtension>& extension) {
return extension->GetName() == name;
}));
}
gd::EventsFunctionsExtension& Project::GetEventsFunctionsExtension(
std::size_t index) {
return *eventsFunctionsExtensions[index];
}
const gd::EventsFunctionsExtension& Project::GetEventsFunctionsExtension(
std::size_t index) const {
return *eventsFunctionsExtensions[index];
}
std::size_t Project::GetEventsFunctionsExtensionPosition(
const gd::String& name) const {
for (std::size_t i = 0; i < eventsFunctionsExtensions.size(); ++i) {
if (eventsFunctionsExtensions[i]->GetName() == name) return i;
}
return gd::String::npos;
}
std::size_t Project::GetEventsFunctionsExtensionsCount() const {
return eventsFunctionsExtensions.size();
}
gd::EventsFunctionsExtension& Project::InsertNewEventsFunctionsExtension(
const gd::String& name, std::size_t position) {
gd::EventsFunctionsExtension& newlyInsertedEventsFunctionsExtension =
*(*(eventsFunctionsExtensions.emplace(
position < eventsFunctionsExtensions.size()
? eventsFunctionsExtensions.begin() + position
: eventsFunctionsExtensions.end(),
new gd::EventsFunctionsExtension())));
newlyInsertedEventsFunctionsExtension.SetName(name);
return newlyInsertedEventsFunctionsExtension;
}
gd::EventsFunctionsExtension& Project::InsertEventsFunctionsExtension(
const gd::EventsFunctionsExtension& extension, std::size_t position) {
gd::EventsFunctionsExtension& newlyInsertedEventsFunctionsExtension =
*(*(eventsFunctionsExtensions.emplace(
position < eventsFunctionsExtensions.size()
? eventsFunctionsExtensions.begin() + position
: eventsFunctionsExtensions.end(),
new gd::EventsFunctionsExtension(extension))));
return newlyInsertedEventsFunctionsExtension;
}
void Project::RemoveEventsFunctionsExtension(const gd::String& name) {
std::vector<std::unique_ptr<gd::EventsFunctionsExtension> >::iterator
eventsFunctionExtension = find_if(
eventsFunctionsExtensions.begin(),
eventsFunctionsExtensions.end(),
[&name](
const std::unique_ptr<gd::EventsFunctionsExtension>& extension) {
return extension->GetName() == name;
});
if (eventsFunctionExtension == eventsFunctionsExtensions.end()) return;
eventsFunctionsExtensions.erase(eventsFunctionExtension);
}
#endif
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
// Compatibility with GD2.x
class SpriteObjectsPositionUpdater : public gd::InitialInstanceFunctor {
@@ -541,6 +641,7 @@ void Project::UnserializeFrom(const SerializerElement& element) {
SetAuthor(propElement.GetChild("author", 0, "Auteur").GetValue().GetString());
SetPackageName(propElement.GetStringAttribute("packageName"));
SetOrientation(propElement.GetStringAttribute("orientation", "default"));
SetAdMobAppId(propElement.GetStringAttribute("adMobAppId", ""));
SetFolderProject(propElement.GetBoolAttribute("folderProject"));
SetProjectFile(propElement.GetStringAttribute("projectFile"));
SetLastCompilationDirectory(propElement
@@ -732,6 +833,24 @@ void Project::UnserializeFrom(const SerializerElement& element) {
GetExternalEventsCount());
externalEvents.UnserializeFrom(*this, externalEventElement);
}
eventsFunctionsExtensions.clear();
const SerializerElement& eventsFunctionsExtensionsElement =
element.GetChild("eventsFunctionsExtensions");
eventsFunctionsExtensionsElement.ConsiderAsArrayOf(
"eventsFunctionsExtension");
for (std::size_t i = 0;
i < eventsFunctionsExtensionsElement.GetChildrenCount();
++i) {
const SerializerElement& eventsFunctionsExtensionElement =
eventsFunctionsExtensionsElement.GetChild(i);
gd::EventsFunctionsExtension& newEventsFunctionsExtension =
InsertNewEventsFunctionsExtension("",
GetEventsFunctionsExtensionsCount());
newEventsFunctionsExtension.UnserializeFrom(
*this, eventsFunctionsExtensionElement);
}
#endif
externalLayouts.clear();
@@ -799,6 +918,7 @@ void Project::SerializeTo(SerializerElement& element) const {
propElement.SetAttribute("folderProject", folderProject);
propElement.SetAttribute("packageName", packageName);
propElement.SetAttribute("orientation", orientation);
propElement.SetAttribute("adMobAppId", adMobAppId);
platformSpecificAssets.SerializeTo(
propElement.AddChild("platformSpecificAssets"));
loadingScreen.SerializeTo(propElement.AddChild("loadingScreen"));
@@ -848,6 +968,14 @@ void Project::SerializeTo(SerializerElement& element) const {
GetExternalEvents(i).SerializeTo(
externalEventsElement.AddChild("externalEvents"));
SerializerElement& eventsFunctionsExtensionsElement =
element.AddChild("eventsFunctionsExtensions");
eventsFunctionsExtensionsElement.ConsiderAsArrayOf(
"eventsFunctionsExtension");
for (std::size_t i = 0; i < eventsFunctionsExtensions.size(); ++i)
eventsFunctionsExtensions[i]->SerializeTo(
eventsFunctionsExtensionsElement.AddChild("eventsFunctionsExtension"));
SerializerElement& externalLayoutsElement =
element.AddChild("externalLayouts");
externalLayoutsElement.ConsiderAsArrayOf("externalLayout");
@@ -878,6 +1006,10 @@ gd::String Project::GetBadObjectNameWarning() {
}
void Project::ExposeResources(gd::ArbitraryResourceWorker& worker) {
// See also gd::WholeProjectRefactorer::ExposeProjectEvents for a method that traverse the whole
// project (this time for events).
// Ideally, this method could be moved outside of gd::Project.
// Add project resources
worker.ExposeResources(&GetResourcesManager());
platformSpecificAssets.ExposeResources(worker);
@@ -898,6 +1030,13 @@ void Project::ExposeResources(gd::ArbitraryResourceWorker& worker) {
LaunchResourceWorkerOnEvents(
*this, GetExternalEvents(s).GetEvents(), worker);
}
// Add events functions extensions resources
for (std::size_t e = 0; e < GetEventsFunctionsExtensionsCount(); e++) {
auto& eventsFunctionsExtension = GetEventsFunctionsExtension(e);
for (auto&& eventsFunction : eventsFunctionsExtension.GetEventsFunctions()) {
LaunchResourceWorkerOnEvents(*this, eventsFunction->GetEvents(), worker);
}
}
#if !defined(GD_NO_WX_GUI)
gd::SafeYield::Do();
#endif
@@ -1115,6 +1254,7 @@ void Project::Init(const gd::Project& game) {
author = game.author;
packageName = game.packageName;
orientation = game.orientation;
adMobAppId = game.adMobAppId;
folderProject = game.folderProject;
latestCompilationDirectory = game.latestCompilationDirectory;
platformSpecificAssets = game.platformSpecificAssets;
@@ -1143,8 +1283,9 @@ void Project::Init(const gd::Project& game) {
#endif
externalLayouts = gd::Clone(game.externalLayouts);
#if defined(GD_IDE_ONLY)
eventsFunctionsExtensions = gd::Clone(game.eventsFunctionsExtensions);
useExternalSourceFiles = game.useExternalSourceFiles;
externalSourceFiles = gd::Clone(game.externalSourceFiles);

View File

@@ -13,9 +13,9 @@ class wxPropertyGrid;
class wxPropertyGridEvent;
class TiXmlElement;
#include "GDCore/Project/ChangesNotifier.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/LoadingScreen.h"
#include "GDCore/Project/ObjectGroupsContainer.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/PlatformSpecificAssets.h"
#include "GDCore/Project/ResourcesManager.h"
#include "GDCore/Project/VariablesContainer.h"
@@ -25,6 +25,7 @@ class Layout;
class ExternalEvents;
class ResourcesManager;
class ExternalLayout;
class EventsFunctionsExtension;
class Object;
class VariablesContainer;
class ArbitraryResourceWorker;
@@ -34,7 +35,7 @@ class Behavior;
class BehaviorsSharedData;
class BaseEvent;
class SerializerElement;
}
} // namespace gd
#undef GetObject // Disable an annoying macro
#undef CreateEvent
@@ -68,7 +69,8 @@ class GD_CORE_API Project : public ObjectsContainer {
/**
* \brief Change the version of the project.
* This can be freely set, but should follow "X.Y.Z" format for compatibility with some exporters.
* This can be freely set, but should follow "X.Y.Z" format for compatibility
* with some exporters.
*/
void SetVersion(const gd::String& version_) { version = version_; };
@@ -114,6 +116,20 @@ class GD_CORE_API Project : public ObjectsContainer {
*/
const gd::String& GetOrientation() const { return orientation; }
/**
* \brief Change the project AdMob application ID (needed
* to use the AdMob extension). This has no effect on desktop
* and web browsers.
*/
void SetAdMobAppId(const gd::String& adMobAppId_) {
adMobAppId = adMobAppId_;
};
/**
* \brief Get the project AdMob application ID.
*/
const gd::String& GetAdMobAppId() const { return adMobAppId; }
/**
* Called when project file has changed.
*/
@@ -456,13 +472,13 @@ class GD_CORE_API Project : public ObjectsContainer {
std::size_t GetLayoutsCount() const;
/**
* \brief Must add a new empty layout called "name" at the specified position
* in the layout list.
* \brief \brief Adds a new empty layout called "name" at the specified
* position in the layout list.
*/
gd::Layout& InsertNewLayout(const gd::String& name, std::size_t position);
/**
* \brief Must add a new layout constructed from the layout passed as
* \brief \brief Adds a new layout constructed from the layout passed as
* parameter. \note No pointer or reference must be kept on the layout passed
* as parameter. \param layout The layout that must be copied and inserted
* into the project \param position Insertion position. Even if the position
@@ -565,15 +581,15 @@ class GD_CORE_API Project : public ObjectsContainer {
std::size_t GetExternalEventsCount() const;
/**
* Must add a new empty external events sheet called "name" at the specified
* position in the layout list.
* \brief Adds a new empty external events sheet called "name" at the
* specified position in the layout list.
*/
ExternalEvents& InsertNewExternalEvents(const gd::String& name,
std::size_t position);
/**
* Must add a new external events sheet constructed from the layout passed as
* parameter. \note No pointer or reference must be kept on the external
* \brief Adds a new external events sheet constructed from the layout passed
* as parameter. \note No pointer or reference must be kept on the external
* events passed as parameter. \param externalEvents The external events that
* must be copied and inserted into the project \param position Insertion
* position. Even if the position is invalid, the external events must be
@@ -642,19 +658,23 @@ class GD_CORE_API Project : public ObjectsContainer {
std::size_t GetExternalLayoutsCount() const;
/**
* Must add a new empty external layout called "name" at the specified
* \brief Adds a new empty external layout called "name" at the specified
* position in the layout list.
*/
gd::ExternalLayout& InsertNewExternalLayout(const gd::String& name,
std::size_t position);
/**
* Must add a new external layout constructed from the layout passed as
* parameter. \note No pointer or reference must be kept on the external
* layout passed as parameter. \param externalLayout The external layout that
* must be copied and inserted into the project \param position Insertion
* position. Even if the position is invalid, the external layout must be
* inserted at the end of the external layout list.
* \brief Adds a new external layout constructed from the layout passed as
* parameter.
*
* \note No pointer or reference must be kept on the external
* layout passed as parameter.
*
* \param externalLayout The external layout that
* must be copied and inserted into the projects
* \param position Insertion position. Even if the position is invalid, the
* external layout must be inserted at the end of the external layout list.
*/
gd::ExternalLayout& InsertExternalLayout(const ExternalLayout& externalLayout,
std::size_t position);
@@ -674,6 +694,81 @@ class GD_CORE_API Project : public ObjectsContainer {
*/
const gd::String& GetFirstLayout() { return firstLayout; }
///@}
/** \name Events functions extensions management
*/
///@{
#if defined(GD_IDE_ONLY)
/**
* Return true if events functions extension called "name" exists.
*/
bool HasEventsFunctionsExtensionNamed(const gd::String& name) const;
/**
* Return a reference to the events functions extension called "name".
*/
EventsFunctionsExtension& GetEventsFunctionsExtension(const gd::String& name);
/**
* Return a reference to the events functions extension called "name".
*/
const EventsFunctionsExtension& GetEventsFunctionsExtension(
const gd::String& name) const;
/**
* Return a reference to the events functions extension at position "index" in
* the list
*/
EventsFunctionsExtension& GetEventsFunctionsExtension(std::size_t index);
/**
* Return a reference to the events functions extension at position "index" in
* the list
*/
const EventsFunctionsExtension& GetEventsFunctionsExtension(
std::size_t index) const;
/**
* Return the position of the events functions extension called "name" in the
* list
*/
std::size_t GetEventsFunctionsExtensionPosition(const gd::String& name) const;
/**
* \brief Swap the specified events functions extensions.
*
* Do nothing if indexes are not correct.
*/
void SwapEventsFunctionsExtensions(std::size_t first, std::size_t second);
/**
* Return the number of events functions extension.
*/
std::size_t GetEventsFunctionsExtensionsCount() const;
/**
* \brief Adds a new empty events functions extension called "name" at the
* specified position in the list.
*/
gd::EventsFunctionsExtension& InsertNewEventsFunctionsExtension(
const gd::String& name, std::size_t position);
/**
* \brief Adds a new events functions extension constructed from the layout
* passed as parameter.
*
* \note No pointer or reference must be kept on the extension passed as
* parameter.
*/
gd::EventsFunctionsExtension& InsertEventsFunctionsExtension(
const EventsFunctionsExtension& externalLayout, std::size_t position);
/**
* Must delete the events functions extension named "name".
*/
void RemoveEventsFunctionsExtension(const gd::String& name);
#endif
///@}
/** \name Resources management
@@ -718,8 +813,11 @@ class GD_CORE_API Project : public ObjectsContainer {
/**
* \brief Called ( e.g. during compilation ) so as to inventory internal
* resources and sometimes update their filename.
* resources, sometimes update their filename or any other work or resources.
*
* See WholeProjectRefactorer for the same thing for events.
*
* \see WholeProjectRefactorer
* \see ArbitraryResourceWorker
*/
void ExposeResources(gd::ArbitraryResourceWorker& worker);
@@ -857,6 +955,10 @@ class GD_CORE_API Project : public ObjectsContainer {
gd::VariablesContainer variables; ///< Initial global variables
std::vector<std::unique_ptr<gd::ExternalLayout> >
externalLayouts; ///< List of all externals layouts
#if defined(GD_IDE_ONLY)
std::vector<std::unique_ptr<gd::EventsFunctionsExtension> >
eventsFunctionsExtensions;
#endif
gd::ResourcesManager
resourcesManager; ///< Contains all resources used by the project
std::shared_ptr<gd::ImageManager>
@@ -870,10 +972,11 @@ class GD_CORE_API Project : public ObjectsContainer {
bool useExternalSourceFiles; ///< True if game used external source files.
std::vector<std::unique_ptr<gd::SourceFile> >
externalSourceFiles; ///< List of external source files used.
gd::String author; ///< Game author name
gd::String packageName; ///< Game package name
gd::String orientation; ///< Lock game orientation (on mobile devices).
///< "default", "landscape" or "portrait".
gd::String author; ///< Game author name
gd::String packageName; ///< Game package name
gd::String orientation; ///< Lock game orientation (on mobile devices).
///< "default", "landscape" or "portrait".
gd::String adMobAppId; ///< AdMob application ID.
bool
folderProject; ///< True if folder project, false if single file project.
gd::String gameFile; ///< File of the game

View File

@@ -79,6 +79,8 @@ std::shared_ptr<Resource> ResourcesManager::CreateResource(
return std::make_shared<ImageResource>();
else if (kind == "audio")
return std::make_shared<AudioResource>();
else if (kind == "font")
return std::make_shared<FontResource>();
std::cout << "Bad resource created (type: " << kind << ")" << std::endl;
return std::make_shared<Resource>();
@@ -92,7 +94,7 @@ bool ResourcesManager::HasResource(const gd::String& name) const {
return false;
}
std::vector<gd::String> ResourcesManager::GetAllResourceNames() {
std::vector<gd::String> ResourcesManager::GetAllResourceNames() const {
std::vector<gd::String> allResources;
for (std::size_t i = 0; i < resources.size(); ++i)
allResources.push_back(resources[i]->GetName());
@@ -134,19 +136,11 @@ bool ImageResource::UpdateProperty(const gd::String& name,
bool ResourcesManager::AddResource(const gd::Resource& resource) {
if (HasResource(resource.GetName())) return false;
try {
const Resource& castedResource = dynamic_cast<const Resource&>(resource);
std::shared_ptr<Resource> newResource =
std::shared_ptr<Resource>(castedResource.Clone());
if (newResource == std::shared_ptr<Resource>()) return false;
resources.push_back(newResource);
} catch (...) {
std::cout << "WARNING: Tried to add a resource which is not a GD C++ "
"Platform Resource to a GD C++ Platform project";
std::cout << char(7);
}
std::shared_ptr<Resource> newResource =
std::shared_ptr<Resource>(resource.Clone());
if (newResource == std::shared_ptr<Resource>()) return false;
resources.push_back(newResource);
return true;
}
@@ -408,16 +402,8 @@ bool ResourceFolder::HasResource(const gd::String& name) const {
void ResourceFolder::AddResource(const gd::String& name,
gd::ResourcesManager& parentManager) {
try {
ResourcesManager& manager = dynamic_cast<ResourcesManager&>(parentManager);
std::shared_ptr<Resource> resource =
std::dynamic_pointer_cast<Resource>(manager.GetResourceSPtr(name));
if (resource != std::shared_ptr<Resource>()) resources.push_back(resource);
} catch (...) {
std::cout << "Warning: A resources manager which is not part of GD C++ "
"Platform was used during call to AddResource"
<< std::endl;
}
std::shared_ptr<Resource> resource = parentManager.GetResourceSPtr(name);
if (resource != std::shared_ptr<Resource>()) resources.push_back(resource);
}
void ResourcesManager::RenameResource(const gd::String& oldName,
@@ -487,9 +473,11 @@ void ResourcesManager::UnserializeFrom(const SerializerElement& element) {
const SerializerElement& resourceElement = resourcesElement.GetChild(i);
gd::String kind = resourceElement.GetStringAttribute("kind");
gd::String name = resourceElement.GetStringAttribute("name");
gd::String metadata = resourceElement.GetStringAttribute("metadata", "");
std::shared_ptr<Resource> resource = CreateResource(kind);
resource->SetName(name);
resource->SetMetadata(metadata);
resource->UnserializeFrom(resourceElement);
resources.push_back(resource);
@@ -519,6 +507,7 @@ void ResourcesManager::SerializeTo(SerializerElement& element) const {
SerializerElement& resourceElement = resourcesElement.AddChild("resource");
resourceElement.SetAttribute("kind", resources[i]->GetKind());
resourceElement.SetAttribute("name", resources[i]->GetName());
resourceElement.SetAttribute("metadata", resources[i]->GetMetadata());
resources[i]->SerializeTo(resourceElement);
}
@@ -577,7 +566,31 @@ void AudioResource::SerializeTo(SerializerElement& element) const {
"file", GetFile()); // Keep the resource path in the current locale (but
// save it in UTF8 for compatibility on other OSes)
}
#endif
void FontResource::SetFile(const gd::String& newFile) {
file = newFile;
// Convert all backslash to slashs.
while (file.find('\\') != gd::String::npos)
file.replace(file.find('\\'), 1, "/");
}
void FontResource::UnserializeFrom(const SerializerElement& element) {
SetUserAdded(element.GetBoolAttribute("userAdded"));
SetFile(element.GetStringAttribute("file"));
}
#if defined(GD_IDE_ONLY)
void FontResource::SerializeTo(SerializerElement& element) const {
element.SetAttribute("userAdded", IsUserAdded());
element.SetAttribute(
"file", GetFile()); // Keep the resource path in the current locale (but
// save it in UTF8 for compatibility on other OSes)
}
#endif
#if defined(GD_IDE_ONLY)
ResourceFolder::ResourceFolder(const ResourceFolder& other) { Init(other); }
ResourceFolder& ResourceFolder::operator=(const ResourceFolder& other) {

View File

@@ -10,14 +10,8 @@
#include "GDCore/String.h"
namespace gd {
class Project;
}
namespace gd {
class ResourceFolder;
}
namespace gd {
class SerializerElement;
}
namespace gd {
class PropertyDescriptor;
}
class wxPaintDC;
@@ -48,7 +42,7 @@ class GD_CORE_API Resource {
*/
virtual void SetKind(const gd::String& newKind) { kind = newKind; }
/** \brief Return the name of the object.
/** \brief Return the kind of the resource.
*/
virtual const gd::String& GetKind() const { return kind; }
@@ -91,6 +85,18 @@ class GD_CORE_API Resource {
*/
gd::String GetAbsoluteFile(const gd::Project& game) const;
/**
* \brief Set the metadata (any string) associated to the resource.
* \note Can be used by external editors to store extra information, for
* example the configuration used to produce a sound.
*/
virtual void SetMetadata(const gd::String& metadata_) { metadata = metadata_; }
/**
* \brief Return the (optional) metadata associated to the resource
*/
virtual const gd::String& GetMetadata() const { return metadata; }
#if !defined(GD_NO_WX_GUI)
/**
* \brief Called when the resource must be rendered in a preview panel.
@@ -150,6 +156,7 @@ class GD_CORE_API Resource {
private:
gd::String kind;
gd::String name;
gd::String metadata;
bool userAdded; ///< True if the resource was added by the user, and not
///< automatically by GDevelop.
@@ -255,6 +262,34 @@ class GD_CORE_API AudioResource : public Resource {
gd::String file;
};
/**
* \brief Describe a font file used by a project.
*
* \see Resource
* \ingroup ResourcesManagement
*/
class GD_CORE_API FontResource : public Resource {
public:
FontResource() : Resource() { SetKind("font"); };
virtual ~FontResource(){};
virtual FontResource* Clone() const override {
return new FontResource(*this);
}
virtual const gd::String& GetFile() const override { return file; };
virtual void SetFile(const gd::String& newFile) override;
#if defined(GD_IDE_ONLY)
virtual bool UseFile() override { return true; }
void SerializeTo(SerializerElement& element) const override;
#endif
void UnserializeFrom(const SerializerElement& element) override;
private:
gd::String file;
};
/**
* \brief Inventory all resources used by a project
*
@@ -291,7 +326,7 @@ class GD_CORE_API ResourcesManager {
/**
* \brief Get a list containing the names of all resources.
*/
std::vector<gd::String> GetAllResourceNames();
std::vector<gd::String> GetAllResourceNames() const;
#if defined(GD_IDE_ONLY)
/**

View File

@@ -121,7 +121,7 @@ double SerializerElement::GetDoubleAttribute(const gd::String& name,
return defaultValue;
}
bool SerializerElement::HasAttribute(const gd::String& name) {
bool SerializerElement::HasAttribute(const gd::String& name) const {
return attributes.find(name) != attributes.end();
}

View File

@@ -164,7 +164,8 @@ class GD_CORE_API SerializerElement {
* \brief Return true if the specified attribute exists.
* \param name The name of the attribute to find.
*/
bool HasAttribute(const gd::String &name);
bool HasAttribute(const gd::String &name) const;
/**
* \brief Return all the children of the element.
*/

View File

@@ -87,11 +87,11 @@ TEST_CASE("Resources", "[common][resources]") {
SECTION("ProjectResourcesAdder") {
std::vector<gd::String> uselessResources =
gd::ProjectResourcesAdder::GetAllUselessImages(project);
gd::ProjectResourcesAdder::GetAllUseless(project, "image");
REQUIRE(uselessResources.size() == 2);
gd::ProjectResourcesAdder::RemoveAllUselessImages(project);
gd::ProjectResourcesAdder::RemoveAllUseless(project, "image");
std::vector<gd::String> remainingResources =
project.GetResourcesManager().GetAllResourceNames();
REQUIRE(remainingResources.size() == 2);

View File

@@ -0,0 +1,361 @@
/**
* This is a declaration of an extension for GDevelop 5.
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change
* to this extension file or to any other *.js file that you reference inside.
*
* The file must be named "JsExtension.js", otherwise GDevelop won't load it.
* ⚠️ If you make a change and the extension is not loaded, open the developer console
* and search for any errors.
*
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
module.exports = {
createExtension: function(t, gd) {
const extension = new gd.PlatformExtension();
extension.setExtensionInformation(
'AdMob',
t('AdMob'),
t(
'Allow the game to display AdMob banner, interstitial and reward video ads'
),
'Franco Maciel',
'MIT'
);
// Banner
extension
.addCondition(
'BannerLoading',
t('Banner loading'),
t('Check if a banner is currently loading.'),
t('Banner is loading'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.isBannerLoading');
extension
.addCondition(
'BannerReady',
t('Banner ready'),
t('Check if a banner is ready to be displayed.'),
t('Banner is ready'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.isBannerReady');
extension
.addCondition(
'BannerShowing',
t('Banner showing'),
t('Check if there is a banner being displayed.'),
t('Banner is showing'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.isBannerShowing');
extension
.addCondition(
'BannerExists',
t('Banner exists'),
t('Check if there is a banner in memory (visible or hidden).'),
t('Banner exists'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.existBanner');
extension
.addAction(
'LoadBanner',
t('Load banner'),
t(
'Start loading a banner, you can display it automatically when finish loading.\nIf test mode is set to true a test banner will be displayed.'
),
t(
'Load banner (at top: _PARAM2_, overlap: _PARAM3_, show on load: _PARAM4_, test mode: _PARAM5_)'
),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.addParameter('string', t('Android banner ID'), '', false)
.addParameter('string', t('iOS banner ID'), '', false)
.addParameter(
'yesorno',
t('Display at top? (bottom otherwise)'),
'',
false
)
.setDefaultValue('false')
.addParameter('yesorno', t('Overlap webview?'), '', false)
.setDefaultValue('true')
.addParameter('yesorno', t('Display on load complete?'), '', false)
.setDefaultValue('true')
.addParameter('yesorno', t('Test mode?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.loadBanner');
extension
.addAction(
'ShowBanner',
t('Show banner'),
t('Show the banner, will work only when the banner is fully loaded.'),
t('Show banner'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.showBanner');
extension
.addAction(
'HideBanner',
t('Hide banner'),
t(
'Hide the banner. You can show it again with the corresponding action.'
),
t('Hide banner'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.hideBanner');
extension
.addAction(
'RemoveBanner',
t('Remove banner'),
t(
'Remove the banner. You have to load another banner to show it again.'
),
t('Remove banner'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.removeBanner');
// Interstitial
extension
.addCondition(
'InterstitialLoading',
t('Interstitial loading'),
t('Check if an interstitial is currently loading.'),
t('Interstitial is loading'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.isInterstitialLoading');
extension
.addCondition(
'InterstitialReady',
t('Interstitial ready'),
t('Check if an interstitial is ready to be displayed.'),
t('Interstitial is ready'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.isInterstitialReady');
extension
.addCondition(
'InterstitialShowing',
t('Interstitial showing'),
t('Check if there is an interstitial being displayed.'),
t('Interstitial is showing'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.isInterstitialShowing');
extension
.addAction(
'LoadInterstitial',
t('Load interstitial'),
t(
'Start loading an interstitial, you can display it automatically when finish loading.\nIf test mode is set to true a test interstitial will be displayed.'
),
t('Load interstitial (show on load: _PARAM2_, test mode: _PARAM3_)'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.addParameter('string', t('Android interstitial ID'), '', false)
.addParameter('string', t('iOS interstitial ID'), '', false)
.addParameter('yesorno', t('Display on load complete?'), '', false)
.setDefaultValue('true')
.addParameter('yesorno', t('Test mode?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.loadInterstitial');
extension
.addAction(
'ShowInterstitial',
t('Show interstitial'),
t(
'Show the interstitial, will work only when the interstitial is fully loaded.'
),
t('Show interstitial'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.showInterstitial');
// Reward video
extension
.addCondition(
'VideoLoading',
t('Video loading'),
t('Check if a reward video is currently loading.'),
t('Reward video is loading'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.isVideoLoading');
extension
.addCondition(
'VideoReady',
t('Video ready'),
t('Check if a reward video is ready to be displayed.'),
t('Reward video is ready'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.isVideoReady');
extension
.addCondition(
'VideoShowing',
t('Video showing'),
t('Check if there is a reward video being displayed.'),
t('Reward video is showing'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.isVideoShowing');
extension
.addCondition(
'VideoReward',
t('Video reward'),
t(
'Check if there is a video reward.\nYou can mark it as non-claimed yet, so you can check this reward in other events.'
),
t('Video reward given'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.addParameter('yesorno', t('Mark as claimed'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.existVideoReward');
extension
.addAction(
'LoadVideo',
t('Load video'),
t(
'Start loading a reward video, you can display it automatically when finish loading.\nIf test mode is set to true a test video will be displayed.'
),
t('Load reward video (show on load: _PARAM2_, test mode: _PARAM3_)'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.addParameter('string', t('Android reward video ID'), '', false)
.addParameter('string', t('iOS reward video ID'), '', false)
.addParameter('yesorno', t('Display on load complete?'), '', false)
.setDefaultValue('true')
.addParameter('yesorno', t('Test mode?'), '', false)
.setDefaultValue('true')
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.loadVideo');
extension
.addAction(
'ShowVideo',
t('Show video'),
t(
'Show the reward video, will work only when the video is fully loaded.'
),
t('Show reward video'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.showVideo');
extension
.addAction(
'ClaimReward',
t('Claim reward'),
t('Mark the video reward as claimed.'),
t('Claim video reward'),
t('AdMob'),
'JsPlatform/Extensions/admobicon24.png',
'JsPlatform/Extensions/admobicon16.png'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/AdMob/admobtools.js')
.setFunctionName('gdjs.adMob.claimVideoReward');
return extension;
},
runExtensionSanityTests: function(gd, extension) {
return [];
},
};

View File

@@ -0,0 +1,352 @@
/**
* @memberof gdjs
* @class adMob
* @static
* @private
*/
gdjs.adMob = {
// Banner
bannerLoading: false,
bannerReady: false,
bannerShowing: false,
bannerExists: false,
bannerAutoshow: false, // Needed because the banner event listeners bug
// Interstitial
interstitialLoading: false,
interstitialReady: false,
interstitialShowing: false,
// Reward video
videoLoading: false,
videoReady: false,
videoShowing: false,
videoReward: false,
};
gdjs.adMob._getPlatformName = function() {
if (/(android)/i.test(navigator.userAgent)) {
return 'android';
} else if (/(ipod|iphone|ipad)/i.test(navigator.userAgent)) {
return 'ios';
} else {
return 'windowsPhone';
}
};
// Banner
gdjs.adMob.isBannerLoading = function() {
return gdjs.adMob.bannerLoading;
};
gdjs.adMob.isBannerReady = function() {
// This block is needed because the banner event listeners bug
if (gdjs.adMob.bannerAutoshow && gdjs.adMob.bannerReady) {
gdjs.adMob.bannerReady = false;
gdjs.adMob.bannerShowing = true;
gdjs.adMob.bannerExists = true;
}
return gdjs.adMob.bannerReady;
};
gdjs.adMob.isBannerShowing = function() {
// This block is needed because the banner event listeners bug
if (gdjs.adMob.bannerAutoshow && gdjs.adMob.bannerReady) {
gdjs.adMob.bannerReady = false;
gdjs.adMob.bannerShowing = true;
gdjs.adMob.bannerExists = true;
}
return gdjs.adMob.bannerShowing;
};
gdjs.adMob.existBanner = function() {
// This block is needed because the banner event listeners bug
if (gdjs.adMob.bannerAutoshow && gdjs.adMob.bannerReady) {
gdjs.adMob.bannerReady = false;
gdjs.adMob.bannerShowing = true;
gdjs.adMob.bannerExists = true;
}
return gdjs.adMob.bannerExists;
};
gdjs.adMob.loadBanner = function(
androidID,
iosID,
atTop,
overlap,
displayOnLoading,
testMode
) {
if (typeof admob === 'undefined') return;
if (
gdjs.adMob.bannerLoading ||
gdjs.adMob.bannerReady ||
gdjs.adMob.bannerExists
)
return;
admob.banner.config({
id: gdjs.adMob._getPlatformName() === 'android' ? androidID : iosID, // Support Android & iOS
bannerAtTop: atTop,
overlap: overlap,
autoShow: displayOnLoading,
isTesting: testMode,
});
admob.banner.prepare();
gdjs.adMob.bannerLoading = true;
gdjs.adMob.bannerReady = false;
// These lines are needed because the banner event listeners bug
gdjs.adMob.bannerAutoshow = displayOnLoading;
gdjs.adMob.bannerShowing = false;
gdjs.adMob.bannerExists = false;
};
gdjs.adMob.showBanner = function() {
if (typeof admob === 'undefined') return;
// This block is needed because the banner event listeners bug
if (gdjs.adMob.bannerReady) {
gdjs.adMob.bannerReady = false;
gdjs.adMob.bannerExists = true;
}
if (gdjs.adMob.bannerExists) gdjs.adMob.bannerShowing = true;
admob.banner.show();
};
gdjs.adMob.hideBanner = function() {
if (typeof admob === 'undefined') return;
if (gdjs.adMob.bannerExists) gdjs.adMob.bannerShowing = false;
admob.banner.hide();
};
gdjs.adMob.removeBanner = function() {
if (typeof admob === 'undefined') return;
// These lines are needed because the banner event listeners bug
gdjs.adMob.bannerExists = false;
gdjs.adMob.bannerShowing = false;
admob.banner.remove();
};
// Interstitial
gdjs.adMob.isInterstitialLoading = function() {
return gdjs.adMob.interstitialLoading;
};
gdjs.adMob.isInterstitialReady = function() {
return gdjs.adMob.interstitialReady;
};
gdjs.adMob.isInterstitialShowing = function() {
return gdjs.adMob.interstitialShowing;
};
gdjs.adMob.loadInterstitial = function(
androidID,
iosID,
displayOnLoading,
testMode
) {
if (typeof admob === 'undefined') return;
if (
gdjs.adMob.interstitialLoading ||
gdjs.adMob.interstitialReady ||
gdjs.adMob.interstitialShowing
)
return;
admob.interstitial.config({
id: gdjs.adMob._getPlatformName() === 'android' ? androidID : iosID, // Support Android & iOS
autoShow: displayOnLoading,
isTesting: testMode,
});
admob.interstitial.prepare();
gdjs.adMob.interstitialLoading = true;
gdjs.adMob.interstitialReady = false;
};
gdjs.adMob.showInterstitial = function() {
if (typeof admob === 'undefined') return;
admob.interstitial.show();
};
// Reward video
gdjs.adMob.isVideoLoading = function() {
return gdjs.adMob.videoLoading;
};
gdjs.adMob.isVideoReady = function() {
return gdjs.adMob.videoReady;
};
gdjs.adMob.isVideoShowing = function() {
return gdjs.adMob.videoShowing;
};
gdjs.adMob.existVideoReward = function(markAsClaimed) {
var reward = gdjs.adMob.videoReward;
if (markAsClaimed) gdjs.adMob.videoReward = false;
return reward;
};
gdjs.adMob.loadVideo = function(androidID, iosID, displayOnLoading, testMode) {
if (typeof admob === 'undefined') return;
if (
gdjs.adMob.videoLoading ||
gdjs.adMob.videoReady ||
gdjs.adMob.videoShowing
)
return;
admob.rewardvideo.config({
id: gdjs.adMob._getPlatformName() === 'android' ? androidID : iosID, // Support Android & iOS
autoShow: displayOnLoading,
isTesting: testMode,
});
admob.rewardvideo.prepare();
gdjs.adMob.videoLoading = true;
gdjs.adMob.videoReady = false;
};
gdjs.adMob.showVideo = function() {
if (typeof admob === 'undefined') return;
admob.rewardvideo.show();
};
gdjs.adMob.claimVideoReward = function() {
gdjs.adMob.videoReward = false;
};
// Banner event listeners
document.addEventListener(
'admob.banner.events.LOAD',
function() {
gdjs.adMob.bannerReady = true;
gdjs.adMob.bannerLoading = false;
},
false
);
document.addEventListener(
'admob.banner.events.LOAD_FAIL',
function() {
gdjs.adMob.bannerLoading = false;
},
false
);
// BUG: These two never get called
/*
document.addEventListener(
"admob.banner.events.OPEN",
function() {
gdjs.adMob.bannerExists = true;
gdjs.adMob.bannerShowing = true;
gdjs.adMob.bannerReady = false;
},
false
);
document.addEventListener(
"admob.banner.events.CLOSE",
function() {
gdjs.adMob.bannerExists = false;
gdjs.adMob.bannerShowing = false;
},
false
);
*/
// Interstitial event listeners
document.addEventListener(
'admob.interstitial.events.LOAD',
function() {
gdjs.adMob.interstitialReady = true;
gdjs.adMob.interstitialLoading = false;
},
false
);
document.addEventListener(
'admob.interstitial.events.LOAD_FAIL',
function() {
gdjs.adMob.interstitialLoading = false;
},
false
);
document.addEventListener(
'admob.interstitial.events.OPEN',
function() {
gdjs.adMob.interstitialShowing = true;
gdjs.adMob.interstitialReady = false;
},
false
);
document.addEventListener(
'admob.interstitial.events.CLOSE',
function() {
gdjs.adMob.interstitialShowing = false;
},
false
);
// Reward video event listeners
document.addEventListener(
'admob.rewardvideo.events.LOAD',
function() {
gdjs.adMob.videoReady = true;
gdjs.adMob.videoLoading = false;
},
false
);
document.addEventListener(
'admob.rewardvideo.events.LOAD_FAIL',
function() {
gdjs.adMob.videoLoading = false;
},
false
);
document.addEventListener(
'admob.rewardvideo.events.OPEN',
function() {
gdjs.adMob.videoShowing = true;
gdjs.adMob.videoReady = false;
},
false
);
document.addEventListener(
'admob.rewardvideo.events.CLOSE',
function() {
gdjs.adMob.videoShowing = false;
},
false
);
document.addEventListener(
'admob.rewardvideo.events.REWARD',
function() {
gdjs.adMob.videoReward = true;
},
false
);

View File

@@ -1,117 +0,0 @@
/**
GDevelop - AdMob Object Extension
Copyright (c) 2008-2016 Florian Rival (Florian.Rival@gmail.com)
This project is released under the MIT License.
*/
#include "AdMobObject.h"
#include <SFML/Graphics.hpp>
#include "GDCore/IDE/Dialogs/PropertyDescriptor.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/Tools/Localization.h"
#include "GDCpp/Runtime/CommonTools.h"
#include "GDCpp/Runtime/ImageManager.h"
#include "GDCpp/Runtime/Project/InitialInstance.h"
#include "GDCpp/Runtime/Project/Object.h"
#include "GDCpp/Runtime/Serialization/SerializerElement.h"
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
#include <wx/bitmap.h>
sf::Texture AdMobObject::edittimeIconImage;
sf::Sprite AdMobObject::edittimeIcon;
#endif
AdMobObject::AdMobObject(gd::String name_)
: Object(name_), isTesting(true), overlap(true), showOnStartup(true) {}
std::map<gd::String, gd::PropertyDescriptor> AdMobObject::GetProperties(
gd::Project& project) const {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[_("Banner ID (Android)")].SetValue(androidBannerId);
properties[_("Interstitial ID (Android)")].SetValue(androidInterstitialId);
properties[_("Banner ID (iOS)")].SetValue(iosBannerId);
properties[_("Interstitial ID (iOS)")].SetValue(iosInterstitialId);
properties[_("Testing mode")]
.SetValue(isTesting ? "true" : "false")
.SetType("Boolean");
properties[_("Overlap game")]
.SetValue(overlap ? "true" : "false")
.SetType("Boolean");
properties[_("Show banner on startup")]
.SetValue(showOnStartup ? "true" : "false")
.SetType("Boolean");
properties[_("Banner position")]
.SetValue(position == "Bottom" ? _("Bottom of the screen")
: _("Top of the screen"))
.SetType("Choice")
.AddExtraInfo(_("Top of the screen"))
.AddExtraInfo(_("Bottom of the screen"));
return properties;
}
bool AdMobObject::UpdateProperty(const gd::String& name,
const gd::String& value,
gd::Project& project) {
if (name == _("Banner ID (Android)")) androidBannerId = value;
if (name == _("Interstitial ID (Android)")) androidInterstitialId = value;
if (name == _("Banner ID (iOS)")) iosBannerId = value;
if (name == _("Interstitial ID (iOS)")) iosInterstitialId = value;
if (name == _("Testing mode")) isTesting = value == "1";
if (name == _("Overlap game")) overlap = value == "1";
if (name == _("Show banner on startup")) showOnStartup = value == "1";
if (name == _("Banner position"))
position = value == _("Top of the screen") ? "Top" : "Bottom";
return true;
}
void AdMobObject::DoUnserializeFrom(gd::Project& project,
const gd::SerializerElement& element) {
androidBannerId = element.GetStringAttribute("androidBannerId");
androidInterstitialId = element.GetStringAttribute("androidInterstitialId");
iosBannerId = element.GetStringAttribute("iosBannerId");
iosInterstitialId = element.GetStringAttribute("iosInterstitialId");
position = element.GetStringAttribute("position");
isTesting = element.GetBoolAttribute("isTesting");
overlap = element.GetBoolAttribute("overlap");
showOnStartup = element.GetBoolAttribute("showOnStartup");
}
void AdMobObject::DoSerializeTo(gd::SerializerElement& element) const {
element.SetAttribute("androidBannerId", androidBannerId);
element.SetAttribute("androidInterstitialId", androidInterstitialId);
element.SetAttribute("iosBannerId", iosBannerId);
element.SetAttribute("iosInterstitialId", iosInterstitialId);
element.SetAttribute("position", position);
element.SetAttribute("isTesting", isTesting);
element.SetAttribute("overlap", overlap);
element.SetAttribute("showOnStartup", showOnStartup);
}
#if !defined(GD_NO_WX_GUI)
void AdMobObject::DrawInitialInstance(gd::InitialInstance& instance,
sf::RenderTarget& renderTarget,
gd::Project& project,
gd::Layout& layout) {
edittimeIcon.setPosition(instance.GetX(), instance.GetY());
renderTarget.draw(edittimeIcon);
}
void AdMobObject::LoadEdittimeIcon() {
edittimeIconImage.loadFromFile("JsPlatform/Extensions/admobicon.png");
edittimeIcon.setTexture(edittimeIconImage);
}
bool AdMobObject::GenerateThumbnail(const gd::Project& project,
wxBitmap& thumbnail) const {
thumbnail =
wxBitmap("JsPlatform/Extensions/admobicon24.png", wxBITMAP_TYPE_ANY);
return true;
}
#endif
gd::Object* CreateAdMobObject(gd::String name) { return new AdMobObject(name); }

View File

@@ -1,73 +0,0 @@
/**
GDevelop - AdMob Object Extension
Copyright (c) 2008-2016 Florian Rival (Florian.Rival@gmail.com)
This project is released under the MIT License.
*/
#ifndef ADMOBOBJECT_H
#define ADMOBOBJECT_H
#include "GDCpp/Runtime/Project/Object.h"
#include "GDCpp/Runtime/String.h"
namespace gd {
class InitialInstance;
}
namespace gd {
class Project;
}
namespace sf {
class Texture;
}
namespace sf {
class Sprite;
}
class wxBitmap;
class GD_EXTENSION_API AdMobObject : public gd::Object {
public:
AdMobObject(gd::String name_);
virtual ~AdMobObject(){};
virtual std::unique_ptr<gd::Object> Clone() const override {
return gd::make_unique<AdMobObject>(*this);
}
#if !defined(GD_NO_WX_GUI)
void DrawInitialInstance(gd::InitialInstance& instance,
sf::RenderTarget& renderTarget,
gd::Project& project,
gd::Layout& layout) override;
bool GenerateThumbnail(const gd::Project& project,
wxBitmap& thumbnail) const override;
static void LoadEdittimeIcon();
#endif
std::map<gd::String, gd::PropertyDescriptor> GetProperties(
gd::Project& project) const override;
bool UpdateProperty(const gd::String& name,
const gd::String& value,
gd::Project& project) override;
private:
void DoUnserializeFrom(gd::Project& project,
const gd::SerializerElement& element) override;
void DoSerializeTo(gd::SerializerElement& element) const override;
gd::String androidBannerId;
gd::String androidInterstitialId;
gd::String iosBannerId;
gd::String iosInterstitialId;
gd::String position; //"Top" or "Bottom"
bool isTesting;
bool overlap;
bool showOnStartup;
#if !defined(GD_NO_WX_GUI)
static sf::Texture edittimeIconImage;
static sf::Sprite edittimeIcon;
#endif
};
gd::Object* CreateAdMobObject(gd::String name);
#endif // ADMOBOBJECT_H

View File

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

View File

@@ -1,94 +0,0 @@
/**
GDevelop - AdMob Object Extension
Copyright (c) 2008-2016 Florian Rival (Florian.Rival@gmail.com)
This project is released under the MIT License.
*/
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Tools/Localization.h"
#include "AdMobObject.h"
void DeclareAdMobObjectExtension(gd::PlatformExtension& extension) {
extension
.SetExtensionInformation(
"AdMobObject",
_("AdMob banners and interstitial screens"),
_("Display an ads banner and interstitial screens powered by AdMob."),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/objects/admob");
gd::ObjectMetadata& obj = extension.AddObject<AdMobObject>(
"AdMob",
_("AdMob banner"),
_("Display an ad banner or interstitial screen using AdMob"),
"JsPlatform/Extensions/admobicon.png");
obj.SetHelpUrl("/gdevelop/documentation/manual/built_admob");
#if !defined(GD_NO_WX_GUI)
AdMobObject::LoadEdittimeIcon();
#endif
obj.AddAction("ShowBanner",
_("Show banner ad"),
_("Show the banner ad"),
_("Show the banner ad of _PARAM0_"),
_("Banner"),
"JsPlatform/Extensions/admobicon24.png",
"JsPlatform/Extensions/admobicon16.png")
.AddParameter("object", _("Object"), "AdMob");
obj.AddAction("HideBanner",
_("Hide banner ad"),
_("Hide the banner ad"),
_("Hide the banner ad of _PARAM0_"),
_("Banner"),
"JsPlatform/Extensions/admobicon24.png",
"JsPlatform/Extensions/admobicon16.png")
.AddParameter("object", _("Object"), "AdMob");
obj.AddCondition(
"BannerDisplayed",
_("Banner is displayed"),
_("Return true if the object is currently displaying a banner"),
_("_PARAM0_ is displaying a banner"),
"",
"JsPlatform/Extensions/admobicon24.png",
"JsPlatform/Extensions/admobicon16.png")
.AddParameter("object", _("Object"), "AdMob");
obj.AddAction("PreloadInterstitial",
_("Preload interstitial screen"),
_("Preload the interstitial screen in memory, so that it can "
"be shown later.\nYou can use this action at the beginning "
"of a level for example."),
_("Preload an interstitial screen for _PARAM0_"),
_("Interstitial screen"),
"JsPlatform/Extensions/admobicon24.png",
"JsPlatform/Extensions/admobicon16.png")
.AddParameter("object", _("Object"), "AdMob");
obj.AddAction(
"ShowInterstitial",
_("Show interstitial screen"),
_("Show the interstitial screen.\nIf the interstitial screen has not "
"been preloaded, it will be loaded and displayed when ready."),
_("Show the interstitial screen of _PARAM0_"),
_("Interstitial screen"),
"JsPlatform/Extensions/admobicon24.png",
"JsPlatform/Extensions/admobicon16.png")
.AddParameter("object", _("Object"), "AdMob");
obj.AddCondition("InterstitialReady",
_("Interstitial screen is ready"),
_("Return true if the interstitial screen was loaded and is "
"ready to be shown."),
_("Interstitial screen of _PARAM0_ is ready"),
"",
"JsPlatform/Extensions/admobicon24.png",
"JsPlatform/Extensions/admobicon16.png")
.AddParameter("object", _("Object"), "AdMob");
}

View File

@@ -1,66 +0,0 @@
/**
GDevelop - AdMob Object Extension
Copyright (c) 2008-2016 Florian Rival (Florian.Rival@gmail.com)
This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#include "GDCore/Extensions/PlatformExtension.h"
#include "AdMobObject.h"
#include <iostream>
#include "GDCore/Tools/Localization.h"
void DeclareAdMobObjectExtension(gd::PlatformExtension& extension);
/**
* \brief This class declares information about the JS extension.
*/
class AdMobObjectJsExtension : public gd::PlatformExtension {
public:
/**
* Constructor of an extension declares everything the extension contains:
* objects, actions, conditions and expressions.
*/
AdMobObjectJsExtension() {
DeclareAdMobObjectExtension(*this);
GetObjectMetadata("AdMobObject::AdMob")
.SetIncludeFile("Extensions/AdMobObject/admobruntimeobject.js");
GetAllActionsForObject("AdMobObject::AdMob")["AdMobObject::ShowBanner"]
.SetFunctionName("showBanner");
GetAllActionsForObject("AdMobObject::AdMob")["AdMobObject::HideBanner"]
.SetFunctionName("hideBanner");
GetAllConditionsForObject(
"AdMobObject::AdMob")["AdMobObject::BannerDisplayed"]
.SetFunctionName("isBannerDisplayed");
GetAllActionsForObject(
"AdMobObject::AdMob")["AdMobObject::PreloadInterstitial"]
.SetFunctionName("prepareInterstitial");
GetAllActionsForObject(
"AdMobObject::AdMob")["AdMobObject::ShowInterstitial"]
.SetFunctionName("showInterstitial");
GetAllConditionsForObject(
"AdMobObject::AdMob")["AdMobObject::InterstitialReady"]
.SetFunctionName("isInterstitialReady");
GD_COMPLETE_EXTENSION_COMPILATION_INFORMATION();
};
};
#if defined(EMSCRIPTEN)
extern "C" gd::PlatformExtension* CreateGDJSAdMobObjectExtension() {
return new AdMobObjectJsExtension;
}
#else
/**
* Used by GDevelop to create the extension class
* -- Do not need to be modified. --
*/
extern "C" gd::PlatformExtension* GD_EXTENSION_API CreateGDJSExtension() {
return new AdMobObjectJsExtension;
}
#endif
#endif

View File

@@ -1,160 +0,0 @@
/**
GDevelop - AdMob Object Extension
Copyright (c) 2008-2016 Florian Rival (Florian.Rival@gmail.com)
This project is released under the MIT License.
*/
if (typeof AdMob !== "undefined")
console.warn("AdMob plugin for Cordova is not installed - no ads will be displayed. Ensure you have installed com.google.cordova.admob or cordova-plugin-admobpro.");
/**
* The AdMobRuntimeObject displays an AdMob ad banner on screen.
* This works with Cordova compatible platforms with `cordova-plugin-admobpro` plugin installed.
*
* @memberof gdjs
* @class AdMobRuntimeObject
* @extends RuntimeObject
* @memberof gdjs
*/
gdjs.AdMobRuntimeObject = function(runtimeScene, objectData)
{
gdjs.RuntimeObject.call(this, runtimeScene, objectData);
this._androidBannerId = objectData.androidBannerId;
this._androidInterstitialId = objectData.androidInterstitialId;
this._iosBannerId = objectData.iosBannerId;
this._iosInterstitialId = objectData.iosInterstitialId;
this._isTesting = objectData.isTesting;
this._position = objectData.position;
this._overlap = objectData.overlap;
this._showOnStartup = objectData.showOnStartup;
this._bannerDisplayed = false;
this._interstitialReady = false;
if (this._showOnStartup)
this.createBanner();
document.addEventListener('onAdPresent', this._onAdPresent.bind(this), false);
document.addEventListener('onAdDismiss', this._onAdDismiss.bind(this), false);
};
gdjs.AdMobRuntimeObject.prototype = Object.create( gdjs.RuntimeObject.prototype );
gdjs.AdMobRuntimeObject.thisIsARuntimeObjectConstructor = "AdMobObject::AdMob";
gdjs.AdMobRuntimeObject.getPlatformName = function() {
if( /(android)/i.test(navigator.userAgent) ) {
return "android";
} else if(/(ipod|iphone|ipad)/i.test(navigator.userAgent)) {
return "ios";
} else {
return "windowsPhone";
}
};
gdjs.AdMobRuntimeObject.prototype._onAdPresent = function(data) {
if (data.adType == 'interstitial')
this._interstitialReady = false;
};
gdjs.AdMobRuntimeObject.prototype._onAdDismiss = function(data) {
if (data.adType == 'interstitial')
this._interstitialReady = false;
};
gdjs.AdMobRuntimeObject.prototype.createBanner = function() {
if (typeof AdMob === "undefined") return;
var adName = "_" + gdjs.AdMobRuntimeObject.getPlatformName() + "BannerId";
if (!this.hasOwnProperty(adName)) return;
var adId = this[adName];
var position = AdMob.AD_POSITION.TOP_CENTER;
if (this._position === "Bottom")
position = AdMob.AD_POSITION.BOTTOM_CENTER;
var that = this;
AdMob.createBanner({
adId: adId || 'not-specified-xxx', //Avoid a crash by never letting the id empty.
position: position,
autoShow: true,
overlap: this._overlap,
isTesting: this._isTesting
}, function() {
that._bannerDisplayed = true;
}, function() {
that._bannerDisplayed = false;
});
};
gdjs.AdMobRuntimeObject.prototype.showBanner = function() {
if (typeof AdMob === "undefined") return;
if (!this._bannerDisplayed)
this.createBanner();
}
gdjs.AdMobRuntimeObject.prototype.hideBanner = function() {
if (typeof AdMob === "undefined") return;
this._bannerDisplayed = false;
AdMob.removeBanner();
};
gdjs.AdMobRuntimeObject.prototype.isBannerDisplayed = function() {
return this._bannerDisplayed;
};
gdjs.AdMobRuntimeObject.prototype.showInterstitial = function(runtimeScene) {
if (typeof AdMob === "undefined") return;
if (!this._interstitialReady) {
this.prepareInterstitial(function() {
AdMob.showInterstitial();
})
} else {
AdMob.showInterstitial();
}
};
gdjs.AdMobRuntimeObject.prototype.prepareInterstitial = function(cb) {
if (typeof AdMob === "undefined") return;
var adName = "_" + gdjs.AdMobRuntimeObject.getPlatformName() + "InterstitialId";
if (!this.hasOwnProperty(adName)) return;
var adId = this[adName];
var that = this;
AdMob.prepareInterstitial({
adId: adId || 'not-specified-xxx', //Avoid a crash by never letting the id empty.
autoShow: false
}, function() {
that._interstitialReady = true;
cb();
}, function() {
that._interstitialReady = false;
cb();
});
};
gdjs.AdMobRuntimeObject.prototype.isInterstitialReady = function() {
return this._interstitialReady;
};
gdjs.AdMobRuntimeObject.prototype.onDeletedFromScene = function(runtimeScene) {
gdjs.RuntimeObject.prototype.onDeletedFromScene.call(this, runtimeScene);
if (typeof AdMob === "undefined") return;
document.removeEventListener('onAdPresent', this._onAdPresent, false);
document.removeEventListener('onAdDismiss', this._onAdDismiss, false);
if (this._bannerDisplayed) this.hideBanner();
};
gdjs.AdMobRuntimeObject.prototype.setLayer = function(layer) {
// No renderable object
};
gdjs.AdMobRuntimeObject.prototype.setZOrder = function(z) {
// No renderable object
};

View File

@@ -45,9 +45,6 @@ gdjs.AnchorRuntimeBehavior.prototype.onActivate = function() {
};
gdjs.AnchorRuntimeBehavior.prototype.doStepPreEvents = function(runtimeScene) {
};
gdjs.AnchorRuntimeBehavior.prototype.doStepPostEvents = function(runtimeScene) {
var game = runtimeScene.getGame();
var rendererWidth = game.getRenderer().getCurrentWidth();
var rendererHeight = game.getRenderer().getCurrentHeight();
@@ -160,3 +157,6 @@ gdjs.AnchorRuntimeBehavior.prototype.doStepPostEvents = function(runtimeScene) {
this.owner.setY(topLeftCoord[1] + this.owner.getY() - this.owner.getDrawableY());
}
};
gdjs.AnchorRuntimeBehavior.prototype.doStepPostEvents = function(runtimeScene) {
};

View File

@@ -8,7 +8,6 @@ project(GD-Extensions)
include(CMakeUtils.txt) #Functions to factor common tasks done in CMakeLists.txt of extensions
#Add all the CMakeLists:
ADD_SUBDIRECTORY(AdMobObject)
ADD_SUBDIRECTORY(AnchorBehavior)
IF (NOT EMSCRIPTEN)
ADD_SUBDIRECTORY(AdvancedXML)

View File

@@ -38,10 +38,18 @@ gdjs.DestroyOutsideRuntimeBehavior.prototype.doStepPostEvents = function(runtime
}
};
/**
* Set an additional border to the camera viewport as a buffer before the object gets destroyed.
* @param {number} val Border in pixels.
*/
gdjs.DestroyOutsideRuntimeBehavior.prototype.setExtraBorder = function(val) {
this._extraBorder = val;
};
/**
* Get the additional border of the camera viewport buffer which triggers the destruction of an object.
* @return {number} The additional border around the camera viewport in pixels
*/
gdjs.DestroyOutsideRuntimeBehavior.prototype.getExtraBorder = function() {
return this._extraBorder;
};

View File

@@ -29,6 +29,10 @@ gdjs.DraggableRuntimeBehavior.prototype.onDeActivate = function() {
this._endDrag();
};
gdjs.DraggableRuntimeBehavior.prototype.ownerRemovedFromScene = function() {
this.onDeActivate();
};
gdjs.DraggableRuntimeBehavior.prototype._endDrag = function() {
if ( this._dragged && this._mouse ) gdjs.DraggableRuntimeBehavior.mouseDraggingSomething = false;
if ( this._dragged && this._touchId !== null ) gdjs.DraggableRuntimeBehavior.touchDraggingSomething[this._touchId] = false;

View File

@@ -183,6 +183,154 @@ module.exports = {
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.getPlayerEntry");
extension
.addCondition(
"AreAdsSupported",
t("Check if ads are supported"),
t("Check if showind ads is supported on this device (only mobile phones can show ads)"),
t("Ads can be shown on this device"),
t("Facebook Instant Games/Ads"),
"JsPlatform/Extensions/facebookicon24.png",
"JsPlatform/Extensions/facebookicon16.png"
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.areAdsSupported");
extension
.addCondition(
"IsInterstitialAdReady",
t("Is the interstitial ad ready"),
t("Check if the interstitial ad requested from Facebook is loaded and ready to be shown."),
t("The interstitial ad is loaded and ready to be shown"),
t("Facebook Instant Games/Ads"),
"JsPlatform/Extensions/facebookicon24.png",
"JsPlatform/Extensions/facebookicon16.png"
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.isInterstitialAdReady");
extension
.addAction(
"LoadInterstitialAd",
t("Load and prepare an interstitial ad"),
t("Request and load an interstitial ad from Facebook, so that it is ready to be shown."),
t("Request and load an interstitial ad from Facebook (ad placement id: _PARAM0_, error in _PARAM1_)"),
t("Facebook Instant Games/Ads"),
"JsPlatform/Extensions/facebookicon24.png",
"JsPlatform/Extensions/facebookicon16.png"
)
.addParameter(
"string",
t("The Ad Placement id (can be found while setting up the ad on Facebook)"),
"",
false
)
.addParameter(
"scenevar",
t("Variable where to error message (optional, if an error occurs)"),
"",
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.loadInterstitialAd");
extension
.addAction(
"ShowInterstitialAd",
t("Show the loaded interstitial ad"),
t("Show the interstitial ad previously loaded in memory. This won't work if you did not load the interstitial before."),
t("Show the interstitial ad previously loaded in memory (if any error, store it in _PARAM0_)"),
t("Facebook Instant Games/Ads"),
"JsPlatform/Extensions/facebookicon24.png",
"JsPlatform/Extensions/facebookicon16.png"
)
.addParameter(
"scenevar",
t("Variable where to error message (optional, if an error occurs)"),
"",
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.showInterstitialAd");
extension
.addCondition(
"IsRewardedVideoReady",
t("Is the rewarded video ready"),
t("Check if the rewarded video requested from Facebook is loaded and ready to be shown."),
t("The rewarded video is loaded and ready to be shown"),
t("Facebook Instant Games/Ads"),
"JsPlatform/Extensions/facebookicon24.png",
"JsPlatform/Extensions/facebookicon16.png"
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.isRewardedVideoReady");
extension
.addAction(
"LoadRewardedVideo",
t("Load and prepare a rewarded video"),
t("Request and load a rewarded video from Facebook, so that it is ready to be shown."),
t("Request and load a rewarded video from Facebook (ad placement id: _PARAM0_, error in _PARAM1_)"),
t("Facebook Instant Games/Ads"),
"JsPlatform/Extensions/facebookicon24.png",
"JsPlatform/Extensions/facebookicon16.png"
)
.addParameter(
"string",
t("The Ad Placement id (can be found while setting up the ad on Facebook)"),
"",
false
)
.addParameter(
"scenevar",
t("Variable where to error message (optional, if an error occurs)"),
"",
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.loadRewardedVideo");
extension
.addAction(
"ShowRewardedVideo",
t("Show the loaded rewarded video"),
t("Show the rewarded video previously loaded in memory. This won't work if you did not load the video before."),
t("Show the rewarded video previously loaded in memory (if any error, store it in _PARAM0_)"),
t("Facebook Instant Games/Ads"),
"JsPlatform/Extensions/facebookicon24.png",
"JsPlatform/Extensions/facebookicon16.png"
)
.addParameter(
"scenevar",
t("Variable where to error message (optional, if an error occurs)"),
"",
true
)
.getCodeExtraInformation()
.setIncludeFile(
"Extensions/FacebookInstantGames/facebookinstantgamestools.js"
)
.setFunctionName("gdjs.evtTools.facebookInstantGames.showRewardedVideo");
extension
.addStrExpression(
"PlayerId",

View File

@@ -4,7 +4,24 @@
* @static
* @private
*/
gdjs.evtTools.facebookInstantGames = {};
gdjs.evtTools.facebookInstantGames = {
_preloadedInterstitial: null,
_preloadedInterstitialLoading: false,
_preloadedInterstitialLoaded: false,
_preloadedRewardedVideo: null,
_preloadedRewardedVideoLoading: false,
_preloadedRewardedVideoLoaded: false
};
gdjs.evtTools.facebookInstantGames.areAdsSupported = function() {
if (typeof FBInstant === "undefined") return false;
var supportedAPIs = FBInstant.getSupportedAPIs();
return (
supportedAPIs.indexOf("getInterstitialAdAsync") !== -1 &&
supportedAPIs.indexOf("getRewardedVideoAsync") !== -1
);
};
gdjs.evtTools.facebookInstantGames.getPlayerId = function() {
if (typeof FBInstant === "undefined") return "";
@@ -102,7 +119,9 @@ gdjs.evtTools.facebookInstantGames.getPlayerEntry = function(
})
.then(function(entry) {
rankVariable.setNumber(entry.getRank() === null ? -1 : entry.getRank());
scoreVariable.setNumber(entry.getScore() === null ? -1 : entry.getScore());
scoreVariable.setNumber(
entry.getScore() === null ? -1 : entry.getScore()
);
gdjs.evtTools.network.jsonToVariableStructure(
entry.getExtraData(),
extraDataVariable
@@ -113,9 +132,123 @@ gdjs.evtTools.facebookInstantGames.getPlayerEntry = function(
});
};
if (typeof FBInstant === "undefined" && typeof window !== "undefined") {
console.log("Creating a mocked version of Facebook Instant Games");
gdjs.evtTools.facebookInstantGames.loadInterstitialAd = function(
adPlacementId,
errorVariable
) {
if (typeof FBInstant === "undefined") return;
if (
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoading ||
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoaded
)
return;
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoading = true;
FBInstant.getInterstitialAdAsync(adPlacementId)
.then(function(interstitial) {
gdjs.evtTools.facebookInstantGames._preloadedInterstitial = interstitial;
return interstitial.loadAsync();
})
.then(function() {
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoading = false;
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoaded = true;
console.info("Facebook Instant Games interstitial preloaded.");
})
.catch(function(err) {
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoading = false;
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoaded = false;
console.error("Interstitial failed to preload: " + err.message);
errorVariable.setString(error.message || "Unknown error");
});
};
gdjs.evtTools.facebookInstantGames.showInterstitialAd = function(
errorVariable
) {
if (typeof FBInstant === "undefined") return;
if (!gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoaded) return;
gdjs.evtTools.facebookInstantGames._preloadedInterstitial
.showAsync()
.then(function() {
console.info("Facebook Instant Games interstitial shown.");
})
.catch(function(err) {
console.error("Interstitial failed to show: " + err.message);
errorVariable.setString(error.message || "Unknown error");
})
.then(function() {
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoaded = false;
});
};
gdjs.evtTools.facebookInstantGames.isInterstitialAdReady = function() {
return gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoaded;
};
gdjs.evtTools.facebookInstantGames.loadRewardedVideo = function(
adPlacementId,
errorVariable
) {
if (typeof FBInstant === "undefined") return;
if (
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoading ||
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoaded
)
return;
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoading = true;
FBInstant.getRewardedVideoAsync(adPlacementId)
.then(function(rewardedVideo) {
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideo = rewardedVideo;
return rewardedVideo.loadAsync();
})
.then(function() {
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoading = false;
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoaded = true;
console.info("Facebook Instant Games rewarded video preloaded.");
})
.catch(function(err) {
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoading = false;
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoaded = false;
console.error("Rewarded video failed to preload: " + err.message);
errorVariable.setString(error.message || "Unknown error");
});
};
gdjs.evtTools.facebookInstantGames.showRewardedVideo = function(errorVariable) {
if (typeof FBInstant === "undefined") return;
if (!gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoaded) return;
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideo
.showAsync()
.then(function() {
console.info("Facebook Instant Games rewarded video shown.");
})
.catch(function(err) {
console.error("Rewarded video failed to show: " + err.message);
errorVariable.setString(error.message || "Unknown error");
})
.then(function() {
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoaded = false;
});
};
gdjs.evtTools.facebookInstantGames.isRewardedVideoReady = function() {
return gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoaded;
};
if (typeof FBInstant === "undefined" && typeof window !== "undefined") {
console.log("Creating a mocked version of Facebook Instant Games.");
/**
* A mocked Leaderboard, part of the mock of FBInstant.
* @class MockedLeaderboard
*/
function MockedLeaderboard() {
this._playerScore = null;
this._playerRank = null;
@@ -147,6 +280,49 @@ if (typeof FBInstant === "undefined" && typeof window !== "undefined") {
});
};
/**
* A mocked RewardedVideo, part of the mock of FBInstant.
* @class RewardedVideo
*/
function MockedRewardedVideo() {
this._isLoaded = false;
}
MockedRewardedVideo.prototype.loadAsync = function() {
this._isLoaded = true;
return Promise.resolve();
};
MockedRewardedVideo.prototype.showAsync = function() {
if (this._isLoaded) {
console.info(
"In a real Instant Game, a video reward should have been shown to the user."
);
return Promise.resolve();
}
return Promise.reject(new Error("Rewarded video is not loaded."));
};
/**
* A mocked MockedInterstitial, part of the mock of FBInstant.
* @class MockedInterstitial
*/
function MockedInterstitial() {
this._isLoaded = false;
}
MockedInterstitial.prototype.loadAsync = function() {
this._isLoaded = true;
return Promise.resolve();
};
MockedInterstitial.prototype.showAsync = function() {
if (this._isLoaded) {
console.info(
"In a real Instant Game, an interstitial should have been shown to the user."
);
return Promise.resolve();
}
return Promise.reject(new Error("Interstitial is not loaded."));
};
var supportedAPIs = [];
var FBInstantMock = {
_mockedPlayerData: {},
_mockedLeaderboards: {},
@@ -176,8 +352,30 @@ if (typeof FBInstant === "undefined" && typeof window !== "undefined") {
new MockedLeaderboard();
resolve(FBInstantMock._mockedLeaderboards[leaderboardName]);
});
},
getInterstitialAdAsync: function() {
return Promise.resolve(new MockedInterstitial());
},
getRewardedVideoAsync: function() {
return Promise.resolve(new MockedRewardedVideo());
},
getSupportedAPIs: function() {
return supportedAPIs;
}
};
// Retrieve the name of the supported APIs in our mock.
for (var property in FBInstantMock) {
if (typeof FBInstantMock[property] == "object") {
for (var subProperty in FBInstantMock[property]) {
if (typeof FBInstantMock[property][subProperty] == "function") {
supportedAPIs.push(property + "." + subProperty);
}
}
} else if (typeof FBInstantMock[property] == "function") {
supportedAPIs.push(property);
}
}
window.FBInstant = FBInstantMock;
}

View File

@@ -59,38 +59,71 @@ gdjs.PanelSpriteRuntimeObject.prototype.extraInitializationFromInitialInstance =
}
};
/**
* Set the x position of the panel sprite.
* @param {number} x The new x position in pixels.
*/
gdjs.PanelSpriteRuntimeObject.prototype.setX = function(x) {
gdjs.RuntimeObject.prototype.setX.call(this, x);
this._renderer.updatePosition();
};
/**
* Set the y position of the panel sprite.
* @param {number} y The new y position in pixels.
*/
gdjs.PanelSpriteRuntimeObject.prototype.setY = function(y) {
gdjs.RuntimeObject.prototype.setY.call(this, y);
this._renderer.updatePosition();
};
/**
* Set the texture of the panel sprite.
* @param {string} textureName The name of the texture.
* @param {gdjs.RuntimeScene} runtimeScene The scene the object lives in.
*/
gdjs.PanelSpriteRuntimeObject.prototype.setTexture = function(textureName, runtimeScene) {
this._renderer.setTexture(textureName, runtimeScene);
};
/**
* Set the angle of the panel sprite.
* @param {number} angle The new angle in degrees.
*/
gdjs.PanelSpriteRuntimeObject.prototype.setAngle = function(angle) {
gdjs.RuntimeObject.prototype.setAngle.call(this, angle);
this._renderer.updateAngle();
};
/**
* Get the width of the panel sprite in pixels
* @return {number} The width in pixels
*/
gdjs.PanelSpriteRuntimeObject.prototype.getWidth = function() {
return this._width;
};
/**
* Get the height of the panel sprite in pixels
* @return {number} The height in pixels
*/
gdjs.PanelSpriteRuntimeObject.prototype.getHeight = function() {
return this._height;
};
/**
* Set the width of the panel sprite.
* @param {number} width The new width in pixels.
*/
gdjs.PanelSpriteRuntimeObject.prototype.setWidth = function(width) {
this._width = width;
this._renderer.updateWidth();
};
/**
* Set the height of the panel sprite.
* @param {number} height The new height in pixels.
*/
gdjs.PanelSpriteRuntimeObject.prototype.setHeight = function(height) {
this._height = height;
this._renderer.updateHeight();

View File

@@ -27,12 +27,13 @@ gdjs.ParticleEmitterObjectCocosRenderer = function(runtimeScene, runtimeObject,
}
else{
if(objectData.textureParticleName){
// Read the comment at gdjs.ParticleEmitterObjectCocosRenderer.prototype.setTexture
var imageManager = runtimeScene.getGame().getImageManager();
var sprite = new cc.Sprite(imageManager.getTexture(objectData.textureParticleName));
this.originalSize = Math.max(sprite.width, sprite.height);
sprite.setPosition( this.originalSize/2.0, this.originalSize/2.0);
sprite.setPosition(this.originalSize/2.0, this.originalSize/2.0);
drawer.addChild(sprite);
renderTexture = new cc.RenderTexture( this.originalSize, this.originalSize);
renderTexture = new cc.RenderTexture(this.originalSize, this.originalSize);
}
else{
drawer.drawRect(cc.p((this.originalSize - objectData.rendererParam1)/2.0,
@@ -163,17 +164,13 @@ gdjs.ParticleEmitterObjectCocosRenderer = function(runtimeScene, runtimeObject,
plist.finishParticleSizeVariance = plist.startParticleSizeVariance;
}
if(objectData.angleParam === "Mutable"){
plist.rotationStart = objectData.particleAngle1 + (objectData.particleAngleRandomness1 + objectData.particleAngleRandomness2)/2.0;
plist.rotationEnd = objectData.particleAngle2 + (objectData.particleAngleRandomness1 + objectData.particleAngleRandomness2)/2.0;
plist.rotationStartVariance = Math.abs(objectData.particleAngleRandomness2 - objectData.particleAngleRandomness1)/2.0;
plist.rotationEndVariance = plist.rotationStartVariance;
}
else{
plist.rotationStart = plist.rotationEnd = (objectData.particleAngleRandomness1 + objectData.particleAngleRandomness2)/2.0;
plist.rotationStartVariance = Math.abs(objectData.particleAngleRandomness2 - objectData.particleAngleRandomness1)/2.0;
plist.rotationEndVariance = plist.rotationStartVariance;
}
var mediumLifetime = (objectData.particleLifeTimeMin + objectData.particleLifeTimeMax)/2.0;
plist.rotationStart = 0.0;
plist.rotationStartVariance = 0.0;
plist.rotationEnd = (objectData.particleAngle1 + objectData.particleAngle2)/2.0 * mediumLifetime;
plist.rotationEndVariance = (Math.max(objectData.particleAngle1, objectData.particleAngle2) -
Math.min(objectData.particleAngle1, objectData.particleAngle2)) *
mediumLifetime / 2.0;
this.renderer = new cc.ParticleSystem(plist);
this.renderer.setTexture(texture);
@@ -273,7 +270,23 @@ gdjs.ParticleEmitterObjectCocosRenderer.prototype.isTextureValid = function(text
gdjs.ParticleEmitterObjectCocosRenderer.prototype.setTexture = function(texture, runtimeScene){
var texture = runtimeScene.getGame().getImageManager().getTexture(texture);
if(texture._textureLoaded){
this.renderer.setTexture(texture);
if(texture.width === texture.height){
this.originalSize = texture.width;
this.renderer.setTexture(texture);
}
// Cocos particles are always square, so if the new texture is not squared we have to
// render it over a squared renderTexture object, this way we keep the original
// texture's aspect ratio
else{
var sprite = new cc.Sprite(texture);
this.originalSize = Math.max(sprite.width, sprite.height);
sprite.setPosition(this.originalSize/2.0, this.originalSize/2.0);
var renderTexture = new cc.RenderTexture(this.originalSize, this.originalSize);
renderTexture.begin();
sprite.visit();
renderTexture.end();
this.renderer.setTexture(renderTexture.getSprite().getTexture());
}
}
};

View File

@@ -132,16 +132,9 @@ gdjs.ParticleEmitterObjectPixiRenderer = function(runtimeScene, runtimeObject, o
max: objectData.emitterAngleB };
}
if(objectData.angleParam === "Mutable"){
var mediumLifetime = (objectData.particleLifeTimeMin + objectData.particleLifeTimeMax)/2;
config.rotationSpeed = { min: objectData.particleAngle1/mediumLifetime,
max: objectData.particleAngle2/mediumLifetime };
}
else{
config.startRotation = { min: objectData.particleAngle1,
max: objectData.particleAngle2 };
config.rotationSpeed = { min: 0, max: 0 };
}
var mediumLifetime = (objectData.particleLifeTimeMin + objectData.particleLifeTimeMax)/2.0;
config.rotationSpeed = { min: objectData.particleAngle1/mediumLifetime,
max: objectData.particleAngle2/mediumLifetime };
config.blendMode = objectData.additive ? "ADD" : "NORMAL";

View File

@@ -152,10 +152,6 @@ gdjs.PlatformRuntimeBehavior.prototype.doStepPreEvents = function(runtimeScene)
gdjs.PlatformRuntimeBehavior.prototype.doStepPostEvents = function(runtimeScene) {
};
gdjs.PlatformRuntimeBehavior.prototype.getAABB = function(){
return this.owner.getAABB();
};
gdjs.PlatformRuntimeBehavior.prototype.onActivate = function() {
if (this._registeredInManager) return;

View File

@@ -41,6 +41,10 @@ gdjs.ShapePainterRuntimeObject.prototype.stepBehaviorsPreEvents = function(runti
gdjs.RuntimeObject.prototype.stepBehaviorsPreEvents.call(this, runtimeScene);
};
gdjs.ShapePainterRuntimeObject.prototype.getVisibilityAABB = function() {
return this._absoluteCoordinates ? null : this.getAABB();
};
gdjs.ShapePainterRuntimeObject.prototype.drawRectangle = function(x1, y1, x2, y2) {
this._renderer.drawRectangle(x1, y1, x2, y2);
};
@@ -95,12 +99,16 @@ gdjs.ShapePainterRuntimeObject.prototype.getOutlineOpacity = function() {
};
gdjs.ShapePainterRuntimeObject.prototype.setX = function(x) {
this.x = x;
if ( x === this.x ) return;
gdjs.RuntimeObject.prototype.setX.call(this, x);
this._renderer.updateXPosition();
};
gdjs.ShapePainterRuntimeObject.prototype.setY = function(y) {
this.y = y;
if ( y === this.y ) return;
gdjs.RuntimeObject.prototype.setY.call(this, y);
this._renderer.updateYPosition();
};

View File

@@ -35,7 +35,7 @@ TextObjectEditor::TextObjectEditor(wxWindow* parent,
// Update from the text object
m_textCtrl->SetValue(object.GetString());
m_fontTextCtrl->SetValue(object.GetFontFilename());
m_fontTextCtrl->SetValue(object.GetFontName());
m_sizeCombobox->SetValue(gd::String::From<float>(object.GetCharacterSize()));
textColor =
wxColour(object.GetColorR(), object.GetColorG(), object.GetColorB());
@@ -56,7 +56,7 @@ TextObjectEditor::~TextObjectEditor() {}
void TextObjectEditor::OnOkBtClicked(wxCommandEvent& event) {
// Update the text object
object.SetString(m_textCtrl->GetValue());
object.SetFontFilename(m_fontTextCtrl->GetValue());
object.SetFontName(m_fontTextCtrl->GetValue());
object.SetCharacterSize(gd::String(m_sizeCombobox->GetValue()).To<float>());
object.SetColor(textColor.Red(), textColor.Green(), textColor.Blue());
object.SetBold(m_toolbar->GetToolToggled(BOLD_TOOL_ID));

View File

@@ -15,12 +15,13 @@ This project is released under the MIT License.
#include "TextObject.h"
void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
extension.SetExtensionInformation(
"TextObject",
_("Text object"),
_("This Extension enables the use of an object that displays text."),
"Florian Rival and Victor Levasseur",
"Open source (MIT License)")
extension
.SetExtensionInformation(
"TextObject",
_("Text object"),
_("This Extension enables the use of an object that displays text."),
"Florian Rival and Victor Levasseur",
"Open source (MIT License)")
.SetExtensionHelpPath("/objects/text");
gd::ObjectMetadata& obj =
@@ -65,7 +66,7 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
obj.AddAction("Font",
_("Font"),
_("Modify the font of the text."),
_("Change the font of the text."),
_("Change font of _PARAM0_ to _PARAM1_"),
_("Font"),
"res/actions/font24.png",
@@ -78,7 +79,7 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
obj.AddAction("Size",
_("Size"),
_("Modify the size of the text."),
_("Change the size of the text."),
_("Do _PARAM1__PARAM2_ to the size of the text of _PARAM0_"),
_(""),
"res/actions/characterSize24.png",
@@ -94,7 +95,7 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
obj.AddCondition("Size",
_("Size"),
_("Test the size of the text"),
_("Compare the size of the text"),
_("The size of the text of _PARAM0_ is _PARAM1__PARAM2_"),
_(""),
"res/conditions/characterSize24.png",
@@ -122,8 +123,9 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
.SetIncludeFile("TextObject/TextObject.h");
obj.AddAction("Opacity",
_("Opacity"),
_("Modify the opacity of a Text object."),
_("Change Text Opacity"),
_("Change the opacity of a Text. 0 is fully transparent, 255 "
"is opaque (default)."),
_("Do _PARAM1__PARAM2_ to the opacity of _PARAM0_"),
_(""),
"res/actions/opacity24.png",
@@ -139,7 +141,8 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
obj.AddCondition("Opacity",
_("Opacity"),
_("Test the value of the opacity of a Text object."),
_("Compare the opacity of a Text object, between 0 (fully "
"transparent) to 255 (opaque)."),
_("The opacity of _PARAM0_ is _PARAM1__PARAM2_"),
_(""),
"res/conditions/opacity24.png",
@@ -167,7 +170,7 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
obj.AddCondition("Smoothed",
_("Smoothing"),
_("Test if an object is smoothed"),
_("Check if an object is smoothed"),
_("_PARAM0_ is smoothed"),
_("Style"),
"res/conditions/opacity24.png",
@@ -192,7 +195,7 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
obj.AddCondition("IsBold",
_("Bold"),
_("Test if the bold style is activated"),
_("Check if the bold style is activated"),
_("_PARAM0_ bold style is set"),
_("Style"),
"res/conditions/bold.png",
@@ -217,7 +220,7 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
obj.AddCondition("IsItalic",
_("Italic"),
_("Test if the italic style is activated"),
_("Check if the italic style is activated"),
_("_PARAM0_ italic style is set"),
_("Style"),
"res/conditions/italic.png",
@@ -242,7 +245,7 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
obj.AddCondition("IsUnderlined",
_("Underlined"),
_("Test if the underlined style of an object is set."),
_("Check if the underlined style of an object is set."),
_("_PARAM0_ underlined style is activated"),
_("Style"),
"res/conditions/underline.png",
@@ -270,7 +273,7 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
obj.AddCondition("Angle",
_("Angle"),
_("Test the value of the angle of a Text object."),
_("Compare the value of the angle of a Text object."),
_("The angle of _PARAM0_ is _PARAM1__PARAM2_"),
_("Rotation"),
"res/conditions/rotate24.png",
@@ -283,9 +286,58 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
.SetManipulatedType("number")
.SetIncludeFile("TextObject/TextObject.h");
obj.AddAction(
"SetWrapping",
_("Wrapping"),
_("De/activate word wrapping. Note that word wrapping is a graphical "
"option,\nyou can't get the number of lines displayed"),
_("Set word wrapping style of _PARAM0_: _PARAM1_"),
_("Style"),
"res/actions/wordWrap24.png",
"res/actions/wordWrap.png")
.AddParameter("object", _("Object"), "Text")
.AddParameter("yesorno", _("Wrapping"));
obj.AddCondition("IsWrapping",
_("Wrapping"),
_("Test if the word wrapping style of an object is set."),
_("_PARAM0_ word wrapping style is activated"),
_("Style"),
"res/conditions/wordWrap24.png",
"res/conditions/wordWrap.png")
.AddParameter("object", _("Object"), "Text");
obj.AddAction("WrappingWidth",
_("Wrapping width"),
_("Modify the word wrapping width of a Text object."),
_("Do _PARAM1__PARAM2_ to the wrapping width of _PARAM0_"),
_("Style"),
"res/actions/wordWrap24.png",
"res/actions/wordWrap.png")
.AddParameter("object", _("Object"), "Text")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddCondition("WrappingWidth",
_("Wrapping width"),
_("Test the word wrapping width of a Text object."),
_("The wrapping width of _PARAM0_ is _PARAM1__PARAM2_"),
_("Style"),
"res/conditions/wordWrap24.png",
"res/conditions/wordWrap.png")
.AddParameter("object", _("Object"), "Text")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to test"))
.SetManipulatedType("number");
obj.AddExpression("Opacity",
_("Opacity"),
_("Opacity"),
_("Opacity of a Text object"),
_("Opacity of a Text object"),
_("Opacity"),
"res/actions/opacity.png")
.AddParameter("object", _("Object"), "Text")

View File

@@ -76,6 +76,21 @@ class TextObjectJsExtension : public gd::PlatformExtension {
.SetFunctionName("isItalic")
.SetIncludeFile("Extensions/TextObject/textruntimeobject.js");
GetAllActionsForObject("TextObject::Text")["TextObject::SetWrapping"]
.SetFunctionName("setWrapping")
.SetIncludeFile("Extensions/TextObject/textruntimeobject.js");
GetAllConditionsForObject("TextObject::Text")["TextObject::IsWrapping"]
.SetFunctionName("isWrapping")
.SetIncludeFile("Extensions/TextObject/textruntimeobject.js");
GetAllActionsForObject("TextObject::Text")["TextObject::WrappingWidth"]
.SetFunctionName("setWrappingWidth")
.SetGetter("getWrappingWidth")
.SetIncludeFile("Extensions/TextObject/textruntimeobject.js");
GetAllConditionsForObject("TextObject::Text")["TextObject::WrappingWidth"]
.SetFunctionName("getWrappingWidth")
.SetIncludeFile("Extensions/TextObject/textruntimeobject.js");
GetAllExpressionsForObject("TextObject::Text")["Opacity"]
.SetFunctionName("getOpacity")
.SetIncludeFile("Extensions/TextObject/textruntimeobject.js");

View File

@@ -54,7 +54,7 @@ TextObject::~TextObject(){};
void TextObject::DoUnserializeFrom(gd::Project& project,
const gd::SerializerElement& element) {
SetString(element.GetChild("string", 0, "String").GetValue().GetString());
SetFontFilename(element.GetChild("font", 0, "Font").GetValue().GetString());
SetFontName(element.GetChild("font", 0, "Font").GetValue().GetString());
SetCharacterSize(element.GetChild("characterSize", 0, "CharacterSize")
.GetValue()
.GetInt());
@@ -119,7 +119,7 @@ void TextObject::LoadResources(gd::Project& project, gd::Layout& layout) {
void TextObject::DoSerializeTo(gd::SerializerElement& element) const {
element.AddChild("string").SetValue(GetString());
element.AddChild("font").SetValue(GetFontFilename());
element.AddChild("font").SetValue(GetFontName());
element.AddChild("characterSize").SetValue(GetCharacterSize());
element.AddChild("color")
.SetAttribute("r", (int)GetColorR())
@@ -133,7 +133,7 @@ void TextObject::DoSerializeTo(gd::SerializerElement& element) const {
}
void TextObject::ExposeResources(gd::ArbitraryResourceWorker& worker) {
worker.ExposeFile(fontName);
worker.ExposeFont(fontName);
}
bool TextObject::GenerateThumbnail(const gd::Project& project,
@@ -157,19 +157,12 @@ void TextObject::EditObject(wxWindow* parent,
}
#endif
void TextObject::SetFontFilename(const gd::String& fontFilename) {
fontName = fontFilename;
#if defined(GD_IDE_ONLY)
fontName = gd::AbstractFileSystem::NormalizeSeparator(fontName);
#endif
};
/* RuntimeTextObject : */
RuntimeTextObject::RuntimeTextObject(RuntimeScene& scene,
const TextObject& textObject)
: RuntimeObject(scene, textObject), opacity(255), angle(0) {
ChangeFont(textObject.GetFontFilename());
ChangeFont(textObject.GetFontName());
SetSmooth(textObject.IsSmoothed());
SetColor(
textObject.GetColorR(), textObject.GetColorG(), textObject.GetColorB());
@@ -332,7 +325,7 @@ void RuntimeTextObject::GetPropertyForDebugger(std::size_t propertyNb,
value = GetString();
} else if (propertyNb == 1) {
name = _("Font");
value = GetFontFilename();
value = GetFontName();
} else if (propertyNb == 2) {
name = _("Font Size");
value = gd::String::From(GetCharacterSize());

View File

@@ -15,26 +15,17 @@ This project is released under the MIT License.
class ImageManager;
class RuntimeScene;
namespace gd {
class Project;
class Object;
}
namespace gd {
class ImageManager;
}
namespace gd {
class InitialInstance;
}
#if defined(GD_IDE_ONLY)
class wxBitmap;
namespace gd {
class Project;
}
class wxWindow;
namespace gd {
class MainFrameWrapper;
}
namespace gd {
class ResourcesMergingHelper;
}
#endif
/**
@@ -82,13 +73,13 @@ class GD_EXTENSION_API TextObject : public gd::Object {
*/
inline float GetCharacterSize() const { return characterSize; };
/** \brief Return the font filename.
/** \brief Return the name of the font resource used for the text.
*/
inline const gd::String& GetFontFilename() const { return fontName; };
inline const gd::String& GetFontName() const { return fontName; };
/** \brief Change the font filename.
/** \brief Change the font resource used for the text.
*/
void SetFontFilename(const gd::String& fontFilename);
void SetFontName(const gd::String& resourceName) { fontName = resourceName; };
bool IsBold() const { return bold; };
void SetBold(bool enable) { bold = enable; };
@@ -170,9 +161,9 @@ class GD_EXTENSION_API RuntimeTextObject : public RuntimeObject {
*/
void ChangeFont(const gd::String& fontFilename);
/** \brief Return the font file name.
/** \brief Return the font resource name.
*/
inline gd::String GetFontFilename() const { return fontName; };
inline gd::String GetFontName() const { return fontName; };
void SetFontStyle(int style);
int GetFontStyle();

View File

@@ -1,6 +1,7 @@
gdjs.TextRuntimeObjectCocosRenderer = function(runtimeObject, runtimeScene)
{
this._object = runtimeObject;
this._fontManager = runtimeScene.getGame().getFontManager();
this._text = new cc.LabelTTF(" ", "Arial", 38);
this._text.disableStroke();
@@ -27,13 +28,14 @@ gdjs.TextRuntimeObjectCocosRenderer.prototype.updateStyle = function() {
this._text.setFontSize(this._object._characterSize);
this._text.setFontFillColor(cc.color(this._object._color[0],
this._object._color[1], this._object._color[2]));
this._text._setBoundingWidth(this._object._wrapping ? this._object._wrappingWidth : 0);
var fontName = !this._object._fontName ?
'Arial' :
(
gdjs.CocosTools.isHTML5() ?
'gdjs_font_' + this._object._fontName :
'res/' + this._object._fontName
this._fontManager.getFontFamily(this._object._fontName) :
'res/' + this._fontManager.getFontFile(this._object._fontName)
);
this._text.setFontName(fontName);
};

View File

@@ -1,6 +1,7 @@
gdjs.TextRuntimeObjectPixiRenderer = function(runtimeObject, runtimeScene)
{
this._object = runtimeObject;
this._fontManager = runtimeScene.getGame().getFontManager();
if ( this._text === undefined ) this._text = new PIXI.Text(" ", {align:"left"});
this._text.anchor.x = 0.5;
@@ -28,7 +29,7 @@ gdjs.TextRuntimeObjectPixiRenderer.prototype.ensureUpToDate = function() {
};
gdjs.TextRuntimeObjectPixiRenderer.prototype.updateStyle = function() {
var fontName = this._object._fontName ? "\"gdjs_font_" + this._object._fontName + "\"" : 'Arial';
var fontName = "\"" + this._fontManager.getFontFamily(this._object._fontName) + "\"";
var style = this._text.style;
style.fontStyle = this._object._italic ? 'italic' : 'normal';
@@ -40,6 +41,10 @@ gdjs.TextRuntimeObjectPixiRenderer.prototype.updateStyle = function() {
this._object._color[1],
this._object._color[2]
);
style.wordWrap = this._object._wrapping;
style.wordWrapWidth = this._object._wrappingWidth;
style.breakWords = true;
this.updatePosition();
// Manually ask the PIXI object to re-render as we changed a style property
// see http://www.html5gamedevs.com/topic/16924-change-text-style-post-render/

View File

@@ -20,6 +20,8 @@ gdjs.TextRuntimeObject = function(runtimeScene, objectData)
this._italic = objectData.italic;
this._underlined = objectData.underlined;
this._color = [objectData.color.r, objectData.color.g, objectData.color.b];
this._wrapping = false;
this._wrappingWidth = 1;
this._str = objectData.string;
@@ -40,6 +42,17 @@ gdjs.TextRuntimeObject.prototype.update = function() {
this._renderer.ensureUpToDate();
};
/**
* Initialize the extra parameters that could be set for an instance.
* @private
*/
gdjs.TextRuntimeObject.prototype.extraInitializationFromInitialInstance = function(initialInstanceData) {
if ( initialInstanceData.customSize ) {
this.setWrapping(true);
this.setWrappingWidth(initialInstanceData.width);
}
};
/**
* Update the position object's.
* @private
@@ -187,3 +200,37 @@ gdjs.TextRuntimeObject.prototype.setColor = function(str) {
this._color[2] = parseInt(color[2], 10);
this._renderer.updateStyle();
};
/**
* Return true if word wrapping is enabled for your text.
*/
gdjs.TextRuntimeObject.prototype.isWrapping = function() {
return this._wrapping;
};
/**
* Set word wrapping for your object text.
* @param enable {Boolean} Set it to true to enable word wrapping, false to disable it.
*/
gdjs.TextRuntimeObject.prototype.setWrapping = function(enable) {
this._wrapping = enable;
this._renderer.updateStyle();
};
/**
* Get the word wrapping width for your text object.
*/
gdjs.TextRuntimeObject.prototype.getWrappingWidth = function() {
return this._wrappingWidth;
};
/**
* Set the word wrapping width for your text object.
* @param {number} width The new width to set.
*/
gdjs.TextRuntimeObject.prototype.setWrappingWidth = function(width) {
if (width <= 1) width = 1;
this._wrappingWidth = width;
this._renderer.updateStyle();
};

View File

@@ -351,7 +351,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
gd::String argOutput;
// Code only parameter type
if (metadata.type == "currentScene") {
if (metadata.type == "currentScene" || metadata.type == "objectsContext") {
argOutput += "*runtimeContext->scene";
}
// Code only parameter type

View File

@@ -126,7 +126,6 @@ CppPlatform::CppPlatform() : gd::Platform() {
std::cout.flush();
AddExtension(std::make_shared<ExternalLayoutsExtension>());
std::cout.flush();
std::cout << "done." << std::endl;
}
bool CppPlatform::AddExtension(

View File

@@ -47,8 +47,8 @@ class JsCodeEvent : public gd::BaseEvent {
const gd::String& GetInlineCode() const { return inlineCode; };
void SetInlineCode(const gd::String& code) { inlineCode = code; };
gd::String GetParameterObjects() const { return parameterObjects; };
void SetParameterObjects(gd::String objectName) {
const gd::String& GetParameterObjects() const { return parameterObjects; };
void SetParameterObjects(const gd::String& objectName) {
parameterObjects = objectName;
};

View File

@@ -15,10 +15,11 @@
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/IDE/SceneNameMangler.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/EventsFunction.h"
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/Project.h"
#include "GDJS/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDJS/Events/CodeGeneration/VariableParserCallbacks.h"
@@ -88,15 +89,16 @@ gd::String EventsCodeGenerator::GenerateSceneEventsCompleteCode(
gd::String EventsCodeGenerator::GenerateEventsFunctionCode(
gd::Project& project,
const std::vector<gd::ParameterMetadata>& parameters,
const gd::EventsList& events,
const gd::EventsFunction& eventsFunction,
const gd::String& codeNamespace,
std::set<gd::String>& includeFiles,
bool compilationForRuntime) {
gd::ObjectsContainer objectsAndGroups;
gd::ObjectsContainer
emptyObjectsAndGroups; // As opposed to layout events, we don't have
// objects in the "outer" scope.
gd::ParameterMetadataTools::ParametersToObjectsContainer(
project, parameters, objectsAndGroups);
project, eventsFunction.GetParameters(), objectsAndGroups);
// Prepare the global context
unsigned int maxDepthLevelReached = 0;
@@ -106,8 +108,9 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionCode(
// Generate whole events code
// Preprocessing then code generation can make changes to the events, so we
// need to do the work on a copy of the events.
gd::EventsList generatedEvents = events;
gd::EventsList generatedEvents = eventsFunction.GetEvents();
codeGenerator.SetGenerateCodeForRuntime(compilationForRuntime);
codeGenerator.SetCodeNamespace(codeNamespace);
codeGenerator.PreprocessEventList(generatedEvents);
gd::String wholeEventsCode =
codeGenerator.GenerateEventsListCode(generatedEvents, context);
@@ -136,23 +139,26 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionCode(
codeGenerator.GetCustomCodeOutsideMain() + "\n\n" +
codeGenerator.GetCodeNamespaceAccessor() + "func = function(" +
codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
parameters) +
") {\n" + codeGenerator.GenerateEventsFunctionContext(parameters) + "\n" +
globalObjectListsReset + "\n" + codeGenerator.GetCustomCodeInMain() +
wholeEventsCode + "\n" + "return;\n" + "}\n";
eventsFunction.GetParameters()) +
") {\n" +
codeGenerator.GenerateEventsFunctionContext(
eventsFunction.GetParameters()) +
"\n" + globalObjectListsReset + "\n" +
codeGenerator.GetCustomCodeInMain() + wholeEventsCode + "\n" +
codeGenerator.GenerateEventsFunctionReturn(eventsFunction) + "\n" + "}\n";
// includeFiles.insert(codeGenerator.GetIncludeFiles().begin(),
// codeGenerator.GetIncludeFiles().end());
includeFiles.insert(codeGenerator.GetIncludeFiles().begin(),
codeGenerator.GetIncludeFiles().end());
return output;
}
gd::String EventsCodeGenerator::GenerateEventsFunctionParameterDeclarationsList(
const vector<gd::ParameterMetadata>& parameters) {
gd::String declaration = "";
gd::String declaration = "runtimeScene";
for (const auto& parameter : parameters) {
if (!declaration.empty()) declaration += ", ";
declaration += parameter.GetName().empty() ? "_" : parameter.GetName();
declaration += ", " + (parameter.GetName().empty() ? "_" : parameter.GetName());
}
declaration += ", parentEventsFunctionContext";
return declaration;
}
@@ -160,14 +166,32 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionParameterDeclarationsList(
gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
const vector<gd::ParameterMetadata>& parameters) {
gd::String objectsGetters;
gd::String objectsCreators;
gd::String argumentsGetters;
for (const auto& parameter : parameters) {
if (parameter.GetName().empty()) continue;
if (gd::ParameterMetadata::IsObject(parameter.GetType())) {
// Generate getter that will be used to get the lists of objects passed
// as parameters
objectsGetters +=
"if (objectName === " + ConvertToStringExplicit(parameter.GetName()) +
") return gdjs.objectsListsToArray(" + parameter.GetName() + ");\n";
"&& !!" + parameter.GetName() + ") return gdjs.objectsListsToArray(" +
parameter.GetName() + ");\n";
// Generate creator functions that will be used to create new objects. We
// need to check if the function was given the context of the calling
// function (parentEventsFunctionContext). If this is the case, use it to
// create the new object as the object names used in the function are not
// the same as the objects available in the scene.
gd::String objectNameCode = parameter.GetName() + ".firstKey()";
objectsCreators +=
"if (objectName === " + ConvertToStringExplicit(parameter.GetName()) +
"&& !!" + parameter.GetName() +
") return parentEventsFunctionContext ? "
"parentEventsFunctionContext.createObject(" +
objectNameCode + ") : runtimeScene.createObject(" + objectNameCode +
");\n";
} else {
argumentsGetters +=
"if (argName === " + ConvertToStringExplicit(parameter.GetName()) +
@@ -179,8 +203,26 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
" getObjects: function(objectName) {\n" + objectsGetters +
" return [];"
" },\n" +
" getArgument: function(argName) {\n" + argumentsGetters +
" return \"\";" + " }\n" + "};\n";
" createObject: function(objectName) {\n" + objectsCreators +
" return null;\n" +
" },\n"
" getArgument: function(argName) {\n" +
argumentsGetters + " return \"\";\n" + " }\n" + "};\n";
}
gd::String EventsCodeGenerator::GenerateEventsFunctionReturn(
const gd::EventsFunction& eventsFunction) {
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
return "return !!eventsFunctionContext.returnValue;";
} else if (eventsFunction.GetFunctionType() ==
gd::EventsFunction::Expression) {
return "return Number(eventsFunctionContext.returnValue) || 0;";
} else if (eventsFunction.GetFunctionType() ==
gd::EventsFunction::StringExpression) {
return "return \"\" + eventsFunctionContext.returnValue;";
}
return "return;";
}
std::pair<gd::String, gd::String>
@@ -725,6 +767,18 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
argOutput = "runtimeScene";
}
// Code only parameter type
else if (metadata.type == "objectsContext") {
argOutput =
"(typeof eventsFunctionContext !== 'undefined' ? eventsFunctionContext "
": runtimeScene)";
}
// Code only parameter type
else if (metadata.type == "eventsFunctionContext") {
argOutput =
"(typeof eventsFunctionContext !== 'undefined' ? eventsFunctionContext "
": undefined)";
}
// Code only parameter type
else if (metadata.type == "objectList") {
std::vector<gd::String> realObjects = ExpandObjectsName(parameter, context);
for (auto& objectName : realObjects) context.ObjectsListNeeded(objectName);
@@ -847,8 +901,10 @@ gd::String EventsCodeGenerator::GetCodeNamespace() {
return "gdjs." +
gd::SceneNameMangler::GetMangledSceneName(GetLayout().GetName()) +
"Code";
} else if (!codeNamespace.empty()) {
return codeNamespace;
} else {
return "gdjs.events" + gd::String::From(&objectsAndGroups) + "Code";
return "gdjs.unspecifiednamespacethisisprobablyanerrorincodegeneratorsetup";
}
}

View File

@@ -13,6 +13,7 @@
#include "GDCore/Events/InstructionsList.h"
namespace gd {
class ObjectsContainer;
class EventsFunction;
class ObjectMetadata;
class BehaviorMetadata;
class InstructionMetadata;
@@ -54,17 +55,17 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
* Generate JavaScript for executing events in a function
*
* \param project Project used
* \param parameters The parameters of the function (objects will be deduced from these).
* \param events events of the scene
* \param compilationForRuntime Set this to true if the code is generated for
* runtime.
* \param parameters The parameters of the function (objects will be deduced
* from these). \param events events of the scene \param compilationForRuntime
* Set this to true if the code is generated for runtime.
*
* \return JavaScript code
*/
static gd::String GenerateEventsFunctionCode(
gd::Project& project,
const std::vector<gd::ParameterMetadata> & parameters,
const gd::EventsList& events,
const gd::EventsFunction& eventsFunction,
const gd::String& codeNamespace,
std::set<gd::String>& includeFiles,
bool compilationForRuntime = false);
/**
@@ -134,6 +135,16 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
*/
virtual gd::String GetCodeNamespace();
/**
* \brief Specify the code namespace to use, useful for functions as it is not
* autogenerated.
*
* Example: "gdjs.something"
*/
void SetCodeNamespace(const gd::String& codeNamespace_) {
codeNamespace = codeNamespace_;
};
protected:
virtual gd::String GenerateParameterCodes(
const gd::String& parameter,
@@ -243,8 +254,25 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
*/
void AddAllObjectsIncludeFiles();
gd::String GenerateEventsFunctionParameterDeclarationsList(const std::vector<gd::ParameterMetadata> & parameters);
gd::String GenerateEventsFunctionContext(const std::vector<gd::ParameterMetadata> & parameters);
/**
* \brief Generate the list of parameters of a function.
*
* \note runtimeScene is always added as the first parameter, and
* parentEventsFunctionContext as the last parameter.
*/
gd::String GenerateEventsFunctionParameterDeclarationsList(
const std::vector<gd::ParameterMetadata>& parameters);
/**
* \brief Generate the "eventsFunctionContext" object that allow a function
* to provides access objects, object creation and access to arguments from
* the rest of the events.
*/
gd::String GenerateEventsFunctionContext(
const std::vector<gd::ParameterMetadata>& parameters);
gd::String GenerateEventsFunctionReturn(
const gd::EventsFunction & eventFunction);
/**
* \brief Construct a code generator for the specified project and layout.
@@ -257,6 +285,9 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
EventsCodeGenerator(gd::ObjectsContainer& globalObjectsAndGroups,
const gd::ObjectsContainer& objectsAndGroups);
virtual ~EventsCodeGenerator();
gd::String codeNamespace; ///< Optional namespace for the generated code,
///< used when generating events function.
};
} // namespace gdjs

View File

@@ -5,7 +5,9 @@
*/
#include "AdvancedExtension.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
#include "GDCore/Tools/Localization.h"
@@ -16,6 +18,121 @@ AdvancedExtension::AdvancedExtension() {
GetAllConditions()["Toujours"].SetFunctionName(
"gdjs.evtTools.common.logicalNegation");
GetAllActions()["SetReturnNumber"]
.GetCodeExtraInformation()
.SetCustomCodeGenerator([](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
gd::String expressionCode;
{
gd::CallbacksForGeneratingExpressionCode callbacks(
expressionCode, codeGenerator, context);
gd::ExpressionParser parser(
instruction.GetParameter(0).GetPlainString());
if (!parser.ParseMathExpression(
codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
callbacks) ||
expressionCode.empty())
expressionCode = "0";
}
return "if (typeof eventsFunctionContext !== 'undefined') { "
"eventsFunctionContext.returnValue = " +
expressionCode + "; }";
});
GetAllActions()["SetReturnString"]
.GetCodeExtraInformation()
.SetCustomCodeGenerator([](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
gd::String expressionCode;
{
gd::CallbacksForGeneratingExpressionCode callbacks(
expressionCode, codeGenerator, context);
gd::ExpressionParser parser(
instruction.GetParameter(0).GetPlainString());
if (!parser.ParseStringExpression(
codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
callbacks) ||
expressionCode.empty())
expressionCode = "\"\"";
}
return "if (typeof eventsFunctionContext !== 'undefined') { "
"eventsFunctionContext.returnValue = " +
expressionCode + "; }";
});
GetAllActions()["SetReturnBoolean"]
.GetCodeExtraInformation()
.SetCustomCodeGenerator([](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
// This is duplicated from EventsCodeGenerator::GenerateParameterCodes
gd::String parameter = instruction.GetParameter(0).GetPlainString();
gd::String booleanCode =
(parameter == "True" || parameter == "Vrai") ? "true" : "false";
return "if (typeof eventsFunctionContext !== 'undefined') { "
"eventsFunctionContext.returnValue = " +
booleanCode + "; }";
});
auto generateParameterNameCode =
[](const std::vector<gd::Expression>& parameters,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
gd::String parameterNameCode;
{
gd::CallbacksForGeneratingExpressionCode callbacks(
parameterNameCode, codeGenerator, context);
gd::ExpressionParser parser(
!parameters.empty() ? parameters[0].GetPlainString() : "");
if (!parser.ParseStringExpression(
codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
callbacks) ||
parameterNameCode.empty())
parameterNameCode = "\"\"";
}
return parameterNameCode;
};
GetAllExpressions()["GetArgumentAsNumber"]
.GetCodeExtraInformation()
.SetCustomCodeGenerator([&generateParameterNameCode](
const std::vector<gd::Expression>& parameters,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
gd::String parameterNameCode =
generateParameterNameCode(parameters, codeGenerator, context);
return "(typeof eventsFunctionContext !== 'undefined' ? "
"Number(eventsFunctionContext.getArgument(" +
parameterNameCode + ")) || 0 : 0)";
});
GetAllStrExpressions()["GetArgumentAsString"]
.GetCodeExtraInformation()
.SetCustomCodeGenerator([&generateParameterNameCode](
const std::vector<gd::Expression>& parameters,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
gd::String parameterNameCode =
generateParameterNameCode(parameters, codeGenerator, context);
return "(typeof eventsFunctionContext !== 'undefined' ? \"\" + "
"eventsFunctionContext.getArgument(" +
parameterNameCode + ") : \"\")";
});
}
} // namespace gdjs

View File

@@ -67,6 +67,12 @@ SpriteExtension::SpriteExtension() {
.SetGetter("getScale");
spriteConditions["ScaleWidth"].SetFunctionName("getScaleX");
spriteConditions["ScaleHeight"].SetFunctionName("getScaleY");
spriteActions["ChangeWidth"]
.SetFunctionName("setWidth")
.SetGetter("getWidth");
spriteActions["ChangeHeight"]
.SetFunctionName("setHeight")
.SetGetter("getHeight");
spriteActions["TourneVersPos"].SetFunctionName("rotateTowardPosition");
spriteActions["TourneVers"].SetFunctionName("turnTowardObject");
spriteActions["ChangeColor"].SetFunctionName("setColor");

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