mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
315 Commits
v5.4.209
...
fix-loader
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c6b7b90694 | ||
![]() |
a1ae2c08fb | ||
![]() |
558d3a869c | ||
![]() |
c22f8afaf1 | ||
![]() |
7ece6c6759 | ||
![]() |
f1ac388c46 | ||
![]() |
8a0045b3b0 | ||
![]() |
4bcac31489 | ||
![]() |
ff1086ce3b | ||
![]() |
e5d77da357 | ||
![]() |
536b0d5c38 | ||
![]() |
ada7dba959 | ||
![]() |
1b0c088f71 | ||
![]() |
b9b09c1fef | ||
![]() |
066c8cd387 | ||
![]() |
a06ef20011 | ||
![]() |
2052db6a39 | ||
![]() |
35fd7e972b | ||
![]() |
d110e83f6f | ||
![]() |
13bdfa4379 | ||
![]() |
689bc014f3 | ||
![]() |
a4f7aa6c43 | ||
![]() |
39690d6a02 | ||
![]() |
3260b285af | ||
![]() |
8743f70aaf | ||
![]() |
eae75bdc72 | ||
![]() |
825cff7ba3 | ||
![]() |
aa12248d86 | ||
![]() |
d0f3abc38d | ||
![]() |
e111706a27 | ||
![]() |
e4f3db71c5 | ||
![]() |
08a7949056 | ||
![]() |
1912916778 | ||
![]() |
59685bc4c4 | ||
![]() |
717948c558 | ||
![]() |
a81c45f91a | ||
![]() |
76eaa747c9 | ||
![]() |
26c95d1745 | ||
![]() |
e0c72fd113 | ||
![]() |
2a6e98c27f | ||
![]() |
5f01ce8701 | ||
![]() |
6ed0e8e4cc | ||
![]() |
fbea483609 | ||
![]() |
90004e3f83 | ||
![]() |
e6343dfe18 | ||
![]() |
ac6b64ba9b | ||
![]() |
44b18cb111 | ||
![]() |
c5fc7e08f5 | ||
![]() |
9eada905f9 | ||
![]() |
13aab9a8e8 | ||
![]() |
dda85cf630 | ||
![]() |
0f81e4c088 | ||
![]() |
5419493349 | ||
![]() |
272766c705 | ||
![]() |
a06138b31e | ||
![]() |
74a7ba5a09 | ||
![]() |
3914d0377f | ||
![]() |
092b29fa0e | ||
![]() |
16762960dc | ||
![]() |
33101ead64 | ||
![]() |
de73d617b0 | ||
![]() |
446b0db05f | ||
![]() |
66ab7abab7 | ||
![]() |
a80b540f06 | ||
![]() |
38761aeec1 | ||
![]() |
602dc9d791 | ||
![]() |
162a70316a | ||
![]() |
10e8094375 | ||
![]() |
82af8dd7f3 | ||
![]() |
8cf739aa78 | ||
![]() |
f3f3d24706 | ||
![]() |
83f80b2350 | ||
![]() |
1172326ae0 | ||
![]() |
aed09d86b3 | ||
![]() |
c2d03050b8 | ||
![]() |
2e941c5afc | ||
![]() |
a3f80f2607 | ||
![]() |
3497eb2945 | ||
![]() |
b9a1f50d13 | ||
![]() |
52d239b60c | ||
![]() |
c549e277a7 | ||
![]() |
afed5d57f7 | ||
![]() |
a3f7176c42 | ||
![]() |
223268554b | ||
![]() |
43ef037a07 | ||
![]() |
20d2e06fc6 | ||
![]() |
9f795c405a | ||
![]() |
0155344ec3 | ||
![]() |
71d6d6a165 | ||
![]() |
edd14b5f8b | ||
![]() |
77d60b699b | ||
![]() |
5bc80537b7 | ||
![]() |
f93b850382 | ||
![]() |
da7cae08a1 | ||
![]() |
0ae68877b7 | ||
![]() |
32c4e040e0 | ||
![]() |
74034a0ac1 | ||
![]() |
1b41225822 | ||
![]() |
c620ed75b3 | ||
![]() |
edc577067b | ||
![]() |
e00a85909d | ||
![]() |
70e6fc7f7f | ||
![]() |
b9a899f82e | ||
![]() |
c38d14ca83 | ||
![]() |
e6b6406a95 | ||
![]() |
ff7c6de660 | ||
![]() |
8d78ec6070 | ||
![]() |
3c2876e08d | ||
![]() |
a68bac6667 | ||
![]() |
53eafe098c | ||
![]() |
ab519d41a1 | ||
![]() |
5ea03b83f0 | ||
![]() |
f2d4778459 | ||
![]() |
56662fb9b5 | ||
![]() |
0788de3d87 | ||
![]() |
6b7bc361a7 | ||
![]() |
32a6e188e7 | ||
![]() |
00f67ca7c7 | ||
![]() |
bb5291ac6f | ||
![]() |
a2ea751007 | ||
![]() |
1a4270195b | ||
![]() |
3df42cce3e | ||
![]() |
b8de302f7e | ||
![]() |
6a2bc6109c | ||
![]() |
0383f8a7e1 | ||
![]() |
bde7e1896d | ||
![]() |
32d855992e | ||
![]() |
d54c1e2f38 | ||
![]() |
f09a1dd5b2 | ||
![]() |
f4e3f2449a | ||
![]() |
a6b2cba281 | ||
![]() |
54237114d9 | ||
![]() |
3c5bcf2762 | ||
![]() |
d66ea06a4c | ||
![]() |
228479c81b | ||
![]() |
1e55c359d8 | ||
![]() |
451d525b36 | ||
![]() |
c755946d42 | ||
![]() |
7a6b6fbf7f | ||
![]() |
730c8283e5 | ||
![]() |
7ea250706c | ||
![]() |
db7a108354 | ||
![]() |
2e15d68bce | ||
![]() |
f6c9e1408c | ||
![]() |
0b3d4d048a | ||
![]() |
5d625dd497 | ||
![]() |
079eca829a | ||
![]() |
35b5f92c59 | ||
![]() |
70eb95b132 | ||
![]() |
7c7ee8b7fc | ||
![]() |
3556dd2e3c | ||
![]() |
f74f77f66a | ||
![]() |
712eb4b647 | ||
![]() |
c4474c766d | ||
![]() |
ad17a21973 | ||
![]() |
5001411ccb | ||
![]() |
05939f5c3e | ||
![]() |
91978d4c6e | ||
![]() |
d6433d89f0 | ||
![]() |
e652ab9f5a | ||
![]() |
e7decc7b92 | ||
![]() |
33dcc04112 | ||
![]() |
58ba2668c2 | ||
![]() |
b34e802dcb | ||
![]() |
31dac9cc93 | ||
![]() |
ab97258832 | ||
![]() |
2ece223737 | ||
![]() |
8342873b6e | ||
![]() |
0a85fd3814 | ||
![]() |
fe15b6d30b | ||
![]() |
f3c3559518 | ||
![]() |
a403b1343b | ||
![]() |
83dba6c21e | ||
![]() |
7a4aea6557 | ||
![]() |
82a6abacb4 | ||
![]() |
f60613cc64 | ||
![]() |
274aedb3d9 | ||
![]() |
efb31c3caf | ||
![]() |
6781c0fd6e | ||
![]() |
e9781133e1 | ||
![]() |
8972e0e3a6 | ||
![]() |
4c76a5979b | ||
![]() |
484a0daec4 | ||
![]() |
de432c1bf2 | ||
![]() |
8c7dcc1c23 | ||
![]() |
39648af248 | ||
![]() |
5c7bbf5293 | ||
![]() |
9d97b9d0eb | ||
![]() |
b39b12864f | ||
![]() |
2c3dbbbbde | ||
![]() |
72cc60bae9 | ||
![]() |
c03e94849b | ||
![]() |
80daaf5e5b | ||
![]() |
cb457cfd04 | ||
![]() |
0a55aa631b | ||
![]() |
8e104f9ae4 | ||
![]() |
a90b9a27e9 | ||
![]() |
6321e82f63 | ||
![]() |
05fc63ab1b | ||
![]() |
85a6a21934 | ||
![]() |
a9741e7b42 | ||
![]() |
23afe7b71c | ||
![]() |
85757e6d98 | ||
![]() |
524ca4dbb3 | ||
![]() |
55cf710ef5 | ||
![]() |
eee7e7f04c | ||
![]() |
ecd984e08b | ||
![]() |
d0a7fbbd02 | ||
![]() |
2a2c930b74 | ||
![]() |
f6cb203029 | ||
![]() |
fe743bbe57 | ||
![]() |
78c31408d4 | ||
![]() |
75a038344a | ||
![]() |
f0567b674c | ||
![]() |
9b85f35856 | ||
![]() |
f4568febf2 | ||
![]() |
de7f60b693 | ||
![]() |
3a595b200e | ||
![]() |
431b5929e8 | ||
![]() |
ec2e82cee5 | ||
![]() |
76517f1a2a | ||
![]() |
43f5bd1c0e | ||
![]() |
7198a22ae2 | ||
![]() |
46c52905f6 | ||
![]() |
40954bf497 | ||
![]() |
02c06ac6e7 | ||
![]() |
1fa3f59a77 | ||
![]() |
cc371273ce | ||
![]() |
364ec2ecfb | ||
![]() |
0d36a27b87 | ||
![]() |
6d597a430b | ||
![]() |
27b71b08e5 | ||
![]() |
82158f7073 | ||
![]() |
8ba352d4ba | ||
![]() |
6cda5d08be | ||
![]() |
1a3a27b73b | ||
![]() |
96d912a6f2 | ||
![]() |
ed3acd5f0d | ||
![]() |
3f269206d1 | ||
![]() |
76b5aefdbc | ||
![]() |
9ef7af803c | ||
![]() |
c77f9b9e0c | ||
![]() |
035ddb8a7a | ||
![]() |
e7dac1bafc | ||
![]() |
54f00e7c57 | ||
![]() |
0bf9dae2b0 | ||
![]() |
428aac8ab0 | ||
![]() |
9391fc2841 | ||
![]() |
cea34337c6 | ||
![]() |
dc45f3dae5 | ||
![]() |
0ca26a865e | ||
![]() |
1bce13f326 | ||
![]() |
34f8f5750a | ||
![]() |
3b9a612094 | ||
![]() |
3a84ed7c89 | ||
![]() |
ef604fd442 | ||
![]() |
d88dc4772f | ||
![]() |
02d40a1d52 | ||
![]() |
35082825d4 | ||
![]() |
6a7c3daa8e | ||
![]() |
95af02bada | ||
![]() |
30516a903e | ||
![]() |
762f7ca19c | ||
![]() |
852bf78c81 | ||
![]() |
b0da0cee34 | ||
![]() |
73771f938b | ||
![]() |
b9dbe6dbb5 | ||
![]() |
0c2341c6e5 | ||
![]() |
e9b4de2ca9 | ||
![]() |
75a4114ce8 | ||
![]() |
20abb9b45a | ||
![]() |
56436fd44a | ||
![]() |
0dd5fc55c9 | ||
![]() |
93db4cb508 | ||
![]() |
f7888abf45 | ||
![]() |
c8144da704 | ||
![]() |
832e8cd593 | ||
![]() |
ef66a9f1a4 | ||
![]() |
5efbaa8c58 | ||
![]() |
ecbf38ccda | ||
![]() |
b3fcfc3f55 | ||
![]() |
a515836add | ||
![]() |
a7c81b47b2 | ||
![]() |
0f22e462ad | ||
![]() |
e6e4d9048f | ||
![]() |
12f5f95d0c | ||
![]() |
c52168a967 | ||
![]() |
1e33a13cc5 | ||
![]() |
505debd60c | ||
![]() |
e3b7109154 | ||
![]() |
9e25899d3e | ||
![]() |
87cb8f0d47 | ||
![]() |
481c6da992 | ||
![]() |
7cbebbb82f | ||
![]() |
fcf668788b | ||
![]() |
0cc844a77f | ||
![]() |
a234d9bd35 | ||
![]() |
465a6ce2ab | ||
![]() |
7e2e19eb33 | ||
![]() |
95101763f7 | ||
![]() |
d4bd5fc671 | ||
![]() |
c7fcf48ba5 | ||
![]() |
8926d4406f | ||
![]() |
9ed2173038 | ||
![]() |
2fc3bc337f | ||
![]() |
0b7cac79ef | ||
![]() |
8721c0099e | ||
![]() |
4453eee3b9 | ||
![]() |
0215ab7dbb | ||
![]() |
87f6d5b99f | ||
![]() |
a440b16f84 | ||
![]() |
f3822ba0df | ||
![]() |
6c5813affd | ||
![]() |
be4fe62bb6 | ||
![]() |
0a29999894 |
@@ -176,6 +176,7 @@ jobs:
|
||||
|
||||
# Build the WebAssembly library only (so that it's cached on a S3 and easy to re-use).
|
||||
build-gdevelop_js-wasm-only:
|
||||
resource_class: medium+ # Compilation time decrease linearly with the number of CPUs, but not linking (so "large" does not speedup total build time).
|
||||
docker:
|
||||
- image: cimg/node:16.13
|
||||
|
||||
@@ -232,10 +233,83 @@ jobs:
|
||||
name: Deploy to S3 (latest)
|
||||
command: aws s3 sync Binaries/embuild/GDevelop.js s3://gdevelop-gdevelop.js/$(git rev-parse --abbrev-ref HEAD)/latest/
|
||||
|
||||
# Build the WebAssembly library with clang-tidy and memory sanitizers.
|
||||
build-gdevelop_js-debug-sanitizers-and-extra-checks:
|
||||
resource_class: xlarge # Total time decrease linearly with the number of CPUs.
|
||||
docker:
|
||||
- image: cimg/node:16.13
|
||||
|
||||
working_directory: ~/GDevelop
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
- aws-cli/setup
|
||||
|
||||
# System dependencies (for Emscripten)
|
||||
- run:
|
||||
name: Install dependencies for Emscripten
|
||||
command: sudo apt-get update && sudo apt install cmake
|
||||
|
||||
- run:
|
||||
name: Install dependencies for clang-tidy v19
|
||||
command: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 19 && sudo apt install clang-tidy-19
|
||||
|
||||
- run:
|
||||
name: Install Python3 dependencies for Emscripten
|
||||
command: sudo apt install python-is-python3 python3-distutils -y
|
||||
|
||||
- run:
|
||||
name: Install Emscripten (for GDevelop.js)
|
||||
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 3.1.21 && ./emsdk activate 3.1.21 && cd ..
|
||||
|
||||
# GDevelop.js dependencies
|
||||
- restore_cache:
|
||||
keys:
|
||||
- gdevelop.js-linux-nodejs-dependencies-{{ checksum "GDevelop.js/package-lock.json" }}
|
||||
# fallback to using the latest cache if no exact match is found
|
||||
- gdevelop.js-linux-nodejs-dependencies-
|
||||
|
||||
- run:
|
||||
name: Install GDevelop.js dependencies and build it
|
||||
command: cd GDevelop.js && npm install && cd ..
|
||||
|
||||
# Build GDevelop.js
|
||||
- run:
|
||||
name: Build GDevelop.js ('debug-sanitizers' variant)
|
||||
command: cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build -- --variant=debug-sanitizers
|
||||
|
||||
- run:
|
||||
name: Run clang-tidy
|
||||
command: cd GDevelop.js && npm run lint
|
||||
|
||||
- run:
|
||||
name: Run tests
|
||||
command: cd GDevelop.js && npm run test -- --maxWorkers=4
|
||||
|
||||
# Upload artifacts (CircleCI)
|
||||
- store_artifacts:
|
||||
path: Binaries/embuild/GDevelop.js
|
||||
|
||||
# Upload artifacts (AWS)
|
||||
- run:
|
||||
name: Deploy to S3 (specific commit)
|
||||
command: aws s3 sync Binaries/embuild/GDevelop.js s3://gdevelop-gdevelop.js/$(git rev-parse --abbrev-ref HEAD)/variant/debug-sanitizers/commit/$(git rev-parse HEAD)/
|
||||
|
||||
workflows:
|
||||
builds:
|
||||
gdevelop_js-wasm:
|
||||
jobs:
|
||||
- build-gdevelop_js-wasm-only
|
||||
gdevelop_js-wasm-extra-checks:
|
||||
jobs:
|
||||
- build-gdevelop_js-debug-sanitizers-and-extra-checks:
|
||||
# Extra checks are resource intensive so don't all run them.
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /experimental-build.*/
|
||||
builds:
|
||||
jobs:
|
||||
- build-macos:
|
||||
filters:
|
||||
branches:
|
||||
|
4
.clang-tidy
Normal file
4
.clang-tidy
Normal file
@@ -0,0 +1,4 @@
|
||||
Checks: 'clang-diagnostic-*,clang-analyzer-*,cppcoreguidelines-*,-cppcoreguidelines-explicit-virtual-functions,-cppcoreguidelines-avoid-const-or-ref-data-members,-cppcoreguidelines-special-member-functions,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-non-private-member-variables-in-classes,-cppcoreguidelines-owning-memory,-cppcoreguidelines-virtual-class-destructor,-clang-analyzer-optin.performance.Padding,-cppcoreguidelines-narrowing-conversions'
|
||||
WarningsAsErrors: 'cppcoreguidelines-pro-type-member-init, clang-analyzer-optin.cplusplus.UninitializedObject'
|
||||
HeaderFilterRegex: '.*'
|
||||
FormatStyle: none
|
22
.github/workflows/gdcore-tools-hook.yml
vendored
Normal file
22
.github/workflows/gdcore-tools-hook.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
# This worflow notifies arthuro555's gdcore-tools repository when a new release is published.
|
||||
#
|
||||
# This is used to allow gdcore-tools, a library to use GDCore outside of GDevelop,
|
||||
# to attempt to automatically build, test, and publish a release for the new
|
||||
# GDevelop version.
|
||||
name: Trigger gdcore-tools pipeline
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
dispatch-event:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Repository Dispatch
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
token: ${{ secrets.GDCORE_TOOLS_PAT }}
|
||||
repository: arthuro555/gdcore-tools
|
||||
event-type: gdevelop-release
|
||||
client-payload: '{"release": ${{ toJson(github.event.release) }}}'
|
2
.vscode/GDevelopExtensions.code-snippets
vendored
2
.vscode/GDevelopExtensions.code-snippets
vendored
@@ -107,7 +107,7 @@
|
||||
"description": "Define a parameter in a GDevelop extension definition.",
|
||||
"prefix": "gdparam",
|
||||
"body": [
|
||||
".addParameter('${1|string,expression,object,behavior,yesorno,stringWithSelector,scenevar,globalvar,objectvar,objectList,objectListWithoutPicking,color,key,sceneName,file,layer,relationalOperator,operator,trueorfalse,musicfile,soundfile,police,mouse,passwordjoyaxis,camera,objectPtr,forceMultiplier|}', '${2:Parameter description}', '${3:Optional parameter data}', /*parameterIsOptional=*/${4|false,true|})"
|
||||
".addParameter('${1|string,expression,object,behavior,yesorno,stringWithSelector,scenevar,globalvar,objectvar,objectList,objectListWithoutPicking,color,key,sceneName,file,layer,relationalOperator,operator,trueorfalse,musicfile,soundfile,mouse,passwordjoyaxis,camera,objectPtr,forceMultiplier|}', '${2:Parameter description}', '${3:Optional parameter data}', /*parameterIsOptional=*/${4|false,true|})"
|
||||
]
|
||||
},
|
||||
"Add code only parameter": {
|
||||
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -114,7 +114,8 @@
|
||||
"__bits": "cpp",
|
||||
"__verbose_abort": "cpp",
|
||||
"variant": "cpp",
|
||||
"charconv": "cpp"
|
||||
"charconv": "cpp",
|
||||
"execution": "cpp"
|
||||
},
|
||||
"files.exclude": {
|
||||
"Binaries/*build*": true,
|
||||
|
@@ -60,7 +60,7 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND NOT WIN32 AND CMAKE_COMPILER_IS_
|
||||
endif()
|
||||
|
||||
#Activate C++11
|
||||
set(CMAKE_CXX_STANDARD 11) # Upgrading to C++17 would need to remove usage of bind2nd (should be easy).
|
||||
set(CMAKE_CXX_STANDARD 11) # Upgrading to C++17 should be tried.
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Mark some warnings as errors
|
||||
@@ -69,12 +69,18 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
# uninitialized variables or other hard to debug bugs.
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wuninitialized
|
||||
-Wconditional-uninitialized
|
||||
-Wno-unknown-warning-option
|
||||
-Wno-reorder-ctor
|
||||
-Wno-reorder
|
||||
-Wno-unused-parameter
|
||||
-Wno-pessimizing-move
|
||||
-Wno-unused-variable
|
||||
-Wno-unused-variable # Not a good style, but not a risk
|
||||
-Wno-unused-private-field
|
||||
-Wno-ignored-qualifiers # Not a risk
|
||||
-Wno-sign-compare # Not a big risk
|
||||
|
||||
# Make as much warnings considered as errors as possible (only one for now).
|
||||
-Werror=return-stack-address
|
||||
|
@@ -72,8 +72,6 @@ class GD_CORE_API WhileEvent : public gd::BaseEvent {
|
||||
///< de/activate infinite loop warning when the
|
||||
///< user create the event
|
||||
|
||||
mutable unsigned int whileConditionsHeight;
|
||||
|
||||
int GetConditionsHeight() const;
|
||||
int GetActionsHeight() const;
|
||||
int GetWhileConditionsHeight() const;
|
||||
|
@@ -14,10 +14,10 @@
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* \brief
|
||||
*/
|
||||
class GD_CORE_API ProjectDiagnostic {
|
||||
public:
|
||||
public:
|
||||
enum ErrorType {
|
||||
UndeclaredVariable,
|
||||
MissingBehavior,
|
||||
@@ -25,12 +25,17 @@ public:
|
||||
MismatchedObjectType,
|
||||
};
|
||||
|
||||
ProjectDiagnostic(ErrorType type_, const gd::String &message_,
|
||||
ProjectDiagnostic(ErrorType type_,
|
||||
const gd::String &message_,
|
||||
const gd::String &actualValue_,
|
||||
const gd::String &expectedValue_, const gd::String &objectName_ = "")
|
||||
: type(type_), message(message_), actualValue(actualValue_), expectedValue(expectedValue_),
|
||||
objectName(objectName_){};
|
||||
virtual ~ProjectDiagnostic(){};
|
||||
const gd::String &expectedValue_,
|
||||
const gd::String &objectName_ = "")
|
||||
: type(type_),
|
||||
message(message_),
|
||||
actualValue(actualValue_),
|
||||
expectedValue(expectedValue_),
|
||||
objectName(objectName_) {};
|
||||
virtual ~ProjectDiagnostic() {};
|
||||
|
||||
ErrorType GetType() const { return type; };
|
||||
const gd::String &GetMessage() const { return message; }
|
||||
@@ -38,7 +43,7 @@ public:
|
||||
const gd::String &GetActualValue() const { return actualValue; }
|
||||
const gd::String &GetExpectedValue() const { return expectedValue; }
|
||||
|
||||
private:
|
||||
private:
|
||||
ErrorType type;
|
||||
gd::String message;
|
||||
gd::String objectName;
|
||||
@@ -47,12 +52,12 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* \brief
|
||||
*/
|
||||
class GD_CORE_API DiagnosticReport {
|
||||
public:
|
||||
DiagnosticReport(){};
|
||||
virtual ~DiagnosticReport(){};
|
||||
public:
|
||||
DiagnosticReport() {};
|
||||
virtual ~DiagnosticReport() {};
|
||||
|
||||
void Add(const gd::ProjectDiagnostic &projectDiagnostic) {
|
||||
projectDiagnostics.push_back(
|
||||
@@ -67,32 +72,39 @@ public:
|
||||
|
||||
const gd::String &GetSceneName() const { return sceneName; }
|
||||
|
||||
void SetSceneName(const gd::String &sceneName_) {
|
||||
sceneName = sceneName_;
|
||||
void SetSceneName(const gd::String &sceneName_) { sceneName = sceneName_; }
|
||||
|
||||
void LogAllDiagnostics() {
|
||||
for (auto &diagnostic : projectDiagnostics) {
|
||||
std::cout << diagnostic->GetMessage()
|
||||
<< "(object: " << diagnostic->GetObjectName()
|
||||
<< ", actual value: " << diagnostic->GetActualValue()
|
||||
<< ", expected value: " << diagnostic->GetExpectedValue() << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
std::vector<std::unique_ptr<gd::ProjectDiagnostic>> projectDiagnostics;
|
||||
gd::String sceneName;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* \brief
|
||||
*/
|
||||
class GD_CORE_API WholeProjectDiagnosticReport {
|
||||
public:
|
||||
WholeProjectDiagnosticReport(){};
|
||||
virtual ~WholeProjectDiagnosticReport(){};
|
||||
public:
|
||||
WholeProjectDiagnosticReport() {};
|
||||
virtual ~WholeProjectDiagnosticReport() {};
|
||||
|
||||
const DiagnosticReport &Get(std::size_t index) const {
|
||||
return *diagnosticReports[index].get();
|
||||
};
|
||||
|
||||
void Clear() {
|
||||
diagnosticReports.clear();
|
||||
};
|
||||
void Clear() { diagnosticReports.clear(); };
|
||||
|
||||
DiagnosticReport& AddNewDiagnosticReportForScene(const gd::String &sceneName) {
|
||||
DiagnosticReport &AddNewDiagnosticReportForScene(
|
||||
const gd::String &sceneName) {
|
||||
auto diagnosticReport = gd::make_unique<gd::DiagnosticReport>();
|
||||
diagnosticReport->SetSceneName(sceneName);
|
||||
diagnosticReports.push_back(std::move(diagnosticReport));
|
||||
@@ -102,7 +114,7 @@ public:
|
||||
std::size_t Count() const { return diagnosticReports.size(); };
|
||||
|
||||
bool HasAnyIssue() {
|
||||
for (auto& diagnosticReport : diagnosticReports) {
|
||||
for (auto &diagnosticReport : diagnosticReports) {
|
||||
if (diagnosticReport->Count() > 0) {
|
||||
return true;
|
||||
}
|
||||
@@ -110,8 +122,8 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
std::vector<std::unique_ptr<gd::DiagnosticReport>> diagnosticReports;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
} // namespace gd
|
||||
|
@@ -77,11 +77,11 @@ gd::String EventsCodeGenerator::GenerateRelationalOperatorCall(
|
||||
|
||||
/**
|
||||
* @brief Generate a relational operation
|
||||
*
|
||||
*
|
||||
* @param relationalOperator the operator
|
||||
* @param lhs the left hand operand
|
||||
* @param rhs the right hand operand
|
||||
* @return gd::String
|
||||
* @return gd::String
|
||||
*/
|
||||
gd::String EventsCodeGenerator::GenerateRelationalOperation(
|
||||
const gd::String& relationalOperator,
|
||||
@@ -345,14 +345,14 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::UnknownObject, "",
|
||||
objectInParameter, "");
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Unknown object - skipped. */";
|
||||
} else if (!expectedObjectType.empty() &&
|
||||
actualObjectType != expectedObjectType) {
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::MismatchedObjectType, "",
|
||||
actualObjectType, expectedObjectType, objectInParameter);
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Mismatched object type - skipped. */";
|
||||
}
|
||||
}
|
||||
@@ -509,7 +509,7 @@ void EventsCodeGenerator::CheckBehaviorParameters(
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::MissingBehavior, "",
|
||||
actualBehaviorType, expectedBehaviorType, lastObjectName);
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -567,14 +567,14 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::UnknownObject, "",
|
||||
objectInParameter, "");
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Unknown object - skipped. */";
|
||||
} else if (!expectedObjectType.empty() &&
|
||||
actualObjectType != expectedObjectType) {
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::MismatchedObjectType, "",
|
||||
actualObjectType, expectedObjectType, objectInParameter);
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Mismatched object type - skipped. */";
|
||||
}
|
||||
}
|
||||
@@ -828,7 +828,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
metadata.GetType() == "spineResource" ||
|
||||
// Deprecated, old parameter names:
|
||||
metadata.GetType() == "password" || metadata.GetType() == "musicfile" ||
|
||||
metadata.GetType() == "soundfile" || metadata.GetType() == "police") {
|
||||
metadata.GetType() == "soundfile") {
|
||||
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
|
||||
} else if (metadata.GetType() == "mouse") {
|
||||
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
|
||||
@@ -1007,7 +1007,7 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(
|
||||
|
||||
output += "\n" + scopeBegin + "\n" + declarationsCode + "\n" +
|
||||
eventCoreCode + "\n" + scopeEnd + "\n";
|
||||
|
||||
|
||||
if (event.HasVariables()) {
|
||||
GetProjectScopedContainers().GetVariablesContainersList().Pop();
|
||||
}
|
||||
|
@@ -528,7 +528,7 @@ protected:
|
||||
parameter -> string
|
||||
* - operator : Used to update a value using a setter and a getter -> string
|
||||
* - key, mouse, objectvar, scenevar, globalvar, password, musicfile,
|
||||
soundfile, police -> string
|
||||
soundfile -> string
|
||||
* - trueorfalse, yesorno -> boolean ( See GenerateTrue/GenerateFalse ).
|
||||
*
|
||||
* <br><br>
|
||||
@@ -849,7 +849,7 @@ protected:
|
||||
instructionUniqueIds; ///< The unique ids generated for instructions.
|
||||
size_t eventsListNextUniqueId; ///< The next identifier to use for an events
|
||||
///< list function name.
|
||||
|
||||
|
||||
gd::DiagnosticReport* diagnosticReport;
|
||||
};
|
||||
|
||||
|
@@ -36,8 +36,8 @@ struct GD_CORE_API ExpressionParserLocation {
|
||||
|
||||
private:
|
||||
bool isValid;
|
||||
size_t startPosition;
|
||||
size_t endPosition;
|
||||
size_t startPosition = 0;
|
||||
size_t endPosition = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -1768,6 +1768,22 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("expression",
|
||||
_("Angle of tolerance, in degrees (0: minimum tolerance)"))
|
||||
.AddCodeOnlyParameter("conditionInverted", "")
|
||||
.SetHidden()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("IsTurnedTowardObject",
|
||||
_("An object is turned toward another"),
|
||||
_("Check if an object is turned toward another"),
|
||||
_("_PARAM0_ is turned toward _PARAM1_ ± _PARAM2_°"),
|
||||
_("Angle"),
|
||||
"res/conditions/estTourne24.png",
|
||||
"res/conditions/estTourne.png")
|
||||
.AddParameter("objectList", _("Name of the object"))
|
||||
.AddParameter("objectList", _("Name of the second object"))
|
||||
.AddParameter("expression",
|
||||
_("Angle of tolerance, in degrees (0: minimum tolerance)"))
|
||||
.AddCodeOnlyParameter("conditionInverted", "")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
|
@@ -338,6 +338,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0");
|
||||
|
||||
// Deprecated
|
||||
extension
|
||||
.AddCondition(
|
||||
"PopStartedTouch",
|
||||
@@ -354,6 +355,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.SetHidden();
|
||||
|
||||
// Deprecated
|
||||
extension
|
||||
.AddCondition(
|
||||
"PopEndedTouch",
|
||||
@@ -370,6 +372,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.SetHidden();
|
||||
|
||||
// Deprecated
|
||||
extension
|
||||
.AddCondition(
|
||||
"HasAnyTouchStarted",
|
||||
|
@@ -33,6 +33,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
"most elements of a game."),
|
||||
"CppPlatform/Extensions/spriteicon.png")
|
||||
.SetCategoryFullName(_("General"))
|
||||
.SetOpenFullEditorLabel(_("Edit animations"))
|
||||
.AddDefaultBehavior("EffectCapability::EffectBehavior")
|
||||
.AddDefaultBehavior("ResizableCapability::ResizableBehavior")
|
||||
.AddDefaultBehavior("ScalableCapability::ScalableBehavior")
|
||||
|
@@ -47,19 +47,11 @@ void SpriteObject::DoSerializeTo(gd::SerializerElement& element) const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> SpriteObject::GetProperties()
|
||||
const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties[_("Animate even if hidden or far from the screen")]
|
||||
.SetValue(updateIfNotVisible ? "true" : "false")
|
||||
.SetType("Boolean");
|
||||
properties["PLEASE_ALSO_SHOW_EDIT_BUTTON_THANKS"].SetValue("");
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
bool SpriteObject::UpdateProperty(const gd::String& name,
|
||||
const gd::String& value) {
|
||||
if (name == _("Animate even if hidden or far from the screen"))
|
||||
updateIfNotVisible = value == "1";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -37,8 +37,7 @@ BehaviorMetadata::BehaviorMetadata(
|
||||
className(className_),
|
||||
iconFilename(icon24x24),
|
||||
instance(instance_),
|
||||
sharedDatasInstance(sharedDatasInstance_),
|
||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {
|
||||
sharedDatasInstance(sharedDatasInstance_) {
|
||||
SetFullName(gd::String(fullname_));
|
||||
SetDescription(gd::String(description_));
|
||||
SetDefaultName(gd::String(defaultName_));
|
||||
@@ -441,12 +440,18 @@ std::map<gd::String, gd::PropertyDescriptor> BehaviorMetadata::GetSharedProperti
|
||||
|
||||
const std::vector<gd::String>& BehaviorMetadata::GetRequiredBehaviorTypes() const {
|
||||
requiredBehaviors.clear();
|
||||
for (auto& property : Get().GetProperties()) {
|
||||
if (!instance) {
|
||||
return requiredBehaviors;
|
||||
}
|
||||
for (auto& property : instance->GetProperties()) {
|
||||
const String& propertyName = property.first;
|
||||
const gd::PropertyDescriptor& propertyDescriptor = property.second;
|
||||
|
||||
if (propertyDescriptor.GetType() == "Behavior") {
|
||||
requiredBehaviors.push_back(propertyDescriptor.GetExtraInfo()[0]);
|
||||
const auto& extraInfos = propertyDescriptor.GetExtraInfo();
|
||||
if (extraInfos.size() > 0) {
|
||||
requiredBehaviors.push_back(extraInfos[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return requiredBehaviors;
|
||||
|
@@ -307,6 +307,15 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
|
||||
return *this;
|
||||
}
|
||||
|
||||
BehaviorMetadata &SetOpenFullEditorLabel(const gd::String& label) {
|
||||
openFullEditorLabel = label;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const gd::String& GetOpenFullEditorLabel() const {
|
||||
return openFullEditorLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the associated gd::Behavior, handling behavior contents.
|
||||
*
|
||||
@@ -384,7 +393,8 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
|
||||
mutable std::vector<gd::String> requiredBehaviors;
|
||||
bool isPrivate = false;
|
||||
bool isHidden = false;
|
||||
QuickCustomization::Visibility quickCustomizationVisibility;
|
||||
gd::String openFullEditorLabel;
|
||||
QuickCustomization::Visibility quickCustomizationVisibility = QuickCustomization::Visibility::Default;
|
||||
|
||||
// TODO: Nitpicking: convert these to std::unique_ptr to clarify ownership.
|
||||
std::shared_ptr<gd::Behavior> instance;
|
||||
|
@@ -185,10 +185,10 @@ class GD_CORE_API EffectMetadata {
|
||||
gd::String fullname;
|
||||
gd::String description;
|
||||
std::vector<gd::String> includeFiles;
|
||||
bool isMarkedAsNotWorkingForObjects;
|
||||
bool isMarkedAsOnlyWorkingFor2D;
|
||||
bool isMarkedAsOnlyWorkingFor3D;
|
||||
bool isMarkedAsUnique;
|
||||
bool isMarkedAsNotWorkingForObjects = false;
|
||||
bool isMarkedAsOnlyWorkingFor2D = false;
|
||||
bool isMarkedAsOnlyWorkingFor3D = false;
|
||||
bool isMarkedAsUnique = false;
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
};
|
||||
|
||||
|
@@ -19,7 +19,8 @@ EventMetadata::EventMetadata(const gd::String &name_,
|
||||
: fullname(fullname_),
|
||||
description(description_),
|
||||
group(group_),
|
||||
instance(instance_) {
|
||||
instance(instance_),
|
||||
hasCustomCodeGenerator(false) {
|
||||
ClearCodeGenerationAndPreprocessing();
|
||||
if (instance) instance->SetType(name_);
|
||||
}
|
||||
|
@@ -83,7 +83,7 @@ class GD_CORE_API EventMetadata {
|
||||
gd::String group;
|
||||
|
||||
std::shared_ptr<gd::BaseEvent> instance;
|
||||
bool hasCustomCodeGenerator;
|
||||
bool hasCustomCodeGenerator = false;
|
||||
std::function<gd::String(gd::BaseEvent& event,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context)>
|
||||
|
@@ -288,8 +288,8 @@ class GD_CORE_API MetadataProvider {
|
||||
static EffectMetadata badEffectMetadata;
|
||||
static gd::InstructionMetadata badInstructionMetadata;
|
||||
static gd::ExpressionMetadata badExpressionMetadata;
|
||||
int useless; // Useless member to avoid emscripten "must have a positive
|
||||
// integer typeid pointer" runtime error.
|
||||
int useless = 0; // Useless member to avoid emscripten "must have a positive
|
||||
// integer typeid pointer" runtime error.
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -54,7 +54,7 @@ ObjectMetadata::ObjectMetadata(const gd::String& extensionNamespace_,
|
||||
[]() -> std::unique_ptr<gd::ObjectConfiguration> {
|
||||
gd::LogFatalError(
|
||||
"Error: Event-based objects don't have blueprint. "
|
||||
"This method should not never be called.");
|
||||
"This method should never be called.");
|
||||
return nullptr;
|
||||
}) {}
|
||||
|
||||
|
@@ -246,6 +246,11 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
|
||||
return *this;
|
||||
}
|
||||
|
||||
ObjectMetadata& ResetDefaultBehaviorsJustForTesting() {
|
||||
defaultBehaviorTypes.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const gd::String& GetName() const override { return name; }
|
||||
const gd::String& GetFullName() const override { return fullname; }
|
||||
const gd::String& GetCategoryFullName() const { return categoryFullName; }
|
||||
@@ -323,6 +328,15 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
|
||||
*/
|
||||
bool IsRenderedIn3D() const { return isRenderedIn3D; }
|
||||
|
||||
ObjectMetadata &SetOpenFullEditorLabel(const gd::String& label) {
|
||||
openFullEditorLabel = label;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const gd::String& GetOpenFullEditorLabel() const {
|
||||
return openFullEditorLabel;
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::InstructionMetadata> conditionsInfos;
|
||||
std::map<gd::String, gd::InstructionMetadata> actionsInfos;
|
||||
std::map<gd::String, gd::ExpressionMetadata> expressionsInfos;
|
||||
@@ -344,6 +358,7 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
|
||||
std::set<gd::String> defaultBehaviorTypes;
|
||||
bool hidden = false;
|
||||
bool isRenderedIn3D = false;
|
||||
gd::String openFullEditorLabel;
|
||||
|
||||
std::shared_ptr<gd::ObjectConfiguration>
|
||||
blueprintObject; ///< The "blueprint" object to be copied when a new
|
||||
|
@@ -6,6 +6,8 @@
|
||||
#include "ParameterMetadataTools.h"
|
||||
|
||||
#include "GDCore/Events/Expression.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/Project/ObjectsContainersList.h"
|
||||
@@ -13,8 +15,6 @@
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "InstructionMetadata.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
|
||||
namespace gd {
|
||||
const ParameterMetadata ParameterMetadataTools::badParameterMetadata;
|
||||
@@ -23,7 +23,10 @@ void ParameterMetadataTools::ParametersToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
const ParameterMetadataContainer& parameters,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
outputObjectsContainer.GetObjects().clear();
|
||||
// Keep track of all objects and their behaviors names, so we can remove
|
||||
// those who are in the container but not in the parameters anymore.
|
||||
std::set<gd::String> allObjectNames;
|
||||
std::map<gd::String, std::set<gd::String>> allObjectNonDefaultBehaviorNames;
|
||||
|
||||
gd::String lastObjectName;
|
||||
for (std::size_t i = 0; i < parameters.GetParametersCount(); ++i) {
|
||||
@@ -31,34 +34,97 @@ void ParameterMetadataTools::ParametersToObjectsContainer(
|
||||
if (parameter.GetName().empty()) continue;
|
||||
|
||||
if (gd::ParameterMetadata::IsObject(parameter.GetType())) {
|
||||
outputObjectsContainer.InsertNewObject(
|
||||
project,
|
||||
parameter.GetExtraInfo(),
|
||||
parameter.GetName(),
|
||||
outputObjectsContainer.GetObjectsCount());
|
||||
const gd::String& objectName = parameter.GetName();
|
||||
const gd::String& objectType = parameter.GetExtraInfo();
|
||||
allObjectNames.insert(objectName);
|
||||
|
||||
// Check if we can keep the existing object.
|
||||
if (outputObjectsContainer.HasObjectNamed(objectName)) {
|
||||
const gd::Object& object = outputObjectsContainer.GetObject(objectName);
|
||||
|
||||
if (object.GetType() != objectType) {
|
||||
// Object type has changed, remove it so it is re-created.
|
||||
outputObjectsContainer.RemoveObject(objectName);
|
||||
}
|
||||
}
|
||||
|
||||
if (outputObjectsContainer.HasObjectNamed(objectName)) {
|
||||
// Keep the existing object, ensure the default behaviors
|
||||
// are all present (and no more than required by the object type).
|
||||
// Non default behaviors coming from parameters will be added or removed later.
|
||||
project.EnsureObjectDefaultBehaviors(outputObjectsContainer.GetObject(objectName));
|
||||
} else {
|
||||
// Create a new object (and its default behaviors) if needed.
|
||||
outputObjectsContainer.InsertNewObject(
|
||||
project,
|
||||
objectType,
|
||||
objectName,
|
||||
outputObjectsContainer.GetObjectsCount());
|
||||
}
|
||||
|
||||
// Memorize the last object name. By convention, parameters that require
|
||||
// an object (mainly, "objectvar" and "behavior") should be placed after
|
||||
// the object in the list of parameters (if possible, just after).
|
||||
// Search "lastObjectName" in the codebase for other place where this
|
||||
// convention is enforced.
|
||||
lastObjectName = parameter.GetName();
|
||||
lastObjectName = objectName;
|
||||
} else if (gd::ParameterMetadata::IsBehavior(parameter.GetType())) {
|
||||
if (!lastObjectName.empty()) {
|
||||
if (outputObjectsContainer.HasObjectNamed(lastObjectName)) {
|
||||
const gd::Object& object =
|
||||
outputObjectsContainer.GetObject(lastObjectName);
|
||||
gd::String behaviorName = parameter.GetName();
|
||||
const gd::String& behaviorName = parameter.GetName();
|
||||
const gd::String& behaviorType = parameter.GetExtraInfo();
|
||||
|
||||
gd::Object& object = outputObjectsContainer.GetObject(lastObjectName);
|
||||
allObjectNonDefaultBehaviorNames[lastObjectName].insert(behaviorName);
|
||||
|
||||
// Check if we can keep the existing behavior.
|
||||
if (object.HasBehaviorNamed(behaviorName)) {
|
||||
if (object.GetBehavior(behaviorName).GetTypeName() !=
|
||||
behaviorType) {
|
||||
// Behavior type has changed, remove it so it is re-created.
|
||||
object.RemoveBehavior(behaviorName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!object.HasBehaviorNamed(behaviorName)) {
|
||||
outputObjectsContainer.GetObject(lastObjectName)
|
||||
.AddNewBehavior(
|
||||
project, parameter.GetExtraInfo(), behaviorName);
|
||||
object.AddNewBehavior(
|
||||
project, parameter.GetExtraInfo(), behaviorName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove objects that are not in the parameters anymore.
|
||||
std::set<gd::String> objectNamesInContainer =
|
||||
outputObjectsContainer.GetAllObjectNames();
|
||||
for (const auto& objectName : objectNamesInContainer) {
|
||||
if (allObjectNames.find(objectName) == allObjectNames.end()) {
|
||||
outputObjectsContainer.RemoveObject(objectName);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove behaviors of objects that are not in the parameters anymore.
|
||||
for (const auto& objectName : allObjectNames) {
|
||||
if (!outputObjectsContainer.HasObjectNamed(objectName)) {
|
||||
// Should not happen.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& object = outputObjectsContainer.GetObject(objectName);
|
||||
const auto& allBehaviorNames = allObjectNonDefaultBehaviorNames[objectName];
|
||||
for (const auto& behaviorName : object.GetAllBehaviorNames()) {
|
||||
if (object.GetBehavior(behaviorName).IsDefaultBehavior()) {
|
||||
// Default behaviors are already ensured to be all present
|
||||
// (and no more than required by the object type).
|
||||
continue;
|
||||
}
|
||||
|
||||
if (allBehaviorNames.find(behaviorName) == allBehaviorNames.end()) {
|
||||
object.RemoveBehavior(behaviorName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParameterMetadataTools::ForEachParameterMatchingSearch(
|
||||
|
@@ -53,27 +53,32 @@ const gd::String &ValueTypeMetadata::GetExpressionPrimitiveValueType(
|
||||
|
||||
const gd::String &
|
||||
ValueTypeMetadata::GetPrimitiveValueType(const gd::String ¶meterType) {
|
||||
if (parameterType == "variable" ||
|
||||
gd::ValueTypeMetadata::IsTypeExpression("variable", parameterType)) {
|
||||
return ValueTypeMetadata::variableType;
|
||||
if (parameterType == "number" ||
|
||||
gd::ValueTypeMetadata::IsTypeValue("number", parameterType)) {
|
||||
return ValueTypeMetadata::numberType;
|
||||
}
|
||||
if (parameterType == "boolean" || parameterType == "yesorno" ||
|
||||
parameterType == "trueorfalse") {
|
||||
return ValueTypeMetadata::booleanType;
|
||||
}
|
||||
// These 2 types are not strings from the code generator point of view,
|
||||
// but it is for event-based extensions.
|
||||
if (parameterType == "key" || parameterType == "mouse") {
|
||||
if (parameterType == "string" ||
|
||||
gd::ValueTypeMetadata::IsTypeValue("string", parameterType)) {
|
||||
return ValueTypeMetadata::stringType;
|
||||
}
|
||||
return GetExpressionPrimitiveValueType(parameterType);
|
||||
if (parameterType == "variable" ||
|
||||
gd::ValueTypeMetadata::IsTypeValue("variable", parameterType)) {
|
||||
return ValueTypeMetadata::variableType;
|
||||
}
|
||||
if (parameterType == "boolean" ||
|
||||
gd::ValueTypeMetadata::IsTypeValue("boolean", parameterType)) {
|
||||
return ValueTypeMetadata::booleanType;
|
||||
}
|
||||
return parameterType;
|
||||
}
|
||||
|
||||
const gd::String ValueTypeMetadata::numberValueType = "number";
|
||||
const gd::String ValueTypeMetadata::booleanValueType = "boolean";
|
||||
const gd::String ValueTypeMetadata::stringValueType = "string";
|
||||
const gd::String ValueTypeMetadata::colorValueType = "color";
|
||||
const gd::String ValueTypeMetadata::choiceValueType = "stringWithSelector";
|
||||
const gd::String ValueTypeMetadata::stringValueType = "string";
|
||||
const gd::String ValueTypeMetadata::behaviorValueType = "behavior";
|
||||
const gd::String ValueTypeMetadata::leaderboardIdValueType = "leaderboardId";
|
||||
|
||||
const gd::String &ValueTypeMetadata::ConvertPropertyTypeToValueType(
|
||||
const gd::String &propertyType) {
|
||||
@@ -85,6 +90,10 @@ const gd::String &ValueTypeMetadata::ConvertPropertyTypeToValueType(
|
||||
return colorValueType;
|
||||
} else if (propertyType == "Choice") {
|
||||
return choiceValueType;
|
||||
} else if (propertyType == "Behavior") {
|
||||
return behaviorValueType;
|
||||
} else if (propertyType == "LeaderboardId") {
|
||||
return leaderboardIdValueType;
|
||||
}
|
||||
// For "String" or default
|
||||
return stringValueType;
|
||||
|
@@ -111,21 +111,21 @@ class GD_CORE_API ValueTypeMetadata {
|
||||
* given type.
|
||||
*/
|
||||
bool IsNumber() const {
|
||||
return gd::ValueTypeMetadata::IsTypeExpression("number", name);
|
||||
return gd::ValueTypeMetadata::IsTypeValue("number", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type is a string.
|
||||
*/
|
||||
bool IsString() const {
|
||||
return gd::ValueTypeMetadata::IsTypeExpression("string", name);
|
||||
return gd::ValueTypeMetadata::IsTypeValue("string", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type is a boolean.
|
||||
*/
|
||||
bool IsBoolean() const {
|
||||
return gd::ValueTypeMetadata::IsTypeExpression("boolean", name);
|
||||
return gd::ValueTypeMetadata::IsTypeValue("boolean", name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,7 +135,17 @@ class GD_CORE_API ValueTypeMetadata {
|
||||
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
|
||||
*/
|
||||
bool IsVariable() const {
|
||||
return gd::ValueTypeMetadata::IsTypeExpression("variable", name);
|
||||
return gd::ValueTypeMetadata::IsVariable(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type of the parameter is a variable.
|
||||
* \note If you had a new type of parameter, also add it in the IDE (
|
||||
* see EventsFunctionParametersEditor, ParameterRenderingService
|
||||
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
|
||||
*/
|
||||
static bool IsVariable(const gd::String &type) {
|
||||
return gd::ValueTypeMetadata::GetPrimitiveValueType(type) == "variable";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,7 +185,9 @@ class GD_CORE_API ValueTypeMetadata {
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type is an expression of the given type.
|
||||
* \brief Return true if the type is an expression of the given type from the
|
||||
* caller point of view.
|
||||
*
|
||||
* \note If you are adding a new type of parameter, also add it in the IDE (
|
||||
* see EventsFunctionParametersEditor, ParameterRenderingService
|
||||
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
|
||||
@@ -186,6 +198,7 @@ class GD_CORE_API ValueTypeMetadata {
|
||||
return parameterType == "number" || parameterType == "expression" ||
|
||||
parameterType == "camera" || parameterType == "forceMultiplier";
|
||||
} else if (type == "string") {
|
||||
// "key" and "mouse" are not mapped her, see GetPrimitiveValueType.
|
||||
return parameterType == "string" || parameterType == "layer" ||
|
||||
parameterType == "color" || parameterType == "file" ||
|
||||
parameterType == "stringWithSelector" ||
|
||||
@@ -227,6 +240,26 @@ class GD_CORE_API ValueTypeMetadata {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type is a value of the given primitive type from
|
||||
* the function events point of view
|
||||
*/
|
||||
static bool IsTypeValue(const gd::String &type,
|
||||
const gd::String ¶meterType) {
|
||||
if (gd::ValueTypeMetadata::IsTypeExpression(type, parameterType)) {
|
||||
return true;
|
||||
}
|
||||
// These 2 parameter types are not strings from the outside of a function as
|
||||
// the generator add quote around a text, but from the events inside of the
|
||||
// function the parameter is a string.
|
||||
//
|
||||
// See EventsCodeGenerator::GenerateParameterCodes
|
||||
if (type == "string") {
|
||||
return parameterType == "key" || parameterType == "mouse";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the expression type from the parameter type.
|
||||
* Declinations of "number" and "string" types (like "forceMultiplier" or
|
||||
@@ -278,9 +311,11 @@ class GD_CORE_API ValueTypeMetadata {
|
||||
|
||||
static const gd::String numberValueType;
|
||||
static const gd::String booleanValueType;
|
||||
static const gd::String stringValueType;
|
||||
static const gd::String colorValueType;
|
||||
static const gd::String choiceValueType;
|
||||
static const gd::String stringValueType;
|
||||
static const gd::String behaviorValueType;
|
||||
static const gd::String leaderboardIdValueType;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -808,6 +808,24 @@ gd::String PlatformExtension::GetObjectFullType(const gd::String &extensionName,
|
||||
return extensionName + separator + objectName;
|
||||
}
|
||||
|
||||
gd::String PlatformExtension::GetExtensionFromFullObjectType(const gd::String& type) {
|
||||
const auto separatorIndex =
|
||||
type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
if (separatorIndex == std::string::npos) {
|
||||
return "";
|
||||
}
|
||||
return type.substr(0, separatorIndex);
|
||||
}
|
||||
|
||||
gd::String PlatformExtension::GetObjectNameFromFullObjectType(const gd::String& type) {
|
||||
const auto separatorIndex =
|
||||
type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
if (separatorIndex == std::string::npos) {
|
||||
return "";
|
||||
}
|
||||
return type.substr(separatorIndex + 2);
|
||||
}
|
||||
|
||||
PlatformExtension::PlatformExtension()
|
||||
: deprecated(false), category(_("General")) {}
|
||||
|
||||
|
@@ -40,8 +40,7 @@ class Object;
|
||||
class ObjectConfiguration;
|
||||
} // namespace gd
|
||||
|
||||
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()>
|
||||
CreateFunPtr;
|
||||
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()> CreateFunPtr;
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -51,25 +50,25 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API CompilationInfo {
|
||||
public:
|
||||
CompilationInfo() : informationCompleted(false){};
|
||||
virtual ~CompilationInfo(){};
|
||||
CompilationInfo() {};
|
||||
virtual ~CompilationInfo() {};
|
||||
|
||||
bool informationCompleted;
|
||||
bool informationCompleted = false;
|
||||
|
||||
bool runtimeOnly; ///< True if the extension was compiled for a runtime use
|
||||
///< only
|
||||
bool runtimeOnly = false; ///< True if the extension was compiled for a
|
||||
///< runtime use only
|
||||
|
||||
#if defined(__GNUC__)
|
||||
int gccMajorVersion;
|
||||
int gccMinorVersion;
|
||||
int gccPatchLevel;
|
||||
int gccMajorVersion = 0;
|
||||
int gccMinorVersion = 0;
|
||||
int gccPatchLevel = 0;
|
||||
#endif
|
||||
|
||||
int sfmlMajorVersion;
|
||||
int sfmlMinorVersion;
|
||||
int sfmlMajorVersion = 0;
|
||||
int sfmlMinorVersion = 0;
|
||||
|
||||
gd::String gdCoreVersion;
|
||||
int sizeOfpInt;
|
||||
int sizeOfpInt = 0;
|
||||
};
|
||||
|
||||
struct GD_CORE_API DuplicatedInstructionOptions {
|
||||
@@ -239,11 +238,12 @@ class GD_CORE_API PlatformExtension {
|
||||
* \param instance The "blueprint" object to be copied when a new object is
|
||||
asked for.
|
||||
*/
|
||||
gd::ObjectMetadata& AddObject(const gd::String& name_,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& icon_,
|
||||
std::shared_ptr<gd::ObjectConfiguration> instance);
|
||||
gd::ObjectMetadata& AddObject(
|
||||
const gd::String& name_,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& icon_,
|
||||
std::shared_ptr<gd::ObjectConfiguration> instance);
|
||||
|
||||
/**
|
||||
* \brief Declare a new events based object as being part of the extension.
|
||||
@@ -253,11 +253,10 @@ class GD_CORE_API PlatformExtension {
|
||||
* \param description The user friendly description of the object
|
||||
* \param icon The icon of the object.
|
||||
*/
|
||||
gd::ObjectMetadata& AddEventsBasedObject(
|
||||
const gd::String& name_,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& icon_);
|
||||
gd::ObjectMetadata& AddEventsBasedObject(const gd::String& name_,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& icon_);
|
||||
|
||||
/**
|
||||
* \brief Declare a new behavior as being part of the extension.
|
||||
@@ -420,8 +419,7 @@ class GD_CORE_API PlatformExtension {
|
||||
PlatformExtension& SetTags(const gd::String& csvTags) {
|
||||
tags.clear();
|
||||
tags = csvTags.Split(',');
|
||||
for (size_t i = 0; i < tags.size(); i++)
|
||||
{
|
||||
for (size_t i = 0; i < tags.size(); i++) {
|
||||
tags[i] = tags[i].Trim().LowerCase();
|
||||
}
|
||||
return *this;
|
||||
@@ -634,26 +632,30 @@ class GD_CORE_API PlatformExtension {
|
||||
*/
|
||||
static gd::String GetNamespaceSeparator() { return "::"; }
|
||||
|
||||
static gd::String GetEventsFunctionFullType(const gd::String &extensionName,
|
||||
const gd::String &functionName);
|
||||
static gd::String GetEventsFunctionFullType(const gd::String& extensionName,
|
||||
const gd::String& functionName);
|
||||
|
||||
static gd::String
|
||||
GetBehaviorEventsFunctionFullType(const gd::String &extensionName,
|
||||
const gd::String &behaviorName,
|
||||
const gd::String &functionName);
|
||||
static gd::String GetBehaviorEventsFunctionFullType(
|
||||
const gd::String& extensionName,
|
||||
const gd::String& behaviorName,
|
||||
const gd::String& functionName);
|
||||
|
||||
static gd::String GetBehaviorFullType(const gd::String &extensionName,
|
||||
const gd::String &behaviorName);
|
||||
static gd::String GetBehaviorFullType(const gd::String& extensionName,
|
||||
const gd::String& behaviorName);
|
||||
|
||||
static gd::String
|
||||
GetObjectEventsFunctionFullType(const gd::String &extensionName,
|
||||
const gd::String &objectName,
|
||||
const gd::String &functionName);
|
||||
static gd::String GetObjectEventsFunctionFullType(
|
||||
const gd::String& extensionName,
|
||||
const gd::String& objectName,
|
||||
const gd::String& functionName);
|
||||
|
||||
static gd::String GetObjectFullType(const gd::String &extensionName,
|
||||
const gd::String &objectName);
|
||||
static gd::String GetObjectFullType(const gd::String& extensionName,
|
||||
const gd::String& objectName);
|
||||
|
||||
private:
|
||||
static gd::String GetExtensionFromFullObjectType(const gd::String& type);
|
||||
|
||||
static gd::String GetObjectNameFromFullObjectType(const gd::String& type);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Set the namespace (the string all actions/conditions/expressions start
|
||||
* with).
|
||||
@@ -668,10 +670,10 @@ private:
|
||||
gd::String fullname; ///< Name displayed to users in the editor.
|
||||
gd::String informations; ///< Description displayed to users in the editor.
|
||||
gd::String category;
|
||||
gd::String author; ///< Author displayed to users in the editor.
|
||||
gd::String license; ///< License name displayed to users in the editor.
|
||||
bool deprecated; ///< true if the extension is deprecated and shouldn't be
|
||||
///< shown in IDE.
|
||||
gd::String author; ///< Author displayed to users in the editor.
|
||||
gd::String license; ///< License name displayed to users in the editor.
|
||||
bool deprecated; ///< true if the extension is deprecated and shouldn't be
|
||||
///< shown in IDE.
|
||||
gd::String helpPath; ///< The relative path to the help for this extension in
|
||||
///< the documentation.
|
||||
gd::String iconUrl; ///< The URL to the icon to be shown for this extension.
|
||||
|
@@ -5,6 +5,8 @@
|
||||
* project is released under the MIT License.
|
||||
*/
|
||||
|
||||
// NOLINTBEGIN
|
||||
|
||||
#ifndef GDCORE_PLATFORMEXTENSION_INL
|
||||
#define GDCORE_PLATFORMEXTENSION_INL
|
||||
|
||||
@@ -36,3 +38,5 @@ gd::ObjectMetadata& PlatformExtension::AddObject(const gd::String& name,
|
||||
} // namespace gd
|
||||
|
||||
#endif
|
||||
|
||||
// NOLINTEND
|
18
Core/GDCore/IDE/CaptureOptions.cpp
Normal file
18
Core/GDCore/IDE/CaptureOptions.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/IDE/CaptureOptions.h"
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
Screenshot::Screenshot() {}
|
||||
|
||||
CaptureOptions::CaptureOptions() {}
|
||||
|
||||
} // namespace gd
|
50
Core/GDCore/IDE/CaptureOptions.h
Normal file
50
Core/GDCore/IDE/CaptureOptions.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
class GD_CORE_API Screenshot {
|
||||
public:
|
||||
Screenshot();
|
||||
virtual ~Screenshot() {};
|
||||
|
||||
void SetDelayTimeInSeconds(int delayTimeInMs_) {
|
||||
delayTimeInMs = delayTimeInMs_;
|
||||
}
|
||||
int GetDelayTimeInSeconds() const { return delayTimeInMs; }
|
||||
|
||||
void SetSignedUrl(const gd::String& signedUrl_) { signedUrl = signedUrl_; }
|
||||
const gd::String& GetSignedUrl() const { return signedUrl; }
|
||||
|
||||
void SetPublicUrl(const gd::String& publicUrl_) { publicUrl = publicUrl_; }
|
||||
const gd::String& GetPublicUrl() const { return publicUrl; }
|
||||
|
||||
private:
|
||||
int delayTimeInMs = 0;
|
||||
gd::String signedUrl;
|
||||
gd::String publicUrl;
|
||||
};
|
||||
|
||||
class GD_CORE_API CaptureOptions {
|
||||
public:
|
||||
CaptureOptions();
|
||||
virtual ~CaptureOptions() {};
|
||||
|
||||
bool IsEmpty() const { return screenshots.empty(); }
|
||||
|
||||
void AddScreenshot(const Screenshot& screenshot) {
|
||||
screenshots.push_back(screenshot);
|
||||
}
|
||||
|
||||
const std::vector<Screenshot>& GetScreenshots() const { return screenshots; }
|
||||
|
||||
void ClearScreenshots() { screenshots.clear(); }
|
||||
|
||||
private:
|
||||
std::vector<Screenshot> screenshots;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -29,9 +29,6 @@ void EventBasedBehaviorBrowser::ExposeEvents(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior, worker);
|
||||
}
|
||||
|
||||
void EventBasedBehaviorBrowser::ExposeObjects(
|
||||
gd::Project &project, gd::ArbitraryObjectsWorker &worker) const {}
|
||||
|
||||
void EventBasedBehaviorBrowser::ExposeFunctions(
|
||||
gd::Project &project, gd::ArbitraryEventsFunctionsWorker &worker) const {
|
||||
worker.Launch(eventsBasedBehavior.GetEventsFunctions());
|
||||
@@ -43,7 +40,4 @@ void EventBasedBehaviorBrowser::ExposeEventBasedBehaviors(
|
||||
worker.Launch(eventsBasedBehavior);
|
||||
}
|
||||
|
||||
void EventBasedBehaviorBrowser::ExposeBehaviorSharedDatas(
|
||||
gd::Project &project, gd::ArbitraryBehaviorSharedDataWorker &worker) const {}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -67,7 +67,7 @@ public:
|
||||
* \brief Do nothing.
|
||||
*/
|
||||
void ExposeObjects(gd::Project &project,
|
||||
gd::ArbitraryObjectsWorker &worker) const override;
|
||||
gd::ArbitraryObjectsWorker &worker) const override {};
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on the event-based behavior.
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
* \brief Do nothing.
|
||||
*/
|
||||
void ExposeBehaviorSharedDatas(gd::Project &project,
|
||||
gd::ArbitraryBehaviorSharedDataWorker &worker) const override;
|
||||
gd::ArbitraryBehaviorSharedDataWorker &worker) const override {};
|
||||
|
||||
private:
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension;
|
||||
|
37
Core/GDCore/IDE/EventBasedObjectBrowser.cpp
Normal file
37
Core/GDCore/IDE/EventBasedObjectBrowser.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "EventBasedObjectBrowser.h"
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryEventBasedBehaviorsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryEventsFunctionsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryBehaviorSharedDataWorker.h"
|
||||
#include "GDCore/IDE/ProjectBrowserHelper.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
void EventBasedObjectBrowser::ExposeEvents(
|
||||
gd::Project &project, gd::ArbitraryEventsWorker &worker) const {
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
|
||||
project, eventsBasedObject, worker);
|
||||
}
|
||||
|
||||
void EventBasedObjectBrowser::ExposeEvents(
|
||||
gd::Project &project, gd::ArbitraryEventsWorkerWithContext &worker) const {
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
|
||||
project, eventsFunctionsExtension, eventsBasedObject, worker);
|
||||
}
|
||||
|
||||
void EventBasedObjectBrowser::ExposeFunctions(
|
||||
gd::Project &project, gd::ArbitraryEventsFunctionsWorker &worker) const {
|
||||
worker.Launch(eventsBasedObject.GetEventsFunctions());
|
||||
}
|
||||
|
||||
} // namespace gd
|
90
Core/GDCore/IDE/EventBasedObjectBrowser.h
Normal file
90
Core/GDCore/IDE/EventBasedObjectBrowser.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/IDE/ProjectBrowser.h"
|
||||
|
||||
namespace gd {
|
||||
class Project;
|
||||
class String;
|
||||
class EventsFunctionsExtension;
|
||||
class EventsFunction;
|
||||
class EventsBasedBehavior;
|
||||
class EventsBasedObject;
|
||||
class ArbitraryEventsWorker;
|
||||
class ArbitraryEventsWorkerWithContext;
|
||||
class ArbitraryEventsFunctionsWorker;
|
||||
class ArbitraryObjectsWorker;
|
||||
class ArbitraryEventBasedBehaviorsWorker;
|
||||
class ArbitraryBehaviorSharedDataWorker;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Expose event-based object contents to workers.
|
||||
*/
|
||||
class GD_CORE_API EventBasedObjectBrowser : public ProjectBrowser {
|
||||
public:
|
||||
EventBasedObjectBrowser(
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension_,
|
||||
gd::EventsBasedObject &eventsBasedObject_)
|
||||
: eventsFunctionsExtension(eventsFunctionsExtension_),
|
||||
eventsBasedObject(eventsBasedObject_) {}
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all events of the event-based
|
||||
* object.
|
||||
*
|
||||
* This should be the preferred way to traverse all the events of an event-based object.
|
||||
*/
|
||||
void ExposeEvents(gd::Project &project,
|
||||
gd::ArbitraryEventsWorker &worker) const override;
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all events of the event-based
|
||||
* object.
|
||||
*
|
||||
* This should be the preferred way to traverse all the events of an event-based object.
|
||||
*/
|
||||
void
|
||||
ExposeEvents(gd::Project &project,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) const override;
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all functions of the event-based object
|
||||
*
|
||||
* This should be the preferred way to traverse all the function signatures
|
||||
* of an event-based object.
|
||||
*/
|
||||
void ExposeFunctions(gd::Project &project,
|
||||
gd::ArbitraryEventsFunctionsWorker &worker) const override;
|
||||
|
||||
/**
|
||||
* \brief Do nothing.
|
||||
*/
|
||||
void ExposeObjects(gd::Project &project,
|
||||
gd::ArbitraryObjectsWorker &worker) const override {};
|
||||
|
||||
/**
|
||||
* @brief Do nothing.
|
||||
*/
|
||||
void ExposeEventBasedBehaviors(
|
||||
gd::Project &project,
|
||||
gd::ArbitraryEventBasedBehaviorsWorker &worker) const override {};
|
||||
|
||||
/**
|
||||
* \brief Do nothing.
|
||||
*/
|
||||
void ExposeBehaviorSharedDatas(gd::Project &project,
|
||||
gd::ArbitraryBehaviorSharedDataWorker &worker) const override {};
|
||||
|
||||
private:
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension;
|
||||
gd::EventsBasedObject &eventsBasedObject;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/IDE/Events/EventsLeaderboardsLister.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
bool EventsLeaderboardsLister::DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
const gd::InstructionMetadata& instrInfo =
|
||||
isCondition ? MetadataProvider::GetConditionMetadata(
|
||||
project.GetCurrentPlatform(), instruction.GetType())
|
||||
: MetadataProvider::GetActionMetadata(
|
||||
project.GetCurrentPlatform(), instruction.GetType());
|
||||
|
||||
for (int i = 0; i < instruction.GetParametersCount() &&
|
||||
i < instrInfo.GetParametersCount();
|
||||
++i)
|
||||
if (instrInfo.GetParameter(i).GetType() == "leaderboardId") {
|
||||
leaderboardIds.insert(instruction.GetParameter(i).GetPlainString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EventsLeaderboardsLister::~EventsLeaderboardsLister() {}
|
||||
|
||||
} // namespace gd
|
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef EventsLeaderboardsLister_H
|
||||
#define EventsLeaderboardsLister_H
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
class Project;
|
||||
class EventsList;
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief List the leaderboard ids in the instructions.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API EventsLeaderboardsLister : public ArbitraryEventsWorker {
|
||||
public:
|
||||
EventsLeaderboardsLister(gd::Project& project_) : project(project_){};
|
||||
virtual ~EventsLeaderboardsLister();
|
||||
|
||||
/**
|
||||
* Return the values of all leaderboardIds found in the events.
|
||||
*/
|
||||
const std::set<gd::String>& GetLeaderboardIds() { return leaderboardIds; }
|
||||
|
||||
private:
|
||||
virtual bool DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition);
|
||||
|
||||
std::set<gd::String> leaderboardIds;
|
||||
gd::Project& project;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // EventsLeaderboardsLister_H
|
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/IDE/Events/EventsLeaderboardsRenamer.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
bool EventsLeaderboardsRenamer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
const gd::InstructionMetadata& instrInfo =
|
||||
isCondition ? MetadataProvider::GetConditionMetadata(
|
||||
project.GetCurrentPlatform(), instruction.GetType())
|
||||
: MetadataProvider::GetActionMetadata(
|
||||
project.GetCurrentPlatform(), instruction.GetType());
|
||||
|
||||
for (int i = 0; i < instruction.GetParametersCount() &&
|
||||
i < instrInfo.GetParametersCount();
|
||||
++i) {
|
||||
const gd::ParameterMetadata parameter = instrInfo.GetParameter(i);
|
||||
|
||||
if (parameter.GetType() == "leaderboardId") {
|
||||
const gd::String leaderboardId =
|
||||
instruction.GetParameter(i).GetPlainString();
|
||||
|
||||
if (leaderboardIdMap.find(leaderboardId) != leaderboardIdMap.end()) {
|
||||
instruction.SetParameter(i, leaderboardIdMap[leaderboardId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EventsLeaderboardsRenamer::~EventsLeaderboardsRenamer() {}
|
||||
|
||||
} // namespace gd
|
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef EventsLeaderboardsRenamer_H
|
||||
#define EventsLeaderboardsRenamer_H
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
class Project;
|
||||
class EventsList;
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Replace the leaderboard ids in the instructions.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API EventsLeaderboardsRenamer : public ArbitraryEventsWorker {
|
||||
public:
|
||||
EventsLeaderboardsRenamer(
|
||||
gd::Project& project_,
|
||||
const std::map<gd::String, gd::String>& leaderboardIdMap_)
|
||||
: project(project_), leaderboardIdMap(leaderboardIdMap_){};
|
||||
virtual ~EventsLeaderboardsRenamer();
|
||||
|
||||
private:
|
||||
virtual bool DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition);
|
||||
|
||||
std::map<gd::String, gd::String> leaderboardIdMap;
|
||||
gd::Project& project;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // EventsLeaderboardsRenamer_H
|
243
Core/GDCore/IDE/Events/EventsParameterReplacer.cpp
Normal file
243
Core/GDCore/IDE/Events/EventsParameterReplacer.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/IDE/Events/EventsParameterReplacer.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/Project/PropertiesContainer.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Go through the nodes and rename parameters.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionParameterReplacer
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionParameterReplacer(
|
||||
const gd::Platform& platform_,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_,
|
||||
bool isParentTypeAVariable_,
|
||||
const std::unordered_map<gd::String, gd::String>& oldToNewPropertyNames_)
|
||||
: hasDoneRenaming(false),
|
||||
platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
isParentTypeAVariable(isParentTypeAVariable_),
|
||||
oldToNewPropertyNames(oldToNewPropertyNames_){};
|
||||
virtual ~ExpressionParameterReplacer(){};
|
||||
|
||||
bool HasDoneRenaming() const { return hasDoneRenaming; }
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
|
||||
node.expression->Visit(*this);
|
||||
}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {
|
||||
node.leftHandSide->Visit(*this);
|
||||
node.rightHandSide->Visit(*this);
|
||||
}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
|
||||
node.factor->Visit(*this);
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
if (isParentTypeAVariable) {
|
||||
// Do nothing, it's a variable.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
return;
|
||||
}
|
||||
|
||||
// The node represents a variable or an object name on which a variable
|
||||
// will be accessed, or a property with a child.
|
||||
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
// The property name is changed after the refactor operation.
|
||||
node.name,
|
||||
[&]() {
|
||||
// Do nothing, it's an object variable.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}, [&]() {
|
||||
// Do nothing, it's a variable.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}, [&]() {
|
||||
// Do nothing, it's a property.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}, [&]() {
|
||||
// This is a parameter
|
||||
RenameParameter(node.name);
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}, [&]() {
|
||||
// Do nothing, it's something else.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
});
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
bool isGrandParentTypeAVariable = isParentTypeAVariable;
|
||||
isParentTypeAVariable = false;
|
||||
node.expression->Visit(*this);
|
||||
isParentTypeAVariable = isGrandParentTypeAVariable;
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
if (isParentTypeAVariable) {
|
||||
// Do nothing, it's a variable.
|
||||
return;
|
||||
}
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
// The property name is changed after the refactor operation
|
||||
node.identifierName,
|
||||
[&]() {
|
||||
// Do nothing, it's an object variable.
|
||||
}, [&]() {
|
||||
// Do nothing, it's a variable.
|
||||
}, [&]() {
|
||||
// Do nothing, it's a property.
|
||||
}, [&]() {
|
||||
// This is a parameter.
|
||||
RenameParameter(node.identifierName);
|
||||
}, [&]() {
|
||||
// Do nothing, it's something else.
|
||||
});
|
||||
}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode &node) override {
|
||||
bool isGrandParentTypeAVariable = isParentTypeAVariable;
|
||||
for (auto ¶meter : node.parameters) {
|
||||
const auto ¶meterMetadata =
|
||||
gd::MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, projectScopedContainers.GetObjectsContainersList(),
|
||||
node, *parameter);
|
||||
if (!parameterMetadata) {
|
||||
continue;
|
||||
}
|
||||
const auto ¶meterTypeMetadata =
|
||||
parameterMetadata->GetValueTypeMetadata();
|
||||
if (gd::EventsParameterReplacer::CanContainParameter(
|
||||
parameterTypeMetadata)) {
|
||||
isParentTypeAVariable = parameterTypeMetadata.IsVariable();
|
||||
parameter->Visit(*this);
|
||||
}
|
||||
}
|
||||
isParentTypeAVariable = isGrandParentTypeAVariable;
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
|
||||
private:
|
||||
bool hasDoneRenaming;
|
||||
|
||||
bool RenameParameter(
|
||||
gd::String& name) {
|
||||
if (oldToNewPropertyNames.count(name) >= 1) {
|
||||
name = oldToNewPropertyNames.find(name)->second;
|
||||
hasDoneRenaming = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // Nothing was changed or done.
|
||||
}
|
||||
|
||||
// Scope:
|
||||
const gd::Platform& platform;
|
||||
const gd::ProjectScopedContainers& projectScopedContainers;
|
||||
|
||||
// Renaming to do
|
||||
const std::unordered_map<gd::String, gd::String>& oldToNewPropertyNames;
|
||||
|
||||
gd::String objectNameToUseForVariableAccessor;
|
||||
bool isParentTypeAVariable;
|
||||
};
|
||||
|
||||
bool EventsParameterReplacer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
const auto& metadata = isCondition
|
||||
? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
|
||||
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
instruction.GetParameters(),
|
||||
metadata.GetParameters(),
|
||||
[&](const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::Expression& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName) {
|
||||
if (!gd::EventsParameterReplacer::CanContainParameter(
|
||||
parameterMetadata.GetValueTypeMetadata())) {
|
||||
return;
|
||||
}
|
||||
auto node = parameterValue.GetRootNode();
|
||||
if (node) {
|
||||
ExpressionParameterReplacer renamer(
|
||||
platform, GetProjectScopedContainers(),
|
||||
parameterMetadata.GetValueTypeMetadata().IsVariable(),
|
||||
oldToNewPropertyNames);
|
||||
node->Visit(renamer);
|
||||
|
||||
if (renamer.HasDoneRenaming()) {
|
||||
instruction.SetParameter(
|
||||
parameterIndex, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EventsParameterReplacer::DoVisitEventExpression(
|
||||
gd::Expression& expression, const gd::ParameterMetadata& metadata) {
|
||||
if (!gd::EventsParameterReplacer::CanContainParameter(
|
||||
metadata.GetValueTypeMetadata())) {
|
||||
return false;
|
||||
}
|
||||
auto node = expression.GetRootNode();
|
||||
if (node) {
|
||||
ExpressionParameterReplacer renamer(
|
||||
platform, GetProjectScopedContainers(),
|
||||
metadata.GetValueTypeMetadata().IsVariable(), oldToNewPropertyNames);
|
||||
node->Visit(renamer);
|
||||
|
||||
if (renamer.HasDoneRenaming()) {
|
||||
expression = ExpressionParser2NodePrinter::PrintNode(*node);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EventsParameterReplacer::CanContainParameter(
|
||||
const gd::ValueTypeMetadata &valueTypeMetadata) {
|
||||
return valueTypeMetadata.IsVariable() || valueTypeMetadata.IsNumber() ||
|
||||
valueTypeMetadata.IsString();
|
||||
}
|
||||
|
||||
EventsParameterReplacer::~EventsParameterReplacer() {}
|
||||
|
||||
} // namespace gd
|
52
Core/GDCore/IDE/Events/EventsParameterReplacer.h
Normal file
52
Core/GDCore/IDE/Events/EventsParameterReplacer.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
class PropertiesContainer;
|
||||
class EventsList;
|
||||
class Platform;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
/**
|
||||
* \brief Replace in expressions and in parameters of actions or conditions,
|
||||
* references to the name of a parameter by another.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API EventsParameterReplacer
|
||||
: public ArbitraryEventsWorkerWithContext {
|
||||
public:
|
||||
EventsParameterReplacer(
|
||||
const gd::Platform &platform_,
|
||||
const std::unordered_map<gd::String, gd::String> &oldToNewPropertyNames_)
|
||||
: platform(platform_),
|
||||
oldToNewPropertyNames(oldToNewPropertyNames_){};
|
||||
virtual ~EventsParameterReplacer();
|
||||
|
||||
static bool CanContainParameter(const gd::ValueTypeMetadata &valueTypeMetadata);
|
||||
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) override;
|
||||
bool DoVisitEventExpression(gd::Expression &expression,
|
||||
const gd::ParameterMetadata &metadata) override;
|
||||
|
||||
const gd::Platform &platform;
|
||||
const std::unordered_map<gd::String, gd::String> &oldToNewPropertyNames;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -41,6 +41,7 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
const gd::Platform& platform_,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_,
|
||||
const gd::PropertiesContainer& targetPropertiesContainer_,
|
||||
bool isParentTypeAVariable_,
|
||||
const std::unordered_map<gd::String, gd::String>& oldToNewPropertyNames_,
|
||||
const std::unordered_set<gd::String>& removedPropertyNames_)
|
||||
: hasDoneRenaming(false),
|
||||
@@ -48,6 +49,7 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
targetPropertiesContainer(targetPropertiesContainer_),
|
||||
isParentTypeAVariable(isParentTypeAVariable_),
|
||||
oldToNewPropertyNames(oldToNewPropertyNames_),
|
||||
removedPropertyNames(removedPropertyNames_){};
|
||||
virtual ~ExpressionPropertyReplacer(){};
|
||||
@@ -69,16 +71,21 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
if (isParentTypeAVariable) {
|
||||
// Do nothing, it's a variable.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& propertiesContainersList =
|
||||
projectScopedContainers.GetPropertiesContainersList();
|
||||
|
||||
// The node represents a variable or an object name on which a variable
|
||||
// will be accessed, or a property with a child.
|
||||
|
||||
// Match the potential *new* name of the property, because refactorings are
|
||||
// done after changes in the variables container.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
GetPotentialNewName(node.name),
|
||||
// The property name is changed after the refactor operation.
|
||||
node.name,
|
||||
[&]() {
|
||||
// Do nothing, it's an object variable.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
@@ -100,16 +107,7 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
// Do nothing, it's a parameter.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}, [&]() {
|
||||
// This is something else - potentially a deleted property.
|
||||
// Check if it's coming from the target container with
|
||||
// properties to replace.
|
||||
if (propertiesContainersList.HasPropertiesContainer(
|
||||
targetPropertiesContainer)) {
|
||||
// The node represents a property, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemovePropertyOfTargetPropertyContainer(node.name);
|
||||
}
|
||||
|
||||
// Do nothing, it's something else.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
});
|
||||
}
|
||||
@@ -118,17 +116,24 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
bool isGrandParentTypeAVariable = isParentTypeAVariable;
|
||||
isParentTypeAVariable = false;
|
||||
node.expression->Visit(*this);
|
||||
isParentTypeAVariable = isGrandParentTypeAVariable;
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
if (isParentTypeAVariable) {
|
||||
// Do nothing, it's a variable.
|
||||
return;
|
||||
}
|
||||
|
||||
auto& propertiesContainersList =
|
||||
projectScopedContainers.GetPropertiesContainersList();
|
||||
|
||||
// Match the potential *new* name of the property, because refactorings are
|
||||
// done after changes in the variables container.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
GetPotentialNewName(node.identifierName),
|
||||
// The property name is changed after the refactor operation
|
||||
node.identifierName,
|
||||
[&]() {
|
||||
// Do nothing, it's an object variable.
|
||||
}, [&]() {
|
||||
@@ -145,22 +150,29 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
}, [&]() {
|
||||
// Do nothing, it's a parameter.
|
||||
}, [&]() {
|
||||
// This is something else - potentially a deleted property.
|
||||
// Check if it's coming from the target container with
|
||||
// properties to replace.
|
||||
if (propertiesContainersList.HasPropertiesContainer(
|
||||
targetPropertiesContainer)) {
|
||||
// The node represents a property, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemovePropertyOfTargetPropertyContainer(node.identifierName);
|
||||
}
|
||||
// Do nothing, it's something else.
|
||||
});
|
||||
}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
for (auto& parameter : node.parameters) {
|
||||
parameter->Visit(*this);
|
||||
void OnVisitFunctionCallNode(FunctionCallNode &node) override {
|
||||
bool isGrandParentTypeAVariable = isParentTypeAVariable;
|
||||
for (auto ¶meter : node.parameters) {
|
||||
const auto ¶meterMetadata =
|
||||
gd::MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, projectScopedContainers.GetObjectsContainersList(),
|
||||
node, *parameter);
|
||||
if (!parameterMetadata) {
|
||||
continue;
|
||||
}
|
||||
const auto ¶meterTypeMetadata =
|
||||
parameterMetadata->GetValueTypeMetadata();
|
||||
if (gd::EventsPropertyReplacer::CanContainProperty(
|
||||
parameterTypeMetadata)) {
|
||||
isParentTypeAVariable = parameterTypeMetadata.IsVariable();
|
||||
parameter->Visit(*this);
|
||||
}
|
||||
}
|
||||
isParentTypeAVariable = isGrandParentTypeAVariable;
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
|
||||
@@ -168,12 +180,6 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
bool hasDoneRenaming;
|
||||
bool removedPropertyUsed;
|
||||
|
||||
const gd::String& GetPotentialNewName(const gd::String& oldName) {
|
||||
return oldToNewPropertyNames.count(oldName) >= 1
|
||||
? oldToNewPropertyNames.find(oldName)->second
|
||||
: oldName;
|
||||
}
|
||||
|
||||
bool RenameOrRemovePropertyOfTargetPropertyContainer(
|
||||
gd::String& propertyName) {
|
||||
if (oldToNewPropertyNames.count(propertyName) >= 1) {
|
||||
@@ -198,6 +204,7 @@ class GD_CORE_API ExpressionPropertyReplacer
|
||||
const std::unordered_set<gd::String>& removedPropertyNames;
|
||||
|
||||
gd::String objectNameToUseForVariableAccessor;
|
||||
bool isParentTypeAVariable;
|
||||
};
|
||||
|
||||
bool EventsPropertyReplacer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
@@ -216,20 +223,16 @@ bool EventsPropertyReplacer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
const gd::Expression& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName) {
|
||||
const gd::String& type = parameterMetadata.GetType();
|
||||
|
||||
if (!gd::ParameterMetadata::IsExpression("variable", type) &&
|
||||
!gd::ParameterMetadata::IsExpression("number", type) &&
|
||||
!gd::ParameterMetadata::IsExpression("string", type))
|
||||
return; // Not an expression that can contain properties.
|
||||
|
||||
if (!gd::EventsPropertyReplacer::CanContainProperty(
|
||||
parameterMetadata.GetValueTypeMetadata())) {
|
||||
return;
|
||||
}
|
||||
auto node = parameterValue.GetRootNode();
|
||||
if (node) {
|
||||
ExpressionPropertyReplacer renamer(platform,
|
||||
GetProjectScopedContainers(),
|
||||
targetPropertiesContainer,
|
||||
oldToNewPropertyNames,
|
||||
removedPropertyNames);
|
||||
ExpressionPropertyReplacer renamer(
|
||||
platform, GetProjectScopedContainers(), targetPropertiesContainer,
|
||||
parameterMetadata.GetValueTypeMetadata().IsVariable(),
|
||||
oldToNewPropertyNames, removedPropertyNames);
|
||||
node->Visit(renamer);
|
||||
|
||||
if (renamer.IsRemovedPropertyUsed()) {
|
||||
@@ -246,20 +249,16 @@ bool EventsPropertyReplacer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
|
||||
bool EventsPropertyReplacer::DoVisitEventExpression(
|
||||
gd::Expression& expression, const gd::ParameterMetadata& metadata) {
|
||||
const gd::String& type = metadata.GetType();
|
||||
|
||||
if (!gd::ParameterMetadata::IsExpression("variable", type) &&
|
||||
!gd::ParameterMetadata::IsExpression("number", type) &&
|
||||
!gd::ParameterMetadata::IsExpression("string", type))
|
||||
return false; // Not an expression that can contain properties.
|
||||
|
||||
if (!gd::EventsPropertyReplacer::CanContainProperty(
|
||||
metadata.GetValueTypeMetadata())) {
|
||||
return false;
|
||||
}
|
||||
auto node = expression.GetRootNode();
|
||||
if (node) {
|
||||
ExpressionPropertyReplacer renamer(platform,
|
||||
GetProjectScopedContainers(),
|
||||
targetPropertiesContainer,
|
||||
oldToNewPropertyNames,
|
||||
removedPropertyNames);
|
||||
ExpressionPropertyReplacer renamer(
|
||||
platform, GetProjectScopedContainers(), targetPropertiesContainer,
|
||||
metadata.GetValueTypeMetadata().IsVariable(), oldToNewPropertyNames,
|
||||
removedPropertyNames);
|
||||
node->Visit(renamer);
|
||||
|
||||
if (renamer.IsRemovedPropertyUsed()) {
|
||||
@@ -272,6 +271,12 @@ bool EventsPropertyReplacer::DoVisitEventExpression(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EventsPropertyReplacer::CanContainProperty(
|
||||
const gd::ValueTypeMetadata &valueTypeMetadata) {
|
||||
return valueTypeMetadata.IsVariable() || valueTypeMetadata.IsNumber() ||
|
||||
valueTypeMetadata.IsString();
|
||||
}
|
||||
|
||||
EventsPropertyReplacer::~EventsPropertyReplacer() {}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -4,6 +4,7 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
@@ -41,6 +42,8 @@ class GD_CORE_API EventsPropertyReplacer
|
||||
removedPropertyNames(removedPropertyNames_){};
|
||||
virtual ~EventsPropertyReplacer();
|
||||
|
||||
static bool CanContainProperty(const gd::ValueTypeMetadata &valueTypeMetadata);
|
||||
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) override;
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -51,17 +52,17 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
|
||||
|
||||
static bool Rename(const gd::Platform &platform,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
const gd::String &rootType,
|
||||
gd::ExpressionNode& node,
|
||||
const gd::String& objectName,
|
||||
const gd::String& objectNewName) {
|
||||
if (gd::ExpressionValidator::HasNoErrors(platform, projectScopedContainers, rootType, node)) {
|
||||
ExpressionObjectRenamer renamer(platform, projectScopedContainers, rootType, objectName, objectNewName);
|
||||
const gd::String &rootType, gd::ExpressionNode &node,
|
||||
const gd::String &objectName,
|
||||
const gd::String &objectNewName) {
|
||||
if (gd::ExpressionValidator::HasNoErrors(platform, projectScopedContainers,
|
||||
rootType, node)) {
|
||||
ExpressionObjectRenamer renamer(platform, projectScopedContainers,
|
||||
rootType, objectName, objectNewName);
|
||||
node.Visit(renamer);
|
||||
|
||||
return renamer.HasDoneRenaming();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -83,7 +84,7 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
auto type = gd::ExpressionTypeFinder::GetType(platform, projectScopedContainers, rootType, node);
|
||||
|
||||
if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
|
||||
if (gd::ValueTypeMetadata::IsVariable(type)) {
|
||||
// Nothing to do (this can't reference an object)
|
||||
} else {
|
||||
if (node.name == objectName) {
|
||||
@@ -119,7 +120,7 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
|
||||
node.identifierName == objectName) {
|
||||
hasDoneRenaming = true;
|
||||
node.identifierName = objectNewName;
|
||||
} else if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
|
||||
} else if (gd::ValueTypeMetadata::IsVariable(type)) {
|
||||
// Nothing to do (this can't reference an object)
|
||||
} else {
|
||||
if (node.identifierName == objectName) {
|
||||
@@ -295,183 +296,114 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
|
||||
const gd::String rootType;
|
||||
};
|
||||
|
||||
bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& actions,
|
||||
gd::String oldName,
|
||||
gd::String newName) {
|
||||
bool somethingModified = false;
|
||||
/**
|
||||
* \brief Replace in expressions and in parameters of actions or conditions,
|
||||
* references to the name of an object by another.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API EventsObjectReplacer
|
||||
: public ArbitraryEventsWorkerWithContext {
|
||||
public:
|
||||
EventsObjectReplacer(const gd::Platform &platform_,
|
||||
const gd::ObjectsContainer &targetedObjectsContainer_,
|
||||
const gd::String &oldObjectName_,
|
||||
const gd::String &newObjectName_)
|
||||
: platform(platform_),
|
||||
targetedObjectsContainer(targetedObjectsContainer_),
|
||||
oldObjectName(oldObjectName_), newObjectName(newObjectName_){};
|
||||
|
||||
for (std::size_t aId = 0; aId < actions.size(); ++aId) {
|
||||
const gd::InstructionMetadata& instrInfos =
|
||||
MetadataProvider::GetActionMetadata(platform, actions[aId].GetType());
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
|
||||
// Replace object's name in parameters
|
||||
if (gd::ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType()) &&
|
||||
actions[aId].GetParameter(pNb).GetPlainString() == oldName)
|
||||
actions[aId].SetParameter(pNb, gd::Expression(newName));
|
||||
// Replace object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters.GetParameter(pNb).GetType())) {
|
||||
auto node = actions[aId].GetParameter(pNb).GetRootNode();
|
||||
virtual ~EventsObjectReplacer() {}
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
|
||||
actions[aId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
// Replace object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
|
||||
auto node = actions[aId].GetParameter(pNb).GetRootNode();
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
|
||||
actions[aId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) override {
|
||||
if (&targetedObjectsContainer !=
|
||||
GetProjectScopedContainers()
|
||||
.GetObjectsContainersList()
|
||||
.GetObjectsContainerFromObjectName(oldObjectName)) {
|
||||
return false;
|
||||
}
|
||||
const auto &metadata = isCondition
|
||||
? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
|
||||
if (!actions[aId].GetSubInstructions().empty())
|
||||
somethingModified =
|
||||
RenameObjectInActions(platform,
|
||||
projectScopedContainers,
|
||||
actions[aId].GetSubInstructions(),
|
||||
oldName,
|
||||
newName) ||
|
||||
somethingModified;
|
||||
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
instruction.GetParameters(), metadata.GetParameters(),
|
||||
[&](const gd::ParameterMetadata ¶meterMetadata,
|
||||
const gd::Expression ¶meterValue, size_t parameterIndex,
|
||||
const gd::String &lastObjectName) {
|
||||
if (!gd::EventsObjectReplacer::CanContainObject(
|
||||
parameterMetadata.GetValueTypeMetadata())) {
|
||||
return;
|
||||
}
|
||||
auto node = parameterValue.GetRootNode();
|
||||
if (node) {
|
||||
ExpressionObjectRenamer renamer(
|
||||
platform, GetProjectScopedContainers(),
|
||||
parameterMetadata.GetValueTypeMetadata().GetName(),
|
||||
oldObjectName, newObjectName);
|
||||
node->Visit(renamer);
|
||||
|
||||
if (renamer.HasDoneRenaming()) {
|
||||
instruction.SetParameter(
|
||||
parameterIndex,
|
||||
ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return somethingModified;
|
||||
}
|
||||
|
||||
bool EventsRefactorer::RenameObjectInConditions(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& conditions,
|
||||
gd::String oldName,
|
||||
gd::String newName) {
|
||||
bool somethingModified = false;
|
||||
|
||||
for (std::size_t cId = 0; cId < conditions.size(); ++cId) {
|
||||
const gd::InstructionMetadata& instrInfos =
|
||||
MetadataProvider::GetConditionMetadata(platform,
|
||||
conditions[cId].GetType());
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.GetParametersCount(); ++pNb) {
|
||||
// Replace object's name in parameters
|
||||
if (gd::ParameterMetadata::IsObject(instrInfos.parameters.GetParameter(pNb).GetType()) &&
|
||||
conditions[cId].GetParameter(pNb).GetPlainString() == oldName)
|
||||
conditions[cId].SetParameter(pNb, gd::Expression(newName));
|
||||
// Replace object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters.GetParameter(pNb).GetType())) {
|
||||
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
|
||||
conditions[cId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
// Replace object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters.GetParameter(pNb).GetType())) {
|
||||
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
|
||||
conditions[cId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
bool DoVisitEventExpression(gd::Expression &expression,
|
||||
const gd::ParameterMetadata &metadata) override {
|
||||
if (&targetedObjectsContainer !=
|
||||
GetProjectScopedContainers()
|
||||
.GetObjectsContainersList()
|
||||
.GetObjectsContainerFromObjectName(oldObjectName)) {
|
||||
return false;
|
||||
}
|
||||
if (!gd::EventsObjectReplacer::CanContainObject(
|
||||
metadata.GetValueTypeMetadata())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!conditions[cId].GetSubInstructions().empty())
|
||||
somethingModified =
|
||||
RenameObjectInConditions(platform,
|
||||
projectScopedContainers,
|
||||
conditions[cId].GetSubInstructions(),
|
||||
oldName,
|
||||
newName) ||
|
||||
somethingModified;
|
||||
}
|
||||
|
||||
return somethingModified;
|
||||
}
|
||||
|
||||
bool EventsRefactorer::RenameObjectInEventParameters(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::Expression& expression,
|
||||
gd::ParameterMetadata parameterMetadata,
|
||||
gd::String oldName,
|
||||
gd::String newName) {
|
||||
bool somethingModified = false;
|
||||
|
||||
if (gd::ParameterMetadata::IsObject(parameterMetadata.GetType()) &&
|
||||
expression.GetPlainString() == oldName)
|
||||
expression = gd::Expression(newName);
|
||||
// Replace object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression("number",
|
||||
parameterMetadata.GetType())) {
|
||||
auto node = expression.GetRootNode();
|
||||
if (node) {
|
||||
ExpressionObjectRenamer renamer(platform, GetProjectScopedContainers(),
|
||||
metadata.GetValueTypeMetadata().GetName(),
|
||||
oldObjectName, newObjectName);
|
||||
node->Visit(renamer);
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
|
||||
expression = ExpressionParser2NodePrinter::PrintNode(*node);
|
||||
if (renamer.HasDoneRenaming()) {
|
||||
expression = ExpressionParser2NodePrinter::PrintNode(*node);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Replace object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression("string",
|
||||
parameterMetadata.GetType())) {
|
||||
auto node = expression.GetRootNode();
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
|
||||
expression = ExpressionParser2NodePrinter::PrintNode(*node);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return somethingModified;
|
||||
}
|
||||
bool CanContainObject(const gd::ValueTypeMetadata &valueTypeMetadata) {
|
||||
return valueTypeMetadata.IsObject() || valueTypeMetadata.IsVariable() ||
|
||||
valueTypeMetadata.IsNumber() || valueTypeMetadata.IsString();
|
||||
}
|
||||
|
||||
const gd::Platform &platform;
|
||||
const gd::ObjectsContainer &targetedObjectsContainer;
|
||||
const gd::String &oldObjectName;
|
||||
const gd::String &newObjectName;
|
||||
};
|
||||
|
||||
void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::EventsList& events,
|
||||
const gd::ObjectsContainer &targetedObjectsContainer,
|
||||
gd::String oldName,
|
||||
gd::String newName) {
|
||||
for (std::size_t i = 0; i < events.size(); ++i) {
|
||||
vector<gd::InstructionsList*> conditionsVectors =
|
||||
events[i].GetAllConditionsVectors();
|
||||
for (std::size_t j = 0; j < conditionsVectors.size(); ++j) {
|
||||
bool somethingModified = RenameObjectInConditions(
|
||||
platform, projectScopedContainers, *conditionsVectors[j], oldName, newName);
|
||||
}
|
||||
|
||||
vector<gd::InstructionsList*> actionsVectors =
|
||||
events[i].GetAllActionsVectors();
|
||||
for (std::size_t j = 0; j < actionsVectors.size(); ++j) {
|
||||
bool somethingModified = RenameObjectInActions(
|
||||
platform, projectScopedContainers, *actionsVectors[j], oldName, newName);
|
||||
}
|
||||
|
||||
vector<pair<gd::Expression*, gd::ParameterMetadata>>
|
||||
expressionsWithMetadata = events[i].GetAllExpressionsWithMetadata();
|
||||
for (std::size_t j = 0; j < expressionsWithMetadata.size(); ++j) {
|
||||
gd::Expression* expression = expressionsWithMetadata[j].first;
|
||||
gd::ParameterMetadata parameterMetadata =
|
||||
expressionsWithMetadata[j].second;
|
||||
bool somethingModified = RenameObjectInEventParameters(platform,
|
||||
projectScopedContainers,
|
||||
*expression,
|
||||
parameterMetadata,
|
||||
oldName,
|
||||
newName);
|
||||
}
|
||||
|
||||
if (events[i].CanHaveSubEvents())
|
||||
RenameObjectInEvents(platform,
|
||||
projectScopedContainers,
|
||||
events[i].GetSubEvents(),
|
||||
oldName,
|
||||
newName);
|
||||
}
|
||||
gd::EventsObjectReplacer eventsParameterReplacer(platform, targetedObjectsContainer, oldName, newName);
|
||||
eventsParameterReplacer.Launch(events, projectScopedContainers);
|
||||
}
|
||||
|
||||
bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
|
||||
|
@@ -83,6 +83,7 @@ class GD_CORE_API EventsRefactorer {
|
||||
static void RenameObjectInEvents(const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::EventsList& events,
|
||||
const gd::ObjectsContainer &targetedObjectsContainer,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
|
||||
@@ -121,44 +122,6 @@ class GD_CORE_API EventsRefactorer {
|
||||
virtual ~EventsRefactorer(){};
|
||||
|
||||
private:
|
||||
/**
|
||||
* Replace all occurrences of an object name by another name in an action
|
||||
* ( include : objects in parameters and in math/text expressions ).
|
||||
*
|
||||
* \return true if something was modified.
|
||||
*/
|
||||
static bool RenameObjectInActions(const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& instructions,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
|
||||
/**
|
||||
* Replace all occurrences of an object name by another name in a condition
|
||||
* ( include : objects in parameters and in math/text expressions ).
|
||||
*
|
||||
* \return true if something was modified.
|
||||
*/
|
||||
static bool RenameObjectInConditions(const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& instructions,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
/**
|
||||
* Replace all occurrences of an object name by another name in an expression
|
||||
* with the specified metadata
|
||||
* ( include : objects or objects in math/text expressions ).
|
||||
*
|
||||
* \return true if something was modified.
|
||||
*/
|
||||
static bool RenameObjectInEventParameters(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::Expression& expression,
|
||||
gd::ParameterMetadata parameterMetadata,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
|
||||
/**
|
||||
* Remove all conditions of the list using an object
|
||||
*
|
||||
|
@@ -337,19 +337,19 @@ struct GD_CORE_API ExpressionCompletionDescription {
|
||||
|
||||
private:
|
||||
CompletionKind completionKind;
|
||||
gd::Variable::Type variableType;
|
||||
gd::VariablesContainer::SourceType variableScope;
|
||||
gd::Variable::Type variableType = gd::Variable::Unknown;
|
||||
gd::VariablesContainer::SourceType variableScope = gd::VariablesContainer::Unknown;
|
||||
gd::String type;
|
||||
gd::String prefix;
|
||||
gd::String completion;
|
||||
size_t replacementStartPosition;
|
||||
size_t replacementEndPosition;
|
||||
size_t replacementStartPosition = 0;
|
||||
size_t replacementEndPosition = 0;
|
||||
gd::String objectName;
|
||||
gd::String behaviorName;
|
||||
bool isExact;
|
||||
bool isLastParameter;
|
||||
const gd::ParameterMetadata* parameterMetadata;
|
||||
const gd::ObjectConfiguration* objectConfiguration;
|
||||
bool isExact = false;
|
||||
bool isLastParameter = false;
|
||||
const gd::ParameterMetadata* parameterMetadata = &badParameterMetadata;
|
||||
const gd::ObjectConfiguration* objectConfiguration = &badObjectConfiguration;
|
||||
|
||||
static const gd::ParameterMetadata badParameterMetadata;
|
||||
static const gd::ObjectConfiguration badObjectConfiguration;
|
||||
@@ -1066,8 +1066,8 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
bool eagerlyCompleteIfExactMatch = false) {
|
||||
projectScopedContainers.ForEachIdentifierMatchingSearch(
|
||||
search,
|
||||
[&](const gd::String& objectName,
|
||||
const ObjectConfiguration* objectConfiguration) {
|
||||
[&](const gd::String &objectName,
|
||||
const ObjectConfiguration *objectConfiguration) {
|
||||
ExpressionCompletionDescription description(
|
||||
ExpressionCompletionDescription::Object,
|
||||
location.GetStartPosition(),
|
||||
@@ -1077,7 +1077,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
description.SetType(type);
|
||||
completions.push_back(description);
|
||||
},
|
||||
[&](const gd::String& variableName, const gd::Variable& variable) {
|
||||
[&](const gd::String &variableName, const gd::Variable &variable) {
|
||||
ExpressionCompletionDescription description(
|
||||
ExpressionCompletionDescription::Variable,
|
||||
location.GetStartPosition(),
|
||||
@@ -1095,23 +1095,29 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
variable, variableName, location);
|
||||
}
|
||||
},
|
||||
[&](const gd::NamedPropertyDescriptor& property) {
|
||||
ExpressionCompletionDescription description(
|
||||
ExpressionCompletionDescription::Property,
|
||||
location.GetStartPosition(),
|
||||
location.GetEndPosition());
|
||||
description.SetCompletion(property.GetName());
|
||||
description.SetType(property.GetType());
|
||||
completions.push_back(description);
|
||||
[&](const gd::NamedPropertyDescriptor &property) {
|
||||
auto propertyType = gd::ValueTypeMetadata::ConvertPropertyTypeToValueType(
|
||||
property.GetType());
|
||||
if (gd::ValueTypeMetadata::IsTypeValue("number", propertyType) ||
|
||||
gd::ValueTypeMetadata::IsTypeValue("string", propertyType)) {
|
||||
ExpressionCompletionDescription description(
|
||||
ExpressionCompletionDescription::Property,
|
||||
location.GetStartPosition(), location.GetEndPosition());
|
||||
description.SetCompletion(property.GetName());
|
||||
description.SetType(property.GetType());
|
||||
completions.push_back(description);
|
||||
}
|
||||
},
|
||||
[&](const gd::ParameterMetadata& parameter) {
|
||||
ExpressionCompletionDescription description(
|
||||
ExpressionCompletionDescription::Parameter,
|
||||
location.GetStartPosition(),
|
||||
location.GetEndPosition());
|
||||
description.SetCompletion(parameter.GetName());
|
||||
description.SetType(parameter.GetType());
|
||||
completions.push_back(description);
|
||||
[&](const gd::ParameterMetadata ¶meter) {
|
||||
if (parameter.GetValueTypeMetadata().IsNumber() ||
|
||||
parameter.GetValueTypeMetadata().IsString()) {
|
||||
ExpressionCompletionDescription description(
|
||||
ExpressionCompletionDescription::Parameter,
|
||||
location.GetStartPosition(), location.GetEndPosition());
|
||||
description.SetCompletion(parameter.GetName());
|
||||
description.SetType(parameter.GetType());
|
||||
completions.push_back(description);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -33,8 +33,10 @@ class GD_CORE_API ExpressionNodeLocationFinder
|
||||
* \brief Initialize the finder to search at the specified position.
|
||||
*/
|
||||
ExpressionNodeLocationFinder(size_t searchedPosition_)
|
||||
: searchedPosition(searchedPosition_), foundNode(nullptr){};
|
||||
virtual ~ExpressionNodeLocationFinder(){};
|
||||
: searchedPosition(searchedPosition_),
|
||||
foundNode(nullptr),
|
||||
parentNode(nullptr) {};
|
||||
virtual ~ExpressionNodeLocationFinder() {};
|
||||
|
||||
/**
|
||||
* \brief Helper function to find the deepest node at the search position, if
|
||||
|
@@ -72,7 +72,7 @@ class GD_CORE_API ExpressionTypeFinder : public ExpressionParser2NodeWorker {
|
||||
child(nullptr) {};
|
||||
|
||||
const gd::String &GetType() {
|
||||
return gd::ParameterMetadata::GetExpressionValueType(type);
|
||||
return gd::ValueTypeMetadata::GetExpressionPrimitiveValueType(type);
|
||||
};
|
||||
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
|
||||
|
@@ -68,19 +68,26 @@ size_t GetMaximumParametersNumber(
|
||||
|
||||
bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
const gd::IdentifierNode& identifier) {
|
||||
return ValidateObjectVariableOrVariableOrProperty(identifier.identifierName, identifier.identifierNameLocation, identifier.childIdentifierName, identifier.childIdentifierNameLocation);
|
||||
}
|
||||
|
||||
bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
const gd::String &identifierName,
|
||||
const gd::ExpressionParserLocation identifierNameLocation,
|
||||
const gd::String &childIdentifierName,
|
||||
const gd::ExpressionParserLocation childIdentifierNameLocation) {
|
||||
auto validateVariableTypeForExpression =
|
||||
[this, &identifier](gd::Variable::Type type) {
|
||||
[this, &identifierNameLocation](gd::Variable::Type type) {
|
||||
// Collections type can't be used directly in expressions, a child
|
||||
// must be accessed.
|
||||
if (type == Variable::Structure) {
|
||||
RaiseTypeError(_("You need to specify the name of the child variable "
|
||||
"to access. For example: `MyVariable.child`."),
|
||||
identifier.identifierNameLocation);
|
||||
identifierNameLocation);
|
||||
} else if (type == Variable::Array) {
|
||||
RaiseTypeError(_("You need to specify the name of the child variable "
|
||||
"to access. For example: `MyVariable[0]`."),
|
||||
identifier.identifierNameLocation);
|
||||
|
||||
identifierNameLocation);
|
||||
} else {
|
||||
// Number, string or boolean variables can be used in expressions.
|
||||
return;
|
||||
@@ -96,38 +103,41 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
// we consider this node will be of the type required by the parent.
|
||||
childType = parentType;
|
||||
|
||||
return projectScopedContainers.MatchIdentifierWithName<bool>(identifier.identifierName,
|
||||
return projectScopedContainers.MatchIdentifierWithName<bool>(identifierName,
|
||||
[&]() {
|
||||
// This represents an object.
|
||||
if (identifier.childIdentifierName.empty()) {
|
||||
if (childIdentifierName.empty()) {
|
||||
RaiseTypeError(_("An object variable or expression should be entered."),
|
||||
identifier.identifierNameLocation);
|
||||
identifierNameLocation);
|
||||
|
||||
return true; // We should have found a variable.
|
||||
}
|
||||
|
||||
auto variableExistence = objectsContainersList.HasObjectOrGroupWithVariableNamed(identifier.identifierName, identifier.childIdentifierName);
|
||||
auto variableExistence =
|
||||
objectsContainersList.HasObjectOrGroupWithVariableNamed(
|
||||
identifierName, childIdentifierName);
|
||||
|
||||
if (variableExistence == gd::ObjectsContainersList::DoesNotExist) {
|
||||
RaiseUndeclaredVariableError(_("This variable does not exist on this object or group."),
|
||||
identifier.childIdentifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
|
||||
childIdentifierNameLocation, childIdentifierName, identifierName);
|
||||
|
||||
return true; // We should have found a variable.
|
||||
}
|
||||
else if (variableExistence == gd::ObjectsContainersList::ExistsOnlyOnSomeObjectsOfTheGroup) {
|
||||
RaiseUndeclaredVariableError(_("This variable only exists on some objects of the group. It must be declared for all objects."),
|
||||
identifier.childIdentifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
|
||||
childIdentifierNameLocation, childIdentifierName, identifierName);
|
||||
|
||||
return true; // We should have found a variable.
|
||||
}
|
||||
else if (variableExistence == gd::ObjectsContainersList::GroupIsEmpty) {
|
||||
RaiseUndeclaredVariableError(_("This group is empty. Add an object to this group first."),
|
||||
identifier.identifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
|
||||
identifierNameLocation, childIdentifierName, identifierName);
|
||||
|
||||
return true; // We should have found a variable.
|
||||
}
|
||||
|
||||
auto variableType = objectsContainersList.GetTypeOfObjectOrGroupVariable(identifier.identifierName, identifier.childIdentifierName);
|
||||
auto variableType = objectsContainersList.GetTypeOfObjectOrGroupVariable(
|
||||
identifierName, childIdentifierName);
|
||||
ReadChildTypeFromVariable(variableType);
|
||||
|
||||
return true; // We found a variable.
|
||||
@@ -137,9 +147,9 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
// Try to identify a declared variable with the name (and maybe the child
|
||||
// variable).
|
||||
const gd::Variable& variable =
|
||||
variablesContainersList.Get(identifier.identifierName);
|
||||
variablesContainersList.Get(identifierName);
|
||||
|
||||
if (identifier.childIdentifierName.empty()) {
|
||||
if (childIdentifierName.empty()) {
|
||||
// Just the root variable is accessed, check it can be used in an
|
||||
// expression.
|
||||
validateVariableTypeForExpression(variable.GetType());
|
||||
@@ -148,33 +158,38 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
return true; // We found a variable.
|
||||
} else {
|
||||
// A child variable is accessed, check it can be used in an expression.
|
||||
if (!variable.HasChild(identifier.childIdentifierName)) {
|
||||
if (!variable.HasChild(childIdentifierName)) {
|
||||
RaiseTypeError(_("No child variable with this name found."),
|
||||
identifier.childIdentifierNameLocation);
|
||||
childIdentifierNameLocation);
|
||||
|
||||
return true; // We should have found a variable.
|
||||
}
|
||||
|
||||
const gd::Variable& childVariable =
|
||||
variable.GetChild(identifier.childIdentifierName);
|
||||
variable.GetChild(childIdentifierName);
|
||||
ReadChildTypeFromVariable(childVariable.GetType());
|
||||
return true; // We found a variable.
|
||||
}
|
||||
}, [&]() {
|
||||
// This is a property.
|
||||
if (!identifier.childIdentifierName.empty()) {
|
||||
if (!childIdentifierName.empty()) {
|
||||
RaiseTypeError(_("Accessing a child variable of a property is not possible - just write the property name."),
|
||||
identifier.childIdentifierNameLocation);
|
||||
childIdentifierNameLocation);
|
||||
|
||||
return true; // We found a property, even if the child is not allowed.
|
||||
}
|
||||
|
||||
const gd::NamedPropertyDescriptor& property = propertiesContainersList.Get(identifier.identifierName).second;
|
||||
const gd::NamedPropertyDescriptor &property =
|
||||
propertiesContainersList.Get(identifierName).second;
|
||||
|
||||
if (property.GetType() == "Number") {
|
||||
childType = Type::Number;
|
||||
childType = Type::Number;
|
||||
} else if (property.GetType() == "Boolean") {
|
||||
// Nothing - we don't know the precise type (this could be used a string or as a number)
|
||||
// Nothing - we don't know the precise type (this could be used a string
|
||||
// or as a number)
|
||||
} else if (property.GetType() == "Behavior") {
|
||||
RaiseTypeError(_("Behaviors can't be used as a value in expressions."),
|
||||
identifierNameLocation);
|
||||
} else {
|
||||
// Assume type is String or equivalent.
|
||||
childType = Type::String;
|
||||
@@ -183,14 +198,14 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
return true; // We found a property.
|
||||
}, [&]() {
|
||||
// This is a parameter.
|
||||
if (!identifier.childIdentifierName.empty()) {
|
||||
if (!childIdentifierName.empty()) {
|
||||
RaiseTypeError(_("Accessing a child variable of a parameter is not possible - just write the parameter name."),
|
||||
identifier.childIdentifierNameLocation);
|
||||
childIdentifierNameLocation);
|
||||
|
||||
return true; // We found a parameter, even if the child is not allowed.
|
||||
}
|
||||
|
||||
const auto& parameter = gd::ParameterMetadataTools::Get(parametersVectorsList, identifier.identifierName);
|
||||
const auto& parameter = gd::ParameterMetadataTools::Get(parametersVectorsList, identifierName);
|
||||
const auto& valueTypeMetadata = parameter.GetValueTypeMetadata();
|
||||
if (valueTypeMetadata.IsNumber()) {
|
||||
childType = Type::Number;
|
||||
@@ -200,7 +215,7 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
// Nothing - we don't know the precise type (this could be used as a string or as a number).
|
||||
} else {
|
||||
RaiseTypeError(_("This parameter is not a string, number or boolean - it can't be used in an expression."),
|
||||
identifier.identifierNameLocation);
|
||||
identifierNameLocation);
|
||||
|
||||
return true; // We found a parameter, even though the type is incompatible.
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/Project/VariablesContainersList.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
|
||||
namespace gd {
|
||||
class Expression;
|
||||
@@ -42,10 +43,12 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
const gd::String &extraInfo_ = "")
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
parentType(StringToType(gd::ParameterMetadata::GetExpressionValueType(rootType_))),
|
||||
parentType(StringToType(gd::ValueTypeMetadata::GetExpressionPrimitiveValueType(rootType_))),
|
||||
childType(Type::Unknown),
|
||||
forbidsUsageOfBracketsBecauseParentIsObject(false),
|
||||
currentParameterExtraInfo(&extraInfo_) {};
|
||||
currentParameterExtraInfo(&extraInfo_),
|
||||
variableObjectName(),
|
||||
variableObjectNameLocation() {};
|
||||
virtual ~ExpressionValidator(){};
|
||||
|
||||
/**
|
||||
@@ -225,7 +228,8 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(node.name,
|
||||
[&]() {
|
||||
// This represents an object.
|
||||
|
||||
variableObjectName = node.name;
|
||||
variableObjectNameLocation = node.nameLocation;
|
||||
// While understood by the parser, it's forbidden to use the bracket notation just after
|
||||
// an object name (`MyObject["MyVariable"]`).
|
||||
forbidsUsageOfBracketsBecauseParentIsObject = true;
|
||||
@@ -264,7 +268,13 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
ReportAnyError(node);
|
||||
|
||||
// TODO Also check child-variables existence on a path with only VariableAccessor to raise non-fatal errors.
|
||||
if (!variableObjectName.empty()) {
|
||||
ValidateObjectVariableOrVariableOrProperty(variableObjectName,
|
||||
variableObjectNameLocation,
|
||||
node.name, node.nameLocation);
|
||||
variableObjectName = "";
|
||||
}
|
||||
// In the case we accessed an object variable (`MyObject.MyVariable`),
|
||||
// brackets can now be used (`MyObject.MyVariable["MyChildVariable"]` is now valid).
|
||||
forbidsUsageOfBracketsBecauseParentIsObject = false;
|
||||
@@ -277,6 +287,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
VariableBracketAccessorNode& node) override {
|
||||
ReportAnyError(node);
|
||||
|
||||
variableObjectName = "";
|
||||
if (forbidsUsageOfBracketsBecauseParentIsObject) {
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::BracketsNotAllowedForObjects,
|
||||
_("You can't use the brackets to access an object variable. "
|
||||
@@ -369,6 +380,11 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, LegacyVariable, Object, Empty};
|
||||
Type ValidateFunction(const gd::FunctionCallNode& function);
|
||||
bool ValidateObjectVariableOrVariableOrProperty(const gd::IdentifierNode& identifier);
|
||||
bool ValidateObjectVariableOrVariableOrProperty(
|
||||
const gd::String &identifierName,
|
||||
const gd::ExpressionParserLocation identifierNameLocation,
|
||||
const gd::String &childIdentifierName,
|
||||
const gd::ExpressionParserLocation childIdentifierNameLocation);
|
||||
|
||||
void CheckVariableExistence(const ExpressionParserLocation &location, const gd::String& name) {
|
||||
if (!currentParameterExtraInfo || *currentParameterExtraInfo != "AllowUndeclaredVariable") {
|
||||
@@ -505,6 +521,8 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
Type childType; ///< The type "discovered" down the tree and passed up.
|
||||
Type parentType; ///< The type "required" by the top of the tree.
|
||||
bool forbidsUsageOfBracketsBecauseParentIsObject;
|
||||
gd::String variableObjectName;
|
||||
gd::ExpressionParserLocation variableObjectNameLocation;
|
||||
const gd::String *currentParameterExtraInfo;
|
||||
const gd::Platform &platform;
|
||||
const gd::ProjectScopedContainers &projectScopedContainers;
|
||||
|
@@ -74,8 +74,8 @@ class GD_CORE_API ExpressionsParameterMover
|
||||
|
||||
const gd::Platform &platform;
|
||||
gd::String functionName;
|
||||
std::size_t oldIndex;
|
||||
std::size_t newIndex;
|
||||
std::size_t oldIndex = 0;
|
||||
std::size_t newIndex = 0;
|
||||
gd::String behaviorType;
|
||||
gd::String objectType;
|
||||
};
|
||||
|
76
Core/GDCore/IDE/Events/LeaderboardIdRenamer.cpp
Normal file
76
Core/GDCore/IDE/Events/LeaderboardIdRenamer.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "LeaderboardIdRenamer.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
void LeaderboardIdRenamer::DoVisitObject(gd::Object &object) {
|
||||
for (auto &pair : object.GetConfiguration().GetProperties()) {
|
||||
auto &propertyName = pair.first;
|
||||
auto &property = pair.second;
|
||||
if (property.GetType() == "LeaderboardId") {
|
||||
auto &leaderboardId = property.GetValue();
|
||||
|
||||
allLeaderboardIds.insert(leaderboardId);
|
||||
|
||||
if (leaderboardIdMap.find(leaderboardId) != leaderboardIdMap.end()) {
|
||||
object.GetConfiguration().UpdateProperty(
|
||||
propertyName, leaderboardIdMap[leaderboardId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void LeaderboardIdRenamer::DoVisitBehavior(gd::Behavior &behavior) {};
|
||||
|
||||
bool LeaderboardIdRenamer::DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) {
|
||||
const gd::InstructionMetadata &instrInfo =
|
||||
isCondition ? MetadataProvider::GetConditionMetadata(
|
||||
project.GetCurrentPlatform(), instruction.GetType())
|
||||
: MetadataProvider::GetActionMetadata(
|
||||
project.GetCurrentPlatform(), instruction.GetType());
|
||||
|
||||
for (int i = 0; i < instruction.GetParametersCount() &&
|
||||
i < instrInfo.GetParametersCount();
|
||||
++i) {
|
||||
const gd::ParameterMetadata parameter = instrInfo.GetParameter(i);
|
||||
|
||||
if (parameter.GetType() != "leaderboardId") {
|
||||
continue;
|
||||
}
|
||||
const gd::String leaderboardIdExpression =
|
||||
instruction.GetParameter(i).GetPlainString();
|
||||
if (leaderboardIdExpression[0] != '"' ||
|
||||
leaderboardIdExpression[leaderboardIdExpression.size() - 1] != '"') {
|
||||
continue;
|
||||
}
|
||||
const gd::String leaderboardId =
|
||||
leaderboardIdExpression.substr(1, leaderboardIdExpression.size() - 2);
|
||||
|
||||
allLeaderboardIds.insert(leaderboardId);
|
||||
|
||||
if (leaderboardIdMap.find(leaderboardId) != leaderboardIdMap.end()) {
|
||||
instruction.SetParameter(i,
|
||||
"\"" + leaderboardIdMap[leaderboardId] + "\"");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
LeaderboardIdRenamer::~LeaderboardIdRenamer() {}
|
||||
|
||||
} // namespace gd
|
50
Core/GDCore/IDE/Events/LeaderboardIdRenamer.h
Normal file
50
Core/GDCore/IDE/Events/LeaderboardIdRenamer.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <map>
|
||||
|
||||
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Object;
|
||||
class Behavior;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
class GD_CORE_API LeaderboardIdRenamer : public ArbitraryObjectsWorker, public ArbitraryEventsWorker {
|
||||
public:
|
||||
LeaderboardIdRenamer(gd::Project& project_): project(project_) {};
|
||||
virtual ~LeaderboardIdRenamer();
|
||||
|
||||
/**
|
||||
* Set the leaderboard identifiers to be replaced.
|
||||
*/
|
||||
void SetLeaderboardIdsToReplace(const std::map<gd::String, gd::String>& leaderboardIdMap_) {
|
||||
leaderboardIdMap = leaderboardIdMap_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the all the leaderboard identifiers found in the project.
|
||||
*/
|
||||
const std::set<gd::String>& GetAllLeaderboardIds() const {
|
||||
return allLeaderboardIds;
|
||||
}
|
||||
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction& instruction, bool isCondition) override;
|
||||
void DoVisitObject(gd::Object& object) override;
|
||||
void DoVisitBehavior(gd::Behavior& behavior) override;
|
||||
|
||||
std::map<gd::String, gd::String> leaderboardIdMap;
|
||||
std::set<gd::String> allLeaderboardIds;
|
||||
gd::Project& project;
|
||||
};
|
||||
|
||||
}; // namespace gd
|
@@ -24,15 +24,16 @@ void EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
// Functions scope for objects is defined according
|
||||
// to parameters
|
||||
outputObjectsContainer.GetObjects().clear();
|
||||
outputObjectsContainer.GetObjectGroups().Clear();
|
||||
|
||||
// to parameters.
|
||||
auto ¶meters = eventsFunction.GetParametersForEvents(functionContainer);
|
||||
gd::ParameterMetadataTools::ParametersToObjectsContainer(
|
||||
project,
|
||||
parameters,
|
||||
outputObjectsContainer);
|
||||
|
||||
// TODO: in theory we should ensure stability of the groups across calls
|
||||
// to this function. BUT groups in functions should probably have never been
|
||||
// supported, so we're phasing this out in the UI.
|
||||
outputObjectsContainer.GetObjectGroups() = eventsFunction.GetObjectGroups();
|
||||
}
|
||||
|
||||
@@ -97,26 +98,6 @@ void EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
"for the parent. ");
|
||||
return;
|
||||
}
|
||||
|
||||
gd::EventsFunctionTools::CopyEventsBasedObjectChildrenToObjectsContainer(
|
||||
eventsBasedObject, outputObjectsContainer);
|
||||
}
|
||||
|
||||
void EventsFunctionTools::CopyEventsBasedObjectChildrenToObjectsContainer(
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
auto &children = eventsBasedObject.GetObjects().GetObjects();
|
||||
for (auto &childObject : children) {
|
||||
auto child = childObject.get();
|
||||
outputObjectsContainer.InsertObject(
|
||||
*child, outputObjectsContainer.GetObjectsCount());
|
||||
}
|
||||
auto &childrenGroups = eventsBasedObject.GetObjects().GetObjectGroups();
|
||||
for (size_t index = 0; index < childrenGroups.Count(); ++index) {
|
||||
auto &childGroup = childrenGroups.Get(index);
|
||||
outputObjectsContainer.GetObjectGroups().Insert(
|
||||
childGroup, outputObjectsContainer.GetObjectGroups().Count());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -68,9 +68,5 @@ class GD_CORE_API EventsFunctionTools {
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
|
||||
static void CopyEventsBasedObjectChildrenToObjectsContainer(
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ObjectsContainer &outputObjectsContainer);
|
||||
};
|
||||
} // namespace gd
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
|
@@ -225,9 +225,7 @@ bool ResourceWorkerInEventsWorker::DoVisitInstruction(gd::Instruction& instructi
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName) {
|
||||
const String& parameterValue = parameterExpression.GetPlainString();
|
||||
if (parameterMetadata.GetType() ==
|
||||
"police" || // Should be renamed fontResource
|
||||
parameterMetadata.GetType() == "fontResource") {
|
||||
if (parameterMetadata.GetType() == "fontResource") {
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeFont(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
@@ -295,7 +293,7 @@ void ResourceWorkerInObjectsWorker::DoVisitObject(gd::Object &object) {
|
||||
};
|
||||
|
||||
void ResourceWorkerInObjectsWorker::DoVisitBehavior(gd::Behavior &behavior){
|
||||
// TODO Allow behaviors to expose resources
|
||||
behavior.ExposeResources(worker);
|
||||
};
|
||||
|
||||
gd::ResourceWorkerInObjectsWorker
|
||||
|
@@ -170,7 +170,8 @@ void ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
// Add (free) events functions
|
||||
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
|
||||
gd::ObjectsContainer parameterObjectsContainer;
|
||||
gd::ObjectsContainer parameterObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project, eventsFunctionsExtension, *eventsFunction,
|
||||
@@ -209,7 +210,8 @@ void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
auto &behaviorEventsFunctions = eventsBasedBehavior.GetEventsFunctions();
|
||||
for (auto &&eventsFunction : behaviorEventsFunctions.GetInternalVector()) {
|
||||
|
||||
gd::ObjectsContainer parameterObjectsContainers;
|
||||
gd::ObjectsContainer parameterObjectsContainers(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForBehaviorEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior,
|
||||
@@ -236,7 +238,8 @@ void ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
|
||||
auto &objectEventsFunctions = eventsBasedObject.GetEventsFunctions();
|
||||
for (auto &&eventsFunction : objectEventsFunctions.GetInternalVector()) {
|
||||
|
||||
gd::ObjectsContainer parameterObjectsContainers;
|
||||
gd::ObjectsContainer parameterObjectsContainers(
|
||||
gd::ObjectsContainer::SourceType::Function);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForObjectEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsBasedObject,
|
||||
|
@@ -247,7 +247,7 @@ bool PropertyFunctionGenerator::CanGenerateGetterAndSetter(
|
||||
const gd::NamedPropertyDescriptor &property) {
|
||||
auto &type = property.GetType();
|
||||
if (type != "Boolean" && type != "Number" && type != "String" &&
|
||||
type != "Choice" && type != "Color") {
|
||||
type != "Choice" && type != "Color" && type != "LeaderboardId") {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -6,17 +6,9 @@
|
||||
#include "ResourceExposer.h"
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/IDE/EventsFunctionTools.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryBehaviorSharedDataWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryEventBasedBehaviorsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryEventsFunctionsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/IDE/ProjectBrowserHelper.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/Effect.h"
|
||||
@@ -24,7 +16,6 @@
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
|
||||
#include "GDCore/IDE/Events/UsedExtensionsFinder.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
|
@@ -13,11 +13,13 @@
|
||||
#include "GDCore/IDE/DependenciesAnalyzer.h"
|
||||
#include "GDCore/IDE/GroupVariableHelper.h"
|
||||
#include "GDCore/IDE/EventBasedBehaviorBrowser.h"
|
||||
#include "GDCore/IDE/EventBasedObjectBrowser.h"
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/IDE/Events/BehaviorParametersFiller.h"
|
||||
#include "GDCore/IDE/Events/BehaviorTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/CustomObjectTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
|
||||
#include "GDCore/IDE/Events/EventsParameterReplacer.h"
|
||||
#include "GDCore/IDE/Events/EventsPropertyReplacer.h"
|
||||
#include "GDCore/IDE/Events/EventsRefactorer.h"
|
||||
#include "GDCore/IDE/Events/EventsVariableInstructionTypeSwitcher.h"
|
||||
@@ -27,12 +29,8 @@
|
||||
#include "GDCore/IDE/Events/InstructionsParameterMover.h"
|
||||
#include "GDCore/IDE/Events/InstructionsTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/LinkEventTargetRenamer.h"
|
||||
#include "GDCore/IDE/Events/LeaderboardIdRenamer.h"
|
||||
#include "GDCore/IDE/Events/ProjectElementRenamer.h"
|
||||
#include "GDCore/IDE/EventsFunctionTools.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryBehaviorSharedDataWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryEventBasedBehaviorsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryEventsFunctionsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
|
||||
#include "GDCore/IDE/Project/BehaviorObjectTypeRenamer.h"
|
||||
#include "GDCore/IDE/Project/BehaviorsSharedDataBehaviorTypeRenamer.h"
|
||||
#include "GDCore/IDE/Project/FunctionParameterBehaviorTypeRenamer.h"
|
||||
@@ -415,20 +413,32 @@ void WholeProjectRefactorer::UpdateExtensionNameInEventsBasedBehavior(
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::String &sourceExtensionName) {
|
||||
const EventBasedBehaviorBrowser eventBasedBehaviorExposer(
|
||||
const EventBasedBehaviorBrowser eventBasedBehaviorBrowser(
|
||||
eventsFunctionsExtension, eventsBasedBehavior);
|
||||
WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
project, eventsFunctionsExtension, sourceExtensionName,
|
||||
eventsFunctionsExtension.GetName(), eventBasedBehaviorExposer);
|
||||
eventsFunctionsExtension.GetName(), eventBasedBehaviorBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::UpdateExtensionNameInEventsBasedObject(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::String &sourceExtensionName) {
|
||||
const EventBasedObjectBrowser eventBasedObjectBrowser(
|
||||
eventsFunctionsExtension, eventsBasedObject);
|
||||
WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
project, eventsFunctionsExtension, sourceExtensionName,
|
||||
eventsFunctionsExtension.GetName(), eventBasedObjectBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::String &oldName, const gd::String &newName) {
|
||||
const WholeProjectBrowser wholeProjectExposer;
|
||||
const WholeProjectBrowser wholeProjectBrowser;
|
||||
RenameEventsFunctionsExtension(project, eventsFunctionsExtension, oldName,
|
||||
newName, wholeProjectExposer);
|
||||
newName, wholeProjectBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
@@ -807,6 +817,51 @@ void WholeProjectRefactorer::RenameObjectEventsFunction(
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameParameter(
|
||||
gd::Project &project, gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::EventsFunction &eventsFunction,
|
||||
const gd::ObjectsContainer ¶meterObjectsContainer,
|
||||
const gd::String &oldParameterName, const gd::String &newParameterName) {
|
||||
auto ¶meters = eventsFunction.GetParameters();
|
||||
if (!parameters.HasParameterNamed(oldParameterName))
|
||||
return;
|
||||
auto ¶meter = parameters.GetParameter(oldParameterName);
|
||||
if (parameter.GetValueTypeMetadata().IsObject()) {
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
project, projectScopedContainers, eventsFunction,
|
||||
parameterObjectsContainer, oldParameterName, newParameterName, false);
|
||||
} else if (parameter.GetValueTypeMetadata().IsBehavior()) {
|
||||
size_t behaviorParameterIndex = parameters.GetParameterPosition(parameter);
|
||||
size_t objectParameterIndex =
|
||||
gd::ParameterMetadataTools::GetObjectParameterIndexFor(
|
||||
parameters, behaviorParameterIndex);
|
||||
if (objectParameterIndex == gd::String::npos) {
|
||||
return;
|
||||
}
|
||||
const gd::String &objectName =
|
||||
parameters.GetParameter(objectParameterIndex).GetName();
|
||||
gd::EventsBehaviorRenamer behaviorRenamer(project.GetCurrentPlatform(),
|
||||
objectName, oldParameterName,
|
||||
newParameterName);
|
||||
behaviorRenamer.Launch(eventsFunction.GetEvents(), projectScopedContainers);
|
||||
} else {
|
||||
// Rename parameter names directly used as an identifier.
|
||||
std::unordered_map<gd::String, gd::String> oldToNewParameterNames = {
|
||||
{oldParameterName, newParameterName}};
|
||||
gd::EventsParameterReplacer eventsParameterReplacer(
|
||||
project.GetCurrentPlatform(), oldToNewParameterNames);
|
||||
eventsParameterReplacer.Launch(eventsFunction.GetEvents(),
|
||||
projectScopedContainers);
|
||||
|
||||
// Rename parameter names in legacy expressions and instructions
|
||||
gd::ProjectElementRenamer projectElementRenamer(
|
||||
project.GetCurrentPlatform(), "functionParameterName", oldParameterName,
|
||||
newParameterName);
|
||||
projectElementRenamer.Launch(eventsFunction.GetEvents(),
|
||||
projectScopedContainers);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::MoveEventsFunctionParameter(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
@@ -941,6 +996,8 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
// Order is important: we first rename the expressions then the
|
||||
// instructions, to avoid being unable to fetch the metadata (the types of
|
||||
// parameters) of instructions after they are renamed.
|
||||
|
||||
// Rename legacy expressions like: Object.Behavior::PropertyMyPropertyName()
|
||||
gd::ExpressionsRenamer expressionRenamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
expressionRenamer.SetReplacedBehaviorExpression(
|
||||
@@ -950,14 +1007,16 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
|
||||
|
||||
// Rename property names directly used as an identifier.
|
||||
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
|
||||
{oldPropertyName, newPropertyName}};
|
||||
std::unordered_set<gd::String> removedPropertyNames;
|
||||
gd::EventsPropertyReplacer eventsPropertyReplacer(
|
||||
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
|
||||
removedPropertyNames);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
|
||||
eventsPropertyReplacer);
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior,
|
||||
eventsPropertyReplacer);
|
||||
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -1012,6 +1071,8 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
|
||||
// Order is important: we first rename the expressions then the
|
||||
// instructions, to avoid being unable to fetch the metadata (the types of
|
||||
// parameters) of instructions after they are renamed.
|
||||
|
||||
// Rename legacy expressions like: Object.Behavior::SharedPropertyMyPropertyName()
|
||||
gd::ExpressionsRenamer expressionRenamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
expressionRenamer.SetReplacedBehaviorExpression(
|
||||
@@ -1021,14 +1082,16 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
|
||||
EventsBasedBehavior::GetSharedPropertyExpressionName(newPropertyName));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
|
||||
|
||||
// Rename property names directly used as an identifier.
|
||||
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
|
||||
{oldPropertyName, newPropertyName}};
|
||||
std::unordered_set<gd::String> removedPropertyNames;
|
||||
gd::EventsPropertyReplacer eventsPropertyReplacer(
|
||||
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
|
||||
removedPropertyNames);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
|
||||
eventsPropertyReplacer);
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior,
|
||||
eventsPropertyReplacer);
|
||||
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -1069,6 +1132,8 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
|
||||
// Order is important: we first rename the expressions then the
|
||||
// instructions, to avoid being unable to fetch the metadata (the types of
|
||||
// parameters) of instructions after they are renamed.
|
||||
|
||||
// Rename legacy expressions like: Object.PropertyMyPropertyName()
|
||||
gd::ExpressionsRenamer expressionRenamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
expressionRenamer.SetReplacedObjectExpression(
|
||||
@@ -1078,14 +1143,16 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
|
||||
EventsBasedObject::GetPropertyExpressionName(newPropertyName));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
|
||||
|
||||
// Rename property names directly used as an identifier.
|
||||
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
|
||||
{oldPropertyName, newPropertyName}};
|
||||
std::unordered_set<gd::String> removedPropertyNames;
|
||||
gd::EventsPropertyReplacer eventsPropertyReplacer(
|
||||
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
|
||||
removedPropertyNames);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
|
||||
eventsPropertyReplacer);
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
|
||||
project, eventsFunctionsExtension, eventsBasedObject,
|
||||
eventsPropertyReplacer);
|
||||
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -1312,6 +1379,19 @@ bool WholeProjectRefactorer::FixInvalidRequiredBehaviorProperties(
|
||||
return !invalidRequiredBehaviorProblems.empty();
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::UpdateBehaviorNameInEventsBasedBehavior(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::String &sourceBehaviorName) {
|
||||
const EventBasedBehaviorBrowser eventBasedBehaviorExposer(
|
||||
eventsFunctionsExtension, eventsBasedBehavior);
|
||||
WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior,
|
||||
sourceBehaviorName, eventsBasedBehavior.GetName(),
|
||||
eventBasedBehaviorExposer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
@@ -1324,10 +1404,22 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
return;
|
||||
}
|
||||
auto &eventsBasedBehavior = eventsBasedBehaviors.Get(oldBehaviorName);
|
||||
const WholeProjectBrowser projectBrowser;
|
||||
WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior, oldBehaviorName,
|
||||
newBehaviorName, projectBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::String &oldBehaviorName,
|
||||
const gd::String &newBehaviorName,
|
||||
const gd::ProjectBrowser &projectBrowser) {
|
||||
auto renameBehaviorEventsFunction =
|
||||
[&project, &eventsFunctionsExtension, &oldBehaviorName,
|
||||
&newBehaviorName](const gd::EventsFunction &eventsFunction) {
|
||||
&newBehaviorName, &projectBrowser](const gd::EventsFunction &eventsFunction) {
|
||||
if (eventsFunction.IsExpression()) {
|
||||
// Nothing to do, expressions are not including the name of the
|
||||
// behavior
|
||||
@@ -1341,12 +1433,12 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), newBehaviorName,
|
||||
eventsFunction.GetName()));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, renamer);
|
||||
projectBrowser.ExposeEvents(project, renamer);
|
||||
}
|
||||
};
|
||||
|
||||
auto renameBehaviorProperty = [&project, &eventsFunctionsExtension,
|
||||
&oldBehaviorName, &newBehaviorName](
|
||||
&oldBehaviorName, &newBehaviorName, &projectBrowser](
|
||||
const gd::NamedPropertyDescriptor
|
||||
&property) {
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
@@ -1357,7 +1449,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), newBehaviorName,
|
||||
EventsBasedBehavior::GetPropertyActionName(property.GetName())));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer);
|
||||
projectBrowser.ExposeEvents(project, actionRenamer);
|
||||
|
||||
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -1367,7 +1459,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), newBehaviorName,
|
||||
EventsBasedBehavior::GetPropertyConditionName(property.GetName())));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, conditionRenamer);
|
||||
projectBrowser.ExposeEvents(project, conditionRenamer);
|
||||
|
||||
// Nothing to do for expression, expressions are not including the name of
|
||||
// the behavior
|
||||
@@ -1375,7 +1467,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
|
||||
auto renameBehaviorSharedProperty =
|
||||
[&project, &eventsFunctionsExtension, &oldBehaviorName,
|
||||
&newBehaviorName](const gd::NamedPropertyDescriptor &property) {
|
||||
&newBehaviorName, &projectBrowser](const gd::NamedPropertyDescriptor &property) {
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
@@ -1386,7 +1478,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
eventsFunctionsExtension.GetName(), newBehaviorName,
|
||||
EventsBasedBehavior::GetSharedPropertyActionName(
|
||||
property.GetName())));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer);
|
||||
projectBrowser.ExposeEvents(project, actionRenamer);
|
||||
|
||||
gd::InstructionsTypeRenamer conditionRenamer =
|
||||
gd::InstructionsTypeRenamer(
|
||||
@@ -1399,8 +1491,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
eventsFunctionsExtension.GetName(), newBehaviorName,
|
||||
EventsBasedBehavior::GetSharedPropertyConditionName(
|
||||
property.GetName())));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
|
||||
conditionRenamer);
|
||||
projectBrowser.ExposeEvents(project, conditionRenamer);
|
||||
|
||||
// Nothing to do for expression, expressions are not including the name
|
||||
// of the behavior
|
||||
@@ -1435,13 +1526,25 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
renameBehaviorSharedProperty(*property);
|
||||
}
|
||||
|
||||
const WholeProjectBrowser wholeProjectExposer;
|
||||
DoRenameBehavior(project,
|
||||
gd::PlatformExtension::GetBehaviorFullType(
|
||||
eventsFunctionsExtension.GetName(), oldBehaviorName),
|
||||
gd::PlatformExtension::GetBehaviorFullType(
|
||||
eventsFunctionsExtension.GetName(), newBehaviorName),
|
||||
wholeProjectExposer);
|
||||
projectBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::UpdateObjectNameInEventsBasedObject(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::String &sourceObjectName) {
|
||||
const EventBasedObjectBrowser eventBasedObjectBrowser(
|
||||
eventsFunctionsExtension, eventsBasedObject);
|
||||
WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
project, eventsFunctionsExtension, eventsBasedObject,
|
||||
sourceObjectName, eventsBasedObject.GetName(),
|
||||
eventBasedObjectBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
@@ -1455,10 +1558,21 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
return;
|
||||
}
|
||||
auto &eventsBasedObject = eventsBasedObjects.Get(oldObjectName);
|
||||
const WholeProjectBrowser projectBrowser;
|
||||
WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
project, eventsFunctionsExtension, eventsBasedObject, oldObjectName,
|
||||
newObjectName, projectBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::String &oldObjectName, const gd::String &newObjectName,
|
||||
const gd::ProjectBrowser &projectBrowser) {
|
||||
auto renameObjectEventsFunction =
|
||||
[&project, &eventsFunctionsExtension, &oldObjectName,
|
||||
&newObjectName](const gd::EventsFunction &eventsFunction) {
|
||||
[&project, &eventsFunctionsExtension, &oldObjectName, &newObjectName,
|
||||
&projectBrowser](const gd::EventsFunction &eventsFunction) {
|
||||
if (eventsFunction.IsExpression()) {
|
||||
// Nothing to do, expressions are not including the name of the
|
||||
// object
|
||||
@@ -1472,12 +1586,12 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), newObjectName,
|
||||
eventsFunction.GetName()));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, renamer);
|
||||
projectBrowser.ExposeEvents(project, renamer);
|
||||
}
|
||||
};
|
||||
|
||||
auto renameObjectProperty = [&project, &eventsFunctionsExtension,
|
||||
&oldObjectName, &newObjectName](
|
||||
&oldObjectName, &newObjectName, &projectBrowser](
|
||||
const gd::NamedPropertyDescriptor &property) {
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -1487,7 +1601,7 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), newObjectName,
|
||||
EventsBasedObject::GetPropertyActionName(property.GetName())));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer);
|
||||
projectBrowser.ExposeEvents(project, actionRenamer);
|
||||
|
||||
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -1497,7 +1611,7 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), newObjectName,
|
||||
EventsBasedObject::GetPropertyConditionName(property.GetName())));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, conditionRenamer);
|
||||
projectBrowser.ExposeEvents(project, conditionRenamer);
|
||||
|
||||
// Nothing to do for expression, expressions are not including the name of
|
||||
// the object
|
||||
@@ -1528,13 +1642,12 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
renameObjectProperty(*property);
|
||||
}
|
||||
|
||||
const WholeProjectBrowser wholeProjectExposer;
|
||||
DoRenameObject(project,
|
||||
gd::PlatformExtension::GetObjectFullType(
|
||||
eventsFunctionsExtension.GetName(), oldObjectName),
|
||||
gd::PlatformExtension::GetObjectFullType(
|
||||
eventsFunctionsExtension.GetName(), newObjectName),
|
||||
wholeProjectExposer);
|
||||
projectBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::DoRenameEventsFunction(
|
||||
@@ -1638,6 +1751,15 @@ void WholeProjectRefactorer::BehaviorsAddedToObjectInScene(
|
||||
void WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
|
||||
gd::Project &project, gd::Layout &layout, const gd::String &oldName,
|
||||
const gd::String &newName, bool isObjectGroup) {
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
|
||||
project, layout, layout.GetObjects(), oldName, newName, isObjectGroup);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
|
||||
gd::Project &project, gd::Layout &layout,
|
||||
const gd::ObjectsContainer &targetedObjectsContainer,
|
||||
const gd::String &oldName, const gd::String &newName, bool isObjectGroup) {
|
||||
|
||||
if (oldName == newName || newName.empty() || oldName.empty())
|
||||
return;
|
||||
|
||||
@@ -1647,7 +1769,7 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
|
||||
// Rename object in the current layout
|
||||
gd::EventsRefactorer::RenameObjectInEvents(
|
||||
project.GetCurrentPlatform(), projectScopedContainers, layout.GetEvents(),
|
||||
oldName, newName);
|
||||
layout.GetObjects(), oldName, newName);
|
||||
|
||||
// Object groups can't have instances or be in other groups
|
||||
if (!isObjectGroup) {
|
||||
@@ -1664,7 +1786,7 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInScene(
|
||||
auto &externalEvents = project.GetExternalEvents(externalEventsName);
|
||||
gd::EventsRefactorer::RenameObjectInEvents(
|
||||
project.GetCurrentPlatform(), projectScopedContainers,
|
||||
externalEvents.GetEvents(), oldName, newName);
|
||||
externalEvents.GetEvents(), layout.GetObjects(), oldName, newName);
|
||||
}
|
||||
|
||||
// Rename object in external layouts
|
||||
@@ -1910,8 +2032,8 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
|
||||
eventsBasedObject.GetEventsFunctions().GetInternalVector()) {
|
||||
auto *function = functionUniquePtr.get();
|
||||
WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
project, projectScopedContainers, *function, oldName, newName,
|
||||
isObjectGroup);
|
||||
project, projectScopedContainers, *function,
|
||||
eventsBasedObject.GetObjects(), oldName, newName, isObjectGroup);
|
||||
}
|
||||
|
||||
// Object groups can't have instances or be in other groups
|
||||
@@ -1928,11 +2050,12 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
|
||||
void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
gd::Project &project,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::EventsFunction &eventsFunction, const gd::String &oldName,
|
||||
const gd::String &newName, bool isObjectGroup) {
|
||||
gd::EventsFunction &eventsFunction,
|
||||
const gd::ObjectsContainer &targetedObjectsContainer,
|
||||
const gd::String &oldName, const gd::String &newName, bool isObjectGroup) {
|
||||
gd::EventsRefactorer::RenameObjectInEvents(
|
||||
project.GetCurrentPlatform(), projectScopedContainers,
|
||||
eventsFunction.GetEvents(), oldName, newName);
|
||||
eventsFunction.GetEvents(), targetedObjectsContainer, oldName, newName);
|
||||
|
||||
// Object groups can't be in other groups
|
||||
if (!isObjectGroup) {
|
||||
@@ -1958,7 +2081,7 @@ void WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
|
||||
if (layout.GetObjects().HasObjectNamed(oldName))
|
||||
continue;
|
||||
|
||||
ObjectOrGroupRenamedInScene(project, layout, oldName, newName,
|
||||
ObjectOrGroupRenamedInScene(project, layout, project.GetObjects(), oldName, newName,
|
||||
isObjectGroup);
|
||||
}
|
||||
}
|
||||
@@ -2090,4 +2213,23 @@ std::vector<gd::String> WholeProjectRefactorer::GetAssociatedExternalEvents(
|
||||
return results;
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameLeaderboards(
|
||||
gd::Project &project,
|
||||
const std::map<gd::String, gd::String> &leaderboardIdMap) {
|
||||
gd::LeaderboardIdRenamer leaderboardIdRenamer(project);
|
||||
leaderboardIdRenamer.SetLeaderboardIdsToReplace(leaderboardIdMap);
|
||||
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, leaderboardIdRenamer);
|
||||
gd::ProjectBrowserHelper::ExposeProjectObjects(project, leaderboardIdRenamer);
|
||||
}
|
||||
|
||||
std::set<gd::String> WholeProjectRefactorer::FindAllLeaderboardIds(gd::Project &project) {
|
||||
gd::LeaderboardIdRenamer leaderboardIdRenamer(project);
|
||||
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, leaderboardIdRenamer);
|
||||
gd::ProjectBrowserHelper::ExposeProjectObjects(project, leaderboardIdRenamer);
|
||||
|
||||
return leaderboardIdRenamer.GetAllLeaderboardIds();
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -27,14 +27,7 @@ class ObjectsContainer;
|
||||
class VariablesContainer;
|
||||
class EventsBasedBehavior;
|
||||
class EventsBasedObject;
|
||||
class ArbitraryEventsWorker;
|
||||
class ArbitraryObjectsWorker;
|
||||
class ArbitraryEventsFunctionsWorker;
|
||||
class ArbitraryEventsWorkerWithContext;
|
||||
class ArbitraryEventBasedBehaviorsWorker;
|
||||
class ArbitraryBehaviorSharedDataWorker;
|
||||
class Behavior;
|
||||
class BehaviorMetadata;
|
||||
class UnfilledRequiredBehaviorPropertyProblem;
|
||||
class ProjectBrowser;
|
||||
class SerializerElement;
|
||||
@@ -121,14 +114,24 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& newName);
|
||||
|
||||
/**
|
||||
* \brief Refactor behavior events after the extension was placed in a new
|
||||
* \brief Refactor behavior events after the behavior has been placed in a new
|
||||
* extension.
|
||||
*/
|
||||
static void UpdateExtensionNameInEventsBasedBehavior(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::String& sourceExtensionName);
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::String &sourceExtensionName);
|
||||
|
||||
/**
|
||||
* \brief Refactor object events after the object has been placed in a new
|
||||
* extension.
|
||||
*/
|
||||
static void UpdateExtensionNameInEventsBasedObject(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::String &sourceExtensionName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** an events function is renamed.
|
||||
@@ -173,6 +176,21 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& oldFunctionName,
|
||||
const gd::String& newFunctionName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the function **before** a parameter is renamed.
|
||||
*
|
||||
* \warning Do the renaming of the specified parameter after calling this.
|
||||
* This is because the function is expected to have its old name for the
|
||||
* refactoring.
|
||||
*/
|
||||
static void
|
||||
RenameParameter(gd::Project &project,
|
||||
gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::EventsFunction &eventsFunction,
|
||||
const gd::ObjectsContainer ¶meterObjectsContainer,
|
||||
const gd::String &oldParameterName,
|
||||
const gd::String &newParameterName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** an events function parameter
|
||||
* is moved.
|
||||
@@ -324,6 +342,16 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& oldBehaviorName,
|
||||
const gd::String& newBehaviorName);
|
||||
|
||||
/**
|
||||
* \brief Refactor events-based behavior events after the events-based
|
||||
* behavior has been duplicated.
|
||||
*/
|
||||
static void UpdateBehaviorNameInEventsBasedBehavior(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::String &sourceBehaviorName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** an object is renamed.
|
||||
*
|
||||
@@ -337,6 +365,16 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& oldObjectName,
|
||||
const gd::String& newObjectName);
|
||||
|
||||
/**
|
||||
* \brief Refactor events-based object events after the events-based object
|
||||
* has been duplicated.
|
||||
*/
|
||||
static void UpdateObjectNameInEventsBasedObject(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::String &sourceObjectName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after a layout is renamed.
|
||||
*/
|
||||
@@ -506,6 +544,7 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
gd::Project& project,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::EventsFunction& eventsFunction,
|
||||
const gd::ObjectsContainer &targetedObjectsContainer,
|
||||
const gd::String& oldName,
|
||||
const gd::String& newName,
|
||||
bool isObjectGroup);
|
||||
@@ -604,6 +643,18 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String &originLayerName,
|
||||
const gd::String &targetLayerName);
|
||||
|
||||
/**
|
||||
* \brief Replace the leaderboard ids in the whole project.
|
||||
*/
|
||||
static void
|
||||
RenameLeaderboards(gd::Project &project,
|
||||
const std::map<gd::String, gd::String> &leaderboardIdMap);
|
||||
|
||||
/**
|
||||
* \brief Find all the leaderboard identifiers in the whole project.
|
||||
*/
|
||||
static std::set<gd::String> FindAllLeaderboardIds(gd::Project &project);
|
||||
|
||||
/**
|
||||
* \brief Return the number of instances on the layer named \a layerName and
|
||||
* all its associated layouts.
|
||||
@@ -614,6 +665,12 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
virtual ~WholeProjectRefactorer(){};
|
||||
|
||||
private:
|
||||
static void ObjectOrGroupRenamedInScene(gd::Project &project,
|
||||
gd::Layout &scene,
|
||||
const gd::ObjectsContainer &targetedObjectsContainer,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName,
|
||||
bool isObjectGroup);
|
||||
static std::vector<gd::String> GetAssociatedExternalLayouts(
|
||||
gd::Project& project, gd::Layout& layout);
|
||||
static std::vector<gd::String>
|
||||
@@ -654,6 +711,35 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& newName,
|
||||
const gd::ProjectBrowser& projectBrowser);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** a behavior is renamed.
|
||||
*
|
||||
* \warning Do the renaming of the specified behavior after calling this.
|
||||
* This is because the behavior is expected to have its old name for the
|
||||
* refactoring.
|
||||
*/
|
||||
static void RenameEventsBasedBehavior(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::String &oldBehaviorName,
|
||||
const gd::String &newBehaviorName,
|
||||
const gd::ProjectBrowser &projectBrowser);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** an object is renamed.
|
||||
*
|
||||
* \warning Do the renaming of the specified object after calling this.
|
||||
* This is because the object is expected to have its old name for the
|
||||
* refactoring.
|
||||
*/
|
||||
static void RenameEventsBasedObject(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::String &oldObjectName, const gd::String &newObjectName,
|
||||
const gd::ProjectBrowser &projectBrowser);
|
||||
|
||||
static void FindDependentBehaviorNames(
|
||||
const gd::Project& project,
|
||||
const gd::Object& object,
|
||||
|
@@ -6,6 +6,7 @@
|
||||
#include "GDCore/Project/BehaviorConfigurationContainer.h"
|
||||
#include <iostream>
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -22,4 +23,48 @@ std::map<gd::String, gd::PropertyDescriptor> BehaviorConfigurationContainer::Get
|
||||
return nothing;
|
||||
}
|
||||
|
||||
void BehaviorConfigurationContainer::ExposeResources(gd::ArbitraryResourceWorker& worker) {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties = GetProperties();
|
||||
|
||||
for (auto& property : properties) {
|
||||
const String& propertyName = property.first;
|
||||
const gd::PropertyDescriptor& propertyDescriptor = property.second;
|
||||
|
||||
if (propertyDescriptor.GetType().LowerCase() == "resource") {
|
||||
auto& extraInfo = propertyDescriptor.GetExtraInfo();
|
||||
const gd::String& resourceType = extraInfo.empty() ? "" : extraInfo[0];
|
||||
const gd::String& oldPropertyValue = propertyDescriptor.GetValue();
|
||||
|
||||
gd::String newPropertyValue = oldPropertyValue;
|
||||
if (resourceType == "image") {
|
||||
worker.ExposeImage(newPropertyValue);
|
||||
} else if (resourceType == "audio") {
|
||||
worker.ExposeAudio(newPropertyValue);
|
||||
} else if (resourceType == "font") {
|
||||
worker.ExposeFont(newPropertyValue);
|
||||
} else if (resourceType == "video") {
|
||||
worker.ExposeVideo(newPropertyValue);
|
||||
} else if (resourceType == "json") {
|
||||
worker.ExposeJson(newPropertyValue);
|
||||
} else if (resourceType == "tilemap") {
|
||||
worker.ExposeTilemap(newPropertyValue);
|
||||
} else if (resourceType == "tileset") {
|
||||
worker.ExposeTileset(newPropertyValue);
|
||||
} else if (resourceType == "bitmapFont") {
|
||||
worker.ExposeBitmapFont(newPropertyValue);
|
||||
} else if (resourceType == "model3D") {
|
||||
worker.ExposeModel3D(newPropertyValue);
|
||||
} else if (resourceType == "atlas") {
|
||||
worker.ExposeAtlas(newPropertyValue);
|
||||
} else if (resourceType == "spine") {
|
||||
worker.ExposeSpine(newPropertyValue);
|
||||
}
|
||||
|
||||
if (newPropertyValue != oldPropertyValue) {
|
||||
UpdateProperty(propertyName, newPropertyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -3,13 +3,14 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_BEHAVIORCONFIGURATIONCONTAINER_H
|
||||
#define GDCORE_BEHAVIORCONFIGURATIONCONTAINER_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
|
||||
#include "GDCore/Project/QuickCustomization.h"
|
||||
#include "GDCore/Project/QuickCustomizationVisibilitiesContainer.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
@@ -17,6 +18,7 @@ class PropertyDescriptor;
|
||||
class SerializerElement;
|
||||
class Project;
|
||||
class Layout;
|
||||
class ArbitraryResourceWorker;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -32,12 +34,21 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API BehaviorConfigurationContainer {
|
||||
public:
|
||||
BehaviorConfigurationContainer() : folded(false), quickCustomizationVisibility(QuickCustomization::Visibility::Default){};
|
||||
BehaviorConfigurationContainer()
|
||||
: folded(false),
|
||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default),
|
||||
propertiesQuickCustomizationVisibilities() {};
|
||||
BehaviorConfigurationContainer(const gd::String& name_,
|
||||
const gd::String& type_)
|
||||
: name(name_), type(type_), folded(false), quickCustomizationVisibility(QuickCustomization::Visibility::Default){};
|
||||
: name(name_),
|
||||
type(type_),
|
||||
folded(false),
|
||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default),
|
||||
propertiesQuickCustomizationVisibilities() {};
|
||||
virtual ~BehaviorConfigurationContainer();
|
||||
virtual BehaviorConfigurationContainer* Clone() const { return new BehaviorConfigurationContainer(*this); }
|
||||
virtual BehaviorConfigurationContainer* Clone() const {
|
||||
return new BehaviorConfigurationContainer(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the name identifying the behavior
|
||||
@@ -68,7 +79,6 @@ class GD_CORE_API BehaviorConfigurationContainer {
|
||||
*/
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to update a custom property of the
|
||||
* behavior
|
||||
@@ -84,9 +94,7 @@ class GD_CORE_API BehaviorConfigurationContainer {
|
||||
* \brief Called to initialize the content with the default properties
|
||||
* for the behavior.
|
||||
*/
|
||||
virtual void InitializeContent() {
|
||||
InitializeContent(content);
|
||||
};
|
||||
virtual void InitializeContent() { InitializeContent(content); };
|
||||
|
||||
/**
|
||||
* \brief Serialize the behavior content.
|
||||
@@ -115,15 +123,54 @@ class GD_CORE_API BehaviorConfigurationContainer {
|
||||
*/
|
||||
bool IsFolded() const { return folded; }
|
||||
|
||||
void SetQuickCustomizationVisibility(QuickCustomization::Visibility visibility) {
|
||||
/**
|
||||
* @brief Set if the whole behavior should be visible or not in the Quick
|
||||
* Customization.
|
||||
*/
|
||||
void SetQuickCustomizationVisibility(
|
||||
QuickCustomization::Visibility visibility) {
|
||||
quickCustomizationVisibility = visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get if the whole behavior should be visible or not in the Quick
|
||||
* Customization.
|
||||
*/
|
||||
QuickCustomization::Visibility GetQuickCustomizationVisibility() const {
|
||||
return quickCustomizationVisibility;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Get the map of properties and their visibility in the Quick
|
||||
* Customization.
|
||||
*/
|
||||
QuickCustomizationVisibilitiesContainer&
|
||||
GetPropertiesQuickCustomizationVisibilities() {
|
||||
return propertiesQuickCustomizationVisibilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the map of properties and their visibility in the Quick
|
||||
* Customization.
|
||||
*/
|
||||
const QuickCustomizationVisibilitiesContainer&
|
||||
GetPropertiesQuickCustomizationVisibilities() const {
|
||||
return propertiesQuickCustomizationVisibilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Called ( e.g. during compilation ) so as to inventory internal
|
||||
* resources and sometimes update their filename. Implementation example:
|
||||
* \code
|
||||
* worker.ExposeImage(myImage);
|
||||
* worker.ExposeFile(myResourceFile);
|
||||
* \endcode
|
||||
*
|
||||
* \see ArbitraryResourceWorker
|
||||
*/
|
||||
void ExposeResources(gd::ArbitraryResourceWorker& worker);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief Called when the IDE wants to know about the custom properties of the
|
||||
* behavior.
|
||||
@@ -159,7 +206,7 @@ protected:
|
||||
* \brief Called to initialize the content with the default properties
|
||||
* for the behavior.
|
||||
*/
|
||||
virtual void InitializeContent(gd::SerializerElement& behaviorContent){};
|
||||
virtual void InitializeContent(gd::SerializerElement& behaviorContent) {};
|
||||
|
||||
private:
|
||||
gd::String name; ///< Name of the behavior
|
||||
@@ -169,8 +216,8 @@ protected:
|
||||
gd::SerializerElement content; // Storage for the behavior properties
|
||||
bool folded;
|
||||
QuickCustomization::Visibility quickCustomizationVisibility;
|
||||
QuickCustomizationVisibilitiesContainer
|
||||
propertiesQuickCustomizationVisibilities;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_BEHAVIORCONFIGURATIONCONTAINER_H
|
||||
|
@@ -26,7 +26,7 @@ void CustomConfigurationHelper::InitializeContent(
|
||||
|
||||
if (propertyType == "String" || propertyType == "Choice" ||
|
||||
propertyType == "Color" || propertyType == "Behavior" ||
|
||||
propertyType == "Resource") {
|
||||
propertyType == "Resource" || propertyType == "LeaderboardId") {
|
||||
element.SetStringValue(property->GetValue());
|
||||
} else if (propertyType == "Number") {
|
||||
element.SetDoubleValue(property->GetValue().To<double>());
|
||||
@@ -39,21 +39,21 @@ void CustomConfigurationHelper::InitializeContent(
|
||||
std::map<gd::String, gd::PropertyDescriptor> CustomConfigurationHelper::GetProperties(
|
||||
const gd::PropertiesContainer &properties,
|
||||
const gd::SerializerElement &configurationContent) {
|
||||
auto behaviorProperties = std::map<gd::String, gd::PropertyDescriptor>();
|
||||
auto objectProperties = std::map<gd::String, gd::PropertyDescriptor>();
|
||||
|
||||
for (auto &property : properties.GetInternalVector()) {
|
||||
const auto &propertyName = property->GetName();
|
||||
const auto &propertyType = property->GetType();
|
||||
|
||||
// Copy the property
|
||||
behaviorProperties[propertyName] = *property;
|
||||
objectProperties[propertyName] = *property;
|
||||
|
||||
auto &newProperty = behaviorProperties[propertyName];
|
||||
auto &newProperty = objectProperties[propertyName];
|
||||
|
||||
if (configurationContent.HasChild(propertyName)) {
|
||||
if (propertyType == "String" || propertyType == "Choice" ||
|
||||
propertyType == "Color" || propertyType == "Behavior" ||
|
||||
propertyType == "Resource") {
|
||||
propertyType == "Resource" || propertyType == "LeaderboardId") {
|
||||
newProperty.SetValue(
|
||||
configurationContent.GetChild(propertyName).GetStringValue());
|
||||
} else if (propertyType == "Number") {
|
||||
@@ -71,7 +71,7 @@ std::map<gd::String, gd::PropertyDescriptor> CustomConfigurationHelper::GetPrope
|
||||
}
|
||||
}
|
||||
|
||||
return behaviorProperties;
|
||||
return objectProperties;
|
||||
}
|
||||
|
||||
bool CustomConfigurationHelper::UpdateProperty(
|
||||
@@ -89,7 +89,7 @@ bool CustomConfigurationHelper::UpdateProperty(
|
||||
|
||||
if (propertyType == "String" || propertyType == "Choice" ||
|
||||
propertyType == "Color" || propertyType == "Behavior" ||
|
||||
propertyType == "Resource") {
|
||||
propertyType == "Resource" || propertyType == "LeaderboardId") {
|
||||
element.SetStringValue(newValue);
|
||||
} else if (propertyType == "Number") {
|
||||
element.SetDoubleValue(newValue.To<double>());
|
||||
|
@@ -21,6 +21,9 @@ void CustomObjectConfiguration::Init(const gd::CustomObjectConfiguration& object
|
||||
project = objectConfiguration.project;
|
||||
objectContent = objectConfiguration.objectContent;
|
||||
animations = objectConfiguration.animations;
|
||||
isMarkedAsOverridingEventsBasedObjectChildrenConfiguration =
|
||||
objectConfiguration
|
||||
.isMarkedAsOverridingEventsBasedObjectChildrenConfiguration;
|
||||
|
||||
// There is no default copy for a map of unique_ptr like childObjectConfigurations.
|
||||
childObjectConfigurations.clear();
|
||||
@@ -42,6 +45,26 @@ const gd::EventsBasedObject* CustomObjectConfiguration::GetEventsBasedObject() c
|
||||
return &project->GetEventsBasedObject(GetType());
|
||||
}
|
||||
|
||||
bool CustomObjectConfiguration::
|
||||
IsForcedToOverrideEventsBasedObjectChildrenConfiguration() const {
|
||||
const auto *eventsBasedObject = GetEventsBasedObject();
|
||||
if (!eventsBasedObject) {
|
||||
// True is safer because nothing will be lost when serializing.
|
||||
return true;
|
||||
}
|
||||
return eventsBasedObject->GetInitialInstances().GetInstancesCount() == 0;
|
||||
}
|
||||
|
||||
bool CustomObjectConfiguration::
|
||||
IsOverridingEventsBasedObjectChildrenConfiguration() const {
|
||||
return isMarkedAsOverridingEventsBasedObjectChildrenConfiguration ||
|
||||
IsForcedToOverrideEventsBasedObjectChildrenConfiguration();
|
||||
}
|
||||
|
||||
void CustomObjectConfiguration::ClearChildrenConfiguration() {
|
||||
childObjectConfigurations.clear();
|
||||
}
|
||||
|
||||
gd::ObjectConfiguration &CustomObjectConfiguration::GetChildObjectConfiguration(const gd::String &objectName) {
|
||||
const auto *eventsBasedObject = GetEventsBasedObject();
|
||||
if (!eventsBasedObject) {
|
||||
@@ -49,12 +72,24 @@ gd::ObjectConfiguration &CustomObjectConfiguration::GetChildObjectConfiguration(
|
||||
}
|
||||
|
||||
if (!eventsBasedObject->GetObjects().HasObjectNamed(objectName)) {
|
||||
gd::LogError("Tried to get the configuration of a child-object:" + objectName
|
||||
gd::LogError("Tried to get the configuration of a child-object: " + objectName
|
||||
+ " that doesn't exist in the event-based object: " + GetType());
|
||||
return badObjectConfiguration;
|
||||
}
|
||||
|
||||
auto &childObject = eventsBasedObject->GetObjects().GetObject(objectName);
|
||||
|
||||
if (!IsOverridingEventsBasedObjectChildrenConfiguration()) {
|
||||
// It should be fine because the editor doesn't allow to edit values when
|
||||
// the default values from the events-based object is used.
|
||||
//
|
||||
// Resource refactor operations may modify it but they will do the same
|
||||
// thing on the custom object as on the event-based object children so it
|
||||
// shouldn't have any side effect.
|
||||
return const_cast<gd::ObjectConfiguration &>(
|
||||
childObject.GetConfiguration());
|
||||
}
|
||||
|
||||
auto configurationPosition = childObjectConfigurations.find(objectName);
|
||||
if (configurationPosition == childObjectConfigurations.end()) {
|
||||
childObjectConfigurations.insert(std::make_pair(
|
||||
@@ -67,7 +102,7 @@ gd::ObjectConfiguration &CustomObjectConfiguration::GetChildObjectConfiguration(
|
||||
auto &configuration = pair.second;
|
||||
return *configuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> CustomObjectConfiguration::GetProperties() const {
|
||||
auto objectProperties = std::map<gd::String, gd::PropertyDescriptor>();
|
||||
@@ -123,31 +158,21 @@ bool CustomObjectConfiguration::UpdateInitialInstanceProperty(
|
||||
void CustomObjectConfiguration::DoSerializeTo(SerializerElement& element) const {
|
||||
element.AddChild("content") = objectContent;
|
||||
|
||||
if (!animations.HasNoAnimations()) {
|
||||
const auto *eventsBasedObject = GetEventsBasedObject();
|
||||
if (!animations.HasNoAnimations() ||
|
||||
(eventsBasedObject && eventsBasedObject->IsAnimatable())) {
|
||||
auto &animatableElement = element.AddChild("animatable");
|
||||
animations.SerializeTo(animatableElement);
|
||||
}
|
||||
|
||||
auto &childrenContentElement = element.AddChild("childrenContent");
|
||||
for (auto &pair : childObjectConfigurations) {
|
||||
auto &childName = pair.first;
|
||||
auto &childConfiguration = pair.second;
|
||||
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());
|
||||
if (IsOverridingEventsBasedObjectChildrenConfiguration()) {
|
||||
auto &childrenContentElement = element.AddChild("childrenContent");
|
||||
for (auto &pair : childObjectConfigurations) {
|
||||
auto &childName = pair.first;
|
||||
auto &childConfiguration = pair.second;
|
||||
auto &childElement = childrenContentElement.AddChild(childName);
|
||||
childConfiguration->SerializeTo(childElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
void CustomObjectConfiguration::DoUnserializeFrom(Project& project,
|
||||
@@ -159,12 +184,16 @@ void CustomObjectConfiguration::DoUnserializeFrom(Project& project,
|
||||
animations.UnserializeFrom(animatableElement);
|
||||
}
|
||||
|
||||
auto &childrenContentElement = element.GetChild("childrenContent");
|
||||
for (auto &pair : childrenContentElement.GetAllChildren()) {
|
||||
auto &childName = pair.first;
|
||||
auto &childElement = pair.second;
|
||||
auto &childConfiguration = GetChildObjectConfiguration(childName);
|
||||
childConfiguration.UnserializeFrom(project, *childElement);
|
||||
isMarkedAsOverridingEventsBasedObjectChildrenConfiguration =
|
||||
element.HasChild("childrenContent");
|
||||
if (isMarkedAsOverridingEventsBasedObjectChildrenConfiguration) {
|
||||
auto &childrenContentElement = element.GetChild("childrenContent");
|
||||
for (auto &pair : childrenContentElement.GetAllChildren()) {
|
||||
auto &childName = pair.first;
|
||||
auto &childElement = pair.second;
|
||||
auto &childConfiguration = GetChildObjectConfiguration(childName);
|
||||
childConfiguration.UnserializeFrom(project, *childElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,8 +204,8 @@ void CustomObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker& wor
|
||||
|
||||
for (auto& property : properties) {
|
||||
const String& propertyName = property.first;
|
||||
const gd::PropertyDescriptor& propertyDescriptor = property.second;
|
||||
if (propertyDescriptor.GetType() == "resource") {
|
||||
const gd::PropertyDescriptor &propertyDescriptor = property.second;
|
||||
if (propertyDescriptor.GetType().LowerCase() == "resource") {
|
||||
auto& extraInfo = propertyDescriptor.GetExtraInfo();
|
||||
const gd::String& resourceType = extraInfo.empty() ? "" : extraInfo[0];
|
||||
const gd::String& oldPropertyValue = propertyDescriptor.GetValue();
|
||||
@@ -245,3 +274,16 @@ const SpriteAnimationList& CustomObjectConfiguration::GetAnimations() const {
|
||||
SpriteAnimationList& CustomObjectConfiguration::GetAnimations() {
|
||||
return animations;
|
||||
}
|
||||
|
||||
const gd::CustomObjectConfiguration::EdgeAnchor
|
||||
CustomObjectConfiguration::GetEdgeAnchorFromString(const gd::String &value) {
|
||||
return (value == _("Window left") || value == _("Window top"))
|
||||
? gd::CustomObjectConfiguration::EdgeAnchor::MinEdge
|
||||
: (value == _("Window right") || value == _("Window bottom"))
|
||||
? gd::CustomObjectConfiguration::EdgeAnchor::MaxEdge
|
||||
: value == _("Proportional")
|
||||
? gd::CustomObjectConfiguration::EdgeAnchor::Proportional
|
||||
: value == _("Window center")
|
||||
? gd::CustomObjectConfiguration::EdgeAnchor::Center
|
||||
: gd::CustomObjectConfiguration::EdgeAnchor::NoAnchor;
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
@@ -30,7 +31,7 @@ namespace gd {
|
||||
class CustomObjectConfiguration : public gd::ObjectConfiguration {
|
||||
public:
|
||||
CustomObjectConfiguration(const Project& project_, const String& type_)
|
||||
: project(&project_) {
|
||||
: project(&project_), isMarkedAsOverridingEventsBasedObjectChildrenConfiguration(false) {
|
||||
SetType(type_);
|
||||
}
|
||||
std::unique_ptr<gd::ObjectConfiguration> Clone() const override;
|
||||
@@ -65,7 +66,22 @@ class CustomObjectConfiguration : public gd::ObjectConfiguration {
|
||||
|
||||
void ExposeResources(gd::ArbitraryResourceWorker& worker) override;
|
||||
|
||||
gd::ObjectConfiguration &GetChildObjectConfiguration(const gd::String& objectName);
|
||||
bool IsForcedToOverrideEventsBasedObjectChildrenConfiguration() const;
|
||||
|
||||
bool IsMarkedAsOverridingEventsBasedObjectChildrenConfiguration() const {
|
||||
return isMarkedAsOverridingEventsBasedObjectChildrenConfiguration;
|
||||
}
|
||||
|
||||
void SetMarkedAsOverridingEventsBasedObjectChildrenConfiguration(
|
||||
bool isOverridingEventsBasedObjectChildrenConfiguration_) {
|
||||
isMarkedAsOverridingEventsBasedObjectChildrenConfiguration =
|
||||
isOverridingEventsBasedObjectChildrenConfiguration_;
|
||||
}
|
||||
|
||||
void ClearChildrenConfiguration();
|
||||
|
||||
gd::ObjectConfiguration &
|
||||
GetChildObjectConfiguration(const gd::String &objectName);
|
||||
|
||||
std::size_t GetAnimationsCount() const override;
|
||||
|
||||
@@ -83,6 +99,38 @@ class CustomObjectConfiguration : public gd::ObjectConfiguration {
|
||||
*/
|
||||
SpriteAnimationList& GetAnimations();
|
||||
|
||||
enum EdgeAnchor {
|
||||
NoAnchor = 0,
|
||||
MinEdge = 1,
|
||||
MaxEdge = 2,
|
||||
Proportional = 3,
|
||||
Center = 4,
|
||||
};
|
||||
|
||||
static const gd::CustomObjectConfiguration::EdgeAnchor
|
||||
GetEdgeAnchorFromString(const gd::String &value);
|
||||
|
||||
/**
|
||||
* Check if a child object properties must be displayed as folded in the editor.
|
||||
* This is only useful when the object can override its children configuration (which
|
||||
* is something being deprecated).
|
||||
*/
|
||||
bool IsChildObjectFolded(const gd::String& childName) const {
|
||||
return unfoldedChildren.find(childName) == unfoldedChildren.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if a child object properties must be displayed as folded in the editor.
|
||||
* This is only useful when the object can override its children configuration (which
|
||||
* is something being deprecated).
|
||||
*/
|
||||
void SetChildObjectFolded(const gd::String& childName, bool folded) {
|
||||
if (!folded)
|
||||
unfoldedChildren.insert(childName);
|
||||
else
|
||||
unfoldedChildren.erase(childName);
|
||||
}
|
||||
|
||||
protected:
|
||||
void DoSerializeTo(SerializerElement& element) const override;
|
||||
void DoUnserializeFrom(Project& project, const SerializerElement& element) override;
|
||||
@@ -90,10 +138,15 @@ protected:
|
||||
private:
|
||||
const gd::EventsBasedObject* GetEventsBasedObject() const;
|
||||
|
||||
const Project* project; ///< The project is used to get the
|
||||
///< EventBasedObject from the fullType.
|
||||
bool IsOverridingEventsBasedObjectChildrenConfiguration() const;
|
||||
|
||||
const Project* project = nullptr; ///< The project is used to get the
|
||||
///< EventBasedObject from the fullType.
|
||||
gd::SerializerElement objectContent;
|
||||
std::map<gd::String, std::unique_ptr<gd::ObjectConfiguration>> childObjectConfigurations;
|
||||
std::unordered_set<gd::String> unfoldedChildren;
|
||||
|
||||
bool isMarkedAsOverridingEventsBasedObjectChildrenConfiguration = false;
|
||||
mutable std::map<gd::String, std::unique_ptr<gd::ObjectConfiguration>> childObjectConfigurations;
|
||||
|
||||
static gd::ObjectConfiguration badObjectConfiguration;
|
||||
|
||||
|
@@ -12,6 +12,7 @@ namespace gd {
|
||||
void Effect::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", GetName());
|
||||
element.SetAttribute("effectType", GetEffectType());
|
||||
if (IsFolded()) element.SetBoolAttribute("folded", true);
|
||||
|
||||
SerializerElement& doubleParametersElement =
|
||||
element.AddChild("doubleParameters");
|
||||
@@ -41,6 +42,7 @@ void Effect::UnserializeFrom(const SerializerElement& element) {
|
||||
"effectName"
|
||||
// end of compatibility code
|
||||
));
|
||||
SetFolded(element.GetBoolAttribute("folded", false));
|
||||
|
||||
doubleParameters.clear();
|
||||
const SerializerElement& doubleParametersElement =
|
||||
|
@@ -21,8 +21,8 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API Effect {
|
||||
public:
|
||||
Effect(){};
|
||||
virtual ~Effect(){};
|
||||
Effect() : folded(false) {};
|
||||
virtual ~Effect() {};
|
||||
|
||||
void SetName(const gd::String& name_) { name = name_; }
|
||||
const gd::String& GetName() const { return name; }
|
||||
@@ -32,6 +32,9 @@ class GD_CORE_API Effect {
|
||||
}
|
||||
const gd::String& GetEffectType() const { return effectType; }
|
||||
|
||||
void SetFolded(bool fold = true) { folded = fold; }
|
||||
bool IsFolded() const { return folded; }
|
||||
|
||||
void SetDoubleParameter(const gd::String& name, double value) {
|
||||
doubleParameters[name] = value;
|
||||
}
|
||||
@@ -85,6 +88,7 @@ class GD_CORE_API Effect {
|
||||
void UnserializeFrom(const SerializerElement& element);
|
||||
|
||||
private:
|
||||
bool folded;
|
||||
gd::String name; ///< The name of the layer.
|
||||
gd::String effectType; ///< The name of the effect to apply.
|
||||
std::map<gd::String, double> doubleParameters; ///< Values of parameters being doubles, keyed by names.
|
||||
|
@@ -16,12 +16,15 @@ EventsBasedObject::EventsBasedObject()
|
||||
isRenderedIn3D(false),
|
||||
isAnimatable(false),
|
||||
isTextContainer(false),
|
||||
isInnerAreaFollowingParentSize(false),
|
||||
isUsingLegacyInstancesRenderer(false),
|
||||
areaMinX(0),
|
||||
areaMinY(0),
|
||||
areaMinZ(0),
|
||||
areaMaxX(64),
|
||||
areaMaxY(64),
|
||||
areaMaxZ(64) {
|
||||
areaMaxZ(64),
|
||||
objectsContainer(gd::ObjectsContainer::SourceType::Object) {
|
||||
}
|
||||
|
||||
EventsBasedObject::~EventsBasedObject() {}
|
||||
@@ -37,6 +40,10 @@ void EventsBasedObject::SerializeTo(SerializerElement& element) const {
|
||||
if (isTextContainer) {
|
||||
element.SetBoolAttribute("isTextContainer", true);
|
||||
}
|
||||
if (isInnerAreaFollowingParentSize) {
|
||||
element.SetBoolAttribute("isInnerAreaFollowingParentSize", true);
|
||||
}
|
||||
element.SetBoolAttribute("isUsingLegacyInstancesRenderer", isUsingLegacyInstancesRenderer);
|
||||
element.SetIntAttribute("areaMinX", areaMinX);
|
||||
element.SetIntAttribute("areaMinY", areaMinY);
|
||||
element.SetIntAttribute("areaMinZ", areaMinZ);
|
||||
@@ -59,6 +66,8 @@ void EventsBasedObject::UnserializeFrom(gd::Project& project,
|
||||
isRenderedIn3D = element.GetBoolAttribute("is3D", false);
|
||||
isAnimatable = element.GetBoolAttribute("isAnimatable", false);
|
||||
isTextContainer = element.GetBoolAttribute("isTextContainer", false);
|
||||
isInnerAreaFollowingParentSize =
|
||||
element.GetBoolAttribute("isInnerAreaFollowingParentSize", false);
|
||||
areaMinX = element.GetIntAttribute("areaMinX", 0);
|
||||
areaMinY = element.GetIntAttribute("areaMinY", 0);
|
||||
areaMinZ = element.GetIntAttribute("areaMinZ", 0);
|
||||
@@ -82,6 +91,15 @@ void EventsBasedObject::UnserializeFrom(gd::Project& project,
|
||||
}
|
||||
|
||||
initialInstances.UnserializeFrom(element.GetChild("instances"));
|
||||
if (element.HasChild("isUsingLegacyInstancesRenderer")) {
|
||||
isUsingLegacyInstancesRenderer =
|
||||
element.GetBoolAttribute("isUsingLegacyInstancesRenderer", false);
|
||||
}
|
||||
else {
|
||||
// Compatibility with GD <= 5.4.212
|
||||
isUsingLegacyInstancesRenderer = initialInstances.GetInstancesCount() == 0;
|
||||
// end of compatibility code
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -101,11 +101,53 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
|
||||
/**
|
||||
* \brief Declare a TextContainer capability.
|
||||
*/
|
||||
EventsBasedObject& MarkAsTextContainer(bool isTextContainer_) {
|
||||
EventsBasedObject &MarkAsTextContainer(bool isTextContainer_) {
|
||||
isTextContainer = isTextContainer_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Declare that the parent scale will always be 1 and children will
|
||||
* adapt there size. This is removing the ScalableCapability.
|
||||
*/
|
||||
EventsBasedObject &
|
||||
MarkAsInnerAreaFollowingParentSize(bool isInnerAreaExpandingWithParent_) {
|
||||
isInnerAreaFollowingParentSize = isInnerAreaExpandingWithParent_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if objects handle size changes on their own and
|
||||
* don't have the ScalableCapability.
|
||||
*
|
||||
* When the parent dimensions change:
|
||||
* - if `false`, the object is stretch proportionally while children local
|
||||
* positions stay the same.
|
||||
* - if `true`, the children local positions need to be adapted by events
|
||||
* to follow their parent size.
|
||||
*/
|
||||
bool IsInnerAreaFollowingParentSize() const {
|
||||
return isInnerAreaFollowingParentSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Declare that custom object are rendered using their child-objects
|
||||
* instead of their child-instances.
|
||||
*/
|
||||
EventsBasedObject &
|
||||
MakAsUsingLegacyInstancesRenderer(bool isUsingLegacyInstancesRenderer_) {
|
||||
isUsingLegacyInstancesRenderer = isUsingLegacyInstancesRenderer_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if custom object are rendered using their child-objects
|
||||
* instead of their child-instances.
|
||||
*/
|
||||
bool IsUsingLegacyInstancesRenderer() const {
|
||||
return isUsingLegacyInstancesRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the object needs a TextContainer capability.
|
||||
*/
|
||||
@@ -279,6 +321,8 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
|
||||
bool isRenderedIn3D;
|
||||
bool isAnimatable;
|
||||
bool isTextContainer;
|
||||
bool isInnerAreaFollowingParentSize;
|
||||
bool isUsingLegacyInstancesRenderer;
|
||||
gd::InitialInstancesContainer initialInstances;
|
||||
gd::LayersContainer layers;
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include "EventsFunction.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Tools/MakeUnique.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -98,8 +99,11 @@ void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
|
||||
|
||||
void EventsFunctionsExtension::UnserializeFrom(
|
||||
gd::Project& project, const SerializerElement& element) {
|
||||
UnserializeExtensionDeclarationFrom(project, element);
|
||||
UnserializeExtensionImplementationFrom(project, element);
|
||||
// Unserialize first the "declaration" (everything but objects content)
|
||||
// so that objects can be then unserialized in proper order (they can depend
|
||||
// on each others)
|
||||
UnserializeExtensionDeclarationFrom(project, element);
|
||||
UnserializeExtensionImplementationFrom(project, element);
|
||||
}
|
||||
|
||||
void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
|
||||
@@ -162,6 +166,7 @@ void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
|
||||
// As event based objects can contains objects using CustomBehavior and/or
|
||||
// CustomObject, this allows them to reference EventBasedBehavior and
|
||||
// EventBasedObject respectively.
|
||||
eventsBasedBehaviors.Clear();
|
||||
auto &behaviorsElement = element.GetChild("eventsBasedBehaviors");
|
||||
behaviorsElement.ConsiderAsArrayOf("eventsBasedBehavior");
|
||||
for (std::size_t i = 0; i < behaviorsElement.GetChildrenCount(); ++i) {
|
||||
@@ -169,6 +174,7 @@ void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
|
||||
behaviorsElement.GetChild(i).GetStringAttribute("name");
|
||||
eventsBasedBehaviors.InsertNew(behaviorName, eventsBasedBehaviors.GetCount());
|
||||
}
|
||||
eventsBasedObjects.Clear();
|
||||
auto &objectsElement = element.GetChild("eventsBasedObjects");
|
||||
objectsElement.ConsiderAsArrayOf("eventsBasedObject");
|
||||
for (std::size_t i = 0; i < objectsElement.GetChildrenCount(); ++i) {
|
||||
@@ -185,11 +191,93 @@ void EventsFunctionsExtension::UnserializeExtensionImplementationFrom(
|
||||
eventsBasedBehaviors.UnserializeElementsFrom(
|
||||
"eventsBasedBehavior", project, element.GetChild("eventsBasedBehaviors"));
|
||||
|
||||
// It's important to load the objects without erasing them first as each object
|
||||
// might reference other objects, and so need to know if a custom object exists
|
||||
// in the project or not.
|
||||
eventsBasedObjects.ProgressivelyUnserializeElementsFrom(
|
||||
"eventsBasedObject", project, element.GetChild("eventsBasedObjects"));
|
||||
auto &eventsBasedObjectsElement = element.GetChild("eventsBasedObjects");
|
||||
eventsBasedObjectsElement.ConsiderAsArrayOf("eventsBasedObject");
|
||||
for (gd::String &eventsBasedObjectName :
|
||||
GetUnserializingOrderEventsBasedObjectNames(eventsBasedObjectsElement)) {
|
||||
size_t extensionIndex = eventsBasedObjects.GetPosition(
|
||||
eventsBasedObjects.Get(eventsBasedObjectName));
|
||||
const SerializerElement &eventsBasedObjectElement =
|
||||
eventsBasedObjectsElement.GetChild(extensionIndex);
|
||||
|
||||
eventsBasedObjects.at(extensionIndex)
|
||||
.UnserializeFrom(project, eventsBasedObjectElement);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<gd::String>
|
||||
EventsFunctionsExtension::GetUnserializingOrderEventsBasedObjectNames(
|
||||
const gd::SerializerElement &eventsBasedObjectsElement) {
|
||||
|
||||
// Child-objects need the event-based objects they use to be loaded completely
|
||||
// before they are unserialized.
|
||||
|
||||
// At the beginning, everything is yet to be loaded.
|
||||
std::vector<gd::String> remainingEventsBasedObjectNames(
|
||||
eventsBasedObjects.size());
|
||||
for (std::size_t i = 0; i < eventsBasedObjects.size(); ++i) {
|
||||
remainingEventsBasedObjectNames[i] = eventsBasedObjects.at(i).GetName();
|
||||
}
|
||||
|
||||
// Helper allowing to find if an object depends on at least one other object from
|
||||
// the extension that is not loaded yet.
|
||||
auto &extensionName = name;
|
||||
auto isDependentFromRemainingEventsBasedObjects =
|
||||
[&remainingEventsBasedObjectNames,
|
||||
&extensionName](const gd::SerializerElement &eventsBasedObjectElement) {
|
||||
auto &objectsElement = eventsBasedObjectElement.GetChild("objects");
|
||||
objectsElement.ConsiderAsArrayOf("object");
|
||||
|
||||
for (std::size_t objectIndex = 0;
|
||||
objectIndex < objectsElement.GetChildrenCount(); ++objectIndex) {
|
||||
const gd::String &objectType =
|
||||
objectsElement.GetChild(objectIndex).GetStringAttribute("type");
|
||||
|
||||
gd::String usedExtensionName =
|
||||
PlatformExtension::GetExtensionFromFullObjectType(objectType);
|
||||
if (usedExtensionName != extensionName) {
|
||||
// The object comes from another extension: the project is already responsible
|
||||
// for loading extensions in the proper order.
|
||||
continue;
|
||||
}
|
||||
gd::String eventsBasedObjectName =
|
||||
gd::PlatformExtension::GetObjectNameFromFullObjectType(
|
||||
objectType);
|
||||
|
||||
if (std::find(remainingEventsBasedObjectNames.begin(),
|
||||
remainingEventsBasedObjectNames.end(),
|
||||
eventsBasedObjectName) !=
|
||||
remainingEventsBasedObjectNames.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Find the order of loading so that the objects are loaded when all the objects
|
||||
// they depend on are already loaded.
|
||||
std::vector<gd::String> loadOrderEventsBasedObjectNames;
|
||||
bool foundAnyEventsBasedObject = true;
|
||||
while (foundAnyEventsBasedObject) {
|
||||
foundAnyEventsBasedObject = false;
|
||||
for (std::size_t i = 0; i < remainingEventsBasedObjectNames.size(); ++i) {
|
||||
auto eventsBasedObjectName = remainingEventsBasedObjectNames[i];
|
||||
size_t extensionIndex = eventsBasedObjects.GetPosition(
|
||||
eventsBasedObjects.Get(eventsBasedObjectName));
|
||||
const SerializerElement &eventsBasedObjectElement =
|
||||
eventsBasedObjectsElement.GetChild(extensionIndex);
|
||||
|
||||
if (!isDependentFromRemainingEventsBasedObjects(
|
||||
eventsBasedObjectElement)) {
|
||||
loadOrderEventsBasedObjectNames.push_back(eventsBasedObjectName);
|
||||
remainingEventsBasedObjectNames.erase(
|
||||
remainingEventsBasedObjectNames.begin() + i);
|
||||
i--;
|
||||
foundAnyEventsBasedObject = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return loadOrderEventsBasedObjectNames;
|
||||
}
|
||||
|
||||
bool EventsFunctionsExtension::IsExtensionLifecycleEventsFunction(
|
||||
|
@@ -314,6 +314,9 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
|
||||
return dependency;
|
||||
}
|
||||
|
||||
std::vector<gd::String> GetUnserializingOrderEventsBasedObjectNames(
|
||||
const gd::SerializerElement &eventsBasedObjectsElement);
|
||||
|
||||
gd::String version;
|
||||
gd::String extensionNamespace;
|
||||
gd::String shortDescription;
|
||||
|
@@ -7,7 +7,7 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
ExternalEvents::ExternalEvents() : lastChangeTimeStamp(0) {
|
||||
ExternalEvents::ExternalEvents() {
|
||||
// ctor
|
||||
}
|
||||
|
||||
@@ -24,14 +24,12 @@ ExternalEvents& ExternalEvents::operator=(const ExternalEvents& rhs) {
|
||||
void ExternalEvents::Init(const ExternalEvents& externalEvents) {
|
||||
name = externalEvents.GetName();
|
||||
associatedScene = externalEvents.GetAssociatedLayout();
|
||||
lastChangeTimeStamp = externalEvents.GetLastChangeTimeStamp();
|
||||
events = externalEvents.events;
|
||||
}
|
||||
|
||||
void ExternalEvents::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", name);
|
||||
element.SetAttribute("associatedLayout", associatedScene);
|
||||
element.SetAttribute("lastChangeTimeStamp", (int)lastChangeTimeStamp);
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
}
|
||||
@@ -41,8 +39,6 @@ void ExternalEvents::UnserializeFrom(gd::Project& project,
|
||||
name = element.GetStringAttribute("name", "", "Name");
|
||||
associatedScene =
|
||||
element.GetStringAttribute("associatedLayout", "", "AssociatedScene");
|
||||
lastChangeTimeStamp =
|
||||
element.GetIntAttribute("lastChangeTimeStamp", 0, "LastChangeTimeStamp");
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
}
|
||||
|
@@ -67,24 +67,6 @@ class GD_CORE_API ExternalEvents {
|
||||
associatedScene = name_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the latest time of the build.
|
||||
* Used when the IDE found that the external events can be compiled separately
|
||||
* from scene's events.
|
||||
*
|
||||
* \todo This is specific to GD C++ Platform
|
||||
*/
|
||||
time_t GetLastChangeTimeStamp() const { return lastChangeTimeStamp; };
|
||||
|
||||
/**
|
||||
* Change the latest time of the build of the external events.
|
||||
*
|
||||
* \todo This is specific to GD C++ Platform
|
||||
*/
|
||||
void SetLastChangeTimeStamp(time_t newTimeStamp) {
|
||||
lastChangeTimeStamp = newTimeStamp;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get the events.
|
||||
*/
|
||||
@@ -109,7 +91,6 @@ class GD_CORE_API ExternalEvents {
|
||||
private:
|
||||
gd::String name;
|
||||
gd::String associatedScene;
|
||||
time_t lastChangeTimeStamp; ///< Time of the last build
|
||||
gd::EventsList events; ///< List of events
|
||||
|
||||
/**
|
||||
@@ -119,19 +100,6 @@ class GD_CORE_API ExternalEvents {
|
||||
void Init(const ExternalEvents& externalEvents);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Functor testing ExternalEvents' name
|
||||
*/
|
||||
struct ExternalEventsHasName
|
||||
: public std::binary_function<std::unique_ptr<gd::ExternalEvents>,
|
||||
gd::String,
|
||||
bool> {
|
||||
bool operator()(const std::unique_ptr<gd::ExternalEvents>& externalEvents,
|
||||
gd::String name) const {
|
||||
return externalEvents->GetName() == name;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXTERNALEVENTS_H
|
||||
|
@@ -96,19 +96,6 @@ class GD_CORE_API ExternalLayout {
|
||||
gd::String associatedLayout;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Functor testing ExternalLayout' name
|
||||
*/
|
||||
struct ExternalLayoutHasName
|
||||
: public std::binary_function<std::unique_ptr<gd::ExternalLayout>,
|
||||
gd::String,
|
||||
bool> {
|
||||
bool operator()(const std::unique_ptr<gd::ExternalLayout>& externalLayout,
|
||||
gd::String name) const {
|
||||
return externalLayout->GetName() == name;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXTERNALLAYOUT_H
|
||||
|
@@ -27,7 +27,11 @@ InitialInstance::InitialInstance()
|
||||
rotationX(0),
|
||||
rotationY(0),
|
||||
zOrder(0),
|
||||
opacity(255),
|
||||
layer(""),
|
||||
flippedX(false),
|
||||
flippedY(false),
|
||||
flippedZ(false),
|
||||
customSize(false),
|
||||
customDepth(false),
|
||||
width(0),
|
||||
@@ -57,7 +61,11 @@ void InitialInstance::UnserializeFrom(const SerializerElement& element) {
|
||||
SetHasCustomDepth(false);
|
||||
}
|
||||
SetZOrder(element.GetIntAttribute("zOrder", 0, "plan"));
|
||||
SetOpacity(element.GetIntAttribute("opacity", 255));
|
||||
SetLayer(element.GetStringAttribute("layer"));
|
||||
SetFlippedX(element.GetBoolAttribute("flippedX", false));
|
||||
SetFlippedY(element.GetBoolAttribute("flippedY", false));
|
||||
SetFlippedZ(element.GetBoolAttribute("flippedZ", false));
|
||||
SetLocked(element.GetBoolAttribute("locked", false));
|
||||
SetSealed(element.GetBoolAttribute("sealed", false));
|
||||
SetShouldKeepRatio(element.GetBoolAttribute("keepRatio", false));
|
||||
@@ -113,6 +121,10 @@ void InitialInstance::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("y", GetY());
|
||||
if (GetZ() != 0) element.SetAttribute("z", GetZ());
|
||||
element.SetAttribute("zOrder", GetZOrder());
|
||||
if (GetOpacity() != 255) element.SetAttribute("opacity", GetOpacity());
|
||||
if (IsFlippedX()) element.SetAttribute("flippedX", IsFlippedX());
|
||||
if (IsFlippedY()) element.SetAttribute("flippedY", IsFlippedY());
|
||||
if (IsFlippedZ()) element.SetAttribute("flippedZ", IsFlippedZ());
|
||||
element.SetAttribute("layer", GetLayer());
|
||||
element.SetAttribute("angle", GetAngle());
|
||||
if (GetRotationX() != 0) element.SetAttribute("rotationX", GetRotationX());
|
||||
@@ -155,8 +167,8 @@ InitialInstance& InitialInstance::ResetPersistentUuid() {
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
InitialInstance::GetCustomProperties(
|
||||
gd::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer) {
|
||||
gd::ObjectsContainer& globalObjectsContainer,
|
||||
gd::ObjectsContainer& objectsContainer) {
|
||||
// Find an object
|
||||
if (objectsContainer.HasObjectNamed(GetObjectName()))
|
||||
return objectsContainer.GetObject(GetObjectName())
|
||||
@@ -172,9 +184,10 @@ InitialInstance::GetCustomProperties(
|
||||
}
|
||||
|
||||
bool InitialInstance::UpdateCustomProperty(
|
||||
const gd::String &name, const gd::String &value,
|
||||
gd::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer) {
|
||||
const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::ObjectsContainer& globalObjectsContainer,
|
||||
gd::ObjectsContainer& objectsContainer) {
|
||||
if (objectsContainer.HasObjectNamed(GetObjectName()))
|
||||
return objectsContainer.GetObject(GetObjectName())
|
||||
.GetConfiguration()
|
||||
|
@@ -29,7 +29,7 @@ class GD_CORE_API InitialInstance {
|
||||
* \brief Create an initial instance pointing to no object, at position (0,0).
|
||||
*/
|
||||
InitialInstance();
|
||||
virtual ~InitialInstance(){};
|
||||
virtual ~InitialInstance() {};
|
||||
|
||||
/**
|
||||
* Must return a pointer to a copy of the object. A such method is needed to
|
||||
@@ -123,6 +123,46 @@ class GD_CORE_API InitialInstance {
|
||||
*/
|
||||
void SetZOrder(int zOrder_) { zOrder = zOrder_; }
|
||||
|
||||
/**
|
||||
* \brief Get Opacity.
|
||||
*/
|
||||
int GetOpacity() const { return opacity; }
|
||||
|
||||
/**
|
||||
* \brief Set the opacity of the instance.
|
||||
*/
|
||||
void SetOpacity(int opacity_) { opacity = opacity_; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the instance is flipped on X axis.
|
||||
*/
|
||||
bool IsFlippedX() const { return flippedX; }
|
||||
|
||||
/**
|
||||
* \brief Set whether the instance is flipped on X axis.
|
||||
*/
|
||||
void SetFlippedX(bool flippedX_) { flippedX = flippedX_; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the instance is flipped on Y axis.
|
||||
*/
|
||||
bool IsFlippedY() const { return flippedY; }
|
||||
|
||||
/**
|
||||
* \brief Set whether the instance is flipped on Y axis.
|
||||
*/
|
||||
void SetFlippedY(bool flippedY_) { flippedY = flippedY_; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the instance is flipped on Z axis.
|
||||
*/
|
||||
bool IsFlippedZ() const { return flippedZ; }
|
||||
|
||||
/**
|
||||
* \brief Set whether the instance is flipped on Z axis.
|
||||
*/
|
||||
void SetFlippedZ(bool flippedZ_) { flippedZ = flippedZ_; }
|
||||
|
||||
/**
|
||||
* \brief Get the layer the instance belongs to.
|
||||
*/
|
||||
@@ -134,8 +174,9 @@ class GD_CORE_API InitialInstance {
|
||||
void SetLayer(const gd::String& layer_) { layer = layer_; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the instance has a width/height which is different from its
|
||||
* object default width/height. This is independent from `HasCustomDepth`.
|
||||
* \brief Return true if the instance has a width/height which is different
|
||||
* from its object default width/height. This is independent from
|
||||
* `HasCustomDepth`.
|
||||
*
|
||||
* \see gd::Object
|
||||
*/
|
||||
@@ -150,15 +191,13 @@ class GD_CORE_API InitialInstance {
|
||||
bool HasCustomDepth() const { return customDepth; }
|
||||
|
||||
/**
|
||||
* \brief Set whether the instance has a width/height which is different from its
|
||||
* object default width/height or not.
|
||||
* This is independent from `SetHasCustomDepth`.
|
||||
* \brief Set whether the instance has a width/height which is different from
|
||||
* its object default width/height or not. This is independent from
|
||||
* `SetHasCustomDepth`.
|
||||
*
|
||||
* \see gd::Object
|
||||
*/
|
||||
void SetHasCustomSize(bool hasCustomSize_) {
|
||||
customSize = hasCustomSize_;
|
||||
}
|
||||
void SetHasCustomSize(bool hasCustomSize_) { customSize = hasCustomSize_; }
|
||||
|
||||
/**
|
||||
* \brief Set whether the instance has a depth which is different from its
|
||||
@@ -264,18 +303,19 @@ 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::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer);
|
||||
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::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer);
|
||||
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.
|
||||
@@ -343,6 +383,10 @@ class GD_CORE_API InitialInstance {
|
||||
double rotationX; ///< Instance angle on X axis (for a 3D object)
|
||||
double rotationY; ///< Instance angle on Y axis (for a 3D object)
|
||||
int zOrder; ///< Instance Z order (for a 2D object)
|
||||
int opacity; ///< Instance opacity
|
||||
bool flippedX; ///< True if the instance is flipped on X axis
|
||||
bool flippedY; ///< True if the instance is flipped on Y axis
|
||||
bool flippedZ; ///< True if the instance is flipped on Z axis
|
||||
gd::String layer; ///< Instance layer
|
||||
bool customSize; ///< True if object has a custom width and height
|
||||
bool customDepth; ///< True if object has a custom depth
|
||||
@@ -352,13 +396,13 @@ class GD_CORE_API InitialInstance {
|
||||
gd::VariablesContainer initialVariables; ///< Instance specific variables
|
||||
bool locked; ///< True if the instance is locked
|
||||
bool sealed; ///< True if the instance is sealed
|
||||
bool keepRatio; ///< True if the instance's dimensions
|
||||
/// should keep the same ratio.
|
||||
bool keepRatio; ///< True if the instance's dimensions
|
||||
/// should keep the same ratio.
|
||||
mutable gd::String persistentUuid; ///< A persistent random version 4 UUID,
|
||||
/// useful for hot reloading.
|
||||
|
||||
static gd::String*
|
||||
badStringPropertyValue; ///< Empty string returned by GetRawStringProperty
|
||||
static gd::String* badStringPropertyValue; ///< Empty string returned by
|
||||
///< GetRawStringProperty
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -163,6 +163,20 @@ bool InitialInstancesContainer::HasInstancesOfObject(
|
||||
});
|
||||
}
|
||||
|
||||
bool InitialInstancesContainer::IsInstancesCountOfObjectGreaterThan(
|
||||
const gd::String &objectName, const std::size_t minInstanceCount) const {
|
||||
std::size_t count = 0;
|
||||
for (const gd::InitialInstance &instance : initialInstances) {
|
||||
if (instance.GetObjectName() == objectName) {
|
||||
count++;
|
||||
if (count > minInstanceCount) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void InitialInstancesContainer::Create(
|
||||
const InitialInstancesContainer& source) {
|
||||
try {
|
||||
|
@@ -153,6 +153,13 @@ class GD_CORE_API InitialInstancesContainer {
|
||||
*/
|
||||
bool HasInstancesOfObject(const gd::String &objectName) const;
|
||||
|
||||
/**
|
||||
* \brief Return true if there is at least N instances of the given object.
|
||||
*/
|
||||
bool
|
||||
IsInstancesCountOfObjectGreaterThan(const gd::String &objectName,
|
||||
const std::size_t minInstanceCount) const;
|
||||
|
||||
/**
|
||||
* \brief Remove all instances
|
||||
*/
|
||||
|
@@ -15,6 +15,7 @@ Camera Layer::badCamera;
|
||||
|
||||
Layer::Layer()
|
||||
: renderingType(""),
|
||||
defaultCameraBehavior("top-left-anchored-if-never-moved"),
|
||||
isVisible(true),
|
||||
isLocked(false),
|
||||
isLightingLayer(false),
|
||||
@@ -40,6 +41,9 @@ void Layer::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", GetName());
|
||||
element.SetAttribute("renderingType", GetRenderingType());
|
||||
element.SetAttribute("cameraType", GetCameraType());
|
||||
if (GetDefaultCameraBehavior() != "top-left-anchored-if-never-moved") {
|
||||
element.SetAttribute("defaultCameraBehavior", GetDefaultCameraBehavior());
|
||||
}
|
||||
element.SetAttribute("visibility", GetVisibility());
|
||||
element.SetAttribute("isLocked", IsLocked());
|
||||
element.SetAttribute("isLightingLayer", IsLightingLayer());
|
||||
@@ -80,6 +84,7 @@ void Layer::UnserializeFrom(const SerializerElement& element) {
|
||||
SetName(element.GetStringAttribute("name", "", "Name"));
|
||||
SetRenderingType(element.GetStringAttribute("renderingType", ""));
|
||||
SetCameraType(element.GetStringAttribute("cameraType", "perspective"));
|
||||
SetDefaultCameraBehavior(element.GetStringAttribute("defaultCameraBehavior", "top-left-anchored-if-never-moved"));
|
||||
SetVisibility(element.GetBoolAttribute("visibility", true, "Visibility"));
|
||||
SetLocked(element.GetBoolAttribute("isLocked", false));
|
||||
SetLightingLayer(element.GetBoolAttribute("isLightingLayer", false));
|
||||
|
@@ -109,6 +109,12 @@ class GD_CORE_API Layer {
|
||||
renderingType = renderingType_;
|
||||
}
|
||||
|
||||
const gd::String& GetDefaultCameraBehavior() const { return defaultCameraBehavior; }
|
||||
|
||||
void SetDefaultCameraBehavior(const gd::String& defaultCameraBehavior_) {
|
||||
defaultCameraBehavior = defaultCameraBehavior_;
|
||||
}
|
||||
|
||||
const gd::String& GetCameraType() const { return cameraType; }
|
||||
|
||||
void SetCameraType(const gd::String& cameraType_) {
|
||||
@@ -275,6 +281,7 @@ class GD_CORE_API Layer {
|
||||
gd::String name; ///< The name of the layer
|
||||
gd::String renderingType; ///< The rendering type: "" (empty), "2d", "3d" or
|
||||
///< "2d+3d".
|
||||
gd::String defaultCameraBehavior;
|
||||
gd::String cameraType;
|
||||
bool isVisible; ///< True if the layer is visible
|
||||
bool isLocked; ///< True if the layer is locked
|
||||
|
@@ -24,10 +24,11 @@
|
||||
#include "GDCore/Project/ObjectGroup.h"
|
||||
#include "GDCore/Project/ObjectGroupsContainer.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/QuickCustomization.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/PolymorphicClone.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
#include "GDCore/Tools/PolymorphicClone.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -35,7 +36,10 @@ namespace gd {
|
||||
|
||||
gd::BehaviorsSharedData Layout::badBehaviorSharedData("", "");
|
||||
|
||||
Layout::Layout(const Layout& other) { Init(other); }
|
||||
Layout::Layout(const Layout &other)
|
||||
: objectsContainer(gd::ObjectsContainer::SourceType::Scene) {
|
||||
Init(other);
|
||||
}
|
||||
|
||||
Layout& Layout::operator=(const Layout& other) {
|
||||
if (this != &other) Init(other);
|
||||
@@ -43,7 +47,7 @@ Layout& Layout::operator=(const Layout& other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Layout::~Layout(){};
|
||||
Layout::~Layout() {};
|
||||
|
||||
Layout::Layout()
|
||||
: backgroundColorR(209),
|
||||
@@ -52,9 +56,8 @@ Layout::Layout()
|
||||
stopSoundsOnStartup(true),
|
||||
standardSortMethod(true),
|
||||
disableInputWhenNotFocused(true),
|
||||
variables(gd::VariablesContainer::SourceType::Scene)
|
||||
{
|
||||
}
|
||||
variables(gd::VariablesContainer::SourceType::Scene),
|
||||
objectsContainer(gd::ObjectsContainer::SourceType::Scene) {}
|
||||
|
||||
void Layout::SetName(const gd::String& name_) {
|
||||
name = name_;
|
||||
@@ -102,7 +105,9 @@ const gd::Layer& Layout::GetLayer(const gd::String& name) const {
|
||||
return layers.GetLayer(name);
|
||||
}
|
||||
|
||||
gd::Layer& Layout::GetLayer(std::size_t index) { return layers.GetLayer(index); }
|
||||
gd::Layer& Layout::GetLayer(std::size_t index) {
|
||||
return layers.GetLayer(index);
|
||||
}
|
||||
|
||||
const gd::Layer& Layout::GetLayer(std::size_t index) const {
|
||||
return layers.GetLayer(index);
|
||||
@@ -125,9 +130,7 @@ void Layout::InsertLayer(const gd::Layer& layer, std::size_t position) {
|
||||
layers.InsertLayer(layer, position);
|
||||
}
|
||||
|
||||
void Layout::RemoveLayer(const gd::String& name) {
|
||||
layers.RemoveLayer(name);
|
||||
}
|
||||
void Layout::RemoveLayer(const gd::String& name) { layers.RemoveLayer(name); }
|
||||
|
||||
void Layout::SwapLayers(std::size_t firstLayerIndex,
|
||||
std::size_t secondLayerIndex) {
|
||||
@@ -153,7 +156,7 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
|
||||
allBehaviorsNames.push_back(behavior.GetName());
|
||||
}
|
||||
}
|
||||
auto &globalObjects = project.GetObjects();
|
||||
auto& globalObjects = project.GetObjects();
|
||||
for (std::size_t i = 0; i < globalObjects.GetObjectsCount(); ++i) {
|
||||
std::vector<gd::String> objectBehaviors =
|
||||
globalObjects.GetObject(i).GetAllBehaviorNames();
|
||||
@@ -173,7 +176,8 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
|
||||
|
||||
if (behaviorsSharedData.find(name) != behaviorsSharedData.end()) continue;
|
||||
|
||||
auto sharedData = CreateBehaviorsSharedData(project, name, allBehaviorsTypes[i]);
|
||||
auto sharedData =
|
||||
CreateBehaviorsSharedData(project, name, allBehaviorsTypes[i]);
|
||||
if (sharedData) {
|
||||
behaviorsSharedData[name] = std::move(sharedData);
|
||||
}
|
||||
@@ -196,37 +200,39 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
|
||||
}
|
||||
|
||||
std::unique_ptr<gd::BehaviorsSharedData> Layout::CreateBehaviorsSharedData(
|
||||
gd::Project& project, const gd::String& name, const gd::String& behaviorsType) {
|
||||
if (project.HasEventsBasedBehavior(behaviorsType)) {
|
||||
auto sharedData =
|
||||
gd::make_unique<gd::CustomBehaviorsSharedData>(name, project, behaviorsType);
|
||||
sharedData->InitializeContent();
|
||||
return std::move(sharedData);
|
||||
}
|
||||
const gd::BehaviorMetadata& behaviorMetadata =
|
||||
gd::MetadataProvider::GetBehaviorMetadata(
|
||||
project.GetCurrentPlatform(),
|
||||
behaviorsType);
|
||||
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
gd::LogWarning("Tried to create a behavior shared data with an unknown type: " +
|
||||
behaviorsType + " on object " + GetName() + "!");
|
||||
gd::Project& project,
|
||||
const gd::String& name,
|
||||
const gd::String& behaviorsType) {
|
||||
if (project.HasEventsBasedBehavior(behaviorsType)) {
|
||||
auto sharedData = gd::make_unique<gd::CustomBehaviorsSharedData>(
|
||||
name, project, behaviorsType);
|
||||
sharedData->InitializeContent();
|
||||
return std::move(sharedData);
|
||||
}
|
||||
const gd::BehaviorMetadata& behaviorMetadata =
|
||||
gd::MetadataProvider::GetBehaviorMetadata(project.GetCurrentPlatform(),
|
||||
behaviorsType);
|
||||
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
gd::LogWarning(
|
||||
"Tried to create a behavior shared data with an unknown type: " +
|
||||
behaviorsType + " on object " + GetName() + "!");
|
||||
// It's probably an events-based behavior that was removed.
|
||||
// Create a custom behavior shared data to preserve the properties values.
|
||||
auto sharedData =
|
||||
gd::make_unique<gd::CustomBehaviorsSharedData>(name, project, behaviorsType);
|
||||
sharedData->InitializeContent();
|
||||
return std::move(sharedData);
|
||||
}
|
||||
|
||||
gd::BehaviorsSharedData* behaviorsSharedDataBluePrint =
|
||||
behaviorMetadata.GetSharedDataInstance();
|
||||
if (!behaviorsSharedDataBluePrint) return nullptr;
|
||||
|
||||
auto sharedData = behaviorsSharedDataBluePrint->Clone();
|
||||
sharedData->SetName(name);
|
||||
sharedData->SetTypeName(behaviorsType);
|
||||
auto sharedData = gd::make_unique<gd::CustomBehaviorsSharedData>(
|
||||
name, project, behaviorsType);
|
||||
sharedData->InitializeContent();
|
||||
return std::unique_ptr<gd::BehaviorsSharedData>(sharedData);
|
||||
return std::move(sharedData);
|
||||
}
|
||||
|
||||
gd::BehaviorsSharedData* behaviorsSharedDataBluePrint =
|
||||
behaviorMetadata.GetSharedDataInstance();
|
||||
if (!behaviorsSharedDataBluePrint) return nullptr;
|
||||
|
||||
auto sharedData = behaviorsSharedDataBluePrint->Clone();
|
||||
sharedData->SetName(name);
|
||||
sharedData->SetTypeName(behaviorsType);
|
||||
sharedData->InitializeContent();
|
||||
return std::unique_ptr<gd::BehaviorsSharedData>(sharedData);
|
||||
}
|
||||
|
||||
void Layout::SerializeTo(SerializerElement& element) const {
|
||||
@@ -243,11 +249,13 @@ void Layout::SerializeTo(SerializerElement& element) const {
|
||||
|
||||
editorSettings.SerializeTo(element.AddChild("uiSettings"));
|
||||
|
||||
objectsContainer.GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
|
||||
objectsContainer.GetObjectGroups().SerializeTo(
|
||||
element.AddChild("objectsGroups"));
|
||||
GetVariables().SerializeTo(element.AddChild("variables"));
|
||||
GetInitialInstances().SerializeTo(element.AddChild("instances"));
|
||||
objectsContainer.SerializeObjectsTo(element.AddChild("objects"));
|
||||
objectsContainer.SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
|
||||
objectsContainer.SerializeFoldersTo(
|
||||
element.AddChild("objectsFolderStructure"));
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
|
||||
@@ -257,15 +265,33 @@ void Layout::SerializeTo(SerializerElement& element) const {
|
||||
element.AddChild("behaviorsSharedData");
|
||||
behaviorDatasElement.ConsiderAsArrayOf("behaviorSharedData");
|
||||
for (const auto& it : behaviorsSharedData) {
|
||||
const gd::BehaviorsSharedData& sharedData = *it.second;
|
||||
SerializerElement& dataElement =
|
||||
behaviorDatasElement.AddChild("behaviorSharedData");
|
||||
|
||||
it.second->SerializeTo(dataElement);
|
||||
sharedData.SerializeTo(dataElement);
|
||||
dataElement.RemoveChild("type"); // The content can contain type or name
|
||||
// properties, remove them.
|
||||
dataElement.RemoveChild("name");
|
||||
dataElement.SetAttribute("type", it.second->GetTypeName());
|
||||
dataElement.SetAttribute("name", it.second->GetName());
|
||||
dataElement.SetAttribute("type", sharedData.GetTypeName());
|
||||
dataElement.SetAttribute("name", sharedData.GetName());
|
||||
|
||||
// Handle Quick Customization info.
|
||||
dataElement.RemoveChild("propertiesQuickCustomizationVisibilities");
|
||||
const QuickCustomizationVisibilitiesContainer&
|
||||
propertiesQuickCustomizationVisibilities =
|
||||
sharedData.GetPropertiesQuickCustomizationVisibilities();
|
||||
if (!propertiesQuickCustomizationVisibilities.IsEmpty()) {
|
||||
propertiesQuickCustomizationVisibilities.SerializeTo(
|
||||
dataElement.AddChild("propertiesQuickCustomizationVisibilities"));
|
||||
}
|
||||
const QuickCustomization::Visibility visibility =
|
||||
sharedData.GetQuickCustomizationVisibility();
|
||||
if (visibility != QuickCustomization::Visibility::Default) {
|
||||
dataElement.SetAttribute(
|
||||
"quickCustomizationVisibility",
|
||||
QuickCustomization::VisibilityAsString(visibility));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,9 +315,11 @@ void Layout::UnserializeFrom(gd::Project& project,
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, GetEvents(), element.GetChild("events", 0, "Events"));
|
||||
|
||||
objectsContainer.UnserializeObjectsFrom(project, element.GetChild("objects", 0, "Objets"));
|
||||
objectsContainer.UnserializeObjectsFrom(
|
||||
project, element.GetChild("objects", 0, "Objets"));
|
||||
if (element.HasChild("objectsFolderStructure")) {
|
||||
objectsContainer.UnserializeFoldersFrom(project, element.GetChild("objectsFolderStructure", 0));
|
||||
objectsContainer.UnserializeFoldersFrom(
|
||||
project, element.GetChild("objectsFolderStructure", 0));
|
||||
}
|
||||
objectsContainer.AddMissingObjectsInRootFolder();
|
||||
|
||||
@@ -321,7 +349,6 @@ void Layout::UnserializeFrom(gd::Project& project,
|
||||
"Behavior"); // Compatibility with GD <= 4
|
||||
gd::String name = sharedDataElement.GetStringAttribute("name", "", "Name");
|
||||
|
||||
|
||||
auto sharedData = CreateBehaviorsSharedData(project, name, type);
|
||||
if (sharedData) {
|
||||
// Compatibility with GD <= 4.0.98
|
||||
@@ -336,6 +363,21 @@ void Layout::UnserializeFrom(gd::Project& project,
|
||||
else {
|
||||
sharedData->UnserializeFrom(sharedDataElement);
|
||||
}
|
||||
|
||||
// Handle Quick Customization info.
|
||||
if (sharedDataElement.HasChild(
|
||||
"propertiesQuickCustomizationVisibilities")) {
|
||||
sharedData->GetPropertiesQuickCustomizationVisibilities()
|
||||
.UnserializeFrom(sharedDataElement.GetChild(
|
||||
"propertiesQuickCustomizationVisibilities"));
|
||||
}
|
||||
if (sharedDataElement.HasChild("quickCustomizationVisibility")) {
|
||||
sharedData->SetQuickCustomizationVisibility(
|
||||
QuickCustomization::StringAsVisibility(
|
||||
sharedDataElement.GetStringAttribute(
|
||||
"quickCustomizationVisibility")));
|
||||
}
|
||||
|
||||
behaviorsSharedData[name] = std::move(sharedData);
|
||||
}
|
||||
}
|
||||
@@ -390,8 +432,9 @@ gd::String GD_CORE_API GetTypeOfObject(const gd::ObjectsContainer& project,
|
||||
type = project.GetObject(name).GetType();
|
||||
|
||||
// Search in groups.
|
||||
// Currently, a group is considered as the "intersection" of all of its objects.
|
||||
// Search "groups is the intersection of its objects" in the codebase.
|
||||
// Currently, a group is considered as the "intersection" of all of its
|
||||
// objects. Search "groups is the intersection of its objects" in the
|
||||
// codebase.
|
||||
else if (searchInGroups) {
|
||||
for (std::size_t i = 0; i < layout.GetObjectGroups().size(); ++i) {
|
||||
if (layout.GetObjectGroups()[i].GetName() == name) {
|
||||
@@ -448,11 +491,12 @@ gd::String GD_CORE_API GetTypeOfObject(const gd::ObjectsContainer& project,
|
||||
return type;
|
||||
}
|
||||
|
||||
void GD_CORE_API FilterBehaviorNamesFromObject(
|
||||
const gd::Object &object, const gd::String &behaviorType,
|
||||
std::vector<gd::String> &behaviorNames) {
|
||||
void GD_CORE_API
|
||||
FilterBehaviorNamesFromObject(const gd::Object& object,
|
||||
const gd::String& behaviorType,
|
||||
std::vector<gd::String>& behaviorNames) {
|
||||
for (size_t i = 0; i < behaviorNames.size();) {
|
||||
auto &behaviorName = behaviorNames[i];
|
||||
auto& behaviorName = behaviorNames[i];
|
||||
if (!object.HasBehaviorNamed(behaviorName) ||
|
||||
object.GetBehavior(behaviorName).GetTypeName() != behaviorType) {
|
||||
behaviorNames.erase(behaviorNames.begin() + i);
|
||||
@@ -462,19 +506,21 @@ void GD_CORE_API FilterBehaviorNamesFromObject(
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
|
||||
const gd::ObjectsContainer &project, const gd::ObjectsContainer &layout,
|
||||
const gd::String &objectOrGroupName, const gd::String &behaviorType,
|
||||
bool searchInGroups) {
|
||||
std::vector<gd::String> GD_CORE_API
|
||||
GetBehaviorNamesInObjectOrGroup(const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
const gd::String& objectOrGroupName,
|
||||
const gd::String& behaviorType,
|
||||
bool searchInGroups) {
|
||||
// Search in objects.
|
||||
if (layout.HasObjectNamed(objectOrGroupName)) {
|
||||
auto &object = layout.GetObject(objectOrGroupName);
|
||||
auto& object = layout.GetObject(objectOrGroupName);
|
||||
auto behaviorNames = object.GetAllBehaviorNames();
|
||||
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
|
||||
return behaviorNames;
|
||||
}
|
||||
if (project.HasObjectNamed(objectOrGroupName)) {
|
||||
auto &object = project.GetObject(objectOrGroupName);
|
||||
auto& object = project.GetObject(objectOrGroupName);
|
||||
auto behaviorNames = object.GetAllBehaviorNames();
|
||||
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
|
||||
return behaviorNames;
|
||||
@@ -486,9 +532,10 @@ std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
|
||||
}
|
||||
|
||||
// Search in groups.
|
||||
// Currently, a group is considered as the "intersection" of all of its objects.
|
||||
// Search "groups is the intersection of its objects" in the codebase.
|
||||
const gd::ObjectsContainer *container;
|
||||
// Currently, a group is considered as the "intersection" of all of its
|
||||
// objects. Search "groups is the intersection of its objects" in the
|
||||
// codebase.
|
||||
const gd::ObjectsContainer* container;
|
||||
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
container = &layout;
|
||||
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
@@ -497,7 +544,7 @@ std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
|
||||
std::vector<gd::String> behaviorNames;
|
||||
return behaviorNames;
|
||||
}
|
||||
const vector<gd::String> &groupsObjects =
|
||||
const vector<gd::String>& groupsObjects =
|
||||
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
|
||||
|
||||
// Empty groups don't contain any behavior.
|
||||
@@ -510,15 +557,15 @@ std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
|
||||
auto behaviorNames = GetBehaviorNamesInObjectOrGroup(
|
||||
project, layout, groupsObjects[0], behaviorType, false);
|
||||
for (size_t i = 1; i < groupsObjects.size(); i++) {
|
||||
auto &objectName = groupsObjects[i];
|
||||
auto& objectName = groupsObjects[i];
|
||||
|
||||
if (layout.HasObjectNamed(objectName)) {
|
||||
auto &object = layout.GetObject(objectName);
|
||||
auto& object = layout.GetObject(objectName);
|
||||
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
|
||||
return behaviorNames;
|
||||
}
|
||||
if (project.HasObjectNamed(objectName)) {
|
||||
auto &object = project.GetObject(objectName);
|
||||
auto& object = project.GetObject(objectName);
|
||||
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
|
||||
return behaviorNames;
|
||||
}
|
||||
@@ -529,10 +576,10 @@ std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
|
||||
return behaviorNames;
|
||||
}
|
||||
|
||||
bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
|
||||
const gd::ObjectsContainer &layout,
|
||||
const gd::String &objectOrGroupName,
|
||||
const gd::String &behaviorName,
|
||||
bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
const gd::String& objectOrGroupName,
|
||||
const gd::String& behaviorName,
|
||||
bool searchInGroups) {
|
||||
// Search in objects.
|
||||
if (layout.HasObjectNamed(objectOrGroupName)) {
|
||||
@@ -547,9 +594,10 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
|
||||
}
|
||||
|
||||
// Search in groups.
|
||||
// Currently, a group is considered as the "intersection" of all of its objects.
|
||||
// Search "groups is the intersection of its objects" in the codebase.
|
||||
const gd::ObjectsContainer *container;
|
||||
// Currently, a group is considered as the "intersection" of all of its
|
||||
// objects. Search "groups is the intersection of its objects" in the
|
||||
// codebase.
|
||||
const gd::ObjectsContainer* container;
|
||||
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
container = &layout;
|
||||
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
@@ -557,7 +605,7 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
const vector<gd::String> &groupsObjects =
|
||||
const vector<gd::String>& groupsObjects =
|
||||
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
|
||||
|
||||
// Empty groups don't contain any behavior.
|
||||
@@ -566,9 +614,9 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
|
||||
}
|
||||
|
||||
// Check that all objects have the behavior.
|
||||
for (auto &&object : groupsObjects) {
|
||||
if (!HasBehaviorInObjectOrGroup(project, layout, object, behaviorName,
|
||||
false)) {
|
||||
for (auto&& object : groupsObjects) {
|
||||
if (!HasBehaviorInObjectOrGroup(
|
||||
project, layout, object, behaviorName, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -576,18 +624,18 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
|
||||
}
|
||||
|
||||
bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
gd::String objectOrGroupName,
|
||||
gd::String behaviorName,
|
||||
bool searchInGroups) {
|
||||
const gd::ObjectsContainer& layout,
|
||||
gd::String objectOrGroupName,
|
||||
gd::String behaviorName,
|
||||
bool searchInGroups) {
|
||||
// Search in objects.
|
||||
if (layout.HasObjectNamed(objectOrGroupName)) {
|
||||
auto &object = layout.GetObject(objectOrGroupName);
|
||||
auto& object = layout.GetObject(objectOrGroupName);
|
||||
return object.HasBehaviorNamed(behaviorName) &&
|
||||
object.GetBehavior(behaviorName).IsDefaultBehavior();
|
||||
}
|
||||
if (project.HasObjectNamed(objectOrGroupName)) {
|
||||
auto &object = project.GetObject(objectOrGroupName);
|
||||
auto& object = project.GetObject(objectOrGroupName);
|
||||
return object.HasBehaviorNamed(behaviorName) &&
|
||||
object.GetBehavior(behaviorName).IsDefaultBehavior();
|
||||
}
|
||||
@@ -597,9 +645,10 @@ bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
|
||||
}
|
||||
|
||||
// Search in groups.
|
||||
// Currently, a group is considered as the "intersection" of all of its objects.
|
||||
// Search "groups is the intersection of its objects" in the codebase.
|
||||
const gd::ObjectsContainer *container;
|
||||
// Currently, a group is considered as the "intersection" of all of its
|
||||
// objects. Search "groups is the intersection of its objects" in the
|
||||
// codebase.
|
||||
const gd::ObjectsContainer* container;
|
||||
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
container = &layout;
|
||||
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
@@ -607,7 +656,7 @@ bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
const vector<gd::String> &groupsObjects =
|
||||
const vector<gd::String>& groupsObjects =
|
||||
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
|
||||
|
||||
// Empty groups don't contain any behavior.
|
||||
@@ -616,30 +665,32 @@ bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
|
||||
}
|
||||
|
||||
// Check that all objects have the same type.
|
||||
for (auto &&object : groupsObjects) {
|
||||
if (!IsDefaultBehavior(project, layout, object, behaviorName,
|
||||
false)) {
|
||||
for (auto&& object : groupsObjects) {
|
||||
if (!IsDefaultBehavior(project, layout, object, behaviorName, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
const gd::String& objectOrGroupName,
|
||||
const gd::String& behaviorName,
|
||||
bool searchInGroups) {
|
||||
gd::String GD_CORE_API
|
||||
GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
const gd::String& objectOrGroupName,
|
||||
const gd::String& behaviorName,
|
||||
bool searchInGroups) {
|
||||
// Search in objects.
|
||||
if (layout.HasObjectNamed(objectOrGroupName)) {
|
||||
auto &object = layout.GetObject(objectOrGroupName);
|
||||
return object.HasBehaviorNamed(behaviorName) ?
|
||||
object.GetBehavior(behaviorName).GetTypeName() : "";
|
||||
auto& object = layout.GetObject(objectOrGroupName);
|
||||
return object.HasBehaviorNamed(behaviorName)
|
||||
? object.GetBehavior(behaviorName).GetTypeName()
|
||||
: "";
|
||||
}
|
||||
if (project.HasObjectNamed(objectOrGroupName)) {
|
||||
auto &object = project.GetObject(objectOrGroupName);
|
||||
return object.HasBehaviorNamed(behaviorName) ?
|
||||
object.GetBehavior(behaviorName).GetTypeName() : "";
|
||||
auto& object = project.GetObject(objectOrGroupName);
|
||||
return object.HasBehaviorNamed(behaviorName)
|
||||
? object.GetBehavior(behaviorName).GetTypeName()
|
||||
: "";
|
||||
}
|
||||
|
||||
if (!searchInGroups) {
|
||||
@@ -647,9 +698,10 @@ gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContain
|
||||
}
|
||||
|
||||
// Search in groups.
|
||||
// Currently, a group is considered as the "intersection" of all of its objects.
|
||||
// Search "groups is the intersection of its objects" in the codebase.
|
||||
const gd::ObjectsContainer *container;
|
||||
// Currently, a group is considered as the "intersection" of all of its
|
||||
// objects. Search "groups is the intersection of its objects" in the
|
||||
// codebase.
|
||||
const gd::ObjectsContainer* container;
|
||||
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
container = &layout;
|
||||
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
@@ -657,7 +709,7 @@ gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContain
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
const vector<gd::String> &groupsObjects =
|
||||
const vector<gd::String>& groupsObjects =
|
||||
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
|
||||
|
||||
// Empty groups don't contain any behavior.
|
||||
@@ -668,9 +720,9 @@ gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContain
|
||||
// Check that all objects have the behavior with the same type.
|
||||
auto behaviorType = GetTypeOfBehaviorInObjectOrGroup(
|
||||
project, layout, groupsObjects[0], behaviorName, false);
|
||||
for (auto &&object : groupsObjects) {
|
||||
if (GetTypeOfBehaviorInObjectOrGroup(project, layout, object, behaviorName,
|
||||
false) != behaviorType) {
|
||||
for (auto&& object : groupsObjects) {
|
||||
if (GetTypeOfBehaviorInObjectOrGroup(
|
||||
project, layout, object, behaviorName, false) != behaviorType) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -682,14 +734,14 @@ gd::String GD_CORE_API GetTypeOfBehavior(const gd::ObjectsContainer& project,
|
||||
gd::String name,
|
||||
bool searchInGroups) {
|
||||
for (std::size_t i = 0; i < layout.GetObjectsCount(); ++i) {
|
||||
const auto &object = layout.GetObject(i);
|
||||
const auto& object = layout.GetObject(i);
|
||||
if (object.HasBehaviorNamed(name)) {
|
||||
return object.GetBehavior(name).GetTypeName();
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < project.GetObjectsCount(); ++i) {
|
||||
const auto &object = project.GetObject(i);
|
||||
const auto& object = project.GetObject(i);
|
||||
if (object.HasBehaviorNamed(name)) {
|
||||
return object.GetBehavior(name).GetTypeName();
|
||||
}
|
||||
@@ -726,8 +778,9 @@ GetBehaviorsOfObject(const gd::ObjectsContainer& project,
|
||||
}
|
||||
|
||||
// Search in groups
|
||||
// Currently, a group is considered as the "intersection" of all of its objects.
|
||||
// Search "groups is the intersection of its objects" in the codebase.
|
||||
// Currently, a group is considered as the "intersection" of all of its
|
||||
// objects. Search "groups is the intersection of its objects" in the
|
||||
// codebase.
|
||||
if (searchInGroups) {
|
||||
for (std::size_t i = 0; i < layout.GetObjectGroups().size(); ++i) {
|
||||
if (layout.GetObjectGroups()[i].GetName() == name) {
|
||||
|
@@ -369,9 +369,9 @@ class GD_CORE_API Layout {
|
||||
private:
|
||||
gd::String name; ///< Scene name
|
||||
gd::String mangledName; ///< The scene name mangled by SceneNameMangler
|
||||
unsigned int backgroundColorR; ///< Background color Red component
|
||||
unsigned int backgroundColorG; ///< Background color Green component
|
||||
unsigned int backgroundColorB; ///< Background color Blue component
|
||||
unsigned int backgroundColorR = 0; ///< Background color Red component
|
||||
unsigned int backgroundColorG = 0; ///< Background color Green component
|
||||
unsigned int backgroundColorB = 0; ///< Background color Blue component
|
||||
gd::String title; ///< Title displayed in the window
|
||||
gd::VariablesContainer variables; ///< Variables list
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
@@ -379,12 +379,12 @@ class GD_CORE_API Layout {
|
||||
gd::LayersContainer layers;
|
||||
std::map<gd::String, std::unique_ptr<gd::BehaviorsSharedData>>
|
||||
behaviorsSharedData; ///< Initial shared datas of behaviors
|
||||
bool stopSoundsOnStartup; ///< True to make the scene stop all sounds at
|
||||
///< startup.
|
||||
bool standardSortMethod; ///< True to sort objects using standard sort.
|
||||
bool disableInputWhenNotFocused; /// If set to true, the input must be
|
||||
/// disabled when the window do not have the
|
||||
/// focus.
|
||||
bool stopSoundsOnStartup = true; ///< True to make the scene stop all sounds at
|
||||
///< startup.
|
||||
bool standardSortMethod = true; ///< True to sort objects using standard sort.
|
||||
bool disableInputWhenNotFocused = true; /// If set to true, the input must be
|
||||
/// disabled when the window do not have the
|
||||
/// focus.
|
||||
static gd::BehaviorsSharedData
|
||||
badBehaviorSharedData; ///< Null object, returned when
|
||||
///< GetBehaviorSharedData can not find the
|
||||
@@ -405,18 +405,6 @@ class GD_CORE_API Layout {
|
||||
const gd::String& behaviorsType);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Functor testing layout name.
|
||||
* \see gd::Layout
|
||||
*/
|
||||
struct LayoutHasName
|
||||
: public std::binary_function<std::unique_ptr<Layout>, gd::String, bool> {
|
||||
bool operator()(const std::unique_ptr<Layout>& layout,
|
||||
gd::String name) const {
|
||||
return layout->GetName() == name;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get the names of all layers from the given layout
|
||||
* that are invisible.
|
||||
|
@@ -12,8 +12,9 @@
|
||||
#include "GDCore/Project/CustomBehavior.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Project/QuickCustomization.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
#include "GDCore/Tools/UUID/UUID.h"
|
||||
|
||||
@@ -27,8 +28,8 @@ Object::Object(const gd::String& name_,
|
||||
: name(name_),
|
||||
configuration(std::move(configuration_)),
|
||||
objectVariables(gd::VariablesContainer::SourceType::Object) {
|
||||
SetType(type_);
|
||||
}
|
||||
SetType(type_);
|
||||
}
|
||||
|
||||
Object::Object(const gd::String& name_,
|
||||
const gd::String& type_,
|
||||
@@ -36,8 +37,8 @@ Object::Object(const gd::String& name_,
|
||||
: name(name_),
|
||||
configuration(configuration_),
|
||||
objectVariables(gd::VariablesContainer::SourceType::Object) {
|
||||
SetType(type_);
|
||||
}
|
||||
SetType(type_);
|
||||
}
|
||||
|
||||
void Object::Init(const gd::Object& object) {
|
||||
persistentUuid = object.persistentUuid;
|
||||
@@ -54,9 +55,7 @@ void Object::Init(const gd::Object& object) {
|
||||
configuration = object.configuration->Clone();
|
||||
}
|
||||
|
||||
gd::ObjectConfiguration& Object::GetConfiguration() {
|
||||
return *configuration;
|
||||
}
|
||||
gd::ObjectConfiguration& Object::GetConfiguration() { return *configuration; }
|
||||
|
||||
const gd::ObjectConfiguration& Object::GetConfiguration() const {
|
||||
return *configuration;
|
||||
@@ -77,8 +76,7 @@ bool Object::RenameBehavior(const gd::String& name, const gd::String& newName) {
|
||||
behaviors.find(newName) != behaviors.end())
|
||||
return false;
|
||||
|
||||
std::unique_ptr<Behavior> aut =
|
||||
std::move(behaviors.find(name)->second);
|
||||
std::unique_ptr<Behavior> aut = std::move(behaviors.find(name)->second);
|
||||
behaviors.erase(name);
|
||||
behaviors[newName] = std::move(aut);
|
||||
behaviors[newName]->SetName(newName);
|
||||
@@ -99,10 +97,10 @@ bool Object::HasBehaviorNamed(const gd::String& name) const {
|
||||
}
|
||||
|
||||
gd::Behavior* Object::AddNewBehavior(const gd::Project& project,
|
||||
const gd::String& type,
|
||||
const gd::String& name) {
|
||||
auto initializeAndAdd =
|
||||
[this, &name](std::unique_ptr<gd::Behavior> behavior) {
|
||||
const gd::String& type,
|
||||
const gd::String& name) {
|
||||
auto initializeAndAdd = [this,
|
||||
&name](std::unique_ptr<gd::Behavior> behavior) {
|
||||
behavior->InitializeContent();
|
||||
this->behaviors[name] = std::move(behavior);
|
||||
return this->behaviors[name].get();
|
||||
@@ -111,18 +109,17 @@ gd::Behavior* Object::AddNewBehavior(const gd::Project& project,
|
||||
if (project.HasEventsBasedBehavior(type)) {
|
||||
return initializeAndAdd(
|
||||
gd::make_unique<CustomBehavior>(name, project, type));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
const gd::BehaviorMetadata& behaviorMetadata =
|
||||
gd::MetadataProvider::GetBehaviorMetadata(project.GetCurrentPlatform(),
|
||||
type);
|
||||
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
gd::LogWarning("Tried to create a behavior with an unknown type: " + type
|
||||
+ " on object " + GetName() + "!");
|
||||
// It's probably an events-based behavior that was removed.
|
||||
// Create a custom behavior to preserve the properties values.
|
||||
return initializeAndAdd(
|
||||
gd::make_unique<CustomBehavior>(name, project, type));
|
||||
gd::LogWarning("Tried to create a behavior with an unknown type: " +
|
||||
type + " on object " + GetName() + "!");
|
||||
// It's probably an events-based behavior that was removed.
|
||||
// Create a custom behavior to preserve the properties values.
|
||||
return initializeAndAdd(
|
||||
gd::make_unique<CustomBehavior>(name, project, type));
|
||||
}
|
||||
std::unique_ptr<gd::Behavior> behavior(behaviorMetadata.Get().Clone());
|
||||
behavior->SetName(name);
|
||||
@@ -196,6 +193,23 @@ void Object::UnserializeFrom(gd::Project& project,
|
||||
else {
|
||||
behavior->UnserializeFrom(behaviorElement);
|
||||
}
|
||||
|
||||
bool isFolded = behaviorElement.GetBoolAttribute("isFolded", false);
|
||||
behavior->SetFolded(isFolded);
|
||||
|
||||
// Handle Quick Customization info.
|
||||
if (behaviorElement.HasChild(
|
||||
"propertiesQuickCustomizationVisibilities")) {
|
||||
behavior->GetPropertiesQuickCustomizationVisibilities().UnserializeFrom(
|
||||
behaviorElement.GetChild(
|
||||
"propertiesQuickCustomizationVisibilities"));
|
||||
}
|
||||
if (behaviorElement.HasChild("quickCustomizationVisibility")) {
|
||||
behavior->SetQuickCustomizationVisibility(
|
||||
QuickCustomization::StringAsVisibility(
|
||||
behaviorElement.GetStringAttribute(
|
||||
"quickCustomizationVisibility")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,8 +231,8 @@ void Object::SerializeTo(SerializerElement& element) const {
|
||||
std::vector<gd::String> allBehaviors = GetAllBehaviorNames();
|
||||
for (std::size_t i = 0; i < allBehaviors.size(); ++i) {
|
||||
const gd::Behavior& behavior = GetBehavior(allBehaviors[i]);
|
||||
// Default behaviors are added at the object creation according to metadata.
|
||||
// They don't need to be serialized.
|
||||
// Default behaviors are added at the object creation according to
|
||||
// metadata. They don't need to be serialized.
|
||||
if (behavior.IsDefaultBehavior()) {
|
||||
continue;
|
||||
}
|
||||
@@ -228,8 +242,27 @@ void Object::SerializeTo(SerializerElement& element) const {
|
||||
behaviorElement.RemoveChild("type"); // The content can contain type or
|
||||
// name properties, remove them.
|
||||
behaviorElement.RemoveChild("name");
|
||||
behaviorElement.RemoveChild("isFolded");
|
||||
behaviorElement.SetAttribute("type", behavior.GetTypeName());
|
||||
behaviorElement.SetAttribute("name", behavior.GetName());
|
||||
if (behavior.IsFolded()) behaviorElement.SetAttribute("isFolded", true);
|
||||
|
||||
// Handle Quick Customization info.
|
||||
behaviorElement.RemoveChild("propertiesQuickCustomizationVisibilities");
|
||||
const QuickCustomizationVisibilitiesContainer&
|
||||
propertiesQuickCustomizationVisibilities =
|
||||
behavior.GetPropertiesQuickCustomizationVisibilities();
|
||||
if (!propertiesQuickCustomizationVisibilities.IsEmpty()) {
|
||||
propertiesQuickCustomizationVisibilities.SerializeTo(
|
||||
behaviorElement.AddChild("propertiesQuickCustomizationVisibilities"));
|
||||
}
|
||||
const QuickCustomization::Visibility visibility =
|
||||
behavior.GetQuickCustomizationVisibility();
|
||||
if (visibility != QuickCustomization::Visibility::Default) {
|
||||
behaviorElement.SetAttribute(
|
||||
"quickCustomizationVisibility",
|
||||
QuickCustomization::VisibilityAsString(visibility));
|
||||
}
|
||||
}
|
||||
|
||||
configuration->SerializeTo(element);
|
||||
|
@@ -193,7 +193,7 @@ class GD_CORE_API ObjectFolderOrObject {
|
||||
static gd::ObjectFolderOrObject badObjectFolderOrObject;
|
||||
|
||||
gd::ObjectFolderOrObject*
|
||||
parent; // nullptr if root folder, points to the parent folder otherwise.
|
||||
parent = nullptr; // nullptr if root folder, points to the parent folder otherwise.
|
||||
QuickCustomization::Visibility quickCustomizationVisibility;
|
||||
|
||||
// Representing an object:
|
||||
|
@@ -20,8 +20,8 @@ namespace gd {
|
||||
/**
|
||||
* \brief Represents an object group.
|
||||
*
|
||||
* Objects groups do not really contains objects : They are just used in events,
|
||||
* so as to create events which can be applied to several objects.
|
||||
* Objects groups do not really contains objects: they are just used in events,
|
||||
* to create events which can be applied to several objects.
|
||||
*
|
||||
* \ingroup PlatformDefinition
|
||||
*/
|
||||
|
@@ -16,7 +16,9 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
ObjectsContainer::ObjectsContainer() {
|
||||
ObjectsContainer::ObjectsContainer(
|
||||
const ObjectsContainer::SourceType sourceType_)
|
||||
: sourceType(sourceType_) {
|
||||
rootFolder = gd::make_unique<gd::ObjectFolderOrObject>("__ROOT");
|
||||
}
|
||||
|
||||
@@ -34,6 +36,7 @@ ObjectsContainer& ObjectsContainer::operator=(
|
||||
}
|
||||
|
||||
void ObjectsContainer::Init(const gd::ObjectsContainer& other) {
|
||||
sourceType = other.sourceType;
|
||||
initialObjects = gd::Clone(other.initialObjects);
|
||||
objectGroups = other.objectGroups;
|
||||
// The objects folders are not copied.
|
||||
@@ -205,6 +208,14 @@ void ObjectsContainer::MoveObjectFolderOrObjectToAnotherContainerInFolder(
|
||||
objectFolderOrObject, newParentFolder, newPosition);
|
||||
}
|
||||
|
||||
std::set<gd::String> ObjectsContainer::GetAllObjectNames() const {
|
||||
std::set<gd::String> names;
|
||||
for (const auto& object : initialObjects) {
|
||||
names.insert(object->GetName());
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
std::vector<const ObjectFolderOrObject*>
|
||||
ObjectsContainer::GetAllObjectFolderOrObjects() const {
|
||||
std::vector<const ObjectFolderOrObject*> results;
|
||||
|
@@ -3,10 +3,11 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_OBJECTSCONTAINER_H
|
||||
#define GDCORE_OBJECTSCONTAINER_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Project/ObjectGroupsContainer.h"
|
||||
#include "GDCore/Project/ObjectFolderOrObject.h"
|
||||
@@ -35,15 +36,25 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API ObjectsContainer {
|
||||
public:
|
||||
enum SourceType {
|
||||
Unknown,
|
||||
Global,
|
||||
Scene,
|
||||
Object,
|
||||
Function,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Default constructor creating a container without any objects.
|
||||
* \brief Constructor creating a container without any objects.
|
||||
*/
|
||||
ObjectsContainer();
|
||||
ObjectsContainer(const SourceType sourceType);
|
||||
virtual ~ObjectsContainer();
|
||||
|
||||
|
||||
ObjectsContainer(const ObjectsContainer&);
|
||||
ObjectsContainer& operator=(const ObjectsContainer& rhs);
|
||||
|
||||
SourceType GetSourceType() const { return sourceType; }
|
||||
|
||||
/** \name Objects management
|
||||
* Members functions related to objects management.
|
||||
*/
|
||||
@@ -57,7 +68,7 @@ class GD_CORE_API ObjectsContainer {
|
||||
/**
|
||||
* \brief Return a reference to the object called \a name.
|
||||
*/
|
||||
Object& GetObject(const gd::String& name);
|
||||
gd::Object& GetObject(const gd::String& name);
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the object called \a name.
|
||||
@@ -68,7 +79,7 @@ class GD_CORE_API ObjectsContainer {
|
||||
* \brief Return a reference to the object at position \a index in the objects
|
||||
* list
|
||||
*/
|
||||
Object& GetObject(std::size_t index);
|
||||
gd::Object& GetObject(std::size_t index);
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the object at position \a index in the objects
|
||||
@@ -168,6 +179,8 @@ class GD_CORE_API ObjectsContainer {
|
||||
const std::vector<std::unique_ptr<gd::Object> >& GetObjects() const {
|
||||
return initialObjects;
|
||||
}
|
||||
|
||||
std::set<gd::String> GetAllObjectNames() const;
|
||||
///@}
|
||||
|
||||
/**
|
||||
@@ -232,6 +245,7 @@ class GD_CORE_API ObjectsContainer {
|
||||
gd::ObjectGroupsContainer objectGroups;
|
||||
|
||||
private:
|
||||
SourceType sourceType = Unknown;
|
||||
std::unique_ptr<gd::ObjectFolderOrObject> rootFolder;
|
||||
|
||||
/**
|
||||
@@ -242,5 +256,3 @@ class GD_CORE_API ObjectsContainer {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_OBJECTSCONTAINER_H
|
||||
|
@@ -416,7 +416,8 @@ gd::String ObjectsContainersList::GetTypeOfObject(
|
||||
return "";
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
gd::ObjectsContainer emptyObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Unknown);
|
||||
return gd::GetTypeOfObject(emptyObjectsContainer, *objectsContainers[0],
|
||||
objectName, true);
|
||||
}
|
||||
@@ -439,7 +440,8 @@ bool ObjectsContainersList::HasBehaviorInObjectOrGroup(
|
||||
return false;
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
gd::ObjectsContainer emptyObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Unknown);
|
||||
return gd::HasBehaviorInObjectOrGroup(
|
||||
emptyObjectsContainer, *objectsContainers[0], objectOrGroupName,
|
||||
behaviorName, true);
|
||||
@@ -468,7 +470,8 @@ gd::String ObjectsContainersList::GetTypeOfBehaviorInObjectOrGroup(
|
||||
return "";
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
gd::ObjectsContainer emptyObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Unknown);
|
||||
return gd::GetTypeOfBehaviorInObjectOrGroup(
|
||||
emptyObjectsContainer, *objectsContainers[0], objectOrGroupName,
|
||||
behaviorName, searchInGroups);
|
||||
@@ -495,7 +498,8 @@ gd::String ObjectsContainersList::GetTypeOfBehavior(
|
||||
return "";
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
gd::ObjectsContainer emptyObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Unknown);
|
||||
return gd::GetTypeOfBehavior(emptyObjectsContainer, *objectsContainers[0],
|
||||
behaviorName, searchInGroups);
|
||||
}
|
||||
@@ -521,7 +525,8 @@ std::vector<gd::String> ObjectsContainersList::GetBehaviorsOfObject(
|
||||
return behaviors;
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
gd::ObjectsContainer emptyObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Unknown);
|
||||
return gd::GetBehaviorsOfObject(emptyObjectsContainer,
|
||||
*objectsContainers[0], objectName,
|
||||
searchInGroups);
|
||||
@@ -530,6 +535,33 @@ std::vector<gd::String> ObjectsContainersList::GetBehaviorsOfObject(
|
||||
*objectsContainers[0], *objectsContainers[1], objectName, searchInGroups);
|
||||
}
|
||||
|
||||
std::vector<gd::String> ObjectsContainersList::GetBehaviorNamesInObjectOrGroup(
|
||||
const gd::String &objectOrGroupName, const gd::String &behaviorType, bool searchInGroups) const {
|
||||
if (objectsContainers.size() > 2) {
|
||||
// TODO: rework forwarded methods so they can work with any number of
|
||||
// containers.
|
||||
gd::LogFatalError(
|
||||
"ObjectsContainersList::GetBehaviorNamesInObjectOrGroup called with objectsContainers "
|
||||
"not being exactly 2. This is a logical error and will crash.");
|
||||
}
|
||||
if (objectsContainers.size() == 0) {
|
||||
gd::LogWarning("ObjectsContainersList::GetBehaviorNamesInObjectOrGroup called without any "
|
||||
"objectsContainer");
|
||||
std::vector<gd::String> behaviors;
|
||||
return behaviors;
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer(
|
||||
gd::ObjectsContainer::SourceType::Unknown);
|
||||
return gd::GetBehaviorNamesInObjectOrGroup(emptyObjectsContainer,
|
||||
*objectsContainers[0], objectOrGroupName, behaviorType,
|
||||
searchInGroups);
|
||||
}
|
||||
return gd::GetBehaviorNamesInObjectOrGroup(
|
||||
*objectsContainers[0], *objectsContainers[1], objectOrGroupName, behaviorType, searchInGroups);
|
||||
}
|
||||
|
||||
|
||||
std::vector<gd::String> ObjectsContainersList::GetAnimationNamesOfObject(
|
||||
const gd::String &objectOrGroupName) const {
|
||||
std::vector<gd::String> animationNames;
|
||||
@@ -589,4 +621,35 @@ std::vector<gd::String> ObjectsContainersList::GetAnimationNamesOfObject(
|
||||
return animationNames;
|
||||
}
|
||||
|
||||
const ObjectsContainer *
|
||||
ObjectsContainersList::GetObjectsContainerFromObjectName(
|
||||
const gd::String &objectOrGroupName) const {
|
||||
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
|
||||
++it) {
|
||||
if ((*it)->HasObjectNamed(objectOrGroupName) ||
|
||||
(*it)->GetObjectGroups().Has(objectOrGroupName)) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const gd::ObjectsContainer::SourceType
|
||||
ObjectsContainersList::GetObjectsContainerSourceType(
|
||||
const gd::String &objectOrGroupName) const {
|
||||
const auto *objectsContainer =
|
||||
GetObjectsContainerFromObjectName(objectOrGroupName);
|
||||
return objectsContainer ? objectsContainer->GetSourceType()
|
||||
: gd::ObjectsContainer::SourceType::Unknown;
|
||||
}
|
||||
|
||||
const gd::ObjectsContainer &
|
||||
ObjectsContainersList::GetObjectsContainer(std::size_t index) const {
|
||||
return *objectsContainers[index];
|
||||
}
|
||||
|
||||
std::size_t ObjectsContainersList::GetObjectsContainersCount() const {
|
||||
return objectsContainers.size();
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -2,12 +2,12 @@
|
||||
#include <vector>
|
||||
|
||||
#include "Variable.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
|
||||
namespace gd {
|
||||
class String;
|
||||
class Project;
|
||||
class Layout;
|
||||
class ObjectsContainer;
|
||||
class VariablesContainer;
|
||||
class Object;
|
||||
class ObjectConfiguration;
|
||||
@@ -50,6 +50,11 @@ class GD_CORE_API ObjectsContainersList {
|
||||
*/
|
||||
bool HasObjectOrGroupNamed(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* \brief Check if the specified object exists ignoring groups.
|
||||
*/
|
||||
bool HasObjectNamed(const gd::String& name) const;
|
||||
|
||||
enum VariableExistence {
|
||||
DoesNotExist,
|
||||
Exists,
|
||||
@@ -128,6 +133,18 @@ class GD_CORE_API ObjectsContainersList {
|
||||
std::vector<gd::String> GetBehaviorsOfObject(
|
||||
const gd::String& objectName, bool searchInGroups = true) const;
|
||||
|
||||
/**
|
||||
* \brief Get behaviors of an object/group of a given behavior type.
|
||||
* \note The behaviors of a group are the behaviors which are found in common
|
||||
* when looking all the objects of the group.
|
||||
*
|
||||
* @return Vector containing names of behaviors
|
||||
*/
|
||||
std::vector<gd::String>
|
||||
GetBehaviorNamesInObjectOrGroup(const gd::String &objectOrGroupName,
|
||||
const gd::String &behaviorType,
|
||||
bool searchInGroups = true) const;
|
||||
|
||||
/**
|
||||
* \brief Get the animation names of an object/group.
|
||||
* \note The animation names of a group are the animation names common to
|
||||
@@ -173,13 +190,41 @@ class GD_CORE_API ObjectsContainersList {
|
||||
std::function<void(const gd::String& variableName,
|
||||
const gd::Variable& variable)> fn) const;
|
||||
|
||||
/**
|
||||
* \brief Return the source type of the container for the specified object or
|
||||
* group of objects.
|
||||
*/
|
||||
const gd::ObjectsContainer::SourceType GetObjectsContainerSourceType(
|
||||
const gd::String& objectOrGroupName) const;
|
||||
|
||||
/**
|
||||
* Get the objects container for for the specified object or group of objects.
|
||||
*/
|
||||
const ObjectsContainer *
|
||||
GetObjectsContainerFromObjectName(const gd::String &objectOrGroupName) const;
|
||||
|
||||
/**
|
||||
* \brief Return a the objects container at position \a index.
|
||||
*
|
||||
* \warning The returned `ObjectsContainer` may contain cloned objects (in the case of
|
||||
* `ProjectScopedContainers::MakeNewProjectScopedContainersForEventsBasedObject`)
|
||||
* or "fake" objects used by events like parameters. They must not be used to
|
||||
* edit the objects.
|
||||
* Search for "ProjectScopedContainers wrongly containing temporary objects containers or objects"
|
||||
* in the codebase.
|
||||
*/
|
||||
const gd::ObjectsContainer &GetObjectsContainer(std::size_t index) const;
|
||||
|
||||
/**
|
||||
* \brief Return the number of objects containers.
|
||||
*/
|
||||
std::size_t GetObjectsContainersCount() const;
|
||||
|
||||
/** Do not use - should be private but accessible to let Emscripten create a
|
||||
* temporary. */
|
||||
ObjectsContainersList(){};
|
||||
|
||||
private:
|
||||
bool HasObjectNamed(const gd::String& name) const;
|
||||
|
||||
const gd::Object* GetObject(const gd::String& name) const;
|
||||
|
||||
bool HasObjectWithVariableNamed(const gd::String& objectName,
|
||||
|
@@ -71,23 +71,22 @@ Project::Project()
|
||||
isPlayableWithKeyboard(false),
|
||||
isPlayableWithGamepad(false),
|
||||
isPlayableWithMobile(false),
|
||||
currentPlatform(NULL),
|
||||
currentPlatform(nullptr),
|
||||
gdMajorVersion(gd::VersionWrapper::Major()),
|
||||
gdMinorVersion(gd::VersionWrapper::Minor()),
|
||||
gdBuildVersion(gd::VersionWrapper::Build()),
|
||||
variables(gd::VariablesContainer::SourceType::Global) {}
|
||||
variables(gd::VariablesContainer::SourceType::Global),
|
||||
objectsContainer(gd::ObjectsContainer::SourceType::Global) {}
|
||||
|
||||
Project::~Project() {}
|
||||
|
||||
void Project::ResetProjectUuid() { projectUuid = UUID::MakeUuid4(); }
|
||||
|
||||
std::unique_ptr<gd::Object> Project::CreateObject(
|
||||
const gd::String& objectType, const gd::String& name) const {
|
||||
std::unique_ptr<gd::Object> object = gd::make_unique<Object>(
|
||||
name, objectType, CreateObjectConfiguration(objectType));
|
||||
|
||||
void Project::EnsureObjectDefaultBehaviors(gd::Object& object) const {
|
||||
auto& platform = GetCurrentPlatform();
|
||||
auto& project = *this;
|
||||
auto& objectType = object.GetType();
|
||||
|
||||
auto addDefaultBehavior = [&platform, &project, &object, &objectType](
|
||||
const gd::String& behaviorType) {
|
||||
auto& behaviorMetadata =
|
||||
@@ -97,17 +96,47 @@ std::unique_ptr<gd::Object> Project::CreateObject(
|
||||
" has an unknown default behavior: " + behaviorType);
|
||||
return;
|
||||
}
|
||||
auto* behavior = object->AddNewBehavior(
|
||||
project, behaviorType, behaviorMetadata.GetDefaultName());
|
||||
behavior->SetDefaultBehavior(true);
|
||||
|
||||
const gd::String& behaviorName = behaviorMetadata.GetDefaultName();
|
||||
|
||||
// Check if we can keep a behavior that would have been already set up on the object.
|
||||
if (object.HasBehaviorNamed(behaviorName)) {
|
||||
const auto& behavior = object.GetBehavior(behaviorName);
|
||||
|
||||
if (!behavior.IsDefaultBehavior() || behavior.GetTypeName() != behaviorType) {
|
||||
// Behavior type has changed, remove it so it is re-created.
|
||||
object.RemoveBehavior(behaviorName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!object.HasBehaviorNamed(behaviorName)) {
|
||||
auto* behavior = object.AddNewBehavior(
|
||||
project, behaviorType, behaviorName);
|
||||
behavior->SetDefaultBehavior(true);
|
||||
}
|
||||
};
|
||||
|
||||
auto &objectMetadata =
|
||||
gd::MetadataProvider::GetObjectMetadata(platform, objectType);
|
||||
if (!MetadataProvider::IsBadObjectMetadata(objectMetadata)) {
|
||||
for (auto &behaviorType : objectMetadata.GetDefaultBehaviors()) {
|
||||
// Add all default behaviors.
|
||||
const auto& defaultBehaviorTypes = objectMetadata.GetDefaultBehaviors();
|
||||
for (auto &behaviorType : defaultBehaviorTypes) {
|
||||
addDefaultBehavior(behaviorType);
|
||||
}
|
||||
|
||||
// Ensure there are no default behaviors that would not be required left on the object.
|
||||
for (const auto& behaviorName : object.GetAllBehaviorNames()) {
|
||||
auto& behavior = object.GetBehavior(behaviorName);
|
||||
if (!behavior.IsDefaultBehavior()) {
|
||||
// Non default behaviors are not handled by this function.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (defaultBehaviorTypes.find(behavior.GetTypeName()) == defaultBehaviorTypes.end()) {
|
||||
object.RemoveBehavior(behaviorName);
|
||||
}
|
||||
}
|
||||
}
|
||||
// During project deserialization, event-based object metadata are not yet
|
||||
// generated. Default behaviors will be added by
|
||||
@@ -115,6 +144,14 @@ std::unique_ptr<gd::Object> Project::CreateObject(
|
||||
else if (!project.HasEventsBasedObject(objectType)) {
|
||||
gd::LogWarning("Object: " + name + " has an unknown type: " + objectType);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<gd::Object> Project::CreateObject(
|
||||
const gd::String& objectType, const gd::String& name) const {
|
||||
std::unique_ptr<gd::Object> object = gd::make_unique<Object>(
|
||||
name, objectType, CreateObjectConfiguration(objectType));
|
||||
|
||||
EnsureObjectDefaultBehaviors(*object);
|
||||
|
||||
return std::move(object);
|
||||
}
|
||||
@@ -264,15 +301,21 @@ bool Project::RemovePlatform(const gd::String& platformName) {
|
||||
bool Project::HasLayoutNamed(const gd::String& name) const {
|
||||
return (find_if(scenes.begin(),
|
||||
scenes.end(),
|
||||
bind2nd(gd::LayoutHasName(), name)) != scenes.end());
|
||||
[&name](const std::unique_ptr<gd::Layout>& layout) {
|
||||
return layout->GetName() == name;
|
||||
}) != scenes.end());
|
||||
}
|
||||
gd::Layout& Project::GetLayout(const gd::String& name) {
|
||||
return *(*find_if(
|
||||
scenes.begin(), scenes.end(), bind2nd(gd::LayoutHasName(), name)));
|
||||
scenes.begin(), scenes.end(), [&name](const std::unique_ptr<gd::Layout>& layout) {
|
||||
return layout->GetName() == name;
|
||||
}));
|
||||
}
|
||||
const gd::Layout& Project::GetLayout(const gd::String& name) const {
|
||||
return *(*find_if(
|
||||
scenes.begin(), scenes.end(), bind2nd(gd::LayoutHasName(), name)));
|
||||
scenes.begin(), scenes.end(), [&name](const std::unique_ptr<gd::Layout>& layout) {
|
||||
return layout->GetName() == name;
|
||||
}));
|
||||
}
|
||||
gd::Layout& Project::GetLayout(std::size_t index) { return *scenes[index]; }
|
||||
const gd::Layout& Project::GetLayout(std::size_t index) const {
|
||||
@@ -317,7 +360,9 @@ gd::Layout& Project::InsertLayout(const gd::Layout& layout,
|
||||
|
||||
void Project::RemoveLayout(const gd::String& name) {
|
||||
std::vector<std::unique_ptr<gd::Layout> >::iterator scene =
|
||||
find_if(scenes.begin(), scenes.end(), bind2nd(gd::LayoutHasName(), name));
|
||||
find_if(scenes.begin(), scenes.end(), [&name](const std::unique_ptr<gd::Layout>& layout) {
|
||||
return layout->GetName() == name;
|
||||
});
|
||||
if (scene == scenes.end()) return;
|
||||
|
||||
scenes.erase(scene);
|
||||
@@ -326,19 +371,24 @@ void Project::RemoveLayout(const gd::String& name) {
|
||||
bool Project::HasExternalEventsNamed(const gd::String& name) const {
|
||||
return (find_if(externalEvents.begin(),
|
||||
externalEvents.end(),
|
||||
bind2nd(gd::ExternalEventsHasName(), name)) !=
|
||||
externalEvents.end());
|
||||
[&name](const std::unique_ptr<gd::ExternalEvents>& externalEvents) {
|
||||
return externalEvents->GetName() == name;
|
||||
}) != externalEvents.end());
|
||||
}
|
||||
gd::ExternalEvents& Project::GetExternalEvents(const gd::String& name) {
|
||||
return *(*find_if(externalEvents.begin(),
|
||||
externalEvents.end(),
|
||||
bind2nd(gd::ExternalEventsHasName(), name)));
|
||||
[&name](const std::unique_ptr<gd::ExternalEvents>& externalEvents) {
|
||||
return externalEvents->GetName() == name;
|
||||
}));
|
||||
}
|
||||
const gd::ExternalEvents& Project::GetExternalEvents(
|
||||
const gd::String& name) const {
|
||||
return *(*find_if(externalEvents.begin(),
|
||||
externalEvents.end(),
|
||||
bind2nd(gd::ExternalEventsHasName(), name)));
|
||||
[&name](const std::unique_ptr<gd::ExternalEvents>& externalEvents) {
|
||||
return externalEvents->GetName() == name;
|
||||
}));
|
||||
}
|
||||
gd::ExternalEvents& Project::GetExternalEvents(std::size_t index) {
|
||||
return *externalEvents[index];
|
||||
@@ -382,7 +432,9 @@ void Project::RemoveExternalEvents(const gd::String& name) {
|
||||
std::vector<std::unique_ptr<gd::ExternalEvents> >::iterator events =
|
||||
find_if(externalEvents.begin(),
|
||||
externalEvents.end(),
|
||||
bind2nd(gd::ExternalEventsHasName(), name));
|
||||
[&name](const std::unique_ptr<gd::ExternalEvents>& externalEvents) {
|
||||
return externalEvents->GetName() == name;
|
||||
});
|
||||
if (events == externalEvents.end()) return;
|
||||
|
||||
externalEvents.erase(events);
|
||||
@@ -448,19 +500,24 @@ void Project::SwapExternalLayouts(std::size_t first, std::size_t second) {
|
||||
bool Project::HasExternalLayoutNamed(const gd::String& name) const {
|
||||
return (find_if(externalLayouts.begin(),
|
||||
externalLayouts.end(),
|
||||
bind2nd(gd::ExternalLayoutHasName(), name)) !=
|
||||
externalLayouts.end());
|
||||
[&name](const std::unique_ptr<gd::ExternalLayout>& externalLayout) {
|
||||
return externalLayout->GetName() == name;
|
||||
}) != externalLayouts.end());
|
||||
}
|
||||
gd::ExternalLayout& Project::GetExternalLayout(const gd::String& name) {
|
||||
return *(*find_if(externalLayouts.begin(),
|
||||
externalLayouts.end(),
|
||||
bind2nd(gd::ExternalLayoutHasName(), name)));
|
||||
[&name](const std::unique_ptr<gd::ExternalLayout>& externalLayout) {
|
||||
return externalLayout->GetName() == name;
|
||||
}));
|
||||
}
|
||||
const gd::ExternalLayout& Project::GetExternalLayout(
|
||||
const gd::String& name) const {
|
||||
return *(*find_if(externalLayouts.begin(),
|
||||
externalLayouts.end(),
|
||||
bind2nd(gd::ExternalLayoutHasName(), name)));
|
||||
[&name](const std::unique_ptr<gd::ExternalLayout>& externalLayout) {
|
||||
return externalLayout->GetName() == name;
|
||||
}));
|
||||
}
|
||||
gd::ExternalLayout& Project::GetExternalLayout(std::size_t index) {
|
||||
return *externalLayouts[index];
|
||||
@@ -504,7 +561,9 @@ void Project::RemoveExternalLayout(const gd::String& name) {
|
||||
std::vector<std::unique_ptr<gd::ExternalLayout> >::iterator externalLayout =
|
||||
find_if(externalLayouts.begin(),
|
||||
externalLayouts.end(),
|
||||
bind2nd(gd::ExternalLayoutHasName(), name));
|
||||
[&name](const std::unique_ptr<gd::ExternalLayout>& externalLayout) {
|
||||
return externalLayout->GetName() == name;
|
||||
});
|
||||
if (externalLayout == externalLayouts.end()) return;
|
||||
|
||||
externalLayouts.erase(externalLayout);
|
||||
@@ -805,34 +864,7 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
eventsFunctionsExtensions.clear();
|
||||
const SerializerElement& eventsFunctionsExtensionsElement =
|
||||
element.GetChild("eventsFunctionsExtensions");
|
||||
eventsFunctionsExtensionsElement.ConsiderAsArrayOf(
|
||||
"eventsFunctionsExtension");
|
||||
// First, only unserialize behaviors and objects names.
|
||||
// As event based objects can contains CustomObject and Custom Object,
|
||||
// this allows them to reference EventBasedBehavior and EventBasedObject
|
||||
// respectively.
|
||||
for (std::size_t i = 0;
|
||||
i < eventsFunctionsExtensionsElement.GetChildrenCount();
|
||||
++i) {
|
||||
const SerializerElement& eventsFunctionsExtensionElement =
|
||||
eventsFunctionsExtensionsElement.GetChild(i);
|
||||
|
||||
gd::EventsFunctionsExtension& newEventsFunctionsExtension =
|
||||
InsertNewEventsFunctionsExtension("",
|
||||
GetEventsFunctionsExtensionsCount());
|
||||
newEventsFunctionsExtension.UnserializeExtensionDeclarationFrom(
|
||||
*this, eventsFunctionsExtensionElement);
|
||||
}
|
||||
// Then unserialize functions, behaviors and objects content.
|
||||
for (std::size_t i = 0;
|
||||
i < eventsFunctionsExtensionsElement.GetChildrenCount();
|
||||
++i) {
|
||||
const SerializerElement& eventsFunctionsExtensionElement =
|
||||
eventsFunctionsExtensionsElement.GetChild(i);
|
||||
|
||||
eventsFunctionsExtensions.at(i)->UnserializeExtensionImplementationFrom(
|
||||
*this, eventsFunctionsExtensionElement);
|
||||
}
|
||||
UnserializeAndInsertExtensionsFrom(eventsFunctionsExtensionsElement);
|
||||
|
||||
objectsContainer.GetObjectGroups().UnserializeFrom(
|
||||
element.GetChild("objectsGroups", 0, "ObjectGroups"));
|
||||
@@ -900,6 +932,120 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
}
|
||||
}
|
||||
|
||||
void Project::UnserializeAndInsertExtensionsFrom(
|
||||
const gd::SerializerElement &eventsFunctionsExtensionsElement) {
|
||||
eventsFunctionsExtensionsElement.ConsiderAsArrayOf(
|
||||
"eventsFunctionsExtension");
|
||||
// First, only unserialize behaviors and objects names.
|
||||
// As event based objects can contains custom behaviors and custom objects,
|
||||
// this allows them to reference EventBasedBehavior and EventBasedObject
|
||||
// respectively.
|
||||
for (std::size_t i = 0;
|
||||
i < eventsFunctionsExtensionsElement.GetChildrenCount();
|
||||
++i) {
|
||||
const SerializerElement& eventsFunctionsExtensionElement =
|
||||
eventsFunctionsExtensionsElement.GetChild(i);
|
||||
const gd::String& name = eventsFunctionsExtensionElement.GetStringAttribute("name");
|
||||
|
||||
gd::EventsFunctionsExtension& eventsFunctionsExtension =
|
||||
HasEventsFunctionsExtensionNamed(name)
|
||||
? GetEventsFunctionsExtension(name)
|
||||
: InsertNewEventsFunctionsExtension(
|
||||
name, GetEventsFunctionsExtensionsCount());
|
||||
eventsFunctionsExtension.UnserializeExtensionDeclarationFrom(
|
||||
*this, eventsFunctionsExtensionElement);
|
||||
}
|
||||
|
||||
// Then unserialize functions, behaviors and objects content.
|
||||
for (gd::String &extensionName :
|
||||
GetUnserializingOrderExtensionNames(eventsFunctionsExtensionsElement)) {
|
||||
size_t extensionIndex = GetEventsFunctionsExtensionPosition(extensionName);
|
||||
const SerializerElement &eventsFunctionsExtensionElement =
|
||||
eventsFunctionsExtensionsElement.GetChild(extensionIndex);
|
||||
|
||||
eventsFunctionsExtensions.at(extensionIndex)
|
||||
->UnserializeExtensionImplementationFrom(
|
||||
*this, eventsFunctionsExtensionElement);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<gd::String> Project::GetUnserializingOrderExtensionNames(
|
||||
const gd::SerializerElement &eventsFunctionsExtensionsElement) {
|
||||
|
||||
// Some extension have custom objects, which have child objects coming from other extension.
|
||||
// These child objects must be loaded completely before the parent custom obejct can be unserialized.
|
||||
// This implies: an order on the extension unserialization (and no cycles).
|
||||
|
||||
// At the beginning, everything is yet to be loaded.
|
||||
std::vector<gd::String> remainingExtensionNames(
|
||||
eventsFunctionsExtensions.size());
|
||||
for (std::size_t i = 0; i < eventsFunctionsExtensions.size(); ++i) {
|
||||
remainingExtensionNames[i] = eventsFunctionsExtensions.at(i)->GetName();
|
||||
}
|
||||
|
||||
// Helper allowing to find if an extension has an object that depends on
|
||||
// at least one other object from another extension that is not loaded yet.
|
||||
auto isDependentFromRemainingExtensions =
|
||||
[&remainingExtensionNames](
|
||||
const gd::SerializerElement &eventsFunctionsExtensionElement) {
|
||||
auto &eventsBasedObjectsElement =
|
||||
eventsFunctionsExtensionElement.GetChild("eventsBasedObjects");
|
||||
eventsBasedObjectsElement.ConsiderAsArrayOf("eventsBasedObject");
|
||||
for (std::size_t eventsBasedObjectsIndex = 0;
|
||||
eventsBasedObjectsIndex <
|
||||
eventsBasedObjectsElement.GetChildrenCount();
|
||||
++eventsBasedObjectsIndex) {
|
||||
auto &objectsElement =
|
||||
eventsBasedObjectsElement.GetChild(eventsBasedObjectsIndex)
|
||||
.GetChild("objects");
|
||||
objectsElement.ConsiderAsArrayOf("object");
|
||||
|
||||
for (std::size_t objectIndex = 0;
|
||||
objectIndex < objectsElement.GetChildrenCount(); ++objectIndex) {
|
||||
const gd::String &objectType =
|
||||
objectsElement.GetChild(objectIndex).GetStringAttribute("type");
|
||||
|
||||
gd::String extensionName =
|
||||
eventsFunctionsExtensionElement.GetStringAttribute("name");
|
||||
gd::String usedExtensionName =
|
||||
gd::PlatformExtension::GetExtensionFromFullObjectType(objectType);
|
||||
|
||||
if (usedExtensionName != extensionName &&
|
||||
std::find(remainingExtensionNames.begin(),
|
||||
remainingExtensionNames.end(),
|
||||
usedExtensionName) != remainingExtensionNames.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Find the order of loading so that the extensions are loaded when all the other
|
||||
// extensions they depend on are already loaded.
|
||||
std::vector<gd::String> loadOrderExtensionNames;
|
||||
bool foundAnyExtension = true;
|
||||
while (foundAnyExtension) {
|
||||
foundAnyExtension = false;
|
||||
for (std::size_t i = 0; i < remainingExtensionNames.size(); ++i) {
|
||||
auto extensionName = remainingExtensionNames[i];
|
||||
size_t extensionIndex =
|
||||
GetEventsFunctionsExtensionPosition(extensionName);
|
||||
const SerializerElement &eventsFunctionsExtensionElement =
|
||||
eventsFunctionsExtensionsElement.GetChild(extensionIndex);
|
||||
|
||||
if (!isDependentFromRemainingExtensions(
|
||||
eventsFunctionsExtensionElement)) {
|
||||
loadOrderExtensionNames.push_back(extensionName);
|
||||
remainingExtensionNames.erase(remainingExtensionNames.begin() + i);
|
||||
i--;
|
||||
foundAnyExtension = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return loadOrderExtensionNames;
|
||||
}
|
||||
|
||||
void Project::SerializeTo(SerializerElement& element) const {
|
||||
SerializerElement& versionElement = element.AddChild("gdVersion");
|
||||
versionElement.SetAttribute("major", gd::VersionWrapper::Major());
|
||||
@@ -1076,7 +1222,9 @@ bool Project::HasSourceFile(gd::String name, gd::String language) const {
|
||||
vector<std::unique_ptr<SourceFile> >::const_iterator sourceFile =
|
||||
find_if(externalSourceFiles.begin(),
|
||||
externalSourceFiles.end(),
|
||||
bind2nd(gd::ExternalSourceFileHasName(), name));
|
||||
[&name](const std::unique_ptr<SourceFile>& sourceFile) {
|
||||
return sourceFile->GetFileName() == name;
|
||||
});
|
||||
|
||||
if (sourceFile == externalSourceFiles.end()) return false;
|
||||
|
||||
@@ -1086,20 +1234,26 @@ bool Project::HasSourceFile(gd::String name, gd::String language) const {
|
||||
gd::SourceFile& Project::GetSourceFile(const gd::String& name) {
|
||||
return *(*find_if(externalSourceFiles.begin(),
|
||||
externalSourceFiles.end(),
|
||||
bind2nd(gd::ExternalSourceFileHasName(), name)));
|
||||
[&name](const std::unique_ptr<SourceFile>& sourceFile) {
|
||||
return sourceFile->GetFileName() == name;
|
||||
}));
|
||||
}
|
||||
|
||||
const gd::SourceFile& Project::GetSourceFile(const gd::String& name) const {
|
||||
return *(*find_if(externalSourceFiles.begin(),
|
||||
externalSourceFiles.end(),
|
||||
bind2nd(gd::ExternalSourceFileHasName(), name)));
|
||||
[&name](const std::unique_ptr<SourceFile>& sourceFile) {
|
||||
return sourceFile->GetFileName() == name;
|
||||
}));
|
||||
}
|
||||
|
||||
void Project::RemoveSourceFile(const gd::String& name) {
|
||||
std::vector<std::unique_ptr<gd::SourceFile> >::iterator sourceFile =
|
||||
find_if(externalSourceFiles.begin(),
|
||||
externalSourceFiles.end(),
|
||||
bind2nd(gd::ExternalSourceFileHasName(), name));
|
||||
[&name](const std::unique_ptr<SourceFile>& sourceFile) {
|
||||
return sourceFile->GetFileName() == name;
|
||||
});
|
||||
if (sourceFile == externalSourceFiles.end()) return;
|
||||
|
||||
externalSourceFiles.erase(sourceFile);
|
||||
@@ -1121,7 +1275,10 @@ gd::SourceFile& Project::InsertNewSourceFile(const gd::String& name,
|
||||
return newlyInsertedSourceFile;
|
||||
}
|
||||
|
||||
Project::Project(const Project& other) { Init(other); }
|
||||
Project::Project(const Project &other)
|
||||
: objectsContainer(gd::ObjectsContainer::SourceType::Global) {
|
||||
Init(other);
|
||||
}
|
||||
|
||||
Project& Project::operator=(const Project& other) {
|
||||
if (this != &other) Init(other);
|
||||
|
@@ -523,13 +523,7 @@ class GD_CORE_API Project {
|
||||
std::unique_ptr<gd::Object> CreateObject(const gd::String& type,
|
||||
const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* Create an object configuration of the given type.
|
||||
*
|
||||
* \param type The type of the object
|
||||
*/
|
||||
std::unique_ptr<gd::ObjectConfiguration> CreateObjectConfiguration(
|
||||
const gd::String& type) const;
|
||||
void EnsureObjectDefaultBehaviors(gd::Object& object) const;
|
||||
|
||||
/**
|
||||
* Create an event of the given type.
|
||||
@@ -899,6 +893,16 @@ class GD_CORE_API Project {
|
||||
const EventsFunctionsExtension& eventsFunctionExtension,
|
||||
std::size_t position);
|
||||
|
||||
/**
|
||||
* \brief Unserialize and insert in the project the extensions.
|
||||
*
|
||||
* Unserialization is done in two passe to allow dependencies between extensions.
|
||||
*
|
||||
* \note If an extension with the same name already exists, it will be overwritten.
|
||||
*/
|
||||
void UnserializeAndInsertExtensionsFrom(
|
||||
const gd::SerializerElement& eventsFunctionsExtensionsElement);
|
||||
|
||||
/**
|
||||
* \brief Delete the events functions extension named "name".
|
||||
*/
|
||||
@@ -990,16 +994,12 @@ class GD_CORE_API Project {
|
||||
/**
|
||||
* \brief return the objects of the project.
|
||||
*/
|
||||
gd::ObjectsContainer& GetObjects() {
|
||||
return objectsContainer;
|
||||
}
|
||||
gd::ObjectsContainer& GetObjects() { return objectsContainer; }
|
||||
|
||||
/**
|
||||
* \brief Return the objects of the project.
|
||||
*/
|
||||
const gd::ObjectsContainer& GetObjects() const {
|
||||
return objectsContainer;
|
||||
}
|
||||
const gd::ObjectsContainer& GetObjects() const { return objectsContainer; }
|
||||
///@}
|
||||
|
||||
/** \name Identifier names
|
||||
@@ -1080,32 +1080,53 @@ class GD_CORE_API Project {
|
||||
*/
|
||||
void Init(const gd::Project& project);
|
||||
|
||||
gd::String name; ///< Game name
|
||||
gd::String description; ///< Game description
|
||||
gd::String version; ///< Game version number (used for some exports)
|
||||
unsigned int windowWidth; ///< Window default width
|
||||
unsigned int windowHeight; ///< Window default height
|
||||
int maxFPS; ///< Maximum Frame Per Seconds, -1 for unlimited
|
||||
unsigned int minFPS; ///< Minimum Frame Per Seconds ( slow down game if FPS
|
||||
///< are below this number )
|
||||
bool verticalSync; ///< If true, must activate vertical synchronization.
|
||||
/**
|
||||
* @brief Get the project extensions names in the order they have to be
|
||||
* unserialized.
|
||||
*
|
||||
* Child-objects need the event-based objects they use to be loaded completely
|
||||
* before they are unserialized.
|
||||
*/
|
||||
std::vector<gd::String> GetUnserializingOrderExtensionNames(
|
||||
const gd::SerializerElement& eventsFunctionsExtensionsElement);
|
||||
|
||||
/**
|
||||
* Create an object configuration of the given type.
|
||||
*
|
||||
* \param type The type of the object
|
||||
*/
|
||||
std::unique_ptr<gd::ObjectConfiguration> CreateObjectConfiguration(
|
||||
const gd::String& type) const;
|
||||
|
||||
gd::String name; ///< Game name
|
||||
gd::String description; ///< Game description
|
||||
gd::String version; ///< Game version number (used for some exports)
|
||||
unsigned int windowWidth = 0; ///< Window default width
|
||||
unsigned int windowHeight = 0; ///< Window default height
|
||||
int maxFPS = 0; ///< Maximum Frame Per Seconds, -1 for unlimited
|
||||
unsigned int minFPS = 0; ///< Minimum Frame Per Seconds ( slow down game if
|
||||
///< FPS are below this number )
|
||||
bool verticalSync =
|
||||
false; ///< If true, must activate vertical synchronization.
|
||||
gd::String scaleMode;
|
||||
bool pixelsRounding; ///< If true, the rendering should stop pixel
|
||||
///< interpolation of rendered objects.
|
||||
bool adaptGameResolutionAtRuntime; ///< Should the game resolution be adapted
|
||||
///< to the window size at runtime
|
||||
bool pixelsRounding = false; ///< If true, the rendering should stop pixel
|
||||
///< interpolation of rendered objects.
|
||||
bool adaptGameResolutionAtRuntime =
|
||||
true; ///< Should the game resolution be adapted
|
||||
///< to the window size at runtime
|
||||
gd::String
|
||||
sizeOnStartupMode; ///< How to adapt the game size to the screen. Can be
|
||||
///< "adaptWidth", "adaptHeight" or empty
|
||||
gd::String antialiasingMode;
|
||||
bool isAntialisingEnabledOnMobile;
|
||||
bool isAntialisingEnabledOnMobile = false;
|
||||
gd::String projectUuid; ///< UUID useful to identify the game in online
|
||||
///< services or database that would require it.
|
||||
bool useDeprecatedZeroAsDefaultZOrder; ///< If true, objects created from
|
||||
///< events will have 0 as Z order,
|
||||
///< instead of the highest Z order
|
||||
///< found on the layer at the scene
|
||||
///< startup.
|
||||
bool useDeprecatedZeroAsDefaultZOrder =
|
||||
false; ///< If true, objects created from
|
||||
///< events will have 0 as Z order,
|
||||
///< instead of the highest Z order
|
||||
///< found on the layer at the scene
|
||||
///< startup.
|
||||
std::vector<std::unique_ptr<gd::Layout> > scenes; ///< List of all scenes
|
||||
gd::VariablesContainer variables; ///< Initial global variables
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
@@ -1118,7 +1139,8 @@ class GD_CORE_API Project {
|
||||
std::vector<gd::Platform*>
|
||||
platforms; ///< Pointers to the platforms this project supports.
|
||||
gd::String firstLayout;
|
||||
bool useExternalSourceFiles; ///< True if game used external source files.
|
||||
bool useExternalSourceFiles =
|
||||
false; ///< True if game used external source files.
|
||||
std::vector<std::unique_ptr<gd::SourceFile> >
|
||||
externalSourceFiles; ///< List of external source files used.
|
||||
gd::String author; ///< Game author name, for publishing purpose.
|
||||
@@ -1127,35 +1149,40 @@ class GD_CORE_API Project {
|
||||
std::vector<gd::String>
|
||||
authorUsernames; ///< Game author usernames, from GDevelop users DB.
|
||||
std::vector<gd::String> categories; ///< Game categories
|
||||
bool isPlayableWithKeyboard; ///< The project is playable with a keyboard.
|
||||
bool isPlayableWithGamepad; ///< The project is playable with a gamepad.
|
||||
bool isPlayableWithMobile; ///< The project is playable on a mobile.
|
||||
gd::String packageName; ///< Game package name
|
||||
bool isPlayableWithKeyboard =
|
||||
false; ///< The project is playable with a keyboard.
|
||||
bool isPlayableWithGamepad =
|
||||
false; ///< The project is playable with a gamepad.
|
||||
bool isPlayableWithMobile = false; ///< The project is playable on a mobile.
|
||||
gd::String packageName; ///< Game package name
|
||||
gd::String templateSlug; ///< The slug of the template from which the game is
|
||||
///< created.
|
||||
gd::String orientation; ///< Lock game orientation (on mobile devices).
|
||||
///< "default", "landscape" or "portrait".
|
||||
bool
|
||||
folderProject; ///< True if folder project, false if single file project.
|
||||
bool folderProject =
|
||||
false; ///< True if folder project, false if single file project.
|
||||
gd::String
|
||||
projectFile; ///< Path to the project file - when editing a local file.
|
||||
gd::String latestCompilationDirectory;
|
||||
gd::Platform*
|
||||
currentPlatform; ///< The platform being used to edit the project.
|
||||
gd::Platform* currentPlatform =
|
||||
nullptr; ///< The platform being used to edit the project.
|
||||
gd::PlatformSpecificAssets platformSpecificAssets;
|
||||
gd::LoadingScreen loadingScreen;
|
||||
gd::Watermark watermark;
|
||||
std::vector<std::unique_ptr<gd::ExternalEvents> >
|
||||
externalEvents; ///< List of all externals events
|
||||
ExtensionProperties
|
||||
extensionProperties; ///< The properties of the extensions.
|
||||
extensionProperties; ///< The properties of the extensions.
|
||||
gd::WholeProjectDiagnosticReport wholeProjectDiagnosticReport;
|
||||
mutable unsigned int gdMajorVersion; ///< The GD major version used the last
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdMinorVersion; ///< The GD minor version used the last
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdBuildVersion; ///< The GD build version used the last
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdMajorVersion =
|
||||
0; ///< The GD major version used the last
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdMinorVersion =
|
||||
0; ///< The GD minor version used the last
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdBuildVersion =
|
||||
0; ///< The GD build version used the last
|
||||
///< time the project was saved.
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -4,12 +4,55 @@
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(
|
||||
const gd::Project &project, const gd::Layout &layout) {
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForProjectAndLayout(
|
||||
project, layout),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForProjectAndLayout(project, layout),
|
||||
&project.GetVariables(), &layout.GetVariables(),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersForProject(
|
||||
const gd::Project &project) {
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForProject(project),
|
||||
VariablesContainersList::MakeNewVariablesContainersListForProject(
|
||||
project),
|
||||
&project.GetVariables(), nullptr,
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersFor(
|
||||
const gd::ObjectsContainer &globalObjectsContainers,
|
||||
const gd::ObjectsContainer &objectsContainers) {
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainers(
|
||||
globalObjectsContainers, objectsContainers),
|
||||
VariablesContainersList::MakeNewEmptyVariablesContainersList(),
|
||||
nullptr, nullptr,
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
};
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersForEventsFunctionsExtension(
|
||||
const gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension) {
|
||||
@@ -18,6 +61,8 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForEventsFunctionsExtensi
|
||||
ObjectsContainersList::MakeNewEmptyObjectsContainersList(),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(eventsFunctionsExtension),
|
||||
&eventsFunctionsExtension.GetGlobalVariables(),
|
||||
&eventsFunctionsExtension.GetSceneVariables(),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
@@ -37,6 +82,8 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
parameterObjectsContainer),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(eventsFunctionsExtension),
|
||||
&eventsFunctionsExtension.GetGlobalVariables(),
|
||||
&eventsFunctionsExtension.GetSceneVariables(),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
projectScopedContainers.AddParameters(
|
||||
@@ -63,6 +110,8 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForBehaviorEventsFunction
|
||||
parameterObjectsContainer),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(eventsFunctionsExtension),
|
||||
&eventsFunctionsExtension.GetGlobalVariables(),
|
||||
&eventsFunctionsExtension.GetSceneVariables(),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
@@ -87,11 +136,14 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForObjectEventsFunction(
|
||||
project, eventsBasedObject, eventsFunction, parameterObjectsContainer);
|
||||
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainers(
|
||||
eventsBasedObject.GetObjects(),
|
||||
parameterObjectsContainer),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(
|
||||
eventsFunctionsExtension),
|
||||
&eventsFunctionsExtension.GetGlobalVariables(),
|
||||
&eventsFunctionsExtension.GetSceneVariables(),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
@@ -109,22 +161,34 @@ ProjectScopedContainers::MakeNewProjectScopedContainersForEventsBasedObject(
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ObjectsContainer &outputObjectsContainer) {
|
||||
|
||||
// TODO: We should avoid to use a single `outputObjectsContainer` and instead
|
||||
// use multiple, stable objects container pointed by the `ProjectScopedContainers`
|
||||
// created below.
|
||||
// Search for "ProjectScopedContainers wrongly containing temporary objects containers or objects"
|
||||
// in the codebase.
|
||||
outputObjectsContainer.GetObjects().clear();
|
||||
outputObjectsContainer.GetObjectGroups().Clear();
|
||||
|
||||
// This object named "Object" represents the parent and is used by events.
|
||||
// TODO: Use a dedicated `ObjectsContainer` with only this "Object" and check in
|
||||
// the codebase that this container is not assumed as a
|
||||
// "globalObjectsContainer".
|
||||
// Search for "ProjectScopedContainers wrongly containing temporary objects containers or objects"
|
||||
// in the codebase.
|
||||
outputObjectsContainer.InsertNewObject(
|
||||
project,
|
||||
gd::PlatformExtension::GetObjectFullType(
|
||||
eventsFunctionsExtension.GetName(), eventsBasedObject.GetName()),
|
||||
"Object", outputObjectsContainer.GetObjectsCount());
|
||||
gd::EventsFunctionTools::CopyEventsBasedObjectChildrenToObjectsContainer(
|
||||
eventsBasedObject, outputObjectsContainer);
|
||||
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
|
||||
outputObjectsContainer),
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainers(
|
||||
eventsBasedObject.GetObjects(), outputObjectsContainer),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(
|
||||
eventsFunctionsExtension),
|
||||
&eventsFunctionsExtension.GetGlobalVariables(),
|
||||
&eventsFunctionsExtension.GetSceneVariables(),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
|
@@ -5,13 +5,11 @@
|
||||
#include "ObjectsContainersList.h"
|
||||
#include "PropertiesContainersList.h"
|
||||
#include "VariablesContainersList.h"
|
||||
#include "VariablesContainer.h"
|
||||
|
||||
namespace gd {
|
||||
class Project;
|
||||
class ObjectsContainer;
|
||||
class ObjectsContainersList;
|
||||
class VariablesContainersList;
|
||||
class PropertiesContainersList;
|
||||
class NamedPropertyDescriptor;
|
||||
class ParameterMetadataContainer;
|
||||
class BaseEvent;
|
||||
@@ -19,7 +17,7 @@ class EventsFunctionsExtension;
|
||||
class EventsFunction;
|
||||
class EventsBasedBehavior;
|
||||
class EventsBasedObject;
|
||||
} // namespace gd
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -38,51 +36,29 @@ class ProjectScopedContainers {
|
||||
ProjectScopedContainers(
|
||||
const gd::ObjectsContainersList &objectsContainersList_,
|
||||
const gd::VariablesContainersList &variablesContainersList_,
|
||||
const gd::VariablesContainer *legacyGlobalVariables_,
|
||||
const gd::VariablesContainer *legacySceneVariables_,
|
||||
const gd::PropertiesContainersList &propertiesContainersList_)
|
||||
: objectsContainersList(objectsContainersList_),
|
||||
variablesContainersList(variablesContainersList_),
|
||||
legacyGlobalVariables(legacyGlobalVariables_),
|
||||
legacySceneVariables(legacySceneVariables_),
|
||||
propertiesContainersList(propertiesContainersList_){};
|
||||
virtual ~ProjectScopedContainers(){};
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersForProjectAndLayout(const gd::Project &project,
|
||||
const gd::Layout &layout) {
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForProjectAndLayout(
|
||||
project, layout),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForProjectAndLayout(project, layout),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
const gd::Layout &layout);
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersForProject(const gd::Project &project) {
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForProject(
|
||||
project),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForProject(project),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
MakeNewProjectScopedContainersForProject(const gd::Project &project);
|
||||
|
||||
/**
|
||||
* @deprecated Use another method for an explicit context instead.
|
||||
*/
|
||||
static ProjectScopedContainers MakeNewProjectScopedContainersFor(
|
||||
const gd::ObjectsContainer &globalObjectsContainers,
|
||||
const gd::ObjectsContainer &objectsContainers) {
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainers(
|
||||
globalObjectsContainers, objectsContainers),
|
||||
VariablesContainersList::MakeNewEmptyVariablesContainersList(),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
};
|
||||
const gd::ObjectsContainer &objectsContainers);
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersForEventsFunctionsExtension(
|
||||
@@ -221,6 +197,24 @@ class ProjectScopedContainers {
|
||||
return variablesContainersList;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Return the global variables of the current scene or the current
|
||||
* extension. It allows legacy "globalvar" parameters to accept extension
|
||||
* variables.
|
||||
*/
|
||||
const gd::VariablesContainer *GetLegacyGlobalVariables() const {
|
||||
return legacyGlobalVariables;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Return the scene variables of the current scene or the current
|
||||
* extension. It allows legacy "scenevar" parameters to accept extension
|
||||
* variables.
|
||||
*/
|
||||
const gd::VariablesContainer *GetLegacySceneVariables() const {
|
||||
return legacySceneVariables;
|
||||
};
|
||||
|
||||
const gd::PropertiesContainersList &GetPropertiesContainersList() const {
|
||||
return propertiesContainersList;
|
||||
};
|
||||
@@ -231,11 +225,14 @@ class ProjectScopedContainers {
|
||||
|
||||
/** Do not use - should be private but accessible to let Emscripten create a
|
||||
* temporary. */
|
||||
ProjectScopedContainers(){};
|
||||
ProjectScopedContainers()
|
||||
: legacyGlobalVariables(nullptr), legacySceneVariables(nullptr){};
|
||||
|
||||
private:
|
||||
private:
|
||||
gd::ObjectsContainersList objectsContainersList;
|
||||
gd::VariablesContainersList variablesContainersList;
|
||||
const gd::VariablesContainer *legacyGlobalVariables;
|
||||
const gd::VariablesContainer *legacySceneVariables;
|
||||
gd::PropertiesContainersList propertiesContainersList;
|
||||
std::vector<const ParameterMetadataContainer *> parametersVectorsList;
|
||||
};
|
||||
|
@@ -33,6 +33,7 @@ class GD_CORE_API PropertyDescriptor {
|
||||
PropertyDescriptor(gd::String propertyValue)
|
||||
: currentValue(propertyValue), type("string"), label(""), hidden(false),
|
||||
deprecated(false), advanced(false),
|
||||
hasImpactOnOtherProperties(false),
|
||||
measurementUnit(gd::MeasurementUnit::GetUndefined()),
|
||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {}
|
||||
|
||||
@@ -41,6 +42,7 @@ class GD_CORE_API PropertyDescriptor {
|
||||
*/
|
||||
PropertyDescriptor()
|
||||
: hidden(false), deprecated(false), advanced(false),
|
||||
hasImpactOnOtherProperties(false),
|
||||
measurementUnit(gd::MeasurementUnit::GetUndefined()),
|
||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default){};
|
||||
|
||||
@@ -175,6 +177,21 @@ class GD_CORE_API PropertyDescriptor {
|
||||
*/
|
||||
bool IsAdvanced() const { return advanced; }
|
||||
|
||||
/**
|
||||
* \brief Check if the property has impact on other properties - which means a change
|
||||
* must re-render other properties.
|
||||
*/
|
||||
bool HasImpactOnOtherProperties() const { return hasImpactOnOtherProperties; }
|
||||
|
||||
/**
|
||||
* \brief Set if the property has impact on other properties - which means a change
|
||||
* must re-render other properties.
|
||||
*/
|
||||
PropertyDescriptor& SetHasImpactOnOtherProperties(bool enable) {
|
||||
hasImpactOnOtherProperties = enable;
|
||||
return *this;
|
||||
}
|
||||
|
||||
QuickCustomization::Visibility GetQuickCustomizationVisibility() const { return quickCustomizationVisibility; }
|
||||
|
||||
PropertyDescriptor& SetQuickCustomizationVisibility(QuickCustomization::Visibility visibility) {
|
||||
@@ -221,6 +238,7 @@ class GD_CORE_API PropertyDescriptor {
|
||||
bool hidden;
|
||||
bool deprecated;
|
||||
bool advanced;
|
||||
bool hasImpactOnOtherProperties;
|
||||
gd::MeasurementUnit measurementUnit; //< The unit of measurement of the property vale.
|
||||
QuickCustomization::Visibility quickCustomizationVisibility;
|
||||
};
|
||||
|
@@ -1,16 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class QuickCustomization {
|
||||
public:
|
||||
enum Visibility {
|
||||
/** Visibility based on the parent or editor heuristics (probably visible). */
|
||||
/** Visibility based on the parent or editor heuristics (probably visible).
|
||||
*/
|
||||
Default,
|
||||
/** Visible in the quick customization editor. */
|
||||
Visible,
|
||||
/** Not visible in the quick customization editor. */
|
||||
Hidden
|
||||
};
|
||||
|
||||
static Visibility StringAsVisibility(const gd::String& str) {
|
||||
if (str == "visible")
|
||||
return Visibility::Visible;
|
||||
else if (str == "hidden")
|
||||
return Visibility::Hidden;
|
||||
|
||||
return Visibility::Default;
|
||||
}
|
||||
|
||||
static gd::String VisibilityAsString(Visibility visibility) {
|
||||
if (visibility == Visibility::Visible)
|
||||
return "visible";
|
||||
else if (visibility == Visibility::Hidden)
|
||||
return "hidden";
|
||||
|
||||
return "default";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Project/QuickCustomizationVisibilitiesContainer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#include "GDCore/Project/QuickCustomization.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/UUID/UUID.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
QuickCustomizationVisibilitiesContainer::
|
||||
QuickCustomizationVisibilitiesContainer() {}
|
||||
|
||||
bool QuickCustomizationVisibilitiesContainer::IsEmpty() const {
|
||||
return visibilities.empty();
|
||||
}
|
||||
|
||||
void QuickCustomizationVisibilitiesContainer::Set(
|
||||
const gd::String& name, QuickCustomization::Visibility visibility) {
|
||||
visibilities[name] = visibility;
|
||||
}
|
||||
|
||||
QuickCustomization::Visibility QuickCustomizationVisibilitiesContainer::Get(
|
||||
const gd::String& name) const {
|
||||
auto it = visibilities.find(name);
|
||||
if (it != visibilities.end()) return it->second;
|
||||
|
||||
return QuickCustomization::Visibility::Default;
|
||||
}
|
||||
|
||||
void QuickCustomizationVisibilitiesContainer::SerializeTo(
|
||||
SerializerElement& element) const {
|
||||
for (auto& visibility : visibilities) {
|
||||
element.SetStringAttribute(
|
||||
visibility.first,
|
||||
QuickCustomization::VisibilityAsString(visibility.second));
|
||||
}
|
||||
}
|
||||
|
||||
void QuickCustomizationVisibilitiesContainer::UnserializeFrom(
|
||||
const SerializerElement& element) {
|
||||
visibilities.clear();
|
||||
for (auto& child : element.GetAllChildren()) {
|
||||
visibilities[child.first] =
|
||||
QuickCustomization::StringAsVisibility(child.second->GetStringValue());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/QuickCustomization.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
class QuickCustomizationVisibilitiesContainer {
|
||||
public:
|
||||
QuickCustomizationVisibilitiesContainer();
|
||||
|
||||
void Set(const gd::String& name, QuickCustomization::Visibility visibility);
|
||||
|
||||
QuickCustomization::Visibility Get(const gd::String& name) const;
|
||||
|
||||
bool IsEmpty() const;
|
||||
|
||||
void SerializeTo(SerializerElement& element) const;
|
||||
|
||||
void UnserializeFrom(const SerializerElement& element);
|
||||
|
||||
private:
|
||||
std::map<gd::String, QuickCustomization::Visibility> visibilities;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -173,9 +173,6 @@ std::map<gd::String, gd::PropertyDescriptor> ImageResource::GetProperties()
|
||||
properties[_("Smooth the image")]
|
||||
.SetValue(smooth ? "true" : "false")
|
||||
.SetType("Boolean");
|
||||
properties[_("Always loaded in memory")]
|
||||
.SetValue(alwaysLoaded ? "true" : "false")
|
||||
.SetType("Boolean");
|
||||
|
||||
return properties;
|
||||
}
|
||||
@@ -184,8 +181,6 @@ bool ImageResource::UpdateProperty(const gd::String& name,
|
||||
const gd::String& value) {
|
||||
if (name == _("Smooth the image"))
|
||||
smooth = value == "1";
|
||||
else if (name == _("Always loaded in memory"))
|
||||
alwaysLoaded = value == "1";
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -569,14 +564,12 @@ void ImageResource::SetFile(const gd::String& newFile) {
|
||||
}
|
||||
|
||||
void ImageResource::UnserializeFrom(const SerializerElement& element) {
|
||||
alwaysLoaded = element.GetBoolAttribute("alwaysLoaded");
|
||||
smooth = element.GetBoolAttribute("smoothed");
|
||||
SetUserAdded(element.GetBoolAttribute("userAdded"));
|
||||
SetFile(element.GetStringAttribute("file"));
|
||||
}
|
||||
|
||||
void ImageResource::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("alwaysLoaded", alwaysLoaded);
|
||||
element.SetAttribute("smoothed", smooth);
|
||||
element.SetAttribute("userAdded", IsUserAdded());
|
||||
element.SetAttribute("file", GetFile());
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user