Compare commits

...

129 Commits

Author SHA1 Message Date
AlexandreSi
5eb5fb3af9 Add checkbox to improve discoverability of tilemap hitboxes 2024-07-19 10:41:07 +02:00
AlexandreSi
cd80872fca Rename existing tilemap object adding external mention in the name 2024-07-19 10:19:49 +02:00
AlexandreSi
61cb6dde0e Replace path painting with rectangle painting 2024-07-19 09:29:52 +02:00
AlexandreSi
29c8de0987 Refactor 2024-07-18 15:41:05 +02:00
AlexandreSi
802e9a5128 Add possibility to select hitboxes using a rectangle 2024-07-18 14:46:38 +02:00
AlexandreSi
c82602919b Update collision mask when tilemap is dirty 2024-07-18 13:40:12 +02:00
AlexandreSi
80cbb8f542 Make it possible to select tiles with a rectangle when setting hit boxes 2024-07-18 11:11:45 +02:00
AlexandreSi
a9ceba7bef Rename file 2024-07-18 10:31:05 +02:00
AlexandreSi
7d9e72c876 Prevent having tile with ids outside of tile set 2024-07-17 16:18:43 +02:00
AlexandreSi
3baf5903d3 Clean a few things 2024-07-17 16:00:42 +02:00
AlexandreSi
6008e1045d Change width and height and opacity from network sync only if different 2024-07-17 15:16:28 +02:00
AlexandreSi
9dda9a89c5 Remove selected instance fill color when painting 2024-07-17 15:16:28 +02:00
AlexandreSi
814c6aec4f Handle rendered instance of tilemap when tilemap is empty 2024-07-17 15:16:28 +02:00
AlexandreSi
84e4158407 Fix typing 2024-07-17 15:16:28 +02:00
AlexandreSi
aa6c3bc1c8 Recompute tile set on tilemap object parameters changes 2024-07-17 15:16:28 +02:00
AlexandreSi
41dc6d0966 Improve runtime typing 2024-07-17 15:16:28 +02:00
AlexandreSi
9c19865dec Fix typing 2024-07-17 15:16:28 +02:00
AlexandreSi
bbfb7f63f0 Save to history when changing tilemap 2024-07-17 15:16:28 +02:00
AlexandreSi
2f8304c2dd Deactivate painting when pressing escape 2024-07-17 15:16:28 +02:00
AlexandreSi
c1aa88861d Add cancel painting action on press escape 2024-07-17 15:16:28 +02:00
AlexandreSi
254ab0350b Display info about tiles with hitboxes 2024-07-17 15:16:28 +02:00
AlexandreSi
b0a3c34803 Use object configuration to set hit boxes 2024-07-17 15:16:28 +02:00
AlexandreSi
63a3265310 Store tiles with hitbox in object configuration 2024-07-17 15:16:28 +02:00
AlexandreSi
d19292f43d Initiate SimpleTileMap object editor 2024-07-17 15:16:28 +02:00
AlexandreSi
3646d05b65 Simplify TileMapPainter component and types 2024-07-17 15:16:28 +02:00
AlexandreSi
25a4d04896 Remove useless react fragment 2024-07-17 15:16:28 +02:00
AlexandreSi
2df6c13ed7 Make opacity setting work for simple tile maps 2024-07-17 15:16:28 +02:00
AlexandreSi
93f84a14cb Implement missing methods for collisions to work 2024-07-17 15:16:28 +02:00
AlexandreSi
02e0ebf63b Post rebase changes 2024-07-17 15:16:28 +02:00
AlexandreSi
da3abb331a Add collision tilemap to simple tile map object 2024-07-17 15:16:28 +02:00
AlexandreSi
a5a9524ed6 Add possibility to set flipping options in tile setting action 2024-07-17 15:16:28 +02:00
AlexandreSi
c9cc1f6fdc Use reusable float point 2024-07-17 15:16:28 +02:00
AlexandreSi
de140f1190 Reposition tilemap when setting/removing tiles 2024-07-17 15:16:28 +02:00
AlexandreSi
9a82fda7fe Use affine transformation in runtime actions 2024-07-17 15:16:28 +02:00
AlexandreSi
eac92704fa Display tile id as title when hovering tileset 2024-07-17 15:16:28 +02:00
AlexandreSi
dc607d85c3 Use AffineTransformation to display tile preview and set tile at coordinates 2024-07-17 15:16:28 +02:00
AlexandreSi
e96269d899 Aff AffineTransformation util from runtime 2024-07-17 15:16:27 +02:00
AlexandreSi
05d622c5c0 Add TODO 2024-07-17 15:16:27 +02:00
AlexandreSi
0758397196 Use flipping controls when painting and previewing the tile to be set 2024-07-17 15:16:27 +02:00
AlexandreSi
65293ddd99 Update tilemap painter with icons and flipping selectors 2024-07-17 15:16:27 +02:00
AlexandreSi
225a3a67c6 Add TODO 2024-07-17 15:16:27 +02:00
AlexandreSi
a96171aacd Add actions to change change tiles in the runtime 2024-07-17 15:16:27 +02:00
AlexandreSi
1a21a0bfb3 Actually hide tilemap instance property 2024-07-17 15:16:27 +02:00
AlexandreSi
cc23301875 Initiate SimpleTileMap runtime object 2024-07-17 15:16:27 +02:00
AlexandreSi
aa513c04e6 Store tilemap on instance instead of object 2024-07-17 15:16:27 +02:00
AlexandreSi
a4e8e8c00b Add method to check if tilemap is empty 2024-07-17 15:16:27 +02:00
AlexandreSi
0d34680fcd Resize and reposition tilemap after trimming tilemap 2024-07-17 15:16:27 +02:00
AlexandreSi
4abdb9dca6 Add methods to trim tilemap from empty rows and columns 2024-07-17 15:16:27 +02:00
AlexandreSi
db05a07023 Add possibility to erase tile from the tilemap 2024-07-17 15:16:27 +02:00
AlexandreSi
78ebe58713 Add possibility to paint with click + drag 2024-07-17 15:16:27 +02:00
AlexandreSi
420c7a4429 Adapt state to support more than one tile selected 2024-07-17 15:16:27 +02:00
AlexandreSi
1442a2772e Support tilemaps with custom heights and widths 2024-07-17 15:16:27 +02:00
AlexandreSi
ce18bdd5a7 Reposition instance after adding columns/rows in negative indices 2024-07-17 15:16:27 +02:00
AlexandreSi
2f2cc1bbe3 Support setting tiles in negative indices 2024-07-17 15:16:27 +02:00
AlexandreSi
097ad4fff5 Make it possible to paint outside of the tilemap dimensions (positive) 2024-07-17 15:16:27 +02:00
AlexandreSi
2112ed789a Set tilemap attribute on object when painting 2024-07-17 15:16:27 +02:00
AlexandreSi
a41a1c14a0 Modify tilemap when clicking on scene when tile is selected 2024-07-17 15:16:27 +02:00
AlexandreSi
771d3264bb Load simple tilemap into editable tile map for scene editor renderer 2024-07-17 15:16:27 +02:00
AlexandreSi
9fa1e552e0 Complete unknown instance rectangle 2024-07-17 15:16:27 +02:00
AlexandreSi
503a0873d9 Make tile map preview position on grid 2024-07-17 15:16:27 +02:00
AlexandreSi
715480bdef Tile map tile preview in Scene editor 2024-07-17 15:16:27 +02:00
AlexandreSi
869fd7eb08 Transfer selected tile map tile data to scene editor 2024-07-17 15:16:26 +02:00
AlexandreSi
e0cb8e4953 Improve object declaration and setup tilemap painter 2024-07-17 15:16:26 +02:00
AlexandreSi
0ef4953241 WIP: Add TileMapPainter 2024-07-17 15:16:26 +02:00
AlexandreSi
d154384164 WIP introduce simple tile map object 2024-07-17 15:16:26 +02:00
AlexandreSi
504df2e0a3 Fix comment 2024-07-17 15:16:26 +02:00
D8H
e9adaa94c5 Remove unused imports (#6778)
Do not show in changelog
2024-07-17 10:24:36 +02:00
D8H
35da31c5c5 Add icons on tabs (#6771) 2024-07-16 14:44:11 +02:00
Aurélien Vivet
e65492e1a1 Translate properly the messages about a new update. (#6775) 2024-07-15 15:38:28 +02:00
AlexandreS
44827ea372 Fix errors when reading source files for autocompletions in JS events (#6773) 2024-07-15 11:01:24 +02:00
github-actions[bot]
ab3ffe6785 Update translations [skip ci] (#6759)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-07-12 16:09:59 +02:00
D8H
d83d049ac9 Fix GDJS type declarations and tests (#6768)
- Don't show in changelog
2024-07-11 14:37:10 +02:00
Aurélien Vivet
67a7bd7af2 Remove dead code (#6767)
Only show in developer changelog
2024-07-11 14:13:55 +02:00
D8H
6db5267878 Allow to drag and drop custom object properties (#6766) 2024-07-11 14:11:24 +02:00
Florian Rival
a51c223c9c Add experimental, work-in-progress visual editor for custom objects (aka "prefabs"/"templates") (#6699)
* Still to do: 
  * Properly handle effects (disable 3D effects) for layers
  * Handle hot reloading properly
  * Avoid duplicating the configuration of the custom object inside each object created from it. Instead, only store the modified values.
  * Add a "Extract as a custom object ("prefab")" when selecting instances in a scene.
  * Add a dialog to give choice between 2D or 3D object when creating one.
  * Make sure "behavior shared data" are properly handled (physics, pathfinding...)
  * Check if we need to give an expression to translate coordinates from the parent to the local custom object.
  * Ensure a deleted custom object does not break the editor

Co-authored-by: Davy Hélard <davy.helard@gmail.com>
2024-07-11 11:27:34 +02:00
Arthur Pacaud (arthuro555)
0a4e5a1012 Add an action (#6191) 2024-07-10 22:48:22 +02:00
D8H
acce714736 Fix raycast test. (#6763)
Do not show in changelog
2024-07-10 14:53:37 +02:00
Florian Rival
3c34a8806b Fix message asking to check Apple/Google account for subscription not always shown (#6761)
- This was the case when the app was opened from https://editor.gdevelop.io?initial-dialog=subscription
2024-07-09 16:42:01 +02:00
Florian Rival
1d4cb7bef0 Fix checkbox to disable ads not displayed properly after being changed (#6760)
* Also address some part of the game dashboard that could be outdated after changes
2024-07-09 16:41:44 +02:00
Clément Pasteau
7badacd24a Fix not building peerjs for web runtime (#6758) 2024-07-09 12:06:10 +02:00
github-actions[bot]
11ab92fc0e Update translations [skip ci] (#6752)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-07-09 10:02:32 +02:00
D8H
ddb1e335bc Improve raycast precision when the distance is 0 (#6757) 2024-07-08 14:51:29 +02:00
Tristan Rhodes
8d035a774d Add Star History to bottom of README (#6749) [skip ci] 2024-07-07 21:25:33 +02:00
Aurélien Vivet
5b1e3565d3 Remove dead code (TinyXml) (#6754)
Only show in developer changelog
2024-07-05 17:45:57 +02:00
Tristan Rhodes
8c88038bfb Added new condition to check the zoom of a camera of a layer (#6747) 2024-07-04 14:05:35 +02:00
D8H
f62811974d Remove an error about object name collision in object variable fields (#6751) 2024-07-04 12:56:25 +02:00
Florian Rival
b516037d2b Fix opening an example from a link or command line argument (#6750)
* An example opened from a link (typically, from the website) will now properly ask for the location where to save it, and will handle leaderboards and multiplayer.
2024-07-04 11:28:58 +02:00
D8H
98befc8000 Fix group list updating. (#6748)
Do not show in changelog
2024-07-03 10:57:59 +02:00
Clément Pasteau
377231fb37 Bump to 5.4.205 (#6746) 2024-07-03 10:27:36 +02:00
github-actions[bot]
22ae8ac489 Update translations [skip ci] (#6744)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-07-03 10:27:24 +02:00
Clément Pasteau
40674fd3b9 Guided lessons opening fixes (#6745)
Do not show in changelog
2024-07-02 17:40:46 +02:00
Clément Pasteau
0792e59b24 Speed up lobbies process in preview (#6743)
- start countdown is reduced
- players are readied automatically
2024-07-02 16:12:51 +02:00
github-actions[bot]
8ba6ad7b43 Update translations [skip ci] (#6741)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-07-02 15:48:29 +02:00
Clément Pasteau
84b07bc84d Open all scenes and focus on first one when opening a guided lesson (#6740)
Do not show in changelog
2024-07-02 15:48:09 +02:00
Clément Pasteau
c46d39cbed Fix returning player auth on first preview (#6742)
Do not show in changelog
2024-07-02 15:21:48 +02:00
github-actions[bot]
b96132964c Update translations [skip ci] (#6734)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-07-02 14:13:22 +02:00
Tristan Rhodes
130cd1e3a7 "Change platform type" action now uses a dropdown selector (#6727) 2024-07-02 14:11:39 +02:00
Clément Pasteau
fbbcf25bf5 Allow tagging a behavior of a multiplayer object as not synced (#6737)
* Also fix the synchronization of the activated state of a behavior
2024-07-02 14:05:51 +02:00
Aurélien Vivet
ffaae4d3d4 New guided lesson - Creating a Multiplayer Co-op game (#6736) 2024-07-02 10:35:36 +02:00
D8H
75d79a7758 Display errors on variable parameters about name collisions with objects (#6732) 2024-07-01 16:42:43 +02:00
D8H
d91fb78848 Use a new icon for global variables (#6735)
- Don't show in changelog
2024-07-01 15:15:41 +02:00
D8H
e0a2ed1654 Fix a refreshing issue of the object list in functions (#6725)
- Fix the default parameters when pasting a function in a behavior
2024-07-01 14:49:09 +02:00
Florian Rival
d5f2be1c19 Add an extra link to create a variable (#6730) 2024-07-01 14:28:51 +02:00
github-actions[bot]
7abcfe8af2 Update translations [skip ci] (#6731)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-07-01 13:01:08 +02:00
Clément Pasteau
b86dd9efce Bump memory for tests (#6733)
Do not show in changelog
2024-07-01 13:00:47 +02:00
github-actions[bot]
15f6b62c5b Update translations [skip ci] (#6724)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-07-01 12:04:26 +02:00
Clément Pasteau
eb995ec7c7 Fix emscripten core version (#6729)
Show in developer changelog only
2024-07-01 12:03:46 +02:00
D8H
a076571120 Fix some array variable expressions visibility (#6728) 2024-07-01 11:37:50 +02:00
Clément Pasteau
ec9cb790e7 Improve multiplayer messages by automatically detecting and using best compression method for lobby (#6690)
- Also remove dependency on P2P extension
2024-07-01 10:52:01 +02:00
D8H
4a283add00 Fix events shortcuts from triggering when a dialog is opened (#6726) 2024-06-30 17:31:00 +02:00
D8H
6b3faa42bb Make variables easier to declare on the fly (#6721) 2024-06-27 21:13:18 +02:00
Florian Rival
555ee61e63 Fix badges text color
Don't show in changelog
2024-06-27 13:00:33 +02:00
github-actions[bot]
b838c8549b Update translations [skip ci] (#6722)
Co-authored-by: ClementPasteau <4895034+ClementPasteau@users.noreply.github.com>
2024-06-27 10:44:05 +02:00
Clément Pasteau
33db6ee359 Fix message sender expression (#6723)
Do not show in changelog
2024-06-27 10:43:42 +02:00
Clément Pasteau
f361d3e1fa Automatically log the user as a player in a preview (#6714)
* Simplifies creating & testing a game in preview, when using player authentication or multiplayer extensions
2024-06-27 09:38:23 +02:00
github-actions[bot]
441401f34c Update translations [skip ci] (#6719)
Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2024-06-26 16:09:55 +02:00
Aurélien Vivet
558daa2075 Remove extra "Add" words in the events context menu (#6713) 2024-06-26 09:37:50 +02:00
AlexandreS
cd475316df Limit leaderboard customization css field length (#6720) 2024-06-26 07:42:41 +02:00
D8H
8b21e72c85 Fix to avoid new variables from being added at the top (#6718) 2024-06-25 17:34:12 +02:00
github-actions[bot]
a9d6f18c11 Update translations [skip ci] (#6689)
Co-authored-by: D8H <2611977+D8H@users.noreply.github.com>
2024-06-25 17:10:32 +02:00
Clément Pasteau
f58e1113b6 Add new actions and expressions for multiplayer (#6717)
* Send a variable with a custom message
* Retrieve the player number of the sender
2024-06-25 17:07:38 +02:00
D8H
f82b5fc66d Fix local variables default values when the wait action is used (#6715) 2024-06-25 16:14:40 +02:00
AlexandreS
2f19a9bb33 Improve some icons in the editor (variables, mobile toolbar) (#6700) 2024-06-25 12:42:41 +02:00
Dennis Fehr
8f739d85c2 Fix dragging bug in the Events Sheet when the indent scale is not 1x (#6702) 2024-06-25 10:07:09 +02:00
AlexandreS
f23847617d Add possibility for players to login with Google/Apple in game. (#6711) 2024-06-24 18:22:43 +02:00
Clément Pasteau
876332a782 Fix multiplayer lobbies properly opening after login (#6712) 2024-06-24 18:15:32 +02:00
D8H
93c74c9fd6 Use property names instead of property labels in descriptions and sentences of internal behavior instructions (#6708) 2024-06-23 17:45:21 +02:00
Florian Rival
e92d8496ac Add missing Spine Runtime license agreement and link to Spine website (#6701) 2024-06-21 18:18:03 +02:00
AlexandreS
35e67a6d26 Try to register game before copying lobby configuration (#6696)
Don't show in changelog
2024-06-20 18:04:29 +02:00
469 changed files with 15386 additions and 18296 deletions

3
.gitattributes vendored
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -709,11 +709,14 @@ EventsCodeGenerator::GenerateCallback(
const gd::String actionsDeclarationsCode =
GenerateObjectsDeclarationCode(callbackContext);
const gd::String callbackCode =
callbackFunctionName + " = function (" +
GenerateEventsParameters(callbackContext) + ") {\n" +
restoreLocalVariablesCode +
actionsDeclarationsCode + actionsCode + "}\n";
const gd::String clearLocalVariablesCode =
GenerateLocalVariablesStackAccessor() + ".length = 0;\n";
const gd::String callbackCode = callbackFunctionName + " = function (" +
GenerateEventsParameters(callbackContext) +
") {\n" + restoreLocalVariablesCode +
actionsDeclarationsCode + actionsCode +
clearLocalVariablesCode + "}\n";
AddCustomCodeOutsideMain(callbackCode);

View File

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

View File

@@ -58,6 +58,7 @@ struct GD_CORE_API ExpressionParserError {
MalformedObjectParameter,
UnknownParameterType,
MissingBehavior,
VariableNameCollision,
};
ExpressionParserError(gd::ExpressionParserError::ErrorType type_,

View File

@@ -1377,7 +1377,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Variables"),
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"));
.AddParameter("objectvar", _("Variable"))
.SetRelevantForFunctionEventsOnly();
obj.AddExpression("ObjectTimerElapsedTime",
_("Object timer value"),

View File

@@ -327,6 +327,25 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.SetDefaultValue("0");
extension
.AddCondition(
"CameraZoom",
_("Camera zoom"),
_("Compare the zoom of a camera of a layer."),
_("Zoom of camera _PARAM2_ of layer _PARAM1_"),
"",
"res/conditions/camera24.png",
"res/conditions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.SetDefaultValue("0")
.UseStandardRelationalOperatorParameters(
"number", gd::ParameterOptions::MakeNewOptions().SetDescription(
_("Zoom")))
.MarkAsAdvanced();
extension
.AddAction(
"FixCamera",

View File

@@ -64,9 +64,7 @@ void SpriteObject::ExposeResources(gd::ArbitraryResourceWorker& worker) {
std::map<gd::String, gd::PropertyDescriptor>
SpriteObject::GetInitialInstanceProperties(
const gd::InitialInstance& initialInstance,
gd::Project& project,
gd::Layout& scene) {
const gd::InitialInstance& initialInstance) {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties["animation"] =
gd::PropertyDescriptor(
@@ -80,9 +78,7 @@ SpriteObject::GetInitialInstanceProperties(
bool SpriteObject::UpdateInitialInstanceProperty(
gd::InitialInstance& initialInstance,
const gd::String& name,
const gd::String& value,
gd::Project& project,
gd::Layout& scene) {
const gd::String& value) {
if (name == "animation") {
initialInstance.SetRawDoubleProperty(
"animation", std::max(0, value.empty() ? 0 : value.To<int>()));

View File

@@ -47,14 +47,10 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
bool UpdateProperty(const gd::String& name, const gd::String& value) override;
std::map<gd::String, gd::PropertyDescriptor> GetInitialInstanceProperties(
const gd::InitialInstance& position,
gd::Project& project,
gd::Layout& scene) override;
const gd::InitialInstance& position) override;
bool UpdateInitialInstanceProperty(gd::InitialInstance& position,
const gd::String& name,
const gd::String& value,
gd::Project& project,
gd::Layout& scene) override;
const gd::String& value) override;
/**
* \brief Return the animation configuration.

View File

@@ -231,8 +231,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"it is a text (string)."),
_("Arrays and structures"),
"res/actions/var.png")
.AddParameter("variable", _("Array variable"))
.SetRelevantForLayoutEventsOnly();
.AddParameter("variable", _("Array variable"));
extension
.AddExpression(
@@ -242,8 +241,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"it is a number."),
_("Arrays and structures"),
"res/actions/var.png")
.AddParameter("variable", _("Array variable"))
.SetRelevantForLayoutEventsOnly();
.AddParameter("variable", _("Array variable"));
extension
.AddStrExpression(
@@ -253,8 +251,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"it is a text (string)."),
_("Arrays and structures"),
"res/actions/var.png")
.AddParameter("variable", _("Array variable"))
.SetRelevantForLayoutEventsOnly();
.AddParameter("variable", _("Array variable"));
extension
.AddExpression(
@@ -264,8 +261,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"it is a number."),
_("Arrays and structures"),
"res/actions/var.png")
.AddParameter("variable", _("Array variable"))
.SetRelevantForLayoutEventsOnly();
.AddParameter("variable", _("Array variable"));
// Legacy instructions
@@ -839,7 +835,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
_("Number of children"),
_("Number of children in a scene array or "
"structure variable"),
_("External variables/Scene variables/Arrays and structures"),
_("Arrays and structures"),
"res/actions/var.png")
.AddParameter("variable", _("Array or structure variable"), "AllowUndeclaredVariable");

View File

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

View File

@@ -296,7 +296,7 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
};
bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& actions,
gd::String oldName,
gd::String newName) {
@@ -347,7 +347,7 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
bool EventsRefactorer::RenameObjectInConditions(
const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& conditions,
gd::String oldName,
gd::String newName) {
@@ -399,7 +399,7 @@ bool EventsRefactorer::RenameObjectInConditions(
bool EventsRefactorer::RenameObjectInEventParameters(
const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::Expression& expression,
gd::ParameterMetadata parameterMetadata,
gd::String oldName,
@@ -432,7 +432,7 @@ bool EventsRefactorer::RenameObjectInEventParameters(
}
void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::EventsList& events,
gd::String oldName,
gd::String newName) {
@@ -475,7 +475,7 @@ void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
}
bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& actions,
gd::String name) {
bool somethingModified = false;
@@ -532,7 +532,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
bool EventsRefactorer::RemoveObjectInConditions(
const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::InstructionsList& conditions,
gd::String name) {
bool somethingModified = false;

View File

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

View File

@@ -203,13 +203,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
if (parentType == Type::Variable) {
childType = parentType;
if (!currentParameterExtraInfo || *currentParameterExtraInfo != "AllowUndeclaredVariable") {
const auto& variablesContainersList = projectScopedContainers.GetVariablesContainersList();
if (!variablesContainersList.Has(node.name)) {
RaiseUndeclaredVariableError(_("No variable with this name found."), node.location, node.name);
}
}
CheckVariableExistence(node.location, node.name);
if (node.child) {
node.child->Visit(*this);
}
@@ -333,12 +327,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
}
}
else if (parentType == Type::Variable) {
if (!currentParameterExtraInfo || *currentParameterExtraInfo != "AllowUndeclaredVariable") {
const auto& variablesContainersList = projectScopedContainers.GetVariablesContainersList();
if (!variablesContainersList.Has(node.identifierName)) {
RaiseUndeclaredVariableError(_("No variable with this name found."), node.location, node.identifierName);
}
}
CheckVariableExistence(node.location, node.identifierName);
}
else if (parentType != Type::Object && parentType != Type::LegacyVariable) {
// It can't happen.
@@ -381,6 +370,45 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
Type ValidateFunction(const gd::FunctionCallNode& function);
bool ValidateObjectVariableOrVariableOrProperty(const gd::IdentifierNode& identifier);
void CheckVariableExistence(const ExpressionParserLocation &location, const gd::String& name) {
if (!currentParameterExtraInfo || *currentParameterExtraInfo != "AllowUndeclaredVariable") {
projectScopedContainers.MatchIdentifierWithName<void>(
name,
[&]() {
// This represents an object.
RaiseVariableNameCollisionError(
_("This variable has the same name as an object. Consider "
"renaming one or the other."),
location, name);
},
[&]() {
// This is a variable.
},
[&]() {
// This is a property.
// This error won't happen unless the priority is changed.
RaiseVariableNameCollisionError(
_("This variable has the same name as a property. Consider "
"renaming one or the other."),
location, name);
},
[&]() {
// This is a parameter.
// This error won't happen unless the priority is changed.
RaiseVariableNameCollisionError(
_("This variable has the same name as a parameter. Consider "
"renaming one or the other."),
location, name);
},
[&]() {
// This is something else.
RaiseUndeclaredVariableError(
_("No variable with this name found."), location,
name);
});
}
}
void ReportAnyError(const ExpressionNode& node, bool isFatal = true) {
if (node.diagnostic) {
// Syntax errors are holden by the AST nodes.
@@ -424,6 +452,14 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
message, location, true, variableName, objectName);
}
void RaiseVariableNameCollisionError(const gd::String &message,
const ExpressionParserLocation &location,
const gd::String &variableName,
const gd::String &objectName = "") {
RaiseError(gd::ExpressionParserError::ErrorType::VariableNameCollision,
message, location, false, variableName, objectName);
}
void RaiseTypeError(const gd::String &message,
const ExpressionParserLocation &location,
bool isFatal = true) {

View File

@@ -20,7 +20,7 @@ namespace gd {
void EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
const gd::Project& project,
const gd::EventsFunctionsContainer functionContainer,
const gd::EventsFunctionsContainer& functionContainer,
const gd::EventsFunction& eventsFunction,
gd::ObjectsContainer& outputObjectsContainer) {
// Functions scope for objects is defined according
@@ -92,17 +92,30 @@ void EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
"its parameters).");
return;
}
if (eventsBasedObject.HasObjectNamed("Object")) {
if (eventsBasedObject.GetObjects().HasObjectNamed("Object")) {
gd::LogWarning("Child-objects can't be named Object because it's reserved"
"for the parent. ");
return;
}
// ...and its children.
auto &children = eventsBasedObject.GetObjects();
gd::EventsFunctionTools::CopyEventsBasedObjectChildrenToObjectsContainer(
eventsBasedObject, outputObjectsContainer);
}
void EventsFunctionTools::CopyEventsBasedObjectChildrenToObjectsContainer(
const gd::EventsBasedObject& eventsBasedObject,
gd::ObjectsContainer& outputObjectsContainer) {
auto &children = eventsBasedObject.GetObjects().GetObjects();
for (auto &childObject : children) {
auto child = childObject.get();
outputObjectsContainer.InsertObject(*child, children.size());
outputObjectsContainer.InsertObject(
*child, outputObjectsContainer.GetObjectsCount());
}
auto &childrenGroups = eventsBasedObject.GetObjects().GetObjectGroups();
for (size_t index = 0; index < childrenGroups.Count(); ++index) {
auto &childGroup = childrenGroups.Get(index);
outputObjectsContainer.GetObjectGroups().Insert(
childGroup, outputObjectsContainer.GetObjectGroups().Count());
}
}

View File

@@ -35,7 +35,7 @@ class GD_CORE_API EventsFunctionTools {
*/
static void FreeEventsFunctionToObjectsContainer(
const gd::Project& project,
const gd::EventsFunctionsContainer functionContainer,
const gd::EventsFunctionsContainer& functionContainer,
const gd::EventsFunction& eventsFunction,
gd::ObjectsContainer& outputObjectsContainer);
@@ -68,5 +68,9 @@ class GD_CORE_API EventsFunctionTools {
const gd::EventsBasedObject& eventsBasedObject,
const gd::EventsFunction& eventsFunction,
gd::ObjectsContainer& outputObjectsContainer);
static void CopyEventsBasedObjectChildrenToObjectsContainer(
const gd::EventsBasedObject &eventsBasedObject,
gd::ObjectsContainer &outputObjectsContainer);
};
} // namespace gd

View File

@@ -0,0 +1,41 @@
/*
* GDevelop JS Platform
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "EventsBasedObjectDependencyFinder.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
namespace gd {
bool EventsBasedObjectDependencyFinder::IsDependentFromEventsBasedObject(
const gd::Project &project, const gd::EventsBasedObject &eventsBasedObject,
const gd::EventsBasedObject &dependency) {
return gd::EventsBasedObjectDependencyFinder::
IsDependentFromEventsBasedObject(project, eventsBasedObject, dependency,
0);
}
bool EventsBasedObjectDependencyFinder::IsDependentFromEventsBasedObject(
const gd::Project &project, const gd::EventsBasedObject &eventsBasedObject,
const gd::EventsBasedObject &dependency, int depth) {
if (&eventsBasedObject == &dependency) {
return true;
}
if (depth > 200) {
return false;
}
for (auto &object : eventsBasedObject.GetObjects().GetObjects()) {
const gd::String &objectType = object->GetType();
if (project.HasEventsBasedObject(objectType) &&
gd::EventsBasedObjectDependencyFinder::IsDependentFromEventsBasedObject(
project, project.GetEventsBasedObject(objectType), dependency,
depth + 1)) {
return true;
}
}
return false;
}
} // namespace gd

View File

@@ -0,0 +1,37 @@
/*
* GDevelop JS Platform
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include "GDCore/String.h"
namespace gd {
class Project;
class EventsBasedObject;
} // namespace gd
namespace gd {
/**
* \brief Find resource usages in several parts of the project.
*
* \ingroup IDE
*/
class EventsBasedObjectDependencyFinder {
public:
static bool IsDependentFromEventsBasedObject(
const gd::Project &project,
const gd::EventsBasedObject &eventsBasedObject,
const gd::EventsBasedObject &dependency);
private:
static bool IsDependentFromEventsBasedObject(
const gd::Project &project,
const gd::EventsBasedObject &eventsBasedObject,
const gd::EventsBasedObject &dependency, int depth);
};
} // namespace gd

View File

@@ -250,7 +250,7 @@ void ProjectBrowserHelper::ExposeProjectObjects(
gd::Project &project, gd::ArbitraryObjectsWorker &worker) {
// Global objects
worker.Launch(project);
worker.Launch(project.GetObjects());
// Layout objects
for (size_t i = 0; i < project.GetLayoutsCount(); i++) {
@@ -265,7 +265,7 @@ void ProjectBrowserHelper::ExposeProjectObjects(
for (auto &&eventsBasedObjectUniquePtr :
eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) {
auto eventsBasedObject = eventsBasedObjectUniquePtr.get();
worker.Launch(*eventsBasedObject);
worker.Launch(eventsBasedObject->GetObjects());
}
}
};
@@ -275,7 +275,7 @@ void ProjectBrowserHelper::ExposeLayoutObjects(gd::Layout &layout,
// In the future, layouts may have children object containers.
// Layout objects
worker.Launch(layout);
worker.Launch(layout.GetObjects());
}
void ProjectBrowserHelper::ExposeProjectFunctions(

View File

@@ -17,7 +17,7 @@
namespace gd {
void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project &project) {
project.GetObjectGroups().Clear();
project.GetObjects().GetObjectGroups().Clear();
while (project.GetExternalEventsCount() > 0)
project.RemoveExternalEvents(project.GetExternalEvents(0).GetName());
@@ -26,7 +26,7 @@ void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project &project) {
wholeProjectBrowser.ExposeObjects(project, behaviorDefaultFlagClearer);
for (unsigned int i = 0; i < project.GetLayoutsCount(); ++i) {
project.GetLayout(i).GetObjectGroups().Clear();
project.GetLayout(i).GetObjects().GetObjectGroups().Clear();
project.GetLayout(i).GetEvents().Clear();
}

View File

@@ -76,7 +76,7 @@ void ResourceExposer::ExposeWholeProjectResources(gd::Project& project, gd::Arbi
void ResourceExposer::ExposeProjectResources(gd::Project& project, gd::ArbitraryResourceWorker& worker) {
// Expose global objects configuration resources
auto objectWorker = gd::GetResourceWorkerOnObjects(project, worker);
objectWorker.Launch(project);
objectWorker.Launch(project.GetObjects());
}
void ResourceExposer::ExposeLayoutResources(

View File

@@ -86,10 +86,10 @@ WholeProjectRefactorer::GetAllObjectTypesUsingEventsBasedBehavior(
}
};
addTypesOfObjectsIn(project);
addTypesOfObjectsIn(project.GetObjects());
for (std::size_t s = 0; s < project.GetLayoutsCount(); s++) {
auto &layout = project.GetLayout(s);
addTypesOfObjectsIn(layout);
addTypesOfObjectsIn(layout.GetObjects());
}
return allTypes;
@@ -1177,12 +1177,14 @@ WholeProjectRefactorer::FindInvalidRequiredBehaviorProperties(
};
// Find in global objects
findInvalidRequiredBehaviorPropertiesInObjects(project.GetObjects());
findInvalidRequiredBehaviorPropertiesInObjects(
project.GetObjects().GetObjects());
// Find in layout objects.
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
const gd::Layout &layout = project.GetLayout(i);
findInvalidRequiredBehaviorPropertiesInObjects(layout.GetObjects());
findInvalidRequiredBehaviorPropertiesInObjects(
layout.GetObjects().GetObjects());
}
return invalidRequiredBehaviorProperties;
}
@@ -1521,10 +1523,10 @@ void WholeProjectRefactorer::ObjectRemovedInLayout(
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
// Object groups can't have instances or be in other groups
for (std::size_t g = 0; g < layout.GetObjectGroups().size(); ++g) {
if (layout.GetObjectGroups()[g].Find(objectName))
layout.GetObjectGroups()[g].RemoveObject(objectName);
auto &groups = layout.GetObjects().GetObjectGroups();
for (std::size_t g = 0; g < groups.size(); ++g) {
if (groups[g].Find(objectName))
groups[g].RemoveObject(objectName);
}
layout.GetInitialInstances().RemoveInitialInstancesOfObject(objectName);
@@ -1562,11 +1564,12 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
project.GetCurrentPlatform(), projectScopedContainers, layout.GetEvents(),
oldName, newName);
if (!isObjectGroup) { // Object groups can't have instances or be in other
// groups
// Object groups can't have instances or be in other groups
if (!isObjectGroup) {
auto &groups = layout.GetObjects().GetObjectGroups();
layout.GetInitialInstances().RenameInstancesOfObject(oldName, newName);
for (std::size_t g = 0; g < layout.GetObjectGroups().size(); ++g) {
layout.GetObjectGroups()[g].RenameObject(oldName, newName);
for (std::size_t g = 0; g < groups.size(); ++g) {
groups[g].RenameObject(oldName, newName);
}
}
@@ -1717,54 +1720,62 @@ void WholeProjectRefactorer::RenameObjectEffect(gd::Project &project,
void WholeProjectRefactorer::ObjectRemovedInEventsBasedObject(
gd::Project &project, gd::EventsBasedObject &eventsBasedObject,
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer, const gd::String &objectName) {
const gd::String &objectName) {
for (auto &functionUniquePtr :
eventsBasedObject.GetEventsFunctions().GetInternalVector()) {
auto function = functionUniquePtr.get();
WholeProjectRefactorer::ObjectRemovedInEventsFunction(
project, *function, globalObjectsContainer, objectsContainer,
objectName);
WholeProjectRefactorer::ObjectRemovedInEventsFunction(project, *function,
objectName);
}
auto &groups = eventsBasedObject.GetObjects().GetObjectGroups();
for (std::size_t g = 0; g < groups.size(); ++g) {
if (groups[g].Find(objectName))
groups[g].RemoveObject(objectName);
}
eventsBasedObject.GetInitialInstances().RemoveInitialInstancesOfObject(
objectName);
}
void WholeProjectRefactorer::ObjectRemovedInEventsFunction(
gd::Project &project, gd::EventsFunction &eventsFunction,
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer, const gd::String &objectName) {
const gd::String &objectName) {
for (std::size_t g = 0; g < eventsFunction.GetObjectGroups().size();
++g) {
for (std::size_t g = 0; g < eventsFunction.GetObjectGroups().size(); ++g) {
if (eventsFunction.GetObjectGroups()[g].Find(objectName))
eventsFunction.GetObjectGroups()[g].RemoveObject(objectName);
}
}
void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
gd::Project &project, gd::ObjectsContainer &globalObjectsContainer,
gd::Project &project,
const gd::ProjectScopedContainers &projectScopedContainers,
gd::EventsBasedObject &eventsBasedObject, const gd::String &oldName,
const gd::String &newName, bool isObjectGroup) {
for (auto &functionUniquePtr :
eventsBasedObject.GetEventsFunctions().GetInternalVector()) {
auto *function = functionUniquePtr.get();
WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
project, *function, globalObjectsContainer, eventsBasedObject, oldName,
newName, isObjectGroup);
project, projectScopedContainers, *function, oldName, newName,
isObjectGroup);
}
// Object groups can't have instances or be in other groups
if (!isObjectGroup) {
eventsBasedObject.GetInitialInstances().RenameInstancesOfObject(oldName,
newName);
auto &groups = eventsBasedObject.GetObjects().GetObjectGroups();
for (std::size_t g = 0; g < groups.size(); ++g) {
groups[g].RenameObject(oldName, newName);
}
}
}
void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
gd::Project &project, gd::EventsFunction &eventsFunction,
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer, const gd::String &oldName,
gd::Project &project,
const gd::ProjectScopedContainers &projectScopedContainers,
gd::EventsFunction &eventsFunction, const gd::String &oldName,
const gd::String &newName, bool isObjectGroup) {
// In theory we should pass a ProjectScopedContainers to this function so it
// does not have to construct one. In practice, this is ok because we only
// deal with objects.
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(
globalObjectsContainer, objectsContainer);
gd::EventsRefactorer::RenameObjectInEvents(
project.GetCurrentPlatform(), projectScopedContainers,
eventsFunction.GetEvents(), oldName, newName);
@@ -1782,14 +1793,16 @@ void WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
bool isObjectGroup) {
// Object groups can't be in other groups
if (!isObjectGroup) {
for (std::size_t g = 0; g < project.GetObjectGroups().size(); ++g) {
project.GetObjectGroups()[g].RenameObject(oldName, newName);
for (std::size_t g = 0;
g < project.GetObjects().GetObjectGroups().size(); ++g) {
project.GetObjects().GetObjectGroups()[g].RenameObject(oldName,
newName);
}
}
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
gd::Layout &layout = project.GetLayout(i);
if (layout.HasObjectNamed(oldName))
if (layout.GetObjects().HasObjectNamed(oldName))
continue;
ObjectOrGroupRenamedInLayout(project, layout, oldName, newName,
@@ -1799,13 +1812,14 @@ void WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
void WholeProjectRefactorer::GlobalObjectRemoved(
gd::Project &project, const gd::String &objectName) {
for (std::size_t g = 0; g < project.GetObjectGroups().size(); ++g) {
project.GetObjectGroups()[g].RemoveObject(objectName);
auto &globalGroups = project.GetObjects().GetObjectGroups();
for (std::size_t g = 0; g < globalGroups.size(); ++g) {
globalGroups[g].RemoveObject(objectName);
}
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
gd::Layout &layout = project.GetLayout(i);
if (layout.HasObjectNamed(objectName))
if (layout.GetObjects().HasObjectNamed(objectName))
continue;
ObjectRemovedInLayout(project, layout, objectName);
@@ -1816,41 +1830,41 @@ void WholeProjectRefactorer::BehaviorsAddedToGlobalObject(
gd::Project &project, const gd::String &objectName) {
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
gd::Layout &layout = project.GetLayout(i);
if (layout.HasObjectNamed(objectName))
if (layout.GetObjects().HasObjectNamed(objectName))
continue;
BehaviorsAddedToObjectInLayout(project, layout, objectName);
}
}
void WholeProjectRefactorer::RemoveLayer(gd::Project &project,
gd::Layout &layout,
void WholeProjectRefactorer::RemoveLayerInScene(gd::Project &project,
gd::Layout &scene,
const gd::String &layerName) {
if (layerName.empty())
return;
layout.GetInitialInstances().RemoveAllInstancesOnLayer(layerName);
scene.GetInitialInstances().RemoveAllInstancesOnLayer(layerName);
std::vector<gd::String> externalLayoutsNames =
GetAssociatedExternalLayouts(project, layout);
GetAssociatedExternalLayouts(project, scene);
for (gd::String name : externalLayoutsNames) {
auto &externalLayout = project.GetExternalLayout(name);
externalLayout.GetInitialInstances().RemoveAllInstancesOnLayer(layerName);
}
}
void WholeProjectRefactorer::MergeLayers(gd::Project &project,
gd::Layout &layout,
void WholeProjectRefactorer::MergeLayersInScene(gd::Project &project,
gd::Layout &scene,
const gd::String &originLayerName,
const gd::String &targetLayerName) {
if (originLayerName == targetLayerName || originLayerName.empty())
return;
layout.GetInitialInstances().MoveInstancesToLayer(originLayerName,
scene.GetInitialInstances().MoveInstancesToLayer(originLayerName,
targetLayerName);
std::vector<gd::String> externalLayoutsNames =
GetAssociatedExternalLayouts(project, layout);
GetAssociatedExternalLayouts(project, scene);
for (gd::String name : externalLayoutsNames) {
auto &externalLayout = project.GetExternalLayout(name);
externalLayout.GetInitialInstances().MoveInstancesToLayer(originLayerName,
@@ -1858,6 +1872,24 @@ void WholeProjectRefactorer::MergeLayers(gd::Project &project,
}
}
void WholeProjectRefactorer::RemoveLayerInEventsBasedObject(
gd::EventsBasedObject &eventsBasedObject, const gd::String &layerName) {
if (layerName.empty())
return;
eventsBasedObject.GetInitialInstances().RemoveAllInstancesOnLayer(layerName);
}
void WholeProjectRefactorer::MergeLayersInEventsBasedObject(
gd::EventsBasedObject &eventsBasedObject, const gd::String &originLayerName,
const gd::String &targetLayerName) {
if (originLayerName == targetLayerName || originLayerName.empty())
return;
eventsBasedObject.GetInitialInstances().MoveInstancesToLayer(originLayerName,
targetLayerName);
}
size_t WholeProjectRefactorer::GetLayoutAndExternalLayoutLayerInstancesCount(
gd::Project &project, gd::Layout &layout, const gd::String &layerName) {
size_t count = layout.GetInitialInstances().GetLayerInstancesCount(layerName);

View File

@@ -37,6 +37,7 @@ class BehaviorMetadata;
class UnfilledRequiredBehaviorPropertyProblem;
class ProjectBrowser;
class SerializerElement;
class ProjectScopedContainers;
struct VariablesRenamingChangesetNode;
} // namespace gd
@@ -416,8 +417,6 @@ class GD_CORE_API WholeProjectRefactorer {
static void ObjectRemovedInEventsBasedObject(
gd::Project& project,
gd::EventsBasedObject& eventsBasedObject,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
const gd::String& objectName);
/**
@@ -427,7 +426,7 @@ class GD_CORE_API WholeProjectRefactorer {
*/
static void ObjectOrGroupRenamedInEventsBasedObject(
gd::Project& project,
gd::ObjectsContainer& globalObjectsContainer,
const gd::ProjectScopedContainers &projectScopedContainers,
gd::EventsBasedObject& eventsBasedObject,
const gd::String& oldName,
const gd::String& newName,
@@ -440,9 +439,8 @@ class GD_CORE_API WholeProjectRefactorer {
*/
static void ObjectOrGroupRenamedInEventsFunction(
gd::Project& project,
const gd::ProjectScopedContainers &projectScopedContainers,
gd::EventsFunction& eventsFunction,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
const gd::String& oldName,
const gd::String& newName,
bool isObjectGroup);
@@ -455,8 +453,6 @@ class GD_CORE_API WholeProjectRefactorer {
static void ObjectRemovedInEventsFunction(
gd::Project& project,
gd::EventsFunction& eventsFunction,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
const gd::String& objectName);
/**
@@ -518,16 +514,31 @@ class GD_CORE_API WholeProjectRefactorer {
/**
* \brief Remove all the instances from one layer.
*/
static void RemoveLayer(gd::Project &project, gd::Layout &layout,
static void RemoveLayerInScene(gd::Project &project, gd::Layout &scene,
const gd::String &layerName);
/**
* \brief Move all the instances from one layer into another.
*/
static void MergeLayers(gd::Project &project, gd::Layout &layout,
static void MergeLayersInScene(gd::Project &project, gd::Layout &scene,
const gd::String &originLayerName,
const gd::String &targetLayerName);
/**
* \brief Remove all the instances from one layer.
*/
static void
RemoveLayerInEventsBasedObject(gd::EventsBasedObject &eventsBasedObject,
const gd::String &layerName);
/**
* \brief Move all the instances from one layer into another.
*/
static void
MergeLayersInEventsBasedObject(gd::EventsBasedObject &eventsBasedObject,
const gd::String &originLayerName,
const gd::String &targetLayerName);
/**
* \brief Return the number of instances on the layer named \a layerName and
* all its associated layouts.

View File

@@ -35,19 +35,26 @@ std::unique_ptr<gd::ObjectConfiguration> CustomObjectConfiguration::Clone() cons
return gd::make_unique<gd::CustomObjectConfiguration>(*this);
}
gd::ObjectConfiguration &CustomObjectConfiguration::GetChildObjectConfiguration(const gd::String &objectName) {
const gd::EventsBasedObject* CustomObjectConfiguration::GetEventsBasedObject() const {
if (!project->HasEventsBasedObject(GetType())) {
return nullptr;
}
return &project->GetEventsBasedObject(GetType());
}
gd::ObjectConfiguration &CustomObjectConfiguration::GetChildObjectConfiguration(const gd::String &objectName) {
const auto *eventsBasedObject = GetEventsBasedObject();
if (!eventsBasedObject) {
return badObjectConfiguration;
}
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
if (!eventsBasedObject.HasObjectNamed(objectName)) {
if (!eventsBasedObject->GetObjects().HasObjectNamed(objectName)) {
gd::LogError("Tried to get the configuration of a child-object:" + objectName
+ " that doesn't exist in the event-based object: " + GetType());
return badObjectConfiguration;
}
auto &childObject = eventsBasedObject.GetObject(objectName);
auto &childObject = eventsBasedObject->GetObjects().GetObject(objectName);
auto configurationPosition = childObjectConfigurations.find(objectName);
if (configurationPosition == childObjectConfigurations.end()) {
childObjectConfigurations.insert(std::make_pair(
@@ -90,8 +97,7 @@ bool CustomObjectConfiguration::UpdateProperty(const gd::String& propertyName,
std::map<gd::String, gd::PropertyDescriptor>
CustomObjectConfiguration::GetInitialInstanceProperties(
const gd::InitialInstance &initialInstance, gd::Project &project,
gd::Layout &scene) {
const gd::InitialInstance &initialInstance) {
std::map<gd::String, gd::PropertyDescriptor> properties;
if (!animations.HasNoAnimations()) {
properties["animation"] =
@@ -105,7 +111,7 @@ CustomObjectConfiguration::GetInitialInstanceProperties(
bool CustomObjectConfiguration::UpdateInitialInstanceProperty(
gd::InitialInstance &initialInstance, const gd::String &name,
const gd::String &value, gd::Project &project, gd::Layout &scene) {
const gd::String &value) {
if (name == "animation") {
initialInstance.SetRawDoubleProperty(
"animation", std::max(0, value.empty() ? 0 : value.To<int>()));
@@ -129,6 +135,20 @@ void CustomObjectConfiguration::DoSerializeTo(SerializerElement& element) const
auto &childElement = childrenContentElement.AddChild(childName);
childConfiguration->SerializeTo(childElement);
}
const auto *eventsBasedObject = GetEventsBasedObject();
if (eventsBasedObject) {
eventsBasedObject->GetInitialInstances().SerializeTo(
element.AddChild("instances"));
eventsBasedObject->GetLayers().SerializeLayersTo(
element.AddChild("layers"));
element.SetIntAttribute("areaMinX", eventsBasedObject->GetAreaMinX());
element.SetIntAttribute("areaMinY", eventsBasedObject->GetAreaMinY());
element.SetIntAttribute("areaMinZ", eventsBasedObject->GetAreaMinZ());
element.SetIntAttribute("areaMaxX", eventsBasedObject->GetAreaMaxX());
element.SetIntAttribute("areaMaxY", eventsBasedObject->GetAreaMaxY());
element.SetIntAttribute("areaMaxZ", eventsBasedObject->GetAreaMaxZ());
}
}
void CustomObjectConfiguration::DoUnserializeFrom(Project& project,
const SerializerElement& element) {
@@ -198,7 +218,7 @@ void CustomObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker& wor
}
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
for (auto& childObject : eventsBasedObject.GetObjects()) {
for (auto& childObject : eventsBasedObject.GetObjects().GetObjects()) {
auto &configuration = GetChildObjectConfiguration(childObject->GetName());
configuration.ExposeResources(worker);
}

View File

@@ -58,14 +58,10 @@ class CustomObjectConfiguration : public gd::ObjectConfiguration {
bool UpdateProperty(const gd::String& name, const gd::String& value) override;
std::map<gd::String, gd::PropertyDescriptor> GetInitialInstanceProperties(
const gd::InitialInstance& instance,
gd::Project& project,
gd::Layout& scene) override;
const gd::InitialInstance& instance) override;
bool UpdateInitialInstanceProperty(gd::InitialInstance& instance,
const gd::String& name,
const gd::String& value,
gd::Project& project,
gd::Layout& scene) override;
const gd::String& value) override;
void ExposeResources(gd::ArbitraryResourceWorker& worker) override;
@@ -86,6 +82,8 @@ protected:
void DoUnserializeFrom(Project& project, const SerializerElement& element) override;
private:
const gd::EventsBasedObject* GetEventsBasedObject() const;
const Project* project; ///< The project is used to get the
///< EventBasedObject from the fullType.
gd::SerializerElement objectContent;

View File

@@ -13,21 +13,19 @@ EventsBasedObject::EventsBasedObject()
: AbstractEventsBasedEntity(
"MyObject",
gd::EventsFunctionsContainer::FunctionOwner::Object),
ObjectsContainer(),
isRenderedIn3D(false),
isAnimatable(false),
isTextContainer(false) {
isTextContainer(false),
areaMinX(0),
areaMinY(0),
areaMinZ(0),
areaMaxX(64),
areaMaxY(64),
areaMaxZ(64) {
}
EventsBasedObject::~EventsBasedObject() {}
EventsBasedObject::EventsBasedObject(const gd::EventsBasedObject &_eventBasedObject)
: AbstractEventsBasedEntity(_eventBasedObject) {
// TODO Add a copy constructor in ObjectsContainer.
initialObjects = gd::Clone(_eventBasedObject.initialObjects);
objectGroups = _eventBasedObject.objectGroups;
}
void EventsBasedObject::SerializeTo(SerializerElement& element) const {
element.SetAttribute("defaultName", defaultName);
if (isRenderedIn3D) {
@@ -39,10 +37,20 @@ void EventsBasedObject::SerializeTo(SerializerElement& element) const {
if (isTextContainer) {
element.SetBoolAttribute("isTextContainer", true);
}
element.SetIntAttribute("areaMinX", areaMinX);
element.SetIntAttribute("areaMinY", areaMinY);
element.SetIntAttribute("areaMinZ", areaMinZ);
element.SetIntAttribute("areaMaxX", areaMaxX);
element.SetIntAttribute("areaMaxY", areaMaxY);
element.SetIntAttribute("areaMaxZ", areaMaxZ);
AbstractEventsBasedEntity::SerializeTo(element);
SerializeObjectsTo(element.AddChild("objects"));
SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
objectsContainer.SerializeObjectsTo(element.AddChild("objects"));
objectsContainer.SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
objectsContainer.GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
layers.SerializeLayersTo(element.AddChild("layers"));
initialInstances.SerializeTo(element.AddChild("instances"));
}
void EventsBasedObject::UnserializeFrom(gd::Project& project,
@@ -51,13 +59,29 @@ void EventsBasedObject::UnserializeFrom(gd::Project& project,
isRenderedIn3D = element.GetBoolAttribute("is3D", false);
isAnimatable = element.GetBoolAttribute("isAnimatable", false);
isTextContainer = element.GetBoolAttribute("isTextContainer", false);
areaMinX = element.GetIntAttribute("areaMinX", 0);
areaMinY = element.GetIntAttribute("areaMinY", 0);
areaMinZ = element.GetIntAttribute("areaMinZ", 0);
areaMaxX = element.GetIntAttribute("areaMaxX", 64);
areaMaxY = element.GetIntAttribute("areaMaxY", 64);
areaMaxZ = element.GetIntAttribute("areaMaxZ", 64);
AbstractEventsBasedEntity::UnserializeFrom(project, element);
UnserializeObjectsFrom(project, element.GetChild("objects"));
objectsContainer.UnserializeObjectsFrom(project, element.GetChild("objects"));
if (element.HasChild("objectsFolderStructure")) {
UnserializeFoldersFrom(project, element.GetChild("objectsFolderStructure", 0));
objectsContainer.UnserializeFoldersFrom(project, element.GetChild("objectsFolderStructure", 0));
}
AddMissingObjectsInRootFolder();
objectsContainer.AddMissingObjectsInRootFolder();
objectsContainer.GetObjectGroups().UnserializeFrom(
element.GetChild("objectsGroups"));
if (element.HasChild("layers")) {
layers.UnserializeLayersFrom(element.GetChild("layers"));
} else {
layers.Reset();
}
initialInstances.UnserializeFrom(element.GetChild("instances"));
}
} // namespace gd

View File

@@ -3,12 +3,13 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EVENTSBASEDOBJECT_H
#define GDCORE_EVENTSBASEDOBJECT_H
#pragma once
#include <vector>
#include "GDCore/Project/AbstractEventsBasedEntity.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/InitialInstancesContainer.h"
#include "GDCore/Project/LayersContainer.h"
#include "GDCore/String.h"
namespace gd {
class SerializerElement;
@@ -26,11 +27,10 @@ namespace gd {
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public ObjectsContainer {
class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
public:
EventsBasedObject();
virtual ~EventsBasedObject();
EventsBasedObject(const gd::EventsBasedObject &_eventBasedObject);
/**
* \brief Return a pointer to a new EventsBasedObject constructed from
@@ -111,6 +111,164 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public Ob
*/
bool IsTextContainer() const { return isTextContainer; }
/** \name Layers
*/
///@{
/**
* \brief Get the layers of the custom object.
*/
const gd::LayersContainer& GetLayers() const { return layers; }
/**
* \brief Get the layers of the custom object.
*/
gd::LayersContainer& GetLayers() { return layers; }
///@}
/** \name Child objects
*/
///@{
/**
* \brief Get the objects of the custom object.
*/
gd::ObjectsContainer& GetObjects() {
return objectsContainer;
}
/**
* \brief Get the objects of the custom object.
*/
const gd::ObjectsContainer& GetObjects() const {
return objectsContainer;
}
///@}
/** \name Instances
*/
///@{
/**
* \brief Get the instances of the custom object.
*/
gd::InitialInstancesContainer& GetInitialInstances() {
return initialInstances;
}
/**
* \brief Get the instances of the custom object.
*/
const gd::InitialInstancesContainer& GetInitialInstances() const {
return initialInstances;
}
/**
* \brief Get the left bound of the custom object.
*
* This is used only if there is any initial instances.
*
* \see EventsBasedObject::GetInitialInstances
*/
int GetAreaMinX() const {
return areaMinX;
}
/**
* \brief Set the left bound of the custom object.
*/
void SetAreaMinX(int areaMinX_) {
areaMinX = areaMinX_;
}
/**
* \brief Get the top bound of the custom object.
*
* This is used only if there is any initial instances.
*
* \see EventsBasedObject::GetInitialInstances
*/
int GetAreaMinY() const {
return areaMinY;
}
/**
* \brief Set the top bound of the custom object.
*/
void SetAreaMinY(int areaMinY_) {
areaMinY = areaMinY_;
}
/**
* \brief Get the min Z bound of the custom object.
*
* This is used only if there is any initial instances.
*
* \see EventsBasedObject::GetInitialInstances
*/
int GetAreaMinZ() const {
return areaMinZ;
}
/**
* \brief Set the min Z bound of the custom object.
*/
void SetAreaMinZ(int areaMinZ_) {
areaMinZ = areaMinZ_;
}
/**
* \brief Get the right bound of the custom object.
*
* This is used only if there is any initial instances.
*
* \see EventsBasedObject::GetInitialInstances
*/
int GetAreaMaxX() const {
return areaMaxX;
}
/**
* \brief Set the right bound of the custom object.
*/
void SetAreaMaxX(int areaMaxX_) {
areaMaxX = areaMaxX_;
}
/**
* \brief Get the bottom bound of the custom object.
*
* This is used only if there is any initial instances.
*
* \see EventsBasedObject::GetInitialInstances
*/
int GetAreaMaxY() const {
return areaMaxY;
}
/**
* \brief Set the bottom bound of the custom object.
*/
void SetAreaMaxY(int areaMaxY_) {
areaMaxY = areaMaxY_;
}
/**
* \brief Get the max Z bound of the custom object.
*
* This is used only if there is any initial instances.
*
* \see EventsBasedObject::GetInitialInstances
*/
int GetAreaMaxZ() const {
return areaMaxZ;
}
/**
* \brief Set the bottom bound of the custom object.
*/
void SetAreaMaxZ(int areaMaxZ_) {
areaMaxZ = areaMaxZ_;
}
///@}
void SerializeTo(SerializerElement& element) const override;
void UnserializeFrom(gd::Project& project,
@@ -121,8 +279,15 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public Ob
bool isRenderedIn3D;
bool isAnimatable;
bool isTextContainer;
gd::InitialInstancesContainer initialInstances;
gd::LayersContainer layers;
gd::ObjectsContainer objectsContainer;
double areaMinX;
double areaMinY;
double areaMinZ;
double areaMaxX;
double areaMaxY;
double areaMaxZ;
};
} // namespace gd
#endif // GDCORE_EVENTSBASEDOBJECT_H

View File

@@ -154,7 +154,7 @@ void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
for (size_t i = 0; i < dependenciesElement.GetChildrenCount(); ++i)
dependencies.push_back(
UnserializeDependencyFrom(dependenciesElement.GetChild(i)));
globalVariables.UnserializeFrom(element.GetChild("globalVariables"));
sceneVariables.UnserializeFrom(element.GetChild("sceneVariables"));
@@ -184,7 +184,11 @@ void EventsFunctionsExtension::UnserializeExtensionImplementationFrom(
UnserializeEventsFunctionsFrom(project, element.GetChild("eventsFunctions"));
eventsBasedBehaviors.UnserializeElementsFrom(
"eventsBasedBehavior", project, element.GetChild("eventsBasedBehaviors"));
eventsBasedObjects.UnserializeElementsFrom(
// It's important to load the objects without erasing them first as each object
// might reference other objects, and so need to know if a custom object exists
// in the project or not.
eventsBasedObjects.ProgressivelyUnserializeElementsFrom(
"eventsBasedObject", project, element.GetChild("eventsBasedObjects"));
}

View File

@@ -9,7 +9,6 @@
#include "GDCore/IDE/Dialogs/LayoutEditorCanvas/EditorSettings.h"
#include "GDCore/Project/InitialInstancesContainer.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/TinyXml/tinyxml.h"
namespace gd {

View File

@@ -8,6 +8,7 @@
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/SerializerElement.h"
@@ -153,33 +154,35 @@ InitialInstance& InitialInstance::ResetPersistentUuid() {
}
std::map<gd::String, gd::PropertyDescriptor>
InitialInstance::GetCustomProperties(gd::Project& project, gd::Layout& layout) {
InitialInstance::GetCustomProperties(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer) {
// Find an object
if (layout.HasObjectNamed(GetObjectName()))
return layout.GetObject(GetObjectName())
if (objectsContainer.HasObjectNamed(GetObjectName()))
return objectsContainer.GetObject(GetObjectName())
.GetConfiguration()
.GetInitialInstanceProperties(*this, project, layout);
else if (project.HasObjectNamed(GetObjectName()))
return project.GetObject(GetObjectName())
.GetInitialInstanceProperties(*this);
else if (globalObjectsContainer.HasObjectNamed(GetObjectName()))
return globalObjectsContainer.GetObject(GetObjectName())
.GetConfiguration()
.GetInitialInstanceProperties(*this, project, layout);
.GetInitialInstanceProperties(*this);
std::map<gd::String, gd::PropertyDescriptor> nothing;
return nothing;
}
bool InitialInstance::UpdateCustomProperty(const gd::String& name,
const gd::String& value,
gd::Project& project,
gd::Layout& layout) {
if (layout.HasObjectNamed(GetObjectName()))
return layout.GetObject(GetObjectName())
bool InitialInstance::UpdateCustomProperty(
const gd::String &name, const gd::String &value,
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer) {
if (objectsContainer.HasObjectNamed(GetObjectName()))
return objectsContainer.GetObject(GetObjectName())
.GetConfiguration()
.UpdateInitialInstanceProperty(*this, name, value, project, layout);
else if (project.HasObjectNamed(GetObjectName()))
return project.GetObject(GetObjectName())
.UpdateInitialInstanceProperty(*this, name, value);
else if (globalObjectsContainer.HasObjectNamed(GetObjectName()))
return globalObjectsContainer.GetObject(GetObjectName())
.GetConfiguration()
.UpdateInitialInstanceProperty(*this, name, value, project, layout);
.UpdateInitialInstanceProperty(*this, name, value);
return false;
}

View File

@@ -4,8 +4,8 @@
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_INITIALINSTANCE_H
#define GDCORE_INITIALINSTANCE_H
#pragma once
#include <map>
#include "GDCore/Project/VariablesContainer.h"
@@ -14,6 +14,7 @@ namespace gd {
class PropertyDescriptor;
class Project;
class Layout;
class ObjectsContainer;
} // namespace gd
namespace gd {
@@ -263,18 +264,18 @@ class GD_CORE_API InitialInstance {
* \note Common properties ( name, position... ) do not need to be
* inserted in this map
*/
std::map<gd::String, gd::PropertyDescriptor> GetCustomProperties(
gd::Project& project, gd::Layout& layout);
std::map<gd::String, gd::PropertyDescriptor>
GetCustomProperties(gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer);
/**
* \brief Update the property called \a name with the new \a value.
*
* \return false if the property could not be updated.
*/
bool UpdateCustomProperty(const gd::String& name,
const gd::String& value,
gd::Project& project,
gd::Layout& layout);
bool UpdateCustomProperty(const gd::String &name, const gd::String &value,
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer);
/**
* \brief Get the value of a double property stored in the instance.
@@ -361,5 +362,3 @@ class GD_CORE_API InitialInstance {
};
} // namespace gd
#endif // GDCORE_INITIALINSTANCE_H

View File

@@ -294,17 +294,6 @@ class GD_CORE_API Layer {
static gd::Camera badCamera;
};
/**
* \brief Functor testing layer name
*
* \see gd::Layer
*/
struct LayerHasName : public std::binary_function<gd::Layer, gd::String, bool> {
bool operator()(const Layer& layer, const gd::String& name) const {
return layer.GetName() == name;
}
};
} // namespace gd
#endif // GDCORE_LAYER_H

View File

@@ -0,0 +1,138 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "LayersContainer.h"
#include <algorithm>
#include <vector>
#include "Layer.h"
#include "Layout.h"
using namespace std;
namespace gd {
gd::Layer LayersContainer::badLayer;
LayersContainer::LayersContainer() {
Reset();
}
void LayersContainer::Reset() {
layers.clear();
gd::Layer layer;
layer.SetCameraCount(1);
layers.push_back(layer);
}
gd::Layer& LayersContainer::GetLayer(const gd::String& name) {
std::vector<gd::Layer>::iterator layer =
find_if(layers.begin(), layers.end(), [&name](const gd::Layer& layer) {
return layer.GetName() == name;
});
if (layer != layers.end()) return *layer;
return badLayer;
}
const gd::Layer& LayersContainer::GetLayer(const gd::String& name) const {
std::vector<gd::Layer>::const_iterator layer =
find_if(layers.begin(), layers.end(), [&name](const gd::Layer& layer) {
return layer.GetName() == name;
});
if (layer != layers.end()) return *layer;
return badLayer;
}
gd::Layer& LayersContainer::GetLayer(std::size_t index) {
return layers[index];
}
const gd::Layer& LayersContainer::GetLayer(std::size_t index) const {
return layers[index];
}
std::size_t LayersContainer::GetLayersCount() const { return layers.size(); }
bool LayersContainer::HasLayerNamed(const gd::String& name) const {
return (
find_if(layers.begin(), layers.end(), [&name](const gd::Layer& layer) {
return layer.GetName() == name;
}) != layers.end());
}
std::size_t LayersContainer::GetLayerPosition(const gd::String& name) const {
for (std::size_t i = 0; i < layers.size(); ++i) {
if (layers[i].GetName() == name) return i;
}
return gd::String::npos;
}
void LayersContainer::InsertNewLayer(const gd::String& name,
std::size_t position) {
gd::Layer newLayer;
newLayer.SetName(name);
if (position < layers.size())
layers.insert(layers.begin() + position, newLayer);
else
layers.push_back(newLayer);
}
void LayersContainer::InsertLayer(const gd::Layer& layer,
std::size_t position) {
if (position < layers.size())
layers.insert(layers.begin() + position, layer);
else
layers.push_back(layer);
}
void LayersContainer::RemoveLayer(const gd::String& name) {
std::vector<gd::Layer>::iterator layer =
find_if(layers.begin(), layers.end(), [&name](const gd::Layer& layer) {
return layer.GetName() == name;
});
if (layer == layers.end()) return;
layers.erase(layer);
}
void LayersContainer::SwapLayers(std::size_t firstLayerIndex,
std::size_t secondLayerIndex) {
if (firstLayerIndex >= layers.size() || secondLayerIndex >= layers.size())
return;
std::iter_swap(layers.begin() + firstLayerIndex,
layers.begin() + secondLayerIndex);
}
void LayersContainer::MoveLayer(std::size_t oldIndex, std::size_t newIndex) {
if (oldIndex >= layers.size() || newIndex >= layers.size()) return;
auto layer = layers[oldIndex];
layers.erase(layers.begin() + oldIndex);
InsertLayer(layer, newIndex);
}
void LayersContainer::SerializeLayersTo(SerializerElement& element) const {
element.ConsiderAsArrayOf("layer");
for (std::size_t j = 0; j < GetLayersCount(); ++j)
GetLayer(j).SerializeTo(element.AddChild("layer"));
}
void LayersContainer::UnserializeLayersFrom(const SerializerElement& element) {
layers.clear();
element.ConsiderAsArrayOf("layer", "Layer");
for (std::size_t i = 0; i < element.GetChildrenCount(); ++i) {
gd::Layer layer;
layer.UnserializeFrom(element.GetChild(i));
layers.push_back(layer);
}
}
} // namespace gd

View File

@@ -0,0 +1,109 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <vector>
#include "GDCore/Project/Layer.h"
#include "GDCore/String.h"
namespace gd {
/**
* \brief Contains the layers for a scene or a custom object.
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API LayersContainer {
public:
LayersContainer();
/**
* \brief Return true if the layer called "name" exists.
*/
bool HasLayerNamed(const gd::String& name) const;
/**
* \brief Return a reference to the layer called "name".
*/
Layer& GetLayer(const gd::String& name);
/**
* \brief Return a reference to the layer called "name".
*/
const Layer& GetLayer(const gd::String& name) const;
/**
* \brief Return a reference to the layer at position "index" in the layers
* list.
*/
Layer& GetLayer(std::size_t index);
/**
* \brief Return a reference to the layer at position "index" in the layers
* list.
*/
const Layer& GetLayer(std::size_t index) const;
/**
* \brief Return the position of the layer called "name" in the layers list.
*/
std::size_t GetLayerPosition(const gd::String& name) const;
/**
* The number of layers.
*/
std::size_t GetLayersCount() const;
/**
* Add a new empty the layer sheet called "name" at the specified
* position in the layers list.
*/
void InsertNewLayer(const gd::String& name, std::size_t position);
/**
* Add a new layer constructed from the layer passed as parameter.
*
* \param theLayer The layer that must be copied and inserted.
* \param position Insertion position.
*/
void InsertLayer(const Layer& theLayer, std::size_t position);
/**
* Delete the layer named "name".
*/
void RemoveLayer(const gd::String& name);
/**
* Swap the position of the specified layers.
*/
void SwapLayers(std::size_t firstLayerIndex, std::size_t secondLayerIndex);
/**
* Change the position of the specified layer.
*/
void MoveLayer(std::size_t oldIndex, std::size_t newIndex);
void Reset();
/**
* \brief Serialize the layers.
*/
void SerializeLayersTo(SerializerElement& element) const;
/**
* \brief Unserialize the layers.
*/
void UnserializeLayersFrom(const SerializerElement& element);
private:
static gd::Layer badLayer; ///< Null object, returned when GetLayer can not
///< find an appropriate layer.
std::vector<gd::Layer> layers; ///< Layers
};
} // namespace gd

View File

@@ -33,7 +33,6 @@ using namespace std;
namespace gd {
gd::Layer Layout::badLayer;
gd::BehaviorsSharedData Layout::badBehaviorSharedData("", "");
Layout::Layout(const Layout& other) { Init(other); }
@@ -53,12 +52,8 @@ Layout::Layout()
stopSoundsOnStartup(true),
standardSortMethod(true),
disableInputWhenNotFocused(true),
profiler(NULL),
variables(gd::VariablesContainer::SourceType::Scene)
{
gd::Layer layer;
layer.SetCameraCount(1);
initialLayers.push_back(layer);
}
void Layout::SetName(const gd::String& name_) {
@@ -100,91 +95,47 @@ Layout::GetAllBehaviorSharedData() const {
}
gd::Layer& Layout::GetLayer(const gd::String& name) {
std::vector<gd::Layer>::iterator layer =
find_if(initialLayers.begin(),
initialLayers.end(),
bind2nd(gd::LayerHasName(), name));
if (layer != initialLayers.end()) return *layer;
return badLayer;
return layers.GetLayer(name);
}
const gd::Layer& Layout::GetLayer(const gd::String& name) const {
std::vector<gd::Layer>::const_iterator layer =
find_if(initialLayers.begin(),
initialLayers.end(),
bind2nd(gd::LayerHasName(), name));
if (layer != initialLayers.end()) return *layer;
return badLayer;
return layers.GetLayer(name);
}
gd::Layer& Layout::GetLayer(std::size_t index) { return initialLayers[index]; }
gd::Layer& Layout::GetLayer(std::size_t index) { return layers.GetLayer(index); }
const gd::Layer& Layout::GetLayer(std::size_t index) const {
return initialLayers[index];
return layers.GetLayer(index);
}
std::size_t Layout::GetLayersCount() const { return initialLayers.size(); }
std::size_t Layout::GetLayersCount() const { return layers.GetLayersCount(); }
#if defined(GD_IDE_ONLY)
bool Layout::HasLayerNamed(const gd::String& name) const {
return (find_if(initialLayers.begin(),
initialLayers.end(),
bind2nd(gd::LayerHasName(), name)) != initialLayers.end());
return layers.HasLayerNamed(name);
}
std::size_t Layout::GetLayerPosition(const gd::String& name) const {
for (std::size_t i = 0; i < initialLayers.size(); ++i) {
if (initialLayers[i].GetName() == name) return i;
}
return gd::String::npos;
return layers.GetLayerPosition(name);
}
void Layout::InsertNewLayer(const gd::String& name, std::size_t position) {
gd::Layer newLayer;
newLayer.SetName(name);
if (position < initialLayers.size())
initialLayers.insert(initialLayers.begin() + position, newLayer);
else
initialLayers.push_back(newLayer);
layers.InsertNewLayer(name, position);
}
void Layout::InsertLayer(const gd::Layer& layer, std::size_t position) {
if (position < initialLayers.size())
initialLayers.insert(initialLayers.begin() + position, layer);
else
initialLayers.push_back(layer);
layers.InsertLayer(layer, position);
}
void Layout::RemoveLayer(const gd::String& name) {
std::vector<gd::Layer>::iterator layer =
find_if(initialLayers.begin(),
initialLayers.end(),
bind2nd(gd::LayerHasName(), name));
if (layer == initialLayers.end()) return;
initialLayers.erase(layer);
layers.RemoveLayer(name);
}
void Layout::SwapLayers(std::size_t firstLayerIndex,
std::size_t secondLayerIndex) {
if (firstLayerIndex >= initialLayers.size() ||
secondLayerIndex >= initialLayers.size())
return;
std::iter_swap(initialLayers.begin() + firstLayerIndex,
initialLayers.begin() + secondLayerIndex);
layers.SwapLayers(firstLayerIndex, secondLayerIndex);
}
void Layout::MoveLayer(std::size_t oldIndex, std::size_t newIndex) {
if (oldIndex >= initialLayers.size() || newIndex >= initialLayers.size())
return;
auto layer = initialLayers[oldIndex];
initialLayers.erase(initialLayers.begin() + oldIndex);
InsertLayer(layer, newIndex);
layers.MoveLayer(oldIndex, newIndex);
}
void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
@@ -192,22 +143,23 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
std::vector<gd::String> allBehaviorsNames;
// Search in objects for the type and the name of every behaviors.
for (std::size_t i = 0; i < initialObjects.size(); ++i) {
for (std::size_t i = 0; i < objectsContainer.GetObjectsCount(); ++i) {
std::vector<gd::String> objectBehaviors =
initialObjects[i]->GetAllBehaviorNames();
objectsContainer.GetObject(i).GetAllBehaviorNames();
for (unsigned int j = 0; j < objectBehaviors.size(); ++j) {
auto& behavior =
initialObjects[i]->GetBehavior(objectBehaviors[j]);
objectsContainer.GetObject(i).GetBehavior(objectBehaviors[j]);
allBehaviorsTypes.push_back(behavior.GetTypeName());
allBehaviorsNames.push_back(behavior.GetName());
}
}
for (std::size_t i = 0; i < project.GetObjectsCount(); ++i) {
auto &globalObjects = project.GetObjects();
for (std::size_t i = 0; i < globalObjects.GetObjectsCount(); ++i) {
std::vector<gd::String> objectBehaviors =
project.GetObject(i).GetAllBehaviorNames();
globalObjects.GetObject(i).GetAllBehaviorNames();
for (std::size_t j = 0; j < objectBehaviors.size(); ++j) {
auto& behavior =
project.GetObject(i).GetBehavior(objectBehaviors[j]);
globalObjects.GetObject(i).GetBehavior(objectBehaviors[j]);
allBehaviorsTypes.push_back(behavior.GetTypeName());
allBehaviorsNames.push_back(behavior.GetName());
}
@@ -291,15 +243,15 @@ void Layout::SerializeTo(SerializerElement& element) const {
editorSettings.SerializeTo(element.AddChild("uiSettings"));
GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
objectsContainer.GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
GetVariables().SerializeTo(element.AddChild("variables"));
GetInitialInstances().SerializeTo(element.AddChild("instances"));
SerializeObjectsTo(element.AddChild("objects"));
SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
objectsContainer.SerializeObjectsTo(element.AddChild("objects"));
objectsContainer.SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
gd::EventsListSerialization::SerializeEventsTo(events,
element.AddChild("events"));
SerializeLayersTo(element.AddChild("layers"));
layers.SerializeLayersTo(element.AddChild("layers"));
SerializerElement& behaviorDatasElement =
element.AddChild("behaviorsSharedData");
@@ -317,23 +269,6 @@ void Layout::SerializeTo(SerializerElement& element) const {
}
}
void Layout::SerializeLayersTo(SerializerElement& element) const {
element.ConsiderAsArrayOf("layer");
for (std::size_t j = 0; j < GetLayersCount(); ++j)
GetLayer(j).SerializeTo(element.AddChild("layer"));
}
#endif
void Layout::UnserializeLayersFrom(const SerializerElement& element) {
initialLayers.clear();
element.ConsiderAsArrayOf("layer", "Layer");
for (std::size_t i = 0; i < element.GetChildrenCount(); ++i) {
gd::Layer layer;
layer.UnserializeFrom(element.GetChild(i));
initialLayers.push_back(layer);
}
}
void Layout::UnserializeFrom(gd::Project& project,
const SerializerElement& element) {
SetBackgroundColor(element.GetIntAttribute("r"),
@@ -349,22 +284,22 @@ void Layout::UnserializeFrom(gd::Project& project,
editorSettings.UnserializeFrom(
element.GetChild("uiSettings", 0, "UISettings"));
GetObjectGroups().UnserializeFrom(
objectsContainer.GetObjectGroups().UnserializeFrom(
element.GetChild("objectsGroups", 0, "GroupesObjets"));
gd::EventsListSerialization::UnserializeEventsFrom(
project, GetEvents(), element.GetChild("events", 0, "Events"));
UnserializeObjectsFrom(project, element.GetChild("objects", 0, "Objets"));
objectsContainer.UnserializeObjectsFrom(project, element.GetChild("objects", 0, "Objets"));
if (element.HasChild("objectsFolderStructure")) {
UnserializeFoldersFrom(project, element.GetChild("objectsFolderStructure", 0));
objectsContainer.UnserializeFoldersFrom(project, element.GetChild("objectsFolderStructure", 0));
}
AddMissingObjectsInRootFolder();
objectsContainer.AddMissingObjectsInRootFolder();
initialInstances.UnserializeFrom(
element.GetChild("instances", 0, "Positions"));
variables.UnserializeFrom(element.GetChild("variables", 0, "Variables"));
UnserializeLayersFrom(element.GetChild("layers", 0, "Layers"));
layers.UnserializeLayersFrom(element.GetChild("layers", 0, "Layers"));
// Compatibility with GD <= 4
gd::String deprecatedTag1 = "automatismsSharedData";
@@ -416,10 +351,10 @@ void Layout::Init(const Layout& other) {
stopSoundsOnStartup = other.stopSoundsOnStartup;
disableInputWhenNotFocused = other.disableInputWhenNotFocused;
initialInstances = other.initialInstances;
initialLayers = other.initialLayers;
layers = other.layers;
variables = other.GetVariables();
initialObjects = gd::Clone(other.initialObjects);
objectsContainer = other.objectsContainer;
behaviorsSharedData.clear();
for (const auto& it : other.behaviorsSharedData) {
@@ -429,9 +364,6 @@ void Layout::Init(const Layout& other) {
events = other.events;
editorSettings = other.editorSettings;
objectGroups = other.objectGroups;
profiler = other.profiler;
}
std::vector<gd::String> GetHiddenLayers(const Layout& layout) {

View File

@@ -9,15 +9,17 @@
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/EventsList.h"
#include "GDCore/IDE/Dialogs/LayoutEditorCanvas/EditorSettings.h"
#include "GDCore/Project/BehaviorsSharedData.h"
#include "GDCore/Project/InitialInstancesContainer.h"
#include "GDCore/Project/Layer.h"
#include "GDCore/Project/LayersContainer.h"
#include "GDCore/Project/ObjectGroupsContainer.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/VariablesContainer.h"
#include "GDCore/String.h"
#include "GDCore/IDE/Dialogs/LayoutEditorCanvas/EditorSettings.h"
namespace gd {
class BaseEvent;
@@ -25,7 +27,6 @@ class Object;
class Project;
class InitialInstancesContainer;
} // namespace gd
class TiXmlElement;
class BaseProfiler;
#undef GetObject // Disable an annoying macro
@@ -36,7 +37,7 @@ namespace gd {
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API Layout : public ObjectsContainer {
class GD_CORE_API Layout {
public:
Layout();
Layout(const Layout&);
@@ -104,6 +105,24 @@ class GD_CORE_API Layout : public ObjectsContainer {
///@}
/** \name Layout's objects
*/
///@{
/**
* \brief return the objects of the scene.
*/
gd::ObjectsContainer& GetObjects() {
return objectsContainer;
}
/**
* \brief Return the objects of the scene.
*/
const gd::ObjectsContainer& GetObjects() const {
return objectsContainer;
}
///@}
/** \name Layout's initial instances
* Members functions related to initial instances of objects created at the
* layout start up
@@ -147,103 +166,96 @@ class GD_CORE_API Layout : public ObjectsContainer {
///@{
/**
* Provide access to the gd::VariablesContainer member containing the layout
* variables \see gd::VariablesContainer
* \brief Get the variables of the scene.
*
* \see gd::VariablesContainer
*/
inline const gd::VariablesContainer& GetVariables() const {
return variables;
}
/**
* Provide access to the gd::VariablesContainer member containing the layout
* variables \see gd::VariablesContainer
* \brief Get the variables of the scene.
*
* \see gd::VariablesContainer
*/
inline gd::VariablesContainer& GetVariables() { return variables; }
///@}
/** \name Layout layers management
* Members functions related to layout layers management.
* TODO: This could be moved to a separate class
/** \name Layers
*/
///@{
/**
* \brief Return true if the layer called "name" exists.
* \brief Get the layers of the scene.
*/
const gd::LayersContainer& GetLayers() const { return layers; }
/**
* \brief Get the layers of the scene.
*/
gd::LayersContainer& GetLayers() { return layers; }
/**
* @deprecated
*/
bool HasLayerNamed(const gd::String& name) const;
/**
* \brief Return a reference to the layer called "name".
* @deprecated
*/
Layer& GetLayer(const gd::String& name);
/**
* \brief Return a reference to the layer called "name".
* @deprecated
*/
const Layer& GetLayer(const gd::String& name) const;
/**
* \brief Return a reference to the layer at position "index" in the layers
* list
* @deprecated
*/
Layer& GetLayer(std::size_t index);
/**
* \brief Return a reference to the layer at position "index" in the layers
* list
* @deprecated
*/
const Layer& GetLayer(std::size_t index) const;
/**
* \brief Return the position of the layer called "name" in the layers list
* @deprecated
*/
std::size_t GetLayerPosition(const gd::String& name) const;
/**
* Must return the number of layers.
* @deprecated
*/
std::size_t GetLayersCount() const;
/**
* Must add a new empty the layer sheet called "name" at the specified
* position in the layout list.
* @deprecated
*/
void InsertNewLayer(const gd::String& name, std::size_t position);
/**
* Must add a new the layer constructed from the layout passed as parameter.
* \note No pointer or reference must be kept on the layer passed as
* parameter. \param theLayer the layer that must be copied and inserted
* into the project \param position Insertion position. Even if the position
* is invalid, the layer must be inserted at the end of the layers list.
* @deprecated
*/
void InsertLayer(const Layer& theLayer, std::size_t position);
/**
* Must delete the layer named "name".
* @deprecated
*/
void RemoveLayer(const gd::String& name);
/**
* Swap the position of the specified layers.
* @deprecated
*/
void SwapLayers(std::size_t firstLayerIndex, std::size_t secondLayerIndex);
/**
* Change the position of the specified layer.
* @deprecated
*/
void MoveLayer(std::size_t oldIndex, std::size_t newIndex);
/**
* \brief Serialize the layers.
*/
void SerializeLayersTo(SerializerElement& element) const;
/**
* \brief Unserialize the layers.
*/
void UnserializeLayersFrom(const SerializerElement& element);
///@}
/**
@@ -275,7 +287,8 @@ class GD_CORE_API Layout : public ObjectsContainer {
/**
* \brief Get the shared data stored for a behavior
*/
gd::BehaviorsSharedData& GetBehaviorSharedData(const gd::String& behaviorName);
gd::BehaviorsSharedData& GetBehaviorSharedData(
const gd::String& behaviorName);
/**
* \brief Get a map of all shared data stored for behaviors
@@ -283,7 +296,6 @@ class GD_CORE_API Layout : public ObjectsContainer {
const std::map<gd::String, std::unique_ptr<gd::BehaviorsSharedData>>&
GetAllBehaviorSharedData() const;
/**
* Return the settings associated to the layout.
* \see gd::EditorSettings
@@ -296,9 +308,7 @@ class GD_CORE_API Layout : public ObjectsContainer {
* Return the settings associated to the layout.
* \see gd::EditorSettings
*/
gd::EditorSettings& GetAssociatedEditorSettings() {
return editorSettings;
}
gd::EditorSettings& GetAssociatedEditorSettings() { return editorSettings; }
/** \name Other properties
*/
@@ -339,12 +349,12 @@ class GD_CORE_API Layout : public ObjectsContainer {
* launched
*/
bool StopSoundsOnStartup() const { return stopSoundsOnStartup; }
///@}
///@}
/** \name Saving and loading
* Members functions related to saving and loading the object.
*/
///@{
/** \name Saving and loading
* Members functions related to saving and loading the object.
*/
///@{
/**
* \brief Serialize the layout.
*/
@@ -354,18 +364,7 @@ class GD_CORE_API Layout : public ObjectsContainer {
* \brief Unserialize the layout.
*/
void UnserializeFrom(gd::Project& project, const SerializerElement& element);
///@}
// TODO: GD C++ Platform specific code below
/**
* Get the profiler associated with the scene. Can be NULL.
*/
BaseProfiler* GetProfiler() const { return profiler; };
/**
* Set the profiler associated with the scene. Can be NULL.
*/
void SetProfiler(BaseProfiler* profiler_) { profiler = profiler_; };
///@}
private:
gd::String name; ///< Scene name
@@ -375,8 +374,9 @@ class GD_CORE_API Layout : public ObjectsContainer {
unsigned int backgroundColorB; ///< Background color Blue component
gd::String title; ///< Title displayed in the window
gd::VariablesContainer variables; ///< Variables list
gd::ObjectsContainer objectsContainer;
gd::InitialInstancesContainer initialInstances; ///< Initial instances
std::vector<gd::Layer> initialLayers; ///< Initial layers
gd::LayersContainer layers;
std::map<gd::String, std::unique_ptr<gd::BehaviorsSharedData>>
behaviorsSharedData; ///< Initial shared datas of behaviors
bool stopSoundsOnStartup; ///< True to make the scene stop all sounds at
@@ -385,20 +385,14 @@ class GD_CORE_API Layout : public ObjectsContainer {
bool disableInputWhenNotFocused; /// If set to true, the input must be
/// disabled when the window do not have the
/// focus.
static gd::Layer badLayer; ///< Null object, returned when GetLayer can not
///< find an appropriate layer.
static gd::BehaviorsSharedData
badBehaviorSharedData; ///< Null object, returned when
///< GetBehaviorSharedData can not find the
///< specified behavior shared data.
///< GetBehaviorSharedData can not find the
///< specified behavior shared data.
EventsList events; ///< Scene events
gd::EditorSettings editorSettings;
// TODO: GD C++ Platform specific code below
BaseProfiler* profiler; ///< Pointer to the profiler. Can be NULL.
/**
* Initialize from another layout. Used by copy-ctor and assign-op.
* Don't forget to update me if members were changed!
@@ -445,20 +439,24 @@ gd::String GD_CORE_API GetTypeOfObject(const ObjectsContainer& game,
bool searchInGroups = true);
/**
* \brief Check if an object or all objects of a group has a behavior.
* \deprecated Use gd::ObjectsContainersList::HasBehaviorInObjectOrGroup instead.
* \deprecated Use gd::ObjectsContainersList::HasBehaviorInObjectOrGroup
* instead.
*/
bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
const gd::ObjectsContainer &layout,
const gd::String &objectOrGroupName,
const gd::String &behaviorName,
bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
const gd::String& objectOrGroupName,
const gd::String& behaviorName,
bool searchInGroups = true);
/**
* \brief Get the names of behavior of a given type if an object or all objects of a group has it.
* \brief Get the names of behavior of a given type if an object or all objects
* of a group has it.
*/
std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
const gd::ObjectsContainer &project, const gd::ObjectsContainer &layout,
const gd::String &objectOrGroupName, const gd::String &behaviorType,
bool searchInGroups);
std::vector<gd::String> GD_CORE_API
GetBehaviorNamesInObjectOrGroup(const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
const gd::String& objectOrGroupName,
const gd::String& behaviorType,
bool searchInGroups);
/**
* \brief Check if a behavior is a default one or doesn't exist in an object or
@@ -471,13 +469,15 @@ bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
bool searchInGroups = true);
/**
* \brief Get the type of a behavior if an object or all objects of a group has it.
* \brief Get the type of a behavior if an object or all objects of a group has
* it.
*/
gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
const gd::ObjectsContainer &layout,
const gd::String &objectOrGroupName,
const gd::String &behaviorName,
bool searchInGroups = true);
gd::String GD_CORE_API
GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
const gd::String& objectOrGroupName,
const gd::String& behaviorName,
bool searchInGroups = true);
/**
* \brief Get a type from a behavior name
* @return Type of the behavior.

View File

@@ -25,9 +25,7 @@ std::map<gd::String, gd::PropertyDescriptor> ObjectConfiguration::GetProperties(
}
std::map<gd::String, gd::PropertyDescriptor>
ObjectConfiguration::GetInitialInstanceProperties(const gd::InitialInstance& instance,
gd::Project& project,
gd::Layout& layout) {
ObjectConfiguration::GetInitialInstanceProperties(const gd::InitialInstance& instance) {
std::map<gd::String, gd::PropertyDescriptor> nothing;
return nothing;
}

View File

@@ -114,9 +114,7 @@ class GD_CORE_API ObjectConfiguration {
* \see gd::InitialInstance
*/
virtual std::map<gd::String, gd::PropertyDescriptor>
GetInitialInstanceProperties(const gd::InitialInstance& instance,
gd::Project& project,
gd::Layout& layout);
GetInitialInstanceProperties(const gd::InitialInstance& instance);
/**
* \brief Called when the IDE wants to update a custom property of an initial
@@ -127,9 +125,7 @@ class GD_CORE_API ObjectConfiguration {
*/
virtual bool UpdateInitialInstanceProperty(gd::InitialInstance& instance,
const gd::String& name,
const gd::String& value,
gd::Project& project,
gd::Layout& layout) {
const gd::String& value) {
return false;
};
///@}

View File

@@ -7,6 +7,7 @@
#include <algorithm>
#include "GDCore/Tools/PolymorphicClone.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectFolderOrObject.h"
@@ -21,6 +22,25 @@ ObjectsContainer::ObjectsContainer() {
ObjectsContainer::~ObjectsContainer() {}
ObjectsContainer::ObjectsContainer(const ObjectsContainer& other) {
Init(other);
}
ObjectsContainer& ObjectsContainer::operator=(
const ObjectsContainer& other) {
if (this != &other) Init(other);
return *this;
}
void ObjectsContainer::Init(const gd::ObjectsContainer& other) {
initialObjects = gd::Clone(other.initialObjects);
objectGroups = other.objectGroups;
// The objects folders are not copied.
// It's not an issue because the UI uses the serialization for duplication.
rootFolder = gd::make_unique<gd::ObjectFolderOrObject>("__ROOT");
}
void ObjectsContainer::SerializeObjectsTo(SerializerElement& element) const {
element.ConsiderAsArrayOf("object");
for (std::size_t j = 0; j < initialObjects.size(); j++) {

View File

@@ -40,6 +40,9 @@ class GD_CORE_API ObjectsContainer {
*/
ObjectsContainer();
virtual ~ObjectsContainer();
ObjectsContainer(const ObjectsContainer&);
ObjectsContainer& operator=(const ObjectsContainer& rhs);
/** \name Objects management
* Members functions related to objects management.
@@ -230,6 +233,12 @@ class GD_CORE_API ObjectsContainer {
private:
std::unique_ptr<gd::ObjectFolderOrObject> rootFolder;
/**
* Initialize from another variables container, copying elements. Used by
* copy-ctor and assign-op. Don't forget to update me if members were changed!
*/
void Init(const ObjectsContainer& other);
};
} // namespace gd

View File

@@ -22,8 +22,8 @@ ObjectsContainersList
ObjectsContainersList::MakeNewObjectsContainersListForProjectAndLayout(
const gd::Project& project, const gd::Layout& layout) {
ObjectsContainersList objectsContainersList;
objectsContainersList.Add(project);
objectsContainersList.Add(layout);
objectsContainersList.Add(project.GetObjects());
objectsContainersList.Add(layout.GetObjects());
return objectsContainersList;
}
@@ -31,7 +31,7 @@ ObjectsContainersList
ObjectsContainersList::MakeNewObjectsContainersListForProject(
const gd::Project& project) {
ObjectsContainersList objectsContainersList;
objectsContainersList.Add(project);
objectsContainersList.Add(project.GetObjects());
return objectsContainersList;
}

View File

@@ -34,7 +34,6 @@
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
#include "GDCore/TinyXml/tinyxml.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/Log.h"
#include "GDCore/Tools/PolymorphicClone.h"
@@ -835,15 +834,15 @@ void Project::UnserializeFrom(const SerializerElement& element) {
*this, eventsFunctionsExtensionElement);
}
GetObjectGroups().UnserializeFrom(
objectsContainer.GetObjectGroups().UnserializeFrom(
element.GetChild("objectsGroups", 0, "ObjectGroups"));
resourcesManager.UnserializeFrom(
element.GetChild("resources", 0, "Resources"));
UnserializeObjectsFrom(*this, element.GetChild("objects", 0, "Objects"));
objectsContainer.UnserializeObjectsFrom(*this, element.GetChild("objects", 0, "Objects"));
if (element.HasChild("objectsFolderStructure")) {
UnserializeFoldersFrom(*this, element.GetChild("objectsFolderStructure", 0));
objectsContainer.UnserializeFoldersFrom(*this, element.GetChild("objectsFolderStructure", 0));
}
AddMissingObjectsInRootFolder();
objectsContainer.AddMissingObjectsInRootFolder();
GetVariables().UnserializeFrom(element.GetChild("variables", 0, "Variables"));
@@ -995,9 +994,9 @@ void Project::SerializeTo(SerializerElement& element) const {
std::cout << "ERROR: The project current platform is NULL.";
resourcesManager.SerializeTo(element.AddChild("resources"));
SerializeObjectsTo(element.AddChild("objects"));
SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
objectsContainer.SerializeObjectsTo(element.AddChild("objects"));
objectsContainer.SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
objectsContainer.GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
GetVariables().SerializeTo(element.AddChild("variables"));
element.SetAttribute("firstLayout", firstLayout);
@@ -1164,7 +1163,6 @@ void Project::Init(const gd::Project& game) {
platformSpecificAssets = game.platformSpecificAssets;
loadingScreen = game.loadingScreen;
watermark = game.watermark;
objectGroups = game.objectGroups;
extensionProperties = game.extensionProperties;
@@ -1177,7 +1175,7 @@ void Project::Init(const gd::Project& game) {
resourcesManager = game.resourcesManager;
initialObjects = gd::Clone(game.initialObjects);
objectsContainer = game.objectsContainer;
scenes = gd::Clone(game.scenes);

View File

@@ -48,7 +48,7 @@ namespace gd {
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API Project : public ObjectsContainer {
class GD_CORE_API Project {
public:
Project();
Project(const Project&);
@@ -984,6 +984,24 @@ class GD_CORE_API Project : public ObjectsContainer {
///@}
/** \name Global objects
*/
///@{
/**
* \brief return the objects of the project.
*/
gd::ObjectsContainer& GetObjects() {
return objectsContainer;
}
/**
* \brief Return the objects of the project.
*/
const gd::ObjectsContainer& GetObjects() const {
return objectsContainer;
}
///@}
/** \name Identifier names
*/
///@{
@@ -1090,6 +1108,7 @@ class GD_CORE_API Project : public ObjectsContainer {
///< startup.
std::vector<std::unique_ptr<gd::Layout> > scenes; ///< List of all scenes
gd::VariablesContainer variables; ///< Initial global variables
gd::ObjectsContainer objectsContainer;
std::vector<std::unique_ptr<gd::ExternalLayout> >
externalLayouts; ///< List of all externals layouts
std::vector<std::unique_ptr<gd::EventsFunctionsExtension> >

View File

@@ -6,6 +6,7 @@
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Events/Event.h"
#include "GDCore/Extensions/PlatformExtension.h"
namespace gd {
@@ -101,6 +102,37 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForObjectEventsFunction(
return projectScopedContainers;
}
ProjectScopedContainers
ProjectScopedContainers::MakeNewProjectScopedContainersForEventsBasedObject(
const gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedObject &eventsBasedObject,
gd::ObjectsContainer &outputObjectsContainer) {
outputObjectsContainer.GetObjects().clear();
outputObjectsContainer.GetObjectGroups().Clear();
outputObjectsContainer.InsertNewObject(
project,
gd::PlatformExtension::GetObjectFullType(
eventsFunctionsExtension.GetName(), eventsBasedObject.GetName()),
"Object", outputObjectsContainer.GetObjectsCount());
gd::EventsFunctionTools::CopyEventsBasedObjectChildrenToObjectsContainer(
eventsBasedObject, outputObjectsContainer);
ProjectScopedContainers projectScopedContainers(
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
outputObjectsContainer),
VariablesContainersList::
MakeNewVariablesContainersListForEventsFunctionsExtension(
eventsFunctionsExtension),
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
projectScopedContainers.AddPropertiesContainer(
eventsBasedObject.GetPropertyDescriptors());
return projectScopedContainers;
}
ProjectScopedContainers
ProjectScopedContainers::MakeNewProjectScopedContainersWithLocalVariables(
const ProjectScopedContainers &projectScopedContainers,

View File

@@ -111,6 +111,13 @@ class ProjectScopedContainers {
const gd::EventsFunction &eventsFunction,
gd::ObjectsContainer &parameterObjectsContainer);
static ProjectScopedContainers
MakeNewProjectScopedContainersForEventsBasedObject(
const gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedObject &eventsBasedObject,
gd::ObjectsContainer &outputObjectsContainer);
static ProjectScopedContainers
MakeNewProjectScopedContainersWithLocalVariables(
const ProjectScopedContainers &projectScopedContainers,

View File

@@ -11,7 +11,6 @@
#include "GDCore/Project/Variable.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
#include "GDCore/TinyXml/tinyxml.h"
#include "GDCore/Tools/UUID/UUID.h"
namespace gd {

View File

@@ -12,7 +12,6 @@
namespace gd {
class SerializerElement;
}
class TiXmlElement;
namespace gd {

View File

@@ -17,91 +17,11 @@
#include "rapidjson/document.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/rapidjson.h"
#if !defined(EMSCRIPTEN)
#include "GDCore/TinyXml/tinyxml.h"
#endif
using namespace rapidjson;
namespace gd {
#if !defined(EMSCRIPTEN)
void Serializer::ToXML(SerializerElement& element, TiXmlElement* xmlElement) {
if (!xmlElement) return;
if (element.IsValueUndefined()) {
const std::map<gd::String, SerializerValue>& attributes =
element.GetAllAttributes();
for (std::map<gd::String, SerializerValue>::const_iterator it =
attributes.begin();
it != attributes.end();
++it) {
const SerializerValue& attr = it->second;
if (attr.IsBoolean())
xmlElement->SetAttribute(it->first.c_str(),
attr.GetBool() ? "true" : "false");
else if (attr.IsString())
xmlElement->SetAttribute(it->first.c_str(), attr.GetString().c_str());
else if (attr.IsInt())
xmlElement->SetAttribute(it->first.c_str(), attr.GetInt());
else if (attr.IsDouble())
xmlElement->SetDoubleAttribute(it->first.c_str(), attr.GetDouble());
else
xmlElement->SetAttribute(it->first.c_str(), attr.GetString().c_str());
}
const std::vector<
std::pair<gd::String, std::shared_ptr<SerializerElement> > >& children =
element.GetAllChildren();
for (size_t i = 0; i < children.size(); ++i) {
if (children[i].second == std::shared_ptr<SerializerElement>()) continue;
TiXmlElement* xmlChild = new TiXmlElement(children[i].first.c_str());
xmlElement->LinkEndChild(xmlChild);
ToXML(*children[i].second, xmlChild);
}
} else {
TiXmlText* xmlValue = new TiXmlText(element.GetValue().GetString().c_str());
xmlElement->LinkEndChild(xmlValue);
}
}
void Serializer::FromXML(SerializerElement& element,
const TiXmlElement* xmlElement) {
if (!xmlElement) return;
const TiXmlAttribute* attr = xmlElement->FirstAttribute();
while (attr) {
if (attr->Name() != NULL) {
gd::String name = gd::String::FromUTF8(attr->Name()).ReplaceInvalid();
if (attr->Value())
element.SetAttribute(
name, gd::String::FromUTF8(attr->Value()).ReplaceInvalid());
}
attr = attr->Next();
}
const TiXmlElement* child = xmlElement->FirstChildElement();
while (child) {
if (child->Value()) {
gd::String name = gd::String::FromUTF8(child->Value()).ReplaceInvalid();
SerializerElement& childElement = element.AddChild(name);
FromXML(childElement, child);
}
child = child->NextSiblingElement();
}
if (xmlElement->GetText()) {
SerializerValue value;
value.Set(gd::String::FromUTF8(xmlElement->GetText()).ReplaceInvalid());
element.SetValue(value);
}
}
#endif
gd::String Serializer::ToEscapedXMLString(const gd::String& str) {
return str.FindAndReplace("&", "&amp;")
.FindAndReplace("'", "&apos;")

View File

@@ -8,7 +8,6 @@
#define GDCORE_SERIALIZER_H
#include <string>
#include "GDCore/Serialization/SerializerElement.h"
class TiXmlElement;
namespace gd {
@@ -22,11 +21,7 @@ class GD_CORE_API Serializer {
* Convert a gd::SerializerElement from/to XML.
*/
///@{
#if !defined(EMSCRIPTEN)
static void ToXML(SerializerElement& element, TiXmlElement* xmlElement);
static void FromXML(SerializerElement& element,
const TiXmlElement* xmlElement);
#endif
/**
* \brief Escape a string for inclusion in a XML tag
*/

View File

@@ -1,117 +0,0 @@
/*
www.sourceforge.net/projects/tinyxml
Original file by Yves Berquin.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
/*
* THIS FILE WAS ALTERED BY Tyge L<>vset, 7. April 2005.
*/
#ifndef TIXML_USE_STL
#include "GDCore/TinyXml/tinystr.h"
// Error value for find primitive
const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1);
// Null rep.
TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } };
void TiXmlString::reserve (size_type cap)
{
if (cap > capacity())
{
TiXmlString tmp;
tmp.init(length(), cap);
memcpy(tmp.start(), data(), length());
swap(tmp);
}
}
TiXmlString& TiXmlString::assign(const char* str, size_type len)
{
size_type cap = capacity();
if (len > cap || cap > 3*(len + 8))
{
TiXmlString tmp;
tmp.init(len);
memcpy(tmp.start(), str, len);
swap(tmp);
}
else
{
memmove(start(), str, len);
set_size(len);
}
return *this;
}
TiXmlString& TiXmlString::append(const char* str, size_type len)
{
size_type newsize = length() + len;
if (newsize > capacity())
{
reserve (newsize + capacity());
}
memmove(finish(), str, len);
set_size(newsize);
return *this;
}
TiXmlString operator + (const TiXmlString & a, const TiXmlString & b)
{
TiXmlString tmp;
tmp.reserve(a.length() + b.length());
tmp += a;
tmp += b;
return tmp;
}
TiXmlString operator + (const TiXmlString & a, const char* b)
{
TiXmlString tmp;
TiXmlString::size_type b_len = static_cast<TiXmlString::size_type>( strlen(b) );
tmp.reserve(a.length() + b_len);
tmp += a;
tmp.append(b, b_len);
return tmp;
}
TiXmlString operator + (const char* a, const TiXmlString & b)
{
TiXmlString tmp;
TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) );
tmp.reserve(a_len + b.length());
tmp.append(a, a_len);
tmp += b;
return tmp;
}
#endif // TIXML_USE_STL

View File

@@ -1,325 +0,0 @@
/*
www.sourceforge.net/projects/tinyxml
Original file by Yves Berquin.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
/*
* THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005.
*
* - completely rewritten. compact, clean, and fast implementation.
* - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems)
* - fixed reserve() to work as per specification.
* - fixed buggy compares operator==(), operator<(), and operator>()
* - fixed operator+=() to take a const ref argument, following spec.
* - added "copy" constructor with length, and most compare operators.
* - added swap(), clear(), size(), capacity(), operator+().
*/
/**
* Changes by Florian Rival :
* Added GD_CORE_API to integrate TinyXml to GDevelop Library.
*/
#ifndef TIXML_USE_STL
#ifndef TIXML_STRING_INCLUDED
#define TIXML_STRING_INCLUDED
#include <assert.h>
#include <string.h>
/* The support for explicit isn't that universal, and it isn't really
required - it is used to check that the TiXmlString class isn't incorrectly
used. Be nice to old compilers and macro it here:
*/
#if defined(_MSC_VER) && (_MSC_VER >= 1200 )
// Microsoft visual studio, version 6 and higher.
#define TIXML_EXPLICIT explicit
#elif defined(__GNUC__) && (__GNUC__ >= 3 )
// GCC version 3 and higher.s
#define TIXML_EXPLICIT explicit
#else
#define TIXML_EXPLICIT
#endif
/*
TiXmlString is an emulation of a subset of the std::string template.
Its purpose is to allow compiling TinyXML on compilers with no or poor STL support.
Only the member functions relevant to the TinyXML project have been implemented.
The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase
a string and there's no more room, we allocate a buffer twice as big as we need.
*/
class GD_CORE_API TiXmlString
{
public :
// The size type used
typedef size_t size_type;
// Error value for find primitive
static const size_type npos; // = -1;
// TiXmlString empty constructor
TiXmlString () : rep_(&nullrep_)
{
}
// TiXmlString copy constructor
TiXmlString ( const TiXmlString & copy) : rep_(0)
{
init(copy.length());
memcpy(start(), copy.data(), length());
}
// TiXmlString constructor, based on a string
TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0)
{
init( static_cast<size_type>( strlen(copy) ));
memcpy(start(), copy, length());
}
// TiXmlString constructor, based on a string
TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0)
{
init(len);
memcpy(start(), str, len);
}
// TiXmlString destructor
~TiXmlString ()
{
quit();
}
// = operator
TiXmlString& operator = (const char * copy)
{
return assign( copy, (size_type)strlen(copy));
}
// = operator
TiXmlString& operator = (const TiXmlString & copy)
{
return assign(copy.start(), copy.length());
}
// += operator. Maps to append
TiXmlString& operator += (const char * suffix)
{
return append(suffix, static_cast<size_type>( strlen(suffix) ));
}
// += operator. Maps to append
TiXmlString& operator += (char single)
{
return append(&single, 1);
}
// += operator. Maps to append
TiXmlString& operator += (const TiXmlString & suffix)
{
return append(suffix.data(), suffix.length());
}
// Convert a TiXmlString into a null-terminated char *
const char * c_str () const { return rep_->str; }
// Convert a TiXmlString into a char * (need not be null terminated).
const char * data () const { return rep_->str; }
// Return the length of a TiXmlString
size_type length () const { return rep_->size; }
// Alias for length()
size_type size () const { return rep_->size; }
// Checks if a TiXmlString is empty
bool empty () const { return rep_->size == 0; }
// Return capacity of string
size_type capacity () const { return rep_->capacity; }
// single char extraction
const char& at (size_type index) const
{
assert( index < length() );
return rep_->str[ index ];
}
// [] operator
char& operator [] (size_type index) const
{
assert( index < length() );
return rep_->str[ index ];
}
// find a char in a string. Return TiXmlString::npos if not found
size_type find (char lookup) const
{
return find(lookup, 0);
}
// find a char in a string from an offset. Return TiXmlString::npos if not found
size_type find (char tofind, size_type offset) const
{
if (offset >= length()) return npos;
for (const char* p = c_str() + offset; *p != '\0'; ++p)
{
if (*p == tofind) return static_cast< size_type >( p - c_str() );
}
return npos;
}
void clear ()
{
//Lee:
//The original was just too strange, though correct:
// TiXmlString().swap(*this);
//Instead use the quit & re-init:
quit();
init(0,0);
}
/* Function to reserve a big amount of data when we know we'll need it. Be aware that this
function DOES NOT clear the content of the TiXmlString if any exists.
*/
void reserve (size_type cap);
TiXmlString& assign (const char* str, size_type len);
TiXmlString& append (const char* str, size_type len);
void swap (TiXmlString& other)
{
Rep* r = rep_;
rep_ = other.rep_;
other.rep_ = r;
}
private:
void init(size_type sz) { init(sz, sz); }
void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; }
char* start() const { return rep_->str; }
char* finish() const { return rep_->str + rep_->size; }
struct Rep
{
size_type size, capacity;
char str[1];
};
void init(size_type sz, size_type cap)
{
if (cap)
{
// Lee: the original form:
// rep_ = static_cast<Rep*>(operator new(sizeof(Rep) + cap));
// doesn't work in some cases of new being overloaded. Switching
// to the normal allocation, although use an 'int' for systems
// that are overly picky about structure alignment.
const size_type bytesNeeded = sizeof(Rep) + cap;
const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int );
rep_ = reinterpret_cast<Rep*>( new int[ intsNeeded ] );
rep_->str[ rep_->size = sz ] = '\0';
rep_->capacity = cap;
}
else
{
rep_ = &nullrep_;
}
}
void quit()
{
if (rep_ != &nullrep_)
{
// The rep_ is really an array of ints. (see the allocator, above).
// Cast it back before delete, so the compiler won't incorrectly call destructors.
delete [] ( reinterpret_cast<int*>( rep_ ) );
}
}
Rep * rep_;
static Rep nullrep_;
} ;
inline bool operator == (const TiXmlString & a, const TiXmlString & b)
{
return ( a.length() == b.length() ) // optimization on some platforms
&& ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare
}
inline bool operator < (const TiXmlString & a, const TiXmlString & b)
{
return strcmp(a.c_str(), b.c_str()) < 0;
}
inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); }
inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; }
inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); }
inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); }
inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; }
inline bool operator == (const char* a, const TiXmlString & b) { return b == a; }
inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); }
inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); }
TiXmlString operator + (const TiXmlString & a, const TiXmlString & b);
TiXmlString operator + (const TiXmlString & a, const char* b);
TiXmlString operator + (const char* a, const TiXmlString & b);
/*
TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString.
Only the operators that we need for TinyXML have been developped.
*/
class GD_CORE_API TiXmlOutStream : public TiXmlString
{
public :
// TiXmlOutStream << operator.
TiXmlOutStream & operator << (const TiXmlString & in)
{
*this += in;
return *this;
}
// TiXmlOutStream << operator.
TiXmlOutStream & operator << (const char * in)
{
*this += in;
return *this;
}
} ;
#endif // TIXML_STRING_INCLUDED
#endif // TIXML_USE_STL

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,54 +0,0 @@
/*
www.sourceforge.net/projects/tinyxml
Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "GDCore/TinyXml/tinyxml.h"
// The goal of the seperate error file is to make the first
// step towards localization. tinyxml (currently) only supports
// english error messages, but the could now be translated.
//
// It also cleans up the code a bit.
//
const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] =
{
"No error",
"Error",
"Failed to open file",
"Memory allocation failed.",
"Error parsing Element.",
"Failed to read Element name",
"Error reading Element value.",
"Error reading Attributes.",
"Error: empty tag.",
"Error reading end tag.",
"Error parsing Unknown.",
"Error parsing Comment.",
"Error parsing Declaration.",
"Error document empty.",
"Error null (0) or unexpected EOF found in input stream.",
"Error parsing CDATA.",
"Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.",
};

File diff suppressed because it is too large Load Diff

View File

@@ -204,6 +204,10 @@ class SerializableWithNameList {
void UnserializeElementsFrom(const gd::String& elementName,
const SerializerElement& element);
void ProgressivelyUnserializeElementsFrom(const gd::String& elementName,
gd::Project& project,
const SerializerElement& element);
///@}
protected:

View File

@@ -127,6 +127,26 @@ void SerializableWithNameList<T>::SerializeElementsTo(
}
}
template <typename T>
void SerializableWithNameList<T>::ProgressivelyUnserializeElementsFrom(
const gd::String& elementName,
gd::Project& project,
const SerializerElement& serializerElement) {
serializerElement.ConsiderAsArrayOf(elementName);
for (std::size_t i = 0; i < serializerElement.GetChildrenCount(); ++i) {
T* newElement = nullptr;
if (elements.size() <= i) {
newElement = &InsertNew("", GetCount());
} else {
newElement = elements[i].get();
}
newElement->UnserializeFrom(project, serializerElement.GetChild(i));
}
while (elements.size() > serializerElement.GetChildrenCount()) {
elements.pop_back();
}
}
template <typename T>
void SerializableWithNameList<T>::UnserializeElementsFrom(
const gd::String& elementName,

View File

@@ -1,39 +0,0 @@
#include "GDCore/Tools/XmlLoader.h"
#include <cstdio>
namespace gd {
namespace {
FILE* GetFileHandle(const gd::String& filename, const gd::String& mode) {
#if defined(WINDOWS)
return _wfopen(filename.ToWide().c_str(), mode.ToWide().c_str());
#else
return fopen(filename.ToLocale().c_str(), mode.ToLocale().c_str());
#endif
}
} // namespace
bool GD_CORE_API LoadXmlFromFile(TiXmlDocument& doc,
const gd::String& filepath) {
FILE* xmlFile = GetFileHandle(filepath, "rb");
if (!xmlFile) return false;
bool res = doc.LoadFile(xmlFile);
fclose(xmlFile);
return res;
}
bool GD_CORE_API SaveXmlToFile(const TiXmlDocument& doc,
const gd::String& filepath) {
FILE* xmlFile = GetFileHandle(filepath, "wb");
if (!xmlFile) return false;
bool res = doc.SaveFile(xmlFile);
fclose(xmlFile);
return res;
}
} // namespace gd

View File

@@ -1,17 +0,0 @@
#ifndef GDCORE_XMLLOADER_H
#define GDCORE_XMLLOADER_H
#include "GDCore/String.h"
#include "GDCore/TinyXml/tinyxml.h"
namespace gd {
bool GD_CORE_API LoadXmlFromFile(TiXmlDocument& doc,
const gd::String& filepath);
bool GD_CORE_API SaveXmlToFile(const TiXmlDocument& doc,
const gd::String& filepath);
} // namespace gd
#endif

View File

@@ -705,7 +705,7 @@ EXCLUDE_PATTERNS =
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
EXCLUDE_SYMBOLS = TiXml*
EXCLUDE_SYMBOLS =
# The EXAMPLE_PATH tag can be used to specify one or more files or
# directories that contain example code fragments that are included (see

View File

@@ -94,7 +94,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
spriteConfiguration.GetAnimations().AddAnimation(anim);
gd::Object obj("myObject", "", spriteConfiguration.Clone());
project.InsertObject(obj, 0);
project.GetObjects().InsertObject(obj, 0);
worker.files.clear();
worker.images.clear();
@@ -141,7 +141,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
spriteConfiguration.GetAnimations().AddAnimation(anim);
gd::Object obj("myObject", "", spriteConfiguration.Clone());
layout.InsertObject(obj, 0);
layout.GetObjects().InsertObject(obj, 0);
worker.files.clear();
worker.images.clear();
@@ -378,8 +378,9 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
auto& layout = project.InsertNewLayout("Scene", 0);
layout.InsertNewLayer("MyLayer", 0);
auto& layer = layout.GetLayer("MyLayer");
auto& object = layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto& effect = object.GetEffects().InsertNewEffect("MyEffect", 0);
auto &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
auto &effect = object.GetEffects().InsertNewEffect("MyEffect", 0);
effect.SetEffectType("MyExtension::EffectWithResource");
effect.SetStringParameter("texture", "res1");
@@ -440,7 +441,7 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
spriteConfiguration.GetAnimations().AddAnimation(anim);
gd::Object obj("myObject", "", spriteConfiguration.Clone());
layout.InsertObject(obj, 0);
layout.GetObjects().InsertObject(obj, 0);
worker.files.clear();
worker.images.clear();
@@ -894,8 +895,9 @@ TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
auto& layout = project.InsertNewLayout("Scene", 0);
layout.InsertNewLayer("MyLayer", 0);
auto& layer = layout.GetLayer("MyLayer");
auto& object = layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto& effect = object.GetEffects().InsertNewEffect("MyEffect", 0);
auto &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
auto &effect = object.GetEffects().InsertNewEffect("MyEffect", 0);
effect.SetEffectType("MyExtension::EffectWithResource");
effect.SetStringParameter("texture", "res1");

View File

@@ -52,7 +52,7 @@ void AddAnotherEventsBasedExtensionWithDependency(gd::Project &project) {
eventsBasedObject.SetFullName("My events based object");
eventsBasedObject.SetDescription("An events based object for test");
gd::Object &object = eventsBasedObject.InsertNewObject(
gd::Object &object = eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
gd::Behavior *behavior =
object.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior",
@@ -65,8 +65,8 @@ void SetupProject(gd::Project &project, gd::Platform &platform) {
AddEventsBasedExtension(project);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
gd::Behavior *behavior =
object.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior",
"MyEventsBasedBehavior");
@@ -127,7 +127,8 @@ TEST_CASE("BehaviorSerialization", "[common]") {
gd::Platform platform;
gd::Project writtenProject;
SetupProject(writtenProject, platform);
CheckBehaviorProperty(writtenProject.GetLayout("Scene"));
CheckBehaviorProperty(
writtenProject.GetLayout("Scene").GetObjects());
SerializerElement projectElement;
writtenProject.SerializeTo(projectElement);
@@ -136,7 +137,7 @@ TEST_CASE("BehaviorSerialization", "[common]") {
gd::Project readProject;
readProject.AddPlatform(platform);
readProject.UnserializeFrom(projectElement);
CheckBehaviorProperty(readProject.GetLayout("Scene"));
CheckBehaviorProperty(readProject.GetLayout("Scene").GetObjects());
}
SECTION("Load a project with a property value on a custom behavior that no longer exists") {
@@ -158,7 +159,7 @@ TEST_CASE("BehaviorSerialization", "[common]") {
// Add the events-based behavior back
AddEventsBasedExtension(readProject);
CheckBehaviorProperty(readProject.GetLayout("Scene"));
CheckBehaviorProperty(readProject.GetLayout("Scene").GetObjects());
}
SECTION("Save and load a project with an event based extension dependency") {
@@ -203,7 +204,9 @@ TEST_CASE("BehaviorSerialization", "[common]") {
// extension.
REQUIRE(readProject.HasEventsBasedObject(
"MyOtherEventsExtension::MyEventsBasedObject"));
CheckBehaviorProperty(readProject.GetEventsBasedObject(
"MyOtherEventsExtension::MyEventsBasedObject"));
CheckBehaviorProperty(
readProject
.GetEventsBasedObject("MyOtherEventsExtension::MyEventsBasedObject")
.GetObjects());
}
}

View File

@@ -80,7 +80,7 @@ TEST_CASE("EventsList", "[common][events]") {
#if defined(WINDOWS)
REQUIRE(3000 >= endMemory - startMemory);
#else
REQUIRE(1600 >= endMemory - startMemory);
REQUIRE(1650 >= endMemory - startMemory);
#endif
}
}

View File

@@ -39,8 +39,8 @@ TEST_CASE("EventsBehaviorRenamer (expressions)", "[common]") {
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
auto &object1 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
auto &object1 = layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior2");
@@ -80,8 +80,8 @@ TEST_CASE("EventsBehaviorRenamer (instructions)", "[common]") {
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
auto &object1 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
auto &object1 = layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior2");

View File

@@ -63,7 +63,8 @@ TEST_CASE("Events-based extension", "[common]") {
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
auto &layout1 = project.InsertNewLayout("Layout1", 0);
auto &object = layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
auto &object = layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
// Attach a behavior to an object.
auto *behavior = object.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior", "MyEventsBasedBehavior");

View File

@@ -195,7 +195,8 @@ TEST_CASE("EventsIdentifiersFinder (object timers)", "[common]") {
DeclareTimerExtension(project, platform);
auto &layout = project.InsertNewLayout("Layout1", 0);
auto &object = layout.InsertNewObject(project, "", "MyObject", 0);
auto &object = layout.GetObjects().InsertNewObject(project, "",
"MyObject", 0);
layout.GetEvents().InsertEvent(UseObjectTimer("MyObject", "MyObjectTimer"));
auto identifierExpressions =
@@ -212,8 +213,10 @@ TEST_CASE("EventsIdentifiersFinder (object timers)", "[common]") {
DeclareTimerExtension(project, platform);
auto &layout = project.InsertNewLayout("Layout1", 0);
auto &object = layout.InsertNewObject(project, "", "MyObject", 0);
layout.GetEvents().InsertEvent(UseObjectTimerInExpression("MyObject", "MyObjectTimer"));
auto &object = layout.GetObjects().InsertNewObject(project, "",
"MyObject", 0);
layout.GetEvents().InsertEvent(
UseObjectTimerInExpression("MyObject", "MyObjectTimer"));
auto identifierExpressions =
gd::EventsIdentifiersFinder::FindAllIdentifierExpressions(
@@ -229,7 +232,8 @@ TEST_CASE("EventsIdentifiersFinder (object timers)", "[common]") {
DeclareTimerExtension(project, platform);
auto &layout = project.InsertNewLayout("Layout1", 0);
auto &object = layout.InsertNewObject(project, "", "MyObject", 0);
auto &object = layout.GetObjects().InsertNewObject(project, "",
"MyObject", 0);
auto &externalEvents = project.InsertNewExternalEvents("ExternalEvents", 0);
externalEvents.GetEvents().InsertEvent(
UseObjectTimer("MyObject", "MyObjectTimer"));
@@ -249,8 +253,10 @@ TEST_CASE("EventsIdentifiersFinder (object timers)", "[common]") {
DeclareTimerExtension(project, platform);
auto &layout = project.InsertNewLayout("Layout1", 0);
auto &object1 = layout.InsertNewObject(project, "", "MyObject1", 0);
auto &object2 = layout.InsertNewObject(project, "", "MyObject2", 0);
auto &object1 = layout.GetObjects().InsertNewObject(
project, "", "MyObject1", 0);
auto &object2 = layout.GetObjects().InsertNewObject(
project, "", "MyObject2", 0);
layout.GetEvents().InsertEvent(
UseObjectTimer("MyObject1", "MyObjectTimer1"));
layout.GetEvents().InsertEvent(
@@ -270,8 +276,10 @@ TEST_CASE("EventsIdentifiersFinder (object timers)", "[common]") {
DeclareTimerExtension(project, platform);
auto &layout = project.InsertNewLayout("Layout1", 0);
auto &object1 = layout.InsertNewObject(project, "", "MyObject1", 0);
auto &object2 = layout.InsertNewObject(project, "", "MyObject2", 0);
auto &object1 = layout.GetObjects().InsertNewObject(
project, "", "MyObject1", 0);
auto &object2 = layout.GetObjects().InsertNewObject(
project, "", "MyObject2", 0);
auto &externalEvents = project.InsertNewExternalEvents("ExternalEvents", 0);
externalEvents.GetEvents().InsertEvent(
UseObjectTimer("MyObject1", "MyObjectTimer1"));

View File

@@ -268,7 +268,8 @@ TEST_CASE("EventsVariablesFinder (FindAllObjectVariables)", "[common]") {
DeclareVariableExtension(project, platform);
auto &layout = project.InsertNewLayout("Layout1", 0);
auto &object = layout.InsertNewObject(project, "", "MyObject", 0);
auto &object = layout.GetObjects().InsertNewObject(project, "",
"MyObject", 0);
layout.GetEvents().InsertEvent(
UseObjectVariable("MyObject", "MyObjectVariable"));
@@ -285,7 +286,8 @@ TEST_CASE("EventsVariablesFinder (FindAllObjectVariables)", "[common]") {
DeclareVariableExtension(project, platform);
auto &layout = project.InsertNewLayout("Layout1", 0);
auto &object = layout.InsertNewObject(project, "", "MyObject", 0);
auto &object = layout.GetObjects().InsertNewObject(project, "",
"MyObject", 0);
layout.GetEvents().InsertEvent(
UseObjectVariableInExpression("MyObject", "MyObjectVariable"));
@@ -302,7 +304,8 @@ TEST_CASE("EventsVariablesFinder (FindAllObjectVariables)", "[common]") {
DeclareVariableExtension(project, platform);
auto &layout = project.InsertNewLayout("Layout1", 0);
auto &object = layout.InsertNewObject(project, "", "MyObject", 0);
auto &object = layout.GetObjects().InsertNewObject(project, "",
"MyObject", 0);
auto &externalEvents = project.InsertNewExternalEvents("ExternalEvents", 0);
externalEvents.GetEvents().InsertEvent(
UseObjectVariable("MyObject", "MyObjectVariable"));
@@ -321,8 +324,10 @@ TEST_CASE("EventsVariablesFinder (FindAllObjectVariables)", "[common]") {
DeclareVariableExtension(project, platform);
auto &layout = project.InsertNewLayout("Layout1", 0);
auto &object1 = layout.InsertNewObject(project, "", "MyObject1", 0);
auto &object2 = layout.InsertNewObject(project, "", "MyObject2", 0);
auto &object1 = layout.GetObjects().InsertNewObject(
project, "", "MyObject1", 0);
auto &object2 = layout.GetObjects().InsertNewObject(
project, "", "MyObject2", 0);
layout.GetEvents().InsertEvent(
UseObjectVariable("MyObject1", "MyObjectVariable1"));
layout.GetEvents().InsertEvent(
@@ -342,8 +347,10 @@ TEST_CASE("EventsVariablesFinder (FindAllObjectVariables)", "[common]") {
DeclareVariableExtension(project, platform);
auto &layout = project.InsertNewLayout("Layout1", 0);
auto &object1 = layout.InsertNewObject(project, "", "MyObject1", 0);
auto &object2 = layout.InsertNewObject(project, "", "MyObject2", 0);
auto &object1 = layout.GetObjects().InsertNewObject(
project, "", "MyObject1", 0);
auto &object2 = layout.GetObjects().InsertNewObject(
project, "", "MyObject2", 0);
auto &externalEvents = project.InsertNewExternalEvents("ExternalEvents", 0);
externalEvents.GetEvents().InsertEvent(
UseObjectVariable("MyObject1", "MyObjectVariable1"));

View File

@@ -46,31 +46,39 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
variable.PushNew().SetString("3");
}
auto &mySpriteObject = layout1.InsertNewObject(project, "MyExtension::Sprite", "MySpriteObject", 0);
auto &mySpriteObject = layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MySpriteObject", 0);
mySpriteObject.GetVariables().InsertNew("MyNumberVariable").SetValue(123);
mySpriteObject.GetVariables().InsertNew("MyStringVariable").SetString("Test");
mySpriteObject.GetVariables().InsertNew("MyStructureVariable").GetChild("MyStringChild").SetString("Test");
layout1.InsertNewObject(
project, "MyExtension::Sprite", "MyOtherSpriteObject", 1);
layout1.InsertNewObject(project,
"MyExtension::FakeObjectWithDefaultBehavior",
"FakeObjectWithDefaultBehavior",
2);
mySpriteObject.GetVariables()
.InsertNew("MyStructureVariable")
.GetChild("MyStringChild")
.SetString("Test");
layout1.GetObjects().InsertNewObject(project, "MyExtension::Sprite",
"MyOtherSpriteObject", 1);
layout1.GetObjects().InsertNewObject(
project, "MyExtension::FakeObjectWithDefaultBehavior",
"FakeObjectWithDefaultBehavior", 2);
// Also insert a variable having the same name as an object:
layout1.InsertNewObject(project, "MyExtension::Sprite", "ObjectWithNameReused", 3);
layout1.GetVariables().InsertNew("ObjectWithNameReused", 3).GetChild("MyChild");
layout1.GetObjects().InsertNewObject(project, "MyExtension::Sprite",
"ObjectWithNameReused", 3);
layout1.GetVariables()
.InsertNew("ObjectWithNameReused", 3)
.GetChild("MyChild");
// Also insert a global variable having the same name as a scene variable:
layout1.GetVariables().InsertNew("SceneVariableWithNameReused", 4);
project.GetVariables().InsertNew("SceneVariableWithNameReused", 0);
auto &group = layout1.GetObjectGroups().InsertNew("AllObjects");
auto &group =
layout1.GetObjects().GetObjectGroups().InsertNew("AllObjects");
group.AddObject("MySpriteObject");
group.AddObject("MyOtherSpriteObject");
group.AddObject("FakeObjectWithDefaultBehavior");
auto &spriteGroup = layout1.GetObjectGroups().InsertNew("MySpriteObjects");
auto &spriteGroup = layout1.GetObjects().GetObjectGroups().InsertNew(
"MySpriteObjects");
spriteGroup.AddObject("MySpriteObject");
spriteGroup.AddObject("MyOtherSpriteObject");

View File

@@ -23,8 +23,8 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SetupProjectWithDummyPlatform(project, platform);
auto& layout1 = project.InsertNewLayout("Layout1", 0);
layout1.GetVariables().InsertNew("myVariable");
auto& object1 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto &object1 = layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
object1.GetVariables().InsertNew("myObjectVariable");
gd::ProjectScopedContainers projectScopedContainers =

View File

@@ -57,7 +57,8 @@ TEST_CASE("ExpressionNodeLocationFinder", "[common][events]") {
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto& layout1 = project.InsertNewLayout("Layout1", 0);
layout1.InsertNewObject(project, "MyExtension::Sprite", "MySpriteObject", 0);
layout1.GetObjects().InsertNewObject(project, "MyExtension::Sprite",
"MySpriteObject", 0);
gd::ExpressionParser2 parser;

View File

@@ -35,29 +35,36 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
// Create an instance of BuiltinObject.
// This is not possible in practice.
auto &myObject = layout1.InsertNewObject(project, "", "MyObject", 0);
auto &myObject =
layout1.GetObjects().InsertNewObject(project, "", "MyObject", 0);
myObject.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
auto &myGroup = layout1.GetObjectGroups().InsertNew("MyGroup");
auto &myGroup =
layout1.GetObjects().GetObjectGroups().InsertNew("MyGroup");
myGroup.AddObject(myObject.GetName());
layout1.GetObjectGroups().InsertNew("EmptyGroup");
layout1.GetObjects().GetObjectGroups().InsertNew("EmptyGroup");
auto &mySpriteObject = layout1.InsertNewObject(project, "MyExtension::Sprite", "MySpriteObject", 1);
auto &mySpriteObject = layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MySpriteObject", 1);
mySpriteObject.GetVariables().InsertNew("MyVariable");
mySpriteObject.GetVariables().InsertNew("MyVariable2");
mySpriteObject.GetVariables().InsertNew("MyVariable3");
mySpriteObject.GetVariables().InsertNew("MyNumberVariable").SetValue(123);
mySpriteObject.GetVariables().InsertNew("MyStringVariable").SetString("Test");
auto &mySpriteObject2 = layout1.InsertNewObject(project, "MyExtension::Sprite", "MySpriteObject2", 1);
// A variable with the same name as the object.
mySpriteObject.GetVariables().InsertNew("MySpriteObject");
auto &mySpriteObject2 = layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MySpriteObject2", 1);
mySpriteObject2.GetVariables().InsertNew("MyVariable", 0);
mySpriteObject2.GetVariables().InsertNew("MyVariable2", 1);
layout1.InsertNewObject(project,
"MyExtension::FakeObjectWithDefaultBehavior",
"FakeObjectWithDefaultBehavior",
2);
layout1.GetObjects().InsertNewObject(
project, "MyExtension::FakeObjectWithDefaultBehavior",
"FakeObjectWithDefaultBehavior", 2);
auto &mySpriteGroup = layout1.GetObjectGroups().InsertNew("MySpriteObjects", 0);
auto &mySpriteGroup =
layout1.GetObjects().GetObjectGroups().InsertNew(
"MySpriteObjects", 0);
mySpriteGroup.AddObject("MySpriteObject");
mySpriteGroup.AddObject("MySpriteObject2");
@@ -1685,6 +1692,27 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
}
}
SECTION("Variable with the same name as an object") {
auto node = parser.ParseExpression("MySpriteObject.MySpriteObject");
REQUIRE(node != nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers,
"number|string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 0);
REQUIRE(validator.GetAllErrors().size() == 0);
}
SECTION("Variable with the same name as an object (with child-variables)") {
auto node = parser.ParseExpression("MySpriteObject.MySpriteObject.MyChild.MyChild");
REQUIRE(node != nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 0);
REQUIRE(validator.GetAllErrors().size() == 0);
}
SECTION("Invalid object variables (1 level, non existing object)") {
{
auto node =
@@ -2785,6 +2813,33 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
"No variable with this name found.");
}
SECTION("Variable name collision with an object") {
auto node = parser.ParseExpression("MySpriteObject");
REQUIRE(node != nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers,
"variable");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 0);
REQUIRE(validator.GetAllErrors().size() == 1);
REQUIRE(validator.GetAllErrors()[0]->GetMessage() ==
"This variable has the same name as an object. Consider renaming "
"one or the other.");
}
SECTION("Variable name collision with an object (with child-variables)") {
auto node = parser.ParseExpression("MySpriteObject.MyChild.MyChild");
REQUIRE(node != nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "variable");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 0);
REQUIRE(validator.GetAllErrors().size() == 1);
REQUIRE(validator.GetAllErrors()[0]->GetMessage() ==
"This variable has the same name as an object. Consider renaming "
"one or the other.");
}
SECTION("Declared scene variable") {
auto node = parser.ParseExpression("MySceneVariable");
REQUIRE(node != nullptr);

View File

@@ -20,7 +20,8 @@ TEST_CASE("ExpressionParser2 - Benchmarks", "[common][events]") {
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &layout1 = project.InsertNewLayout("Layout1", 0);
layout1.InsertNewObject(project, "MyExtension::Sprite", "MySpriteObject", 0);
layout1.GetObjects().InsertNewObject(project, "MyExtension::Sprite",
"MySpriteObject", 0);
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);

View File

@@ -19,7 +19,8 @@ TEST_CASE("ExpressionParser2 - Naughty strings", "[common][events]") {
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &layout1 = project.InsertNewLayout("Layout1", 0);
layout1.InsertNewObject(project, "MyExtension::Sprite", "MySpriteObject", 0);
layout1.GetObjects().InsertNewObject(project, "MyExtension::Sprite",
"MySpriteObject", 0);
gd::ExpressionParser2 parser;

View File

@@ -18,7 +18,8 @@ TEST_CASE("ExpressionParser2NodePrinter", "[common][events]") {
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &layout1 = project.InsertNewLayout("Layout1", 0);
layout1.InsertNewObject(project, "MyExtension::Sprite", "MySpriteObject", 0);
layout1.GetObjects().InsertNewObject(project, "MyExtension::Sprite",
"MySpriteObject", 0);
gd::ExpressionParser2 parser;

View File

@@ -25,13 +25,13 @@ TEST_CASE("Layout", "[common]") {
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
object.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(project, layout, "MyObject",
"MyBehavior", true) ==
"MyExtension::MyBehavior");
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(
project.GetObjects(), layout.GetObjects(),
"MyObject", "MyBehavior", true) == "MyExtension::MyBehavior");
}
SECTION("Give an empty type for an object that doesn't have the behavior") {
@@ -40,11 +40,12 @@ TEST_CASE("Layout", "[common]") {
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(project, layout, "MyObject",
"MyBehavior", true) == "");
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(
project.GetObjects(), layout.GetObjects(),
"MyObject", "MyBehavior", true) == "");
}
SECTION("Find the type of a behavior in a group") {
@@ -53,63 +54,70 @@ TEST_CASE("Layout", "[common]") {
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject1", 0);
gd::Object &object1 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
gd::Object &object2 =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject2", 0);
gd::Object &object2 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject2", 0);
object2.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
auto &group = layout.GetObjectGroups().InsertNew("MyGroup", 0);
auto &group =
layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(project, layout, "MyGroup",
"MyBehavior", true) ==
"MyExtension::MyBehavior");
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(
project.GetObjects(), layout.GetObjects(),
"MyGroup", "MyBehavior", true) == "MyExtension::MyBehavior");
}
SECTION("Give an empty type for a group with an object missing the behavior") {
SECTION(
"Give an empty type for a group with an object missing the behavior") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject1", 0);
gd::Object &object1 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
gd::Object &object2 =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject2", 0);
gd::Object &object2 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject2", 0);
// object2 doesn't have the behavior.
auto &group = layout.GetObjectGroups().InsertNew("MyGroup", 0);
auto &group =
layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(project, layout, "MyGroup",
"MyBehavior", true) == "");
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(
project.GetObjects(), layout.GetObjects(),
"MyGroup", "MyBehavior", true) == "");
}
SECTION("Give an empty type for a group with behaviors of same name but different types") {
SECTION("Give an empty type for a group with behaviors of same name but "
"different types") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object1 =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject1", 0);
gd::Object &object1 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject1", 0);
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
gd::Object &object2 =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject2", 0);
gd::Object &object2 = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject2", 0);
object2.AddNewBehavior(project, "MyExtension::MyOtherBehavior",
"MyBehavior");
auto &group = layout.GetObjectGroups().InsertNew("MyGroup", 0);
auto &group =
layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
group.AddObject(object1.GetName());
group.AddObject(object2.GetName());
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(project, layout, "MyGroup",
"MyBehavior", true) == "");
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(
project.GetObjects(), layout.GetObjects(),
"MyGroup", "MyBehavior", true) == "");
}
SECTION("Give an empty type for an empty group") {
@@ -118,9 +126,11 @@ TEST_CASE("Layout", "[common]") {
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
auto &group = layout.GetObjectGroups().InsertNew("MyGroup", 0);
auto &group =
layout.GetObjects().GetObjectGroups().InsertNew("MyGroup", 0);
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(project, layout, "MyGroup",
"MyBehavior", true) == "");
REQUIRE(GetTypeOfBehaviorInObjectOrGroup(
project.GetObjects(), layout.GetObjects(),
"MyGroup", "MyBehavior", true) == "");
}
}

View File

@@ -36,7 +36,7 @@ TEST_CASE("Object", "[common]") {
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.InsertNewObject(
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::FakeObjectWithDefaultBehavior", "MyObject", 0);
REQUIRE(object.HasBehaviorNamed("Effect"));

View File

@@ -43,8 +43,8 @@ TEST_CASE("ObjectAssetSerializer", "[common]") {
"MyEventsBasedObject", 0);
eventsBasedObject.SetFullName("My events based object");
eventsBasedObject.SetDescription("An events based object for test");
eventsBasedObject.InsertNewObject(project, "MyExtension::Sprite", "MyChild",
0);
eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyChild", 0);
auto &resourceManager = project.GetResourcesManager();
gd::ImageResource imageResource;
@@ -54,7 +54,7 @@ TEST_CASE("ObjectAssetSerializer", "[common]") {
resourceManager.AddResource(imageResource);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.InsertNewObject(
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyEventsExtension::MyEventsBasedObject", "MyObject", 0);
auto &configuration = object.GetConfiguration();
auto *customObjectConfiguration =

View File

@@ -43,8 +43,8 @@ gd::Object &SetupProjectWithSprite(gd::Project &project,
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object =
layout.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
SetupSpriteConfiguration(object.GetConfiguration());
return object;
@@ -98,7 +98,7 @@ void CheckSpriteConfiguration(gd::Object &object) {
void CheckSpriteConfiguration(gd::Project &project) {
auto &layout = project.GetLayout("Scene");
auto &object = layout.GetObject("MyObject");
auto &object = layout.GetObjects().GetObject("MyObject");
CheckSpriteConfiguration(object);
};
@@ -112,11 +112,11 @@ gd::Object &SetupProjectWithCustomObject(gd::Project &project,
"MyEventsBasedObject", 0);
eventsBasedObject.SetFullName("My events based object");
eventsBasedObject.SetDescription("An events based object for test");
eventsBasedObject.InsertNewObject(project, "MyExtension::Sprite", "MyChild",
0);
eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyChild", 0);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.InsertNewObject(
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyEventsExtension::MyEventsBasedObject", "MyObject", 0);
auto &configuration = object.GetConfiguration();
auto *customObjectConfiguration =
@@ -167,7 +167,7 @@ void CheckCustomObjectConfiguration(gd::Object &object) {
void CheckCustomObjectConfiguration(gd::Project &project) {
auto &layout = project.GetLayout("Scene");
auto &object = layout.GetObject("MyObject");
auto &object = layout.GetObjects().GetObject("MyObject");
CheckCustomObjectConfiguration(object);
};
} // namespace
@@ -232,7 +232,7 @@ TEST_CASE("ObjectSerialization", "[common]") {
SetupProjectWithDummyPlatform(project, platform);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.InsertNewObject(
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::FakeObjectWithDefaultBehavior", "MyObject", 0);
REQUIRE(object.HasBehaviorNamed("Effect"));

View File

@@ -79,15 +79,15 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
.SetValue(123);
// Declare variables in objects.
auto &object1 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
auto &object1 = layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
object1.GetVariables().InsertNew("MyObjectVariable");
object1.GetVariables()
.InsertNew("MyObjectStructureVariable")
.GetChild("MyChild")
.SetValue(123);
auto &object2 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object2", 0);
auto &object2 = layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object2", 0);
object2.GetVariables().InsertNew("MyObjectVariable");
object2.GetVariables()
.InsertNew("MyObjectStructureVariable")
@@ -339,22 +339,23 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
project, "BuiltinCommonInstructions::Repeat"));
// Declare variables in objects.
auto &object1 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
auto &object1 = layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
object1.GetVariables().InsertNew("MyObjectVariable");
object1.GetVariables()
.InsertNew("MyObjectStructureVariable")
.GetChild("MyChild")
.SetValue(123);
auto &object2 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object2", 0);
auto &object2 = layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object2", 0);
object2.GetVariables().InsertNew("MyObjectVariable");
object2.GetVariables()
.InsertNew("MyObjectStructureVariable")
.GetChild("MyChild")
.SetValue(123);
auto& group = layout1.GetObjectGroups().InsertNew("MyObjectGroup");
auto &group = layout1.GetObjects().GetObjectGroups().InsertNew(
"MyObjectGroup");
group.AddObject("Object1");
group.AddObject("Object2");
@@ -536,15 +537,15 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
.SetValue(123);
// Declare variables in objects.
auto &object1 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
auto &object1 = layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
object1.GetVariables().InsertNew("MyObjectVariable");
object1.GetVariables()
.InsertNew("MyObjectStructureVariable")
.GetChild("MyChild")
.SetValue(123);
auto &object2 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object2", 0);
auto &object2 = layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object2", 0);
object2.GetVariables().InsertNew("MyObjectVariable");
object2.GetVariables()
.InsertNew("MyObjectStructureVariable")
@@ -959,8 +960,8 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
SetupProjectWithDummyPlatform(project, platform);
auto &scene = project.InsertNewLayout("Scene", 0);
auto &object =
scene.InsertNewObject(project, "MyExtension::Sprite", "Object", 0);
auto &object = scene.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object", 0);
object.GetVariables()
.InsertNew("MyVariable")
.GetChild("MyChild")
@@ -1009,8 +1010,8 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
SetupProjectWithDummyPlatform(project, platform);
auto &scene = project.InsertNewLayout("Scene", 0);
auto &object =
scene.InsertNewObject(project, "MyExtension::Sprite", "Object", 0);
auto &object = scene.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object", 0);
object.GetVariables()
.InsertNew("MyVariable")
.GetChild("MyChild")
@@ -1057,8 +1058,8 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
SetupProjectWithDummyPlatform(project, platform);
auto &scene = project.InsertNewLayout("Scene", 0);
auto &object =
scene.InsertNewObject(project, "MyExtension::Sprite", "Object", 0);
auto &object = scene.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object", 0);
object.GetVariables()
.InsertNew("MyVariable")
.GetChild("MyChild")
@@ -1795,8 +1796,8 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
SetupProjectWithDummyPlatform(project, platform);
auto &scene = project.InsertNewLayout("Scene", 0);
auto &object =
scene.InsertNewObject(project, "MyExtension::Sprite", "Object", 0);
auto &object = scene.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object", 0);
object.GetVariables().InsertNew("MyObjectVariable").SetValue(123);
gd::StandardEvent &event =
@@ -1840,8 +1841,8 @@ TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
SetupProjectWithDummyPlatform(project, platform);
auto &scene = project.InsertNewLayout("Scene", 0);
auto &object =
scene.InsertNewObject(project, "MyExtension::Sprite", "Object", 0);
auto &object = scene.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object", 0);
object.GetVariables()
.InsertNew("MyObjectVariable")
.GetChild("MyChild")

View File

@@ -27,6 +27,7 @@
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/Project/Variable.h"
#include "catch.hpp"
@@ -1069,15 +1070,20 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
// Add a child-object with the same names the one from the scene
// to be able to use the same events list.
auto &childObject = eventsBasedObject.InsertNewObject(
auto &childObject = eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "ObjectWithMyBehavior", 0);
childObject.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior", "MyBehavior");
childObject.AddNewBehavior(
project, "MyEventsExtension::MyEventsBasedBehavior", "MyBehavior");
childObject.GetVariables().InsertNew("MyVariable");
childObject.GetVariables().InsertNew("MyStructureVariable").CastTo(gd::Variable::Structure);
auto &group = eventsBasedObject.GetObjectGroups().InsertNew("GroupWithMyBehavior");
childObject.GetVariables()
.InsertNew("MyStructureVariable")
.CastTo(gd::Variable::Structure);
auto &group =
eventsBasedObject.GetObjects().GetObjectGroups().InsertNew(
"GroupWithMyBehavior");
group.AddObject(childObject.GetName());
eventsBasedObject.InsertNewObject(
eventsBasedObject.GetObjects().InsertNewObject(
project, "MyEventsExtension::MyEventsBasedObject", "MyCustomObject", 1);
}
@@ -1157,24 +1163,30 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
externalEvents.SetAssociatedLayout("Scene");
// Objects with event based behaviors
auto &object = layout.InsertNewObject(project, "MyExtension::Sprite",
"ObjectWithMyBehavior", 0);
object.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior", "MyBehavior");
auto &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "ObjectWithMyBehavior", 0);
object.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior",
"MyBehavior");
object.GetVariables().InsertNew("MyVariable");
object.GetVariables().InsertNew("MyStructureVariable").CastTo(gd::Variable::Structure);
auto &group = layout.GetObjectGroups().InsertNew("GroupWithMyBehavior", 0);
object.GetVariables()
.InsertNew("MyStructureVariable")
.CastTo(gd::Variable::Structure);
auto &group = layout.GetObjects().GetObjectGroups().InsertNew(
"GroupWithMyBehavior", 0);
group.AddObject("ObjectWithMyBehavior");
auto &globalObject = project.InsertNewObject(
auto &globalObject = project.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "GlobalObjectWithMyBehavior", 0);
globalObject.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior", "MyBehavior");
globalObject.AddNewBehavior(
project, "MyEventsExtension::MyEventsBasedBehavior", "MyBehavior");
// Custom objects
layout.InsertNewObject(project, "MyEventsExtension::MyEventsBasedObject",
"MyCustomObject", 1);
layout.GetObjects().InsertNewObject(
project, "MyEventsExtension::MyEventsBasedObject", "MyCustomObject", 1);
project.InsertNewObject(project, "MyEventsExtension::MyEventsBasedObject",
"MyGlobalCustomObject", 1);
project.GetObjects().InsertNewObject(
project, "MyEventsExtension::MyEventsBasedObject",
"MyGlobalCustomObject", 1);
SetupEvents(layout.GetEvents());
SetupEvents(externalEvents.GetEvents());
@@ -1209,19 +1221,24 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
group1.AddObject("Object2");
group1.AddObject("NotExistingObject");
group1.AddObject("GlobalObject1");
layout1.GetObjectGroups().Insert(group1);
layout1.GetObjects().GetObjectGroups().Insert(group1);
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object2", 0);
layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object2", 0);
gd::WholeProjectRefactorer::ObjectRemovedInLayout(
project, layout1, "Object1");
gd::WholeProjectRefactorer::GlobalObjectRemoved(
project, "GlobalObject1");
REQUIRE(layout1.GetObjectGroups()[0].Find("Object1") == false);
REQUIRE(layout1.GetObjectGroups()[0].Find("Object2") == true);
REQUIRE(layout1.GetObjectGroups()[0].Find("NotExistingObject") == true);
REQUIRE(layout1.GetObjectGroups()[0].Find("GlobalObject1") == false);
gd::WholeProjectRefactorer::ObjectRemovedInLayout(project, layout1,
"Object1");
gd::WholeProjectRefactorer::GlobalObjectRemoved(project, "GlobalObject1");
REQUIRE(layout1.GetObjects().GetObjectGroups()[0].Find(
"Object1") == false);
REQUIRE(layout1.GetObjects().GetObjectGroups()[0].Find(
"Object2") == true);
REQUIRE(layout1.GetObjects().GetObjectGroups()[0].Find(
"NotExistingObject") == true);
REQUIRE(layout1.GetObjects().GetObjectGroups()[0].Find(
"GlobalObject1") == false);
}
SECTION("Initial instances") {
@@ -1230,8 +1247,10 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
SetupProjectWithDummyPlatform(project, platform);
auto &layout1 = project.InsertNewLayout("Layout1", 0);
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object2", 0);
layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object2", 0);
gd::InitialInstance instance1;
instance1.SetObjectName("Object1");
@@ -1269,8 +1288,10 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
externalLayout1.SetAssociatedLayout("Layout1");
externalLayout2.SetAssociatedLayout("Layout2");
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object2", 0);
layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object2", 0);
gd::InitialInstance instance1;
instance1.SetObjectName("Object1");
@@ -1316,20 +1337,27 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
group1.AddObject("Object2");
group1.AddObject("NotExistingObject");
group1.AddObject("GlobalObject1");
layout1.GetObjectGroups().Insert(group1);
layout1.GetObjects().GetObjectGroups().Insert(group1);
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object2", 0);
layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object2", 0);
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
project, layout1, "Object1", "Object3", /* isObjectGroup =*/false);
gd::WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
project, "GlobalObject1", "GlobalObject3", /* isObjectGroup =*/false);
REQUIRE(layout1.GetObjectGroups()[0].Find("Object1") == false);
REQUIRE(layout1.GetObjectGroups()[0].Find("Object2") == true);
REQUIRE(layout1.GetObjectGroups()[0].Find("Object3") == true);
REQUIRE(layout1.GetObjectGroups()[0].Find("GlobalObject1") == false);
REQUIRE(layout1.GetObjectGroups()[0].Find("GlobalObject3") == true);
REQUIRE(layout1.GetObjects().GetObjectGroups()[0].Find(
"Object1") == false);
REQUIRE(layout1.GetObjects().GetObjectGroups()[0].Find(
"Object2") == true);
REQUIRE(layout1.GetObjects().GetObjectGroups()[0].Find(
"Object3") == true);
REQUIRE(layout1.GetObjects().GetObjectGroups()[0].Find(
"GlobalObject1") == false);
REQUIRE(layout1.GetObjects().GetObjectGroups()[0].Find(
"GlobalObject3") == true);
}
SECTION("Initial instances") {
@@ -1338,8 +1366,10 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
SetupProjectWithDummyPlatform(project, platform);
auto &layout1 = project.InsertNewLayout("Layout1", 0);
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object2", 0);
layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object2", 0);
gd::InitialInstance instance1;
instance1.SetObjectName("Object1");
@@ -1379,8 +1409,10 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
externalLayout1.SetAssociatedLayout("Layout1");
externalLayout2.SetAssociatedLayout("Layout2");
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object2", 0);
layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
layout1.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object2", 0);
gd::InitialInstance instance1;
instance1.SetObjectName("Object1");
@@ -1481,8 +1513,8 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
SetupProjectWithDummyPlatform(project, platform);
auto &scene = project.InsertNewLayout("Scene", 0);
auto &object =
scene.InsertNewObject(project, "MyExtension::Sprite", "Object", 0);
auto &object = scene.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object", 0);
gd::StandardEvent &event =
dynamic_cast<gd::StandardEvent &>(scene.GetEvents().InsertNewEvent(
@@ -1529,16 +1561,15 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
// events in this test.
// Create the objects container for the events function
gd::ObjectsContainer globalObjectsContainer;
gd::ObjectsContainer objectsContainer;
gd::ParameterMetadataTools::ParametersToObjectsContainer(
project, eventsFunction.GetParameters(), objectsContainer);
// (this is strictly not necessary because we're not testing events in
// this test)
gd::ObjectsContainer parametersObjectsContainer;
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForFreeEventsFunction(
project, eventsExtension, eventsFunction,
parametersObjectsContainer);
// Trigger the refactoring after the renaming of an object
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
project, eventsFunction, globalObjectsContainer, objectsContainer,
project, projectScopedContainers, eventsFunction,
"Object1", "RenamedObject1",
/* isObjectGroup=*/false);
@@ -1558,20 +1589,21 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
eventsExtension.GetEventsFunction("MyOtherEventsFunction");
// Create the objects container for the events function
gd::ObjectsContainer globalObjectsContainer;
gd::ObjectsContainer objectsContainer;
gd::ParameterMetadataTools::ParametersToObjectsContainer(
project, eventsFunction.GetParameters(), objectsContainer);
gd::ObjectsContainer parametersObjectsContainer;
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForFreeEventsFunction(
project, eventsExtension, eventsFunction,
parametersObjectsContainer);
// Simulate a variable in ObjectWithMyBehavior, even if this is not
// supported by the editor.
auto& objectWithMyBehavior = objectsContainer.GetObject("ObjectWithMyBehavior");
auto& objectWithMyBehavior = parametersObjectsContainer.GetObject("ObjectWithMyBehavior");
objectWithMyBehavior.GetVariables().InsertNew("MyVariable");
objectWithMyBehavior.GetVariables().InsertNew("MyStructureVariable").CastTo(gd::Variable::Structure);
// Trigger the refactoring after the renaming of an object
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
project, eventsFunction, globalObjectsContainer, objectsContainer,
project, projectScopedContainers, eventsFunction,
"ObjectWithMyBehavior", "RenamedObjectWithMyBehavior",
/* isObjectGroup=*/false);
@@ -1590,76 +1622,230 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
}
SECTION("Object renamed (in events-based object)") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
SECTION("Groups") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &eventsBasedObject =
eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
auto &eventsBasedObject =
project.GetEventsFunctionsExtension("MyEventsExtension")
.GetEventsBasedObjects()
.Get("MyOtherEventsBasedObject");
gd::ObjectGroup group1;
group1.AddObject("Object1");
group1.AddObject("Object2");
group1.AddObject("NotExistingObject");
eventsBasedObject.GetObjects().GetObjectGroups().Insert(group1);
// Create the objects container for the events function
gd::ObjectsContainer globalObjectsContainer;
eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object2", 0);
// Trigger the refactoring after the renaming of an object
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
project, globalObjectsContainer, eventsBasedObject,
"ObjectWithMyBehavior", "RenamedObjectWithMyBehavior",
/* isObjectGroup=*/false);
// Create the objects container for the events function
gd::ObjectsContainer parametersObjectsContainer;
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForEventsBasedObject(
project, eventsExtension, eventsBasedObject,
parametersObjectsContainer);
auto &objectFunctionEvents =
eventsBasedObject
.GetEventsFunctions()
.GetEventsFunction("MyObjectEventsFunction")
.GetEvents();
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
project, projectScopedContainers, eventsBasedObject, "Object1",
"Object3", /* isObjectGroup =*/false);
REQUIRE(eventsBasedObject.GetObjects().GetObjectGroups().size() == 1);
REQUIRE(eventsBasedObject.GetObjects().GetObjectGroups()[0].Find(
"Object1") == false);
REQUIRE(eventsBasedObject.GetObjects().GetObjectGroups()[0].Find(
"Object2") == true);
REQUIRE(eventsBasedObject.GetObjects().GetObjectGroups()[0].Find(
"Object3") == true);
}
// Check object name has been renamed in action parameters.
REQUIRE(GetEventFirstActionFirstParameterString(
objectFunctionEvents.GetEvent(FreeFunctionWithObjects)) ==
"RenamedObjectWithMyBehavior");
SECTION("Initial instances") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &eventsBasedObject =
eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
// Check object name has been renamed in expressions and object variables.
REQUIRE(GetEventFirstActionFirstParameterString(
objectFunctionEvents.GetEvent(FreeFunctionWithObjectExpression)) ==
"RenamedObjectWithMyBehavior.GetObjectNumber() + RenamedObjectWithMyBehavior.MyVariable + RenamedObjectWithMyBehavior.MyStructureVariable.Child");
eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object2", 0);
gd::InitialInstance instance1;
instance1.SetObjectName("Object1");
gd::InitialInstance instance2;
instance2.SetObjectName("Object2");
eventsBasedObject.GetInitialInstances().InsertInitialInstance(instance1);
eventsBasedObject.GetInitialInstances().InsertInitialInstance(instance2);
// Create the objects container for the events function
gd::ObjectsContainer parametersObjectsContainer;
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForEventsBasedObject(
project, eventsExtension, eventsBasedObject,
parametersObjectsContainer);
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
project, projectScopedContainers, eventsBasedObject, "Object1",
"Object3", /* isObjectGroup =*/false);
REQUIRE(eventsBasedObject.GetInitialInstances().HasInstancesOfObject(
"Object1") == false);
REQUIRE(eventsBasedObject.GetInitialInstances().HasInstancesOfObject(
"Object3") == true);
}
SECTION("Events") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
auto &eventsBasedObject =
project.GetEventsFunctionsExtension("MyEventsExtension")
.GetEventsBasedObjects()
.Get("MyOtherEventsBasedObject");
// Create the objects container for the events function
gd::ObjectsContainer parametersObjectsContainer;
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForEventsBasedObject(
project, eventsExtension, eventsBasedObject,
parametersObjectsContainer);
// Trigger the refactoring after the renaming of an object
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
project, projectScopedContainers, eventsBasedObject,
"ObjectWithMyBehavior", "RenamedObjectWithMyBehavior",
/* isObjectGroup=*/false);
auto &objectFunctionEvents =
eventsBasedObject.GetEventsFunctions()
.GetEventsFunction("MyObjectEventsFunction")
.GetEvents();
// Check object name has been renamed in action parameters.
REQUIRE(GetEventFirstActionFirstParameterString(
objectFunctionEvents.GetEvent(FreeFunctionWithObjects)) ==
"RenamedObjectWithMyBehavior");
// Check object name has been renamed in expressions and object variables.
REQUIRE(
GetEventFirstActionFirstParameterString(objectFunctionEvents.GetEvent(
FreeFunctionWithObjectExpression)) ==
"RenamedObjectWithMyBehavior.GetObjectNumber() + "
"RenamedObjectWithMyBehavior.MyVariable + "
"RenamedObjectWithMyBehavior.MyStructureVariable.Child");
}
}
SECTION("Object deleted (in events function)") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
SECTION("Object deleted (in events-based object)") {
SECTION("Groups") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &eventsBasedObject =
eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
// Add a (free) function with an object group
gd::EventsFunction &eventsFunction =
eventsExtension.InsertNewEventsFunction("MyEventsFunction", 0);
gd::ObjectGroup &objectGroup =
eventsFunction.GetObjectGroups().InsertNew("MyGroup", 0);
objectGroup.AddObject("Object1");
objectGroup.AddObject("Object2");
// In theory, we would add the object parameters, but we're not testing
// events in this test.
gd::ObjectGroup group1;
group1.AddObject("Object1");
group1.AddObject("Object2");
group1.AddObject("NotExistingObject");
eventsBasedObject.GetObjects().GetObjectGroups().Insert(group1);
// Create the objects container for the events function
gd::ObjectsContainer globalObjectsContainer;
gd::ObjectsContainer objectsContainer;
gd::ParameterMetadataTools::ParametersToObjectsContainer(
project, eventsFunction.GetParameters(), objectsContainer);
// (this is strictly not necessary because we're not testing events in this
// test)
eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object2", 0);
// Trigger the refactoring after the renaming of an object
gd::WholeProjectRefactorer::ObjectRemovedInEventsFunction(
project, eventsFunction, globalObjectsContainer, objectsContainer,
"Object1");
// Create the objects container for the events function
gd::ObjectsContainer parametersObjectsContainer;
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForEventsBasedObject(
project, eventsExtension, eventsBasedObject,
parametersObjectsContainer);
REQUIRE(objectGroup.Find("Object1") == false);
REQUIRE(objectGroup.Find("Object2") == true);
gd::WholeProjectRefactorer::ObjectRemovedInEventsBasedObject(
project, eventsBasedObject, "Object1");
REQUIRE(eventsBasedObject.GetObjects().GetObjectGroups().size() == 1);
REQUIRE(eventsBasedObject.GetObjects().GetObjectGroups()[0].Find(
"Object1") == false);
REQUIRE(eventsBasedObject.GetObjects().GetObjectGroups()[0].Find(
"Object2") == true);
REQUIRE(eventsBasedObject.GetObjects().GetObjectGroups()[0].Find(
"NotExistingObject") == true);
}
// Events are not tested
SECTION("Initial instances") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &eventsBasedObject =
eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object1", 0);
eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "Object2", 0);
gd::InitialInstance instance1;
instance1.SetObjectName("Object1");
gd::InitialInstance instance2;
instance2.SetObjectName("Object2");
eventsBasedObject.GetInitialInstances().InsertInitialInstance(instance1);
eventsBasedObject.GetInitialInstances().InsertInitialInstance(instance2);
// Create the objects container for the events function
gd::ObjectsContainer parametersObjectsContainer;
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForEventsBasedObject(
project, eventsExtension, eventsBasedObject,
parametersObjectsContainer);
gd::WholeProjectRefactorer::ObjectRemovedInEventsBasedObject(
project, eventsBasedObject, "Object1");
REQUIRE(eventsBasedObject.GetInitialInstances().HasInstancesOfObject(
"Object1") == false);
REQUIRE(eventsBasedObject.GetInitialInstances().HasInstancesOfObject(
"Object2") == true);
}
SECTION("Function groups") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
// Add a (free) function with an object group
gd::EventsFunction &eventsFunction =
eventsExtension.InsertNewEventsFunction("MyEventsFunction", 0);
gd::ObjectGroup &objectGroup =
eventsFunction.GetObjectGroups().InsertNew("MyGroup", 0);
objectGroup.AddObject("Object1");
objectGroup.AddObject("Object2");
// In theory, we would add the object parameters, but we're not testing
// events in this test.
// Trigger the refactoring after the renaming of an object
gd::WholeProjectRefactorer::ObjectRemovedInEventsFunction(
project, eventsFunction, "Object1");
REQUIRE(objectGroup.Find("Object1") == false);
REQUIRE(objectGroup.Find("Object2") == true);
// Events are not tested
}
}
SECTION("Events extension renamed in instructions") {
@@ -1700,31 +1886,37 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
// Check that the type of the behavior was changed in the behaviors of
// objects. Name is *not* changed.
REQUIRE(project.GetLayout("Scene")
.GetObjects()
.GetObject("ObjectWithMyBehavior")
.GetBehavior("MyBehavior")
.GetTypeName() ==
"MyRenamedExtension::MyEventsBasedBehavior");
REQUIRE(project.GetObject("GlobalObjectWithMyBehavior")
REQUIRE(project.GetObjects()
.GetObject("GlobalObjectWithMyBehavior")
.GetBehavior("MyBehavior")
.GetTypeName() ==
"MyRenamedExtension::MyEventsBasedBehavior");
REQUIRE(project.GetEventsFunctionsExtension("MyEventsExtension")
.GetEventsBasedObjects()
.Get("MyOtherEventsBasedObject")
.GetObjects()
.GetObject("ObjectWithMyBehavior")
.GetBehavior("MyBehavior")
.GetTypeName() ==
"MyRenamedExtension::MyEventsBasedBehavior");
// Check that the type of the object was changed. Name is *not* changed.
REQUIRE(
project.GetLayout("Scene").GetObject("MyCustomObject").GetType() ==
"MyRenamedExtension::MyEventsBasedObject");
REQUIRE(project.GetObject("MyGlobalCustomObject").GetType() ==
"MyRenamedExtension::MyEventsBasedObject");
REQUIRE(project.GetLayout("Scene")
.GetObjects()
.GetObject("MyCustomObject")
.GetType() == "MyRenamedExtension::MyEventsBasedObject");
REQUIRE(project.GetObjects()
.GetObject("MyGlobalCustomObject")
.GetType() == "MyRenamedExtension::MyEventsBasedObject");
REQUIRE(project.GetEventsFunctionsExtension("MyEventsExtension")
.GetEventsBasedObjects()
.Get("MyOtherEventsBasedObject")
.GetObjects()
.GetObject("MyCustomObject")
.GetType() == "MyRenamedExtension::MyEventsBasedObject");
@@ -1774,11 +1966,13 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
// Check that the type of the object was changed in the custom
// objects. Name is *not* changed.
REQUIRE(
project.GetLayout("Scene").GetObject("MyCustomObject").GetType() ==
"MyRenamedExtension::MyEventsBasedObject");
REQUIRE(project.GetObject("MyGlobalCustomObject").GetType() ==
"MyRenamedExtension::MyEventsBasedObject");
REQUIRE(project.GetLayout("Scene")
.GetObjects()
.GetObject("MyCustomObject")
.GetType() == "MyRenamedExtension::MyEventsBasedObject");
REQUIRE(project.GetObjects()
.GetObject("MyGlobalCustomObject")
.GetType() == "MyRenamedExtension::MyEventsBasedObject");
// Check if events-based object methods have been renamed in
// instructions
@@ -2075,17 +2269,20 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
// Check that the type of the behavior was changed in the behaviors of
// objects. Name is *not* changed.
REQUIRE(project.GetLayout("Scene")
.GetObjects()
.GetObject("ObjectWithMyBehavior")
.GetBehavior("MyBehavior")
.GetTypeName() ==
"MyEventsExtension::MyRenamedEventsBasedBehavior");
REQUIRE(project.GetObject("GlobalObjectWithMyBehavior")
REQUIRE(project.GetObjects()
.GetObject("GlobalObjectWithMyBehavior")
.GetBehavior("MyBehavior")
.GetTypeName() ==
"MyEventsExtension::MyRenamedEventsBasedBehavior");
REQUIRE(project.GetEventsFunctionsExtension("MyEventsExtension")
.GetEventsBasedObjects()
.Get("MyOtherEventsBasedObject")
.GetObjects()
.GetObject("ObjectWithMyBehavior")
.GetBehavior("MyBehavior")
.GetTypeName() ==
@@ -2187,13 +2384,17 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
"MyRenamedEventsBasedObject");
// Check that the type of the object was changed. Name is *not* changed.
REQUIRE(project.GetLayout("Scene").GetObject("MyCustomObject").GetType() ==
"MyEventsExtension::MyRenamedEventsBasedObject");
REQUIRE(project.GetObject("MyGlobalCustomObject").GetType() ==
"MyEventsExtension::MyRenamedEventsBasedObject");
REQUIRE(project.GetLayout("Scene")
.GetObjects()
.GetObject("MyCustomObject")
.GetType() == "MyEventsExtension::MyRenamedEventsBasedObject");
REQUIRE(project.GetObjects()
.GetObject("MyGlobalCustomObject")
.GetType() == "MyEventsExtension::MyRenamedEventsBasedObject");
REQUIRE(project.GetEventsFunctionsExtension("MyEventsExtension")
.GetEventsBasedObjects()
.Get("MyOtherEventsBasedObject")
.GetObjects()
.GetObject("MyCustomObject")
.GetType() == "MyEventsExtension::MyRenamedEventsBasedObject");
@@ -2844,8 +3045,8 @@ TEST_CASE("WholeProjectRefactorer (FindInvalidRequiredBehaviorProperties)",
// Insert an object using a behavior requiring another behavior.
// But don't fill the property, which is a problem.
auto &object =
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto &object = project.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
object.AddNewBehavior(project,
"MyExtension::BehaviorWithRequiredBehaviorProperty",
"MyBehaviorWithRequiredBehaviorProperty");
@@ -2867,8 +3068,8 @@ TEST_CASE("WholeProjectRefactorer (FindInvalidRequiredBehaviorProperties)",
SetupProjectWithDummyPlatform(project, platform);
// Insert an object using a behavior requiring another behavior.
auto &object =
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto &object = project.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
object.AddNewBehavior(project,
"MyExtension::BehaviorWithRequiredBehaviorProperty",
"MyBehaviorWithRequiredBehaviorProperty");
@@ -2891,8 +3092,8 @@ TEST_CASE("WholeProjectRefactorer (FindInvalidRequiredBehaviorProperties)",
SetupProjectWithDummyPlatform(project, platform);
// Insert an object using a behavior requiring another behavior.
auto &object =
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto &object = project.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
object.AddNewBehavior(project,
"MyExtension::BehaviorWithRequiredBehaviorProperty",
"MyBehaviorWithRequiredBehaviorProperty");
@@ -2923,8 +3124,8 @@ TEST_CASE("WholeProjectRefactorer (FindInvalidRequiredBehaviorProperties)",
SetupProjectWithDummyPlatform(project, platform);
// Insert an object using a behavior requiring another behavior.
auto &object =
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto &object = project.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
object.AddNewBehavior(project,
"MyExtension::BehaviorWithRequiredBehaviorProperty",
"MyBehaviorWithRequiredBehaviorProperty");
@@ -2974,8 +3175,8 @@ TEST_CASE("WholeProjectRefactorer (FixInvalidRequiredBehaviorProperties)",
// Insert an object using a behavior requiring another behavior.
// But don't fill the property, which is a problem.
auto &object =
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto &object = project.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
object.AddNewBehavior(project,
"MyExtension::BehaviorWithRequiredBehaviorProperty",
"MyBehaviorWithRequiredBehaviorProperty");
@@ -3014,8 +3215,8 @@ TEST_CASE("WholeProjectRefactorer (FixInvalidRequiredBehaviorProperties)",
SetupProjectWithDummyPlatform(project, platform);
// Insert an object using a behavior requiring another behavior.
auto &object =
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto &object = project.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
object.AddNewBehavior(project,
"MyExtension::BehaviorWithRequiredBehaviorProperty",
"MyBehaviorWithRequiredBehaviorProperty");
@@ -3057,8 +3258,8 @@ TEST_CASE("WholeProjectRefactorer (AddBehaviorAndRequiredBehaviors)",
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &object =
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto &object = project.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
// Add a simple behavior.
gd::WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
@@ -3072,8 +3273,8 @@ TEST_CASE("WholeProjectRefactorer (AddBehaviorAndRequiredBehaviors)",
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &object =
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto &object = project.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
// Add an unknown behavior.
gd::WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
@@ -3088,8 +3289,8 @@ TEST_CASE("WholeProjectRefactorer (AddBehaviorAndRequiredBehaviors)",
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &object =
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto &object = project.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
// Add the behavior that requires a behavior.
gd::WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
@@ -3118,8 +3319,8 @@ TEST_CASE("WholeProjectRefactorer (AddBehaviorAndRequiredBehaviors)",
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &object =
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto &object = project.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
// Add the behavior that requires a behavior that requires another.
gd::WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
@@ -3161,8 +3362,8 @@ TEST_CASE("WholeProjectRefactorer (FindDependentBehaviorNames)", "[common]") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &object =
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto &object = project.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
// Add the behavior that requires a behavior that requires another.
gd::WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
@@ -3213,8 +3414,8 @@ TEST_CASE("WholeProjectRefactorer (FindDependentBehaviorNames failing cases)",
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &object =
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
auto &object = project.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
// Add the behavior that requires a behavior that requires another.
gd::WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
@@ -3625,9 +3826,12 @@ TEST_CASE("RenameObjectAnimation", "[common]") {
auto &otherExternalEvents =
project.InsertNewExternalEvents("My external events", 0);
otherExternalEvents.SetAssociatedLayout("My other layout");
auto &object = layout.InsertNewObject(project, "MyExtension::Sprite", "MySprite", 0);
layout.InsertNewObject(project, "MyExtension::Sprite", "MySprite2", 1);
otherLayout.InsertNewObject(project, "MyExtension::Sprite", "MySprite", 0);
auto &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MySprite", 0);
layout.GetObjects().InsertNewObject(project, "MyExtension::Sprite",
"MySprite2", 1);
otherLayout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MySprite", 0);
auto &layoutAction =
CreateActionWithAnimationParameter(project, layout.GetEvents(), "MySprite");
@@ -3733,9 +3937,12 @@ TEST_CASE("RenameLayerEffect", "[common]") {
auto &otherExternalEvents =
project.InsertNewExternalEvents("My external events", 0);
otherExternalEvents.SetAssociatedLayout("My other layout");
auto &object = layout.InsertNewObject(project, "MyExtension::Sprite", "MySprite", 0);
layout.InsertNewObject(project, "MyExtension::Sprite", "MySprite2", 1);
otherLayout.InsertNewObject(project, "MyExtension::Sprite", "MySprite", 0);
auto &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MySprite", 0);
layout.GetObjects().InsertNewObject(project, "MyExtension::Sprite",
"MySprite2", 1);
otherLayout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MySprite", 0);
auto &layoutAction =
CreateActionWithLayerEffectParameter(project, layout.GetEvents(), "My layer");
@@ -3794,7 +4001,7 @@ TEST_CASE("RenameLayerEffect", "[common]") {
}
TEST_CASE("RemoveLayer", "[common]") {
SECTION("Can remove instances in a layout and its associated external layouts") {
SECTION("Can remove instances from a layer (in a scene and their associated external layouts)") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
@@ -3838,7 +4045,7 @@ TEST_CASE("RemoveLayer", "[common]") {
REQUIRE(initialInstances.GetLayerInstancesCount("My layer") == 3);
REQUIRE(externalInitialInstances.GetLayerInstancesCount("My layer") == 2);
gd::WholeProjectRefactorer::RemoveLayer(project, layout, "My layer");
gd::WholeProjectRefactorer::RemoveLayerInScene(project, layout, "My layer");
REQUIRE(initialInstances.GetInstancesCount() == 2);
REQUIRE(externalInitialInstances.GetInstancesCount() == 1);
@@ -3848,10 +4055,38 @@ TEST_CASE("RemoveLayer", "[common]") {
REQUIRE(initialInstances.GetLayerInstancesCount("My layer") == 0);
REQUIRE(externalInitialInstances.GetLayerInstancesCount("My layer") == 0);
}
SECTION("Can remove instances from a layer (in an events-based object)") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &eventsBasedObject = eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
eventsBasedObject.GetLayers().InsertNewLayer("My layer", 0);
auto &initialInstances = eventsBasedObject.GetInitialInstances();
initialInstances.InsertNewInitialInstance().SetLayer("My layer");
initialInstances.InsertNewInitialInstance().SetLayer("My layer");
initialInstances.InsertNewInitialInstance().SetLayer("My layer");
initialInstances.InsertNewInitialInstance().SetLayer("");
initialInstances.InsertNewInitialInstance().SetLayer("");
REQUIRE(initialInstances.GetInstancesCount() == 5);
REQUIRE(initialInstances.GetLayerInstancesCount("My layer") == 3);
gd::WholeProjectRefactorer::RemoveLayerInEventsBasedObject(
eventsBasedObject, "My layer");
REQUIRE(initialInstances.GetInstancesCount() == 2);
REQUIRE(initialInstances.GetLayerInstancesCount("My layer") == 0);
}
}
TEST_CASE("MergeLayers", "[common]") {
SECTION("Can merge instances from a layout into another layout (and their associated external layouts)") {
SECTION("Can merge instances from a layer into another layer (in a scene and their associated external layouts)") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
@@ -3897,7 +4132,7 @@ TEST_CASE("MergeLayers", "[common]") {
REQUIRE(initialInstances.GetLayerInstancesCount("My layer") == 3);
REQUIRE(externalInitialInstances.GetLayerInstancesCount("My layer") == 2);
gd::WholeProjectRefactorer::MergeLayers(project, layout, "My layer", "");
gd::WholeProjectRefactorer::MergeLayersInScene(project, layout, "My layer", "");
// No instance was removed.
REQUIRE(initialInstances.GetInstancesCount() == 6);
@@ -3917,4 +4152,39 @@ TEST_CASE("MergeLayers", "[common]") {
REQUIRE(initialInstances.GetLayerInstancesCount("My other layer") == 1);
REQUIRE(externalInitialInstances.GetLayerInstancesCount("My other layer") == 1);
}
SECTION("Can merge instances from a layer into another layer (in an events-based object)") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &eventsBasedObject = eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
eventsBasedObject.GetLayers().InsertNewLayer("My layer", 0);
auto &initialInstances = eventsBasedObject.GetInitialInstances();
initialInstances.InsertNewInitialInstance().SetLayer("My layer");
initialInstances.InsertNewInitialInstance().SetLayer("My layer");
initialInstances.InsertNewInitialInstance().SetLayer("My layer");
initialInstances.InsertNewInitialInstance().SetLayer("");
initialInstances.InsertNewInitialInstance().SetLayer("");
initialInstances.InsertNewInitialInstance().SetLayer("My other layer");
REQUIRE(initialInstances.GetInstancesCount() == 6);
REQUIRE(initialInstances.GetLayerInstancesCount("My layer") == 3);
gd::WholeProjectRefactorer::MergeLayersInEventsBasedObject(
eventsBasedObject, "My layer", "");
// No instance was removed.
REQUIRE(initialInstances.GetInstancesCount() == 6);
// No instance remain in "My layer".
REQUIRE(initialInstances.GetLayerInstancesCount("My layer") == 0);
// Other layers from the same layout are untouched.
REQUIRE(initialInstances.GetLayerInstancesCount("My other layer") == 1);
}
}

View File

@@ -1094,19 +1094,12 @@ module.exports = {
objectContent,
instance,
propertyName,
newValue,
project,
layout
newValue
) {
return false;
};
Cube3DObject.getInitialInstanceProperties = function (
content,
instance,
project,
layout
) {
Cube3DObject.getInitialInstanceProperties = function (content, instance) {
const instanceProperties = new gd.MapStringPropertyDescriptor();
return instanceProperties;
};
@@ -2115,7 +2108,6 @@ module.exports = {
constructor(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
@@ -2123,7 +2115,6 @@ module.exports = {
) {
super(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
@@ -2300,7 +2291,6 @@ module.exports = {
class RenderedCube3DObject3DInstance extends Rendered3DInstance {
constructor(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
@@ -2309,7 +2299,6 @@ module.exports = {
) {
super(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
@@ -2682,7 +2671,6 @@ module.exports = {
constructor(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
@@ -2690,7 +2678,6 @@ module.exports = {
) {
super(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
@@ -2945,7 +2932,6 @@ module.exports = {
constructor(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
@@ -2954,7 +2940,6 @@ module.exports = {
) {
super(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,

View File

@@ -165,14 +165,13 @@ Model3DObjectConfiguration::GetProperties() const {
bool Model3DObjectConfiguration::UpdateInitialInstanceProperty(
gd::InitialInstance &instance, const gd::String &propertyName,
const gd::String &newValue, gd::Project &project, gd::Layout &layout) {
const gd::String &newValue) {
return false;
}
std::map<gd::String, gd::PropertyDescriptor>
Model3DObjectConfiguration::GetInitialInstanceProperties(
const gd::InitialInstance &instance, gd::Project &project,
gd::Layout &layout) {
const gd::InitialInstance &instance) {
std::map<gd::String, gd::PropertyDescriptor> instanceProperties;
return instanceProperties;
}

View File

@@ -75,15 +75,11 @@ public:
const gd::String &value) override;
virtual std::map<gd::String, gd::PropertyDescriptor>
GetInitialInstanceProperties(const gd::InitialInstance &instance,
gd::Project &project,
gd::Layout &layout) override;
GetInitialInstanceProperties(const gd::InitialInstance &instance) override;
virtual bool UpdateInitialInstanceProperty(gd::InitialInstance &instance,
const gd::String &name,
const gd::String &value,
gd::Project &project,
gd::Layout &layout) override;
const gd::String &value) override;
/** \name Animations
* Methods related to animations management

View File

@@ -132,18 +132,11 @@ module.exports = {
objectContent,
instance,
propertyName,
newValue,
project,
layout
newValue
) {
return false;
};
objectBBText.getInitialInstanceProperties = function (
content,
instance,
project,
layout
) {
objectBBText.getInitialInstanceProperties = function (content, instance) {
var instanceProperties = new gd.MapStringPropertyDescriptor();
return instanceProperties;
};
@@ -500,7 +493,6 @@ module.exports = {
class RenderedBBTextInstance extends RenderedInstance {
constructor(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
@@ -508,7 +500,6 @@ module.exports = {
) {
super(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,

View File

@@ -134,17 +134,13 @@ module.exports = {
objectContent,
instance,
propertyName,
newValue,
project,
layout
newValue
) {
return false;
};
bitmapTextObject.getInitialInstanceProperties = function (
content,
instance,
project,
layout
instance
) {
var instanceProperties = new gd.MapStringPropertyDescriptor();
return instanceProperties;
@@ -641,7 +637,6 @@ module.exports = {
constructor(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
@@ -649,7 +644,6 @@ module.exports = {
) {
super(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,

View File

@@ -349,9 +349,7 @@ module.exports = {
objectContent,
instance,
propertyName,
newValue,
project,
layout
newValue
) {
if (propertyName === 'My instance property') {
instance.setRawStringProperty('instanceprop1', newValue);
@@ -364,12 +362,7 @@ module.exports = {
return false;
};
dummyObject.getInitialInstanceProperties = function (
content,
instance,
project,
layout
) {
dummyObject.getInitialInstanceProperties = function (content, instance) {
var instanceProperties = new gd.MapStringPropertyDescriptor();
instanceProperties
@@ -475,7 +468,6 @@ module.exports = {
class RenderedDummyObjectInstance extends RenderedInstance {
constructor(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
@@ -483,7 +475,6 @@ module.exports = {
) {
super(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,

View File

@@ -381,6 +381,28 @@ module.exports = {
.setFunctionName('gdjs.fileSystem.deleteFileAsync')
.setAsyncFunctionName('gdjs.fileSystem.deleteFileAsyncTask');
extension
.addAction(
'ReadDirectory',
_('Read a directory'),
_(
'Reads the contents of a directory (all files and sub-directories) and stores them in an array.'
),
_('Read the directory _PARAM0_ into _PARAM1_'),
_('Windows, Linux, MacOS/Asynchronous'),
'JsPlatform/Extensions/filesystem_delete_file32.png',
'JsPlatform/Extensions/filesystem_delete_file32.png'
)
.addParameter('string', _('Directory path'), '', false)
.addParameter('scenevar', _('Variable to store the result'), '', true)
.setParameterLongDescription(
'It is set to `"error"` if an error has occured, otherwise it is set to an array of all files and sub-directories present in the directory.'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/FileSystem/filesystemtools.js')
.setFunctionName('gdjs.fileSystem.readdir')
.setAsyncFunctionName('gdjs.fileSystem.readdirAsync');
extension
.addStrExpression(
'DesktopPath',

View File

@@ -662,6 +662,56 @@ namespace gdjs {
)
: (resultVar.setString('error'), new gdjs.ResolveTask());
/**
* Reads the contents of a directory.
* @param directoryPath Path to the directory.
* @param resultVar The variable where to store the result of the operation.
*/
export const readdir = function (
directoryPath: string,
resultVar: gdjs.Variable
) {
let result: string[] | string = 'error';
if (fs) {
try {
result = fs.readdirSync(directoryPath);
} catch (err) {
logger.error(
"Unable to read the directory: '" + directoryPath + "': ",
err
);
result = 'error';
}
}
resultVar.fromJSObject(result);
};
/**
* Read a directory's contents asynchronously.
* @param directoryPath Path to the directory
* @param resultVar The variable where to store the result of the operation
*/
export const readdirAsync = (
directoryPath: string,
resultVar: gdjs.Variable
) =>
asyncFs
? new gdjs.PromiseTask(
asyncFs
.readdir(directoryPath)
.then((results) => {
resultVar.fromJSObject(results);
})
.catch((err) => {
resultVar.setString('error');
logger.error(
"Unable to read the directory: '" + directoryPath + "': ",
err
);
})
)
: (resultVar.setString('error'), new gdjs.ResolveTask());
/**
* Check if the file or directory exists.
* @param filePath The path to the file or directory

View File

@@ -10,7 +10,6 @@ declare namespace PIXI {}
*/
class RenderedInstance {
_project: gd.Project;
_layout: gd.Layout;
_instance: gd.InitialInstance;
_associatedObjectConfiguration: gd.ObjectConfiguration;
_pixiContainer: PIXI.Container;
@@ -20,7 +19,6 @@ class RenderedInstance {
constructor(
project: gdProject,
layout: gdLayout,
instance: gdInitialInstance,
associatedObjectConfiguration: gdObjectConfiguration,
pixiContainer: PIXI.Container,
@@ -86,7 +84,6 @@ class RenderedInstance {
*/
class Rendered3DInstance {
_project: gdProject;
_layout: gdLayout;
_instance: gdInitialInstance;
_associatedObjectConfiguration: gdObjectConfiguration;
_pixiContainer: PIXI.Container;
@@ -98,7 +95,6 @@ class Rendered3DInstance {
constructor(
project: gdProject,
layout: gdLayout,
instance: gdInitialInstance,
associatedObjectConfiguration: gdObjectConfiguration,
pixiContainer: PIXI.Container,

View File

@@ -153,19 +153,12 @@ module.exports = {
objectContent,
instance,
propertyName,
newValue,
project,
layout
newValue
) {
return false;
};
lightObject.getInitialInstanceProperties = function (
content,
instance,
project,
layout
) {
lightObject.getInitialInstanceProperties = function (content, instance) {
const instanceProperties = new gd.MapStringPropertyDescriptor();
return instanceProperties;
@@ -247,7 +240,6 @@ module.exports = {
class RenderedLightObjectInstance extends RenderedInstance {
constructor(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
@@ -255,7 +247,6 @@ module.exports = {
) {
super(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,

View File

@@ -46,8 +46,8 @@ module.exports = {
.addCodeOnlyParameter('currentScene', '')
.setHelpPath('/all-features/multiplayer')
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -74,8 +74,8 @@ module.exports = {
.addParameter('yesorno', _('Show close button'), '', false)
.setHelpPath('/all-features/multiplayer')
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -102,8 +102,8 @@ module.exports = {
)
.setHelpPath('/all-features/multiplayer')
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -116,6 +116,34 @@ module.exports = {
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayer.endLobbyGame');
extension
.addAction(
'LeaveGameLobby',
_('Leave Game Lobby'),
_(
'Leave the current game lobby. This will trigger the "Player has left" condition on the other players, and the "Lobby game has ended" condition on the player leaving.'
),
_('Leave the game lobby'),
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
.setHelpPath('/all-features/multiplayer')
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayer.leaveGameLobby');
extension
.addAction(
'SendMessage',
@@ -132,8 +160,8 @@ module.exports = {
.addParameter('string', _('Message name'), '', false)
.addParameter('string', _('Message content'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -144,7 +172,71 @@ module.exports = {
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayerMessageManager.sendMessage');
.setFunctionName('gdjs.multiplayerMessageManager.sendCustomMessage');
extension
.addAction(
'SendVariableMessage',
_('Send custom message to other players with a variable'),
_(
"Send a custom message to other players in the lobby containing a variable, with an automatic retry system if it hasn't been received. Use with the condition 'Message has been received' to know when the message has been properly processed by the host."
),
_('Send message _PARAM0_ to other players with variable _PARAM1_'),
_('Advanced'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
.setHelpPath('/all-features/multiplayer')
.addParameter('string', _('Message name'), '', false)
.addParameter('variable', _('Variable'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName(
'gdjs.multiplayerMessageManager.sendVariableCustomMessage'
);
extension
.addAction(
'GetMessageVariable',
_('Get message variable'),
_(
"Store the data of the specified message in a variable. Use with the condition 'Message has been received' to know when the message has been properly processed by the host."
),
_('Save message _PARAM0_ data in _PARAM1_'),
_('Advanced'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
.setHelpPath('/all-features/multiplayer')
.addParameter('string', _('Message name'), '', false)
.addParameter('variable', _('Variable'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName(
'gdjs.multiplayerMessageManager.getVariableCustomMessageData'
);
extension
.addCondition(
@@ -158,8 +250,8 @@ module.exports = {
)
.addCodeOnlyParameter('currentScene', '')
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -183,8 +275,8 @@ module.exports = {
'JsPlatform/Extensions/multiplayer.svg'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -208,8 +300,8 @@ module.exports = {
'JsPlatform/Extensions/multiplayer.svg'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -233,8 +325,8 @@ module.exports = {
'JsPlatform/Extensions/multiplayer.svg'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -261,8 +353,8 @@ module.exports = {
)
.addParameter('string', _('Message name'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -273,7 +365,9 @@ module.exports = {
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayerMessageManager.hasMessageBeenReceived');
.setFunctionName(
'gdjs.multiplayerMessageManager.hasCustomMessageBeenReceived'
);
extension
.addCondition(
@@ -286,8 +380,8 @@ module.exports = {
'JsPlatform/Extensions/multiplayer.svg'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -311,8 +405,8 @@ module.exports = {
'JsPlatform/Extensions/multiplayer.svg'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -337,8 +431,8 @@ module.exports = {
)
.getCodeExtraInformation()
.addParameter('number', _('Player number'), '', false)
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -363,8 +457,8 @@ module.exports = {
)
.addParameter('string', _('Message name'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -375,7 +469,31 @@ module.exports = {
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayerMessageManager.getMessageData');
.setFunctionName('gdjs.multiplayerMessageManager.getCustomMessageData');
extension
.addExpression(
'MessageSender',
_('Message sender'),
_('Returns the player number of the sender of the specified message.'),
_('Advanced'),
'JsPlatform/Extensions/multiplayer.svg'
)
.addParameter('string', _('Message name'), '', false)
.getCodeExtraInformation()
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
.setFunctionName('gdjs.multiplayerMessageManager.getCustomMessageSender');
extension
.addExpressionAndCondition(
@@ -387,8 +505,8 @@ module.exports = {
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg'
)
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -412,8 +530,8 @@ module.exports = {
_('Lobbies'),
'JsPlatform/Extensions/multiplayer.svg'
)
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -442,8 +560,8 @@ module.exports = {
false
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -465,8 +583,8 @@ module.exports = {
'JsPlatform/Extensions/multiplayer.svg'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -494,8 +612,8 @@ module.exports = {
false
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -517,8 +635,8 @@ module.exports = {
'JsPlatform/Extensions/multiplayer.svg'
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -547,8 +665,8 @@ module.exports = {
'number',
gd.ParameterOptions.makeNewOptions().setDescription(_('Player number'))
)
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -579,8 +697,8 @@ module.exports = {
.addParameter('variable', _('Variable'), '', false)
.setHelpPath('/all-features/multiplayer')
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -610,8 +728,8 @@ module.exports = {
.addParameter('variable', _('Variable'), '', false)
.setHelpPath('/all-features/multiplayer')
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -641,8 +759,8 @@ module.exports = {
.addParameter('variable', _('Variable'), '', false)
.setHelpPath('/all-features/multiplayer')
.getCodeExtraInformation()
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -747,8 +865,8 @@ module.exports = {
multiplayerObjectBehavior,
sharedData
)
.setIncludeFile('Extensions/P2P/A_peer.js')
.addIncludeFile('Extensions/P2P/B_p2ptools.js')
.setIncludeFile('Extensions/Multiplayer/peer.js')
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
@@ -769,7 +887,7 @@ module.exports = {
_('Player object ownership'),
_('the player owning the object'),
_('the player owning the instance'),
_('Objects'),
_('Multiplayer'),
'JsPlatform/Extensions/multiplayer.svg'
)
.addParameter('object', _('Object'), '', false)
@@ -790,7 +908,7 @@ module.exports = {
'Check if the object is owned by the current player, as a player or the host.'
),
_('Object _PARAM0_ is owned by current player'),
_('Objects'),
_('Multiplayer'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
@@ -812,7 +930,7 @@ module.exports = {
'Take the ownership of the object. It will then be synchronized to other players, with the current player as the owner.'
),
_('Take ownership of _PARAM0_'),
_('Objects'),
_('Multiplayer'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
@@ -834,7 +952,7 @@ module.exports = {
'Remove the ownership of the object from the player. It will still be synchronized to other players, but the host owns it.'
),
_('Remove ownership of _PARAM0_'),
_('Objects'),
_('Multiplayer'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
@@ -848,6 +966,30 @@ module.exports = {
.markAsAdvanced()
.setFunctionName('removeObjectOwnership');
behavior
.addScopedAction(
'EnableBehaviorSynchronization',
_('Enable (or disable) the synchronization of a behavior'),
_(
"Enable or disable the synchronization of a behavior over the network. If disabled, the behavior's current state will not be sent to other players anymore."
),
_('Enable synchronization of _PARAM2_ for _PARAM0_: _PARAM3_'),
_('Multiplayer'),
'JsPlatform/Extensions/multiplayer.svg',
'JsPlatform/Extensions/multiplayer.svg'
)
.addParameter('object', _('Object'), '', false)
.addParameter(
'behavior',
_('Multiplayer behavior'),
'MultiplayerObjectBehavior',
false
)
.addParameter('behavior', _('Object behavior'), '', false)
.addParameter('yesorno', _('Enable synchronization'), '', false)
.markAsAdvanced()
.setFunctionName('enableBehaviorSynchronization');
return extension;
},
runExtensionSanityTests: function (gd, extension) {

File diff suppressed because it is too large Load Diff

View File

@@ -228,7 +228,7 @@ namespace gdjs {
// Before sending the change owner message, if we are becoming the new owner,
// we want to ensure this message is acknowledged, by everyone we're connected to.
if (variableData.newVariableOwner === currentPlayerNumber) {
const otherPeerIds = gdjs.evtTools.p2p.getAllPeers();
const otherPeerIds = gdjs.multiplayerPeerJsHelper.getAllPeers();
const variableOwnerChangedMessageName = gdjs.multiplayerMessageManager.createVariableOwnerChangedMessageNameFromChangeVariableOwnerMessage(
messageName
);
@@ -243,14 +243,12 @@ namespace gdjs {
}
debugLogger.info('Sending change owner message', messageName);
const connectedPeerIds = gdjs.evtTools.p2p.getAllPeers();
for (const peerId of connectedPeerIds) {
gdjs.multiplayerMessageManager.sendDataTo(
peerId,
messageName,
messageData
);
}
const connectedPeerIds = gdjs.multiplayerPeerJsHelper.getAllPeers();
gdjs.multiplayerMessageManager.sendDataTo(
connectedPeerIds,
messageName,
messageData
);
// Remove the variable from the list of variables ownership changes to sync.
delete variableOwnershipChangesToSyncAtEndOfFrame[variableNetworkId];

View File

@@ -101,17 +101,19 @@ namespace gdjs {
}, this._timeBeforeDestroyingObjectWithoutNetworkIdInMs);
}
private _sendDataToPeersWithIncreasedClock(
private _sendDataToPeersWithIncreasedClock = async (
messageName: string,
data: Object
) {
) => {
this._clock++;
data['_clock'] = this._clock;
const connectedPeerIds = gdjs.evtTools.p2p.getAllPeers();
for (const peerId of connectedPeerIds) {
gdjs.multiplayerMessageManager.sendDataTo(peerId, messageName, data);
}
}
const connectedPeerIds = gdjs.multiplayerPeerJsHelper.getAllPeers();
await gdjs.multiplayerMessageManager.sendDataTo(
connectedPeerIds,
messageName,
data
);
};
private _isOwnerAsPlayerOrHost() {
const currentPlayerNumber = gdjs.multiplayer.getCurrentPlayerNumber();
@@ -453,7 +455,7 @@ namespace gdjs {
// If we are player 1, we are connected to everyone, so we expect an acknowledgment from everyone.
// If we are another player, we are only connected to player 1, so we expect an acknowledgment from player 1.
// In both cases, this represents the list of peers the current user is connected to.
const otherPeerIds = gdjs.evtTools.p2p.getAllPeers();
const otherPeerIds = gdjs.multiplayerPeerJsHelper.getAllPeers();
const {
messageName: destroyMessageName,
messageData: destroyMessageData,
@@ -563,7 +565,7 @@ namespace gdjs {
// If we are another player, we are only connected to player 1, so we expect an acknowledgment from player 1.
// In both cases, this represents the list of peers the current user is connected to.
if (newObjectPlayerNumber === currentPlayerNumber) {
const otherPeerIds = gdjs.evtTools.p2p.getAllPeers();
const otherPeerIds = gdjs.multiplayerPeerJsHelper.getAllPeers();
const changeOwnerAcknowledgedMessageName = gdjs.multiplayerMessageManager.createInstanceOwnerChangedMessageNameFromChangeInstanceOwnerMessage(
messageName
);
@@ -586,6 +588,9 @@ namespace gdjs {
// If we are the new owner, also send directly an update of the position,
// so that the object is immediately moved on the screen and we don't wait for the next tick.
if (newObjectPlayerNumber === currentPlayerNumber) {
debugLogger.info(
'Sending update message to move the object immediately.'
);
const objectNetworkSyncData = this.owner.getNetworkSyncData();
const {
messageName: updateMessageName,
@@ -624,6 +629,18 @@ namespace gdjs {
getActionOnPlayerDisconnect() {
return this.actionOnPlayerDisconnect;
}
enableBehaviorSynchronization(behaviorName: string, enable: boolean) {
const behavior = this.owner.getBehavior(behaviorName);
if (!behavior) {
logger.error(
`Behavior ${behaviorName} does not exist on object ${this.owner.getName()}.`
);
return;
}
behavior.enableSynchronization(enable);
}
}
gdjs.registerBehavior(
'Multiplayer::MultiplayerObjectBehavior',

View File

@@ -1,24 +1,26 @@
namespace gdjs {
const logger = new gdjs.Logger('Multiplayer');
type Lobby = {
id: string;
name: string;
status: string;
players: { playerId: string; status: string }[];
};
export namespace multiplayer {
/** Set to true in testing to avoid relying on the multiplayer extension. */
export let disableMultiplayerForTesting = false;
let _isGameRegistered: boolean | null = null;
let _isCheckingIfGameIsRegistered = false;
let _isWaitingForLoginCallback = false;
let _isWaitingForLogin = false;
let _hasLobbyGameJustStarted = false;
export let _isLobbyGameRunning = false;
let _hasLobbyGameJustEnded = false;
let _lobbyId: string | null = null;
let _connectionId: string | null = null;
export let _lobby: {
id: string;
name: string;
status: string;
players: { playerId: string; status: string }[];
} | null = null;
export let _lobby: Lobby | null = null;
let _playerPublicProfiles: { id: string; username?: string }[] = [];
// Communication methods.
@@ -29,6 +31,7 @@ namespace gdjs {
const DEFAULT_WEBSOCKET_HEARTBEAT_INTERVAL = 10000;
const DEFAULT_LOBBY_HEARTBEAT_INTERVAL = 30000;
const DEFAULT_COUNTDOWN_SECONDS_TO_START = 5;
// Save if we are on dev environment so we don't need to use the runtimeGame every time.
let isUsingGDevelopDevelopmentEnvironment = false;
@@ -407,15 +410,17 @@ namespace gdjs {
// When socket is open, ask for the connectionId and send more session info, so that we can inform the lobbies window.
if (_websocket) {
_websocket.send(JSON.stringify({ action: 'getConnectionId' }));
const plarformInfo = runtimeScene.getGame().getPlatformInfo();
const platformInfo = runtimeScene.getGame().getPlatformInfo();
_websocket.send(
JSON.stringify({
action: 'sessionInformation',
connectionType: 'lobby',
isCordova: plarformInfo.isCordova,
devicePlatform: plarformInfo.devicePlatform,
navigatorPlatform: plarformInfo.navigatorPlatform,
hasTouch: plarformInfo.hasTouch,
isCordova: platformInfo.isCordova,
devicePlatform: platformInfo.devicePlatform,
navigatorPlatform: platformInfo.navigatorPlatform,
hasTouch: platformInfo.hasTouch,
supportedCompressionMethods:
platformInfo.supportedCompressionMethods,
})
);
}
@@ -461,11 +466,24 @@ namespace gdjs {
logger.error('No lobby received');
return;
}
handleLobbyUpdatedEvent(runtimeScene, lobby, positionInLobby);
handleLobbyUpdatedEvent({
runtimeScene,
updatedLobby: lobby,
positionInLobby,
});
break;
}
case 'gameCountdownStarted': {
handleGameCountdownStartedEvent(runtimeScene);
const messageData = messageContent.data;
const compressionMethod = messageData.compressionMethod || 'none';
const secondsToStart =
messageData.secondsToStart ||
DEFAULT_COUNTDOWN_SECONDS_TO_START;
handleGameCountdownStartedEvent({
runtimeScene,
compressionMethod,
secondsToStart,
});
break;
}
case 'gameStarted': {
@@ -474,7 +492,7 @@ namespace gdjs {
messageData.heartbeatInterval ||
DEFAULT_LOBBY_HEARTBEAT_INTERVAL;
handleGameStartedEvent(runtimeScene, heartbeatInterval);
handleGameStartedEvent({ runtimeScene, heartbeatInterval });
break;
}
case 'peerId': {
@@ -489,7 +507,7 @@ namespace gdjs {
return;
}
handlePeerIdEvent(peerId);
handlePeerIdEvent({ peerId });
break;
}
}
@@ -562,7 +580,7 @@ namespace gdjs {
// When the connectionId is received, initialise PeerJS so players can connect to each others afterwards.
if (validIceServers.length) {
for (const server of validIceServers) {
gdjs.evtTools.p2p.useCustomICECandidate(
gdjs.multiplayerPeerJsHelper.useCustomICECandidate(
server.urls,
server.username,
server.credential
@@ -570,7 +588,7 @@ namespace gdjs {
}
}
if (brokerServerConfig) {
gdjs.evtTools.p2p.useCustomBrokerServer(
gdjs.multiplayerPeerJsHelper.useCustomBrokerServer(
brokerServerConfig.hostname,
brokerServerConfig.port,
brokerServerConfig.path,
@@ -578,7 +596,7 @@ namespace gdjs {
brokerServerConfig.secure
);
} else {
gdjs.evtTools.p2p.useDefaultBrokerServer();
gdjs.multiplayerPeerJsHelper.useDefaultBrokerServer();
}
_connectionId = connectionId;
@@ -625,11 +643,15 @@ namespace gdjs {
_websocket = null;
};
const handleLobbyUpdatedEvent = function (
runtimeScene: gdjs.RuntimeScene,
const handleLobbyUpdatedEvent = function ({
runtimeScene,
updatedLobby,
positionInLobby: number
) {
positionInLobby,
}: {
runtimeScene: gdjs.RuntimeScene;
updatedLobby: Lobby;
positionInLobby: number;
}) {
// Update the object representing the lobby in the extension.
_lobby = updatedLobby;
@@ -663,9 +685,17 @@ namespace gdjs {
);
};
const handleGameCountdownStartedEvent = function (
runtimeScene: gdjs.RuntimeScene
) {
const handleGameCountdownStartedEvent = function ({
runtimeScene,
compressionMethod,
secondsToStart,
}: {
runtimeScene: gdjs.RuntimeScene;
compressionMethod: gdjs.multiplayerPeerJsHelper.CompressionMethod;
secondsToStart: number;
}) {
gdjs.multiplayerPeerJsHelper.setCompressionMethod(compressionMethod);
// When the countdown starts, if we are player number 1, then send the peerId to others so they can connect via P2P.
if (getCurrentPlayerNumber() === 1) {
sendPeerId();
@@ -684,6 +714,7 @@ namespace gdjs {
lobbiesIframe.contentWindow.postMessage(
{
id: 'gameCountdownStarted',
secondsToStart,
},
'*' // We could restrict to GDevelop games platform but it's not necessary as the message is not sensitive, and it allows easy debugging.
);
@@ -698,14 +729,17 @@ namespace gdjs {
* When the game receives the information that the game has started, close the
* lobbies window, focus on the game, and set the flag to true.
*/
const handleGameStartedEvent = function (
runtimeScene: gdjs.RuntimeScene,
heartbeatInterval: number
) {
const handleGameStartedEvent = function ({
runtimeScene,
heartbeatInterval,
}: {
runtimeScene: gdjs.RuntimeScene;
heartbeatInterval: number;
}) {
// It is possible the connection to other players didn't work.
// If that's the case, show an error message and leave the lobby.
// If we are the host, still start the game, as this allows a player to test the game alone.
const allConnectedPeers = gdjs.evtTools.p2p.getAllPeers();
const allConnectedPeers = gdjs.multiplayerPeerJsHelper.getAllPeers();
if (!isPlayerHost() && allConnectedPeers.length === 0) {
gdjs.multiplayerComponents.displayConnectionErrorNotification(
runtimeScene
@@ -775,7 +809,7 @@ namespace gdjs {
}
// Disconnect from any P2P connections.
gdjs.evtTools.p2p.disconnectFromAllPeers();
gdjs.multiplayerPeerJsHelper.disconnectFromAllPeers();
// Clear the expected acknowledgments, as the game is ending.
gdjs.multiplayerMessageManager.clearExpectedMessageAcknowledgements();
@@ -785,9 +819,9 @@ namespace gdjs {
* When the game receives the information of the peerId, then
* the player can connect to the peer.
*/
const handlePeerIdEvent = function (peerId: string) {
const handlePeerIdEvent = function ({ peerId }: { peerId: string }) {
// When a peerId is received, trigger a P2P connection with the peer.
const currentPeerId = gdjs.evtTools.p2p.getCurrentId();
const currentPeerId = gdjs.multiplayerPeerJsHelper.getCurrentId();
if (!currentPeerId) {
logger.error(
'No peerId found, the player does not seem connected to the broker server.'
@@ -800,7 +834,7 @@ namespace gdjs {
return;
}
gdjs.evtTools.p2p.connect(peerId);
gdjs.multiplayerPeerJsHelper.connect(peerId);
};
/**
@@ -862,6 +896,8 @@ namespace gdjs {
// Consider the game is ended, so that we don't listen to other players disconnecting.
_isLobbyGameRunning = false;
logger.info('Ending the lobby game.');
// Inform the players that the game has ended.
gdjs.multiplayerMessageManager.sendEndGameMessage();
@@ -912,7 +948,7 @@ namespace gdjs {
return;
}
const peerId = gdjs.evtTools.p2p.getCurrentId();
const peerId = gdjs.multiplayerPeerJsHelper.getCurrentId();
if (!peerId) {
logger.error(
"No peerId found, the player doesn't seem connected to the broker server."
@@ -1064,7 +1100,7 @@ namespace gdjs {
return;
}
if (_isCheckingIfGameIsRegistered || _isWaitingForLoginCallback) {
if (_isCheckingIfGameIsRegistered || _isWaitingForLogin) {
// The action is called multiple times, let's prevent that.
return;
}
@@ -1089,13 +1125,13 @@ namespace gdjs {
const playerId = gdjs.playerAuthentication.getUserId();
const playerToken = gdjs.playerAuthentication.getUserToken();
if (!playerId || !playerToken) {
_isWaitingForLoginCallback = true;
_isWaitingForLogin = true;
const {
status,
} = await gdjs.playerAuthentication.openAuthenticationWindow(
runtimeScene
).promise;
_isWaitingForLoginCallback = false;
_isWaitingForLogin = false;
if (status === 'logged') {
openLobbiesWindow(runtimeScene);
@@ -1207,5 +1243,15 @@ namespace gdjs {
const gameCanvas = runtimeScene.getGame().getRenderer().getCanvas();
if (gameCanvas) gameCanvas.focus();
};
/**
* Action to allow the player to leave the lobby in-game.
*/
export const leaveGameLobby = async (runtimeScene: gdjs.RuntimeScene) => {
// Handle the case where the game has not started yet, so the player is in the lobby.
handleLobbyLeaveEvent();
// Handle the case where the game has started, so the player is in the game and connected to other players.
handleLobbyGameEnded();
};
}
}

10
Extensions/Multiplayer/peer.js vendored Normal file

File diff suppressed because one or more lines are too long

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