mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
583 Commits
v5.2.177
...
experiment
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5ebe8ab072 | ||
![]() |
066e474031 | ||
![]() |
54bc2b1c5a | ||
![]() |
f7ea137f32 | ||
![]() |
73374200b7 | ||
![]() |
0506fba90c | ||
![]() |
e9b873b8d2 | ||
![]() |
ff6862b9dd | ||
![]() |
def3bfef5b | ||
![]() |
fc782c44e9 | ||
![]() |
e26a2e297f | ||
![]() |
3e7b91fc0c | ||
![]() |
92b9203ce8 | ||
![]() |
9b0b031b2d | ||
![]() |
0b081bb4d3 | ||
![]() |
623ddcf0dc | ||
![]() |
7fe65e7bd7 | ||
![]() |
ef58895b90 | ||
![]() |
7b1378701b | ||
![]() |
bcd225fe31 | ||
![]() |
1ad86b878a | ||
![]() |
4232ea911f | ||
![]() |
b7d92249dd | ||
![]() |
9891ba29bb | ||
![]() |
3090bdcc00 | ||
![]() |
4ca859c8b9 | ||
![]() |
9e53bea7f8 | ||
![]() |
ec9a1dda96 | ||
![]() |
212eb1d802 | ||
![]() |
bc42367841 | ||
![]() |
15976105df | ||
![]() |
c2aa314395 | ||
![]() |
5448576511 | ||
![]() |
2ef3e93a42 | ||
![]() |
552a818cd1 | ||
![]() |
701b5a3250 | ||
![]() |
1e87b74d48 | ||
![]() |
43e56ef014 | ||
![]() |
5d51554518 | ||
![]() |
83f34527ba | ||
![]() |
2cfdcc7d5d | ||
![]() |
2f14a3e4dd | ||
![]() |
4072999480 | ||
![]() |
97d4cb2bf6 | ||
![]() |
56264ce3cf | ||
![]() |
73eb5b3d5d | ||
![]() |
50b89cd4e4 | ||
![]() |
a734f1c935 | ||
![]() |
6b39c26dd0 | ||
![]() |
3726bc7b9e | ||
![]() |
72733afb23 | ||
![]() |
2fc3355246 | ||
![]() |
62baa43e9f | ||
![]() |
3ed0782ca8 | ||
![]() |
02358ae735 | ||
![]() |
cb16eb37a4 | ||
![]() |
9f1a8ad29d | ||
![]() |
b07bcf678c | ||
![]() |
f0e65b9aa0 | ||
![]() |
2facabc351 | ||
![]() |
7642a4b3bb | ||
![]() |
74283a8f8e | ||
![]() |
f7a0e566e0 | ||
![]() |
bcf26fabd1 | ||
![]() |
e72173979e | ||
![]() |
68d0ec4c71 | ||
![]() |
23e63e623a | ||
![]() |
48b42b2ad5 | ||
![]() |
33209cb4e6 | ||
![]() |
be7b2a27ae | ||
![]() |
519413f155 | ||
![]() |
a621cef6ea | ||
![]() |
83cbace83b | ||
![]() |
778c7fc979 | ||
![]() |
ab9340eb4d | ||
![]() |
aa89468337 | ||
![]() |
f529ba09a4 | ||
![]() |
56107ab6e6 | ||
![]() |
f8c99d2582 | ||
![]() |
fe68e449bc | ||
![]() |
d7f66d92dc | ||
![]() |
5c1626c420 | ||
![]() |
29f296a479 | ||
![]() |
222c6ef111 | ||
![]() |
0abb21de3d | ||
![]() |
c6928ae319 | ||
![]() |
a865dee46a | ||
![]() |
215169c08e | ||
![]() |
8fa1141494 | ||
![]() |
5a371905c5 | ||
![]() |
2c5d683d57 | ||
![]() |
d512d90224 | ||
![]() |
1cd8999589 | ||
![]() |
7f46a76ed5 | ||
![]() |
ee7f6ef896 | ||
![]() |
330189fa4e | ||
![]() |
08fd7f0475 | ||
![]() |
75ed38bcba | ||
![]() |
1901c0d52c | ||
![]() |
69e3fde654 | ||
![]() |
57ce230fce | ||
![]() |
2f253d8c9e | ||
![]() |
47bdf734cb | ||
![]() |
8ec16c9cc6 | ||
![]() |
605b392e3c | ||
![]() |
1c66b8b8c4 | ||
![]() |
15f405b385 | ||
![]() |
3637551cd7 | ||
![]() |
4b6d5d069e | ||
![]() |
1b9a17e243 | ||
![]() |
d4d35ee8e9 | ||
![]() |
d956433d6b | ||
![]() |
d9e5e269a0 | ||
![]() |
4a69e59d98 | ||
![]() |
276ac4137c | ||
![]() |
4352e3d7ef | ||
![]() |
faaaac446a | ||
![]() |
283d8a36df | ||
![]() |
913373e56d | ||
![]() |
bc8535bbca | ||
![]() |
eb9bef00ca | ||
![]() |
2dc6b5d91d | ||
![]() |
17777f68b7 | ||
![]() |
dac08538b0 | ||
![]() |
a5946ec7db | ||
![]() |
c9d73a2ad4 | ||
![]() |
9d464fe8a8 | ||
![]() |
0c2158c3dc | ||
![]() |
fa22e1b272 | ||
![]() |
e6ec5997ee | ||
![]() |
c45eef1114 | ||
![]() |
c92eb17486 | ||
![]() |
ca227ef077 | ||
![]() |
460770e9d8 | ||
![]() |
c4915fabd9 | ||
![]() |
737c497e66 | ||
![]() |
b7a4bab53c | ||
![]() |
2223b6516b | ||
![]() |
7d89208e7b | ||
![]() |
70508292e4 | ||
![]() |
c899db1dba | ||
![]() |
2fb27f430e | ||
![]() |
6cd2400848 | ||
![]() |
fadccba757 | ||
![]() |
29a43514ce | ||
![]() |
e64ab94f76 | ||
![]() |
ed969d2909 | ||
![]() |
77bf67fdf0 | ||
![]() |
580c7a370c | ||
![]() |
266f0f2b6e | ||
![]() |
58af6aacb4 | ||
![]() |
1c4ee1c928 | ||
![]() |
0275476bec | ||
![]() |
3f0194acf0 | ||
![]() |
017d8b28c2 | ||
![]() |
4b518ba0fc | ||
![]() |
e4938b25b5 | ||
![]() |
c56ad2d277 | ||
![]() |
f069f9d942 | ||
![]() |
9f7c60a69e | ||
![]() |
774bf0db61 | ||
![]() |
ccd9c5c0ff | ||
![]() |
5b130a34e3 | ||
![]() |
3e6d147660 | ||
![]() |
433d85db94 | ||
![]() |
b75f707b30 | ||
![]() |
67799eb3eb | ||
![]() |
1173210386 | ||
![]() |
007cc48291 | ||
![]() |
12813c9ad9 | ||
![]() |
e503e34059 | ||
![]() |
4bf576a889 | ||
![]() |
eff1c1bcb6 | ||
![]() |
abce34f2b1 | ||
![]() |
07276d5e16 | ||
![]() |
1fdd8cc792 | ||
![]() |
79e40605d5 | ||
![]() |
fcc91e3fea | ||
![]() |
5c66623631 | ||
![]() |
5637642e1b | ||
![]() |
7e8b44af2e | ||
![]() |
0dd4650aae | ||
![]() |
c7cac31830 | ||
![]() |
56cb8581c4 | ||
![]() |
1993040b70 | ||
![]() |
883991081a | ||
![]() |
7d8afef1ad | ||
![]() |
8178595546 | ||
![]() |
a478068c64 | ||
![]() |
368da1b610 | ||
![]() |
4ee43202e9 | ||
![]() |
602fdf4bfd | ||
![]() |
6110acafcc | ||
![]() |
a3696ca9d1 | ||
![]() |
1bb473b0b0 | ||
![]() |
4376b4f36e | ||
![]() |
6ecbae9c35 | ||
![]() |
93e9fc6aed | ||
![]() |
7c0a7a4152 | ||
![]() |
d4cdb3ff83 | ||
![]() |
a7cac91e45 | ||
![]() |
6a6d72cd9a | ||
![]() |
11d74b3ea5 | ||
![]() |
5b65cf84eb | ||
![]() |
6b7af0474f | ||
![]() |
99f7e55044 | ||
![]() |
6b522b1c31 | ||
![]() |
0f35e48690 | ||
![]() |
53d19dd628 | ||
![]() |
155dc1bec8 | ||
![]() |
be26e39eae | ||
![]() |
90fa5ea8e8 | ||
![]() |
4845251f78 | ||
![]() |
31ef3fec58 | ||
![]() |
292b23ea17 | ||
![]() |
9c5a5db7a8 | ||
![]() |
d73ae4c56e | ||
![]() |
339929e021 | ||
![]() |
cea1cf20f1 | ||
![]() |
4ec2705f75 | ||
![]() |
408f6f8134 | ||
![]() |
c64bac0010 | ||
![]() |
f8d5c89ebf | ||
![]() |
ca3bb40e96 | ||
![]() |
713d437b70 | ||
![]() |
09381c3836 | ||
![]() |
ea4c2e0827 | ||
![]() |
a5d1149c21 | ||
![]() |
119b0fadce | ||
![]() |
7111859768 | ||
![]() |
08dfb4d36b | ||
![]() |
cacd482af9 | ||
![]() |
3568a58019 | ||
![]() |
a32d5fcd7e | ||
![]() |
1a999fd2dd | ||
![]() |
76648764bb | ||
![]() |
c25803c122 | ||
![]() |
ba8d7f4e38 | ||
![]() |
e1c22f6994 | ||
![]() |
7b70f9172f | ||
![]() |
a871e0f2ec | ||
![]() |
f6499e1163 | ||
![]() |
d03e58636d | ||
![]() |
a7be928f2f | ||
![]() |
7c83610d28 | ||
![]() |
1a1e92b072 | ||
![]() |
5118f13e0b | ||
![]() |
f3ee18cdc7 | ||
![]() |
c5584f746e | ||
![]() |
706a6de94c | ||
![]() |
8c750b54dd | ||
![]() |
649d744664 | ||
![]() |
12a6fec18e | ||
![]() |
7fc4aa47f6 | ||
![]() |
483f78fa75 | ||
![]() |
35b80818dc | ||
![]() |
b3f19726dc | ||
![]() |
dd332e3cce | ||
![]() |
dc95a7511f | ||
![]() |
77130c7d2e | ||
![]() |
8d1c3e8290 | ||
![]() |
63570fd3c8 | ||
![]() |
6945409280 | ||
![]() |
e345b2726f | ||
![]() |
3a2a662f62 | ||
![]() |
73d850f933 | ||
![]() |
1f2293e7d6 | ||
![]() |
b038984097 | ||
![]() |
a45a5bfe7e | ||
![]() |
8cbefa0cde | ||
![]() |
1d607d474a | ||
![]() |
3cd6e36a73 | ||
![]() |
cfbec2df4a | ||
![]() |
2823fde86a | ||
![]() |
f29ae50f2e | ||
![]() |
ba40c67941 | ||
![]() |
c8ca3c2931 | ||
![]() |
0bb0969ab8 | ||
![]() |
3b0a7c442f | ||
![]() |
df3c95c466 | ||
![]() |
482d52ff5a | ||
![]() |
5a78c763ef | ||
![]() |
3393af4b3b | ||
![]() |
c2b77c9df7 | ||
![]() |
514e4692ab | ||
![]() |
210e59f201 | ||
![]() |
e2058052f2 | ||
![]() |
90dca41e20 | ||
![]() |
15b463dad1 | ||
![]() |
a97a1f8a86 | ||
![]() |
901f84daaa | ||
![]() |
6af50ae5c0 | ||
![]() |
f7bd4bee6e | ||
![]() |
4a4b015242 | ||
![]() |
75ee0b68e3 | ||
![]() |
778104447c | ||
![]() |
a4ddc0a6ef | ||
![]() |
3e713029e2 | ||
![]() |
7eb5402ee2 | ||
![]() |
25adb026b8 | ||
![]() |
54bd2960ac | ||
![]() |
1fde65b5e3 | ||
![]() |
b4295b4077 | ||
![]() |
c7a929374d | ||
![]() |
7571e64396 | ||
![]() |
198267d7cb | ||
![]() |
0982424d0d | ||
![]() |
29747690c2 | ||
![]() |
ad74532752 | ||
![]() |
80e5376f74 | ||
![]() |
cc24eab2aa | ||
![]() |
423c8165ad | ||
![]() |
0af00818dc | ||
![]() |
9f5c783d73 | ||
![]() |
ad65971c01 | ||
![]() |
85ef9a9561 | ||
![]() |
455d77fcdf | ||
![]() |
02093fec0f | ||
![]() |
8227ab9cad | ||
![]() |
f8eb91f3d2 | ||
![]() |
a260aa5e3e | ||
![]() |
4d8d93a550 | ||
![]() |
cf160bcca1 | ||
![]() |
44a0e22f97 | ||
![]() |
d47d3285b2 | ||
![]() |
2ee6590967 | ||
![]() |
cd77951e1a | ||
![]() |
fa4efef857 | ||
![]() |
bc8204d696 | ||
![]() |
b2eab5a327 | ||
![]() |
dba65822dd | ||
![]() |
8f155e4322 | ||
![]() |
13ebe5c588 | ||
![]() |
bcd8e5608a | ||
![]() |
14e444413d | ||
![]() |
a2f75bc0dc | ||
![]() |
6914e01a15 | ||
![]() |
90b5f7a322 | ||
![]() |
13cf9b1d0b | ||
![]() |
6fc0198298 | ||
![]() |
0999ba611d | ||
![]() |
119d1af76a | ||
![]() |
d6b4dacb1e | ||
![]() |
9edb3cfe91 | ||
![]() |
d44a1c3537 | ||
![]() |
8cc84e5728 | ||
![]() |
76130b43d4 | ||
![]() |
40b0823b91 | ||
![]() |
9b447e08e2 | ||
![]() |
10314a1911 | ||
![]() |
d0195719c2 | ||
![]() |
dd8c040381 | ||
![]() |
5e0c8a92aa | ||
![]() |
977c102ddc | ||
![]() |
849d79d5d7 | ||
![]() |
28f7c9ae0b | ||
![]() |
38e58327fa | ||
![]() |
3cc29efaa2 | ||
![]() |
65eb76fb57 | ||
![]() |
9eb721662f | ||
![]() |
b10b131010 | ||
![]() |
b5fd1bb351 | ||
![]() |
f1c9521625 | ||
![]() |
6ceb3c2c10 | ||
![]() |
43827876cd | ||
![]() |
62b746300a | ||
![]() |
769ebcd91c | ||
![]() |
70d5de16bf | ||
![]() |
7fbe1bd23d | ||
![]() |
de8a679e31 | ||
![]() |
a1a4029b35 | ||
![]() |
a377467031 | ||
![]() |
dd090fd1d7 | ||
![]() |
26ee9b3891 | ||
![]() |
ad18eab4ae | ||
![]() |
007fc36a2e | ||
![]() |
c8ebfde85b | ||
![]() |
d0005ba2cb | ||
![]() |
f623b352ee | ||
![]() |
16e2d8a005 | ||
![]() |
7654883cb1 | ||
![]() |
3ae5db2a49 | ||
![]() |
9ed002c879 | ||
![]() |
d4283c2350 | ||
![]() |
5a176d21e7 | ||
![]() |
bfdfd7f0fb | ||
![]() |
aae75f2232 | ||
![]() |
977092c0a3 | ||
![]() |
556688cedb | ||
![]() |
ce93dc5310 | ||
![]() |
d6d425db4f | ||
![]() |
2737e75639 | ||
![]() |
36eab18133 | ||
![]() |
48acbb12ee | ||
![]() |
21904e46f1 | ||
![]() |
94753ac053 | ||
![]() |
b160ee9b27 | ||
![]() |
f76e8a72b6 | ||
![]() |
5bc342688d | ||
![]() |
3e6204c0eb | ||
![]() |
7b1c340ad0 | ||
![]() |
fac724dc3f | ||
![]() |
9b4151f64c | ||
![]() |
6b5ab6c811 | ||
![]() |
5943092b0c | ||
![]() |
deb0c5ffc3 | ||
![]() |
c56fa03bf6 | ||
![]() |
0d49d449db | ||
![]() |
fdd702cd09 | ||
![]() |
5a8e4a7ca9 | ||
![]() |
2e4e91c21e | ||
![]() |
6ece930809 | ||
![]() |
c5baa81977 | ||
![]() |
d24be38874 | ||
![]() |
1efffbbb78 | ||
![]() |
090d76a368 | ||
![]() |
d44a9375de | ||
![]() |
5a2a3893f9 | ||
![]() |
0a6b0dc785 | ||
![]() |
02e99726dc | ||
![]() |
843055d8df | ||
![]() |
f7fda5cb5e | ||
![]() |
e529642aec | ||
![]() |
c8e10d7043 | ||
![]() |
5f0de0e9a7 | ||
![]() |
e51638ce4b | ||
![]() |
0fbd6a606a | ||
![]() |
2fa543c3db | ||
![]() |
38e35c9695 | ||
![]() |
ad13a1a101 | ||
![]() |
cb9d98d027 | ||
![]() |
064c3f1572 | ||
![]() |
9e5320f9d4 | ||
![]() |
a1826d355d | ||
![]() |
32a3a094d1 | ||
![]() |
ee7dc2654b | ||
![]() |
64ffad3c0a | ||
![]() |
dcc62f078f | ||
![]() |
d920f05dbc | ||
![]() |
ac82be800b | ||
![]() |
2c92ae4042 | ||
![]() |
465e934605 | ||
![]() |
248ba7675e | ||
![]() |
fd2b59ba45 | ||
![]() |
be54236ece | ||
![]() |
6edf63e98f | ||
![]() |
034f1ad9cc | ||
![]() |
94b8c31ac2 | ||
![]() |
57d1241e2d | ||
![]() |
eb4708ca87 | ||
![]() |
fac710780b | ||
![]() |
d28aac325a | ||
![]() |
306b341ee5 | ||
![]() |
1d8e04cb78 | ||
![]() |
3b2855de59 | ||
![]() |
d5c2982b2d | ||
![]() |
315b7387b3 | ||
![]() |
f4f92566f4 | ||
![]() |
7b72d4e080 | ||
![]() |
ae96ebf79c | ||
![]() |
be813a0271 | ||
![]() |
b306d80915 | ||
![]() |
9baed02aa1 | ||
![]() |
1b4c5c1b1c | ||
![]() |
4f04190614 | ||
![]() |
d3134ecde9 | ||
![]() |
61ed7ffa16 | ||
![]() |
8be1961d3f | ||
![]() |
112c306610 | ||
![]() |
423f15b513 | ||
![]() |
a9c89b14c3 | ||
![]() |
bd898463f5 | ||
![]() |
ed4635664c | ||
![]() |
b6f25db40c | ||
![]() |
f78662be5f | ||
![]() |
7aae35a029 | ||
![]() |
6c323614ef | ||
![]() |
eb4170df20 | ||
![]() |
8830bb93ae | ||
![]() |
87fa0a39ac | ||
![]() |
a9cc911ca8 | ||
![]() |
d3fe6cf532 | ||
![]() |
e2c40ff205 | ||
![]() |
970d04b0df | ||
![]() |
8c5076443c | ||
![]() |
3744e98065 | ||
![]() |
b6a1332124 | ||
![]() |
0251997703 | ||
![]() |
57faa9fb4a | ||
![]() |
ba95f66ccd | ||
![]() |
9465873dbd | ||
![]() |
b5a9fe4fe1 | ||
![]() |
6531e2e970 | ||
![]() |
4f900c9451 | ||
![]() |
f97f267a96 | ||
![]() |
6cd8f54869 | ||
![]() |
9718fb788e | ||
![]() |
38651edf3e | ||
![]() |
d34f1a654f | ||
![]() |
5abc74b66b | ||
![]() |
a848764318 | ||
![]() |
c0c6fddcbb | ||
![]() |
95ac26f05d | ||
![]() |
1f852648ef | ||
![]() |
b7da4361c3 | ||
![]() |
71b369d40e | ||
![]() |
4d8cf56922 | ||
![]() |
1a6e0ba5a1 | ||
![]() |
ec1ebcbf5b | ||
![]() |
4ee9ccd7a9 | ||
![]() |
1ac248bfa4 | ||
![]() |
65b78d4db7 | ||
![]() |
639d90d743 | ||
![]() |
45d0a78656 | ||
![]() |
0a0811e355 | ||
![]() |
a8f9df3dac | ||
![]() |
35db56d778 | ||
![]() |
27efe8e3dd | ||
![]() |
3584ee2aaf | ||
![]() |
19a762fb60 | ||
![]() |
8a6dd8b940 | ||
![]() |
2173b49b19 | ||
![]() |
caf2752acb | ||
![]() |
e3291b515d | ||
![]() |
c1627b5ab2 | ||
![]() |
7db5b97c45 | ||
![]() |
425a0e92ca | ||
![]() |
c2dfe579af | ||
![]() |
4ea6fb78bd | ||
![]() |
8e668db6ea | ||
![]() |
88063a4cad | ||
![]() |
b180f5032e | ||
![]() |
29e7f7d7a4 | ||
![]() |
547f1e4bce | ||
![]() |
9e176d91ec | ||
![]() |
cac59d4727 | ||
![]() |
4f98ffa9ab | ||
![]() |
7229406cfb | ||
![]() |
d39cfd16a2 | ||
![]() |
2965f374bb | ||
![]() |
2d5b2a49e7 | ||
![]() |
05df9cb599 | ||
![]() |
7b28d2525e | ||
![]() |
533e61cdbc | ||
![]() |
3a823113f1 | ||
![]() |
17bc8b584d | ||
![]() |
dbaf8a6569 | ||
![]() |
fcbc538c30 | ||
![]() |
decd96c52f | ||
![]() |
8dbf9c99ce | ||
![]() |
1318523804 | ||
![]() |
8ef5e2c1ed | ||
![]() |
d945426068 | ||
![]() |
8eb07a492f | ||
![]() |
37c9dd95ce | ||
![]() |
a6d837cbe6 | ||
![]() |
f6539626d3 | ||
![]() |
e0df9b0ff3 | ||
![]() |
0b50231027 | ||
![]() |
94c9924a88 | ||
![]() |
581cc5837a | ||
![]() |
ff77d107b2 | ||
![]() |
3a5198cb34 | ||
![]() |
c92025549d | ||
![]() |
600b307e7e | ||
![]() |
297fade0bd | ||
![]() |
84d7500eab | ||
![]() |
f99c4ab948 | ||
![]() |
5fe4f23c83 | ||
![]() |
8820bd45e4 | ||
![]() |
5e16968f37 | ||
![]() |
6b6179ff22 | ||
![]() |
94bcd87a9f | ||
![]() |
356a1974ef | ||
![]() |
345bad9876 | ||
![]() |
0b8d843a73 | ||
![]() |
9f0c987ec7 | ||
![]() |
0e79209d2b | ||
![]() |
f991c09c39 | ||
![]() |
6e24dfa9b8 | ||
![]() |
a3cd00dc94 | ||
![]() |
300c011151 | ||
![]() |
230d410469 |
@@ -30,7 +30,7 @@ jobs:
|
||||
|
||||
- run:
|
||||
name: Install Emscripten (for GDevelop.js)
|
||||
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 1.39.6 && ./emsdk activate 1.39.6 && cd ..
|
||||
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:
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
|
||||
- run:
|
||||
name: Install Emscripten (for GDevelop.js)
|
||||
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 1.39.6 && ./emsdk activate 1.39.6 && cd ..
|
||||
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 3.1.21 && ./emsdk activate 3.1.21 && cd ..
|
||||
|
||||
- run:
|
||||
name: Install system dependencies for Electron builder
|
||||
@@ -127,7 +127,8 @@ jobs:
|
||||
# Build GDevelop.js (and run tests to ensure it works)
|
||||
- run:
|
||||
name: Build GDevelop.js
|
||||
command: cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build && npm test && cd ..
|
||||
# Use "--runInBand" as it's faster and avoid deadlocks on CircleCI Linux machines (probably because limited in processes number).
|
||||
command: cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build && npm test -- --runInBand && cd ..
|
||||
|
||||
# GDevelop IDE dependencies (after building GDevelop.js to avoid downloading a pre-built version)
|
||||
- run:
|
||||
@@ -184,7 +185,7 @@ jobs:
|
||||
|
||||
- run:
|
||||
name: Install Emscripten (for GDevelop.js)
|
||||
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 1.39.6 && ./emsdk activate 1.39.6 && cd ..
|
||||
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:
|
||||
@@ -200,7 +201,8 @@ jobs:
|
||||
# Build GDevelop.js (and run tests to ensure it works)
|
||||
- run:
|
||||
name: Build GDevelop.js
|
||||
command: cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build && npm test && cd ..
|
||||
# Use "--runInBand" as it's faster and avoid deadlocks on CircleCI Linux machines (probably because limited in processes number).
|
||||
command: cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build && npm test -- --runInBand && cd ..
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
|
37
.github/ISSUE_TEMPLATE/--automatic-crash.yml
vendored
Normal file
37
.github/ISSUE_TEMPLATE/--automatic-crash.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: 💥 Automatic crash report
|
||||
description: Do not use this template for bug reports. This template is only for automatic crash reports.
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Describe what you were doing when the crash happened
|
||||
description: If applicable, add screenshots to help explain your problem.
|
||||
placeholder: |
|
||||
1. Went to '...'
|
||||
2. Clicked on '...'
|
||||
3. Scrolled down to '...'
|
||||
4. Saw error
|
||||
- type: input
|
||||
id: gdevelop_version
|
||||
attributes:
|
||||
label: GDevelop version
|
||||
description: |
|
||||
The version of GDevelop used. Leave the prefilled value.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: platform_info
|
||||
attributes:
|
||||
label: Platform info
|
||||
description: |
|
||||
The platform you are using GDevelop on. Leave the prefilled value.
|
||||
- type: textarea
|
||||
id: error_stack
|
||||
attributes:
|
||||
label: Additional error context
|
||||
description: Additonal context about the problem. Leave the prefilled value.
|
||||
- type: textarea
|
||||
id: component_stack
|
||||
attributes:
|
||||
label: Additional component context
|
||||
description: Additonal context about the problem. Leave the prefilled value.
|
11
.github/ISSUE_TEMPLATE/--bug-report.yml
vendored
11
.github/ISSUE_TEMPLATE/--bug-report.yml
vendored
@@ -2,18 +2,21 @@ name: 🐛Bug report
|
||||
description: Create a bug report about GDevelop or the game engine
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: searched_issues
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
options:
|
||||
- label: I have searched the [existing issues](https://github.com/4ian/GDevelop/issues)
|
||||
required: true
|
||||
- label: I have searched the [existing issues](https://github.com/4ian/GDevelop/issues)
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear and concise description of what the bug is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduction_steps
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: |
|
||||
@@ -27,6 +30,7 @@ body:
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: platform
|
||||
attributes:
|
||||
label: GDevelop platform
|
||||
description: Which platform of GDevelop are you using?
|
||||
@@ -38,6 +42,7 @@ body:
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: gdevelop_version
|
||||
attributes:
|
||||
label: GDevelop version
|
||||
description: |
|
||||
@@ -47,6 +52,7 @@ body:
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: platform_info
|
||||
attributes:
|
||||
label: Platform info
|
||||
value: |
|
||||
@@ -66,6 +72,7 @@ body:
|
||||
|
||||
</details>
|
||||
- type: textarea
|
||||
id: additional_context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context about the problem here.
|
||||
|
4
.github/workflows/update-translations.yml
vendored
4
.github/workflows/update-translations.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
cache-dependency-path: "newIDE/app/package-lock.json"
|
||||
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
working-directory: newIDE/app
|
||||
|
||||
- name: Create a Pull Request with the changes
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
commit-message: Update translations [skip ci]
|
||||
branch: chore/update-translations
|
||||
|
@@ -14,7 +14,7 @@ tasks:
|
||||
init: |
|
||||
sudo apt-get update
|
||||
sudo apt install cmake python-is-python3 python3-distutils -y
|
||||
git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 1.39.6 && ./emsdk activate 1.39.6 && cd ..
|
||||
git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 3.1.21 && ./emsdk activate 3.1.21 && cd ..
|
||||
cd GDevelop.js
|
||||
npm install
|
||||
source ../emsdk/emsdk_env.sh && npm run build -- --dev
|
||||
|
@@ -56,6 +56,7 @@ blocks:
|
||||
- name: GDJS typing and documentation generation
|
||||
commands:
|
||||
- checkout
|
||||
- cache restore newIDE-app-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum newIDE/app/package-lock.json)
|
||||
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
|
||||
- cache restore GDJS-tests-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/tests/package-lock.json)
|
||||
- cd GDJS
|
||||
|
@@ -39,7 +39,7 @@ install:
|
||||
- cd ..
|
||||
# Install Emscripten (for GDevelop.js)
|
||||
- git clone https://github.com/juj/emsdk.git
|
||||
- cd emsdk && ./emsdk install 1.39.6 && ./emsdk activate 1.39.6 && cd ..
|
||||
- cd emsdk && ./emsdk install 3.1.21 && ./emsdk activate 3.1.21 && cd ..
|
||||
# Install GDevelop.js dependencies
|
||||
- cd GDevelop.js && npm install && cd ..
|
||||
# Build GDevelop.js
|
||||
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -113,7 +113,8 @@
|
||||
"memory_resource": "cpp",
|
||||
"__bits": "cpp",
|
||||
"__verbose_abort": "cpp",
|
||||
"variant": "cpp"
|
||||
"variant": "cpp",
|
||||
"charconv": "cpp"
|
||||
},
|
||||
"files.exclude": {
|
||||
"Binaries/*build*": true,
|
||||
|
1
.vscode/tasks.json
vendored
1
.vscode/tasks.json
vendored
@@ -8,6 +8,7 @@
|
||||
"group": "build",
|
||||
"label": "Start development server",
|
||||
"detail": "Starts the GDevelop development server.",
|
||||
"options": { "env": { "NODE_OPTIONS": "--max-old-space-size=8192" } },
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "cra",
|
||||
|
@@ -164,7 +164,7 @@ void LinkEvent::UnserializeFrom(gd::Project& project,
|
||||
}
|
||||
|
||||
bool LinkEvent::AcceptVisitor(gd::EventVisitor &eventVisitor) {
|
||||
return BaseEvent::AcceptVisitor(eventVisitor) |
|
||||
return BaseEvent::AcceptVisitor(eventVisitor) ||
|
||||
eventVisitor.VisitLinkEvent(*this);
|
||||
}
|
||||
|
||||
|
@@ -15,7 +15,8 @@ using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
StandardEvent::StandardEvent() : BaseEvent() {}
|
||||
StandardEvent::StandardEvent()
|
||||
: BaseEvent(), variables(gd::VariablesContainer::SourceType::Local) {}
|
||||
|
||||
StandardEvent::~StandardEvent(){};
|
||||
|
||||
@@ -57,6 +58,9 @@ void StandardEvent::SerializeTo(SerializerElement& element) const {
|
||||
if (!events.IsEmpty())
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
if (HasVariables()) {
|
||||
variables.SerializeTo(element.AddChild("variables"));
|
||||
}
|
||||
}
|
||||
|
||||
void StandardEvent::UnserializeFrom(gd::Project& project,
|
||||
@@ -71,6 +75,11 @@ void StandardEvent::UnserializeFrom(gd::Project& project,
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
}
|
||||
|
||||
variables.Clear();
|
||||
if (element.HasChild("variables")) {
|
||||
variables.UnserializeFrom(element.GetChild("variables"));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -4,13 +4,13 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef GDCORE_STANDARDEVENT_H
|
||||
#define GDCORE_STANDARDEVENT_H
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Events/InstructionsList.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
namespace gd {
|
||||
class Instruction;
|
||||
class Project;
|
||||
@@ -33,6 +33,10 @@ class GD_CORE_API StandardEvent : public gd::BaseEvent {
|
||||
virtual const gd::EventsList& GetSubEvents() const { return events; };
|
||||
virtual gd::EventsList& GetSubEvents() { return events; };
|
||||
|
||||
virtual bool CanHaveVariables() const { return true; }
|
||||
virtual const gd::VariablesContainer& GetVariables() const { return variables; };
|
||||
virtual gd::VariablesContainer& GetVariables() { return variables; };
|
||||
|
||||
const gd::InstructionsList& GetConditions() const { return conditions; };
|
||||
gd::InstructionsList& GetConditions() { return conditions; };
|
||||
|
||||
@@ -53,9 +57,7 @@ class GD_CORE_API StandardEvent : public gd::BaseEvent {
|
||||
gd::InstructionsList conditions;
|
||||
gd::InstructionsList actions;
|
||||
EventsList events;
|
||||
VariablesContainer variables;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_STANDARDEVENT_H
|
||||
#endif
|
||||
|
@@ -46,10 +46,6 @@ void EffectsCodeGenerator::GenerateEffectsIncludeFiles(
|
||||
// TODO Add unit tests on this function.
|
||||
|
||||
// TODO Merge with UsedExtensionsFinder.
|
||||
// Default lights rely on the fact that UsedExtensionsFinder doesn't find
|
||||
// extension usages for effects. This has the happy side effect of not
|
||||
// including Three.js when no 3D object are in the scenes.
|
||||
// We need to make something explicit to avoid future bugs.
|
||||
|
||||
// See also gd::Project::ExposeResources for a method that traverse the whole
|
||||
// project (this time for resources) and
|
||||
|
@@ -3,8 +3,8 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef EVENTSCODEGENERATIONCONTEXT_H
|
||||
#define EVENTSCODEGENERATIONCONTEXT_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
@@ -325,4 +325,3 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
#endif // EVENTSCODEGENERATIONCONTEXT_H
|
||||
|
@@ -254,12 +254,12 @@ gd::String EventsCodeGenerator::GenerateMutatorCall(
|
||||
}
|
||||
|
||||
gd::String operatorStr = arguments[operatorIndex];
|
||||
if (operatorStr.size() > 2)
|
||||
if (operatorStr.size() > 2 && operatorStr[0] == '\"') {
|
||||
operatorStr = operatorStr.substr(
|
||||
1,
|
||||
operatorStr.length() - 1 -
|
||||
1); // Operator contains quote which must be removed.
|
||||
|
||||
}
|
||||
auto mutators = instrInfos.codeExtraInformation.optionalMutators;
|
||||
auto mutator = mutators.find(operatorStr);
|
||||
if (mutator == mutators.end()) {
|
||||
@@ -279,6 +279,9 @@ gd::String EventsCodeGenerator::GenerateMutatorCall(
|
||||
argumentsStr += arguments[i];
|
||||
}
|
||||
}
|
||||
if (instrInfos.GetManipulatedType() == "boolean") {
|
||||
return callStartString + "(" + argumentsStr + ")." + mutator->second;
|
||||
}
|
||||
|
||||
return callStartString + "(" + argumentsStr + ")." + mutator->second + "(" +
|
||||
rhs + ")";
|
||||
@@ -583,6 +586,12 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
return actionCode;
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateLocalVariablesStackAccessor() {
|
||||
return (HasProjectAndLayout() ? GetCodeNamespace()
|
||||
: "eventsFunctionContext") +
|
||||
".localVariables";
|
||||
}
|
||||
|
||||
const EventsCodeGenerator::CallbackDescriptor
|
||||
EventsCodeGenerator::GenerateCallback(
|
||||
const gd::String& callbackID,
|
||||
@@ -607,14 +616,20 @@ EventsCodeGenerator::GenerateCallback(
|
||||
actionsCode += "} //End of subevents\n";
|
||||
}
|
||||
|
||||
gd::String restoreLocalVariablesCode;
|
||||
restoreLocalVariablesCode +=
|
||||
"asyncObjectsList.restoreLocalVariablesContainers(" +
|
||||
GenerateLocalVariablesStackAccessor() + ");\n";
|
||||
|
||||
// Compose the callback function and add outside main
|
||||
const gd::String actionsDeclarationsCode =
|
||||
GenerateObjectsDeclarationCode(callbackContext);
|
||||
|
||||
const gd::String callbackCode = callbackFunctionName + " = function (" +
|
||||
GenerateEventsParameters(callbackContext) +
|
||||
") {\n" + actionsDeclarationsCode +
|
||||
actionsCode + "}\n";
|
||||
const gd::String callbackCode =
|
||||
callbackFunctionName + " = function (" +
|
||||
GenerateEventsParameters(callbackContext) + ") {\n" +
|
||||
restoreLocalVariablesCode +
|
||||
actionsDeclarationsCode + actionsCode + "}\n";
|
||||
|
||||
AddCustomCodeOutsideMain(callbackCode);
|
||||
|
||||
@@ -677,13 +692,13 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
|
||||
if (ParameterMetadata::IsExpression("number", metadata.GetType())) {
|
||||
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, "number", parameter, lastObjectName);
|
||||
*this, context, "number", parameter, lastObjectName, metadata.GetExtraInfo());
|
||||
} else if (ParameterMetadata::IsExpression("string", metadata.GetType())) {
|
||||
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, "string", parameter, lastObjectName);
|
||||
*this, context, "string", parameter, lastObjectName, metadata.GetExtraInfo());
|
||||
} else if (ParameterMetadata::IsExpression("variable", metadata.GetType())) {
|
||||
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, metadata.GetType(), parameter, lastObjectName);
|
||||
*this, context, metadata.GetType(), parameter, lastObjectName, metadata.GetExtraInfo());
|
||||
} else if (ParameterMetadata::IsObject(metadata.GetType())) {
|
||||
// It would be possible to run a gd::ExpressionCodeGenerator if later
|
||||
// objects can have nested objects, or function returning objects.
|
||||
@@ -695,7 +710,8 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
} else if (metadata.GetType() == "operator") {
|
||||
argOutput += parameter.GetPlainString();
|
||||
if (argOutput != "=" && argOutput != "+" && argOutput != "-" &&
|
||||
argOutput != "/" && argOutput != "*") {
|
||||
argOutput != "/" && argOutput != "*" && argOutput != "True" &&
|
||||
argOutput != "False" && argOutput != "Toggle") {
|
||||
cout << "Warning: Bad operator: Set to = by default." << endl;
|
||||
argOutput = "=";
|
||||
}
|
||||
@@ -714,6 +730,8 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
metadata.GetType() == "tilesetResource" ||
|
||||
metadata.GetType() == "videoResource" ||
|
||||
metadata.GetType() == "model3DResource" ||
|
||||
metadata.GetType() == "atlasResource" ||
|
||||
metadata.GetType() == "spineResource" ||
|
||||
// Deprecated, old parameter names:
|
||||
metadata.GetType() == "password" || metadata.GetType() == "musicfile" ||
|
||||
metadata.GetType() == "soundfile" || metadata.GetType() == "police") {
|
||||
@@ -863,6 +881,11 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(
|
||||
gd::EventsList& events, EventsCodeGenerationContext& parentContext) {
|
||||
gd::String output;
|
||||
for (std::size_t eId = 0; eId < events.size(); ++eId) {
|
||||
auto& event = events[eId];
|
||||
if (event.HasVariables()) {
|
||||
GetProjectScopedContainers().GetVariablesContainersList().Push(event.GetVariables());
|
||||
}
|
||||
|
||||
// Each event has its own context : Objects picked in an event are totally
|
||||
// different than the one picked in another.
|
||||
gd::EventsCodeGenerationContext newContext;
|
||||
@@ -883,13 +906,17 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(
|
||||
|
||||
auto& context = reuseParentContext ? reusedContext : newContext;
|
||||
|
||||
gd::String eventCoreCode = events[eId].GenerateEventCode(*this, context);
|
||||
gd::String eventCoreCode = event.GenerateEventCode(*this, context);
|
||||
gd::String scopeBegin = GenerateScopeBegin(context);
|
||||
gd::String scopeEnd = GenerateScopeEnd(context);
|
||||
gd::String declarationsCode = GenerateObjectsDeclarationCode(context);
|
||||
|
||||
output += "\n" + scopeBegin + "\n" + declarationsCode + "\n" +
|
||||
eventCoreCode + "\n" + scopeEnd + "\n";
|
||||
|
||||
if (event.HasVariables()) {
|
||||
GetProjectScopedContainers().GetVariablesContainersList().Pop();
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
@@ -1065,7 +1092,8 @@ gd::String EventsCodeGenerator::GenerateFreeAction(
|
||||
// Generate call
|
||||
gd::String call;
|
||||
if (instrInfos.codeExtraInformation.type == "number" ||
|
||||
instrInfos.codeExtraInformation.type == "string") {
|
||||
instrInfos.codeExtraInformation.type == "string" ||
|
||||
instrInfos.codeExtraInformation.type == "boolean") {
|
||||
if (instrInfos.codeExtraInformation.accessType ==
|
||||
gd::InstructionMetadata::ExtraInformation::MutatorAndOrAccessor)
|
||||
call = GenerateOperatorCall(
|
||||
|
@@ -336,6 +336,16 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Give access to the project scoped containers as code generation might
|
||||
* push and pop variable containers (for local variables).
|
||||
* This could be passed as a parameter recursively in code generation, but this requires
|
||||
* heavy refactoring. Instead, we use this single instance.
|
||||
*/
|
||||
gd::ProjectScopedContainers& GetProjectScopedContainers() {
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the code generation is done for a given project and
|
||||
* layout. If not, this means that the code is generated for a function.
|
||||
@@ -448,7 +458,7 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
*/
|
||||
virtual gd::String GetCodeNamespace() { return ""; };
|
||||
|
||||
enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE };
|
||||
enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE, ANY_VARIABLE };
|
||||
|
||||
/**
|
||||
* Generate a single unique number for the specified instruction.
|
||||
@@ -478,6 +488,11 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
const gd::String& lhs,
|
||||
const gd::String& rhs);
|
||||
|
||||
/**
|
||||
* \brief Generate the code to access the local variables stack.
|
||||
*/
|
||||
virtual gd::String GenerateLocalVariablesStackAccessor();
|
||||
|
||||
protected:
|
||||
virtual const gd::String GenerateRelationalOperatorCodes(
|
||||
const gd::String& operatorString);
|
||||
@@ -534,11 +549,15 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
const VariableScope& scope,
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
const gd::String& objectName) {
|
||||
// This code is only used as a mock.
|
||||
// See the real implementation in GDJS.
|
||||
if (scope == LAYOUT_VARIABLE) {
|
||||
return "getLayoutVariable(" + variableName + ")";
|
||||
|
||||
} else if (scope == PROJECT_VARIABLE) {
|
||||
return "getProjectVariable(" + variableName + ")";
|
||||
} else if (scope == ANY_VARIABLE) {
|
||||
return "getAnyVariable(" + variableName + ")";
|
||||
}
|
||||
|
||||
return "getVariableForObject(" + objectName + ", " + variableName + ")";
|
||||
|
@@ -39,7 +39,8 @@ gd::String ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
EventsCodeGenerationContext& context,
|
||||
const gd::String& rootType,
|
||||
const gd::Expression& expression,
|
||||
const gd::String& rootObjectName) {
|
||||
const gd::String& rootObjectName,
|
||||
const gd::String& extraInfo) {
|
||||
ExpressionCodeGenerator generator(rootType, rootObjectName, codeGenerator, context);
|
||||
|
||||
auto node = expression.GetRootNode();
|
||||
@@ -52,7 +53,8 @@ gd::String ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
|
||||
gd::ExpressionValidator validator(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetProjectScopedContainers(),
|
||||
rootType);
|
||||
rootType,
|
||||
extraInfo);
|
||||
node->Visit(validator);
|
||||
if (!validator.GetFatalErrors().empty()) {
|
||||
std::cout << "Error: \"" << validator.GetFatalErrors()[0]->GetMessage()
|
||||
@@ -110,11 +112,13 @@ void ExpressionCodeGenerator::OnVisitVariableNode(VariableNode& node) {
|
||||
if (gd::ParameterMetadata::IsExpression("variable", type)) {
|
||||
// The node is a variable inside an expression waiting for a *variable* to be returned, not its value.
|
||||
EventsCodeGenerator::VariableScope scope =
|
||||
type == "globalvar"
|
||||
type == "variable"
|
||||
? gd::EventsCodeGenerator::ANY_VARIABLE
|
||||
: type == "globalvar"
|
||||
? gd::EventsCodeGenerator::PROJECT_VARIABLE
|
||||
: ((type == "scenevar")
|
||||
: type == "scenevar"
|
||||
? gd::EventsCodeGenerator::LAYOUT_VARIABLE
|
||||
: gd::EventsCodeGenerator::OBJECT_VARIABLE);
|
||||
: gd::EventsCodeGenerator::OBJECT_VARIABLE;
|
||||
|
||||
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetObjectsContainersList(),
|
||||
@@ -137,19 +141,8 @@ void ExpressionCodeGenerator::OnVisitVariableNode(VariableNode& node) {
|
||||
|
||||
output += codeGenerator.GenerateVariableValueAs(type);
|
||||
}, [&]() {
|
||||
if (!codeGenerator.HasProjectAndLayout()) {
|
||||
gd::LogWarning("Tried to generate access to a variable without a project/scene - the code generator only works for global and scene variables for now.");
|
||||
output += GenerateDefaultValue(type);
|
||||
return;
|
||||
}
|
||||
|
||||
// This could be adapted in the future if more scopes are supported.
|
||||
EventsCodeGenerator::VariableScope scope = gd::EventsCodeGenerator::PROJECT_VARIABLE;
|
||||
if (codeGenerator.GetProjectScopedContainers().GetVariablesContainersList().GetBottomMostVariablesContainer()->Has(node.name)) {
|
||||
scope = gd::EventsCodeGenerator::LAYOUT_VARIABLE;
|
||||
}
|
||||
|
||||
output += codeGenerator.GenerateGetVariable(node.name, scope, context, "");
|
||||
output += codeGenerator.GenerateGetVariable(
|
||||
node.name, gd::EventsCodeGenerator::ANY_VARIABLE, context, "");
|
||||
if (node.child) node.child->Visit(*this);
|
||||
output += codeGenerator.GenerateVariableValueAs(type);
|
||||
}, [&]() {
|
||||
@@ -209,11 +202,13 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
|
||||
codeGenerator.GenerateObject(node.identifierName, type, context);
|
||||
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
|
||||
EventsCodeGenerator::VariableScope scope =
|
||||
type == "globalvar"
|
||||
type == "variable"
|
||||
? gd::EventsCodeGenerator::ANY_VARIABLE
|
||||
: type == "globalvar"
|
||||
? gd::EventsCodeGenerator::PROJECT_VARIABLE
|
||||
: ((type == "scenevar")
|
||||
: type == "scenevar"
|
||||
? gd::EventsCodeGenerator::LAYOUT_VARIABLE
|
||||
: gd::EventsCodeGenerator::OBJECT_VARIABLE);
|
||||
: gd::EventsCodeGenerator::OBJECT_VARIABLE;
|
||||
|
||||
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetObjectsContainersList(),
|
||||
@@ -236,19 +231,9 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
|
||||
node.childIdentifierName, gd::EventsCodeGenerator::OBJECT_VARIABLE, context, node.identifierName);
|
||||
output += codeGenerator.GenerateVariableValueAs(type);
|
||||
}, [&]() {
|
||||
if (!codeGenerator.HasProjectAndLayout()) {
|
||||
gd::LogWarning("Tried to generate access to a variable without a project/scene - the code generator only works for global and scene variables for now.");
|
||||
output += GenerateDefaultValue(type);
|
||||
return;
|
||||
}
|
||||
|
||||
// This could be adapted in the future if more scopes are supported at runtime.
|
||||
EventsCodeGenerator::VariableScope scope = gd::EventsCodeGenerator::PROJECT_VARIABLE;
|
||||
if (variablesContainersList.GetBottomMostVariablesContainer()->Has(node.identifierName)) {
|
||||
scope = gd::EventsCodeGenerator::LAYOUT_VARIABLE;
|
||||
}
|
||||
|
||||
output += codeGenerator.GenerateGetVariable(node.identifierName, scope, context, "");
|
||||
output += codeGenerator.GenerateGetVariable(
|
||||
node.identifierName, gd::EventsCodeGenerator::ANY_VARIABLE, context,
|
||||
"");
|
||||
if (!node.childIdentifierName.empty()) {
|
||||
output += codeGenerator.GenerateVariableAccessor(node.childIdentifierName);
|
||||
}
|
||||
|
@@ -59,7 +59,8 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
|
||||
EventsCodeGenerationContext& context,
|
||||
const gd::String& type,
|
||||
const gd::Expression& expression,
|
||||
const gd::String& objectName = "");
|
||||
const gd::String& objectName = "",
|
||||
const gd::String& extraInfo = "");
|
||||
|
||||
const gd::String& GetOutput() { return output; };
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
namespace gd {
|
||||
|
||||
EventsList BaseEvent::badSubEvents;
|
||||
VariablesContainer BaseEvent::badLocalVariables;
|
||||
std::vector<gd::String> BaseEvent::emptyDependencies;
|
||||
gd::String BaseEvent::emptySourceFile;
|
||||
|
||||
@@ -28,6 +29,8 @@ BaseEvent::BaseEvent()
|
||||
|
||||
bool BaseEvent::HasSubEvents() const { return !GetSubEvents().IsEmpty(); }
|
||||
|
||||
bool BaseEvent::HasVariables() const { return GetVariables().Count() > 0; }
|
||||
|
||||
gd::String BaseEvent::GenerateEventCode(
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
|
@@ -3,9 +3,7 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef GDCORE_EVENT_H
|
||||
#define GDCORE_EVENT_H
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
@@ -26,6 +24,7 @@ class SerializerElement;
|
||||
class Instruction;
|
||||
class EventVisitor;
|
||||
class ReadOnlyEventVisitor;
|
||||
class VariablesContainer;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -92,6 +91,32 @@ class GD_CORE_API BaseEvent {
|
||||
*/
|
||||
bool HasSubEvents() const;
|
||||
|
||||
/**
|
||||
* Derived class have to redefine this function, so as to return true, if they
|
||||
* can have local variables.
|
||||
*/
|
||||
virtual bool CanHaveVariables() const { return false; }
|
||||
|
||||
/**
|
||||
* Return the local variables, if applicable.
|
||||
*/
|
||||
virtual const gd::VariablesContainer& GetVariables() const {
|
||||
return badLocalVariables;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the local variables, if applicable.
|
||||
*/
|
||||
virtual gd::VariablesContainer& GetVariables() {
|
||||
return badLocalVariables;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Return true if the events has local variables.
|
||||
* \warning This is only applicable when CanHaveVariables() return true.
|
||||
*/
|
||||
bool HasVariables() const;
|
||||
|
||||
/**
|
||||
* \brief Return a list of all conditions of the event.
|
||||
* \note Used to preprocess or search in the conditions.
|
||||
@@ -301,6 +326,7 @@ class GD_CORE_API BaseEvent {
|
||||
///< Used for saving the event for instance.
|
||||
|
||||
static gd::EventsList badSubEvents;
|
||||
static gd::VariablesContainer badLocalVariables;
|
||||
static std::vector<gd::String> emptyDependencies;
|
||||
static gd::String emptySourceFile;
|
||||
};
|
||||
@@ -325,6 +351,3 @@ class EmptyEvent : public BaseEvent {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EVENT_H
|
||||
#endif
|
||||
|
@@ -277,8 +277,11 @@ class GD_CORE_API ExpressionParser2 {
|
||||
|
||||
std::unique_ptr<VariableNode> Variable(const gd::String &name, gd::ExpressionParserLocation nameLocation) {
|
||||
auto variable = gd::make_unique<VariableNode>(name);
|
||||
variable->child = VariableAccessorOrVariableBracketAccessor();
|
||||
variable->child->parent = variable.get();
|
||||
|
||||
if (CheckIfChar(IsOpeningSquareBracket) || CheckIfChar(IsDot)) {
|
||||
variable->child = VariableAccessorOrVariableBracketAccessor();
|
||||
variable->child->parent = variable.get();
|
||||
}
|
||||
|
||||
variable->location = ExpressionParserLocation(
|
||||
nameLocation.GetStartPosition(), GetCurrentPosition());
|
||||
@@ -302,8 +305,12 @@ class GD_CORE_API ExpressionParser2 {
|
||||
"bracket for each opening bracket."));
|
||||
}
|
||||
SkipIfChar(IsClosingSquareBracket);
|
||||
child->child = VariableAccessorOrVariableBracketAccessor();
|
||||
child->child->parent = child.get();
|
||||
|
||||
SkipAllWhitespaces();
|
||||
if (CheckIfChar(IsOpeningSquareBracket) || CheckIfChar(IsDot)) {
|
||||
child->child = VariableAccessorOrVariableBracketAccessor();
|
||||
child->child->parent = child.get();
|
||||
}
|
||||
child->location =
|
||||
ExpressionParserLocation(childStartPosition, GetCurrentPosition());
|
||||
|
||||
@@ -315,8 +322,15 @@ class GD_CORE_API ExpressionParser2 {
|
||||
auto identifierAndLocation = ReadIdentifierName(/*allowDeprecatedSpacesInName=*/ false);
|
||||
auto child =
|
||||
gd::make_unique<VariableAccessorNode>(identifierAndLocation.name);
|
||||
child->child = VariableAccessorOrVariableBracketAccessor();
|
||||
child->child->parent = child.get();
|
||||
if (identifierAndLocation.name.empty()) {
|
||||
child->diagnostic = RaiseSyntaxError(_("A name should be entered after the dot."));
|
||||
}
|
||||
|
||||
SkipAllWhitespaces();
|
||||
if (CheckIfChar(IsOpeningSquareBracket) || CheckIfChar(IsDot)) {
|
||||
child->child = VariableAccessorOrVariableBracketAccessor();
|
||||
child->child->parent = child.get();
|
||||
}
|
||||
child->nameLocation = identifierAndLocation.location;
|
||||
child->dotLocation = dotLocation;
|
||||
child->location =
|
||||
@@ -325,7 +339,11 @@ class GD_CORE_API ExpressionParser2 {
|
||||
return std::move(child);
|
||||
}
|
||||
|
||||
return std::move(gd::make_unique<VariableAccessorOrVariableBracketAccessorNode>());
|
||||
// Should never happen, unless a node called this function without checking if the current character
|
||||
// was a dot or an opening bracket - this means there is an error in the grammar.
|
||||
auto unrecognisedNode = gd::make_unique<VariableAccessorOrVariableBracketAccessorNode>();
|
||||
unrecognisedNode->diagnostic = RaiseSyntaxError(_("A dot or bracket was expected here."));
|
||||
return std::move(unrecognisedNode);
|
||||
}
|
||||
|
||||
std::unique_ptr<FunctionCallNode> FreeFunction(
|
||||
@@ -361,18 +379,24 @@ class GD_CORE_API ExpressionParser2 {
|
||||
const auto &childIdentifierNameLocation =
|
||||
childIdentifierAndLocation.location;
|
||||
|
||||
std::unique_ptr<gd::ExpressionParserError> emptyNameError = childIdentifierName.empty() ?
|
||||
RaiseSyntaxError(_("A name should be entered after the dot.")) : nullptr;
|
||||
|
||||
SkipAllWhitespaces();
|
||||
|
||||
if (IsNamespaceSeparator()) {
|
||||
ExpressionParserLocation namespaceSeparatorLocation =
|
||||
SkipNamespaceSeparator();
|
||||
SkipAllWhitespaces();
|
||||
return BehaviorFunction(parentIdentifier,
|
||||
auto behaviorFunction = BehaviorFunction(parentIdentifier,
|
||||
childIdentifierName,
|
||||
parentIdentifierLocation,
|
||||
parentIdentifierDotLocation,
|
||||
childIdentifierNameLocation,
|
||||
namespaceSeparatorLocation);
|
||||
|
||||
if (emptyNameError) behaviorFunction->diagnostic = std::move(emptyNameError);
|
||||
return std::move(behaviorFunction);
|
||||
} else if (CheckIfChar(IsOpeningParenthesis)) {
|
||||
ExpressionParserLocation openingParenthesisLocation = SkipChar();
|
||||
|
||||
@@ -381,7 +405,7 @@ class GD_CORE_API ExpressionParser2 {
|
||||
childIdentifierName);
|
||||
auto parametersNode = Parameters(function.get(), parentIdentifier);
|
||||
function->parameters = std::move(parametersNode.parameters),
|
||||
function->diagnostic = std::move(parametersNode.diagnostic);
|
||||
function->diagnostic = emptyNameError ? std::move(emptyNameError) : std::move(parametersNode.diagnostic);
|
||||
|
||||
function->location = ExpressionParserLocation(
|
||||
parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
|
||||
@@ -394,6 +418,8 @@ class GD_CORE_API ExpressionParser2 {
|
||||
return std::move(function);
|
||||
} else if (CheckIfChar(IsDot) || CheckIfChar(IsOpeningSquareBracket)) {
|
||||
auto variable = gd::make_unique<VariableNode>(parentIdentifier);
|
||||
variable->diagnostic = std::move(emptyNameError);
|
||||
|
||||
auto child =
|
||||
gd::make_unique<VariableAccessorNode>(childIdentifierName);
|
||||
child->child = VariableAccessorOrVariableBracketAccessor();
|
||||
@@ -419,6 +445,7 @@ class GD_CORE_API ExpressionParser2 {
|
||||
node->identifierNameLocation = parentIdentifierLocation;
|
||||
node->identifierNameDotLocation = parentIdentifierDotLocation;
|
||||
node->childIdentifierNameLocation = childIdentifierNameLocation;
|
||||
node->diagnostic = std::move(emptyNameError);
|
||||
return std::move(node);
|
||||
}
|
||||
|
||||
@@ -491,11 +518,6 @@ class GD_CORE_API ExpressionParser2 {
|
||||
std::vector<std::unique_ptr<ExpressionNode>> parameters;
|
||||
gd::String lastObjectName = "";
|
||||
|
||||
// By convention, object is always the first parameter, and behavior the
|
||||
// second one.
|
||||
size_t parameterIndex =
|
||||
WrittenParametersFirstIndex(objectName, behaviorName);
|
||||
|
||||
bool previousCharacterIsParameterSeparator = false;
|
||||
while (!IsEndReached()) {
|
||||
SkipAllWhitespaces();
|
||||
@@ -514,7 +536,6 @@ class GD_CORE_API ExpressionParser2 {
|
||||
SkipAllWhitespaces();
|
||||
previousCharacterIsParameterSeparator = CheckIfChar(IsParameterSeparator);
|
||||
SkipIfChar(IsParameterSeparator);
|
||||
parameterIndex++;
|
||||
}
|
||||
|
||||
ExpressionParserLocation invalidClosingParenthesisLocation;
|
||||
|
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
namespace gd {
|
||||
@@ -43,6 +44,11 @@ class GD_CORE_API ExpressionParser2NodePrinter
|
||||
*/
|
||||
const gd::String& GetOutput() { return output; };
|
||||
|
||||
static gd::String PrintStringLiteral(const gd::String& str) {
|
||||
return "\"" +
|
||||
str.FindAndReplace("\\", "\\\\").FindAndReplace("\"", "\\\"") + "\"";
|
||||
}
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
|
||||
output += "(";
|
||||
@@ -69,10 +75,7 @@ class GD_CORE_API ExpressionParser2NodePrinter
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode& node) override { output += node.number; }
|
||||
void OnVisitTextNode(TextNode& node) override {
|
||||
output +=
|
||||
"\"" +
|
||||
node.text.FindAndReplace("\\", "\\\\").FindAndReplace("\"", "\\\"") +
|
||||
"\"";
|
||||
output += PrintStringLiteral(node.text);
|
||||
}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
output += node.name;
|
||||
@@ -97,8 +100,8 @@ class GD_CORE_API ExpressionParser2NodePrinter
|
||||
}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
if (!node.behaviorFunctionName.empty()) {
|
||||
output +=
|
||||
node.objectName + "." + node.objectFunctionOrBehaviorName + "::" + node.behaviorFunctionName;
|
||||
output += node.objectName + "." + node.objectFunctionOrBehaviorName +
|
||||
"::" + node.behaviorFunctionName;
|
||||
} else {
|
||||
output += node.objectName + "." + node.objectFunctionOrBehaviorName;
|
||||
}
|
||||
|
@@ -396,7 +396,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Z order"),
|
||||
_("Modify the Z-order of an object"),
|
||||
_("the z-order"),
|
||||
_("Z order"),
|
||||
_("Layers and cameras"),
|
||||
"res/actions/planicon24.png",
|
||||
"res/actions/planicon.png")
|
||||
|
||||
@@ -417,6 +417,93 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.SetDefaultValue("\"\"")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("SetNumberObjectVariable",
|
||||
_("Change variable value"),
|
||||
_("Modify the number value of an object variable."),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("number",
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction("SetStringObjectVariable",
|
||||
_("Change text variable"),
|
||||
_("Modify the text of an object variable."),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("string",
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction("SetBooleanObjectVariable",
|
||||
_("Change boolean variable"),
|
||||
_("Modify the boolean value of an object variable."),
|
||||
_("Change the variable _PARAM1_ of _PARAM0_: _PARAM2_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("operator", _("Value"), "boolean")
|
||||
// This parameter allows to keep the operand expression
|
||||
// when the editor switch between variable instructions.
|
||||
.AddCodeOnlyParameter("yesorno", _("Value"))
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddCondition("NumberObjectVariable",
|
||||
_("Variable value"),
|
||||
_("Compare the number value of an object variable."),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddCondition("StringObjectVariable",
|
||||
_("Text variable"),
|
||||
_("Compare the text of an object variable."),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddCondition("BooleanObjectVariable",
|
||||
_("Boolean variable"),
|
||||
_("Compare the boolean value of an object variable."),
|
||||
_("The variable _PARAM1_ of _PARAM0_ is _PARAM2_"),
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("Check if the value is"))
|
||||
.SetDefaultValue("true")
|
||||
// This parameter allows to keep the operand expression
|
||||
// when the editor switch between variable instructions.
|
||||
.AddCodeOnlyParameter("yesorno", _("Value"))
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction("ModVarObjet",
|
||||
_("Change number variable"),
|
||||
_("Modify the number value of an object variable."),
|
||||
@@ -428,7 +515,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("number",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction("ModVarObjetTxt",
|
||||
_("Change text variable"),
|
||||
@@ -441,7 +529,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("string",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction("SetObjectVariableAsBoolean",
|
||||
_("Change boolean variable"),
|
||||
@@ -454,7 +543,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("New Value:"));
|
||||
.AddParameter("trueorfalse", _("New Value:"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction(
|
||||
"ToggleObjectVariableAsBoolean",
|
||||
@@ -469,7 +559,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/actions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"));
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddCondition("ObjectVariableChildExists",
|
||||
_("Child existence"),
|
||||
@@ -550,7 +641,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Z-order"),
|
||||
_("Compare the Z-order of the specified object."),
|
||||
_("the Z-order"),
|
||||
_("Z-order"),
|
||||
_("Layer"),
|
||||
"res/conditions/planicon24.png",
|
||||
"res/conditions/planicon.png")
|
||||
|
||||
@@ -657,7 +748,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions());
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddCondition("VarObjetTxt",
|
||||
_("Text variable"),
|
||||
@@ -670,7 +762,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", ParameterOptions::MakeNewOptions());
|
||||
"string", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddCondition("ObjectVariableAsBoolean",
|
||||
_("Boolean variable"),
|
||||
@@ -683,7 +776,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("Check if the value is"))
|
||||
.SetDefaultValue("true");
|
||||
.SetDefaultValue("true")
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddCondition("VarObjetDef",
|
||||
"Variable defined",
|
||||
@@ -697,6 +791,47 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("string", _("Variable"))
|
||||
.SetHidden(); // Deprecated.
|
||||
|
||||
obj.AddAction(
|
||||
"PushStringToObjectVariable",
|
||||
_("Add text variable"),
|
||||
_("Adds a text (string) to the end of an object array variable."),
|
||||
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction("PushNumberToObjectVariable",
|
||||
_("Add variable array value"),
|
||||
_("Adds a number to the end of an object array variable."),
|
||||
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction(
|
||||
"PushBooleanToObjectVariable",
|
||||
_("Add boolean variable"),
|
||||
_("Adds a boolean to the end of an object array variable."),
|
||||
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction(
|
||||
"ObjectVariablePush",
|
||||
_("Add existing variable"),
|
||||
@@ -724,7 +859,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction("ObjectVariablePushNumber",
|
||||
_("Add number variable"),
|
||||
@@ -736,7 +872,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction(
|
||||
"ObjectVariablePushBool",
|
||||
@@ -749,7 +886,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction(
|
||||
"ObjectVariableRemoveAt",
|
||||
@@ -1151,7 +1289,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
obj.AddExpression("ZOrder",
|
||||
_("Z-order"),
|
||||
_("Z-order of an object"),
|
||||
_("Visibility"),
|
||||
"",
|
||||
"res/actions/planicon.png")
|
||||
.AddParameter("object", _("Object"));
|
||||
|
||||
@@ -1203,7 +1341,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"));
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddExpression(
|
||||
"VariableChildCount",
|
||||
@@ -1281,8 +1420,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Enable an effect on the object"),
|
||||
_("Enable effect _PARAM1_ on _PARAM0_: _PARAM2_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
.AddParameter("yesorno", _("Enable?"))
|
||||
@@ -1297,8 +1436,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"names) in the effects window."),
|
||||
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
.AddParameter("objectEffectParameterName", _("Property name"))
|
||||
@@ -1315,8 +1454,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"names) in the effects window."),
|
||||
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
.AddParameter("objectEffectParameterName", _("Property name"))
|
||||
@@ -1332,8 +1471,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"names) in the effects window."),
|
||||
_("Enable _PARAM2_ for effect _PARAM1_ of _PARAM0_: _PARAM3_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
.AddParameter("objectEffectParameterName", _("Property name"))
|
||||
@@ -1347,8 +1486,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Check if the effect on an object is enabled."),
|
||||
_("Effect _PARAM1_ of _PARAM0_ is enabled"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
.MarkAsSimple()
|
||||
@@ -1624,7 +1763,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Cast a ray from _PARAM1_;_PARAM2_, angle: _PARAM3_ and max "
|
||||
"distance: _PARAM4_px, against _PARAM0_, and save the "
|
||||
"result in _PARAM5_, _PARAM6_"),
|
||||
"",
|
||||
_("Collision"),
|
||||
"res/conditions/raycast24.png",
|
||||
"res/conditions/raycast.png")
|
||||
.AddParameter("objectList", _("Objects to test against the ray"))
|
||||
@@ -1655,7 +1794,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Cast a ray from _PARAM1_;_PARAM2_ to _PARAM3_;_PARAM4_ "
|
||||
"against _PARAM0_, and save the "
|
||||
"result in _PARAM5_, _PARAM6_"),
|
||||
"",
|
||||
_("Collision"),
|
||||
"res/conditions/raycast24.png",
|
||||
"res/conditions/raycast.png")
|
||||
.AddParameter("objectList", _("Objects to test against the ray"))
|
||||
|
@@ -27,7 +27,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Layers and cameras"))
|
||||
.SetIcon("res/conditions/camera24.png");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
|
||||
.SetIcon("res/actions/effect24.png");
|
||||
.SetIcon("res/actions/effect_black.svg");
|
||||
|
||||
extension
|
||||
.AddExpressionAndConditionAndAction(
|
||||
@@ -327,7 +327,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0");
|
||||
|
||||
// TODO Deprecated: hide this action in a future release.
|
||||
extension
|
||||
.AddAction(
|
||||
"FixCamera",
|
||||
@@ -339,6 +338,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"",
|
||||
"res/actions/camera24.png",
|
||||
"res/actions/camera.png")
|
||||
.SetHidden()
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("objectPtr", _("Object"))
|
||||
.AddParameter("expression",
|
||||
@@ -386,7 +386,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
_("Center the camera on an object"),
|
||||
_("Center the camera on the specified object."),
|
||||
_("Center camera on _PARAM1_ (layer: _PARAM3_)"),
|
||||
"",
|
||||
_("Layers and cameras"),
|
||||
"res/actions/camera24.png",
|
||||
"res/actions/camera.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
@@ -450,8 +450,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"names) in the effects window."),
|
||||
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of layer _PARAM1_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
@@ -469,8 +469,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"names) in the effects window."),
|
||||
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of layer _PARAM1_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
@@ -488,8 +488,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"names) in the effects window."),
|
||||
_("Enable _PARAM3_ for effect _PARAM2_ of layer _PARAM1_: _PARAM4_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
@@ -504,8 +504,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
_("The effect on a layer is enabled"),
|
||||
_("Effect _PARAM2_ on layer _PARAM1_ is enabled"),
|
||||
_(""),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
@@ -518,8 +518,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
_("Enable an effect on a layer"),
|
||||
_("Enable effect _PARAM2_ on layer _PARAM1_: _PARAM3_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
@@ -548,7 +548,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
extension
|
||||
.AddAction(
|
||||
"ChangeLayerTimeScale",
|
||||
_("Change layer time scale"),
|
||||
_("Layer time scale"),
|
||||
_("Change the time scale applied to the objects of the layer."),
|
||||
_("Set the time scale of layer _PARAM1_ to _PARAM2_"),
|
||||
"",
|
||||
@@ -594,7 +594,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
extension
|
||||
.AddAction(
|
||||
"SetLayerAmbientLightColor",
|
||||
_("Set the ambient light color"),
|
||||
_("Ambient light color"),
|
||||
_("Set the ambient light color of the lighting layer in format "
|
||||
"\"R;G;B\" string."),
|
||||
_("Set the ambient color of the lighting layer _PARAM1_ to _PARAM2_"),
|
||||
|
@@ -44,7 +44,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAnimatableExtension(
|
||||
"number",
|
||||
"Index",
|
||||
_("Animation (by number)"),
|
||||
_("the number of the animation played by the object (the number from "
|
||||
_("the animation played by the object using the animation number (from "
|
||||
"the animations list)"),
|
||||
_("the number of the animation"),
|
||||
_("Animations and images"),
|
||||
|
@@ -24,7 +24,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
|
||||
.SetIcon("res/actions/effect24.png");
|
||||
.SetIcon("res/actions/effect_black.svg");
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
"EffectBehavior",
|
||||
@@ -32,7 +32,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
"Effect",
|
||||
_("Apply visual effects to objects."),
|
||||
"",
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect_black.svg",
|
||||
"EffectBehavior",
|
||||
std::make_shared<gd::Behavior>(),
|
||||
std::make_shared<gd::BehaviorsSharedData>())
|
||||
@@ -43,8 +43,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
_("Enable an effect on the object"),
|
||||
_("Enable effect _PARAM2_ on _PARAM0_: _PARAM3_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
@@ -58,8 +58,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
"names) in the effects window."),
|
||||
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
@@ -75,8 +75,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
"names) in the effects window."),
|
||||
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
@@ -91,8 +91,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
"names) in the effects window."),
|
||||
_("Enable _PARAM3_ for effect _PARAM2_ of _PARAM0_: _PARAM4_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
@@ -105,8 +105,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
_("Check if the effect on an object is enabled."),
|
||||
_("Effect _PARAM2_ of _PARAM0_ is enabled"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
"res/actions/effect_black.svg",
|
||||
"res/actions/effect_black.svg")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
|
@@ -24,7 +24,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFlippableExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
|
||||
.SetIcon("res/actions/effect24.png");
|
||||
.SetIcon("res/actions/effect_black.svg");
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
"FlippableBehavior",
|
||||
|
@@ -46,7 +46,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsScalableExtension(
|
||||
_("Scale"),
|
||||
_("the scale of the object (default scale is 1)"),
|
||||
_("the scale"),
|
||||
_("Scale"),
|
||||
_("Size"),
|
||||
"res/actions/scale24_black.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "ScalableBehavior")
|
||||
@@ -63,7 +63,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsScalableExtension(
|
||||
_("Scale on X axis"),
|
||||
_("the scale on X axis of the object (default scale is 1)"),
|
||||
_("the scale on X axis"),
|
||||
_("Scale"),
|
||||
_("Size"),
|
||||
"res/actions/scaleWidth24_black.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "ScalableBehavior")
|
||||
@@ -80,7 +80,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsScalableExtension(
|
||||
_("Scale on Y axis"),
|
||||
_("the scale on Y axis of the object (default scale is 1)"),
|
||||
_("the scale on Y axis"),
|
||||
_("Scale"),
|
||||
_("Size"),
|
||||
"res/actions/scaleHeight24_black.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "ScalableBehavior")
|
||||
|
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
#include "AllBuiltinExtensions.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h"
|
||||
|
||||
using namespace std;
|
||||
namespace gd {
|
||||
@@ -57,7 +58,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
|
||||
extension
|
||||
.AddCondition("DoesSceneExist",
|
||||
_("Does scene exist"),
|
||||
_("Check if scene exists."),
|
||||
_("Check if a scene exists."),
|
||||
_("Scene _PARAM1_ exists"),
|
||||
"",
|
||||
"res/actions/texte.png",
|
||||
@@ -163,6 +164,45 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
|
||||
"res/actions/window.png")
|
||||
.SetHelpPath("/interface/scene-editor/events")
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
|
||||
extension
|
||||
.AddAction("PrioritizeLoadingOfScene",
|
||||
_("Preload scene"),
|
||||
_("Preload a scene resources as soon as possible in background."),
|
||||
_("Preload scene _PARAM1_ in background"),
|
||||
"",
|
||||
"res/actions/hourglass_black.svg",
|
||||
"res/actions/hourglass_black.svg")
|
||||
.SetHelpPath("/all-features/resources-loading")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("sceneName", _("Name of the new scene"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension.AddExpressionAndCondition("number",
|
||||
"SceneLoadingProgress",
|
||||
_("Scene loading progress"),
|
||||
_("The progress of resources loading in background for a scene (between 0 and 1)."),
|
||||
_("_PARAM0_ loading progress"),
|
||||
_(""),
|
||||
"res/actions/hourglass_black.svg")
|
||||
.SetHelpPath("/all-features/resources-loading")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("sceneName", _("Scene name"))
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("AreSceneAssetsLoaded",
|
||||
_("Scene preloaded"),
|
||||
_("Check if scene resources have finished to load in background."),
|
||||
_("Scene _PARAM1_ was preloaded in background"),
|
||||
"",
|
||||
"res/actions/hourglass_black.svg",
|
||||
"res/actions/hourglass_black.svg")
|
||||
.SetHelpPath("/all-features/resources-loading")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("sceneName", _("Scene name"))
|
||||
.MarkAsAdvanced();
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -6,8 +6,6 @@
|
||||
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Animation.h"
|
||||
#include <vector>
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
@@ -4,13 +4,11 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef GDCORE_ANIMATION_H
|
||||
#define GDCORE_ANIMATION_H
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class Direction;
|
||||
}
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -93,4 +91,3 @@ class GD_CORE_API Animation {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
#endif // GDCORE_ANIMATION_H
|
||||
|
@@ -3,12 +3,12 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_DIRECTION_H
|
||||
#define GDCORE_DIRECTION_H
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
|
||||
namespace gd {
|
||||
class Sprite;
|
||||
class SerializerElement;
|
||||
}
|
||||
|
||||
@@ -142,4 +142,3 @@ class GD_CORE_API Direction {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
#endif // GDCORE_DIRECTION_H
|
||||
|
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteAnimationList.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Animation.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/Project/InitialInstance.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
Animation SpriteAnimationList::badAnimation;
|
||||
|
||||
SpriteAnimationList::SpriteAnimationList()
|
||||
: adaptCollisionMaskAutomatically(true) {}
|
||||
|
||||
SpriteAnimationList::~SpriteAnimationList(){};
|
||||
|
||||
void SpriteAnimationList::UnserializeFrom(const gd::SerializerElement& element) {
|
||||
adaptCollisionMaskAutomatically =
|
||||
element.GetBoolAttribute("adaptCollisionMaskAutomatically", false);
|
||||
|
||||
RemoveAllAnimations();
|
||||
const gd::SerializerElement& animationsElement =
|
||||
element.GetChild("animations", 0, "Animations");
|
||||
animationsElement.ConsiderAsArrayOf("animation", "Animation");
|
||||
for (std::size_t i = 0; i < animationsElement.GetChildrenCount(); ++i) {
|
||||
const gd::SerializerElement& animationElement =
|
||||
animationsElement.GetChild(i);
|
||||
Animation newAnimation;
|
||||
|
||||
newAnimation.useMultipleDirections = animationElement.GetBoolAttribute(
|
||||
"useMultipleDirections", false, "typeNormal");
|
||||
newAnimation.SetName(animationElement.GetStringAttribute("name", ""));
|
||||
|
||||
// Compatibility with GD <= 3.3
|
||||
if (animationElement.HasChild("Direction")) {
|
||||
for (std::size_t j = 0;
|
||||
j < animationElement.GetChildrenCount("Direction");
|
||||
++j) {
|
||||
Direction direction;
|
||||
direction.UnserializeFrom(animationElement.GetChild("Direction", j));
|
||||
|
||||
newAnimation.SetDirectionsCount(newAnimation.GetDirectionsCount() + 1);
|
||||
newAnimation.SetDirection(direction,
|
||||
newAnimation.GetDirectionsCount() - 1);
|
||||
}
|
||||
}
|
||||
// End of compatibility code
|
||||
else {
|
||||
const gd::SerializerElement& directionsElement =
|
||||
animationElement.GetChild("directions");
|
||||
directionsElement.ConsiderAsArrayOf("direction");
|
||||
for (std::size_t j = 0; j < directionsElement.GetChildrenCount(); ++j) {
|
||||
Direction direction;
|
||||
direction.UnserializeFrom(directionsElement.GetChild(j));
|
||||
|
||||
newAnimation.SetDirectionsCount(newAnimation.GetDirectionsCount() + 1);
|
||||
newAnimation.SetDirection(direction,
|
||||
newAnimation.GetDirectionsCount() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
AddAnimation(newAnimation);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteAnimationList::SerializeTo(gd::SerializerElement& element) const {
|
||||
element.SetAttribute("adaptCollisionMaskAutomatically",
|
||||
adaptCollisionMaskAutomatically);
|
||||
|
||||
// Animations
|
||||
gd::SerializerElement& animationsElement = element.AddChild("animations");
|
||||
animationsElement.ConsiderAsArrayOf("animation");
|
||||
for (std::size_t k = 0; k < GetAnimationsCount(); k++) {
|
||||
gd::SerializerElement& animationElement =
|
||||
animationsElement.AddChild("animation");
|
||||
|
||||
animationElement.SetAttribute("useMultipleDirections",
|
||||
GetAnimation(k).useMultipleDirections);
|
||||
animationElement.SetAttribute("name", GetAnimation(k).GetName());
|
||||
|
||||
gd::SerializerElement& directionsElement =
|
||||
animationElement.AddChild("directions");
|
||||
directionsElement.ConsiderAsArrayOf("direction");
|
||||
for (std::size_t l = 0; l < GetAnimation(k).GetDirectionsCount(); l++) {
|
||||
GetAnimation(k).GetDirection(l).SerializeTo(
|
||||
directionsElement.AddChild("direction"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteAnimationList::ExposeResources(gd::ArbitraryResourceWorker& worker) {
|
||||
for (std::size_t j = 0; j < GetAnimationsCount(); j++) {
|
||||
for (std::size_t k = 0; k < GetAnimation(j).GetDirectionsCount(); k++) {
|
||||
for (std::size_t l = 0;
|
||||
l < GetAnimation(j).GetDirection(k).GetSpritesCount();
|
||||
l++) {
|
||||
worker.ExposeImage(
|
||||
GetAnimation(j).GetDirection(k).GetSprite(l).GetImageName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Animation& SpriteAnimationList::GetAnimation(std::size_t nb) const {
|
||||
if (nb >= animations.size()) return badAnimation;
|
||||
|
||||
return animations[nb];
|
||||
}
|
||||
|
||||
Animation& SpriteAnimationList::GetAnimation(std::size_t nb) {
|
||||
if (nb >= animations.size()) return badAnimation;
|
||||
|
||||
return animations[nb];
|
||||
}
|
||||
|
||||
void SpriteAnimationList::AddAnimation(const Animation& animation) {
|
||||
animations.push_back(animation);
|
||||
}
|
||||
|
||||
bool SpriteAnimationList::RemoveAnimation(std::size_t nb) {
|
||||
if (nb >= GetAnimationsCount()) return false;
|
||||
|
||||
animations.erase(animations.begin() + nb);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SpriteAnimationList::SwapAnimations(std::size_t firstIndex,
|
||||
std::size_t secondIndex) {
|
||||
if (firstIndex < animations.size() && secondIndex < animations.size() &&
|
||||
firstIndex != secondIndex)
|
||||
std::swap(animations[firstIndex], animations[secondIndex]);
|
||||
}
|
||||
|
||||
void SpriteAnimationList::MoveAnimation(std::size_t oldIndex, std::size_t newIndex) {
|
||||
if (oldIndex >= animations.size() || newIndex >= animations.size()) return;
|
||||
|
||||
auto animation = animations[oldIndex];
|
||||
animations.erase(animations.begin() + oldIndex);
|
||||
animations.insert(animations.begin() + newIndex, animation);
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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/Extensions/Builtin/SpriteExtension/Animation.h"
|
||||
|
||||
namespace gd {
|
||||
class InitialInstance;
|
||||
class SerializerElement;
|
||||
class PropertyDescriptor;
|
||||
class ArbitraryResourceWorker;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief A list of animations, containing directions with images and collision mask.
|
||||
*
|
||||
* It's used in the configuration of object that implements image-based animations.
|
||||
*
|
||||
* \see Animation
|
||||
* \see Direction
|
||||
* \see Sprite
|
||||
* \ingroup SpriteObjectExtension
|
||||
*/
|
||||
class GD_CORE_API SpriteAnimationList {
|
||||
public:
|
||||
SpriteAnimationList();
|
||||
virtual ~SpriteAnimationList();
|
||||
|
||||
void ExposeResources(gd::ArbitraryResourceWorker& worker);
|
||||
|
||||
/**
|
||||
* \brief Return the animation at the specified index.
|
||||
* If the index is out of bound, a "bad animation" object is returned.
|
||||
*/
|
||||
const Animation& GetAnimation(std::size_t nb) const;
|
||||
|
||||
/**
|
||||
* \brief Return the animation at the specified index.
|
||||
* If the index is out of bound, a "bad animation" object is returned.
|
||||
*/
|
||||
Animation& GetAnimation(std::size_t nb);
|
||||
|
||||
/**
|
||||
* \brief Return the number of animations this object has.
|
||||
*/
|
||||
std::size_t GetAnimationsCount() const { return animations.size(); };
|
||||
|
||||
/**
|
||||
* \brief Add an animation at the end of the existing ones.
|
||||
*/
|
||||
void AddAnimation(const Animation& animation);
|
||||
|
||||
/**
|
||||
* \brief Remove an animation.
|
||||
*/
|
||||
bool RemoveAnimation(std::size_t nb);
|
||||
|
||||
/**
|
||||
* \brief Remove all animations.
|
||||
*/
|
||||
void RemoveAllAnimations() { animations.clear(); }
|
||||
|
||||
/**
|
||||
* \brief Return true if the object hasn't any animation.
|
||||
*/
|
||||
bool HasNoAnimations() const { return animations.empty(); }
|
||||
|
||||
/**
|
||||
* \brief Swap the position of two animations
|
||||
*/
|
||||
void SwapAnimations(std::size_t firstIndex, std::size_t secondIndex);
|
||||
|
||||
/**
|
||||
* \brief Change the position of the specified animation
|
||||
*/
|
||||
void MoveAnimation(std::size_t oldIndex, std::size_t newIndex);
|
||||
|
||||
/**
|
||||
* \brief Return a read-only reference to the vector containing all the
|
||||
* animation of the object.
|
||||
*/
|
||||
const std::vector<Animation>& GetAllAnimations() const { return animations; }
|
||||
|
||||
/**
|
||||
* @brief Check if the collision mask adapts automatically to the animation.
|
||||
*/
|
||||
bool AdaptCollisionMaskAutomatically() const {
|
||||
return adaptCollisionMaskAutomatically;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set if the collision mask adapts automatically to the animation.
|
||||
*/
|
||||
void SetAdaptCollisionMaskAutomatically(bool enable) {
|
||||
adaptCollisionMaskAutomatically = enable;
|
||||
}
|
||||
|
||||
void UnserializeFrom(const gd::SerializerElement& element);
|
||||
void SerializeTo(gd::SerializerElement& element) const;
|
||||
|
||||
private:
|
||||
|
||||
mutable std::vector<Animation> animations;
|
||||
|
||||
static Animation badAnimation; //< Bad animation when an out of bound
|
||||
// animation is requested.
|
||||
bool adaptCollisionMaskAutomatically; ///< If set to true, the collision
|
||||
///< mask will be automatically
|
||||
///< adapted to the animation of the
|
||||
///< object.
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -30,7 +30,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
.AddObject<SpriteObject>("Sprite",
|
||||
_("Sprite"),
|
||||
_("Animated object which can be used for "
|
||||
"most elements of a game"),
|
||||
"most elements of a game."),
|
||||
"CppPlatform/Extensions/spriteicon.png")
|
||||
.SetCategoryFullName(_("General"))
|
||||
.AddDefaultBehavior("EffectCapability::EffectBehavior")
|
||||
@@ -408,6 +408,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
.SetHidden()
|
||||
.MarkAsSimple();
|
||||
|
||||
// Deprecated
|
||||
obj.AddCondition("ScaleWidth",
|
||||
_("Scale on X axis"),
|
||||
_("Compare the scale of the width of an object."),
|
||||
@@ -415,7 +416,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Size"),
|
||||
"res/conditions/scaleWidth24_black.png",
|
||||
"res/conditions/scaleWidth_black.png")
|
||||
|
||||
.SetHidden()
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number",
|
||||
@@ -423,6 +424,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Scale (1 by default)")))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
// Deprecated
|
||||
obj.AddCondition("ScaleHeight",
|
||||
_("Scale on Y axis"),
|
||||
_("Compare the scale of the height of an object."),
|
||||
@@ -430,7 +432,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Size"),
|
||||
"res/conditions/scaleHeight24_black.png",
|
||||
"res/conditions/scaleHeight_black.png")
|
||||
|
||||
.SetHidden()
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number",
|
||||
|
@@ -23,88 +23,20 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
Animation SpriteObject::badAnimation;
|
||||
|
||||
SpriteObject::SpriteObject()
|
||||
: updateIfNotVisible(false), adaptCollisionMaskAutomatically(true) {}
|
||||
: updateIfNotVisible(false) {}
|
||||
|
||||
SpriteObject::~SpriteObject(){};
|
||||
|
||||
void SpriteObject::DoUnserializeFrom(gd::Project& project,
|
||||
const gd::SerializerElement& element) {
|
||||
updateIfNotVisible = element.GetBoolAttribute("updateIfNotVisible", true);
|
||||
adaptCollisionMaskAutomatically =
|
||||
element.GetBoolAttribute("adaptCollisionMaskAutomatically", false);
|
||||
|
||||
RemoveAllAnimations();
|
||||
const gd::SerializerElement& animationsElement =
|
||||
element.GetChild("animations", 0, "Animations");
|
||||
animationsElement.ConsiderAsArrayOf("animation", "Animation");
|
||||
for (std::size_t i = 0; i < animationsElement.GetChildrenCount(); ++i) {
|
||||
const gd::SerializerElement& animationElement =
|
||||
animationsElement.GetChild(i);
|
||||
Animation newAnimation;
|
||||
|
||||
newAnimation.useMultipleDirections = animationElement.GetBoolAttribute(
|
||||
"useMultipleDirections", false, "typeNormal");
|
||||
newAnimation.SetName(animationElement.GetStringAttribute("name", ""));
|
||||
|
||||
// Compatibility with GD <= 3.3
|
||||
if (animationElement.HasChild("Direction")) {
|
||||
for (std::size_t j = 0;
|
||||
j < animationElement.GetChildrenCount("Direction");
|
||||
++j) {
|
||||
Direction direction;
|
||||
direction.UnserializeFrom(animationElement.GetChild("Direction", j));
|
||||
|
||||
newAnimation.SetDirectionsCount(newAnimation.GetDirectionsCount() + 1);
|
||||
newAnimation.SetDirection(direction,
|
||||
newAnimation.GetDirectionsCount() - 1);
|
||||
}
|
||||
}
|
||||
// End of compatibility code
|
||||
else {
|
||||
const gd::SerializerElement& directionsElement =
|
||||
animationElement.GetChild("directions");
|
||||
directionsElement.ConsiderAsArrayOf("direction");
|
||||
for (std::size_t j = 0; j < directionsElement.GetChildrenCount(); ++j) {
|
||||
Direction direction;
|
||||
direction.UnserializeFrom(directionsElement.GetChild(j));
|
||||
|
||||
newAnimation.SetDirectionsCount(newAnimation.GetDirectionsCount() + 1);
|
||||
newAnimation.SetDirection(direction,
|
||||
newAnimation.GetDirectionsCount() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
AddAnimation(newAnimation);
|
||||
}
|
||||
animations.UnserializeFrom(element);
|
||||
}
|
||||
|
||||
void SpriteObject::DoSerializeTo(gd::SerializerElement& element) const {
|
||||
element.SetAttribute("updateIfNotVisible", updateIfNotVisible);
|
||||
element.SetAttribute("adaptCollisionMaskAutomatically",
|
||||
adaptCollisionMaskAutomatically);
|
||||
|
||||
// Animations
|
||||
gd::SerializerElement& animationsElement = element.AddChild("animations");
|
||||
animationsElement.ConsiderAsArrayOf("animation");
|
||||
for (std::size_t k = 0; k < GetAnimationsCount(); k++) {
|
||||
gd::SerializerElement& animationElement =
|
||||
animationsElement.AddChild("animation");
|
||||
|
||||
animationElement.SetAttribute("useMultipleDirections",
|
||||
GetAnimation(k).useMultipleDirections);
|
||||
animationElement.SetAttribute("name", GetAnimation(k).GetName());
|
||||
|
||||
gd::SerializerElement& directionsElement =
|
||||
animationElement.AddChild("directions");
|
||||
directionsElement.ConsiderAsArrayOf("direction");
|
||||
for (std::size_t l = 0; l < GetAnimation(k).GetDirectionsCount(); l++) {
|
||||
GetAnimation(k).GetDirection(l).SerializeTo(
|
||||
directionsElement.AddChild("direction"));
|
||||
}
|
||||
}
|
||||
animations.SerializeTo(element);
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> SpriteObject::GetProperties()
|
||||
@@ -127,16 +59,7 @@ bool SpriteObject::UpdateProperty(const gd::String& name,
|
||||
}
|
||||
|
||||
void SpriteObject::ExposeResources(gd::ArbitraryResourceWorker& worker) {
|
||||
for (std::size_t j = 0; j < GetAnimationsCount(); j++) {
|
||||
for (std::size_t k = 0; k < GetAnimation(j).GetDirectionsCount(); k++) {
|
||||
for (std::size_t l = 0;
|
||||
l < GetAnimation(j).GetDirection(k).GetSpritesCount();
|
||||
l++) {
|
||||
worker.ExposeImage(
|
||||
GetAnimation(j).GetDirection(k).GetSprite(l).GetImageName());
|
||||
}
|
||||
}
|
||||
}
|
||||
animations.ExposeResources(worker);
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
@@ -168,42 +91,12 @@ bool SpriteObject::UpdateInitialInstanceProperty(
|
||||
return true;
|
||||
}
|
||||
|
||||
const Animation& SpriteObject::GetAnimation(std::size_t nb) const {
|
||||
if (nb >= animations.size()) return badAnimation;
|
||||
|
||||
return animations[nb];
|
||||
const SpriteAnimationList& SpriteObject::GetAnimations() const {
|
||||
return animations;
|
||||
}
|
||||
|
||||
Animation& SpriteObject::GetAnimation(std::size_t nb) {
|
||||
if (nb >= animations.size()) return badAnimation;
|
||||
|
||||
return animations[nb];
|
||||
}
|
||||
|
||||
void SpriteObject::AddAnimation(const Animation& animation) {
|
||||
animations.push_back(animation);
|
||||
}
|
||||
|
||||
bool SpriteObject::RemoveAnimation(std::size_t nb) {
|
||||
if (nb >= GetAnimationsCount()) return false;
|
||||
|
||||
animations.erase(animations.begin() + nb);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SpriteObject::SwapAnimations(std::size_t firstIndex,
|
||||
std::size_t secondIndex) {
|
||||
if (firstIndex < animations.size() && secondIndex < animations.size() &&
|
||||
firstIndex != secondIndex)
|
||||
std::swap(animations[firstIndex], animations[secondIndex]);
|
||||
}
|
||||
|
||||
void SpriteObject::MoveAnimation(std::size_t oldIndex, std::size_t newIndex) {
|
||||
if (oldIndex >= animations.size() || newIndex >= animations.size()) return;
|
||||
|
||||
auto animation = animations[oldIndex];
|
||||
animations.erase(animations.begin() + oldIndex);
|
||||
animations.insert(animations.begin() + newIndex, animation);
|
||||
SpriteAnimationList& SpriteObject::GetAnimations() {
|
||||
return animations;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -4,18 +4,15 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef GDCORE_SPRITEOBJECT_H
|
||||
#define GDCORE_SPRITEOBJECT_H
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Animation.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteAnimationList.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
|
||||
namespace gd {
|
||||
class InitialInstance;
|
||||
class Object;
|
||||
class Layout;
|
||||
class Sprite;
|
||||
class Animation;
|
||||
class SerializerElement;
|
||||
class PropertyDescriptor;
|
||||
} // namespace gd
|
||||
@@ -59,76 +56,15 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
|
||||
gd::Project& project,
|
||||
gd::Layout& scene) override;
|
||||
|
||||
/** \name Animations
|
||||
* Methods related to animations management
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Return the animation at the specified index.
|
||||
* If the index is out of bound, a "bad animation" object is returned.
|
||||
* \brief Return the animation configuration.
|
||||
*/
|
||||
const Animation& GetAnimation(std::size_t nb) const;
|
||||
const SpriteAnimationList& GetAnimations() const;
|
||||
|
||||
/**
|
||||
* \brief Return the animation at the specified index.
|
||||
* If the index is out of bound, a "bad animation" object is returned.
|
||||
* @brief Return the animation configuration.
|
||||
*/
|
||||
Animation& GetAnimation(std::size_t nb);
|
||||
|
||||
/**
|
||||
* \brief Return the number of animations this object has.
|
||||
*/
|
||||
std::size_t GetAnimationsCount() const { return animations.size(); };
|
||||
|
||||
/**
|
||||
* \brief Add an animation at the end of the existing ones.
|
||||
*/
|
||||
void AddAnimation(const Animation& animation);
|
||||
|
||||
/**
|
||||
* \brief Remove an animation.
|
||||
*/
|
||||
bool RemoveAnimation(std::size_t nb);
|
||||
|
||||
/**
|
||||
* \brief Remove all animations.
|
||||
*/
|
||||
void RemoveAllAnimations() { animations.clear(); }
|
||||
|
||||
/**
|
||||
* \brief Return true if the object hasn't any animation.
|
||||
*/
|
||||
bool HasNoAnimations() const { return animations.empty(); }
|
||||
|
||||
/**
|
||||
* \brief Swap the position of two animations
|
||||
*/
|
||||
void SwapAnimations(std::size_t firstIndex, std::size_t secondIndex);
|
||||
|
||||
/**
|
||||
* \brief Change the position of the specified animation
|
||||
*/
|
||||
void MoveAnimation(std::size_t oldIndex, std::size_t newIndex);
|
||||
|
||||
/**
|
||||
* \brief Return a read-only reference to the vector containing all the
|
||||
* animation of the object.
|
||||
*/
|
||||
const std::vector<Animation>& GetAllAnimations() const { return animations; }
|
||||
|
||||
/**
|
||||
* @brief Check if the collision mask adapts automatically to the animation.
|
||||
*/
|
||||
bool AdaptCollisionMaskAutomatically() const {
|
||||
return adaptCollisionMaskAutomatically;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set if the collision mask adapts automatically to the animation.
|
||||
*/
|
||||
void SetAdaptCollisionMaskAutomatically(bool enable) {
|
||||
adaptCollisionMaskAutomatically = enable;
|
||||
}
|
||||
SpriteAnimationList& GetAnimations();
|
||||
|
||||
/**
|
||||
* \brief Set if the object animation should be played even if the object is
|
||||
@@ -143,25 +79,17 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
|
||||
* is hidden or far from the camera (false by default).
|
||||
*/
|
||||
bool GetUpdateIfNotVisible() const { return updateIfNotVisible; }
|
||||
///@}
|
||||
|
||||
private:
|
||||
void DoUnserializeFrom(gd::Project& project,
|
||||
const gd::SerializerElement& element) override;
|
||||
void DoSerializeTo(gd::SerializerElement& element) const override;
|
||||
|
||||
mutable std::vector<Animation> animations;
|
||||
SpriteAnimationList animations;
|
||||
|
||||
bool updateIfNotVisible; ///< If set to true, ask the game engine to play
|
||||
///< object animation even if hidden or far from
|
||||
///< the screen.
|
||||
|
||||
static Animation badAnimation; //< Bad animation when an out of bound
|
||||
// animation is requested.
|
||||
bool adaptCollisionMaskAutomatically; ///< If set to true, the collision
|
||||
///< mask will be automatically
|
||||
///< adapted to the animation of the
|
||||
///< object.
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
#endif // GDCORE_SPRITEOBJECT_H
|
||||
|
@@ -25,29 +25,275 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Variables"))
|
||||
.SetIcon("res/conditions/var24.png");
|
||||
|
||||
extension
|
||||
.AddCondition("NumberVariable",
|
||||
_("Variable value"),
|
||||
_("Compare the number value of a variable."),
|
||||
_("The variable _PARAM0_"),
|
||||
"",
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions());
|
||||
|
||||
extension
|
||||
.AddCondition("StringVariable",
|
||||
_("Variable value"),
|
||||
_("Compare the text (string) of a variable."),
|
||||
_("The variable _PARAM0_"),
|
||||
"",
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", ParameterOptions::MakeNewOptions());
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"BooleanVariable",
|
||||
_("Variable value"),
|
||||
_("Compare the boolean value of a variable."),
|
||||
_("The variable _PARAM0_ is _PARAM1_"),
|
||||
"",
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("Check if the value is"))
|
||||
.SetDefaultValue("true")
|
||||
// This parameter allows to keep the operand expression
|
||||
// when the editor switch between variable instructions.
|
||||
.AddCodeOnlyParameter("trueorfalse", "");
|
||||
|
||||
extension
|
||||
.AddAction("SetNumberVariable",
|
||||
_("Change variable value"),
|
||||
_("Modify the number value of a variable."),
|
||||
_("the variable _PARAM0_"),
|
||||
"",
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.UseStandardOperatorParameters("number",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
|
||||
extension
|
||||
.AddAction("SetStringVariable",
|
||||
_("Change text variable"),
|
||||
_("Modify the text (string) of a variable."),
|
||||
_("the variable _PARAM0_"),
|
||||
"",
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.UseStandardOperatorParameters("string",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"SetBooleanVariable",
|
||||
_("Change boolean variable"),
|
||||
_("Modify the boolean value of a variable."),
|
||||
_("Change the variable _PARAM0_: _PARAM1_"),
|
||||
"",
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.AddParameter("operator", _("Value"), "boolean")
|
||||
// This parameter allows to keep the operand expression
|
||||
// when the editor switch between variable instructions.
|
||||
.AddCodeOnlyParameter("trueorfalse", "");
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"VariableChildCount",
|
||||
_("Number of children"),
|
||||
_("Compare the number of children in an array variable."),
|
||||
_("The number of children in the array variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("VariableChildExists2",
|
||||
_("Child existence"),
|
||||
_("Check if the specified child of the structure "
|
||||
"variable exists."),
|
||||
_("Child _PARAM1_ of variable _PARAM0_ exists"),
|
||||
_("Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.AddParameter("string", _("Name of the child"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"RemoveVariableChild",
|
||||
_("Remove a child"),
|
||||
_("Remove a child from a structure variable."),
|
||||
_("Remove child _PARAM1_ from structure variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Structure variable"))
|
||||
.AddParameter("string", _("Child's name"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("ClearVariableChildren",
|
||||
_("Clear children"),
|
||||
_("Remove all the children from the structure or array "
|
||||
"variable."),
|
||||
_("Clear children from variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Structure or array variable"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("PushVariable",
|
||||
_("Add existing variable"),
|
||||
_("Adds an existing variable at the end of an array "
|
||||
"variable."),
|
||||
_("Add variable _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.AddParameter("variable", _("Variable with the content to add"))
|
||||
.SetParameterLongDescription(
|
||||
_("The content of the variable will *be copied* and added at the "
|
||||
"end of the array."))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"PushString",
|
||||
_("Add text variable"),
|
||||
_("Adds a text (string) at the end of a array variable."),
|
||||
_("Add the value _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("PushNumber",
|
||||
_("Add variable array value"),
|
||||
_("Adds a number at the end of an array variable."),
|
||||
_("Add the value _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("PushBoolean",
|
||||
_("Add boolean variable"),
|
||||
_("Adds a boolean at the end of an array variable."),
|
||||
_("Add the value _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("RemoveVariableAt",
|
||||
_("Remove variable by index"),
|
||||
_("Removes a variable at the specified index of an array "
|
||||
"variable."),
|
||||
_("Remove variable at index _PARAM1_ from array "
|
||||
"variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.AddParameter("expression", _("Index to remove"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddStrExpression(
|
||||
"VariableFirstString",
|
||||
_("First text child"),
|
||||
_("Get the value of the first element of an array variable, if "
|
||||
"it is a text (string)."),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
"VariableFirstNumber",
|
||||
_("First number child"),
|
||||
_("Get the value of the first element of an array variable, if "
|
||||
"it is a number."),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
extension
|
||||
.AddStrExpression(
|
||||
"VariableLastString",
|
||||
_("Last text child"),
|
||||
_("Get the value of the last element of an array variable, if "
|
||||
"it is a text (string)."),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
"VariableLastNumber",
|
||||
_("Last number child"),
|
||||
_("Get the value of the last element of an array variable, if "
|
||||
"it is a number."),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
// Legacy instructions
|
||||
|
||||
extension
|
||||
.AddCondition("VarScene",
|
||||
_("Number variable"),
|
||||
_("Compare the number value of a scene variable."),
|
||||
_("The number of scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions());
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddCondition("VarSceneTxt",
|
||||
_("Text variable"),
|
||||
_("Compare the text (string) of a scene variable."),
|
||||
_("The text of scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", ParameterOptions::MakeNewOptions());
|
||||
"string", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
@@ -55,12 +301,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Boolean variable"),
|
||||
_("Compare the boolean value of a scene variable."),
|
||||
_("The boolean value of scene variable _PARAM0_ is _PARAM1_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("Check if the value is"))
|
||||
.SetDefaultValue("true");
|
||||
.SetDefaultValue("true")
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddCondition("VariableChildExists",
|
||||
@@ -68,11 +315,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Check if the specified child of the scene structure "
|
||||
"variable exists."),
|
||||
_("Child _PARAM1_ of scene variable _PARAM0_ exists"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddParameter("string", _("Name of the child"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -81,11 +329,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Check if the specified child of the global structure "
|
||||
"variable exists."),
|
||||
_("Child _PARAM1_ of global variable _PARAM0_ exists"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddParameter("string", _("Name of the child"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -93,7 +342,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
"Variable defined",
|
||||
"Test if the scene variable exists.",
|
||||
"Scene variable _PARAM0_ is defined",
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
@@ -105,12 +354,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Number variable"),
|
||||
_("Compare the number value of a global variable."),
|
||||
_("the global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -118,12 +368,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Text variable"),
|
||||
_("Compare the text (string) of a global variable."),
|
||||
_("the text of the global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -132,19 +383,20 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Boolean variable"),
|
||||
_("Compare the boolean value of a global variable."),
|
||||
_("The boolean value of global variable _PARAM0_ is _PARAM1_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("Check if the value is"))
|
||||
.SetDefaultValue("true");
|
||||
.SetDefaultValue("true")
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddCondition("VarGlobalDef",
|
||||
"Variable defined",
|
||||
"Test if a global variable exists.",
|
||||
"Global variable _PARAM0_ is defined",
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
@@ -157,24 +409,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Change number variable"),
|
||||
_("Modify the number value of a scene variable."),
|
||||
_("the scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.UseStandardOperatorParameters("number",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction("ModVarSceneTxt",
|
||||
_("Change text variable"),
|
||||
_("Modify the text (string) of a scene variable."),
|
||||
_("the text of scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.UseStandardOperatorParameters("string",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
@@ -182,11 +436,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Change boolean variable"),
|
||||
_("Modify the boolean value of a scene variable."),
|
||||
_("Set the boolean value of scene variable _PARAM0_ to _PARAM1_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("New Value:"));
|
||||
.AddParameter("trueorfalse", _("New Value:"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction("ToggleSceneVariableAsBoolean",
|
||||
@@ -195,22 +450,24 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("If it was true, it will become false, and if it was "
|
||||
"false it will become true."),
|
||||
_("Toggle the boolean value of scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"));
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction("ModVarGlobal",
|
||||
_("Change number variable"),
|
||||
_("Modify the number value of a global variable."),
|
||||
_("the global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("number",
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -218,12 +475,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Change text variable"),
|
||||
_("Modify the text (string) of a global variable."),
|
||||
_("the text of global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("string",
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -232,11 +490,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Change boolean variable"),
|
||||
_("Modify the boolean value of a global variable."),
|
||||
_("Set the boolean value of global variable _PARAM0_ to _PARAM1_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("New Value:"));
|
||||
.AddParameter("trueorfalse", _("New Value:"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction("ToggleGlobalVariableAsBoolean",
|
||||
@@ -245,10 +504,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("If it was true, it will become false, and if it was "
|
||||
"false it will become true."),
|
||||
_("Toggle the boolean value of global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"));
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
@@ -256,12 +516,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Remove a child"),
|
||||
_("Remove a child from a scene structure variable."),
|
||||
_("Remove child _PARAM1_ from scene structure variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Structure variable"))
|
||||
.AddParameter("string", _("Child's name"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
@@ -269,12 +530,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Remove a child"),
|
||||
_("Remove a child from a global structure variable."),
|
||||
_("Remove child _PARAM1_ from global structure variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Structure variable"))
|
||||
.AddParameter("string", _("Child's name"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction("VariableClearChildren",
|
||||
@@ -282,10 +544,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Remove all the children from the scene structure or array "
|
||||
"variable."),
|
||||
_("Clear children from scene variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Structure or array variable"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -294,10 +557,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Remove all the children from the global structure or array "
|
||||
"variable."),
|
||||
_("Clear children from global variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Structure or array variable"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -306,7 +570,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Adds an existing variable at the end of a scene array "
|
||||
"variable."),
|
||||
_("Add variable _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
@@ -314,6 +578,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
.SetParameterLongDescription(
|
||||
_("The content of the variable will *be copied* and added at the "
|
||||
"end of the array."))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -322,11 +587,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add text variable"),
|
||||
_("Adds a text (string) at the end of a scene array variable."),
|
||||
_("Add text _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -334,11 +600,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add number variable"),
|
||||
_("Adds a number at the end of a scene array variable."),
|
||||
_("Add number _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -346,11 +613,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add boolean variable"),
|
||||
_("Adds a boolean at the end of a scene array variable."),
|
||||
_("Add boolean _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -360,11 +628,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
"variable."),
|
||||
_("Remove variable at index _PARAM1_ from scene array "
|
||||
"variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("expression", _("Index to remove"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -373,12 +642,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Number of children"),
|
||||
_("Compare the number of children in a scene array variable."),
|
||||
_("The number of children in the array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -387,9 +657,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("First text child"),
|
||||
_("Get the value of the first element of a scene array variable, if "
|
||||
"it is a text (string)."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
@@ -397,9 +668,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("First number child"),
|
||||
_("Get the value of the first element of a scene array variable, if "
|
||||
"it is a number."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddStrExpression(
|
||||
@@ -407,9 +679,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Last text child"),
|
||||
_("Get the value of the last element of a scene array variable, if "
|
||||
"it is a text (string)."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
@@ -417,9 +690,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Last number child"),
|
||||
_("Get the value of the last element of a scene array variable, if "
|
||||
"it is a number."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
@@ -427,7 +701,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add existing variable"),
|
||||
_("Adds an existing variable at the end of a global array variable."),
|
||||
_("Add variable _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
@@ -435,6 +709,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
.SetParameterLongDescription(
|
||||
_("The content of the variable will *be copied* and added at the "
|
||||
"end of the array."))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -444,11 +719,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
"array variable."),
|
||||
_("Remove variable at index _PARAM1_ from global array "
|
||||
"variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Index to remove"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -457,11 +733,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add text variable"),
|
||||
_("Adds a text (string) at the end of a global array variable."),
|
||||
_("Add text _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -469,11 +746,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add number variable"),
|
||||
_("Adds a number at the end of a global array variable."),
|
||||
_("Add number _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -481,11 +759,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add boolean variable"),
|
||||
_("Adds a boolean at the end of a global array variable."),
|
||||
_("Add boolean _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -494,12 +773,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Number of children"),
|
||||
_("Compare the number of children in a global array variable."),
|
||||
_("The number of children of the array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -507,18 +787,20 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("First text child"),
|
||||
_("Value of the first element of a global array "
|
||||
"variable, if it is a text (string) variable."),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression("GlobalVariableFirstNumber",
|
||||
_("First number child"),
|
||||
_("Value of the first element of a global array "
|
||||
"variable, if it is a number variable"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddStrExpression(
|
||||
@@ -526,9 +808,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Last text child"),
|
||||
_("Value of the last element of a global array variable, if "
|
||||
"it is a text (string) variable."),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
@@ -536,59 +819,65 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Last number child"),
|
||||
_("Value of the last element of a global array variable, if "
|
||||
"it is a number variable"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression("GlobalVariableChildCount",
|
||||
_("Number of children"),
|
||||
_("Number of children in a global array or "
|
||||
"structure variable"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array or structure variable"));
|
||||
.AddParameter("globalvar", _("Array or structure variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression("VariableChildCount",
|
||||
_("Number of children"),
|
||||
_("Number of children in a scene array or "
|
||||
"structure variable"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array or structure variable"));
|
||||
.AddParameter("variable", _("Array or structure variable"), "AllowUndeclaredVariable");
|
||||
|
||||
extension
|
||||
.AddExpression("Variable",
|
||||
_("Number variable"),
|
||||
_("Number value of a scene variable"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"));
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddStrExpression("VariableString",
|
||||
_("Text variable"),
|
||||
_("Text of a scene variable"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"));
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression("GlobalVariable",
|
||||
_("Number variable"),
|
||||
_("Number value of a global variable"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Name of the global variable"));
|
||||
.AddParameter("globalvar", _("Name of the global variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddStrExpression("GlobalVariableString",
|
||||
_("Text variable"),
|
||||
_("Text of a global variable"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"));
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -87,8 +87,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
|
||||
extension
|
||||
.AddAction(
|
||||
"SetWindowSize",
|
||||
_("Change the size of the game window"),
|
||||
_("This action changes the size of the game window. Note that this "
|
||||
_("Game window size"),
|
||||
_("Changes the size of the game window. Note that this "
|
||||
"will only work on platform supporting this operation: games "
|
||||
"running in browsers or on mobile phones can not update their "
|
||||
"window size. Game resolution can still be updated."),
|
||||
|
@@ -114,6 +114,8 @@ public:
|
||||
|
||||
/**
|
||||
* \brief Erase any existing include file and add the specified include.
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
virtual AbstractFunctionMetadata &
|
||||
SetIncludeFile(const gd::String &includeFile) = 0;
|
||||
|
@@ -13,12 +13,15 @@
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/BehaviorsSharedData.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCore/Tools/MakeUnique.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
const std::map<gd::String, gd::PropertyDescriptor> BehaviorMetadata::badProperties;
|
||||
|
||||
BehaviorMetadata::BehaviorMetadata(
|
||||
const gd::String& extensionNamespace_,
|
||||
const gd::String& nameWithNamespace,
|
||||
@@ -47,8 +50,14 @@ BehaviorMetadata::BehaviorMetadata(
|
||||
"BehaviorMetadata is valid for: " + nameWithNamespace);
|
||||
}
|
||||
|
||||
if (instance) instance->SetTypeName(nameWithNamespace);
|
||||
if (sharedDatasInstance) sharedDatasInstance->SetTypeName(nameWithNamespace);
|
||||
if (instance) {
|
||||
instance->SetTypeName(nameWithNamespace);
|
||||
instance->InitializeContent();
|
||||
}
|
||||
if (sharedDatasInstance) {
|
||||
sharedDatasInstance->SetTypeName(nameWithNamespace);
|
||||
sharedDatasInstance->InitializeContent();
|
||||
}
|
||||
}
|
||||
|
||||
gd::InstructionMetadata& BehaviorMetadata::AddCondition(
|
||||
@@ -405,10 +414,30 @@ gd::Behavior& BehaviorMetadata::Get() const {
|
||||
return *instance;
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> BehaviorMetadata::GetProperties() const {
|
||||
if (!instance) {
|
||||
return badProperties;
|
||||
}
|
||||
// TODO Properties should be declared on BehaviorMetadata directly.
|
||||
// - Add 2 `properties` members (one for shared properties)
|
||||
// - Add methods to declare new properties
|
||||
return instance->GetProperties();
|
||||
}
|
||||
|
||||
gd::BehaviorsSharedData* BehaviorMetadata::GetSharedDataInstance() const {
|
||||
return sharedDatasInstance.get();
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> BehaviorMetadata::GetSharedProperties() const {
|
||||
if (!sharedDatasInstance) {
|
||||
return badProperties;
|
||||
}
|
||||
// TODO Properties should be declared on BehaviorMetadata directly.
|
||||
// - Add 2 `properties` members (one for shared properties)
|
||||
// - Add methods to declare new properties
|
||||
return sharedDatasInstance->GetProperties();
|
||||
}
|
||||
|
||||
const std::vector<gd::String>& BehaviorMetadata::GetRequiredBehaviorTypes() const {
|
||||
requiredBehaviors.clear();
|
||||
for (auto& property : Get().GetProperties()) {
|
||||
|
@@ -18,6 +18,7 @@ class BehaviorsSharedData;
|
||||
class MultipleInstructionMetadata;
|
||||
class InstructionMetadata;
|
||||
class ExpressionMetadata;
|
||||
class PropertyDescriptor;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -204,6 +205,8 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
|
||||
* \brief Erase any existing include file and add the specified include.
|
||||
* \note The requirement may vary depending on the platform: Most of the time,
|
||||
* the include file contains the declaration of the behavior.
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
BehaviorMetadata& SetIncludeFile(const gd::String& includeFile) override;
|
||||
|
||||
@@ -302,6 +305,15 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
|
||||
*/
|
||||
gd::Behavior& Get() const;
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to know about the custom properties of the
|
||||
* behavior.
|
||||
*
|
||||
* \return a std::map with properties names as key.
|
||||
* \see gd::PropertyDescriptor
|
||||
*/
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
|
||||
|
||||
/**
|
||||
* \brief Return the associated gd::BehaviorsSharedData, handling behavior
|
||||
* shared data, if any (nullptr if none).
|
||||
@@ -311,6 +323,15 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
|
||||
*/
|
||||
gd::BehaviorsSharedData* GetSharedDataInstance() const;
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to know about the custom shared properties
|
||||
* of the behavior.
|
||||
*
|
||||
* \return a std::map with properties names as key.
|
||||
* \see gd::PropertyDescriptor
|
||||
*/
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetSharedProperties() const;
|
||||
|
||||
/**
|
||||
* \brief Return a reference to a map containing the names of the actions
|
||||
* (as keys) and the metadata associated with (as values).
|
||||
@@ -357,6 +378,8 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
|
||||
// TODO: Nitpicking: convert these to std::unique_ptr to clarify ownership.
|
||||
std::shared_ptr<gd::Behavior> instance;
|
||||
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance;
|
||||
|
||||
static const std::map<gd::String, gd::PropertyDescriptor> badProperties;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -65,6 +65,8 @@ class GD_CORE_API EffectMetadata {
|
||||
|
||||
/**
|
||||
* \brief Clear any existing include file and add the specified include file.
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
EffectMetadata& SetIncludeFile(const gd::String& includeFile);
|
||||
|
||||
|
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
#include "ExpressionMetadata.h"
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
@@ -46,16 +47,14 @@ gd::ExpressionMetadata& ExpressionMetadata::AddParameter(
|
||||
// For objects/behavior, the supplementary information
|
||||
// parameter is an object/behavior type...
|
||||
((gd::ParameterMetadata::IsObject(type) ||
|
||||
gd::ParameterMetadata::IsBehavior(type))
|
||||
// Prefix with the namespace if it's not already there.
|
||||
&& !(supplementaryInformation.rfind(extensionNamespace, 0) == 0))
|
||||
? (supplementaryInformation.empty()
|
||||
? ""
|
||||
: extensionNamespace +
|
||||
supplementaryInformation //... so prefix it with the extension
|
||||
// namespace.
|
||||
)
|
||||
: supplementaryInformation); // Otherwise don't change anything
|
||||
gd::ParameterMetadata::IsBehavior(type))
|
||||
// Prefix with the namespace if it's not already there.
|
||||
&& (supplementaryInformation.find(
|
||||
PlatformExtension::GetNamespaceSeparator()) == gd::String::npos)
|
||||
? (supplementaryInformation.empty()
|
||||
? ""
|
||||
: extensionNamespace + supplementaryInformation)
|
||||
: supplementaryInformation));
|
||||
|
||||
// TODO: Assert against supplementaryInformation === "emsc" (when running with
|
||||
// Emscripten), and warn about a missing argument when calling addParameter.
|
||||
|
@@ -288,6 +288,8 @@ class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
|
||||
|
||||
/**
|
||||
* \brief Erase any existing include file and add the specified include.
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
ExpressionMetadata& SetIncludeFile(
|
||||
const gd::String& includeFile) override {
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
@@ -64,17 +65,14 @@ InstructionMetadata& InstructionMetadata::AddParameter(
|
||||
// For objects/behavior, the supplementary information
|
||||
// parameter is an object/behavior type...
|
||||
((gd::ParameterMetadata::IsObject(type) ||
|
||||
gd::ParameterMetadata::IsBehavior(type))
|
||||
// Prefix with the namespace if it's not already there.
|
||||
&& !(supplementaryInformation.rfind(extensionNamespace, 0) == 0))
|
||||
? (supplementaryInformation.empty()
|
||||
? ""
|
||||
: extensionNamespace +
|
||||
supplementaryInformation //... so prefix it with the
|
||||
// extension
|
||||
// namespace.
|
||||
)
|
||||
: supplementaryInformation); // Otherwise don't change anything
|
||||
gd::ParameterMetadata::IsBehavior(type))
|
||||
// Prefix with the namespace if it's not already there.
|
||||
&& (supplementaryInformation.find(
|
||||
PlatformExtension::GetNamespaceSeparator()) == gd::String::npos)
|
||||
? (supplementaryInformation.empty()
|
||||
? ""
|
||||
: extensionNamespace + supplementaryInformation)
|
||||
: supplementaryInformation));
|
||||
|
||||
// TODO: Assert against supplementaryInformation === "emsc" (when running with
|
||||
// Emscripten), and warn about a missing argument when calling addParameter.
|
||||
@@ -190,7 +188,7 @@ InstructionMetadata::UseStandardRelationalOperatorParameters(
|
||||
gd::String templateSentence = _("<subject> of _PARAM0_ <operator> <value>");
|
||||
|
||||
sentence =
|
||||
templateSentence.FindAndReplace("<subject>", sentence)
|
||||
templateSentence.FindAndReplace("<subject>", sentence.CapitalizeFirstLetter())
|
||||
.FindAndReplace(
|
||||
"<operator>",
|
||||
"_PARAM" + gd::String::From(operatorParamIndex) + "_")
|
||||
@@ -200,7 +198,7 @@ InstructionMetadata::UseStandardRelationalOperatorParameters(
|
||||
gd::String templateSentence = _("<subject> <operator> <value>");
|
||||
|
||||
sentence =
|
||||
templateSentence.FindAndReplace("<subject>", sentence)
|
||||
templateSentence.FindAndReplace("<subject>", sentence.CapitalizeFirstLetter())
|
||||
.FindAndReplace(
|
||||
"<operator>",
|
||||
"_PARAM" + gd::String::From(operatorParamIndex) + "_")
|
||||
|
@@ -456,6 +456,15 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the type manipulated in a standard way by the instruction.
|
||||
*
|
||||
* \param type "number" or "string"
|
||||
*/
|
||||
const gd::String &GetManipulatedType() const {
|
||||
return codeExtraInformation.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* If InstructionMetadata::ExtraInformation::SetManipulatedType was called
|
||||
* with "number" or "string", this function will tell the code generator the
|
||||
@@ -494,6 +503,8 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
|
||||
|
||||
/**
|
||||
* \brief Erase any existing include file and add the specified include.
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
InstructionMetadata &SetIncludeFile(const gd::String &includeFile) override {
|
||||
codeExtraInformation.includeFiles.clear();
|
||||
|
@@ -142,6 +142,8 @@ public:
|
||||
* \brief Erase any existing include file and add the specified include.
|
||||
* \note The requirement may vary depending on the platform: Most of the time,
|
||||
* the include file contains the declaration of the behavior.
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
virtual InstructionOrExpressionContainerMetadata &
|
||||
SetIncludeFile(const gd::String &includeFile) = 0;
|
||||
|
@@ -150,6 +150,10 @@ class GD_CORE_API MultipleInstructionMetadata : public AbstractFunctionMetadata
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
MultipleInstructionMetadata &SetIncludeFile(const gd::String &includeFile) override {
|
||||
if (expression)
|
||||
expression->SetIncludeFile(includeFile);
|
||||
@@ -191,6 +195,16 @@ class GD_CORE_API MultipleInstructionMetadata : public AbstractFunctionMetadata
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \see gd::InstructionMetadata::SetHelpPath
|
||||
*/
|
||||
MultipleInstructionMetadata &SetHelpPath(const gd::String &path) {
|
||||
if (expression) expression->SetHelpPath(path);
|
||||
if (condition) condition->SetHelpPath(path);
|
||||
if (action) action->SetHelpPath(path);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \see gd::InstructionMetadata::MarkAsSimple
|
||||
*/
|
||||
|
@@ -264,6 +264,8 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
|
||||
* \brief Erase any existing include file and add the specified include.
|
||||
* \note The requirement may vary depending on the platform: Most of the time,
|
||||
* the include file contains the declaration of the object.
|
||||
* \deprecated Use `AddIncludeFile` instead as clearing the list is more
|
||||
* error prone.
|
||||
*/
|
||||
ObjectMetadata& SetIncludeFile(const gd::String& includeFile) override;
|
||||
|
||||
@@ -303,12 +305,24 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return true if the instruction must be hidden in the IDE.
|
||||
* \brief Return true if the object must be hidden in the IDE.
|
||||
*/
|
||||
bool IsHidden() const { return hidden; }
|
||||
|
||||
/**
|
||||
* \brief Declare a usage of the 3D renderer.
|
||||
*/
|
||||
ObjectMetadata &MarkAsRenderedIn3D() {
|
||||
isRenderedIn3D = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the object uses the 3D renderer.
|
||||
*/
|
||||
bool IsRenderedIn3D() const { return isRenderedIn3D; }
|
||||
|
||||
std::map<gd::String, gd::InstructionMetadata> conditionsInfos;
|
||||
std::map<gd::String, gd::InstructionMetadata> actionsInfos;
|
||||
std::map<gd::String, gd::ExpressionMetadata> expressionsInfos;
|
||||
@@ -329,6 +343,7 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
|
||||
gd::String categoryFullName;
|
||||
std::set<gd::String> defaultBehaviorTypes;
|
||||
bool hidden = false;
|
||||
bool isRenderedIn3D = false;
|
||||
|
||||
std::shared_ptr<gd::ObjectConfiguration>
|
||||
blueprintObject; ///< The "blueprint" object to be copied when a new
|
||||
|
@@ -217,7 +217,9 @@ class GD_CORE_API ValueTypeMetadata {
|
||||
parameterType == "jsonResource" ||
|
||||
parameterType == "tilemapResource" ||
|
||||
parameterType == "tilesetResource" ||
|
||||
parameterType == "model3DResource";
|
||||
parameterType == "model3DResource" ||
|
||||
parameterType == "atlasResource" ||
|
||||
parameterType == "spineResource";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@@ -264,8 +264,11 @@ class GD_CORE_API PlatformExtension {
|
||||
*
|
||||
* \param name The name of the behavior
|
||||
* \param fullname The user friendly name of the behavior
|
||||
* \param defaultName The default name of behavior instances
|
||||
* \param description The user friendly description of the behavior
|
||||
* \param group The behavior category label
|
||||
* \param icon The icon of the behavior.
|
||||
* \param className The name of the class implementing the behavior
|
||||
* \param instance An instance of the behavior that
|
||||
* will be used to create the behavior
|
||||
* \param sharedDatasInstance Optional
|
||||
@@ -282,21 +285,6 @@ class GD_CORE_API PlatformExtension {
|
||||
std::shared_ptr<gd::Behavior> instance,
|
||||
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance);
|
||||
|
||||
/**
|
||||
* \brief Declare a new events based behavior as being part of the extension.
|
||||
*
|
||||
* \param name The name of the behavior
|
||||
* \param fullname The user friendly name of the behavior
|
||||
* \param description The user friendly description of the behavior
|
||||
* \param icon The icon of the behavior.
|
||||
*/
|
||||
gd::BehaviorMetadata& AddEventsBasedBehavior(
|
||||
const gd::String& name_,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& group_,
|
||||
const gd::String& icon_);
|
||||
|
||||
/**
|
||||
* \brief Declare a new effect as being part of the extension.
|
||||
* \param name The internal name of the effect (also called effect type).
|
||||
|
@@ -4,7 +4,6 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include "DependenciesAnalyzer.h"
|
||||
#include <algorithm>
|
||||
#include "GDCore/Events/Builtin/LinkEvent.h"
|
||||
@@ -29,9 +28,9 @@ DependenciesAnalyzer::DependenciesAnalyzer(const gd::Project& project_,
|
||||
|
||||
bool DependenciesAnalyzer::Analyze() {
|
||||
if (layout)
|
||||
return Analyze(layout->GetEvents(), true);
|
||||
return Analyze(layout->GetEvents());
|
||||
else if (externalEvents)
|
||||
return Analyze(externalEvents->GetEvents(), true);
|
||||
return Analyze(externalEvents->GetEvents());
|
||||
|
||||
std::cout << "ERROR: DependenciesAnalyzer called without any layout or "
|
||||
"external events.";
|
||||
@@ -40,63 +39,38 @@ bool DependenciesAnalyzer::Analyze() {
|
||||
|
||||
DependenciesAnalyzer::~DependenciesAnalyzer() {}
|
||||
|
||||
bool DependenciesAnalyzer::Analyze(const gd::EventsList& events, bool isOnTopLevel) {
|
||||
bool DependenciesAnalyzer::Analyze(const gd::EventsList& events) {
|
||||
for (unsigned int i = 0; i < events.size(); ++i) {
|
||||
const gd::LinkEvent* linkEvent = dynamic_cast<const gd::LinkEvent*>(&events[i]);
|
||||
if (linkEvent) {
|
||||
DependenciesAnalyzer analyzer(*this);
|
||||
|
||||
gd::String linked = linkEvent->GetTarget();
|
||||
if (project.HasExternalEventsNamed(linked)) {
|
||||
if (std::find(parentExternalEvents.begin(),
|
||||
parentExternalEvents.end(),
|
||||
linked) != parentExternalEvents.end())
|
||||
return false; // Circular dependency!
|
||||
|
||||
externalEventsDependencies.insert(
|
||||
linked); // There is a direct dependency
|
||||
if (!isOnTopLevel) notTopLevelExternalEventsDependencies.insert(linked);
|
||||
analyzer.AddParentExternalEvents(linked);
|
||||
if (!analyzer.Analyze(project.GetExternalEvents(linked).GetEvents(),
|
||||
isOnTopLevel))
|
||||
linked) != parentExternalEvents.end()) {
|
||||
// Circular dependency!
|
||||
return false;
|
||||
|
||||
}
|
||||
bool wasDependencyJustAdded = externalEventsDependencies.insert(linked).second;
|
||||
if (wasDependencyJustAdded) {
|
||||
parentExternalEvents.push_back(linked);
|
||||
if (!Analyze(project.GetExternalEvents(linked).GetEvents()))
|
||||
return false;
|
||||
parentExternalEvents.pop_back();
|
||||
}
|
||||
} else if (project.HasLayoutNamed(linked)) {
|
||||
if (std::find(parentScenes.begin(), parentScenes.end(), linked) !=
|
||||
parentScenes.end())
|
||||
return false; // Circular dependency!
|
||||
|
||||
scenesDependencies.insert(linked); // There is a direct dependency
|
||||
if (!isOnTopLevel) notTopLevelScenesDependencies.insert(linked);
|
||||
analyzer.AddParentScene(linked);
|
||||
if (!analyzer.Analyze(project.GetLayout(linked).GetEvents(),
|
||||
isOnTopLevel))
|
||||
parentScenes.end()) {
|
||||
// Circular dependency!
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update with indirect dependencies.
|
||||
scenesDependencies.insert(analyzer.GetScenesDependencies().begin(),
|
||||
analyzer.GetScenesDependencies().end());
|
||||
externalEventsDependencies.insert(
|
||||
analyzer.GetExternalEventsDependencies().begin(),
|
||||
analyzer.GetExternalEventsDependencies().end());
|
||||
sourceFilesDependencies.insert(
|
||||
analyzer.GetSourceFilesDependencies().begin(),
|
||||
analyzer.GetSourceFilesDependencies().end());
|
||||
notTopLevelScenesDependencies.insert(
|
||||
analyzer.GetNotTopLevelScenesDependencies().begin(),
|
||||
analyzer.GetNotTopLevelScenesDependencies().end());
|
||||
notTopLevelExternalEventsDependencies.insert(
|
||||
analyzer.GetNotTopLevelExternalEventsDependencies().begin(),
|
||||
analyzer.GetNotTopLevelExternalEventsDependencies().end());
|
||||
|
||||
if (!isOnTopLevel) {
|
||||
notTopLevelScenesDependencies.insert(
|
||||
analyzer.GetScenesDependencies().begin(),
|
||||
analyzer.GetScenesDependencies().end());
|
||||
notTopLevelExternalEventsDependencies.insert(
|
||||
analyzer.GetExternalEventsDependencies().begin(),
|
||||
analyzer.GetExternalEventsDependencies().end());
|
||||
}
|
||||
bool wasDependencyJustAdded = scenesDependencies.insert(linked).second;
|
||||
if (wasDependencyJustAdded) {
|
||||
parentScenes.push_back(linked);
|
||||
if (!Analyze(project.GetLayout(linked).GetEvents()))
|
||||
return false;
|
||||
parentScenes.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,45 +86,9 @@ bool DependenciesAnalyzer::Analyze(const gd::EventsList& events, bool isOnTopLev
|
||||
|
||||
// Analyze sub events dependencies
|
||||
if (events[i].CanHaveSubEvents()) {
|
||||
if (!Analyze(events[i].GetSubEvents(), false)) return false;
|
||||
if (!Analyze(events[i].GetSubEvents())) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
gd::String DependenciesAnalyzer::ExternalEventsCanBeCompiledForAScene() {
|
||||
if (!externalEvents) {
|
||||
std::cout << "ERROR: ExternalEventsCanBeCompiledForAScene called without "
|
||||
"external events set!"
|
||||
<< std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
gd::String sceneName;
|
||||
for (unsigned int i = 0; i < project.GetLayoutsCount(); ++i) {
|
||||
// For each layout, compute the dependencies and the dependencies which are
|
||||
// not coming from a top level event.
|
||||
DependenciesAnalyzer analyzer(project, project.GetLayout(i));
|
||||
if (!analyzer.Analyze()) continue; // Analyze failed -> Cyclic dependencies
|
||||
const std::set<gd::String>& dependencies =
|
||||
analyzer.GetExternalEventsDependencies();
|
||||
const std::set<gd::String>& notTopLevelDependencies =
|
||||
analyzer.GetNotTopLevelExternalEventsDependencies();
|
||||
|
||||
// Check if the external events is a dependency, and that is is only present
|
||||
// as a link on the top level.
|
||||
if (dependencies.find(externalEvents->GetName()) != dependencies.end() &&
|
||||
notTopLevelDependencies.find(externalEvents->GetName()) ==
|
||||
notTopLevelDependencies.end()) {
|
||||
if (!sceneName.empty())
|
||||
return ""; // External events can be compiled only if one scene is
|
||||
// including them.
|
||||
else
|
||||
sceneName = project.GetLayout(i).GetName();
|
||||
}
|
||||
}
|
||||
|
||||
return sceneName; // External events can be compiled and used for the scene.
|
||||
}
|
||||
#endif
|
||||
|
@@ -39,11 +39,6 @@ class GD_CORE_API DependenciesAnalyzer {
|
||||
|
||||
/**
|
||||
* \brief Constructor for analyzing the dependencies of external events.
|
||||
*
|
||||
* You can also call then
|
||||
* DependenciesAnalyzer::ExternalEventsCanBeCompiledForAScene to check if the
|
||||
* external events can be compiled separately and called by a scene. \see
|
||||
* DependenciesAnalyzer::ExternalEventsCanBeCompiledForAScene
|
||||
*/
|
||||
DependenciesAnalyzer(const gd::Project& project_,
|
||||
const gd::ExternalEvents& externalEvents);
|
||||
@@ -60,18 +55,6 @@ class GD_CORE_API DependenciesAnalyzer {
|
||||
*/
|
||||
bool Analyze();
|
||||
|
||||
/**
|
||||
* Check if the external events (passed in the constructor) can be compiled
|
||||
* and called by a single scene:<br> This is possible when the link calling
|
||||
* the external events does not have any parent event and when this situation
|
||||
* occurs only in a single scene and not in another.
|
||||
*
|
||||
* \return The name of the scene which is able to call the compiled external
|
||||
* events. If empty, no scene is able to call them. (So external events have
|
||||
* to be included directly by links).
|
||||
*/
|
||||
gd::String ExternalEventsCanBeCompiledForAScene();
|
||||
|
||||
/**
|
||||
* \brief Return the scenes being dependencies of the scene or external events
|
||||
* passed in the constructor.
|
||||
@@ -96,25 +79,6 @@ class GD_CORE_API DependenciesAnalyzer {
|
||||
return sourceFilesDependencies;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Return the scenes being dependencies of the scene or external events
|
||||
* passed in the constructor, but being not top level dependencies: The links
|
||||
* including them are not a top level events (i.e: They have a parent event).
|
||||
*/
|
||||
const std::set<gd::String>& GetNotTopLevelScenesDependencies() const {
|
||||
return notTopLevelScenesDependencies;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Return the external events being dependencies of the scene or
|
||||
* external events passed in the constructor, but being not top level
|
||||
* dependencies: The links including them are not a top level events (i.e:
|
||||
* They have a parent event).
|
||||
*/
|
||||
const std::set<gd::String>& GetNotTopLevelExternalEventsDependencies() const {
|
||||
return notTopLevelExternalEventsDependencies;
|
||||
};
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief Analyze the dependencies of the events.
|
||||
@@ -124,32 +88,11 @@ class GD_CORE_API DependenciesAnalyzer {
|
||||
* (they have no parents). \return false if a circular dependency exists, true
|
||||
* otherwise.
|
||||
*/
|
||||
bool Analyze(const gd::EventsList& events, bool isOnTopLevel);
|
||||
|
||||
void AddParentScene(gd::String parentScene) {
|
||||
parentScenes.push_back(parentScene);
|
||||
};
|
||||
void AddParentExternalEvents(gd::String parentExternalEvents_) {
|
||||
parentExternalEvents.push_back(parentExternalEvents_);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return true if all links pointing to external events called \a
|
||||
* externalEventsName are only at the top level of \a events. The function
|
||||
* return false as soon as it discover a link to external events which is not
|
||||
* at the top level ( i.e: It has a parent event ).
|
||||
*
|
||||
* \warning The function assumes that there are not cyclic dependencies.
|
||||
*/
|
||||
bool CheckIfExternalEventsIsLinkedOnlyAtTopLevel(
|
||||
const gd::String& externalEventsName,
|
||||
std::vector<std::shared_ptr<gd::BaseEvent> >& events);
|
||||
bool Analyze(const gd::EventsList& events);
|
||||
|
||||
std::set<gd::String> scenesDependencies;
|
||||
std::set<gd::String> externalEventsDependencies;
|
||||
std::set<gd::String> sourceFilesDependencies;
|
||||
std::set<gd::String> notTopLevelScenesDependencies;
|
||||
std::set<gd::String> notTopLevelExternalEventsDependencies;
|
||||
std::vector<gd::String>
|
||||
parentScenes; ///< Used to check for circular dependencies.
|
||||
std::vector<gd::String>
|
||||
|
@@ -26,7 +26,7 @@ void EventBasedBehaviorBrowser::ExposeEvents(
|
||||
void EventBasedBehaviorBrowser::ExposeEvents(
|
||||
gd::Project &project, gd::ArbitraryEventsWorkerWithContext &worker) const {
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
project, eventsBasedBehavior, worker);
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior, worker);
|
||||
}
|
||||
|
||||
void EventBasedBehaviorBrowser::ExposeObjects(
|
||||
|
@@ -29,8 +29,11 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API EventBasedBehaviorBrowser : public ProjectBrowser {
|
||||
public:
|
||||
EventBasedBehaviorBrowser(gd::EventsBasedBehavior &eventsBasedBehavior_)
|
||||
: eventsBasedBehavior(eventsBasedBehavior_) {}
|
||||
EventBasedBehaviorBrowser(
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension_,
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior_)
|
||||
: eventsFunctionsExtension(eventsFunctionsExtension_),
|
||||
eventsBasedBehavior(eventsBasedBehavior_) {}
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all events of the event-based
|
||||
@@ -48,7 +51,7 @@ public:
|
||||
* This should be the preferred way to traverse all the events of an event-based behavior.
|
||||
*/
|
||||
void
|
||||
ExposeEvents(gd::Project &project,
|
||||
ExposeEvents(gd::Project &project,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) const override;
|
||||
|
||||
/**
|
||||
@@ -80,6 +83,7 @@ public:
|
||||
gd::ArbitraryBehaviorSharedDataWorker &worker) const override;
|
||||
|
||||
private:
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension;
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior;
|
||||
};
|
||||
|
||||
|
@@ -19,9 +19,9 @@ using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
ArbitraryEventsWorker::~ArbitraryEventsWorker() {}
|
||||
AbstractArbitraryEventsWorker::~AbstractArbitraryEventsWorker() {}
|
||||
|
||||
void ArbitraryEventsWorker::VisitEventList(gd::EventsList& events) {
|
||||
void AbstractArbitraryEventsWorker::VisitEventList(gd::EventsList& events) {
|
||||
DoVisitEventList(events);
|
||||
|
||||
for (std::size_t i = 0; i < events.size();) {
|
||||
@@ -36,7 +36,7 @@ void ArbitraryEventsWorker::VisitEventList(gd::EventsList& events) {
|
||||
}
|
||||
}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
|
||||
bool AbstractArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
|
||||
bool shouldDelete = DoVisitEvent(event);
|
||||
if (shouldDelete) return true;
|
||||
|
||||
@@ -55,15 +55,14 @@ bool ArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
|
||||
*expressionAndMetadata.first, expressionAndMetadata.second);
|
||||
}
|
||||
|
||||
|
||||
return shouldDelete;
|
||||
}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitLinkEvent(gd::LinkEvent& linkEvent) {
|
||||
bool AbstractArbitraryEventsWorker::VisitLinkEvent(gd::LinkEvent& linkEvent) {
|
||||
return DoVisitLinkEvent(linkEvent);
|
||||
}
|
||||
|
||||
void ArbitraryEventsWorker::VisitInstructionList(
|
||||
void AbstractArbitraryEventsWorker::VisitInstructionList(
|
||||
gd::InstructionsList& instructions, bool areConditions) {
|
||||
DoVisitInstructionList(instructions, areConditions);
|
||||
|
||||
@@ -79,22 +78,19 @@ void ArbitraryEventsWorker::VisitInstructionList(
|
||||
}
|
||||
}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitInstruction(gd::Instruction& instruction,
|
||||
bool AbstractArbitraryEventsWorker::VisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
return DoVisitInstruction(instruction, isCondition);
|
||||
}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitEventExpression(gd::Expression& expression,
|
||||
bool AbstractArbitraryEventsWorker::VisitEventExpression(gd::Expression& expression,
|
||||
const gd::ParameterMetadata& metadata) {
|
||||
return DoVisitEventExpression(expression, metadata);
|
||||
}
|
||||
|
||||
ArbitraryEventsWorkerWithContext::~ArbitraryEventsWorkerWithContext() {}
|
||||
AbstractReadOnlyArbitraryEventsWorker::~AbstractReadOnlyArbitraryEventsWorker() {}
|
||||
|
||||
|
||||
ReadOnlyArbitraryEventsWorker::~ReadOnlyArbitraryEventsWorker() {}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events) {
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events) {
|
||||
DoVisitEventList(events);
|
||||
|
||||
for (std::size_t i = 0; i < events.size(); ++i) {
|
||||
@@ -109,7 +105,7 @@ void ReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events)
|
||||
}
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
|
||||
DoVisitEvent(event);
|
||||
|
||||
const vector<const gd::InstructionsList*> conditionsVectors =
|
||||
@@ -130,11 +126,11 @@ void ReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
|
||||
}
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitLinkEvent(const gd::LinkEvent& linkEvent) {
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitLinkEvent(const gd::LinkEvent& linkEvent) {
|
||||
DoVisitLinkEvent(linkEvent);
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitInstructionList(
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitInstructionList(
|
||||
const gd::InstructionsList& instructions, bool areConditions) {
|
||||
DoVisitInstructionList(instructions, areConditions);
|
||||
|
||||
@@ -150,21 +146,73 @@ void ReadOnlyArbitraryEventsWorker::VisitInstructionList(
|
||||
}
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitInstruction(const gd::Instruction& instruction,
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitInstruction(const gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
DoVisitInstruction(instruction, isCondition);
|
||||
}
|
||||
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitEventExpression(const gd::Expression& expression,
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitEventExpression(const gd::Expression& expression,
|
||||
const gd::ParameterMetadata& metadata) {
|
||||
DoVisitEventExpression(expression, metadata);
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::StopAnyEventIteration() {
|
||||
void AbstractReadOnlyArbitraryEventsWorker::StopAnyEventIteration() {
|
||||
shouldStopIteration = true;
|
||||
}
|
||||
|
||||
ArbitraryEventsWorker::~ArbitraryEventsWorker() {}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitEvent(gd::BaseEvent &event) {
|
||||
return AbstractArbitraryEventsWorker::VisitEvent(event);
|
||||
}
|
||||
|
||||
ArbitraryEventsWorkerWithContext::~ArbitraryEventsWorkerWithContext() {}
|
||||
|
||||
bool ArbitraryEventsWorkerWithContext::VisitEvent(gd::BaseEvent &event) {
|
||||
if (!event.HasVariables()) {
|
||||
return AbstractArbitraryEventsWorker::VisitEvent(event);
|
||||
}
|
||||
// Push local variables
|
||||
auto newProjectScopedContainers =
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersWithLocalVariables(
|
||||
*currentProjectScopedContainers, event);
|
||||
auto *parentProjectScopedContainers = currentProjectScopedContainers;
|
||||
currentProjectScopedContainers = &newProjectScopedContainers;
|
||||
|
||||
bool shouldDelete = AbstractArbitraryEventsWorker::VisitEvent(event);
|
||||
|
||||
// Pop local variables
|
||||
currentProjectScopedContainers = parentProjectScopedContainers;
|
||||
return shouldDelete;
|
||||
}
|
||||
|
||||
ReadOnlyArbitraryEventsWorker::~ReadOnlyArbitraryEventsWorker() {}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitEvent(
|
||||
const gd::BaseEvent &event) {
|
||||
AbstractReadOnlyArbitraryEventsWorker::VisitEvent(event);
|
||||
}
|
||||
|
||||
ReadOnlyArbitraryEventsWorkerWithContext::~ReadOnlyArbitraryEventsWorkerWithContext() {}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorkerWithContext::VisitEvent(
|
||||
const gd::BaseEvent &event) {
|
||||
if (!event.HasVariables()) {
|
||||
AbstractReadOnlyArbitraryEventsWorker::VisitEvent(event);
|
||||
return;
|
||||
}
|
||||
// Push local variables
|
||||
auto newProjectScopedContainers =
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersWithLocalVariables(
|
||||
*currentProjectScopedContainers, event);
|
||||
auto *parentProjectScopedContainers = currentProjectScopedContainers;
|
||||
currentProjectScopedContainers = &newProjectScopedContainers;
|
||||
|
||||
AbstractReadOnlyArbitraryEventsWorker::VisitEvent(event);
|
||||
|
||||
// Pop local variables
|
||||
currentProjectScopedContainers = parentProjectScopedContainers;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -3,8 +3,8 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_ARBITRARYEVENTSWORKER_H
|
||||
#define GDCORE_ARBITRARYEVENTSWORKER_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "GDCore/Events/EventVisitor.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Instruction;
|
||||
class BaseEvent;
|
||||
@@ -25,27 +26,24 @@ class ParameterMetadata;
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief ArbitraryEventsWorker is an abstract class used to browse events (and
|
||||
* instructions) and do some work on them. Can be used to implement refactoring
|
||||
* for example.
|
||||
* \brief AbstractArbitraryEventsWorker is a base abstract class used to browse events (and
|
||||
* instructions) and do some work on them. It must not be inherited directly.
|
||||
*
|
||||
* \see gd::ArbitraryEventsWorker
|
||||
* \see gd::ArbitraryEventsWorkerWithContext
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
|
||||
class GD_CORE_API AbstractArbitraryEventsWorker : private EventVisitor {
|
||||
public:
|
||||
ArbitraryEventsWorker(){};
|
||||
virtual ~ArbitraryEventsWorker();
|
||||
AbstractArbitraryEventsWorker(){};
|
||||
virtual ~AbstractArbitraryEventsWorker();
|
||||
|
||||
/**
|
||||
* \brief Launch the worker on the specified events list.
|
||||
*/
|
||||
void Launch(gd::EventsList& events) { VisitEventList(events); };
|
||||
protected:
|
||||
virtual bool VisitEvent(gd::BaseEvent& event) override;
|
||||
void VisitEventList(gd::EventsList& events);
|
||||
|
||||
private:
|
||||
void VisitEventList(gd::EventsList& events);
|
||||
bool VisitEvent(gd::BaseEvent& event) override;
|
||||
bool VisitLinkEvent(gd::LinkEvent& linkEvent) override;
|
||||
void VisitInstructionList(gd::InstructionsList& instructions,
|
||||
bool areConditions);
|
||||
@@ -101,6 +99,31 @@ class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ArbitraryEventsWorker is an abstract class used to browse events (and
|
||||
* instructions) and do some work on them. Can be used to implement refactoring
|
||||
* for example.
|
||||
*
|
||||
* \see gd::ArbitraryEventsWorkerWithContext
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ArbitraryEventsWorker : public AbstractArbitraryEventsWorker {
|
||||
public:
|
||||
ArbitraryEventsWorker(){};
|
||||
virtual ~ArbitraryEventsWorker();
|
||||
|
||||
/**
|
||||
* \brief Launch the worker on the specified events list.
|
||||
*/
|
||||
void Launch(gd::EventsList &events) {
|
||||
AbstractArbitraryEventsWorker::VisitEventList(events);
|
||||
};
|
||||
|
||||
private:
|
||||
bool VisitEvent(gd::BaseEvent &event) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief An events worker that will know about the context (the objects
|
||||
* container). Useful for workers working on expressions notably.
|
||||
@@ -110,10 +133,10 @@ class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ArbitraryEventsWorkerWithContext
|
||||
: public ArbitraryEventsWorker {
|
||||
: public AbstractArbitraryEventsWorker {
|
||||
public:
|
||||
ArbitraryEventsWorkerWithContext()
|
||||
: projectScopedContainers(nullptr){};
|
||||
: currentProjectScopedContainers(nullptr){};
|
||||
virtual ~ArbitraryEventsWorkerWithContext();
|
||||
|
||||
/**
|
||||
@@ -121,53 +144,50 @@ class GD_CORE_API ArbitraryEventsWorkerWithContext
|
||||
* giving the objects container on which the events are applying to.
|
||||
*/
|
||||
void Launch(gd::EventsList& events,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_) {
|
||||
projectScopedContainers = &projectScopedContainers_;
|
||||
ArbitraryEventsWorker::Launch(events);
|
||||
const gd::ProjectScopedContainers& projectScopedContainers) {
|
||||
currentProjectScopedContainers = &projectScopedContainers;
|
||||
AbstractArbitraryEventsWorker::VisitEventList(events);
|
||||
};
|
||||
|
||||
void Launch(gd::EventsList& events) = delete;
|
||||
|
||||
protected:
|
||||
protected:
|
||||
const gd::ProjectScopedContainers& GetProjectScopedContainers() {
|
||||
// Pointers are guaranteed to be not nullptr after
|
||||
// Launch was called.
|
||||
return *projectScopedContainers;
|
||||
return *currentProjectScopedContainers;
|
||||
};
|
||||
const gd::ObjectsContainersList& GetObjectsContainersList() {
|
||||
// Pointers are guaranteed to be not nullptr after
|
||||
// Launch was called.
|
||||
return projectScopedContainers->GetObjectsContainersList();
|
||||
return currentProjectScopedContainers->GetObjectsContainersList();
|
||||
};
|
||||
|
||||
private:
|
||||
const gd::ProjectScopedContainers* projectScopedContainers;
|
||||
bool VisitEvent(gd::BaseEvent& event) override;
|
||||
|
||||
const gd::ProjectScopedContainers* currentProjectScopedContainers;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ReadOnlyArbitraryEventsWorker is an abstract class used to browse events (and
|
||||
* instructions). It can be used to implement autocompletion for example.
|
||||
* instructions). It must not be inherited directly.
|
||||
*
|
||||
* \see gd::ReadOnlyArbitraryEventsWorker
|
||||
* \see gd::ReadOnlyArbitraryEventsWorkerWithContext
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ReadOnlyArbitraryEventsWorker : private ReadOnlyEventVisitor {
|
||||
class GD_CORE_API AbstractReadOnlyArbitraryEventsWorker : private ReadOnlyEventVisitor {
|
||||
public:
|
||||
ReadOnlyArbitraryEventsWorker() : shouldStopIteration(false) {};
|
||||
virtual ~ReadOnlyArbitraryEventsWorker();
|
||||
|
||||
/**
|
||||
* \brief Launch the worker on the specified events list.
|
||||
*/
|
||||
void Launch(const gd::EventsList& events) { VisitEventList(events); };
|
||||
AbstractReadOnlyArbitraryEventsWorker() : shouldStopIteration(false) {};
|
||||
virtual ~AbstractReadOnlyArbitraryEventsWorker();
|
||||
|
||||
protected:
|
||||
void StopAnyEventIteration() override;
|
||||
virtual void VisitEvent(const gd::BaseEvent& event) override;
|
||||
|
||||
void VisitEventList(const gd::EventsList& events);
|
||||
|
||||
private:
|
||||
void VisitEventList(const gd::EventsList& events);
|
||||
void VisitEvent(const gd::BaseEvent& event) override;
|
||||
void VisitLinkEvent(const gd::LinkEvent& linkEvent) override;
|
||||
void VisitInstructionList(const gd::InstructionsList& instructions,
|
||||
bool areConditions);
|
||||
@@ -213,6 +233,31 @@ protected:
|
||||
bool shouldStopIteration;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ReadOnlyArbitraryEventsWorker is an abstract class used to browse events (and
|
||||
* instructions). It can be used to implement autocompletion for example.
|
||||
*
|
||||
* \see gd::ReadOnlyArbitraryEventsWorkerWithContext
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ReadOnlyArbitraryEventsWorker
|
||||
: public AbstractReadOnlyArbitraryEventsWorker {
|
||||
public:
|
||||
ReadOnlyArbitraryEventsWorker(){};
|
||||
virtual ~ReadOnlyArbitraryEventsWorker();
|
||||
|
||||
/**
|
||||
* \brief Launch the worker on the specified events list.
|
||||
*/
|
||||
void Launch(const gd::EventsList &events) {
|
||||
AbstractReadOnlyArbitraryEventsWorker::VisitEventList(events);
|
||||
};
|
||||
|
||||
private:
|
||||
void VisitEvent(const gd::BaseEvent &event) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief An events worker that will know about the context (the objects
|
||||
* container). Useful for workers working on expressions notably.
|
||||
@@ -222,10 +267,10 @@ protected:
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ReadOnlyArbitraryEventsWorkerWithContext
|
||||
: public ReadOnlyArbitraryEventsWorker {
|
||||
: public AbstractReadOnlyArbitraryEventsWorker {
|
||||
public:
|
||||
ReadOnlyArbitraryEventsWorkerWithContext()
|
||||
: projectScopedContainers(nullptr){};
|
||||
: currentProjectScopedContainers(nullptr){};
|
||||
virtual ~ReadOnlyArbitraryEventsWorkerWithContext();
|
||||
|
||||
/**
|
||||
@@ -233,24 +278,22 @@ class GD_CORE_API ReadOnlyArbitraryEventsWorkerWithContext
|
||||
* giving the objects container on which the events are applying to.
|
||||
*/
|
||||
void Launch(const gd::EventsList& events,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_) {
|
||||
projectScopedContainers = &projectScopedContainers_;
|
||||
ReadOnlyArbitraryEventsWorker::Launch(events);
|
||||
const gd::ProjectScopedContainers& projectScopedContainers) {
|
||||
currentProjectScopedContainers = &projectScopedContainers;
|
||||
AbstractReadOnlyArbitraryEventsWorker::VisitEventList(events);
|
||||
};
|
||||
|
||||
void Launch(gd::EventsList& events) = delete;
|
||||
|
||||
protected:
|
||||
protected:
|
||||
const gd::ProjectScopedContainers& GetProjectScopedContainers() {
|
||||
// Pointers are guaranteed to be not nullptr after
|
||||
// Launch was called.
|
||||
return *projectScopedContainers;
|
||||
return *currentProjectScopedContainers;
|
||||
};
|
||||
|
||||
private:
|
||||
const gd::ProjectScopedContainers* projectScopedContainers;
|
||||
void VisitEvent(const gd::BaseEvent& event) override;
|
||||
|
||||
const gd::ProjectScopedContainers* currentProjectScopedContainers;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_ARBITRARYEVENTSWORKER_H
|
||||
|
@@ -226,7 +226,7 @@ void EventsIdentifiersFinder::FindArgumentsInEventsAndDependencies(
|
||||
eventWorker.Launch(layout.GetEvents(),
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout));
|
||||
|
||||
DependenciesAnalyzer dependenciesAnalyzer = DependenciesAnalyzer(project, layout);
|
||||
DependenciesAnalyzer dependenciesAnalyzer(project, layout);
|
||||
dependenciesAnalyzer.Analyze();
|
||||
for (const gd::String& externalEventName : dependenciesAnalyzer.GetExternalEventsDependencies()) {
|
||||
const gd::ExternalEvents& externalEvents = project.GetExternalEvents(externalEventName);
|
||||
|
@@ -20,6 +20,8 @@
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableNameFinder.h"
|
||||
#include "GDCore/IDE/VariableInstructionSwitcher.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
@@ -104,7 +106,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList()
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
// The node represents a variable, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
|
||||
@@ -123,7 +125,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
[&]() {
|
||||
// This is something else - potentially a deleted variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList()
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
// The node represents a variable, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
|
||||
@@ -136,7 +138,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
auto& objectsContainersList =
|
||||
projectScopedContainers.GetObjectsContainersList();
|
||||
if (!objectNameToUseForVariableAccessor.empty()) {
|
||||
if (objectsContainersList.HasVariablesContainer(
|
||||
if (objectsContainersList.HasObjectOrGroupVariablesContainer(
|
||||
objectNameToUseForVariableAccessor, targetVariablesContainer)) {
|
||||
// The node represents an object variable, and this object variables are
|
||||
// the target. Do the replacement or removals:
|
||||
@@ -177,7 +179,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
GetPotentialNewName(node.identifierName),
|
||||
[&]() {
|
||||
// This represents an object.
|
||||
if (objectsContainersList.HasVariablesContainer(
|
||||
if (objectsContainersList.HasObjectOrGroupVariablesContainer(
|
||||
node.identifierName, targetVariablesContainer)) {
|
||||
// The node represents an object variable, and this object variables
|
||||
// are the target. Do the replacement or removals:
|
||||
@@ -188,7 +190,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList()
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
// The node represents a variable, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(
|
||||
@@ -204,7 +206,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
[&]() {
|
||||
// This is something else - potentially a deleted variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList()
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
// The node represents a variable, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(
|
||||
@@ -364,6 +366,50 @@ bool EventsVariableReplacer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
parameterIndex, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
|
||||
if (gd::ParameterMetadata::IsExpression("variable", type) &&
|
||||
gd::VariableInstructionSwitcher::IsSwitchableVariableInstruction(
|
||||
instruction.GetType())) {
|
||||
const auto &newParameterValue =
|
||||
instruction.GetParameter(parameterIndex);
|
||||
const auto variableName =
|
||||
gd::ExpressionVariableNameFinder::GetVariableName(
|
||||
*newParameterValue.GetRootNode());
|
||||
|
||||
const gd::VariablesContainer *variablesContainer = nullptr;
|
||||
if (type == "objectvar") {
|
||||
const auto &objectsContainersList =
|
||||
GetProjectScopedContainers().GetObjectsContainersList();
|
||||
if (objectsContainersList.HasObjectOrGroupWithVariableNamed(
|
||||
lastObjectName, variableName) !=
|
||||
gd::ObjectsContainersList::VariableExistence::DoesNotExist) {
|
||||
variablesContainer =
|
||||
GetProjectScopedContainers()
|
||||
.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(lastObjectName);
|
||||
}
|
||||
} else {
|
||||
if (GetProjectScopedContainers().GetVariablesContainersList().Has(
|
||||
variableName)) {
|
||||
variablesContainer =
|
||||
&GetProjectScopedContainers()
|
||||
.GetVariablesContainersList()
|
||||
.GetVariablesContainerFromVariableName(variableName);
|
||||
}
|
||||
}
|
||||
|
||||
// Every occurrence of the variable or its children are checked.
|
||||
// Ensuring that a child is actually the one with a type change would
|
||||
// take more time.
|
||||
if (variablesContainer == &targetVariablesContainer) {
|
||||
if (typeChangedVariableNames.find(variableName) !=
|
||||
typeChangedVariableNames.end()) {
|
||||
gd::VariableInstructionSwitcher::
|
||||
SwitchBetweenUnifiedInstructionIfNeeded(
|
||||
platform, GetProjectScopedContainers(), instruction);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return shouldDeleteInstruction;
|
||||
|
@@ -34,11 +34,13 @@ class GD_CORE_API EventsVariableReplacer
|
||||
const gd::Platform &platform_,
|
||||
const gd::VariablesContainer &targetVariablesContainer_,
|
||||
const std::unordered_map<gd::String, gd::String> &oldToNewVariableNames_,
|
||||
const std::unordered_set<gd::String> &removedVariableNames_)
|
||||
const std::unordered_set<gd::String> &removedVariableNames_,
|
||||
const std::unordered_set<gd::String> &typeChangedVariableNames_)
|
||||
: platform(platform_),
|
||||
targetVariablesContainer(targetVariablesContainer_),
|
||||
oldToNewVariableNames(oldToNewVariableNames_),
|
||||
removedVariableNames(removedVariableNames_){};
|
||||
removedVariableNames(removedVariableNames_),
|
||||
typeChangedVariableNames(typeChangedVariableNames_){};
|
||||
virtual ~EventsVariableReplacer();
|
||||
|
||||
private:
|
||||
@@ -55,6 +57,7 @@ class GD_CORE_API EventsVariableReplacer
|
||||
gd::String objectName;
|
||||
const std::unordered_map<gd::String, gd::String> &oldToNewVariableNames;
|
||||
const std::unordered_set<gd::String> &removedVariableNames;
|
||||
const std::unordered_set<gd::String> &typeChangedVariableNames;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -229,7 +229,7 @@ std::set<gd::String> EventsVariablesFinder::FindAllObjectVariables(
|
||||
const gd::Platform& platform,
|
||||
const gd::Project& project,
|
||||
const gd::Layout& layout,
|
||||
const gd::Object& object) {
|
||||
const gd::String& objectName) {
|
||||
std::set<gd::String> results;
|
||||
|
||||
FindArgumentsInEventsAndDependencies(
|
||||
@@ -238,7 +238,7 @@ std::set<gd::String> EventsVariablesFinder::FindAllObjectVariables(
|
||||
project,
|
||||
layout,
|
||||
"objectvar",
|
||||
object.GetName());
|
||||
objectName);
|
||||
|
||||
return results;
|
||||
}
|
||||
@@ -258,7 +258,7 @@ void EventsVariablesFinder::FindArgumentsInEventsAndDependencies(
|
||||
eventWorker.Launch(layout.GetEvents(),
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout));
|
||||
|
||||
DependenciesAnalyzer dependenciesAnalyzer = DependenciesAnalyzer(project, layout);
|
||||
DependenciesAnalyzer dependenciesAnalyzer(project, layout);
|
||||
dependenciesAnalyzer.Analyze();
|
||||
for (const gd::String& externalEventName : dependenciesAnalyzer.GetExternalEventsDependencies()) {
|
||||
const gd::ExternalEvents& externalEvents = project.GetExternalEvents(externalEventName);
|
||||
|
@@ -63,14 +63,14 @@ class EventsVariablesFinder {
|
||||
*
|
||||
* \param project The project
|
||||
* \param layout The layout to use.
|
||||
* \param object The object to be scanned
|
||||
* \param objectName The name of the object to be scanned
|
||||
* \return A std::set containing the names of all object variables used.
|
||||
*/
|
||||
static std::set<gd::String> FindAllObjectVariables(
|
||||
const gd::Platform& platform,
|
||||
const gd::Project& project,
|
||||
const gd::Layout& layout,
|
||||
const gd::Object& object);
|
||||
const gd::String& objectName);
|
||||
|
||||
private:
|
||||
|
||||
|
@@ -3,21 +3,23 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
|
||||
#define GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Events/Parsers/GrammarTerminals.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/ValueTypeMetadata.h"
|
||||
#include "GDCore/IDE/Events/ExpressionNodeLocationFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariablePathFinder.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
|
||||
@@ -486,47 +488,56 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
auto type = gd::ExpressionTypeFinder::GetType(
|
||||
platform, projectScopedContainers, rootType, node);
|
||||
|
||||
// Only attempt to complete with the children of the variable
|
||||
// if it's the last child (no more `.AnotherVariable` written after).
|
||||
bool eagerlyCompleteIfExactMatch = node.child == nullptr;
|
||||
|
||||
if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
|
||||
if (type == "globalvar") {
|
||||
if (type == "globalvar" || type == "scenevar") {
|
||||
const auto* variablesContainer =
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetTopMostVariablesContainer();
|
||||
type == "globalvar"
|
||||
? projectScopedContainers.GetVariablesContainersList()
|
||||
.GetTopMostVariablesContainer()
|
||||
: projectScopedContainers.GetVariablesContainersList()
|
||||
.GetBottomMostVariablesContainer();
|
||||
if (variablesContainer) {
|
||||
AddCompletionsForVariablesMatchingSearch(
|
||||
*variablesContainer, node.name, node.nameLocation);
|
||||
}
|
||||
} else if (type == "scenevar") {
|
||||
const auto* variablesContainer =
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetBottomMostVariablesContainer();
|
||||
if (variablesContainer) {
|
||||
AddCompletionsForVariablesMatchingSearch(
|
||||
*variablesContainer, node.name, node.nameLocation);
|
||||
AddCompletionsForVariablesMatchingSearch(*variablesContainer,
|
||||
node.name,
|
||||
node.nameLocation,
|
||||
eagerlyCompleteIfExactMatch);
|
||||
}
|
||||
} else if (type == "objectvar") {
|
||||
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
|
||||
platform,
|
||||
objectsContainersList,
|
||||
// Variable fields doesn't use expression completion,
|
||||
// so the object will be found inside the expression itself.
|
||||
"",
|
||||
node);
|
||||
platform, objectsContainersList, rootObjectName, node);
|
||||
|
||||
AddCompletionsForObjectOrGroupVariablesMatchingSearch(
|
||||
objectsContainersList, objectName, node.name, node.nameLocation);
|
||||
objectsContainersList,
|
||||
objectName,
|
||||
node.name,
|
||||
node.nameLocation,
|
||||
eagerlyCompleteIfExactMatch);
|
||||
}
|
||||
} else {
|
||||
AddCompletionsForObjectsAndVariablesMatchingSearch(
|
||||
node.name, type, node.nameLocation);
|
||||
node.name, type, node.nameLocation, eagerlyCompleteIfExactMatch);
|
||||
}
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
// No completions
|
||||
VariableAndItsParent variableAndItsParent =
|
||||
gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, node);
|
||||
|
||||
// If no child, we're at the end of a variable (like `GrandChild` in
|
||||
// `Something.Child.GrandChild`) so we can complete eagerly children if we
|
||||
// can.
|
||||
gd::String eagerlyCompleteForVariableName =
|
||||
node.child == nullptr ? node.name : "";
|
||||
AddCompletionsForChildrenVariablesOf(variableAndItsParent,
|
||||
node.nameLocation,
|
||||
eagerlyCompleteForVariableName);
|
||||
}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
// No completions
|
||||
}
|
||||
VariableBracketAccessorNode& node) override {}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
const auto& objectsContainersList =
|
||||
projectScopedContainers.GetObjectsContainersList();
|
||||
@@ -537,45 +548,81 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
AddCompletionsForObjectMatchingSearch(
|
||||
node.identifierName, type, node.location);
|
||||
} else if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
|
||||
if (type == "globalvar") {
|
||||
if (type == "globalvar" || type == "scenevar") {
|
||||
const auto* variablesContainer =
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetTopMostVariablesContainer();
|
||||
type == "globalvar"
|
||||
? projectScopedContainers.GetVariablesContainersList()
|
||||
.GetTopMostVariablesContainer()
|
||||
: projectScopedContainers.GetVariablesContainersList()
|
||||
.GetBottomMostVariablesContainer();
|
||||
if (variablesContainer) {
|
||||
AddCompletionsForVariablesMatchingSearch(*variablesContainer,
|
||||
node.identifierName,
|
||||
node.identifierNameLocation);
|
||||
}
|
||||
} else if (type == "scenevar") {
|
||||
const auto* variablesContainer =
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetBottomMostVariablesContainer();
|
||||
if (variablesContainer) {
|
||||
AddCompletionsForVariablesMatchingSearch(*variablesContainer,
|
||||
node.identifierName,
|
||||
node.identifierNameLocation);
|
||||
if (IsCaretOn(node.identifierNameDotLocation) ||
|
||||
IsCaretOn(node.childIdentifierNameLocation)) {
|
||||
// Complete a potential child variable:
|
||||
if (variablesContainer->Has(node.identifierName)) {
|
||||
AddCompletionsForChildrenVariablesOf(
|
||||
&variablesContainer->Get(node.identifierName),
|
||||
node.childIdentifierNameLocation,
|
||||
node.childIdentifierName);
|
||||
}
|
||||
} else {
|
||||
// Complete a root variable of the scene or project.
|
||||
|
||||
// Don't attempt to complete children variables if there is
|
||||
// already a dot written (`MyVariable.`).
|
||||
bool eagerlyCompleteIfPossible =
|
||||
!node.identifierNameDotLocation.IsValid();
|
||||
AddCompletionsForVariablesMatchingSearch(
|
||||
*variablesContainer,
|
||||
node.identifierName,
|
||||
node.identifierNameLocation,
|
||||
eagerlyCompleteIfPossible);
|
||||
}
|
||||
}
|
||||
} else if (type == "objectvar") {
|
||||
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
|
||||
platform,
|
||||
objectsContainersList,
|
||||
// Variable fields doesn't use expression completion,
|
||||
// so the object will be found inside the expression itself.
|
||||
"",
|
||||
node);
|
||||
platform, objectsContainersList, rootObjectName, node);
|
||||
|
||||
AddCompletionsForObjectOrGroupVariablesMatchingSearch(
|
||||
objectsContainersList,
|
||||
objectName,
|
||||
node.identifierName,
|
||||
node.identifierNameLocation);
|
||||
if (IsCaretOn(node.identifierNameDotLocation) ||
|
||||
IsCaretOn(node.childIdentifierNameLocation)) {
|
||||
// Complete a potential child variable:
|
||||
const auto* variablesContainer =
|
||||
objectsContainersList.GetObjectOrGroupVariablesContainer(
|
||||
objectName);
|
||||
if (variablesContainer &&
|
||||
variablesContainer->Has(node.identifierName)) {
|
||||
AddCompletionsForChildrenVariablesOf(
|
||||
&variablesContainer->Get(node.identifierName),
|
||||
node.childIdentifierNameLocation,
|
||||
node.childIdentifierName);
|
||||
}
|
||||
} else {
|
||||
// Complete a root variable of the object.
|
||||
|
||||
// Don't attempt to complete children variables if there is
|
||||
// already a dot written (`MyVariable.`).
|
||||
bool eagerlyCompleteIfPossible =
|
||||
!node.identifierNameDotLocation.IsValid();
|
||||
AddCompletionsForObjectOrGroupVariablesMatchingSearch(
|
||||
objectsContainersList,
|
||||
objectName,
|
||||
node.identifierName,
|
||||
node.identifierNameLocation,
|
||||
eagerlyCompleteIfPossible);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Object function, behavior name, variable, object variable.
|
||||
if (IsCaretOn(node.identifierNameLocation)) {
|
||||
// Is this the proper position?
|
||||
// Don't attempt to complete children variables if there is
|
||||
// already a dot written (`MyVariable.`).
|
||||
bool eagerlyCompleteIfPossible =
|
||||
!node.identifierNameDotLocation.IsValid();
|
||||
AddCompletionsForAllIdentifiersMatchingSearch(
|
||||
node.identifierName, type, node.identifierNameLocation);
|
||||
node.identifierName,
|
||||
type,
|
||||
node.identifierNameLocation,
|
||||
eagerlyCompleteIfPossible);
|
||||
if (!node.identifierNameDotLocation.IsValid()) {
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpressionWithPrefix(
|
||||
@@ -586,27 +633,57 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
}
|
||||
} else if (IsCaretOn(node.identifierNameDotLocation) ||
|
||||
IsCaretOn(node.childIdentifierNameLocation)) {
|
||||
const gd::String& objectName = node.identifierName;
|
||||
// Might be:
|
||||
// - An object variable, object behavior or object expression.
|
||||
// - Or a variable with a child.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
node.identifierName,
|
||||
[&]() {
|
||||
// This is an object.
|
||||
const gd::String& objectName = node.identifierName;
|
||||
AddCompletionsForObjectOrGroupVariablesMatchingSearch(
|
||||
objectsContainersList,
|
||||
objectName,
|
||||
node.childIdentifierName,
|
||||
node.childIdentifierNameLocation,
|
||||
true);
|
||||
|
||||
// Might be an object variable, object behavior or object expression:
|
||||
AddCompletionsForObjectOrGroupVariablesMatchingSearch(
|
||||
objectsContainersList,
|
||||
objectName,
|
||||
node.childIdentifierName,
|
||||
node.childIdentifierNameLocation);
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForBehaviorWithPrefix(
|
||||
node.childIdentifierName,
|
||||
node.childIdentifierNameLocation.GetStartPosition(),
|
||||
node.childIdentifierNameLocation.GetEndPosition(),
|
||||
objectName));
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpressionWithPrefix(
|
||||
type,
|
||||
node.childIdentifierName,
|
||||
node.childIdentifierNameLocation.GetStartPosition(),
|
||||
node.childIdentifierNameLocation.GetEndPosition(),
|
||||
objectName));
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForBehaviorWithPrefix(
|
||||
node.childIdentifierName,
|
||||
node.childIdentifierNameLocation.GetStartPosition(),
|
||||
node.childIdentifierNameLocation.GetEndPosition(),
|
||||
objectName));
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpressionWithPrefix(
|
||||
type,
|
||||
node.childIdentifierName,
|
||||
node.childIdentifierNameLocation.GetStartPosition(),
|
||||
node.childIdentifierNameLocation.GetEndPosition(),
|
||||
objectName));
|
||||
},
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
VariableAndItsParent variableAndItsParent =
|
||||
gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, node);
|
||||
|
||||
AddCompletionsForChildrenVariablesOf(
|
||||
variableAndItsParent,
|
||||
node.childIdentifierNameLocation,
|
||||
node.childIdentifierName);
|
||||
},
|
||||
[&]() {
|
||||
// Ignore properties here.
|
||||
// There is no support for "children" of properties.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore parameters here.
|
||||
// There is no support for "children" of parameters.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore unrecognised identifiers here.
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -736,7 +813,8 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
auto type = gd::ExpressionTypeFinder::GetType(
|
||||
platform, projectScopedContainers, rootType, node);
|
||||
|
||||
AddCompletionsForAllIdentifiersMatchingSearch(node.text, type, node.location);
|
||||
AddCompletionsForAllIdentifiersMatchingSearch(
|
||||
node.text, type, node.location);
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpressionWithPrefix(
|
||||
type,
|
||||
@@ -755,10 +833,96 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
(inclusive && searchedPosition <= location.GetEndPosition())));
|
||||
}
|
||||
|
||||
/**
|
||||
* A slightly less strict check than `gd::Project::IsNameSafe` as child
|
||||
* variables can be completed even if they start with a number.
|
||||
*/
|
||||
bool IsIdentifierSafe(const gd::String& name) {
|
||||
if (name.empty()) return false;
|
||||
|
||||
for (auto character : name) {
|
||||
if (!GrammarTerminals::IsAllowedInIdentifier(character)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddCompletionsForChildrenVariablesOf(
|
||||
VariableAndItsParent variableAndItsParent,
|
||||
const ExpressionParserLocation& location,
|
||||
gd::String eagerlyCompleteForVariableName = "") {
|
||||
if (variableAndItsParent.parentVariable) {
|
||||
AddCompletionsForChildrenVariablesOf(variableAndItsParent.parentVariable,
|
||||
location,
|
||||
eagerlyCompleteForVariableName);
|
||||
} else if (variableAndItsParent.parentVariablesContainer) {
|
||||
AddCompletionsForVariablesMatchingSearch(
|
||||
*variableAndItsParent.parentVariablesContainer, "", location);
|
||||
}
|
||||
}
|
||||
|
||||
void AddCompletionsForChildrenVariablesOf(
|
||||
const gd::Variable* variable,
|
||||
const ExpressionParserLocation& location,
|
||||
gd::String eagerlyCompleteForVariableName = "") {
|
||||
if (!variable) return;
|
||||
|
||||
if (variable->GetType() == gd::Variable::Structure) {
|
||||
for (const auto& name : variable->GetAllChildrenNames()) {
|
||||
if (!IsIdentifierSafe(name)) continue;
|
||||
|
||||
const auto& childVariable = variable->GetChild(name);
|
||||
ExpressionCompletionDescription description(
|
||||
ExpressionCompletionDescription::Variable,
|
||||
location.GetStartPosition(),
|
||||
location.GetEndPosition());
|
||||
description.SetCompletion(name);
|
||||
description.SetVariableType(childVariable.GetType());
|
||||
completions.push_back(description);
|
||||
|
||||
if (name == eagerlyCompleteForVariableName) {
|
||||
AddEagerCompletionForVariableChildren(childVariable, name, location);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO: we could do a "comment only completion" to indicate that nothing
|
||||
// can/should be completed?
|
||||
}
|
||||
}
|
||||
|
||||
void AddEagerCompletionForVariableChildren(
|
||||
const gd::Variable& variable,
|
||||
const gd::String& variableName,
|
||||
const ExpressionParserLocation& location) {
|
||||
if (variable.GetType() == gd::Variable::Structure) {
|
||||
gd::String prefix = variableName + ".";
|
||||
for (const auto& name : variable.GetAllChildrenNames()) {
|
||||
gd::String completion =
|
||||
IsIdentifierSafe(name)
|
||||
? (prefix + name)
|
||||
: (variableName + "[" +
|
||||
gd::ExpressionParser2NodePrinter::PrintStringLiteral(name) +
|
||||
"]");
|
||||
|
||||
const auto& childVariable = variable.GetChild(name);
|
||||
ExpressionCompletionDescription description(
|
||||
ExpressionCompletionDescription::Variable,
|
||||
location.GetStartPosition(),
|
||||
location.GetEndPosition());
|
||||
description.SetCompletion(completion);
|
||||
description.SetVariableType(childVariable.GetType());
|
||||
completions.push_back(description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddCompletionsForVariablesMatchingSearch(
|
||||
const gd::VariablesContainer& variablesContainer,
|
||||
const gd::String& search,
|
||||
const ExpressionParserLocation& location) {
|
||||
const ExpressionParserLocation& location,
|
||||
bool eagerlyCompleteIfExactMatch = false) {
|
||||
variablesContainer.ForEachVariableMatchingSearch(
|
||||
search,
|
||||
[&](const gd::String& variableName, const gd::Variable& variable) {
|
||||
@@ -769,6 +933,11 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
description.SetCompletion(variableName);
|
||||
description.SetVariableType(variable.GetType());
|
||||
completions.push_back(description);
|
||||
|
||||
if (eagerlyCompleteIfExactMatch && variableName == search) {
|
||||
AddEagerCompletionForVariableChildren(
|
||||
variable, variableName, location);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -776,7 +945,8 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
const gd::ObjectsContainersList& objectsContainersList,
|
||||
const gd::String& objectOrGroupName,
|
||||
const gd::String& search,
|
||||
const ExpressionParserLocation& location) {
|
||||
const ExpressionParserLocation& location,
|
||||
bool eagerlyCompleteIfExactMatch) {
|
||||
objectsContainersList.ForEachObjectOrGroupVariableMatchingSearch(
|
||||
objectOrGroupName,
|
||||
search,
|
||||
@@ -788,6 +958,11 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
description.SetCompletion(variableName);
|
||||
description.SetVariableType(variable.GetType());
|
||||
completions.push_back(description);
|
||||
|
||||
if (eagerlyCompleteIfExactMatch && variableName == search) {
|
||||
AddEagerCompletionForVariableChildren(
|
||||
variable, variableName, location);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -795,25 +970,27 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
const gd::String& search,
|
||||
const gd::String& type,
|
||||
const ExpressionParserLocation& location) {
|
||||
projectScopedContainers.GetObjectsContainersList().ForEachNameMatchingSearch(
|
||||
search,
|
||||
[&](const gd::String& name,
|
||||
const gd::ObjectConfiguration* objectConfiguration) {
|
||||
ExpressionCompletionDescription description(
|
||||
ExpressionCompletionDescription::Object,
|
||||
location.GetStartPosition(),
|
||||
location.GetEndPosition());
|
||||
description.SetObjectConfiguration(objectConfiguration);
|
||||
description.SetCompletion(name);
|
||||
description.SetType(type);
|
||||
completions.push_back(description);
|
||||
});
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.ForEachNameMatchingSearch(
|
||||
search,
|
||||
[&](const gd::String& name,
|
||||
const gd::ObjectConfiguration* objectConfiguration) {
|
||||
ExpressionCompletionDescription description(
|
||||
ExpressionCompletionDescription::Object,
|
||||
location.GetStartPosition(),
|
||||
location.GetEndPosition());
|
||||
description.SetObjectConfiguration(objectConfiguration);
|
||||
description.SetCompletion(name);
|
||||
description.SetType(type);
|
||||
completions.push_back(description);
|
||||
});
|
||||
}
|
||||
|
||||
void AddCompletionsForObjectsAndVariablesMatchingSearch(
|
||||
const gd::String& search,
|
||||
const gd::String& type,
|
||||
const ExpressionParserLocation& location) {
|
||||
const ExpressionParserLocation& location,
|
||||
bool eagerlyCompleteIfExactMatch) {
|
||||
projectScopedContainers.ForEachIdentifierMatchingSearch(
|
||||
search,
|
||||
[&](const gd::String& objectName,
|
||||
@@ -835,6 +1012,11 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
description.SetCompletion(variableName);
|
||||
description.SetVariableType(variable.GetType());
|
||||
completions.push_back(description);
|
||||
|
||||
if (eagerlyCompleteIfExactMatch && variableName == search) {
|
||||
AddEagerCompletionForVariableChildren(
|
||||
variable, variableName, location);
|
||||
}
|
||||
},
|
||||
[&](const gd::NamedPropertyDescriptor& property) {
|
||||
// Ignore properties here.
|
||||
@@ -845,7 +1027,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
}
|
||||
|
||||
void AddCompletionsForAllIdentifiersMatchingSearch(const gd::String& search,
|
||||
const gd::String& type) {
|
||||
const gd::String& type) {
|
||||
AddCompletionsForAllIdentifiersMatchingSearch(
|
||||
search,
|
||||
type,
|
||||
@@ -855,7 +1037,8 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
void AddCompletionsForAllIdentifiersMatchingSearch(
|
||||
const gd::String& search,
|
||||
const gd::String& type,
|
||||
const ExpressionParserLocation& location) {
|
||||
const ExpressionParserLocation& location,
|
||||
bool eagerlyCompleteIfExactMatch = false) {
|
||||
projectScopedContainers.ForEachIdentifierMatchingSearch(
|
||||
search,
|
||||
[&](const gd::String& objectName,
|
||||
@@ -877,6 +1060,11 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
description.SetCompletion(variableName);
|
||||
description.SetVariableType(variable.GetType());
|
||||
completions.push_back(description);
|
||||
|
||||
if (eagerlyCompleteIfExactMatch && variableName == search) {
|
||||
AddEagerCompletionForVariableChildren(
|
||||
variable, variableName, location);
|
||||
}
|
||||
},
|
||||
[&](const gd::NamedPropertyDescriptor& property) {
|
||||
ExpressionCompletionDescription description(
|
||||
@@ -904,11 +1092,14 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
const gd::String& rootType_,
|
||||
size_t searchedPosition_,
|
||||
gd::ExpressionNode* maybeParentNodeAtLocation_)
|
||||
: platform(platform_),
|
||||
: searchedPosition(searchedPosition_),
|
||||
maybeParentNodeAtLocation(maybeParentNodeAtLocation_),
|
||||
platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
rootType(rootType_),
|
||||
searchedPosition(searchedPosition_),
|
||||
maybeParentNodeAtLocation(maybeParentNodeAtLocation_){};
|
||||
rootObjectName("") // Always empty, might be changed if variable fields
|
||||
// in the editor are changed to use completion.
|
||||
{};
|
||||
|
||||
std::vector<ExpressionCompletionDescription> completions;
|
||||
size_t searchedPosition;
|
||||
@@ -917,8 +1108,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
const gd::Platform& platform;
|
||||
const gd::ProjectScopedContainers& projectScopedContainers;
|
||||
const gd::String rootType;
|
||||
const gd::String rootObjectName;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
|
||||
|
@@ -166,8 +166,7 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
return true; // We found a property, even if the child is not allowed.
|
||||
}
|
||||
|
||||
const gd::NamedPropertyDescriptor& property = projectScopedContainers
|
||||
.GetPropertiesContainersList().Get(identifier.identifierName).second;
|
||||
const gd::NamedPropertyDescriptor& property = propertiesContainersList.Get(identifier.identifierName).second;
|
||||
|
||||
if (property.GetType() == "Number") {
|
||||
childType = Type::Number;
|
||||
@@ -263,11 +262,17 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
|
||||
}
|
||||
|
||||
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
|
||||
RaiseError("invalid_function_name",
|
||||
if (function.functionName.empty()) {
|
||||
RaiseError("invalid_function_name",
|
||||
_("Enter the name of the function to call."),
|
||||
function.location);
|
||||
} else {
|
||||
RaiseError("invalid_function_name",
|
||||
_("Cannot find an expression with this name: ") +
|
||||
function.functionName + "\n" +
|
||||
_("Double check that you've not made any typo in the name."),
|
||||
function.location);
|
||||
}
|
||||
return returnType;
|
||||
}
|
||||
|
||||
@@ -370,7 +375,10 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
|
||||
dynamic_cast<EmptyNode*>(parameter.get()) == nullptr) {
|
||||
auto currentParentType = parentType;
|
||||
parentType = StringToType(parameterMetadata.GetType());
|
||||
auto parentParameterExtraInfo = currentParameterExtraInfo;
|
||||
currentParameterExtraInfo = ¶meterMetadata.GetExtraInfo();
|
||||
parameter->Visit(*this);
|
||||
currentParameterExtraInfo = parentParameterExtraInfo;
|
||||
parentType = currentParentType;
|
||||
|
||||
const gd::String& expectedParameterType = parameterMetadata.GetType();
|
||||
@@ -434,6 +442,10 @@ const gd::String& ExpressionValidator::TypeToString(Type type) {
|
||||
return numberOrStringTypeString;
|
||||
case Type::Variable:
|
||||
return variableTypeString;
|
||||
case Type::LegacyVariable:
|
||||
// This function is only used to display error.
|
||||
// Users don't care if it's legacy or not.
|
||||
return variableTypeString;
|
||||
case Type::Object:
|
||||
return objectTypeString;
|
||||
case Type::Empty:
|
||||
@@ -460,7 +472,12 @@ ExpressionValidator::Type ExpressionValidator::StringToType(
|
||||
if (type == ExpressionValidator::variableTypeString ||
|
||||
gd::ParameterMetadata::IsExpression(
|
||||
ExpressionValidator::variableTypeString, type)) {
|
||||
return Type::Variable;
|
||||
if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
|
||||
return Type::LegacyVariable;
|
||||
}
|
||||
else {
|
||||
return Type::Variable;
|
||||
}
|
||||
}
|
||||
if (type == ExpressionValidator::objectTypeString ||
|
||||
gd::ParameterMetadata::IsObject(type)) {
|
||||
|
@@ -3,8 +3,7 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EXPRESSIONVALIDATOR_H
|
||||
#define GDCORE_EXPRESSIONVALIDATOR_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -39,12 +38,14 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionValidator(const gd::Platform &platform_,
|
||||
const gd::ProjectScopedContainers & projectScopedContainers_,
|
||||
const gd::String &rootType_)
|
||||
const gd::String &rootType_,
|
||||
const gd::String &extraInfo_ = "")
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
parentType(StringToType(gd::ParameterMetadata::GetExpressionValueType(rootType_))),
|
||||
childType(Type::Unknown),
|
||||
forbidsUsageOfBracketsBecauseParentIsObject(false) {};
|
||||
forbidsUsageOfBracketsBecauseParentIsObject(false),
|
||||
currentParameterExtraInfo(&extraInfo_) {};
|
||||
virtual ~ExpressionValidator(){};
|
||||
|
||||
/**
|
||||
@@ -86,8 +87,10 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {
|
||||
ReportAnyError(node);
|
||||
|
||||
// The "required" type ("parentType") will be used when visiting the first operand.
|
||||
// Note that it may be refined thanks to this first operand (see later).
|
||||
node.leftHandSide->Visit(*this);
|
||||
const Type leftType = childType;
|
||||
const Type leftType = childType; // Store the type of the first operand.
|
||||
|
||||
if (leftType == Type::Number) {
|
||||
if (node.op == ' ') {
|
||||
@@ -113,22 +116,26 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
_("Operators (+, -, /, *) can't be used with an object name. Remove "
|
||||
"the operator."),
|
||||
node.rightHandSide->location);
|
||||
} else if (leftType == Type::Variable) {
|
||||
} else if (leftType == Type::Variable || leftType == Type::LegacyVariable) {
|
||||
RaiseOperatorError(
|
||||
_("Operators (+, -, /, *) can't be used in variable names. Remove "
|
||||
"the operator from the variable name."),
|
||||
node.rightHandSide->location);
|
||||
}
|
||||
|
||||
parentType = leftType;
|
||||
// The "required" type ("parentType") of the second operator is decided by:
|
||||
// - the parent type. Unless it can (`number|string`) or should (`unknown`) be refined, then:
|
||||
// - the first operand.
|
||||
parentType = ShouldTypeBeRefined(parentType) ? leftType : parentType;
|
||||
node.rightHandSide->Visit(*this);
|
||||
const Type rightType = childType;
|
||||
|
||||
// The type is decided by the first operand, unless it can (`number|string`)
|
||||
// or should (`unknown`) be refined, in which case we go for the right
|
||||
// operand (which got visited knowing the type of the first operand, so it's
|
||||
// The type of the overall operator ("childType") is decided by:
|
||||
// - the parent type. Unless it can (`number|string`) or should (`unknown`) be refined, then:
|
||||
// - the first operand. Unless it can (`number|string`) or should (`unknown`) be refined, then:
|
||||
// - the right operand (which got visited knowing the type of the first operand, so it's
|
||||
// equal or strictly more precise than the left operand).
|
||||
childType = (leftType == Type::Unknown || leftType == Type::NumberOrString) ? leftType : rightType;
|
||||
childType = ShouldTypeBeRefined(parentType) ? (ShouldTypeBeRefined(leftType) ? leftType : rightType) : parentType;
|
||||
}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
|
||||
ReportAnyError(node);
|
||||
@@ -156,7 +163,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
_("Operators (+, -) can't be used with an object name. Remove the "
|
||||
"operator."),
|
||||
node.location);
|
||||
} else if (rightType == Type::Variable) {
|
||||
} else if (rightType == Type::Variable || rightType == Type::LegacyVariable) {
|
||||
RaiseTypeError(
|
||||
_("Operators (+, -) can't be used in variable names. Remove "
|
||||
"the operator from the variable name."),
|
||||
@@ -194,7 +201,20 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
ReportAnyError(node);
|
||||
|
||||
if (parentType == Type::Variable) {
|
||||
childType = Type::Variable;
|
||||
childType = parentType;
|
||||
|
||||
if (!currentParameterExtraInfo || *currentParameterExtraInfo != "AllowUndeclaredVariable") {
|
||||
const auto& variablesContainersList = projectScopedContainers.GetVariablesContainersList();
|
||||
if (!variablesContainersList.Has(node.name)) {
|
||||
RaiseTypeError(_("No variable with this name found."), node.location);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.child) {
|
||||
node.child->Visit(*this);
|
||||
}
|
||||
} else if (parentType == Type::LegacyVariable) {
|
||||
childType = parentType;
|
||||
|
||||
if (node.child) {
|
||||
node.child->Visit(*this);
|
||||
@@ -274,7 +294,10 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
|
||||
Type currentParentType = parentType;
|
||||
parentType = Type::NumberOrString;
|
||||
auto parentParameterExtraInfo = currentParameterExtraInfo;
|
||||
currentParameterExtraInfo = nullptr;
|
||||
node.expression->Visit(*this);
|
||||
currentParameterExtraInfo = parentParameterExtraInfo;
|
||||
parentType = currentParentType;
|
||||
|
||||
if (node.child) {
|
||||
@@ -308,7 +331,15 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
node.location);
|
||||
}
|
||||
}
|
||||
else if (parentType != Type::Object && parentType != Type::Variable) {
|
||||
else if (parentType == Type::Variable) {
|
||||
if (!currentParameterExtraInfo || *currentParameterExtraInfo != "AllowUndeclaredVariable") {
|
||||
const auto& variablesContainersList = projectScopedContainers.GetVariablesContainersList();
|
||||
if (!variablesContainersList.Has(node.identifierName)) {
|
||||
RaiseTypeError(_("No variable with this name found."), node.location);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (parentType != Type::Object && parentType != Type::LegacyVariable) {
|
||||
// It can't happen.
|
||||
RaiseTypeError(
|
||||
_("You've entered a name, but this type was expected:") + " " + TypeToString(parentType),
|
||||
@@ -332,7 +363,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
} else if (parentType == Type::String) {
|
||||
message = _(
|
||||
"You must enter a text (between quotes) or a valid expression call.");
|
||||
} else if (parentType == Type::Variable) {
|
||||
} else if (parentType == Type::Variable || parentType == Type::LegacyVariable) {
|
||||
message = _("You must enter a variable name.");
|
||||
} else if (parentType == Type::Object) {
|
||||
message = _("You must enter a valid object name.");
|
||||
@@ -345,7 +376,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
}
|
||||
|
||||
private:
|
||||
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, Object, Empty};
|
||||
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, LegacyVariable, Object, Empty};
|
||||
Type ValidateFunction(const gd::FunctionCallNode& function);
|
||||
bool ValidateObjectVariableOrVariableOrProperty(const gd::IdentifierNode& identifier);
|
||||
|
||||
@@ -395,6 +426,10 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
}
|
||||
}
|
||||
|
||||
static bool ShouldTypeBeRefined(Type type) {
|
||||
return (type == Type::Unknown || type == Type::NumberOrString);
|
||||
}
|
||||
|
||||
static Type StringToType(const gd::String &type);
|
||||
static const gd::String &TypeToString(Type type);
|
||||
static const gd::String unknownTypeString;
|
||||
@@ -402,6 +437,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
static const gd::String stringTypeString;
|
||||
static const gd::String numberOrStringTypeString;
|
||||
static const gd::String variableTypeString;
|
||||
static const gd::String legacyVariableTypeString;
|
||||
static const gd::String objectTypeString;
|
||||
static const gd::String identifierTypeString;
|
||||
static const gd::String emptyTypeString;
|
||||
@@ -412,10 +448,10 @@ 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;
|
||||
const gd::String *currentParameterExtraInfo;
|
||||
const gd::Platform &platform;
|
||||
const gd::ProjectScopedContainers &projectScopedContainers;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXPRESSIONVALIDATOR_H
|
||||
|
55
Core/GDCore/IDE/Events/ExpressionVariableNameFinder.h
Normal file
55
Core/GDCore/IDE/Events/ExpressionVariableNameFinder.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Find the variable name from a variable expression.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionVariableNameFinder : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
|
||||
static const gd::String GetVariableName(gd::ExpressionNode& node) {
|
||||
gd::ExpressionVariableNameFinder typeFinder;
|
||||
node.Visit(typeFinder);
|
||||
return typeFinder.variableName;
|
||||
}
|
||||
|
||||
virtual ~ExpressionVariableNameFinder(){};
|
||||
|
||||
protected:
|
||||
ExpressionVariableNameFinder()
|
||||
: variableName("") {};
|
||||
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
variableName = node.name;
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
variableName = node.identifierName;
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {}
|
||||
|
||||
private:
|
||||
gd::String variableName;
|
||||
};
|
||||
|
||||
} // namespace gd
|
195
Core/GDCore/IDE/Events/ExpressionVariablePathFinder.cpp
Normal file
195
Core/GDCore/IDE/Events/ExpressionVariablePathFinder.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "ExpressionVariablePathFinder.h"
|
||||
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Find the pre-scoped container of legacy variables or the object name
|
||||
* from the function call node.
|
||||
*/
|
||||
class GD_CORE_API ExpressionLiteralFinder : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
virtual ~ExpressionLiteralFinder(){};
|
||||
|
||||
gd::String literalValue;
|
||||
|
||||
ExpressionLiteralFinder() : literalValue(""){};
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode &node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode &node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode &node) override {}
|
||||
void OnVisitNumberNode(NumberNode &node) override {
|
||||
literalValue = node.number;
|
||||
}
|
||||
void OnVisitTextNode(TextNode &node) override { literalValue = node.text; }
|
||||
void OnVisitVariableNode(VariableNode &node) override {}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode &node) override {}
|
||||
void OnVisitIdentifierNode(IdentifierNode &node) override {}
|
||||
void OnVisitEmptyNode(EmptyNode &node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode &node) override {}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode &node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode &functionCall) override {}
|
||||
};
|
||||
|
||||
void ExpressionVariablePathFinder::OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode &node) {
|
||||
// Try to find a literal accessor or add a child with an empty name, which
|
||||
// will be interpreted as "take the first child/item of the structure/array".
|
||||
gd::ExpressionLiteralFinder expressionLiteralFinder;
|
||||
if (node.expression) {
|
||||
node.expression->Visit(expressionLiteralFinder);
|
||||
}
|
||||
childVariableNames.push_back(expressionLiteralFinder.literalValue);
|
||||
|
||||
if (node.child && &node != lastNodeToCheck) {
|
||||
node.child->Visit(*this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Find the pre-scoped container of legacy variables or the object name
|
||||
* from the function call node.
|
||||
*/
|
||||
class GD_CORE_API ExpressionVariableContextFinder
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
|
||||
virtual ~ExpressionVariableContextFinder(){};
|
||||
|
||||
gd::String objectName;
|
||||
gd::String parameterType;
|
||||
gd::ExpressionNode* variableNode;
|
||||
|
||||
ExpressionVariableContextFinder(
|
||||
const gd::Platform& platform_,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_)
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
variableNode(nullptr),
|
||||
objectName(""),
|
||||
parameterType("") {};
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
if (variableNode) {
|
||||
// This is not possible
|
||||
return;
|
||||
}
|
||||
variableNode = &node;
|
||||
|
||||
// Check if the parent is a function call, in which we might be dealing
|
||||
// with a legacy pre-scoped variable parameter:
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
if (variableNode) {
|
||||
// This is not possible
|
||||
return;
|
||||
}
|
||||
// This node is not necessarily a variable node.
|
||||
// It will be checked when visiting the FunctionCallNode, just after.
|
||||
variableNode = &node;
|
||||
|
||||
// Check if the parent is a function call, in which we might be dealing
|
||||
// with a legacy pre-scoped variable parameter:
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {
|
||||
int parameterIndex = -1;
|
||||
for (int i = 0; i < functionCall.parameters.size(); i++) {
|
||||
if (functionCall.parameters.at(i).get() == variableNode) {
|
||||
parameterIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parameterIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& objectsContainersList =
|
||||
projectScopedContainers.GetObjectsContainersList();
|
||||
|
||||
const gd::ParameterMetadata* parameterMetadata =
|
||||
MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, objectsContainersList, functionCall, parameterIndex);
|
||||
if (parameterMetadata == nullptr) return; // Unexpected
|
||||
|
||||
if (parameterMetadata->GetType() == "objectvar") {
|
||||
// Legacy convention where a "objectvar"
|
||||
// parameter represents a variable of the object represented by the
|
||||
// previous "object" parameter. The object on which the function is
|
||||
// called is returned if no previous parameters are objects.
|
||||
objectName = functionCall.objectName;
|
||||
for (int previousIndex = parameterIndex - 1; previousIndex >= 0;
|
||||
previousIndex--) {
|
||||
const gd::ParameterMetadata* previousParameterMetadata =
|
||||
MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, objectsContainersList, functionCall, previousIndex);
|
||||
if (previousParameterMetadata != nullptr &&
|
||||
gd::ParameterMetadata::IsObject(
|
||||
previousParameterMetadata->GetType())) {
|
||||
auto previousParameterNode =
|
||||
functionCall.parameters[previousIndex].get();
|
||||
IdentifierNode* objectNode =
|
||||
dynamic_cast<IdentifierNode*>(previousParameterNode);
|
||||
objectName = objectNode->identifierName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
parameterType = parameterMetadata->GetType();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const gd::Platform& platform;
|
||||
const gd::ProjectScopedContainers& projectScopedContainers;
|
||||
|
||||
};
|
||||
|
||||
VariableAndItsParent ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
const gd::Platform &platform,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::ExpressionNode &node) {
|
||||
|
||||
gd::ExpressionVariableContextFinder contextFinder(platform,
|
||||
projectScopedContainers);
|
||||
node.Visit(contextFinder);
|
||||
if (!contextFinder.variableNode) {
|
||||
return {};
|
||||
}
|
||||
|
||||
gd::ExpressionVariablePathFinder typeFinder(platform, projectScopedContainers,
|
||||
contextFinder.parameterType,
|
||||
contextFinder.objectName, &node);
|
||||
contextFinder.variableNode->Visit(typeFinder);
|
||||
|
||||
if (typeFinder.variableName.empty() || !typeFinder.variablesContainer) {
|
||||
return {};
|
||||
}
|
||||
return typeFinder.WalkUntilLastParent(*typeFinder.variablesContainer,
|
||||
typeFinder.childVariableNames);
|
||||
}
|
||||
|
||||
} // namespace gd
|
354
Core/GDCore/IDE/Events/ExpressionVariablePathFinder.h
Normal file
354
Core/GDCore/IDE/Events/ExpressionVariablePathFinder.h
Normal file
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
|
||||
namespace gd {
|
||||
class Platform;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Contains a variables container or a variable. Useful
|
||||
* to refer to the parent of a variable (which can be a VariablesContainer
|
||||
* or another Variable).
|
||||
*/
|
||||
struct VariableAndItsParent {
|
||||
const gd::VariablesContainer* parentVariablesContainer;
|
||||
const gd::Variable* parentVariable;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Find a variable path from an expression node.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionVariablePathFinder
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
|
||||
static VariableAndItsParent GetLastParentOfNode(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::ExpressionNode& node);
|
||||
|
||||
static const gd::Variable::Type GetVariableType(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::ExpressionNode& node, const gd::String& objectName) {
|
||||
// The context is not checked because this is called on variable parameters.
|
||||
gd::String parameterType = objectName.empty() ? "variable" : "objectvar";
|
||||
gd::String objName = objectName;
|
||||
gd::ExpressionVariablePathFinder typeFinder(
|
||||
platform, projectScopedContainers, parameterType, objName);
|
||||
node.Visit(typeFinder);
|
||||
|
||||
if (typeFinder.variableName.empty() || !typeFinder.variablesContainer) {
|
||||
return gd::Variable::Unknown;
|
||||
}
|
||||
auto *variable = typeFinder.WalkUntilLastChild(
|
||||
typeFinder.variablesContainer->Get(typeFinder.variableName),
|
||||
typeFinder.childVariableNames);
|
||||
return variable ? variable->GetType() : gd::Variable::Unknown;
|
||||
}
|
||||
|
||||
static const gd::Variable::Type GetArrayVariableType(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::ExpressionNode& node, const gd::String& objectName) {
|
||||
// The context is not checked because this is called on variable parameters.
|
||||
gd::String parameterType = objectName.empty() ? "variable" : "objectvar";
|
||||
gd::String objName = objectName;
|
||||
gd::ExpressionVariablePathFinder typeFinder(
|
||||
platform, projectScopedContainers, parameterType, objName);
|
||||
node.Visit(typeFinder);
|
||||
|
||||
if (typeFinder.variableName.empty() || !typeFinder.variablesContainer) {
|
||||
return gd::Variable::Unknown;
|
||||
}
|
||||
auto *variable = typeFinder.WalkUntilLastChild(
|
||||
typeFinder.variablesContainer->Get(typeFinder.variableName),
|
||||
typeFinder.childVariableNames);
|
||||
return variable && variable->GetChildrenCount() > 0
|
||||
? variable->GetAtIndex(0).GetType()
|
||||
: gd::Variable::Unknown;
|
||||
}
|
||||
|
||||
virtual ~ExpressionVariablePathFinder(){};
|
||||
|
||||
protected:
|
||||
ExpressionVariablePathFinder(
|
||||
const gd::Platform& platform_,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_,
|
||||
const gd::String& parameterType_,
|
||||
gd::String& objectName_,
|
||||
const gd::ExpressionNode* lastNodeToCheck_ = nullptr)
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
parameterType(parameterType_),
|
||||
objectName(objectName_),
|
||||
lastNodeToCheck(lastNodeToCheck_),
|
||||
variablesContainer(nullptr),
|
||||
variableName(""),
|
||||
bailOutBecauseEmptyVariableName(false) {};
|
||||
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override;
|
||||
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
FindVariableFor(node.name);
|
||||
if (node.child && &node != lastNodeToCheck) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
if (node.name.empty() && node.child) {
|
||||
// A variable accessor should always have a name if it has a child (i.e:
|
||||
// another accessor). While the parser may have generated an empty name,
|
||||
// flag this so we avoid finding a wrong parent (and so, run the risk of
|
||||
// giving wrong autocompletions).
|
||||
bailOutBecauseEmptyVariableName = true;
|
||||
}
|
||||
if (variableName.empty()) {
|
||||
const auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
|
||||
if (objectsContainersList.HasObjectOrGroupWithVariableNamed(objectName,
|
||||
node.name) !=
|
||||
gd::ObjectsContainersList::VariableExistence::DoesNotExist) {
|
||||
variableName = node.name;
|
||||
variablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(objectName);
|
||||
}
|
||||
} else {
|
||||
childVariableNames.push_back(node.name);
|
||||
}
|
||||
if (node.child && &node != lastNodeToCheck) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
FindVariableFor(node.identifierName, node.identifierNameDotLocation.IsValid() ? &node.childIdentifierName : nullptr);
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {}
|
||||
|
||||
void FindVariableFor(const gd::String& identifier, gd::String* childIdentifier = nullptr) {
|
||||
if (!objectName.empty()) {
|
||||
const auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
|
||||
if (objectsContainersList.HasObjectOrGroupWithVariableNamed(objectName,
|
||||
identifier) !=
|
||||
gd::ObjectsContainersList::VariableExistence::DoesNotExist) {
|
||||
variableName = identifier;
|
||||
variablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(objectName);
|
||||
if (childIdentifier) {
|
||||
childVariableNames.push_back(*childIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (parameterType == "scenevar") {
|
||||
// The node represents a variable name, and the variables container
|
||||
// containing it was identified in the FunctionCallNode.
|
||||
variablesContainer = projectScopedContainers.GetVariablesContainersList()
|
||||
.GetBottomMostVariablesContainer();
|
||||
variableName = identifier;
|
||||
if (childIdentifier) {
|
||||
childVariableNames.push_back(*childIdentifier);
|
||||
}
|
||||
}
|
||||
else if (parameterType == "globalvar") {
|
||||
// The node represents a variable name, and the variables container
|
||||
// containing it was identified in the FunctionCallNode.
|
||||
variablesContainer = projectScopedContainers.GetVariablesContainersList()
|
||||
.GetTopMostVariablesContainer();
|
||||
variableName = identifier;
|
||||
if (childIdentifier) {
|
||||
childVariableNames.push_back(*childIdentifier);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, the identifier is to be interpreted as usual:
|
||||
// it can be an object (on which a variable is accessed),
|
||||
// or a variable.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
identifier,
|
||||
[&]() {
|
||||
objectName = identifier;
|
||||
if (childIdentifier) {
|
||||
if (parameterType == "variable") {
|
||||
// An object is overlapping the variable.
|
||||
// Even in "variable" parameters, this is not allowed to be
|
||||
// consistent with expressions.
|
||||
} else {
|
||||
// It's an object variable expression.
|
||||
const auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
|
||||
if (objectsContainersList.HasObjectOrGroupWithVariableNamed(objectName,
|
||||
*childIdentifier) !=
|
||||
gd::ObjectsContainersList::VariableExistence::DoesNotExist) {
|
||||
variableName = *childIdentifier;
|
||||
variablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(objectName);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList().Has(identifier)) {
|
||||
variablesContainer =
|
||||
&(projectScopedContainers.GetVariablesContainersList()
|
||||
.GetVariablesContainerFromVariableName(identifier));
|
||||
variableName = identifier;
|
||||
if (childIdentifier) {
|
||||
childVariableNames.push_back(*childIdentifier);
|
||||
}
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
// Ignore properties here.
|
||||
// There is no support for "children" of properties.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore parameters here.
|
||||
// There is no support for "children" of parameters.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore unrecognised identifiers here.
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const gd::Variable* WalkUntilLastChild(
|
||||
const gd::Variable& variable,
|
||||
const std::vector<gd::String>& childVariableNames,
|
||||
size_t startIndex = 0) {
|
||||
if (bailOutBecauseEmptyVariableName)
|
||||
return nullptr; // Do not even attempt to find the parent if we had an issue
|
||||
// when visiting nodes.
|
||||
|
||||
const gd::Variable* currentVariable = &variable;
|
||||
|
||||
for (size_t index = startIndex; index < childVariableNames.size();
|
||||
++index) {
|
||||
const gd::String& childName = childVariableNames[index];
|
||||
|
||||
if (childName.empty()) {
|
||||
if (currentVariable->GetChildrenCount() == 0) {
|
||||
// The array or structure is empty, we can't walk through it - there
|
||||
// is no "parent".
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (currentVariable->GetType() == gd::Variable::Array) {
|
||||
currentVariable = ¤tVariable->GetAtIndex(0);
|
||||
} else {
|
||||
currentVariable =
|
||||
currentVariable->GetAllChildren().begin()->second.get();
|
||||
}
|
||||
} else {
|
||||
if (!currentVariable->HasChild(childName)) {
|
||||
// Non existing child - there is no "parent".
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
currentVariable = ¤tVariable->GetChild(childName);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the last parent of the chain of variables (so not the last
|
||||
// variable but the one before it).
|
||||
return currentVariable;
|
||||
}
|
||||
|
||||
VariableAndItsParent WalkUntilLastParent(
|
||||
const gd::Variable& variable,
|
||||
const std::vector<gd::String>& childVariableNames,
|
||||
size_t startIndex = 0) {
|
||||
if (bailOutBecauseEmptyVariableName)
|
||||
return {}; // Do not even attempt to find the parent if we had an issue
|
||||
// when visiting nodes.
|
||||
|
||||
const gd::Variable* currentVariable = &variable;
|
||||
|
||||
// Walk until size - 1 as we want the last parent.
|
||||
for (size_t index = startIndex; index + 1 < childVariableNames.size();
|
||||
++index) {
|
||||
const gd::String& childName = childVariableNames[index];
|
||||
|
||||
if (childName.empty()) {
|
||||
if (currentVariable->GetChildrenCount() == 0) {
|
||||
// The array or structure is empty, we can't walk through it - there
|
||||
// is no "parent".
|
||||
return {};
|
||||
}
|
||||
|
||||
if (currentVariable->GetType() == gd::Variable::Array) {
|
||||
currentVariable = ¤tVariable->GetAtIndex(0);
|
||||
} else {
|
||||
currentVariable =
|
||||
currentVariable->GetAllChildren().begin()->second.get();
|
||||
}
|
||||
} else {
|
||||
if (!currentVariable->HasChild(childName)) {
|
||||
// Non existing child - there is no "parent".
|
||||
return {};
|
||||
}
|
||||
|
||||
currentVariable = ¤tVariable->GetChild(childName);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the last parent of the chain of variables (so not the last
|
||||
// variable but the one before it).
|
||||
return {.parentVariable = currentVariable};
|
||||
}
|
||||
|
||||
VariableAndItsParent WalkUntilLastParent(
|
||||
const gd::VariablesContainer& variablesContainer,
|
||||
const std::vector<gd::String>& childVariableNames) {
|
||||
if (bailOutBecauseEmptyVariableName)
|
||||
return {}; // Do not even attempt to find the parent if we had an issue
|
||||
// when visiting nodes.
|
||||
|
||||
if (variableName.empty())
|
||||
return {}; // There is no "parent" to the variables container itself.
|
||||
|
||||
const gd::Variable* variable = variablesContainer.Has(variableName)
|
||||
? &variablesContainer.Get(variableName)
|
||||
: nullptr;
|
||||
if (childVariableNames.empty() || !variable)
|
||||
return {// No child: the parent is the variables container itself.
|
||||
.parentVariablesContainer = &variablesContainer};
|
||||
|
||||
return WalkUntilLastParent(*variable, childVariableNames, 0);
|
||||
}
|
||||
|
||||
const gd::Platform& platform;
|
||||
const gd::ProjectScopedContainers& projectScopedContainers;
|
||||
const gd::String& parameterType;
|
||||
gd::String& objectName;
|
||||
const gd::ExpressionNode* lastNodeToCheck;
|
||||
|
||||
const gd::VariablesContainer* variablesContainer;
|
||||
gd::String variableName;
|
||||
std::vector<gd::String> childVariableNames;
|
||||
bool bailOutBecauseEmptyVariableName;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -25,6 +25,9 @@ const UsedExtensionsResult UsedExtensionsFinder::ScanProject(gd::Project& projec
|
||||
void UsedExtensionsFinder::DoVisitObject(gd::Object &object) {
|
||||
auto metadata = gd::MetadataProvider::GetExtensionAndObjectMetadata(
|
||||
project.GetCurrentPlatform(), object.GetType());
|
||||
if (metadata.GetMetadata().IsRenderedIn3D()) {
|
||||
result.MarkAsHaving3DObjects();
|
||||
}
|
||||
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());
|
||||
for (auto &&includeFile : metadata.GetMetadata().includeFiles) {
|
||||
result.GetUsedIncludeFiles().insert(includeFile);
|
||||
|
@@ -44,6 +44,13 @@ public:
|
||||
return usedRequiredFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true when at least 1 object uses the 3D renderer.
|
||||
*/
|
||||
bool Has3DObjects() const {
|
||||
return has3DObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* The extensions used by the project (or part of it).
|
||||
*/
|
||||
@@ -59,10 +66,15 @@ public:
|
||||
*/
|
||||
std::set<gd::String> &GetUsedRequiredFiles() { return usedRequiredFiles; }
|
||||
|
||||
void MarkAsHaving3DObjects() {
|
||||
has3DObjects = true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<gd::String> usedExtensions;
|
||||
std::set<gd::String> usedIncludeFiles;
|
||||
std::set<gd::String> usedRequiredFiles;
|
||||
bool has3DObjects = false;
|
||||
};
|
||||
|
||||
class GD_CORE_API UsedExtensionsFinder
|
||||
|
@@ -22,12 +22,7 @@ void EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
const gd::EventsFunctionsContainer functionContainer,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
// Functions don't have access to objects from the "outer" scope.
|
||||
outputGlobalObjectsContainer.GetObjects().clear();
|
||||
outputGlobalObjectsContainer.GetObjectGroups().Clear();
|
||||
|
||||
// Functions scope for objects is defined according
|
||||
// to parameters
|
||||
outputObjectsContainer.GetObjects().clear();
|
||||
@@ -45,13 +40,11 @@ void EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
// The context is build the same way as free function...
|
||||
FreeEventsFunctionToObjectsContainer(project,
|
||||
eventsBasedBehavior.GetEventsFunctions(),
|
||||
eventsFunction,
|
||||
outputGlobalObjectsContainer,
|
||||
outputObjectsContainer);
|
||||
|
||||
// ...and has an "Object" by convention...
|
||||
@@ -83,13 +76,11 @@ void EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
// The context is build the same way as free function...
|
||||
FreeEventsFunctionToObjectsContainer(project,
|
||||
eventsBasedObject.GetEventsFunctions(),
|
||||
eventsFunction,
|
||||
outputGlobalObjectsContainer,
|
||||
outputObjectsContainer);
|
||||
|
||||
// TODO EBO Use a constant instead a hard coded value "Object".
|
||||
|
@@ -3,11 +3,11 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef EventsFunctionTools_H
|
||||
#define EventsFunctionTools_H
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Project;
|
||||
class EventsFunctionsContainer;
|
||||
@@ -37,8 +37,8 @@ class GD_CORE_API EventsFunctionTools {
|
||||
const gd::Project& project,
|
||||
const gd::EventsFunctionsContainer functionContainer,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
|
||||
/**
|
||||
* \brief Given a behavior events function, initialize the given objects container
|
||||
* with objects described in the events function parameters, in
|
||||
@@ -52,8 +52,8 @@ class GD_CORE_API EventsFunctionTools {
|
||||
const gd::Project& project,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
|
||||
/**
|
||||
* \brief Given a parent-object events function, initialize the given objects container
|
||||
* with objects described in the events function parameters, in
|
||||
@@ -67,10 +67,6 @@ class GD_CORE_API EventsFunctionTools {
|
||||
const gd::Project& project,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
};
|
||||
} // namespace gd
|
||||
|
||||
#endif // EventsFunctionTools_H
|
||||
#endif
|
||||
|
@@ -43,7 +43,6 @@ void ExtensionsLoader::LoadAllExtensions(const gd::String &directory,
|
||||
struct dirent *lecture;
|
||||
DIR *rep;
|
||||
rep = opendir(directory.c_str());
|
||||
int l = 0;
|
||||
|
||||
if (rep == NULL) {
|
||||
cout << "Unable to open Extensions (" << directory << ") directory."
|
||||
@@ -63,8 +62,6 @@ void ExtensionsLoader::LoadAllExtensions(const gd::String &directory,
|
||||
|
||||
LoadExtension(directory + "/" + lec, platform, forgiving);
|
||||
librariesLoaded.push_back(directory + "/" + lec);
|
||||
|
||||
l++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +100,6 @@ void ExtensionsLoader::ExtensionsLoadingDone(const gd::String &directory) {
|
||||
struct dirent *lecture;
|
||||
DIR *rep;
|
||||
rep = opendir(directory.c_str());
|
||||
int l = 0;
|
||||
|
||||
if (rep == NULL) {
|
||||
cout << "Unable to open Extensions (" << directory << ") directory."
|
||||
@@ -118,7 +114,6 @@ void ExtensionsLoader::ExtensionsLoadingDone(const gd::String &directory) {
|
||||
lec.find(".xgd" + suffix, lec.length() - 4 - suffix.length()) !=
|
||||
string::npos) {
|
||||
librariesLoaded.push_back(directory + "/" + lec);
|
||||
l++;
|
||||
}
|
||||
}
|
||||
|
||||
|
111
Core/GDCore/IDE/ObjectAssetSerializer.cpp
Normal file
111
Core/GDCore/IDE/ObjectAssetSerializer.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "ObjectAssetSerializer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
|
||||
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/IDE/Project/AssetResourcePathCleaner.h"
|
||||
#include "GDCore/IDE/Project/ResourcesInUseHelper.h"
|
||||
#include "GDCore/IDE/Project/ResourcesRenamer.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/CustomBehavior.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
gd::String
|
||||
ObjectAssetSerializer::GetObjectExtensionName(const gd::Object &object) {
|
||||
const gd::String &type = object.GetType();
|
||||
const auto separatorIndex =
|
||||
type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
return separatorIndex != std::string::npos ? type.substr(0, separatorIndex)
|
||||
: "";
|
||||
}
|
||||
|
||||
void ObjectAssetSerializer::SerializeTo(
|
||||
gd::Project &project, const gd::Object &object,
|
||||
const gd::String &objectFullName, SerializerElement &element,
|
||||
std::vector<gd::String> &usedResourceNames) {
|
||||
auto cleanObject = object.Clone();
|
||||
cleanObject->GetVariables().Clear();
|
||||
cleanObject->GetEffects().Clear();
|
||||
for (auto &&behaviorName : cleanObject->GetAllBehaviorNames()) {
|
||||
cleanObject->RemoveBehavior(behaviorName);
|
||||
}
|
||||
|
||||
gd::String extensionName = GetObjectExtensionName(*cleanObject);
|
||||
|
||||
element.SetAttribute("id", "");
|
||||
element.SetAttribute("name", "");
|
||||
element.SetAttribute("license", "");
|
||||
if (project.HasEventsFunctionsExtensionNamed(extensionName)) {
|
||||
auto &extension = project.GetEventsFunctionsExtension(extensionName);
|
||||
element.SetAttribute("description", extension.GetShortDescription());
|
||||
}
|
||||
element.SetAttribute("gdevelopVersion", "");
|
||||
element.SetAttribute("version", "");
|
||||
element.SetIntAttribute("animationsCount", 1);
|
||||
element.SetIntAttribute("maxFramesCount", 1);
|
||||
// TODO Find the right object dimensions.
|
||||
element.SetIntAttribute("width", 0);
|
||||
element.SetIntAttribute("height", 0);
|
||||
SerializerElement &authorsElement = element.AddChild("authors");
|
||||
authorsElement.ConsiderAsArrayOf("author");
|
||||
SerializerElement &tagsElement = element.AddChild("tags");
|
||||
tagsElement.ConsiderAsArrayOf("tag");
|
||||
|
||||
SerializerElement &objectAssetsElement = element.AddChild("objectAssets");
|
||||
objectAssetsElement.ConsiderAsArrayOf("objectAsset");
|
||||
SerializerElement &objectAssetElement =
|
||||
objectAssetsElement.AddChild("objectAsset");
|
||||
|
||||
cleanObject->SerializeTo(objectAssetElement.AddChild("object"));
|
||||
|
||||
SerializerElement &resourcesElement =
|
||||
objectAssetElement.AddChild("resources");
|
||||
resourcesElement.ConsiderAsArrayOf("resource");
|
||||
auto &resourcesManager = project.GetResourcesManager();
|
||||
gd::ResourcesInUseHelper resourcesInUse(resourcesManager);
|
||||
cleanObject->GetConfiguration().ExposeResources(resourcesInUse);
|
||||
for (auto &&resourceName : resourcesInUse.GetAllResources()) {
|
||||
if (resourceName.length() == 0) {
|
||||
continue;
|
||||
}
|
||||
usedResourceNames.push_back(resourceName);
|
||||
auto &resource = resourcesManager.GetResource(resourceName);
|
||||
SerializerElement &resourceElement = resourcesElement.AddChild("resource");
|
||||
resource.SerializeTo(resourceElement);
|
||||
resourceElement.SetAttribute("kind", resource.GetKind());
|
||||
resourceElement.SetAttribute("name", resource.GetName());
|
||||
}
|
||||
|
||||
SerializerElement &requiredExtensionsElement =
|
||||
objectAssetElement.AddChild("requiredExtensions");
|
||||
requiredExtensionsElement.ConsiderAsArrayOf("requiredExtension");
|
||||
if (project.HasEventsFunctionsExtensionNamed(extensionName)) {
|
||||
SerializerElement &requiredExtensionElement =
|
||||
requiredExtensionsElement.AddChild("requiredExtension");
|
||||
requiredExtensionElement.SetAttribute("extensionName", extensionName);
|
||||
requiredExtensionElement.SetAttribute("extensionVersion", "1.0.0");
|
||||
}
|
||||
|
||||
// TODO This can be removed when the asset script no longer require it.
|
||||
SerializerElement &customizationElement =
|
||||
objectAssetElement.AddChild("customization");
|
||||
customizationElement.ConsiderAsArrayOf("empty");
|
||||
}
|
||||
} // namespace gd
|
57
Core/GDCore/IDE/ObjectAssetSerializer.h
Normal file
57
Core/GDCore/IDE/ObjectAssetSerializer.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Object;
|
||||
class ExtensionDependency;
|
||||
class PropertyDescriptor;
|
||||
class Project;
|
||||
class Layout;
|
||||
class ArbitraryResourceWorker;
|
||||
class InitialInstance;
|
||||
class SerializerElement;
|
||||
class EffectsContainer;
|
||||
class AbstractFileSystem;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Serialize objects into an asset for the store.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ObjectAssetSerializer {
|
||||
public:
|
||||
/**
|
||||
* \brief Serialize an object into an asset.
|
||||
*
|
||||
* \param project The project that contains the object and its resources.
|
||||
* It's not actually modified.
|
||||
* \param object The object to serialize as an asset.
|
||||
* \param objectFullName The object name with spaces instead of PascalCase.
|
||||
* \param element The element where the asset is serialize.
|
||||
* \param usedResourceNames Return the names of the resources used by the asset.
|
||||
*/
|
||||
static void
|
||||
SerializeTo(gd::Project &project, const gd::Object &object,
|
||||
const gd::String &objectFullName, SerializerElement &element,
|
||||
std::vector<gd::String> &usedResourceNames);
|
||||
|
||||
~ObjectAssetSerializer(){};
|
||||
|
||||
private:
|
||||
ObjectAssetSerializer(){};
|
||||
|
||||
static gd::String GetObjectExtensionName(const gd::Object &object);
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -52,6 +52,16 @@ void ArbitraryResourceWorker::ExposeModel3D(gd::String& resourceName){
|
||||
// do.
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeAtlas(gd::String& resourceName){
|
||||
// Nothing to do by default - each child class can define here the action to
|
||||
// do.
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeSpine(gd::String& resourceName){
|
||||
// Nothing to do by default - each child class can define here the action to
|
||||
// do.
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeVideo(gd::String& videoName){
|
||||
// Nothing to do by default - each child class can define here the action to
|
||||
// do.
|
||||
@@ -63,14 +73,10 @@ void ArbitraryResourceWorker::ExposeBitmapFont(gd::String& bitmapFontName){
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeAudio(gd::String& audioName) {
|
||||
for (auto resources : GetResources()) {
|
||||
if (!resources) continue;
|
||||
|
||||
if (resources->HasResource(audioName) &&
|
||||
resources->GetResource(audioName).GetKind() == "audio") {
|
||||
// Nothing to do, the audio is a reference to a proper resource.
|
||||
return;
|
||||
}
|
||||
if (resourcesManager->HasResource(audioName) &&
|
||||
resourcesManager->GetResource(audioName).GetKind() == "audio") {
|
||||
// Nothing to do, the audio is a reference to a proper resource.
|
||||
return;
|
||||
}
|
||||
|
||||
// For compatibility with older projects (where events were referring to files
|
||||
@@ -80,14 +86,10 @@ void ArbitraryResourceWorker::ExposeAudio(gd::String& audioName) {
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeFont(gd::String& fontName) {
|
||||
for (auto resources : GetResources()) {
|
||||
if (!resources) continue;
|
||||
|
||||
if (resources->HasResource(fontName) &&
|
||||
resources->GetResource(fontName).GetKind() == "font") {
|
||||
// Nothing to do, the font is a reference to a proper resource.
|
||||
return;
|
||||
}
|
||||
if (resourcesManager->HasResource(fontName) &&
|
||||
resourcesManager->GetResource(fontName).GetKind() == "font") {
|
||||
// Nothing to do, the font is a reference to a proper resource.
|
||||
return;
|
||||
}
|
||||
|
||||
// For compatibility with older projects (where events were referring to files
|
||||
@@ -96,12 +98,7 @@ void ArbitraryResourceWorker::ExposeFont(gd::String& fontName) {
|
||||
ExposeFile(fontName);
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeResources(
|
||||
gd::ResourcesManager* resourcesManager) {
|
||||
if (!resourcesManager) return;
|
||||
|
||||
resourcesManagers.push_back(resourcesManager);
|
||||
|
||||
void ArbitraryResourceWorker::ExposeResources() {
|
||||
std::vector<gd::String> resources = resourcesManager->GetAllResourceNames();
|
||||
for (std::size_t i = 0; i < resources.size(); i++) {
|
||||
if (resourcesManager->GetResource(resources[i]).UseFile())
|
||||
@@ -110,9 +107,6 @@ void ArbitraryResourceWorker::ExposeResources(
|
||||
}
|
||||
|
||||
void ArbitraryResourceWorker::ExposeEmbeddeds(gd::String& resourceName) {
|
||||
if (resourcesManagers.empty()) return;
|
||||
gd::ResourcesManager* resourcesManager = resourcesManagers[0];
|
||||
|
||||
gd::Resource& resource = resourcesManager->GetResource(resourceName);
|
||||
|
||||
if (!resource.GetMetadata().empty()) {
|
||||
@@ -136,6 +130,7 @@ void ArbitraryResourceWorker::ExposeEmbeddeds(gd::String& resourceName) {
|
||||
|
||||
gd::String potentiallyUpdatedTargetResourceName = targetResourceName;
|
||||
ExposeResourceWithType(targetResource.GetKind(), potentiallyUpdatedTargetResourceName);
|
||||
ExposeEmbeddeds(potentiallyUpdatedTargetResourceName);
|
||||
|
||||
if (potentiallyUpdatedTargetResourceName != targetResourceName) {
|
||||
// The resource name was renamed. Also update the mapping.
|
||||
@@ -176,6 +171,7 @@ void ArbitraryResourceWorker::ExposeResourceWithType(
|
||||
}
|
||||
if (resourceType == "tilemap") {
|
||||
ExposeTilemap(resourceName);
|
||||
ExposeEmbeddeds(resourceName);
|
||||
return;
|
||||
}
|
||||
if (resourceType == "tileset") {
|
||||
@@ -184,12 +180,21 @@ void ArbitraryResourceWorker::ExposeResourceWithType(
|
||||
}
|
||||
if (resourceType == "json") {
|
||||
ExposeJson(resourceName);
|
||||
ExposeEmbeddeds(resourceName);
|
||||
return;
|
||||
}
|
||||
if (resourceType == "video") {
|
||||
ExposeVideo(resourceName);
|
||||
return;
|
||||
}
|
||||
if (resourceType == "atlas") {
|
||||
ExposeAtlas(resourceName);
|
||||
return;
|
||||
}
|
||||
if (resourceType == "spine") {
|
||||
ExposeSpine(resourceName);
|
||||
return;
|
||||
}
|
||||
gd::LogError("Unexpected resource type: " + resourceType + " for: " + resourceName);
|
||||
return;
|
||||
}
|
||||
@@ -243,10 +248,12 @@ bool ResourceWorkerInEventsWorker::DoVisitInstruction(gd::Instruction& instructi
|
||||
} else if (parameterMetadata.GetType() == "jsonResource") {
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeJson(updatedParameterValue);
|
||||
worker.ExposeEmbeddeds(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
} else if (parameterMetadata.GetType() == "tilemapResource") {
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeTilemap(updatedParameterValue);
|
||||
worker.ExposeEmbeddeds(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
} else if (parameterMetadata.GetType() == "tilesetResource") {
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
@@ -256,19 +263,20 @@ bool ResourceWorkerInEventsWorker::DoVisitInstruction(gd::Instruction& instructi
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeModel3D(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
} else if (parameterMetadata.GetType() == "atlasResource") {
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeAtlas(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
} else if (parameterMetadata.GetType() == "spineResource") {
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeSpine(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
void LaunchResourceWorkerOnEvents(const gd::Project& project,
|
||||
gd::EventsList& events,
|
||||
gd::ArbitraryResourceWorker& worker) {
|
||||
gd::ResourceWorkerInEventsWorker eventsWorker(project, worker);
|
||||
eventsWorker.Launch(events);
|
||||
}
|
||||
|
||||
gd::ResourceWorkerInEventsWorker
|
||||
GetResourceWorkerOnEvents(const gd::Project &project,
|
||||
gd::ArbitraryResourceWorker &worker) {
|
||||
|
@@ -37,13 +37,14 @@ namespace gd {
|
||||
* \see ResourcesMergingHelper
|
||||
* \see gd::ResourcesInUseHelper
|
||||
*
|
||||
* \see gd::LaunchResourceWorkerOnEvents
|
||||
* \see gd::GetResourceWorkerOnEvents
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ArbitraryResourceWorker {
|
||||
public:
|
||||
ArbitraryResourceWorker(){};
|
||||
public:
|
||||
ArbitraryResourceWorker(gd::ResourcesManager &resourcesManager_)
|
||||
: resourcesManager(&resourcesManager_){};
|
||||
virtual ~ArbitraryResourceWorker();
|
||||
|
||||
/**
|
||||
@@ -52,7 +53,7 @@ class GD_CORE_API ArbitraryResourceWorker {
|
||||
* first to ensure that resources are known so that images, shaders & audio
|
||||
* can make reference to them.
|
||||
*/
|
||||
void ExposeResources(gd::ResourcesManager *resourcesManager);
|
||||
void ExposeResources();
|
||||
|
||||
/**
|
||||
* \brief Expose a resource from a given type.
|
||||
@@ -95,6 +96,16 @@ class GD_CORE_API ArbitraryResourceWorker {
|
||||
* \brief Expose a 3D model, which is always a reference to a "model3D" resource.
|
||||
*/
|
||||
virtual void ExposeModel3D(gd::String &resourceName);
|
||||
|
||||
/**
|
||||
* \brief Expose an atlas, which is always a reference to a "atlas" resource.
|
||||
*/
|
||||
virtual void ExposeAtlas(gd::String &resourceName);
|
||||
|
||||
/**
|
||||
* \brief Expose an spine, which is always a reference to a "spine" resource.
|
||||
*/
|
||||
virtual void ExposeSpine(gd::String &resourceName);
|
||||
|
||||
/**
|
||||
* \brief Expose a video, which is always a reference to a "video" resource.
|
||||
@@ -122,10 +133,8 @@ class GD_CORE_API ArbitraryResourceWorker {
|
||||
*/
|
||||
virtual void ExposeEmbeddeds(gd::String &resourceName);
|
||||
|
||||
protected:
|
||||
const std::vector<gd::ResourcesManager *> &GetResources() {
|
||||
return resourcesManagers;
|
||||
};
|
||||
protected:
|
||||
gd::ResourcesManager * resourcesManager;
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -133,8 +142,6 @@ class GD_CORE_API ArbitraryResourceWorker {
|
||||
* exposed as file (see ExposeFile).
|
||||
*/
|
||||
void ExposeResource(gd::Resource &resource);
|
||||
|
||||
std::vector<gd::ResourcesManager *> resourcesManagers;
|
||||
};
|
||||
|
||||
/**
|
||||
|
74
Core/GDCore/IDE/Project/AssetResourcePathCleaner.cpp
Normal file
74
Core/GDCore/IDE/Project/AssetResourcePathCleaner.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "AssetResourcePathCleaner.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/ResourcesManager.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
void AssetResourcePathCleaner::ExposeImage(gd::String &imageName) {
|
||||
ExposeResourceAsFile(imageName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeAudio(gd::String &audioName) {
|
||||
ExposeResourceAsFile(audioName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeFont(gd::String &fontName) {
|
||||
ExposeResourceAsFile(fontName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeJson(gd::String &jsonName) {
|
||||
ExposeResourceAsFile(jsonName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeTilemap(gd::String &tilemapName) {
|
||||
ExposeResourceAsFile(tilemapName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeTileset(gd::String &tilesetName) {
|
||||
ExposeResourceAsFile(tilesetName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeVideo(gd::String &videoName) {
|
||||
ExposeResourceAsFile(videoName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeBitmapFont(gd::String &bitmapFontName) {
|
||||
ExposeResourceAsFile(bitmapFontName);
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeResourceAsFile(gd::String &resourceName) {
|
||||
|
||||
auto &resource = resourcesManager->GetResource(resourceName);
|
||||
gd::String file = resource.GetFile();
|
||||
ExposeFile(file);
|
||||
|
||||
resourcesNameReverseMap[file] = resourceName;
|
||||
resourceName = file;
|
||||
}
|
||||
|
||||
void AssetResourcePathCleaner::ExposeFile(gd::String &resourceFilePath) {
|
||||
|
||||
size_t slashPos = resourceFilePath.find_last_of("/");
|
||||
size_t antiSlashPos = resourceFilePath.find_last_of("\\");
|
||||
size_t baseNamePos =
|
||||
slashPos == String::npos
|
||||
? antiSlashPos == String::npos ? 0 : (antiSlashPos + 1)
|
||||
: antiSlashPos == String::npos ? (slashPos + 1)
|
||||
: slashPos > antiSlashPos ? (slashPos + 1)
|
||||
: (antiSlashPos + 1);
|
||||
gd::String baseName =
|
||||
baseNamePos != 0
|
||||
? resourceFilePath.substr(baseNamePos, resourceFilePath.length())
|
||||
: resourceFilePath;
|
||||
|
||||
resourcesFileNameMap[resourceFilePath] = baseName;
|
||||
resourceFilePath = baseName;
|
||||
}
|
||||
|
||||
} // namespace gd
|
65
Core/GDCore/IDE/Project/AssetResourcePathCleaner.h
Normal file
65
Core/GDCore/IDE/Project/AssetResourcePathCleaner.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/IDE/Project/ResourcesMergingHelper.h"
|
||||
#include "GDCore/String.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace gd {
|
||||
class AbstractFileSystem;
|
||||
class Project;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief AssetResourcePathCleaner is used when exporting an object as an asset.
|
||||
* It removes the folder from the path.
|
||||
*
|
||||
* \see ArbitraryResourceWorker
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API AssetResourcePathCleaner : public ArbitraryResourceWorker {
|
||||
public:
|
||||
AssetResourcePathCleaner(
|
||||
gd::ResourcesManager &resourcesManager,
|
||||
std::map<gd::String, gd::String> &resourcesFileNameMap_,
|
||||
std::map<gd::String, gd::String> &resourcesNameReverseMap_)
|
||||
: ArbitraryResourceWorker(resourcesManager),
|
||||
resourcesFileNameMap(resourcesFileNameMap_),
|
||||
resourcesNameReverseMap(resourcesNameReverseMap_){};
|
||||
virtual ~AssetResourcePathCleaner(){};
|
||||
|
||||
void ExposeImage(gd::String &imageName) override;
|
||||
void ExposeAudio(gd::String &audioName) override;
|
||||
void ExposeFont(gd::String &fontName) override;
|
||||
void ExposeJson(gd::String &jsonName) override;
|
||||
void ExposeTilemap(gd::String &tilemapName) override;
|
||||
void ExposeTileset(gd::String &tilesetName) override;
|
||||
void ExposeVideo(gd::String &videoName) override;
|
||||
void ExposeBitmapFont(gd::String &bitmapFontName) override;
|
||||
void ExposeFile(gd::String &resource) override;
|
||||
|
||||
protected:
|
||||
void ExposeResourceAsFile(gd::String &resourceName);
|
||||
|
||||
/**
|
||||
* New file names that can be accessed by their original name.
|
||||
*/
|
||||
std::map<gd::String, gd::String> &resourcesFileNameMap;
|
||||
|
||||
/**
|
||||
* Original resource names that can be accessed by their new name.
|
||||
*/
|
||||
std::map<gd::String, gd::String> &resourcesNameReverseMap;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -6,7 +6,7 @@
|
||||
namespace gd {
|
||||
|
||||
void ObjectsUsingResourceCollector::DoVisitObject(gd::Object& object) {
|
||||
gd::ResourceNameMatcher resourceNameMatcher(resourceName);
|
||||
gd::ResourceNameMatcher resourceNameMatcher(*resourcesManager, resourceName);
|
||||
|
||||
object.GetConfiguration().ExposeResources(resourceNameMatcher);
|
||||
if (resourceNameMatcher.AnyResourceMatches()) {
|
||||
|
@@ -4,8 +4,7 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef ProjectObjectsUsingResourceCollector_H
|
||||
#define ProjectObjectsUsingResourceCollector_H
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -21,9 +20,10 @@ namespace gd {
|
||||
|
||||
class GD_CORE_API ObjectsUsingResourceCollector
|
||||
: public ArbitraryObjectsWorker {
|
||||
public:
|
||||
ObjectsUsingResourceCollector(const gd::String& resourceName_)
|
||||
: resourceName(resourceName_){};
|
||||
public:
|
||||
ObjectsUsingResourceCollector(gd::ResourcesManager &resourcesManager_,
|
||||
const gd::String &resourceName_)
|
||||
: resourcesManager(&resourcesManager_), resourceName(resourceName_){};
|
||||
virtual ~ObjectsUsingResourceCollector();
|
||||
|
||||
std::vector<gd::String>& GetObjectNames() { return objectNames; }
|
||||
@@ -33,12 +33,16 @@ class GD_CORE_API ObjectsUsingResourceCollector
|
||||
|
||||
std::vector<gd::String> objectNames;
|
||||
gd::String resourceName;
|
||||
gd::ResourcesManager *resourcesManager;
|
||||
};
|
||||
|
||||
class GD_CORE_API ResourceNameMatcher : public ArbitraryResourceWorker {
|
||||
public:
|
||||
ResourceNameMatcher(const gd::String& resourceName_)
|
||||
: resourceName(resourceName_), matchesResourceName(false){};
|
||||
public:
|
||||
ResourceNameMatcher(gd::ResourcesManager &resourcesManager,
|
||||
const gd::String &resourceName_)
|
||||
: resourceName(resourceName_),
|
||||
matchesResourceName(false), gd::ArbitraryResourceWorker(
|
||||
resourcesManager){};
|
||||
virtual ~ResourceNameMatcher(){};
|
||||
|
||||
bool AnyResourceMatches() { return matchesResourceName; }
|
||||
@@ -75,6 +79,12 @@ class GD_CORE_API ResourceNameMatcher : public ArbitraryResourceWorker {
|
||||
virtual void ExposeModel3D(gd::String& otherResourceName) override {
|
||||
MatchResourceName(otherResourceName);
|
||||
};
|
||||
virtual void ExposeAtlas(gd::String& otherResourceName) override {
|
||||
MatchResourceName(otherResourceName);
|
||||
};
|
||||
virtual void ExposeSpine(gd::String& otherResourceName) override {
|
||||
MatchResourceName(otherResourceName);
|
||||
};
|
||||
|
||||
void MatchResourceName(gd::String& otherResourceName) {
|
||||
if (otherResourceName == resourceName) matchesResourceName = true;
|
||||
@@ -85,5 +95,3 @@ class GD_CORE_API ResourceNameMatcher : public ArbitraryResourceWorker {
|
||||
};
|
||||
|
||||
}; // namespace gd
|
||||
|
||||
#endif // ProjectObjectsUsingResourceCollector_H
|
||||
|
@@ -18,8 +18,9 @@ namespace gd {
|
||||
std::vector<gd::String> ProjectResourcesAdder::GetAllUseless(
|
||||
gd::Project& project, const gd::String& resourceType) {
|
||||
std::vector<gd::String> unusedResources;
|
||||
|
||||
// Search for resources used in the project
|
||||
gd::ResourcesInUseHelper resourcesInUse;
|
||||
gd::ResourcesInUseHelper resourcesInUse(project.GetResourcesManager());
|
||||
gd::ResourceExposer::ExposeWholeProjectResources(project, resourcesInUse);
|
||||
std::set<gd::String>& usedResources = resourcesInUse.GetAll(resourceType);
|
||||
|
||||
|
@@ -25,8 +25,29 @@ bool ProjectResourcesCopier::CopyAllResourcesTo(
|
||||
bool updateOriginalProject,
|
||||
bool preserveAbsoluteFilenames,
|
||||
bool preserveDirectoryStructure) {
|
||||
if (updateOriginalProject) {
|
||||
gd::ProjectResourcesCopier::CopyAllResourcesTo(
|
||||
originalProject, originalProject, fs, destinationDirectory,
|
||||
preserveAbsoluteFilenames, preserveDirectoryStructure);
|
||||
} else {
|
||||
gd::Project clonedProject = originalProject;
|
||||
gd::ProjectResourcesCopier::CopyAllResourcesTo(
|
||||
originalProject, clonedProject, fs, destinationDirectory,
|
||||
preserveAbsoluteFilenames, preserveDirectoryStructure);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProjectResourcesCopier::CopyAllResourcesTo(
|
||||
gd::Project& originalProject,
|
||||
gd::Project& clonedProject,
|
||||
AbstractFileSystem& fs,
|
||||
gd::String destinationDirectory,
|
||||
bool preserveAbsoluteFilenames,
|
||||
bool preserveDirectoryStructure) {
|
||||
|
||||
// Check if there are some resources with absolute filenames
|
||||
gd::ResourcesAbsolutePathChecker absolutePathChecker(fs);
|
||||
gd::ResourcesAbsolutePathChecker absolutePathChecker(originalProject.GetResourcesManager(), fs);
|
||||
gd::ResourceExposer::ExposeWholeProjectResources(originalProject, absolutePathChecker);
|
||||
|
||||
auto projectDirectory = fs.DirNameFrom(originalProject.GetProjectFile());
|
||||
@@ -34,24 +55,18 @@ bool ProjectResourcesCopier::CopyAllResourcesTo(
|
||||
<< destinationDirectory << "..." << std::endl;
|
||||
|
||||
// Get the resources to be copied
|
||||
gd::ResourcesMergingHelper resourcesMergingHelper(fs);
|
||||
gd::ResourcesMergingHelper resourcesMergingHelper(
|
||||
clonedProject.GetResourcesManager(), fs);
|
||||
resourcesMergingHelper.SetBaseDirectory(projectDirectory);
|
||||
resourcesMergingHelper.PreserveDirectoriesStructure(
|
||||
preserveDirectoryStructure);
|
||||
resourcesMergingHelper.PreserveAbsoluteFilenames(
|
||||
preserveAbsoluteFilenames);
|
||||
|
||||
if (updateOriginalProject) {
|
||||
gd::ResourceExposer::ExposeWholeProjectResources(originalProject, resourcesMergingHelper);
|
||||
} else {
|
||||
std::shared_ptr<gd::Project> project(new gd::Project(originalProject));
|
||||
gd::ResourceExposer::ExposeWholeProjectResources(*project, resourcesMergingHelper);
|
||||
}
|
||||
resourcesMergingHelper.PreserveAbsoluteFilenames(preserveAbsoluteFilenames);
|
||||
gd::ResourceExposer::ExposeWholeProjectResources(clonedProject,
|
||||
resourcesMergingHelper);
|
||||
|
||||
// Copy resources
|
||||
map<gd::String, gd::String>& resourcesNewFilename =
|
||||
resourcesMergingHelper.GetAllResourcesOldAndNewFilename();
|
||||
unsigned int i = 0;
|
||||
for (map<gd::String, gd::String>::const_iterator it =
|
||||
resourcesNewFilename.begin();
|
||||
it != resourcesNewFilename.end();
|
||||
@@ -71,8 +86,6 @@ bool ProjectResourcesCopier::CopyAllResourcesTo(
|
||||
destinationFile + _("\"."));
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@@ -3,9 +3,10 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef PROJECTRESOURCESCOPIER_H
|
||||
#define PROJECTRESOURCESCOPIER_H
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Project;
|
||||
class AbstractFileSystem;
|
||||
@@ -47,8 +48,14 @@ class GD_CORE_API ProjectResourcesCopier {
|
||||
bool updateOriginalProject,
|
||||
bool preserveAbsoluteFilenames = true,
|
||||
bool preserveDirectoryStructure = true);
|
||||
|
||||
private:
|
||||
static bool CopyAllResourcesTo(gd::Project& originalProject,
|
||||
gd::Project& clonedProject,
|
||||
gd::AbstractFileSystem& fs,
|
||||
gd::String destinationDirectory,
|
||||
bool preserveAbsoluteFilenames = true,
|
||||
bool preserveDirectoryStructure = true);
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // PROJECTRESOURCESCOPIER_H
|
||||
|
@@ -3,8 +3,7 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef RESOURCESABSOLUTEPATHCHECKER_H
|
||||
#define RESOURCESABSOLUTEPATHCHECKER_H
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/IDE/AbstractFileSystem.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
@@ -22,10 +21,10 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API ResourcesAbsolutePathChecker
|
||||
: public ArbitraryResourceWorker {
|
||||
public:
|
||||
ResourcesAbsolutePathChecker(AbstractFileSystem& fileSystem)
|
||||
: ArbitraryResourceWorker(),
|
||||
hasAbsoluteFilenames(false),
|
||||
public:
|
||||
ResourcesAbsolutePathChecker(gd::ResourcesManager &resourcesManager,
|
||||
AbstractFileSystem &fileSystem)
|
||||
: ArbitraryResourceWorker(resourcesManager), hasAbsoluteFilenames(false),
|
||||
fs(fileSystem){};
|
||||
virtual ~ResourcesAbsolutePathChecker(){};
|
||||
|
||||
@@ -47,5 +46,3 @@ class GD_CORE_API ResourcesAbsolutePathChecker
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // RESOURCESABSOLUTEPATHCHECKER_H
|
||||
|
25
Core/GDCore/IDE/Project/ResourcesInUseHelper.cpp
Normal file
25
Core/GDCore/IDE/Project/ResourcesInUseHelper.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "ResourcesInUseHelper.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
const std::vector<gd::String> ResourcesInUseHelper::resourceTypes = {
|
||||
"image", "audio", "font", "json", "tilemap",
|
||||
"tileset", "video", "bitmapFont", "model3D"};
|
||||
|
||||
const std::vector<gd::String> &ResourcesInUseHelper::GetAllResources() {
|
||||
allResources.clear();
|
||||
for (auto &&resourceType : gd::ResourcesInUseHelper::resourceTypes) {
|
||||
for (auto &&resourceName : GetAll(resourceType)) {
|
||||
allResources.push_back(resourceName);
|
||||
}
|
||||
}
|
||||
return allResources;
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -4,9 +4,7 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef IMAGESUSEDINVENTORIZER_H
|
||||
#define IMAGESUSEDINVENTORIZER_H
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
@@ -33,10 +31,12 @@ std::set<gd::String> & usedImages = resourcesInUse.GetAllImages();
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class ResourcesInUseHelper : public gd::ArbitraryResourceWorker {
|
||||
public:
|
||||
ResourcesInUseHelper() : gd::ArbitraryResourceWorker(){};
|
||||
public:
|
||||
ResourcesInUseHelper(gd::ResourcesManager &resourcesManager)
|
||||
: gd::ArbitraryResourceWorker(resourcesManager){};
|
||||
virtual ~ResourcesInUseHelper(){};
|
||||
|
||||
const std::vector<gd::String>& GetAllResources();
|
||||
std::set<gd::String>& GetAllImages() { return GetAll("image"); };
|
||||
std::set<gd::String>& GetAllAudios() { return GetAll("audio"); };
|
||||
std::set<gd::String>& GetAllFonts() { return GetAll("font"); };
|
||||
@@ -46,6 +46,8 @@ class ResourcesInUseHelper : public gd::ArbitraryResourceWorker {
|
||||
std::set<gd::String>& GetAllVideos() { return GetAll("video"); };
|
||||
std::set<gd::String>& GetAllBitmapFonts() { return GetAll("bitmapFont"); };
|
||||
std::set<gd::String>& GetAll3DModels() { return GetAll("model3D"); };
|
||||
std::set<gd::String>& GetAllAtlases() { return GetAll("atlas"); };
|
||||
std::set<gd::String>& GetAllSpines() { return GetAll("spine"); };
|
||||
std::set<gd::String>& GetAll(const gd::String& resourceType) {
|
||||
if (resourceType == "image") return allImages;
|
||||
if (resourceType == "audio") return allAudios;
|
||||
@@ -56,6 +58,8 @@ class ResourcesInUseHelper : public gd::ArbitraryResourceWorker {
|
||||
if (resourceType == "video") return allVideos;
|
||||
if (resourceType == "bitmapFont") return allBitmapFonts;
|
||||
if (resourceType == "model3D") return allModel3Ds;
|
||||
if (resourceType == "atlas") return allAtlases;
|
||||
if (resourceType == "spine") return allSpines;
|
||||
|
||||
return emptyResources;
|
||||
};
|
||||
@@ -63,35 +67,42 @@ class ResourcesInUseHelper : public gd::ArbitraryResourceWorker {
|
||||
virtual void ExposeFile(gd::String& resource) override{
|
||||
/*Don't care, we just list resource names*/
|
||||
};
|
||||
virtual void ExposeImage(gd::String& imageResourceName) override {
|
||||
allImages.insert(imageResourceName);
|
||||
virtual void ExposeImage(gd::String& resourceName) override {
|
||||
allImages.insert(resourceName);
|
||||
};
|
||||
virtual void ExposeAudio(gd::String& audioResourceName) override {
|
||||
allAudios.insert(audioResourceName);
|
||||
virtual void ExposeAudio(gd::String& resourceName) override {
|
||||
allAudios.insert(resourceName);
|
||||
};
|
||||
virtual void ExposeFont(gd::String& fontResourceName) override {
|
||||
allFonts.insert(fontResourceName);
|
||||
virtual void ExposeFont(gd::String& resourceName) override {
|
||||
allFonts.insert(resourceName);
|
||||
};
|
||||
virtual void ExposeJson(gd::String& jsonResourceName) override {
|
||||
allJsons.insert(jsonResourceName);
|
||||
virtual void ExposeJson(gd::String& resourceName) override {
|
||||
allJsons.insert(resourceName);
|
||||
};
|
||||
virtual void ExposeTilemap(gd::String& tilemapResourceName) override {
|
||||
allTilemaps.insert(tilemapResourceName);
|
||||
virtual void ExposeTilemap(gd::String& resourceName) override {
|
||||
allTilemaps.insert(resourceName);
|
||||
};
|
||||
virtual void ExposeTileset(gd::String& tilesetResourceName) override {
|
||||
allTilesets.insert(tilesetResourceName);
|
||||
virtual void ExposeTileset(gd::String& resourceName) override {
|
||||
allTilesets.insert(resourceName);
|
||||
};
|
||||
virtual void ExposeVideo(gd::String& videoResourceName) override {
|
||||
allVideos.insert(videoResourceName);
|
||||
virtual void ExposeVideo(gd::String& resourceName) override {
|
||||
allVideos.insert(resourceName);
|
||||
};
|
||||
virtual void ExposeBitmapFont(gd::String& bitmapFontResourceName) override {
|
||||
allBitmapFonts.insert(bitmapFontResourceName);
|
||||
virtual void ExposeBitmapFont(gd::String& resourceName) override {
|
||||
allBitmapFonts.insert(resourceName);
|
||||
};
|
||||
virtual void ExposeModel3D(gd::String& resourceName) override {
|
||||
allModel3Ds.insert(resourceName);
|
||||
};
|
||||
virtual void ExposeAtlas(gd::String& resourceName) override {
|
||||
allAtlases.insert(resourceName);
|
||||
};
|
||||
virtual void ExposeSpine(gd::String& resourceName) override {
|
||||
allSpines.insert(resourceName);
|
||||
};
|
||||
|
||||
protected:
|
||||
std::vector<gd::String> allResources;
|
||||
std::set<gd::String> allImages;
|
||||
std::set<gd::String> allAudios;
|
||||
std::set<gd::String> allFonts;
|
||||
@@ -101,10 +112,11 @@ class ResourcesInUseHelper : public gd::ArbitraryResourceWorker {
|
||||
std::set<gd::String> allVideos;
|
||||
std::set<gd::String> allBitmapFonts;
|
||||
std::set<gd::String> allModel3Ds;
|
||||
std::set<gd::String> allAtlases;
|
||||
std::set<gd::String> allSpines;
|
||||
std::set<gd::String> emptyResources;
|
||||
|
||||
static const std::vector<gd::String> resourceTypes;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // IMAGESUSEDINVENTORIZER_H
|
||||
#endif
|
||||
|
@@ -28,7 +28,7 @@ void ResourcesMergingHelper::ExposeFile(gd::String& resourceFilename) {
|
||||
auto stripToFilenameOnly = [&]() {
|
||||
fs.MakeAbsolute(resourceFullFilename, baseDirectory);
|
||||
SetNewFilename(resourceFullFilename, fs.FileNameFrom(resourceFullFilename));
|
||||
resourceFilename = oldFilenames[resourceFullFilename];
|
||||
resourceFilename = newFilenames[resourceFullFilename];
|
||||
};
|
||||
|
||||
// if we do not want to preserve the folders at all,
|
||||
@@ -45,7 +45,7 @@ void ResourcesMergingHelper::ExposeFile(gd::String& resourceFilename) {
|
||||
gd::String relativeFilename = resourceFullFilename;
|
||||
if (fs.MakeRelative(relativeFilename, baseDirectory)) {
|
||||
SetNewFilename(resourceFullFilename, relativeFilename);
|
||||
resourceFilename = oldFilenames[resourceFullFilename];
|
||||
resourceFilename = newFilenames[resourceFullFilename];
|
||||
} else {
|
||||
// The filename cannot be made relative. Consider that it is absolute.
|
||||
// Just strip the filename to its file part
|
||||
@@ -63,7 +63,7 @@ void ResourcesMergingHelper::ExposeFile(gd::String& resourceFilename) {
|
||||
|
||||
void ResourcesMergingHelper::SetNewFilename(gd::String oldFilename,
|
||||
gd::String newFilename) {
|
||||
if (oldFilenames.find(oldFilename) != oldFilenames.end()) return;
|
||||
if (newFilenames.find(oldFilename) != newFilenames.end()) return;
|
||||
|
||||
// Extract baseName and extension from the new filename
|
||||
size_t extensionPos = newFilename.find_last_of(".");
|
||||
@@ -80,13 +80,13 @@ void ResourcesMergingHelper::SetNewFilename(gd::String oldFilename,
|
||||
gd::NewNameGenerator::Generate(
|
||||
baseName,
|
||||
[this, extension](const gd::String& newBaseName) {
|
||||
return newFilenames.find(newBaseName + extension) !=
|
||||
newFilenames.end();
|
||||
return oldFilenames.find(newBaseName + extension) !=
|
||||
oldFilenames.end();
|
||||
}) +
|
||||
extension;
|
||||
|
||||
oldFilenames[oldFilename] = finalFilename;
|
||||
newFilenames[finalFilename] = oldFilename;
|
||||
newFilenames[oldFilename] = finalFilename;
|
||||
oldFilenames[finalFilename] = oldFilename;
|
||||
}
|
||||
|
||||
void ResourcesMergingHelper::SetBaseDirectory(
|
||||
|
@@ -28,11 +28,11 @@ namespace gd {
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ResourcesMergingHelper : public ArbitraryResourceWorker {
|
||||
public:
|
||||
ResourcesMergingHelper(gd::AbstractFileSystem& fileSystem)
|
||||
: ArbitraryResourceWorker(),
|
||||
preserveDirectoriesStructure(false),
|
||||
preserveAbsoluteFilenames(false),
|
||||
public:
|
||||
ResourcesMergingHelper(gd::ResourcesManager &resourcesManager,
|
||||
gd::AbstractFileSystem &fileSystem)
|
||||
: ArbitraryResourceWorker(resourcesManager),
|
||||
preserveDirectoriesStructure(false), preserveAbsoluteFilenames(false),
|
||||
fs(fileSystem){};
|
||||
virtual ~ResourcesMergingHelper(){};
|
||||
|
||||
@@ -64,19 +64,25 @@ class GD_CORE_API ResourcesMergingHelper : public ArbitraryResourceWorker {
|
||||
* the Base Directory.
|
||||
*/
|
||||
std::map<gd::String, gd::String>& GetAllResourcesOldAndNewFilename() {
|
||||
return oldFilenames;
|
||||
return newFilenames;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resources merging helper collects all resources filenames and update these
|
||||
* filenames.
|
||||
*/
|
||||
virtual void ExposeFile(gd::String& resource) override;
|
||||
void ExposeFile(gd::String& resource) override;
|
||||
|
||||
protected:
|
||||
void SetNewFilename(gd::String oldFilename, gd::String newFilename);
|
||||
|
||||
/**
|
||||
* Original file names that can be accessed by their new name.
|
||||
*/
|
||||
std::map<gd::String, gd::String> oldFilenames;
|
||||
/**
|
||||
* New file names that can be accessed by their original name.
|
||||
*/
|
||||
std::map<gd::String, gd::String> newFilenames;
|
||||
gd::String baseDirectory;
|
||||
bool preserveDirectoriesStructure; ///< If set to true, the directory
|
||||
|
@@ -22,13 +22,16 @@ namespace gd {
|
||||
*/
|
||||
class ResourcesRenamer : public gd::ArbitraryResourceWorker {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor taking the map from old name to new name.
|
||||
* @param oldToNewNames_ A map associating to a resource name the new name to
|
||||
* use.
|
||||
*/
|
||||
ResourcesRenamer(const std::map<gd::String, gd::String>& oldToNewNames_)
|
||||
: gd::ArbitraryResourceWorker(), oldToNewNames(oldToNewNames_){};
|
||||
/**
|
||||
* @brief Constructor taking the map from old name to new name.
|
||||
* @param oldToNewNames_ A map associating to a resource name the new name to
|
||||
* use.
|
||||
*/
|
||||
ResourcesRenamer(gd::ResourcesManager &resourcesManager,
|
||||
const std::map<gd::String, gd::String> &oldToNewNames_)
|
||||
: gd::ArbitraryResourceWorker(resourcesManager),
|
||||
oldToNewNames(oldToNewNames_){};
|
||||
|
||||
virtual ~ResourcesRenamer(){};
|
||||
|
||||
virtual void ExposeFile(gd::String& resourceFileName) override{
|
||||
@@ -62,6 +65,12 @@ class ResourcesRenamer : public gd::ArbitraryResourceWorker {
|
||||
virtual void ExposeModel3D(gd::String& resourceName) override {
|
||||
RenameIfNeeded(resourceName);
|
||||
};
|
||||
virtual void ExposeAtlas(gd::String& resourceName) override {
|
||||
RenameIfNeeded(resourceName);
|
||||
};
|
||||
virtual void ExposeSpine(gd::String& resourceName) override {
|
||||
RenameIfNeeded(resourceName);
|
||||
};
|
||||
|
||||
private:
|
||||
void RenameIfNeeded(gd::String& resourceName) {
|
||||
|
37
Core/GDCore/IDE/Project/SceneResourcesFinder.cpp
Normal file
37
Core/GDCore/IDE/Project/SceneResourcesFinder.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* GDevelop JS Platform
|
||||
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "SceneResourcesFinder.h"
|
||||
|
||||
#include "GDCore/IDE/ResourceExposer.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
std::set<gd::String> SceneResourcesFinder::FindProjectResources(gd::Project &project) {
|
||||
gd::SceneResourcesFinder resourceWorker(project.GetResourcesManager());
|
||||
|
||||
gd::ResourceExposer::ExposeProjectResources(project, resourceWorker);
|
||||
return resourceWorker.resourceNames;
|
||||
}
|
||||
|
||||
std::set<gd::String> SceneResourcesFinder::FindSceneResources(gd::Project &project,
|
||||
gd::Layout &layout) {
|
||||
gd::SceneResourcesFinder resourceWorker(project.GetResourcesManager());
|
||||
|
||||
gd::ResourceExposer::ExposeLayoutResources(project, layout, resourceWorker);
|
||||
return resourceWorker.resourceNames;
|
||||
}
|
||||
|
||||
void SceneResourcesFinder::AddUsedResource(gd::String &resourceName) {
|
||||
if (resourceName.empty()) {
|
||||
return;
|
||||
}
|
||||
resourceNames.insert(resourceName);
|
||||
}
|
||||
|
||||
} // namespace gd
|
93
Core/GDCore/IDE/Project/SceneResourcesFinder.h
Normal file
93
Core/GDCore/IDE/Project/SceneResourcesFinder.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* GDevelop JS Platform
|
||||
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace gd {
|
||||
class Project;
|
||||
class Layout;
|
||||
class SerializerElement;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Find resource usages in several parts of the project.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class SceneResourcesFinder : private gd::ArbitraryResourceWorker {
|
||||
public:
|
||||
/**
|
||||
* @brief Find resource usages in a given scenes.
|
||||
*
|
||||
* It doesn't include resources used globally.
|
||||
*/
|
||||
static std::set<gd::String> FindSceneResources(gd::Project &project,
|
||||
gd::Layout &layout);
|
||||
|
||||
/**
|
||||
* @brief Find resource that are used globally in the project.
|
||||
*
|
||||
* It doesn't include resources used in scenes.
|
||||
*/
|
||||
static std::set<gd::String> FindProjectResources(gd::Project &project);
|
||||
|
||||
virtual ~SceneResourcesFinder(){};
|
||||
|
||||
private:
|
||||
SceneResourcesFinder(gd::ResourcesManager &resourcesManager)
|
||||
: gd::ArbitraryResourceWorker(resourcesManager){};
|
||||
|
||||
void AddUsedResource(gd::String &resourceName);
|
||||
|
||||
void ExposeFile(gd::String &resourceFileName) override{
|
||||
// Don't do anything: we're renaming resources, not the files they are
|
||||
// pointing to.
|
||||
};
|
||||
void ExposeImage(gd::String &imageResourceName) override {
|
||||
AddUsedResource(imageResourceName);
|
||||
};
|
||||
void ExposeAudio(gd::String &audioResourceName) override {
|
||||
AddUsedResource(audioResourceName);
|
||||
};
|
||||
void ExposeFont(gd::String &fontResourceName) override {
|
||||
AddUsedResource(fontResourceName);
|
||||
};
|
||||
void ExposeJson(gd::String &jsonResourceName) override {
|
||||
AddUsedResource(jsonResourceName);
|
||||
};
|
||||
void ExposeTilemap(gd::String &tilemapResourceName) override {
|
||||
AddUsedResource(tilemapResourceName);
|
||||
};
|
||||
void ExposeTileset(gd::String &tilesetResourceName) override {
|
||||
AddUsedResource(tilesetResourceName);
|
||||
};
|
||||
void ExposeVideo(gd::String &videoResourceName) override {
|
||||
AddUsedResource(videoResourceName);
|
||||
};
|
||||
void ExposeBitmapFont(gd::String &bitmapFontName) override {
|
||||
AddUsedResource(bitmapFontName);
|
||||
};
|
||||
void ExposeModel3D(gd::String &resourceName) override {
|
||||
AddUsedResource(resourceName);
|
||||
};
|
||||
void ExposeAtlas(gd::String &resourceName) override {
|
||||
AddUsedResource(resourceName);
|
||||
};
|
||||
void ExposeSpine(gd::String &resourceName) override {
|
||||
AddUsedResource(resourceName);
|
||||
};
|
||||
|
||||
std::set<gd::String> resourceNames;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -20,6 +20,7 @@
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/IDE/DependenciesAnalyzer.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -33,27 +34,8 @@ void ProjectBrowserHelper::ExposeProjectEvents(
|
||||
// Add events based extensions
|
||||
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
|
||||
e++) {
|
||||
// Add (free) events functions
|
||||
auto &eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
|
||||
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
|
||||
worker.Launch(eventsFunction->GetEvents());
|
||||
}
|
||||
|
||||
// Add (behavior) events functions
|
||||
for (auto &&eventsBasedBehavior :
|
||||
eventsFunctionsExtension.GetEventsBasedBehaviors()
|
||||
.GetInternalVector()) {
|
||||
ExposeEventsBasedBehaviorEvents(project, *eventsBasedBehavior, worker);
|
||||
}
|
||||
|
||||
// Add (object) events functions
|
||||
for (auto &&eventsBasedObject :
|
||||
eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) {
|
||||
auto &objectEventsFunctions = eventsBasedObject->GetEventsFunctions();
|
||||
for (auto &&eventsFunction : objectEventsFunctions.GetInternalVector()) {
|
||||
worker.Launch(eventsFunction->GetEvents());
|
||||
}
|
||||
}
|
||||
ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(project, eventsFunctionsExtension, worker);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +51,7 @@ void ProjectBrowserHelper::ExposeProjectEventsWithoutExtensions(
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeLayoutEvents(
|
||||
void ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
|
||||
gd::Project &project, gd::Layout &layout,
|
||||
gd::ArbitraryEventsWorker &worker) {
|
||||
|
||||
@@ -85,7 +67,7 @@ void ProjectBrowserHelper::ExposeLayoutEvents(
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeLayoutEvents(
|
||||
void ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
|
||||
gd::Project &project, gd::Layout &layout,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
auto projectScopedContainers =
|
||||
@@ -103,6 +85,32 @@ void ProjectBrowserHelper::ExposeLayoutEvents(
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeLayoutEventsAndDependencies(
|
||||
gd::Project &project, gd::Layout &layout,
|
||||
gd::ArbitraryEventsWorker &worker) {
|
||||
// Add layouts events
|
||||
worker.Launch(layout.GetEvents());
|
||||
|
||||
DependenciesAnalyzer dependenciesAnalyzer(project, layout);
|
||||
bool hasCircularDependencies = !dependenciesAnalyzer.Analyze();
|
||||
if (hasCircularDependencies) {
|
||||
// The analyzer stops when it finds circular dependencies so the dependencies are not complete.
|
||||
// TODO Should the analyzer still continue to avoid side effect on thing that would not be code generation related?
|
||||
// Maybe a boolean parameter should be added?
|
||||
return;
|
||||
}
|
||||
for (const gd::String& externalEventName : dependenciesAnalyzer.GetExternalEventsDependencies()) {
|
||||
gd::ExternalEvents& externalEvents = project.GetExternalEvents(externalEventName);
|
||||
|
||||
worker.Launch(externalEvents.GetEvents());
|
||||
}
|
||||
for (const gd::String& sceneName : dependenciesAnalyzer.GetScenesDependencies()) {
|
||||
gd::Layout& dependencyLayout = project.GetLayout(sceneName);
|
||||
|
||||
worker.Launch(dependencyLayout.GetEvents());
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeProjectEvents(
|
||||
gd::Project &project, gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
// See also gd::Project::ExposeResources for a method that traverse the whole
|
||||
@@ -130,19 +138,17 @@ void ProjectBrowserHelper::ExposeProjectEvents(
|
||||
// Add events based extensions
|
||||
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
|
||||
e++) {
|
||||
// Add (free) events functions
|
||||
auto &eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
|
||||
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
project, eventsFunctionsExtension, *eventsFunction,
|
||||
globalObjectsAndGroups, objectsAndGroups);
|
||||
auto projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsAndGroups, objectsAndGroups);
|
||||
projectScopedContainers.AddParameters(eventsFunction->GetParametersForEvents(eventsFunctionsExtension));
|
||||
ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(project, eventsFunctionsExtension, worker);
|
||||
}
|
||||
}
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
|
||||
void ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
|
||||
gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::ArbitraryEventsWorker &worker) {
|
||||
// Add (free) events functions
|
||||
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
|
||||
worker.Launch(eventsFunction->GetEvents());
|
||||
}
|
||||
|
||||
// Add (behavior) events functions
|
||||
@@ -157,7 +163,34 @@ void ProjectBrowserHelper::ExposeProjectEvents(
|
||||
eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) {
|
||||
ExposeEventsBasedObjectEvents(project, *eventsBasedObject, worker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
|
||||
gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
// Add (free) events functions
|
||||
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
|
||||
gd::ObjectsContainer parameterObjectsContainer;
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project, eventsFunctionsExtension, *eventsFunction,
|
||||
parameterObjectsContainer);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
|
||||
}
|
||||
|
||||
// Add (behavior) events functions
|
||||
for (auto &&eventsBasedBehavior :
|
||||
eventsFunctionsExtension.GetEventsBasedBehaviors()
|
||||
.GetInternalVector()) {
|
||||
ExposeEventsBasedBehaviorEvents(project, eventsFunctionsExtension, *eventsBasedBehavior, worker);
|
||||
}
|
||||
|
||||
// Add (object) events functions
|
||||
for (auto &&eventsBasedObject :
|
||||
eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) {
|
||||
ExposeEventsBasedObjectEvents(project, eventsFunctionsExtension, *eventsBasedObject, worker);
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
@@ -170,20 +203,17 @@ void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
gd::Project &project, const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
auto &behaviorEventsFunctions = eventsBasedBehavior.GetEventsFunctions();
|
||||
for (auto &&eventsFunction : behaviorEventsFunctions.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
|
||||
project, eventsBasedBehavior, *eventsFunction, globalObjectsAndGroups,
|
||||
objectsAndGroups);
|
||||
auto projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsAndGroups, objectsAndGroups);
|
||||
projectScopedContainers.AddPropertiesContainer(eventsBasedBehavior.GetSharedPropertyDescriptors());
|
||||
projectScopedContainers.AddPropertiesContainer(eventsBasedBehavior.GetPropertyDescriptors());
|
||||
projectScopedContainers.AddParameters(eventsFunction->GetParametersForEvents(eventsBasedBehavior.GetEventsFunctions()));
|
||||
|
||||
gd::ObjectsContainer parameterObjectsContainers;
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForBehaviorEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior,
|
||||
*eventsFunction, parameterObjectsContainers);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
|
||||
}
|
||||
@@ -191,18 +221,26 @@ void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
|
||||
void ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
|
||||
gd::Project &project, const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ArbitraryEventsWorker &worker) {
|
||||
auto &objectEventsFunctions = eventsBasedObject.GetEventsFunctions();
|
||||
for (auto &&eventsFunction : objectEventsFunctions.GetInternalVector()) {
|
||||
worker.Launch(eventsFunction->GetEvents());
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
auto &objectEventsFunctions = eventsBasedObject.GetEventsFunctions();
|
||||
for (auto &&eventsFunction : objectEventsFunctions.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
project, eventsBasedObject, *eventsFunction, globalObjectsAndGroups,
|
||||
objectsAndGroups);
|
||||
auto projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsAndGroups, objectsAndGroups);
|
||||
projectScopedContainers.AddPropertiesContainer(eventsBasedObject.GetPropertyDescriptors());
|
||||
projectScopedContainers.AddParameters(eventsFunction->GetParametersForEvents(eventsBasedObject.GetEventsFunctions()));
|
||||
|
||||
gd::ObjectsContainer parameterObjectsContainers;
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForObjectEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsBasedObject,
|
||||
*eventsFunction, parameterObjectsContainers);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
|
||||
}
|
||||
@@ -216,7 +254,7 @@ void ProjectBrowserHelper::ExposeProjectObjects(
|
||||
|
||||
// Layout objects
|
||||
for (size_t i = 0; i < project.GetLayoutsCount(); i++) {
|
||||
worker.Launch(project.GetLayout(i));
|
||||
gd::ProjectBrowserHelper::ExposeLayoutObjects(project.GetLayout(i), worker);
|
||||
}
|
||||
|
||||
// Event based objects children
|
||||
@@ -232,6 +270,14 @@ void ProjectBrowserHelper::ExposeProjectObjects(
|
||||
}
|
||||
};
|
||||
|
||||
void ProjectBrowserHelper::ExposeLayoutObjects(gd::Layout &layout,
|
||||
gd::ArbitraryObjectsWorker &worker) {
|
||||
// In the future, layouts may have children object containers.
|
||||
|
||||
// Layout objects
|
||||
worker.Launch(layout);
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeProjectFunctions(
|
||||
gd::Project &project, gd::ArbitraryEventsFunctionsWorker &worker) {
|
||||
|
||||
|
@@ -60,18 +60,52 @@ public:
|
||||
* \brief Call the specified worker on all events of a layout and
|
||||
* its external events.
|
||||
*/
|
||||
static void ExposeLayoutEvents(gd::Project &project, gd::Layout &layout,
|
||||
static void ExposeLayoutEventsAndExternalEvents(gd::Project &project, gd::Layout &layout,
|
||||
gd::ArbitraryEventsWorker &worker);
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all events of a layout and
|
||||
* its external events.
|
||||
*/
|
||||
static void ExposeLayoutEvents(gd::Project &project, gd::Layout &layout,
|
||||
static void ExposeLayoutEventsAndExternalEvents(gd::Project &project, gd::Layout &layout,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker);
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all events of a layout and
|
||||
* its dependencies according to EventLink (external events or other layout
|
||||
* events).
|
||||
*/
|
||||
static void
|
||||
ExposeLayoutEventsAndDependencies(gd::Project &project, gd::Layout &layout,
|
||||
gd::ArbitraryEventsWorker &worker);
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all events of the event-based
|
||||
* behavior
|
||||
* extension.
|
||||
*
|
||||
* This should be the preferred way to traverse all the events of an events
|
||||
* based extension.
|
||||
*/
|
||||
static void ExposeEventsFunctionsExtensionEvents(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::ArbitraryEventsWorker &worker);
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all events of the event-based
|
||||
* extension.
|
||||
*
|
||||
* This should be the preferred way to traverse all the events of an events
|
||||
* based extension.
|
||||
*/
|
||||
static void ExposeEventsFunctionsExtensionEvents(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker);
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all events of the event-based
|
||||
* behavior.
|
||||
*
|
||||
* This should be the preferred way to traverse all the events of an events
|
||||
* based behavior.
|
||||
@@ -88,20 +122,35 @@ public:
|
||||
* event-based behavior.
|
||||
*/
|
||||
static void ExposeEventsBasedBehaviorEvents(
|
||||
gd::Project &project, const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker);
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all events of the event-based
|
||||
* behavior.
|
||||
* object.
|
||||
*
|
||||
* This should be the preferred way to traverse all the events of an
|
||||
* event-based behavior.
|
||||
* event-based object.
|
||||
*/
|
||||
static void
|
||||
ExposeEventsBasedObjectEvents(gd::Project &project,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker);
|
||||
gd::ArbitraryEventsWorker &worker);
|
||||
|
||||
/**
|
||||
* \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.
|
||||
*/
|
||||
static void ExposeEventsBasedObjectEvents(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker);
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all ObjectContainers of the project
|
||||
@@ -112,6 +161,14 @@ public:
|
||||
static void ExposeProjectObjects(gd::Project &project,
|
||||
gd::ArbitraryObjectsWorker &worker);
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all ObjectContainers of the layout.
|
||||
*
|
||||
* This should be the preferred way to traverse all the objects of a layout.
|
||||
*/
|
||||
static void ExposeLayoutObjects(gd::Layout &layout,
|
||||
gd::ArbitraryObjectsWorker &worker);
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all FunctionsContainers of the project
|
||||
* (global, layouts...)
|
||||
|
@@ -30,14 +30,18 @@ void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project &project) {
|
||||
project.GetLayout(i).GetEvents().Clear();
|
||||
}
|
||||
|
||||
// Keep the EventsBasedObject object list because it's useful for the Runtime
|
||||
// Keep:
|
||||
// - the EventsBasedObject object list because it's useful for the Runtime
|
||||
// to create the child-object.
|
||||
// - the globalVariables and sceneVariables
|
||||
for (unsigned int extensionIndex = 0;
|
||||
extensionIndex < project.GetEventsFunctionsExtensionsCount();
|
||||
++extensionIndex) {
|
||||
auto &extension = project.GetEventsFunctionsExtension(extensionIndex);
|
||||
auto &eventsBasedObjects = extension.GetEventsBasedObjects();
|
||||
if (eventsBasedObjects.size() == 0) {
|
||||
if (eventsBasedObjects.size() == 0 &&
|
||||
extension.GetGlobalVariables().Count() == 0 &&
|
||||
extension.GetSceneVariables().Count() == 0) {
|
||||
project.RemoveEventsFunctionsExtension(extension.GetName());
|
||||
extensionIndex--;
|
||||
continue;
|
||||
@@ -51,6 +55,7 @@ void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project &project) {
|
||||
eventsBasedObject.GetPropertyDescriptors().GetInternalVector().clear();
|
||||
}
|
||||
extension.GetEventsBasedBehaviors().Clear();
|
||||
extension.ClearEventsFunctions();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -128,11 +128,7 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
|
||||
} else {
|
||||
gd::Instruction action;
|
||||
action.SetType("SetReturn" + numberOrString);
|
||||
gd::String receiver = isBehavior ? "Object.Behavior::" : "Object.";
|
||||
gd::String propertyPrefix =
|
||||
(isSharedProperties ? "SharedProperty" : "Property");
|
||||
action.AddParameter(receiver + propertyPrefix + property.GetName() +
|
||||
"()");
|
||||
action.AddParameter(property.GetName());
|
||||
event.GetActions().Insert(action, 0);
|
||||
}
|
||||
}
|
||||
@@ -233,15 +229,13 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
|
||||
gd::Instruction action;
|
||||
action.SetType(setterType);
|
||||
action.AddParameter("Object");
|
||||
gd::String parameterGetterCall =
|
||||
"GetArgumentAs" + numberOrString + "(\"Value\")";
|
||||
if (isBehavior) {
|
||||
action.AddParameter("Behavior");
|
||||
action.AddParameter("=");
|
||||
action.AddParameter(parameterGetterCall);
|
||||
action.AddParameter("Value");
|
||||
} else {
|
||||
action.AddParameter("=");
|
||||
action.AddParameter(parameterGetterCall);
|
||||
action.AddParameter("Value");
|
||||
}
|
||||
event.GetActions().Insert(action, 0);
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#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 {
|
||||
|
||||
@@ -32,10 +33,9 @@ void ResourceExposer::ExposeWholeProjectResources(gd::Project& project, gd::Arbi
|
||||
// traverse the whole project (this time for events) and ExposeProjectEffects
|
||||
// (this time for effects).
|
||||
|
||||
gd::ResourcesManager* resourcesManager = &(project.GetResourcesManager());
|
||||
|
||||
// Expose any project resources as files.
|
||||
worker.ExposeResources(resourcesManager);
|
||||
worker.ExposeResources();
|
||||
|
||||
project.GetPlatformSpecificAssets().ExposeResources(worker);
|
||||
|
||||
// Expose event resources
|
||||
@@ -73,6 +73,49 @@ void ResourceExposer::ExposeWholeProjectResources(gd::Project& project, gd::Arbi
|
||||
worker.ExposeImage(loadingScreen.GetBackgroundImageResourceName());
|
||||
}
|
||||
|
||||
void ResourceExposer::ExposeProjectResources(gd::Project& project, gd::ArbitraryResourceWorker& worker) {
|
||||
// Expose global objects configuration resources
|
||||
auto objectWorker = gd::GetResourceWorkerOnObjects(project, worker);
|
||||
objectWorker.Launch(project);
|
||||
}
|
||||
|
||||
void ResourceExposer::ExposeLayoutResources(
|
||||
gd::Project &project, gd::Layout &layout,
|
||||
gd::ArbitraryResourceWorker &worker) {
|
||||
|
||||
// Expose object configuration resources
|
||||
auto objectWorker = gd::GetResourceWorkerOnObjects(project, worker);
|
||||
gd::ProjectBrowserHelper::ExposeLayoutObjects(layout, objectWorker);
|
||||
|
||||
// Expose layer effect resources
|
||||
for (std::size_t layerIndex = 0; layerIndex < layout.GetLayersCount();
|
||||
layerIndex++) {
|
||||
auto &layer = layout.GetLayer(layerIndex);
|
||||
|
||||
auto &effects = layer.GetEffects();
|
||||
for (size_t effectIndex = 0; effectIndex < effects.GetEffectsCount();
|
||||
effectIndex++) {
|
||||
auto &effect = effects.GetEffect(effectIndex);
|
||||
gd::ResourceExposer::ExposeEffectResources(project.GetCurrentPlatform(),
|
||||
effect, worker);
|
||||
}
|
||||
}
|
||||
|
||||
// Expose event resources
|
||||
auto eventWorker = gd::GetResourceWorkerOnEvents(project, worker);
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEventsAndDependencies(project, layout,
|
||||
eventWorker);
|
||||
|
||||
// Exposed extension event resources
|
||||
// Note that using resources in extensions is very unlikely and probably not
|
||||
// worth the effort of something smart.
|
||||
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
|
||||
e++) {
|
||||
auto &eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
|
||||
gd::ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(project, eventsFunctionsExtension, eventWorker);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceExposer::ExposeEffectResources(
|
||||
gd::Platform &platform, gd::Effect &effect,
|
||||
gd::ArbitraryResourceWorker &worker) {
|
||||
@@ -88,11 +131,13 @@ void ResourceExposer::ExposeEffectResources(
|
||||
auto &resourceType = propertyDescriptor.GetExtraInfo()[0];
|
||||
|
||||
const gd::String &resourceName = effect.GetStringParameter(propertyName);
|
||||
gd::String potentiallyUpdatedResourceName = resourceName;
|
||||
worker.ExposeResourceWithType(resourceType,
|
||||
potentiallyUpdatedResourceName);
|
||||
if (potentiallyUpdatedResourceName != resourceName) {
|
||||
effect.SetStringParameter(propertyName, potentiallyUpdatedResourceName);
|
||||
if (!resourceName.empty()) {
|
||||
gd::String potentiallyUpdatedResourceName = resourceName;
|
||||
worker.ExposeResourceWithType(resourceType,
|
||||
potentiallyUpdatedResourceName);
|
||||
if (potentiallyUpdatedResourceName != resourceName) {
|
||||
effect.SetStringParameter(propertyName, potentiallyUpdatedResourceName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ class Platform;
|
||||
class Project;
|
||||
class ArbitraryResourceWorker;
|
||||
class Effect;
|
||||
class Layout;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -31,6 +32,25 @@ public:
|
||||
static void ExposeWholeProjectResources(gd::Project &project,
|
||||
gd::ArbitraryResourceWorker &worker);
|
||||
|
||||
/**
|
||||
* @brief Expose only the resources used globally on a project.
|
||||
*
|
||||
* It doesn't include resources used in layouts.
|
||||
*/
|
||||
static void ExposeProjectResources(gd::Project &project,
|
||||
gd::ArbitraryResourceWorker &worker);
|
||||
|
||||
/**
|
||||
* @brief Expose the resources used in a given layout.
|
||||
*
|
||||
* It doesn't include resources used globally.
|
||||
*/
|
||||
static void ExposeLayoutResources(gd::Project &project, gd::Layout &layout,
|
||||
gd::ArbitraryResourceWorker &worker);
|
||||
|
||||
/**
|
||||
* @brief Expose the resources used in a given effect.
|
||||
*/
|
||||
static void ExposeEffectResources(gd::Platform &platform, gd::Effect &effect,
|
||||
gd::ArbitraryResourceWorker &worker);
|
||||
};
|
||||
|
241
Core/GDCore/IDE/VariableInstructionSwitcher.cpp
Normal file
241
Core/GDCore/IDE/VariableInstructionSwitcher.cpp
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "VariableInstructionSwitcher.h"
|
||||
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariablePathFinder.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
const gd::String VariableInstructionSwitcher::variableGetterIdentifier =
|
||||
"NumberVariable";
|
||||
const gd::String VariableInstructionSwitcher::variableSetterIdentifier =
|
||||
"SetNumberVariable";
|
||||
const gd::String VariableInstructionSwitcher::variablePushIdentifier =
|
||||
"PushNumber";
|
||||
const gd::String VariableInstructionSwitcher::objectVariableGetterIdentifier =
|
||||
"NumberObjectVariable";
|
||||
const gd::String VariableInstructionSwitcher::objectVariableSetterIdentifier =
|
||||
"SetNumberObjectVariable";
|
||||
const gd::String VariableInstructionSwitcher::objectVariablePushIdentifier =
|
||||
"PushNumberToObjectVariable";
|
||||
const gd::String VariableInstructionSwitcher::unknownInstructionIdentifier = "";
|
||||
|
||||
bool VariableInstructionSwitcher::IsSwitchableVariableInstruction(
|
||||
const gd::String &instructionType) {
|
||||
return instructionType == "NumberVariable" ||
|
||||
instructionType == "StringVariable" ||
|
||||
instructionType == "BooleanVariable" ||
|
||||
|
||||
instructionType == "SetNumberVariable" ||
|
||||
instructionType == "SetStringVariable" ||
|
||||
instructionType == "SetBooleanVariable" ||
|
||||
|
||||
instructionType == "PushNumber" || instructionType == "PushString" ||
|
||||
instructionType == "PushBoolean" ||
|
||||
|
||||
IsSwitchableObjectVariableInstruction(instructionType);
|
||||
}
|
||||
|
||||
bool VariableInstructionSwitcher::IsSwitchableObjectVariableInstruction(
|
||||
const gd::String &instructionType) {
|
||||
return instructionType == "NumberObjectVariable" ||
|
||||
instructionType == "StringObjectVariable" ||
|
||||
instructionType == "BooleanObjectVariable" ||
|
||||
|
||||
instructionType == "SetNumberObjectVariable" ||
|
||||
instructionType == "SetStringObjectVariable" ||
|
||||
instructionType == "SetBooleanObjectVariable" ||
|
||||
|
||||
instructionType == "PushNumberToObjectVariable" ||
|
||||
instructionType == "PushStringToObjectVariable" ||
|
||||
instructionType == "PushBooleanToObjectVariable";
|
||||
}
|
||||
|
||||
const gd::String &
|
||||
VariableInstructionSwitcher::GetSwitchableVariableInstructionIdentifier(
|
||||
const gd::String &instructionType) {
|
||||
return instructionType == "NumberVariable" ||
|
||||
instructionType == "StringVariable" ||
|
||||
instructionType == "BooleanVariable"
|
||||
? VariableInstructionSwitcher::variableGetterIdentifier
|
||||
:
|
||||
|
||||
instructionType == "SetNumberVariable" ||
|
||||
instructionType == "SetStringVariable" ||
|
||||
instructionType == "SetBooleanVariable"
|
||||
? VariableInstructionSwitcher::variableSetterIdentifier
|
||||
:
|
||||
|
||||
instructionType == "PushNumber" || instructionType == "PushString" ||
|
||||
instructionType == "PushBoolean"
|
||||
? VariableInstructionSwitcher::variablePushIdentifier
|
||||
:
|
||||
|
||||
instructionType == "NumberObjectVariable" ||
|
||||
instructionType == "StringObjectVariable" ||
|
||||
instructionType == "BooleanObjectVariable"
|
||||
? VariableInstructionSwitcher::objectVariableGetterIdentifier
|
||||
:
|
||||
|
||||
instructionType == "SetNumberObjectVariable" ||
|
||||
instructionType == "SetStringObjectVariable" ||
|
||||
instructionType == "SetBooleanObjectVariable"
|
||||
? VariableInstructionSwitcher::objectVariableSetterIdentifier
|
||||
:
|
||||
|
||||
instructionType == "PushNumberToObjectVariable" ||
|
||||
instructionType == "PushStringToObjectVariable" ||
|
||||
instructionType == "PushBooleanToObjectVariable"
|
||||
? VariableInstructionSwitcher::objectVariablePushIdentifier
|
||||
:
|
||||
|
||||
VariableInstructionSwitcher::unknownInstructionIdentifier;
|
||||
}
|
||||
|
||||
const gd::Variable::Type
|
||||
VariableInstructionSwitcher::GetSwitchableInstructionVariableType(
|
||||
const gd::String &instructionType) {
|
||||
return instructionType == "NumberVariable" ||
|
||||
instructionType == "SetNumberVariable" ||
|
||||
instructionType == "PushNumber" ||
|
||||
instructionType == "NumberObjectVariable" ||
|
||||
instructionType == "SetNumberObjectVariable" ||
|
||||
instructionType == "PushNumberToObjectVariable"
|
||||
? gd::Variable::Number
|
||||
:
|
||||
|
||||
instructionType == "StringVariable" ||
|
||||
instructionType == "SetStringVariable" ||
|
||||
instructionType == "PushString" ||
|
||||
instructionType == "StringObjectVariable" ||
|
||||
instructionType == "SetStringObjectVariable" ||
|
||||
instructionType == "PushStringToObjectVariable"
|
||||
? gd::Variable::String
|
||||
:
|
||||
|
||||
instructionType == "BooleanVariable" ||
|
||||
instructionType == "SetBooleanVariable" ||
|
||||
instructionType == "PushBoolean" ||
|
||||
instructionType == "BooleanObjectVariable" ||
|
||||
instructionType == "SetBooleanObjectVariable" ||
|
||||
instructionType == "PushBooleanToObjectVariable"
|
||||
? gd::Variable::Boolean
|
||||
:
|
||||
|
||||
gd::Variable::Unknown;
|
||||
}
|
||||
|
||||
void VariableInstructionSwitcher::SwitchVariableInstructionType(
|
||||
gd::Instruction &instruction, const gd::Variable::Type variableType) {
|
||||
if (instruction.GetType() == "NumberVariable" ||
|
||||
instruction.GetType() == "StringVariable" ||
|
||||
instruction.GetType() == "BooleanVariable") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("NumberVariable");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("StringVariable");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("BooleanVariable");
|
||||
}
|
||||
} else if (instruction.GetType() == "SetNumberVariable" ||
|
||||
instruction.GetType() == "SetStringVariable" ||
|
||||
instruction.GetType() == "SetBooleanVariable") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("SetNumberVariable");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("SetStringVariable");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("SetBooleanVariable");
|
||||
}
|
||||
} else if (instruction.GetType() == "PushNumber" ||
|
||||
instruction.GetType() == "PushString" ||
|
||||
instruction.GetType() == "PushBoolean") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("PushNumber");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("PushString");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("PushBoolean");
|
||||
}
|
||||
} else if (instruction.GetType() == "NumberObjectVariable" ||
|
||||
instruction.GetType() == "StringObjectVariable" ||
|
||||
instruction.GetType() == "BooleanObjectVariable") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("NumberObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("StringObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("BooleanObjectVariable");
|
||||
}
|
||||
} else if (instruction.GetType() == "SetNumberObjectVariable" ||
|
||||
instruction.GetType() == "SetStringObjectVariable" ||
|
||||
instruction.GetType() == "SetBooleanObjectVariable") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("SetNumberObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("SetStringObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("SetBooleanObjectVariable");
|
||||
}
|
||||
} else if (instruction.GetType() == "PushNumberToObjectVariable" ||
|
||||
instruction.GetType() == "PushStringToObjectVariable" ||
|
||||
instruction.GetType() == "PushBooleanToObjectVariable") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("PushNumberToObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("PushStringToObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("PushBooleanToObjectVariable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const gd::Variable::Type
|
||||
VariableInstructionSwitcher::GetVariableTypeFromParameters(
|
||||
const gd::Platform &platform,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
const gd::Instruction &instruction) {
|
||||
if (instruction.GetParametersCount() < 2 ||
|
||||
!gd::VariableInstructionSwitcher::IsSwitchableVariableInstruction(
|
||||
instruction.GetType())) {
|
||||
return gd::Variable::Type::Unknown;
|
||||
}
|
||||
const bool isObjectVariable =
|
||||
gd::VariableInstructionSwitcher::IsSwitchableObjectVariableInstruction(
|
||||
instruction.GetType());
|
||||
const gd::String &objectName =
|
||||
isObjectVariable ? instruction.GetParameter(0).GetPlainString() : "";
|
||||
|
||||
const std::size_t variableParameterIndex = isObjectVariable ? 1 : 0;
|
||||
auto &variableExpressionNode =
|
||||
*instruction.GetParameter(variableParameterIndex).GetRootNode();
|
||||
|
||||
auto variableType = gd::ExpressionVariablePathFinder::GetVariableType(
|
||||
platform, projectScopedContainers, variableExpressionNode, objectName);
|
||||
return variableType == gd::Variable::Type::Array
|
||||
? // "Push" actions need the child type to be able to switch.
|
||||
gd::ExpressionVariablePathFinder::GetArrayVariableType(
|
||||
platform, projectScopedContainers, variableExpressionNode,
|
||||
objectName)
|
||||
: variableType;
|
||||
}
|
||||
|
||||
void VariableInstructionSwitcher::SwitchBetweenUnifiedInstructionIfNeeded(
|
||||
const gd::Platform &platform,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::Instruction &instruction) {
|
||||
const auto variableType =
|
||||
gd::VariableInstructionSwitcher::GetVariableTypeFromParameters(
|
||||
platform, projectScopedContainers, instruction);
|
||||
if (variableType != gd::Variable::Type::Unknown) {
|
||||
gd::VariableInstructionSwitcher::SwitchVariableInstructionType(
|
||||
instruction, variableType);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user