Compare commits
1061 Commits
Author | SHA1 | Date |
---|---|---|
|
1a192b6129 | |
|
8e3f37d46a | |
|
98778c1645 | |
|
7ca4c63191 | |
|
8788d8bf12 | |
|
f31d722320 | |
|
bbb4512437 | |
|
43ec612949 | |
|
998bf212b7 | |
|
ec8eb4bf91 | |
|
05cd3e67b0 | |
|
ed9762e62f | |
|
ac0b68aa13 | |
|
c3da26caba | |
|
e9f6a6fea5 | |
|
c3144875df | |
|
e37ff39641 | |
|
6292ee4404 | |
|
77dc9b3b85 | |
|
88701e9f20 | |
|
576df4092a | |
|
b8f266588a | |
|
eac7e56f42 | |
|
7aebed5897 | |
|
a6613c32f9 | |
|
76e02a75e5 | |
|
1b9cf17339 | |
|
0584b0401f | |
|
98917a2055 | |
|
10defe21a5 | |
|
3dcbee829c | |
|
e3be34670e | |
|
e3262108d7 | |
|
b144ebc7bc | |
|
672f92c87b | |
|
e2e42b90a8 | |
|
a952009293 | |
|
0982804a86 | |
|
dd427c25e2 | |
|
dddc713a3a | |
|
6fecc1e4b5 | |
|
fe87a87759 | |
|
0e0a4685f9 | |
|
955da07652 | |
|
90c0a9a4f6 | |
|
1359f1e606 | |
|
0d65c1117a | |
|
a5118ebc1b | |
|
17872e7048 | |
|
f7a63ca673 | |
|
691208016c | |
|
35a2cbac56 | |
|
db827a8d30 | |
|
360e24c330 | |
|
e9884589a8 | |
|
9cfdabca3f | |
|
23a6e5fdfe | |
|
6644f191ca | |
|
8b0b15fce4 | |
|
11548c51f0 | |
|
62a142f188 | |
|
7a3d5bc6a2 | |
|
6d79b7474e | |
|
44040dda06 | |
|
ba90deaa6a | |
|
08d8fcdf92 | |
|
51878e4b6e | |
|
008702b1e4 | |
|
6e8c22d598 | |
|
0b3b11a383 | |
|
4cac6276aa | |
|
ea671dd54b | |
|
bc7f677810 | |
|
057d4e669c | |
|
f600d633a3 | |
|
ae61d551c0 | |
|
a14cc4cc68 | |
|
d304f957ef | |
|
bf85350260 | |
|
03476721d9 | |
|
bebd6a15eb | |
|
4c9028fc66 | |
|
e21156df35 | |
|
591a1fe672 | |
|
f90c48eb81 | |
|
162de0f868 | |
|
423c4ce7a4 | |
|
a5d59a0a51 | |
|
85eda3c804 | |
|
6de8b9e4c4 | |
|
bbe71bb378 | |
|
7feff38d6b | |
|
632e26c922 | |
|
106608aca9 | |
|
d5bc62830a | |
|
3b15abf2c9 | |
|
6d049a3701 | |
|
65454c36a8 | |
|
e0e15b0ec4 | |
|
ee8c773e71 | |
|
7f38fe2b8b | |
|
500775eb14 | |
|
1cdde4d5a9 | |
|
eaa43020f5 | |
|
b5b1ac7289 | |
|
ece17d68d9 | |
|
85787616e7 | |
|
11abf36c99 | |
|
19d771fef2 | |
|
2b89d1d23e | |
|
6f318b83b8 | |
|
7a1b56f9c8 | |
|
2b86928737 | |
|
8c557f87f7 | |
|
6776319472 | |
|
760af804c0 | |
|
c49e5142a5 | |
|
60a767032e | |
|
60142b191d | |
|
134bb3214a | |
|
db7c990f51 | |
|
08884e6180 | |
|
c2130a7b2f | |
|
5ddc43fe94 | |
|
601aed3684 | |
|
0e4c06f3b8 | |
|
ac2d734122 | |
|
1ca1154cd0 | |
|
a8a0f24492 | |
|
50e9e570dd | |
|
d72c2e0648 | |
|
da2bc5e3bb | |
|
c4481d8bed | |
|
689c8fab6f | |
|
fd0eb34b4e | |
|
bfcc2f8e1b | |
|
b8c9db0d44 | |
|
4df6647a75 | |
|
d78adabf7c | |
|
1742018696 | |
|
a460c7898b | |
|
8ee3688da2 | |
|
9032ca0c7b | |
|
1cb85807dd | |
|
78396708d4 | |
|
6c86ce566c | |
|
16a3bb0273 | |
|
ac209e7fc3 | |
|
49b3a0ad6f | |
|
ad11f401b1 | |
|
d972b2e7ff | |
|
a5517313d2 | |
|
f694980c6d | |
|
b981d430f1 | |
|
c0bc484f0c | |
|
af68b1eebc | |
|
f83cf659e8 | |
|
bd0dcb3184 | |
|
338c9c8ccb | |
|
a92fb9da8e | |
|
9da16a1e0f | |
|
472f360cf9 | |
|
c94ec7613d | |
|
9ae61e0556 | |
|
9c8d782fb2 | |
|
d709389c87 | |
|
f550ddd23f | |
|
f232069dc4 | |
|
6fabad213e | |
|
cc3d650d23 | |
|
3a4caeb298 | |
|
ee404c828a | |
|
43035839b1 | |
|
cfacd57f15 | |
|
000f9c15d8 | |
|
d7438b8a8d | |
|
b59db1eee8 | |
|
26cf0bb6b4 | |
|
635ada23dd | |
|
e12beee51e | |
|
1f6cc8e55c | |
|
f8ab80defa | |
|
314fcfd741 | |
|
6ada9cef2f | |
|
410efbe0d3 | |
|
85d5af180b | |
|
b4eec2c364 | |
|
02af29f2fa | |
|
3a40de482f | |
|
1e1fb5adaf | |
|
80e3ff705d | |
|
10b90b70fe | |
|
7708a11840 | |
|
98accb1aa8 | |
|
bf33917cfd | |
|
304bd86220 | |
|
629062ea26 | |
|
2528741333 | |
|
d5becadd59 | |
|
7b0d0aa779 | |
|
650e381659 | |
|
6134d5130c | |
|
32d74427e5 | |
|
f14a19b947 | |
|
1b04a8589f | |
|
abb2af7d27 | |
|
84becbe914 | |
|
549a595b42 | |
|
a56272a248 | |
|
63de416066 | |
|
c19fd54927 | |
|
f8c6e83688 | |
|
5a4893fc53 | |
|
14d8df0858 | |
|
868baa470a | |
|
319c5787be | |
|
1e9b321283 | |
|
8b2770116d | |
|
40863313dd | |
|
ee12a56e96 | |
|
0f82fa3d64 | |
|
df11afaf44 | |
|
d2ba904243 | |
|
63ef3e0555 | |
|
869b6465b9 | |
|
91edd1c0b5 | |
|
6b4c97e545 | |
|
5f5b62a4ea | |
|
68a9492f3d | |
|
9abfe4ce95 | |
|
6c794d6a7e | |
|
47ad95b265 | |
|
c4c9b5fe09 | |
|
fc26f51ff2 | |
|
a2a62f636b | |
|
ce1867be7a | |
|
09185211ff | |
|
9e79183579 | |
|
bed04dbf87 | |
|
64df43c7c9 | |
|
d7daa027ee | |
|
abe9a26460 | |
|
2c58cfc3cb | |
|
a1d6276097 | |
|
afc2b63f06 | |
|
af27aca021 | |
|
dad5082e7e | |
|
6aa4e63929 | |
|
8568572092 | |
|
3cce7aa0a6 | |
|
f1dba8f061 | |
|
17eb029497 | |
|
456687c857 | |
|
186ee3c6a7 | |
|
0e059c8a52 | |
|
17ccd50806 | |
|
b478c8eb2c | |
|
cf99a27692 | |
|
f7eb374c1e | |
|
a7881a0eea | |
|
0934e4e672 | |
|
ddbfa132a5 | |
|
7c57c7dd62 | |
|
3565d6dc43 | |
|
18ee21554e | |
|
7073db7bfa | |
|
3e5e34f5f8 | |
|
0f9c566a63 | |
|
86d31f5f00 | |
|
5f40d38f8d | |
|
800bc8f16d | |
|
40acd04eb9 | |
|
f1af947060 | |
|
5f5e4a28cc | |
|
254a9ca943 | |
|
3ceedbebad | |
|
bc99965205 | |
|
cfa1f70d79 | |
|
7c0d49bafa | |
|
da9d80d110 | |
|
4787413cb6 | |
|
2813728785 | |
|
2973590533 | |
|
b74f664da6 | |
|
7baa395d3f | |
|
b305041f28 | |
|
7d6cc1a828 | |
|
4d0d2c0507 | |
|
4cba3b39db | |
|
872f7a4532 | |
|
6432dae35d | |
|
ed19d787f6 | |
|
e3305782f2 | |
|
d98be526b6 | |
|
ae3b4ebb94 | |
|
2f62b53b6a | |
|
8dfbd70718 | |
|
4d4f0d7886 | |
|
cd0bc8e796 | |
|
5e89a82743 | |
|
d2ca303c5e | |
|
fe597a5a46 | |
|
d20d28be78 | |
|
2f1fd6fb62 | |
|
022d95434d | |
|
ce28ed92d2 | |
|
8f294ac5ea | |
|
9410031d45 | |
|
61b2db5a07 | |
|
15464e288c | |
|
4467ebbbd9 | |
|
a2dedabd77 | |
|
2356e6c967 | |
|
b712fe25dc | |
|
5bdec804b3 | |
|
2784937ca8 | |
|
d383e9d1a4 | |
|
4f1b22c668 | |
|
8fa609ef9e | |
|
c6851259e8 | |
|
5a60ad9308 | |
|
7a90fdb113 | |
|
3bc8343e8b | |
|
1c7eb994d4 | |
|
c76278b735 | |
|
fc53078130 | |
|
88583a8a2e | |
|
d6076d131f | |
|
2d1c5fa4ba | |
|
7eaebc4e7c | |
|
db73133f1b | |
|
7c0c81d141 | |
|
adff6bd08c | |
|
06de52492a | |
|
2c8e0d2da0 | |
|
ce5f012101 | |
|
3bca05bc50 | |
|
56bb91df0a | |
|
c793c8ba53 | |
|
808ca1de7f | |
|
809efc1be2 | |
|
29532113c0 | |
|
1e6c3fa92b | |
|
35f2c3c142 | |
|
49f5e3be79 | |
|
a04d4aaca4 | |
|
08ad6c1d99 | |
|
c9825413c0 | |
|
990438db55 | |
|
2b299c0007 | |
|
88e468c526 | |
|
a0cd983927 | |
|
792502db84 | |
|
5f5ecc2db1 | |
|
361eb3eb15 | |
|
dbb89e6883 | |
|
fa3034d190 | |
|
9e0489a034 | |
|
a7d4b1e7f7 | |
|
127fa678f4 | |
|
e0d47ddf08 | |
|
57382e10a7 | |
|
0a28feb7a9 | |
|
6f8f95b5de | |
|
e9eec23c3e | |
|
d0fcea5574 | |
|
e059429760 | |
|
918095622c | |
|
23c19c11e6 | |
|
bc2c4a26ac | |
|
83214fc93b | |
|
e062669cf7 | |
|
2e94bf8bf2 | |
|
e8816091e6 | |
|
fc1b99a5b1 | |
|
04300e5222 | |
|
2f326e5b6f | |
|
064d00fdfa | |
|
ff61d55c44 | |
|
7ab7a9d098 | |
|
b54f3696ff | |
|
dc77ecd2b2 | |
|
026272f7f7 | |
|
d08018b7b1 | |
|
00396dce61 | |
|
69201fa877 | |
|
d920060dee | |
|
2718271bb1 | |
|
3cf90f9387 | |
|
c6b1a40627 | |
|
d36f8f1122 | |
|
a572613001 | |
|
c30c5a4d7a | |
|
ef1c1e5192 | |
|
3b12288ae0 | |
|
a1cdff2e2e | |
|
e43bc25d82 | |
|
549d73b8fc | |
|
0d1e846d93 | |
|
2d493a76bd | |
|
bdfe5f52c2 | |
|
e55611a1a9 | |
|
ba467ad62c | |
|
5e961ec6fa | |
|
bc5d5d8610 | |
|
e5d04b9eda | |
|
e36ea6d3e6 | |
|
803da63fa8 | |
|
84c89356a6 | |
|
a2dae24b99 | |
|
af23272e3d | |
|
506d8aa967 | |
|
5dff2e537b | |
|
75e8e68da4 | |
|
4fe4049c3a | |
|
69e921be31 | |
|
c6bb5bad74 | |
|
2c2f2dd4be | |
|
dedffc4f22 | |
|
4491a23d52 | |
|
0e843d3193 | |
|
769de9a7e2 | |
|
2bfedec518 | |
|
29d4b92bf4 | |
|
40850067c8 | |
|
f45e954e62 | |
|
40ea2ce01a | |
|
e1c8ce4a58 | |
|
af0250dc60 | |
|
4207fbf8f3 | |
|
03de485ebb | |
|
7f89659110 | |
|
1a37540797 | |
|
c4df916bdf | |
|
5048d6a485 | |
|
24382d3fd1 | |
|
5045e5b864 | |
|
c739a876b0 | |
|
5e63477f9b | |
|
09562ffbd3 | |
|
ceeb4dbeb3 | |
|
0ff93faacc | |
|
3918272227 | |
|
302de87e32 | |
|
d48daf2135 | |
|
5ff42e29e4 | |
|
7160804c82 | |
|
58d7ea223e | |
|
e50b00c70e | |
|
31db4b4543 | |
|
671ca50b82 | |
|
a5aea72a17 | |
|
1de6256401 | |
|
930493101d | |
|
ebc2ce310f | |
|
12fd9d00d6 | |
|
f36f5af92a | |
|
94a277ef9d | |
|
6c8045b280 | |
|
6edb7017b9 | |
|
9e62fe8fa3 | |
|
79d72c39e0 | |
|
5a8fe97aac | |
|
d9a9a1d4e5 | |
|
06ea008105 | |
|
705f4d7415 | |
|
cbd467f97f | |
|
088ef008a6 | |
|
06ebff7518 | |
|
39c4511249 | |
|
ca6b497019 | |
|
434545ebad | |
|
a6e6b53e18 | |
|
7de582c4e6 | |
|
e2edb083ff | |
|
b09006a11b | |
|
92010f19f1 | |
|
b0e31f569a | |
|
eba867706b | |
|
3ae38ee5da | |
|
0be16edee0 | |
|
37d3dcd988 | |
|
b0e3753d76 | |
|
9957ef2ea7 | |
|
f4ceb27b35 | |
|
fda6fd5b8f | |
|
b90b85f0c3 | |
|
e182a56f7e | |
|
653bf13a7d | |
|
dd837ff472 | |
|
3f34e4dde2 | |
|
41dafe642a | |
|
25c72302ca | |
|
81f49be6b4 | |
|
2658060b1c | |
|
f452552ecd | |
|
193743e782 | |
|
27f3982250 | |
|
4c26583007 | |
|
ae718ab00c | |
|
bea25049a0 | |
|
0bd52d9b18 | |
|
d66f1e83fd | |
|
923587e6e2 | |
|
ecf1e4b65f | |
|
7cf4a4b3b8 | |
|
88df78c4a2 | |
|
84aeb4bfff | |
|
350c27abbc | |
|
b7d1bc11ab | |
|
e1bddb5d02 | |
|
507da30f04 | |
|
6b376e5e9a | |
|
73aa636271 | |
|
f5d21e2669 | |
|
c96e2019af | |
|
bb6fab7555 | |
|
c4931ae420 | |
|
ba462c9526 | |
|
e260498776 | |
|
6f9ff6a487 | |
|
aab38c9fb9 | |
|
6d877c800a | |
|
543f2bb32c | |
|
eaeb57e2d7 | |
|
1aa64f8c5d | |
|
24730a9213 | |
|
7626c84633 | |
|
2d98a38ada | |
|
c7a4988e6c | |
|
1c01767a56 | |
|
9fbbea49a9 | |
|
01d643831c | |
|
9d99e8bf9f | |
|
d393784bbe | |
|
c8ad4dc956 | |
|
b8d054a080 | |
|
0caa2369c6 | |
|
fb958c7c34 | |
|
8176d5c83c | |
|
5b478b6229 | |
|
27327cf18e | |
|
487c008f5c | |
|
e7f1d3a424 | |
|
0f0a09cc5e | |
|
dad8d86d3e | |
|
e1d03d651a | |
|
291a40d33a | |
|
cac44eadc7 | |
|
78c61d459d | |
|
b3380bd0ac | |
|
7ebdfc9026 | |
|
ecf44e83e0 | |
|
b9cd31eb2b | |
|
0ea8b9932c | |
|
38409d45f9 | |
|
1711cb6b87 | |
|
b220a9f418 | |
|
91f3148493 | |
|
5909735add | |
|
bc3fe05a4d | |
|
d9c6a64a62 | |
|
ed69bcf0bb | |
|
ac2052bd4b | |
|
3c9fc333b0 | |
|
17291081e5 | |
|
b0245457db | |
|
b5247dda0f | |
|
69751260a6 | |
|
8e2fdc4bc0 | |
|
8a226a1160 | |
|
e09928f87f | |
|
cd4e28f391 | |
|
9443c50d94 | |
|
9eb7a9c346 | |
|
1de059d806 | |
|
dae96feeb9 | |
|
f54c86f9fc | |
|
22eea7be0e | |
|
adc9490672 | |
|
7949330c90 | |
|
c925bab659 | |
|
73152b5760 | |
|
065b6dc29b | |
|
102a770c42 | |
|
2451cf801f | |
|
51012571ae | |
|
39d1440b96 | |
|
2fd15f04d6 | |
|
dc8aaa6098 | |
|
778ee80dda | |
|
fa804f3f6d | |
|
79813d57a8 | |
|
f6ce516771 | |
|
92ecc17a44 | |
|
d0ff58052d | |
|
c8ecaf6c8c | |
|
8bce9cceb7 | |
|
154bd2a839 | |
|
bea67b9a87 | |
|
688a5416f2 | |
|
e9e582f251 | |
|
f85555675b | |
|
597a795d6b | |
|
c61f265454 | |
|
67d86214f0 | |
|
4719c77f94 | |
|
828f4dbad5 | |
|
da8c5b9a83 | |
|
c2603554e6 | |
|
1d35d84ec5 | |
|
a839be1ada | |
|
47c0c4e85c | |
|
55fb102838 | |
|
dd3eebabf1 | |
|
58ff47d688 | |
|
a60280ccfb | |
|
be0b5233c0 | |
|
fcedf681cd | |
|
69bcc763f7 | |
|
0081731654 | |
|
6d36d20d06 | |
|
5621b433c9 | |
|
3a6dc1e90c | |
|
55dfd55645 | |
|
e6e2f5595d | |
|
654eda1c65 | |
|
899335d1fe | |
|
95c2496adf | |
|
98a685b592 | |
|
d38e6f97f1 | |
|
fca8aea99c | |
|
22c472fdd1 | |
|
8260954654 | |
|
6405f9031b | |
|
449538d6d3 | |
|
6713ea1590 | |
|
16840057a1 | |
|
a353e561de | |
|
d0c7d98fc4 | |
|
74a3635e1c | |
|
3ce199f628 | |
|
f60fa3a7f2 | |
|
8dc645c9a7 | |
|
c5b92aa676 | |
|
5bd8a90dcd | |
|
3e32051791 | |
|
b0e4c15982 | |
|
b765b2adc8 | |
|
ab564eb631 | |
|
c49f5d2b0a | |
|
9576cdc8e7 | |
|
caff21137d | |
|
61ef929411 | |
|
b4ab521e0f | |
|
ee0795269d | |
|
11f43c2494 | |
|
656bc169b0 | |
|
c44648c69c | |
|
de8d3abbc8 | |
|
011040e46f | |
|
87a1687c74 | |
|
174810fb34 | |
|
7ac1bc2dec | |
|
b8bf8e07e9 | |
|
73f51f23ef | |
|
2612ec0855 | |
|
c81c1ec872 | |
|
a6717ec76d | |
|
761b211740 | |
|
f8ce5c1311 | |
|
662738e6bf | |
|
f912f0acc4 | |
|
a22860b244 | |
|
5fee89b00b | |
|
a251d92aa3 | |
|
8155c2764a | |
|
fb1ab16682 | |
|
06052332b2 | |
|
15e0323919 | |
|
20a995d1d2 | |
|
b04f7530e4 | |
|
f84127657b | |
|
dc40109ade | |
|
8c67886b52 | |
|
a247d0d67b | |
|
6ef0dd942e | |
|
33b455f8d9 | |
|
881a32f92d | |
|
782e72d92d | |
|
a3f8c09766 | |
|
390d4a9385 | |
|
caa1508fea | |
|
db51defddd | |
|
c5be3a725f | |
|
27d3ec7555 | |
|
dc8dcf9d71 | |
|
242c1f03d7 | |
|
7ccda2736d | |
|
a5728a11a0 | |
|
12dbd9e1a6 | |
|
9bfa0268c1 | |
|
1ac96bc330 | |
|
565097e897 | |
|
076269e5e3 | |
|
594097ae4c | |
|
1648728e1b | |
|
3b82946444 | |
|
17a480ed19 | |
|
c63785b5bc | |
|
184361d460 | |
|
aca9784c95 | |
|
61790085cc | |
|
73c6bfe2c7 | |
|
476dc8b0dd | |
|
9b557250b8 | |
|
80781db7cd | |
|
34e763c8f3 | |
|
3fa6d58b01 | |
|
5245f19fa8 | |
|
f9219fd509 | |
|
cbbc0b0135 | |
|
2496869153 | |
|
74a0d44f44 | |
|
48418114da | |
|
cc16879a45 | |
|
46cd946d35 | |
|
c875f9d5d6 | |
|
f546e285b7 | |
|
eec085278a | |
|
947e253bf9 | |
|
1d3cea6b2e | |
|
8cb8f65469 | |
|
392a2ac691 | |
|
c55c6553b2 | |
|
21b5053b72 | |
|
3af6995fd0 | |
|
52f218e6b9 | |
|
e6c87be723 | |
|
0e37d3dfa3 | |
|
ac3da5ab90 | |
|
8e9cc74857 | |
|
1dfa3e9808 | |
|
59537138bc | |
|
68b2aaf9d5 | |
|
a8dc78765b | |
|
835d053c00 | |
|
960f04b0ab | |
|
cdd5159a08 | |
|
1b031dfea3 | |
|
5b475b3273 | |
|
966199e8dc | |
|
c1d0353798 | |
|
a9a38bbffb | |
|
b07fb71359 | |
|
d1030b877c | |
|
59a8ab97d8 | |
|
9645baeb30 | |
|
bb346ef5f2 | |
|
97daa29eda | |
|
73497b1908 | |
|
f9ad9cc794 | |
|
3d86a76db9 | |
|
f5b1b52f67 | |
|
0767c0eee1 | |
|
4f97c1bd24 | |
|
8eed672213 | |
|
2c4e343a48 | |
|
c18fc2abf6 | |
|
c364378e30 | |
|
fb36b6902d | |
|
6ed5bc8203 | |
|
56c3c26572 | |
|
6bcffe712d | |
|
044de6eea0 | |
|
7fc3831384 | |
|
4cf5a18721 | |
|
9e33b81f50 | |
|
22bfb9e3ab | |
|
8af747c599 | |
|
56d7fb91c6 | |
|
ab311c5770 | |
|
586cdb24bd | |
|
3d9426c515 | |
|
3f61204961 | |
|
e03887cdde | |
|
4c93ddabb4 | |
|
a00f370805 | |
|
35f1dabe93 | |
|
a2a2ba1f7b | |
|
c20e0dfc2d | |
|
eccbfc6a0e | |
|
239f6bd94d | |
|
1fb92ca412 | |
|
df231e3f2c | |
|
9abf8a084f | |
|
0f902041e0 | |
|
ed72784766 | |
|
08a8ef9c77 | |
|
f94aca4433 | |
|
0e6c83d07c | |
|
fb8585282d | |
|
a3594e173c | |
|
dfa332490a | |
|
678df76c65 | |
|
2fc5732ed8 | |
|
949583a6b4 | |
|
106abe0b5a | |
|
7bce63fbcb | |
|
91ed8bfe3d | |
|
b4bef31df5 | |
|
b94428b35b | |
|
76b3098ce7 | |
|
5979166c1e | |
|
8c7b19ea12 | |
|
ada246acf9 | |
|
948e99a9ef | |
|
71909648b7 | |
|
60012d984b | |
|
6347311749 | |
|
cc38d257cc | |
|
548ff374ee | |
|
caf1ff86b0 | |
|
3108a9d44b | |
|
c48eeef081 | |
|
554ae5a165 | |
|
1ac24e67bb | |
|
b57528e4dc | |
|
a7bd8b81ea | |
|
9548fb601c | |
|
8a35b17ba6 | |
|
d51be136e1 | |
|
59b2f4af3c | |
|
65346459d3 | |
|
16a55e0f64 | |
|
58848b709c | |
|
f231e854e5 | |
|
55580f25ae | |
|
edfb3527cf | |
|
f4bac67aa9 | |
|
0cb62ea051 | |
|
e8ae3e7b8f | |
|
6e6e9985b2 | |
|
793dba1e07 | |
|
d688953fd8 | |
|
218e4e7361 | |
|
7efca710f2 | |
|
c77b9a92c2 | |
|
52a8dc2a0b | |
|
dca3ba38c0 | |
|
ecc750bfaf | |
|
0ad33e9af6 | |
|
04537d1e96 | |
|
f9f930133f | |
|
bf91be1ff1 | |
|
e05a6fd6ea | |
|
f1694b45ec | |
|
2555c383d6 | |
|
0ae3a53f26 | |
|
166cc8b1d9 | |
|
14c162de39 | |
|
446925adac | |
|
39971b1e1a | |
|
2b13c24277 | |
|
93cba4581a | |
|
d481d43790 | |
|
7dbdd52141 | |
|
8e53f02e00 | |
|
cab9f853c0 | |
|
81b415a6bf | |
|
3d5cbbf50f | |
|
047b75258b | |
|
91d582ab09 | |
|
7324f0462b | |
|
eb58363977 | |
|
cb8c824314 | |
|
f71e158418 | |
|
d887d9ef35 | |
|
0c325e3660 | |
|
f4289ca839 | |
|
84201f6e44 | |
|
d2bde1a805 | |
|
978a47f505 | |
|
00f9e03f02 | |
|
953d98f89c | |
|
b5a44c0807 | |
|
dd978b636c | |
|
cd299bef4b | |
|
27254581a4 | |
|
d0e9bb0ed3 | |
|
1df821fdfa | |
|
52a70fdee5 | |
|
32cbce6b80 | |
|
b33c1cae31 | |
|
a7f6388bd7 | |
|
55e0b7404c | |
|
c94073fb39 | |
|
22d82d7c02 | |
|
e7687d7a57 | |
|
9a4fd8ad12 | |
|
827dc80cce | |
|
efe693347e | |
|
50bcbcf616 | |
|
9ed075120e | |
|
dd01cc82bb | |
|
a998b45341 | |
|
ff4991654f | |
|
f7380db6a2 | |
|
46e45c6cfb | |
|
22f2529b08 | |
|
1753301753 | |
|
5d0d2660f7 | |
|
75a7883184 | |
|
65bd2dbb48 | |
|
9da55981d1 | |
|
c7d7c0fcff | |
|
dc3312cc2e | |
|
a0a2c4e519 | |
|
14128948ee | |
|
bdb158ff27 | |
|
476c4fd497 | |
|
427de50ea1 | |
|
0e10c2022f | |
|
fb98d2f34e | |
|
3e8a158835 | |
|
7767d7c72a | |
|
97eee2a801 | |
|
05486d3907 | |
|
e1604fab67 | |
|
6baa6d5686 | |
|
073cac5e71 | |
|
198954e45f | |
|
029abbfc08 | |
|
3952ba46cb | |
|
fe81b90dc1 | |
|
9ec1675db2 | |
|
eab6ec9323 | |
|
804ff2dddd | |
|
4e9d8d1e18 | |
|
48a149dafa | |
|
8d88d5a7ef | |
|
fe551e0299 | |
|
16b25fa760 | |
|
76689659f7 | |
|
b834175016 | |
|
9ab9599e4f | |
|
8965cb5ce1 | |
|
915ccdc964 | |
|
68fdfb0597 | |
|
6f8292bc2d | |
|
6cf4045e0f | |
|
b9fc99cb2c | |
|
fd87a3633e | |
|
8a5c60322a | |
|
62ab2db885 | |
|
5fe64c5aae | |
|
369aead56a | |
|
f7159123c6 | |
|
3fdcb0b753 | |
|
3667360d35 | |
|
9600e94ee6 | |
|
e3e65994ec | |
|
740f2e2f9e | |
|
7252a37b2c | |
|
dad8d5297f | |
|
108526ec07 | |
|
a625173786 | |
|
8dd61357da | |
|
235d596e59 | |
|
e794436c69 | |
|
4ff1b874f3 | |
|
feab3c1ba9 | |
|
2cc68b23ad | |
|
a07654394b | |
|
5a0ff91658 | |
|
f89b7897f6 | |
|
df92ea02f0 | |
|
25246a1c77 | |
|
e73d4b0959 | |
|
60f1d12246 | |
|
8341396640 | |
|
a601d44517 | |
|
62f964474c | |
|
0bd60bae88 | |
|
cff4626b2d | |
|
04cb2b1560 | |
|
2ffcbf0565 | |
|
26b9327090 | |
|
f489744755 | |
|
a7d86c5356 | |
|
067f73e11e | |
|
2fdcff4886 | |
|
e2d596d44a | |
|
24678e4332 | |
|
4942173e5b | |
|
b33b0c6993 | |
|
00ed65f0fb | |
|
4cabbc6082 | |
|
1cb3b64a29 | |
|
79c71d06f5 | |
|
2afdb4bc95 | |
|
e851011678 | |
|
3f673c6865 | |
|
0ae2b6869a | |
|
17c72b7378 | |
|
a717a3ed8f | |
|
107b94fad6 | |
|
5c3445236f | |
|
b3dedc737e | |
|
985c4812f3 | |
|
a2b123a9be | |
|
03d5de1482 | |
|
8d89f80d6b | |
|
13f5eb1f71 | |
|
21c65541bf | |
|
b1aae71f5f | |
|
46fd93a766 | |
|
d037295e1c | |
|
51fb7b83ae | |
|
4b57c8fd99 | |
|
d642dbedc5 | |
|
015ec64771 | |
|
694eebcf6d | |
|
0c4a98cf35 | |
|
b293d52fbb | |
|
94f6d289a8 | |
|
8e3c4c7570 | |
|
f776779175 | |
|
404c9274f9 | |
|
92b0f24dcb | |
|
0b1d249ebe | |
|
abe1117055 | |
|
fb7ea31a49 | |
|
9eb912816f | |
|
45cf74dca9 | |
|
10e601fcd5 | |
|
f286673dde | |
|
de2137bfd2 | |
|
272824562b | |
|
3741d2ea2c | |
|
b9d3eac5b0 | |
|
557d457c1c | |
|
eb97cd2d5c | |
|
fb9cb06ccb | |
|
d3d5a0c50e | |
|
605444ee0f | |
|
00329bafc9 | |
|
bdb4df82c9 | |
|
ea9d3c77a0 | |
|
a6077e202d | |
|
d6db3f5ed2 | |
|
afe210b014 | |
|
2795c6dcf2 | |
|
5204bf644e | |
|
471a12fec4 | |
|
c8ec35c798 | |
|
34e70d48ce | |
|
b662c10513 | |
|
258437c340 | |
|
458ad5280e | |
|
737bc6b1a2 |
|
@ -0,0 +1 @@
|
|||
ko_fi: limbonaut
|
|
@ -0,0 +1,64 @@
|
|||
name: Bug report
|
||||
description: Report a bug in LimboAI
|
||||
labels:
|
||||
- bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
- Write a descriptive title above.
|
||||
- Search [open](https://github.com/limbonaut/limboai/issues) and [closed](https://github.com/limbonaut/limboai/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported.
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Godot version
|
||||
description: |
|
||||
- Specify the Godot version and hardware information if relevant.
|
||||
- You can copy the version info by clicking on it in the Godot status bar.
|
||||
- Alternatively, you can copy the version and hardware info in Godot using the main menu command "Help -> Copy System Info".
|
||||
placeholder: v4.2.2.limboai+v1.1.0.gha [15073afe3]
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: LimboAI version
|
||||
description: |
|
||||
- Specify the LimboAI version.
|
||||
- You can copy the version info by clicking on it in the toolbar of the LimboAI editor (top-right corner).
|
||||
placeholder: v1.1.0 [8fa609e]
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: variant
|
||||
attributes:
|
||||
label: LimboAI variant
|
||||
description: Which variant of our plugin are you running?
|
||||
options:
|
||||
- GDExtension / AssetLib
|
||||
- Module (custom editor or template build)
|
||||
default: 0
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Issue description
|
||||
description: |
|
||||
- Describe your issue in detail. What doesn't work and how do you expect it to work instead?
|
||||
- Provide screenshots and/or a console output if it helps to convey the problem.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: How to reproduce
|
||||
description: |
|
||||
- Provide a list of steps or sample code that reproduces the issue.
|
||||
- You can provide a small Godot project which reproduces the issue, with no unnecessary files included.
|
||||
- Drag and drop a ZIP archive to upload it (10Mb limit).
|
||||
- Don't include the `.godot` folder in the archive.
|
||||
- Redroduction project helps to find the bug more quickly!
|
||||
validations:
|
||||
required: true
|
|
@ -0,0 +1,14 @@
|
|||
blank_issues_enabled: false
|
||||
|
||||
contact_links:
|
||||
- name: Documentation
|
||||
url: https://limboai.readthedocs.io/en/stable/
|
||||
about: Please see our documentation for more information.
|
||||
|
||||
- name: Discussions
|
||||
url: https://github.com/limbonaut/limboai/discussions
|
||||
about: Need help? Ask questions in Discussions or on our Discord server.
|
||||
|
||||
- name: Discord Server
|
||||
url: https://discord.gg/N5MGC95GpP
|
||||
about: Share your experience or get help on our Discord server.
|
|
@ -0,0 +1,38 @@
|
|||
name: Feature or improvement proposal
|
||||
description: Propose a new feature to be added or improved in LimboAI
|
||||
labels:
|
||||
- enhancement
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
- Write a descriptive title above.
|
||||
- Search [open](https://github.com/limbonaut/limboai/issues) and [closed](https://github.com/limbonaut/limboai/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Problem statement
|
||||
description: |
|
||||
- Describe the problem or limitation you're currently facing with the LimboAI plugin.
|
||||
- If it helps, describe the project you're working on and how it relates to the problem or limitation.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Proposed solution
|
||||
description: |
|
||||
- Describe your proposed solution and how it helps to overcome the problem or limitation.
|
||||
- If it helps, show how it will work with code, pseudo-code, mock-ups, and/or diagrams.
|
||||
- You can include any images or videos with drag'n'drop, and sample code blocks with <code>```</code> tags.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Alternatives
|
||||
description: |
|
||||
- Describe alternative solutions and features you've considered.
|
||||
- If this enhancement will not be used often, can it be worked around with a few clicks or lines of code?
|
||||
validations:
|
||||
required: true
|
|
@ -0,0 +1,33 @@
|
|||
name: Build .NET assemblies
|
||||
|
||||
inputs:
|
||||
platform:
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- linuxbsd
|
||||
- windows
|
||||
- macos
|
||||
bin:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Override GODOT_VERSION_STATUS for NuGet packages
|
||||
shell: bash
|
||||
run: |
|
||||
GODOT_VERSION_STATUS=$(echo "${GODOT_VERSION_STATUS}" | sed "s|+|-|").gha
|
||||
echo "GODOT_VERSION_STATUS=${GODOT_VERSION_STATUS}" >> "$GITHUB_ENV"
|
||||
echo "GODOT_VERSION_STATUS: ${GODOT_VERSION_STATUS}"
|
||||
|
||||
- name: Generate C# glue
|
||||
shell: bash
|
||||
run: |
|
||||
./bin/${{inputs.bin}} --headless --generate-mono-glue ./modules/mono/glue || true
|
||||
|
||||
- name: Build .NET assemblies
|
||||
shell: bash
|
||||
run: |
|
||||
python ./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=${{ inputs.platform }}
|
|
@ -0,0 +1,24 @@
|
|||
name: Setup version
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Set GDEXTENSION_VERSION & LIMBOAI_VERSION
|
||||
shell: bash
|
||||
run: |
|
||||
cd godot-cpp
|
||||
GDEXTENSION_VERSION=$( (git describe --tags --exact-match HEAD || git rev-parse --short HEAD) | sed 's/\(.*\)-\(.*\)/\1/g' )
|
||||
|
||||
if [[ ${GDEXTENSION_VERSION} == godot-* ]]; then
|
||||
GDEXTENSION_VERSION=${GDEXTENSION_VERSION#"godot-"}
|
||||
fi
|
||||
|
||||
echo "GDEXTENSION_VERSION=${GDEXTENSION_VERSION}" >> "$GITHUB_ENV"
|
||||
|
||||
cd ..
|
||||
echo "LIMBOAI_VERSION=$( (git describe --tags --exact-match HEAD || git rev-parse --short HEAD) | sed 's/\(.*\)-\(.*\)/\1.\2/g' )" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Set NAME_PREFIX
|
||||
shell: bash
|
||||
run: |
|
||||
echo "NAME_PREFIX=limboai+${LIMBOAI_VERSION}.gdextension-${GDEXTENSION_VERSION}" >> "$GITHUB_ENV"
|
|
@ -8,11 +8,11 @@ runs:
|
|||
run: |
|
||||
echo "GODOT_VERSION=$( (git describe --tags --exact-match HEAD || git rev-parse --short HEAD) | sed 's/\(.*\)-\(.*\)/\1/g' )" >> "$GITHUB_ENV"
|
||||
cd modules/limboai
|
||||
echo "LIMBOAI_VERSION=$( (git describe --tags --exact-match HEAD || git rev-parse --short HEAD) | sed 's/\(.*\)-\(.*\)/\1/g' )" >> "$GITHUB_ENV"
|
||||
echo "LIMBOAI_VERSION=$( (git describe --tags --exact-match HEAD || git rev-parse --short HEAD) | sed 's/\(.*\)-\(.*\)/\1.\2/g' )" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Set NAME_PREFIX
|
||||
shell: bash
|
||||
run: echo "NAME_PREFIX=godot-${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}" >> "$GITHUB_ENV"
|
||||
run: echo "NAME_PREFIX=limboai+${LIMBOAI_VERSION}.godot-${GODOT_VERSION}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Set GODOT_VERSION_STATUS & BUILD_NAME
|
||||
shell: bash
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
name: Setup Linux toolchain
|
||||
|
||||
inputs:
|
||||
arch:
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Set up environment
|
||||
shell: bash
|
||||
run: |
|
||||
# ! Settings:
|
||||
TOOLCHAIN_64_URL=https://github.com/godotengine/buildroot/releases/download/godot-2020.11.x-2/x86_64-godot-linux-gnu_sdk-buildroot.tar.bz2
|
||||
TOOLCHAIN_64_SHA=16c8302fcb676c1f0fb9df73d6cff250ba1f4286
|
||||
TOOLCHAIN_32_URL=https://github.com/godotengine/buildroot/releases/download/godot-2020.11.x-2/i686-godot-linux-gnu_sdk-buildroot.tar.bz2
|
||||
TOOLCHAIN_32_SHA=6171652abc54ef219e5187bc53660ee4e2f796f4
|
||||
TOOLCHAIN_ARM64_URL=https://github.com/godotengine/buildroot/releases/download/godot-2023.08.x-3/aarch64-godot-linux-gnu_sdk-buildroot.tar.bz2
|
||||
TOOLCHAIN_ARM64_SHA=73bed3d26b92c8b9a93c0ceb6bcce8fe567d1764
|
||||
TOOLCHAIN_ARM32_URL=https://github.com/godotengine/buildroot/releases/download/godot-2023.08.x-3/arm-godot-linux-gnueabihf_sdk-buildroot.tar.bz2
|
||||
TOOLCHAIN_ARM32_SHA=aa5853fd73faec3837c6127649471275d7e61cb2
|
||||
|
||||
# ! Export variables:
|
||||
if [[ "${{ inputs.arch }}" == "x86_64" ]]; then
|
||||
echo "TOOLCHAIN_URL=${TOOLCHAIN_64_URL}" >> "$GITHUB_ENV"
|
||||
echo "TOOLCHAIN_SHA=${TOOLCHAIN_64_SHA}" >> "$GITHUB_ENV"
|
||||
elif [[ "${{ inputs.arch }}" == "x86_32" ]]; then
|
||||
echo "TOOLCHAIN_URL=${TOOLCHAIN_32_URL}" >> "$GITHUB_ENV"
|
||||
echo "TOOLCHAIN_SHA=${TOOLCHAIN_32_SHA}" >> "$GITHUB_ENV"
|
||||
elif [[ "${{ inputs.arch }}" == "arm64" ]]; then
|
||||
echo "TOOLCHAIN_URL=${TOOLCHAIN_ARM64_URL}" >> "$GITHUB_ENV"
|
||||
echo "TOOLCHAIN_SHA=${TOOLCHAIN_ARM64_SHA}" >> "$GITHUB_ENV"
|
||||
elif [[ "${{ inputs.arch }}" == "arm32" ]]; then
|
||||
echo "TOOLCHAIN_URL=${TOOLCHAIN_ARM32_URL}" >> "$GITHUB_ENV"
|
||||
echo "TOOLCHAIN_SHA=${TOOLCHAIN_ARM32_SHA}" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
- name: Cache buildroot
|
||||
id: cache-buildroot
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: buildroot
|
||||
key: ${{env.TOOLCHAIN_SHA}}
|
||||
|
||||
- name: Set up buildroot
|
||||
if: steps.cache-buildroot.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir buildroot
|
||||
wget ${TOOLCHAIN_URL} -O buildroot/buildroot.tar.bz2
|
||||
cd buildroot
|
||||
echo "${TOOLCHAIN_SHA} buildroot.tar.bz2"
|
||||
echo "${TOOLCHAIN_SHA} buildroot.tar.bz2" | shasum --check
|
||||
tar -xjf buildroot.tar.bz2 --strip-components=1
|
||||
ls -l
|
||||
rm buildroot.tar.bz2
|
||||
./relocate-sdk.sh
|
||||
cd ..
|
|
@ -0,0 +1,127 @@
|
|||
name: 🔗 All builds
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
godot-ref:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
default: master
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
godot-cpp-ref:
|
||||
description: A tag, branch or commit hash in the godot-cpp repository.
|
||||
type: string
|
||||
default: master
|
||||
|
||||
jobs:
|
||||
cache-sha:
|
||||
name: Cache SHA
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
godot-sha: ${{ steps.cache-sha.outputs.godot-sha }}
|
||||
limboai-sha: ${{ steps.cache-sha.outputs.limboai-sha }}
|
||||
steps:
|
||||
- name: Clone Godot
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: godotengine/godot
|
||||
ref: ${{ inputs.godot-ref }}
|
||||
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: modules/limboai
|
||||
ref: ${{ inputs.limboai-ref }}
|
||||
|
||||
- name: Cache SHA
|
||||
id: cache-sha
|
||||
run: |
|
||||
echo "godot-sha=$(git describe --tags --exact-match HEAD || git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
|
||||
cd modules/limboai
|
||||
echo "limboai-sha=$(git describe --tags --exact-match HEAD || git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
android-build:
|
||||
name: 🤖 Android
|
||||
needs: cache-sha
|
||||
uses: ./.github/workflows/android.yml
|
||||
with:
|
||||
godot-ref: ${{ needs.cache-sha.outputs.godot-sha }}
|
||||
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
|
||||
|
||||
ios-build:
|
||||
name: 🍏 iOS
|
||||
needs: cache-sha
|
||||
uses: ./.github/workflows/ios.yml
|
||||
with:
|
||||
godot-ref: ${{ needs.cache-sha.outputs.godot-sha }}
|
||||
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
|
||||
|
||||
linux-build:
|
||||
name: 🐧 Linux
|
||||
needs: cache-sha
|
||||
uses: ./.github/workflows/linux.yml
|
||||
with:
|
||||
godot-ref: ${{ needs.cache-sha.outputs.godot-sha }}
|
||||
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
|
||||
test-build: false
|
||||
|
||||
macos-build:
|
||||
name: 🍎 macOS
|
||||
needs: cache-sha
|
||||
uses: ./.github/workflows/macos.yml
|
||||
with:
|
||||
godot-ref: ${{ needs.cache-sha.outputs.godot-sha }}
|
||||
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
|
||||
|
||||
windows-build:
|
||||
name: 🪟 Windows
|
||||
needs: cache-sha
|
||||
uses: ./.github/workflows/windows.yml
|
||||
with:
|
||||
godot-ref: ${{ needs.cache-sha.outputs.godot-sha }}
|
||||
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
|
||||
test-build: false
|
||||
|
||||
web-build:
|
||||
name: 🌐 Web
|
||||
needs: cache-sha
|
||||
uses: ./.github/workflows/web.yml
|
||||
with:
|
||||
godot-ref: ${{ needs.cache-sha.outputs.godot-sha }}
|
||||
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
|
||||
|
||||
gdextension:
|
||||
name: 🔌 GDExtension
|
||||
needs: cache-sha
|
||||
uses: ./.github/workflows/gdextension.yml
|
||||
with:
|
||||
godot-cpp-ref: ${{ inputs.godot-cpp-ref }}
|
||||
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
|
||||
test-build: false
|
||||
|
||||
demo:
|
||||
name: 🎮️ Demo project
|
||||
needs: cache-sha
|
||||
uses: ./.github/workflows/demo.yml
|
||||
with:
|
||||
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
|
||||
|
||||
merge_templates:
|
||||
name: 📦 Merge templates
|
||||
if: ${{ always() }}
|
||||
needs:
|
||||
[
|
||||
cache-sha,
|
||||
android-build,
|
||||
ios-build,
|
||||
linux-build,
|
||||
macos-build,
|
||||
windows-build,
|
||||
web-build,
|
||||
]
|
||||
uses: ./.github/workflows/merge_templates.yml
|
||||
with:
|
||||
godot-ref: ${{ needs.cache-sha.outputs.godot-sha }}
|
||||
limboai-ref: ${{ needs.cache-sha.outputs.limboai-sha }}
|
|
@ -2,22 +2,22 @@ name: 🤖 Android builds
|
|||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
godot-treeish:
|
||||
godot-ref:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
default: master
|
||||
limboai-treeish:
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
godot-treeish:
|
||||
godot-ref:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
default: master
|
||||
limboai-treeish:
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
|
@ -37,62 +37,126 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# * Standard arm64
|
||||
|
||||
- name: Template (arm64, debug)
|
||||
arch: arm64
|
||||
target: template_debug
|
||||
dotnet: false
|
||||
|
||||
- name: Template (arm64, release)
|
||||
arch: arm64
|
||||
target: template_release
|
||||
dotnet: false
|
||||
|
||||
# * Standard arm32
|
||||
|
||||
- name: Template (arm32, debug)
|
||||
arch: arm32
|
||||
target: template_debug
|
||||
dotnet: false
|
||||
|
||||
- name: Template (arm32, release)
|
||||
arch: arm32
|
||||
target: template_release
|
||||
dotnet: false
|
||||
|
||||
# * Standard x86_64
|
||||
|
||||
- name: Template (x86_64, debug)
|
||||
arch: x86_64
|
||||
target: template_debug
|
||||
dotnet: false
|
||||
|
||||
- name: Template (x86_64, release)
|
||||
arch: x86_64
|
||||
target: template_release
|
||||
dotnet: false
|
||||
|
||||
# * Standard x86_32
|
||||
|
||||
- name: Template (x86_32, debug)
|
||||
arch: x86_32
|
||||
target: template_debug
|
||||
dotnet: false
|
||||
|
||||
- name: Template (x86_32, release)
|
||||
arch: x86_32
|
||||
target: template_release
|
||||
dotnet: false
|
||||
|
||||
# * .NET arm64
|
||||
|
||||
- name: Template .NET (arm64, debug)
|
||||
arch: arm64
|
||||
target: template_debug
|
||||
dotnet: true
|
||||
|
||||
- name: Template .NET (arm64, release)
|
||||
arch: arm64
|
||||
target: template_release
|
||||
dotnet: true
|
||||
|
||||
# * .NET arm32
|
||||
|
||||
- name: Template .NET (arm32, debug)
|
||||
arch: arm32
|
||||
target: template_debug
|
||||
dotnet: true
|
||||
|
||||
- name: Template .NET (arm32, release)
|
||||
arch: arm32
|
||||
target: template_release
|
||||
dotnet: true
|
||||
|
||||
# * .NET x86_64
|
||||
|
||||
- name: Template .NET (x86_64, debug)
|
||||
arch: x86_64
|
||||
target: template_debug
|
||||
dotnet: true
|
||||
|
||||
- name: Template .NET (x86_64, release)
|
||||
arch: x86_64
|
||||
target: template_release
|
||||
dotnet: true
|
||||
|
||||
# * .NET x86_32
|
||||
|
||||
- name: Template .NET (x86_32, debug)
|
||||
arch: x86_32
|
||||
target: template_debug
|
||||
dotnet: true
|
||||
|
||||
- name: Template .NET (x86_32, release)
|
||||
arch: x86_32
|
||||
target: template_release
|
||||
dotnet: true
|
||||
|
||||
env:
|
||||
BIN: godot.linuxbsd.${{matrix.target}}.${{matrix.arch}} #${{ matrix.build-mono == true && '.mono' || '' }}
|
||||
BIN: godot.linuxbsd.${{matrix.target}}.${{matrix.arch}}${{ matrix.dotnet == true && '.mono' || '' }}
|
||||
|
||||
steps:
|
||||
- name: Clone Godot
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: godotengine/godot
|
||||
ref: ${{ inputs.godot-treeish }}
|
||||
ref: ${{ inputs.godot-ref }}
|
||||
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: modules/limboai
|
||||
ref: ${{ inputs.limboai-treeish }}
|
||||
ref: ${{ inputs.limboai-ref }}
|
||||
|
||||
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
|
||||
- uses: ./modules/limboai/.github/actions/init-version
|
||||
|
||||
- name: Set up Java 11
|
||||
uses: actions/setup-java@v3
|
||||
- name: Set up Java 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 11
|
||||
java-version: 17
|
||||
|
||||
- name: Set up scons
|
||||
run: |
|
||||
|
@ -101,65 +165,75 @@ jobs:
|
|||
python --version
|
||||
scons --version
|
||||
|
||||
- name: Set up scons cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{github.workspace}}/.scons_cache/
|
||||
key: ${{matrix.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
restore-keys: |
|
||||
${{env.BIN}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
${{env.BIN}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}
|
||||
${{env.BIN}}-${{env.GODOT_BASE_BRANCH}}
|
||||
# ! Note: we stopped using the scons cache in release builds.
|
||||
# - name: Set up scons cache
|
||||
# uses: actions/cache@v4
|
||||
# with:
|
||||
# path: ${{github.workspace}}/.scons_cache/
|
||||
# key: ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
|
||||
# restore-keys: |
|
||||
# ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
|
||||
# ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}
|
||||
# ${{env.BIN}}-${{inputs.godot-ref}}
|
||||
|
||||
- name: Compilation
|
||||
env:
|
||||
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
|
||||
run: |
|
||||
scons platform=android target=${{matrix.target}} arch=${{matrix.arch}} ${{env.SCONSFLAGS}}
|
||||
scons platform=android target=${{matrix.target}} arch=${{matrix.arch}} module_mono_enabled=${{matrix.dotnet}} ${{env.SCONSFLAGS}}
|
||||
ls platform/android/java/lib/libs/*
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: android-templates
|
||||
name: tmp-android${{matrix.dotnet == true && '-dotnet' || ''}}-templates-${{strategy.job-index}}
|
||||
path: platform/android/java/lib/libs/*
|
||||
|
||||
|
||||
make-android-package:
|
||||
runs-on: "ubuntu-20.04"
|
||||
name: Make Android package
|
||||
needs: android-builds
|
||||
name: ${{ matrix.name }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: Package Android templates
|
||||
dotnet: false
|
||||
- name: Package Android .NET templates
|
||||
dotnet: true
|
||||
|
||||
steps:
|
||||
- name: Clone Godot
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: godotengine/godot
|
||||
ref: ${{ inputs.godot-treeish }}
|
||||
ref: ${{ inputs.godot-ref }}
|
||||
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: modules/limboai
|
||||
ref: ${{ inputs.limboai-treeish }}
|
||||
ref: ${{ inputs.limboai-ref }}
|
||||
|
||||
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
|
||||
- uses: ./modules/limboai/.github/actions/init-version
|
||||
|
||||
- name: Download Android template builds
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: android-templates
|
||||
pattern: tmp-android${{matrix.dotnet == true && '-dotnet' || ''}}-templates-*
|
||||
merge-multiple: true
|
||||
path: platform/android/java/lib/libs/
|
||||
|
||||
- name: Set up Java 11
|
||||
uses: actions/setup-java@v3
|
||||
- name: Set up Java 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 11
|
||||
java-version: 17
|
||||
|
||||
- name: Set up Python 3.x
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
architecture: x64
|
||||
|
@ -180,22 +254,24 @@ jobs:
|
|||
|
||||
mkdir -p out/templates/
|
||||
mv bin/android_* out/templates/
|
||||
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}${{matrix.dotnet == true && '.mono' || ''}}" > out/templates/version.txt
|
||||
ls -l out/*
|
||||
|
||||
- name: Delete Android template builds
|
||||
uses: geekyeggo/delete-artifact@v2
|
||||
uses: geekyeggo/delete-artifact@v5
|
||||
with:
|
||||
name: android-templates
|
||||
failOnError: false
|
||||
name: tmp-android${{matrix.dotnet == true && '-dotnet' || ''}}-templates-*
|
||||
useGlob: true
|
||||
failOnError: false
|
||||
|
||||
- name: Upload Android libs
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{env.NAME_PREFIX}}.android-lib
|
||||
name: ${{env.NAME_PREFIX}}${{matrix.dotnet == true && '.dotnet' || ''}}.android-lib
|
||||
path: bin/godot-lib.*
|
||||
|
||||
- name: Upload Android templates
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{env.NAME_PREFIX}}.export-templates
|
||||
name: ${{env.NAME_PREFIX}}${{matrix.dotnet == true && '.dotnet' || ''}}.export-templates.android
|
||||
path: out/*
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
name: 🎮️ Demo project
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
|
||||
jobs:
|
||||
package-demo:
|
||||
runs-on: ubuntu-latest
|
||||
name: Package demo
|
||||
|
||||
steps:
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-tags: true
|
||||
ref: ${{ inputs.limboai-ref }}
|
||||
|
||||
- name: Init version
|
||||
run: echo "LIMBOAI_VERSION=$( (git describe --tags --exact-match HEAD || git rev-parse --short HEAD) | sed 's/\(.*\)-\(.*\)/\1.\2/g' )" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Prepare artifact
|
||||
shell: bash
|
||||
run: |
|
||||
cp {README,LICENSE}.md demo/
|
||||
mkdir -p demo/addons/limboai/
|
||||
cp -R icons/ demo/addons/limboai/icons
|
||||
echo "${LIMBOAI_VERSION}" > demo/version.txt
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
env:
|
||||
NAME: limboai+${{env.LIMBOAI_VERSION}}.demo-project
|
||||
with:
|
||||
name: ${{ env.NAME }}
|
||||
path: demo/*
|
|
@ -0,0 +1,386 @@
|
|||
name: 🔌 GDExtension
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
godot-cpp-ref:
|
||||
description: A tag, branch or commit hash in the godot-cpp repository.
|
||||
type: string
|
||||
default: godot-4.3-stable
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
test-build:
|
||||
description: Limit to pre-defined test builds
|
||||
type: boolean
|
||||
default: false
|
||||
debug-symbols:
|
||||
description: Build with debug symbols
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
godot-cpp-ref:
|
||||
description: A tag, branch or commit hash in the godot-cpp repository.
|
||||
type: string
|
||||
default: godot-4.3-stable
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
test-build:
|
||||
description: Limit to pre-defined test builds
|
||||
type: boolean
|
||||
default: false
|
||||
debug-symbols:
|
||||
description: Build with debug symbols
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
# Global Settings
|
||||
env:
|
||||
SCONS_CACHE_LIMIT: 4096
|
||||
SCONSFLAGS: use_mingw=yes dev_build=no
|
||||
EM_VERSION: 3.1.45
|
||||
EM_CACHE_FOLDER: "emsdk-cache"
|
||||
GODOT_VERSION: 4.4-beta3
|
||||
GODOT_REPO: godotengine/godot-builds
|
||||
|
||||
jobs:
|
||||
gdextension:
|
||||
runs-on: ${{ matrix.opts.runner }}
|
||||
name: ${{ matrix.opts.name }}
|
||||
outputs:
|
||||
name-prefix: ${{ steps.output-name-prefix.outputs.name-prefix }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
opts:
|
||||
- name: 🐧 Linux (x86_64, release)
|
||||
runner: ubuntu-20.04
|
||||
platform: linux
|
||||
target: template_release
|
||||
arch: x86_64
|
||||
should-build: true
|
||||
|
||||
- name: 🐧 Linux (x86_64, debug)
|
||||
runner: ubuntu-20.04
|
||||
platform: linux
|
||||
target: editor
|
||||
arch: x86_64
|
||||
should-build: true
|
||||
|
||||
- name: 🪟 Windows (x86_64, release)
|
||||
runner: windows-latest
|
||||
platform: windows
|
||||
target: template_release
|
||||
arch: x86_64
|
||||
should-build: true
|
||||
|
||||
- name: 🪟 Windows (x86_64, debug)
|
||||
runner: windows-latest
|
||||
platform: windows
|
||||
target: editor
|
||||
arch: x86_64
|
||||
should-build: true
|
||||
|
||||
- name: 🍎 macOS (universal, release)
|
||||
runner: macos-latest
|
||||
platform: macos
|
||||
target: template_release
|
||||
arch: universal
|
||||
should-build: true
|
||||
|
||||
- name: 🍎 macOS (universal, debug)
|
||||
runner: macos-latest
|
||||
platform: macos
|
||||
target: editor
|
||||
arch: universal
|
||||
should-build: true
|
||||
|
||||
- name: 🌐 Web (wasm32, release)
|
||||
runner: ubuntu-20.04
|
||||
platform: web
|
||||
target: template_release
|
||||
arch: wasm32
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: 🌐 Web (wasm32, debug)
|
||||
runner: ubuntu-20.04
|
||||
platform: web
|
||||
target: editor
|
||||
arch: wasm32
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: 🤖 Android (arm64, release)
|
||||
runner: ubuntu-20.04
|
||||
platform: android
|
||||
target: template_release
|
||||
arch: arm64
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: 🤖 Android (arm64, debug)
|
||||
runner: ubuntu-20.04
|
||||
platform: android
|
||||
target: editor
|
||||
arch: arm64
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: 🤖 Android (arm32, release)
|
||||
runner: ubuntu-20.04
|
||||
platform: android
|
||||
target: template_release
|
||||
arch: arm32
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: 🤖 Android (arm32, debug)
|
||||
runner: ubuntu-20.04
|
||||
platform: android
|
||||
target: editor
|
||||
arch: arm32
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: 🤖 Android (x86_64, release)
|
||||
runner: ubuntu-20.04
|
||||
platform: android
|
||||
target: template_release
|
||||
arch: x86_64
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: 🤖 Android (x86_64, debug)
|
||||
runner: ubuntu-20.04
|
||||
platform: android
|
||||
target: editor
|
||||
arch: x86_64
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: 🤖 Android (x86_32, release)
|
||||
runner: ubuntu-20.04
|
||||
platform: android
|
||||
target: template_release
|
||||
arch: x86_32
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: 🤖 Android (x86_32, debug)
|
||||
runner: ubuntu-20.04
|
||||
platform: android
|
||||
target: editor
|
||||
arch: x86_32
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: 🍏 iOS (arm64, release)
|
||||
runner: macos-latest
|
||||
platform: ios
|
||||
target: template_release
|
||||
arch: arm64
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: 🍏 iOS (arm64, debug)
|
||||
runner: macos-latest
|
||||
platform: ios
|
||||
target: editor
|
||||
arch: arm64
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: 🍏 iOS (simulator, release)
|
||||
runner: macos-latest
|
||||
platform: ios
|
||||
target: template_release
|
||||
arch: universal
|
||||
scons-flags: ios_simulator=yes
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: 🍏 iOS (simulator, debug)
|
||||
runner: macos-latest
|
||||
platform: ios
|
||||
target: editor
|
||||
arch: universal
|
||||
scons-flags: ios_simulator=yes
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
exclude:
|
||||
- { opts: { should-build: false } }
|
||||
|
||||
env:
|
||||
BIN: liblimboai.${{matrix.opts.platform}}.${{matrix.opts.target}}.${{matrix.opts.arch}}
|
||||
|
||||
steps:
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-tags: true
|
||||
ref: ${{ inputs.limboai-ref }}
|
||||
|
||||
- name: Clone godot-cpp
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: godotengine/godot-cpp
|
||||
fetch-tags: true
|
||||
path: godot-cpp
|
||||
ref: ${{ inputs.godot-cpp-ref }}
|
||||
|
||||
# Inits GDEXTENSION_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
|
||||
- uses: ./.github/actions/init-version-gdext
|
||||
|
||||
- name: Output NAME_PREFIX
|
||||
id: output-name-prefix
|
||||
run: echo "name-prefix=${NAME_PREFIX}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup Linux toolchain
|
||||
if: matrix.opts.platform == 'linux'
|
||||
uses: ./.github/actions/setup-linux-toolchain
|
||||
with:
|
||||
arch: ${{matrix.opts.arch}}
|
||||
|
||||
- name: Set up Python 3.x
|
||||
if: matrix.opts.platform == 'windows' || matrix.opts.platform == 'macos'
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
architecture: "x64"
|
||||
|
||||
- name: Set up Emscripten cache
|
||||
if: matrix.opts.platform == 'web'
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{env.EM_CACHE_FOLDER}}
|
||||
key: ${{env.EM_VERSION}}-${{runner.os}}-libs
|
||||
|
||||
- name: Set up Emscripten
|
||||
if: matrix.opts.platform == 'web'
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
with:
|
||||
version: ${{env.EM_VERSION}}
|
||||
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
|
||||
|
||||
- name: Verify Emscripten setup
|
||||
if: matrix.opts.platform == 'web'
|
||||
run: |
|
||||
emcc -v
|
||||
|
||||
- name: Set up scons
|
||||
if: matrix.opts.platform != 'linux'
|
||||
run: |
|
||||
python -c "import sys; print(sys.version)"
|
||||
python -m pip install scons==4.4.0
|
||||
python --version
|
||||
scons --version
|
||||
|
||||
- name: Set up Java 17
|
||||
if: matrix.opts.platform == 'android'
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 17
|
||||
|
||||
- uses: nttld/setup-ndk@v1
|
||||
if: matrix.opts.platform == 'android'
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r23c
|
||||
link-to-sdk: true
|
||||
|
||||
- name: Set up MSVC problem matcher on Windows
|
||||
if: matrix.opts.platform == 'windows'
|
||||
uses: ammaraskar/msvc-problem-matcher@master
|
||||
|
||||
- name: Set up scons cache
|
||||
if: inputs.test-build # ! Only cache test/PR builds
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{github.workspace}}/.scons_cache/
|
||||
key: ${{env.BIN}}-${{inputs.debug-symbols}}-${{inputs.godot-cpp-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
|
||||
restore-keys: |
|
||||
${{env.BIN}}-${{inputs.debug-symbols}}-${{inputs.godot-cpp-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
|
||||
${{env.BIN}}-${{inputs.debug-symbols}}-${{inputs.godot-cpp-ref}}-${{inputs.limboai-ref}}
|
||||
${{env.BIN}}-${{inputs.debug-symbols}}-${{inputs.godot-cpp-ref}}
|
||||
|
||||
- name: Compilation
|
||||
shell: bash
|
||||
env:
|
||||
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
|
||||
DEBUG_FLAGS: ${{ inputs.debug-symbols && 'debug_symbols=yes symbols_visibility=visible' || 'debug_symbols=no' }}
|
||||
run: |
|
||||
PATH=${GITHUB_WORKSPACE}/buildroot/bin:$PATH
|
||||
scons platform=${{matrix.opts.platform}} target=${{matrix.opts.target}} arch=${{matrix.opts.arch}} ${{env.DEBUG_FLAGS}} ${{matrix.opts.scons-flags}} ${{env.SCONSFLAGS}}
|
||||
|
||||
- name: Prepare artifact
|
||||
shell: bash
|
||||
run: |
|
||||
ls -R demo/addons/limboai/
|
||||
mkdir out
|
||||
mv demo/addons/ out/
|
||||
cp {README,LICENSE,LOGO_LICENSE}.md out/addons/limboai/
|
||||
cp -R demo/demo/ out/demo/
|
||||
cp demo/LICENSE_ASSETS.md out/demo/
|
||||
rm -f out/addons/limboai/bin/*.{exp,lib,pdb}
|
||||
echo "${LIMBOAI_VERSION}" > out/addons/limboai/version.txt
|
||||
echo "---"
|
||||
ls -R out/
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
env:
|
||||
NAME: tmp-gdextension.${{matrix.opts.platform}}.${{matrix.opts.target}}.${{matrix.opts.arch}}
|
||||
with:
|
||||
name: ${{ env.NAME }}
|
||||
path: out/*
|
||||
|
||||
package-extension:
|
||||
name: 📦 Package extension
|
||||
runs-on: ubuntu-latest
|
||||
needs: gdextension
|
||||
|
||||
steps:
|
||||
- name: Merge artifacts
|
||||
uses: actions/upload-artifact/merge@v4
|
||||
with:
|
||||
name: ${{needs.gdextension.outputs.name-prefix}}
|
||||
pattern: tmp-gdextension.*
|
||||
delete-merged: true
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{needs.gdextension.outputs.name-prefix}}
|
||||
path: out/
|
||||
|
||||
- name: Setup Godot
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Downloading Godot ${GODOT_VERSION}"
|
||||
mkdir bin
|
||||
cd bin
|
||||
wget "https://github.com/${GODOT_REPO}/releases/download/${GODOT_VERSION}/Godot_v${GODOT_VERSION}_linux.x86_64.zip" -O godot.zip
|
||||
unzip godot.zip
|
||||
rm godot.zip
|
||||
mv Godot_* godot
|
||||
chmod u+x godot
|
||||
ls -l
|
||||
cd ..
|
||||
./bin/godot --version
|
||||
|
||||
- name: Generate icon .import files
|
||||
shell: bash
|
||||
run: |
|
||||
touch out/project.godot
|
||||
timeout 20s ./bin/godot --headless --editor --path ./out/ || /bin/true
|
||||
rm out/project.godot
|
||||
rm -rf out/.godot/
|
||||
|
||||
- name: Change editor icon import settings
|
||||
shell: bash
|
||||
run: |
|
||||
echo "--- Listing icons dir:"
|
||||
ls out/addons/limboai/icons/
|
||||
echo "--- (end of listing)"
|
||||
sed -i 's|editor/scale_with_editor_scale=false|editor/scale_with_editor_scale=true|' out/addons/limboai/icons/*.import
|
||||
sed -i 's|editor/convert_colors_with_editor_theme=false|editor/convert_colors_with_editor_theme=true|' out/addons/limboai/icons/*.import
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{needs.gdextension.outputs.name-prefix}}
|
||||
path: out/*
|
||||
overwrite: true
|
|
@ -2,36 +2,34 @@ name: 🍏 iOS builds
|
|||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
godot-treeish:
|
||||
godot-ref:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
default: master
|
||||
limboai-treeish:
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
godot-treeish:
|
||||
godot-ref:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
default: master
|
||||
limboai-treeish:
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
|
||||
|
||||
# Global Settings
|
||||
env:
|
||||
SCONS_CACHE_LIMIT: 4096
|
||||
SCONSFLAGS: production=yes tests=no verbose=yes warnings=extra werror=yes
|
||||
SCONSFLAGS: production=yes tests=no verbose=yes warnings=extra
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: true
|
||||
|
||||
jobs:
|
||||
|
||||
ios-builds:
|
||||
runs-on: "macos-latest"
|
||||
name: ${{ matrix.name }}
|
||||
|
@ -44,21 +42,25 @@ jobs:
|
|||
target: template_release
|
||||
arch: arm64
|
||||
ios_simulator: false
|
||||
dotnet: false
|
||||
|
||||
- name: Template (arm64, debug)
|
||||
target: template_debug
|
||||
arch: arm64
|
||||
ios_simulator: false
|
||||
dotnet: false
|
||||
|
||||
- name: Simulator Lib (x86_64, release)
|
||||
- name: Simulator (x86_64, release)
|
||||
target: template_release
|
||||
arch: x86_64
|
||||
ios_simulator: true
|
||||
dotnet: false
|
||||
|
||||
- name: Simulator Lib (x86_64, debug)
|
||||
- name: Simulator (x86_64, debug)
|
||||
target: template_debug
|
||||
arch: x86_64
|
||||
ios_simulator: true
|
||||
dotnet: false
|
||||
|
||||
# ! Disabled for now as it doesn't work with cctools-port and current LLVM.
|
||||
# * See https://github.com/godotengine/build-containers/pull/85.
|
||||
|
@ -72,31 +74,54 @@ jobs:
|
|||
# arch: arm64
|
||||
# ios_simulator: true
|
||||
|
||||
- name: Template .NET (arm64, release)
|
||||
target: template_release
|
||||
arch: arm64
|
||||
ios_simulator: false
|
||||
dotnet: true
|
||||
|
||||
- name: Template .NET (arm64, debug)
|
||||
target: template_debug
|
||||
arch: arm64
|
||||
ios_simulator: false
|
||||
dotnet: true
|
||||
|
||||
- name: Simulator .NET (x86_64, release)
|
||||
target: template_release
|
||||
arch: x86_64
|
||||
ios_simulator: true
|
||||
dotnet: true
|
||||
|
||||
- name: Simulator .NET (x86_64, debug)
|
||||
target: template_debug
|
||||
arch: x86_64
|
||||
ios_simulator: true
|
||||
dotnet: true
|
||||
|
||||
env:
|
||||
BIN: godot.ios.${{matrix.target}}.${{matrix.arch}}
|
||||
BIN: godot.ios.${{matrix.target}}.${{matrix.arch}}${{ matrix.dotnet == true && '.mono' || '' }}
|
||||
|
||||
steps:
|
||||
|
||||
- name: Clone Godot
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: godotengine/godot
|
||||
ref: ${{ inputs.godot-treeish }}
|
||||
ref: ${{ inputs.godot-ref }}
|
||||
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: modules/limboai
|
||||
ref: ${{ inputs.limboai-treeish }}
|
||||
ref: ${{ inputs.limboai-ref }}
|
||||
|
||||
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
|
||||
- uses: ./modules/limboai/.github/actions/init-version
|
||||
|
||||
- name: Set up Python 3.x
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
architecture: 'x64'
|
||||
python-version: "3.x"
|
||||
architecture: "x64"
|
||||
|
||||
- name: Set up scons
|
||||
run: |
|
||||
|
@ -111,60 +136,84 @@ jobs:
|
|||
|
||||
- name: Set up Vulkan SDK
|
||||
run: |
|
||||
sh misc/scripts/install_vulkan_sdk_macos.sh
|
||||
# ! Note: Vulkan SDK changed packaging, so we need to inline these steps for the time being.
|
||||
#sh misc/scripts/install_vulkan_sdk_macos.sh
|
||||
|
||||
- name: Set up scons cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{github.workspace}}/.scons_cache/
|
||||
key: ${{matrix.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
restore-keys: |
|
||||
${{env.BIN}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
${{env.BIN}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}
|
||||
${{env.BIN}}-${{env.GODOT_BASE_BRANCH}}
|
||||
curl -L "https://sdk.lunarg.com/sdk/download/latest/mac/vulkan-sdk.zip" -o /tmp/vulkan-sdk.zip
|
||||
unzip /tmp/vulkan-sdk.zip -d /tmp
|
||||
/tmp/InstallVulkan.app/Contents/MacOS/InstallVulkan --accept-licenses --default-answer --confirm-command install
|
||||
rm -Rf /tmp/InstallVulkan.app
|
||||
rm -f /tmp/vulkan-sdk.zip
|
||||
|
||||
# ! Note: we stopped using the scons cache in release builds.
|
||||
# - name: Set up scons cache
|
||||
# uses: actions/cache@v4
|
||||
# with:
|
||||
# path: ${{github.workspace}}/.scons_cache/
|
||||
# key: ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
|
||||
# restore-keys: |
|
||||
# ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
|
||||
# ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}
|
||||
# ${{env.BIN}}-${{inputs.godot-ref}}
|
||||
|
||||
- name: Compilation
|
||||
env:
|
||||
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
|
||||
run: |
|
||||
scons platform=ios target=${{matrix.target}} arch=${{matrix.arch}} ios_simulator=${{matrix.ios_simulator}} ${{env.SCONSFLAGS}}
|
||||
scons platform=ios target=${{matrix.target}} arch=${{matrix.arch}} ios_simulator=${{matrix.ios_simulator}} module_mono_enabled=${{matrix.dotnet}} ${{env.SCONSFLAGS}}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ios-templates
|
||||
name: tmp-ios${{matrix.dotnet == true && '-dotnet' || ''}}-templates-${{strategy.job-index}}
|
||||
path: bin/*
|
||||
|
||||
package-ios-templates:
|
||||
runs-on: "macos-latest"
|
||||
name: Package iOS templates
|
||||
name: ${{ matrix.name }}
|
||||
needs: ios-builds
|
||||
|
||||
steps:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: Package iOS templates
|
||||
dotnet: false
|
||||
- name: Package iOS .NET templates
|
||||
dotnet: true
|
||||
|
||||
steps:
|
||||
- name: Clone Godot
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: godotengine/godot
|
||||
ref: ${{ inputs.godot-treeish }}
|
||||
ref: ${{ inputs.godot-ref }}
|
||||
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: modules/limboai
|
||||
ref: ${{ inputs.limboai-treeish }}
|
||||
ref: ${{ inputs.limboai-ref }}
|
||||
|
||||
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
|
||||
- uses: ./modules/limboai/.github/actions/init-version
|
||||
|
||||
- name: Set up Vulkan SDK
|
||||
run: |
|
||||
sh misc/scripts/install_vulkan_sdk_macos.sh
|
||||
# ! Note: Vulkan SDK changed packaging, so we need to inline these steps for the time being.
|
||||
#sh misc/scripts/install_vulkan_sdk_macos.sh
|
||||
|
||||
curl -L "https://sdk.lunarg.com/sdk/download/latest/mac/vulkan-sdk.zip" -o /tmp/vulkan-sdk.zip
|
||||
unzip /tmp/vulkan-sdk.zip -d /tmp
|
||||
/tmp/InstallVulkan.app/Contents/MacOS/InstallVulkan --accept-licenses --default-answer --confirm-command install
|
||||
rm -Rf /tmp/InstallVulkan.app
|
||||
rm -f /tmp/vulkan-sdk.zip
|
||||
|
||||
- name: Download templates artifact
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ios-templates
|
||||
pattern: tmp-ios${{matrix.dotnet == true && '-dotnet' || ''}}-templates-*
|
||||
merge-multiple: true
|
||||
path: bin/
|
||||
|
||||
- name: Make template bundle
|
||||
|
@ -173,8 +222,6 @@ jobs:
|
|||
cp -r misc/dist/ios_xcode bin/
|
||||
cd bin/
|
||||
|
||||
strip *.a
|
||||
|
||||
mv libgodot.ios.template_debug.arm64.a ios_xcode/libgodot.ios.debug.xcframework/ios-arm64/libgodot.a
|
||||
# ! lipo -create libgodot.ios.template_debug.arm64.simulator.a libgodot.ios.template_debug.x86_64.simulator.a -output ios_xcode/libgodot.ios.debug.xcframework/ios-arm64_x86_64-simulator/libgodot.a
|
||||
mv libgodot.ios.template_debug.x86_64.simulator.a ios_xcode/libgodot.ios.debug.xcframework/ios-arm64_x86_64-simulator/libgodot.a
|
||||
|
@ -183,23 +230,26 @@ jobs:
|
|||
# ! lipo -create libgodot.ios.template_release.arm64.simulator.a libgodot.ios.template_release.x86_64.simulator.a -output ios_xcode/libgodot.ios.release.xcframework/ios-arm64_x86_64-simulator/libgodot.a
|
||||
mv libgodot.ios.template_release.x86_64.simulator.a ios_xcode/libgodot.ios.release.xcframework/ios-arm64_x86_64-simulator/libgodot.a
|
||||
|
||||
cp -r ~/VulkanSDK/*/MoltenVK/MoltenVK.xcframework ios_xcode
|
||||
cp -r ~/VulkanSDK/*/macOS/lib/MoltenVK.xcframework ios_xcode
|
||||
rm -rf ios_xcode/MoltenVK.xcframework/{macos,tvos}*
|
||||
|
||||
mkdir -p ${{github.workspace}}/out/templates/
|
||||
cd ios_xcode
|
||||
zip -q -9 -r ${{github.workspace}}/out/templates/ios.zip *
|
||||
|
||||
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}${{matrix.dotnet == true && '.mono' || ''}}" > ${{github.workspace}}/out/templates/version.txt
|
||||
|
||||
ls -l ${{github.workspace}}/out/*
|
||||
|
||||
- name: Upload template bundle
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{env.NAME_PREFIX}}.export-templates
|
||||
name: ${{env.NAME_PREFIX}}${{matrix.dotnet == true && '.dotnet' || ''}}.export-templates.ios
|
||||
path: out/*
|
||||
|
||||
- name: Delete templates artifact
|
||||
uses: geekyeggo/delete-artifact@v2
|
||||
uses: geekyeggo/delete-artifact@v5
|
||||
with:
|
||||
name: ios-templates
|
||||
failOnError: false
|
||||
name: tmp-ios${{matrix.dotnet == true && '-dotnet' || ''}}-templates-*
|
||||
useGlob: true
|
||||
failOnError: false
|
||||
|
|
|
@ -2,25 +2,33 @@ name: 🐧 Linux builds
|
|||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
godot-treeish:
|
||||
godot-ref:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
default: master
|
||||
limboai-treeish:
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
test-build:
|
||||
description: Limit to pre-defined test builds
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
godot-treeish:
|
||||
godot-ref:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
default: master
|
||||
limboai-treeish:
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
test-build:
|
||||
description: Limit to pre-defined test builds
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
# Global Settings
|
||||
env:
|
||||
|
@ -32,157 +40,250 @@ env:
|
|||
jobs:
|
||||
linux-builds:
|
||||
runs-on: "ubuntu-20.04"
|
||||
name: ${{ matrix.name }}
|
||||
name: ${{ matrix.opts.name }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
opts:
|
||||
# * Standard x86_64
|
||||
|
||||
- name: Editor (x86_64, release)
|
||||
target: editor
|
||||
arch: x86_64
|
||||
build-mono: false
|
||||
dotnet: false
|
||||
should-build: true
|
||||
|
||||
- name: Template (x86_64, release)
|
||||
target: template_release
|
||||
arch: x86_64
|
||||
build-mono: false
|
||||
dotnet: false
|
||||
should-build: true
|
||||
|
||||
- name: Template (x86_64, debug)
|
||||
target: template_debug
|
||||
arch: x86_64
|
||||
build-mono: false
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# * Standard x86_32
|
||||
|
||||
# - name: Editor (x86_32, release)
|
||||
# target: editor
|
||||
# arch: x86_32
|
||||
# build-mono: false
|
||||
# dotnet: false
|
||||
# should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template (x86_32, release)
|
||||
target: template_release
|
||||
arch: x86_32
|
||||
build-mono: false
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template (x86_32, debug)
|
||||
target: template_debug
|
||||
arch: x86_32
|
||||
build-mono: false
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# * Standard arm64
|
||||
|
||||
- name: Editor (arm64, release)
|
||||
target: editor
|
||||
arch: arm64
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template (arm64, release)
|
||||
target: template_release
|
||||
arch: arm64
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template (arm64, debug)
|
||||
target: template_debug
|
||||
arch: arm64
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# * Standard arm32
|
||||
|
||||
- name: Template (arm32, release)
|
||||
target: template_release
|
||||
arch: arm32
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template (arm32, debug)
|
||||
target: template_debug
|
||||
arch: arm32
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# * .NET x86_64
|
||||
|
||||
- name: Editor .NET (x86_64, release)
|
||||
target: editor
|
||||
arch: x86_64
|
||||
build-mono: true
|
||||
dotnet: true
|
||||
should-build: true
|
||||
|
||||
- name: Template .NET (x86_64, release)
|
||||
target: template_release
|
||||
arch: x86_64
|
||||
build-mono: true
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template .NET (x86_64, debug)
|
||||
target: template_debug
|
||||
arch: x86_64
|
||||
build-mono: true
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# * .NET x86_32
|
||||
|
||||
# - name: Editor .NET (x86_32, release)
|
||||
# target: editor
|
||||
# arch: x86_32
|
||||
# build-mono: true
|
||||
# dotnet: true
|
||||
# should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template .NET (x86_32, release)
|
||||
target: template_release
|
||||
arch: x86_32
|
||||
build-mono: true
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template .NET (x86_32, debug)
|
||||
target: template_debug
|
||||
arch: x86_32
|
||||
build-mono: true
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# * .NET arm64
|
||||
|
||||
# ! FIXME: Needs a separate job for .NET glue generation since we can't execute arm64 binaries on x86_64.
|
||||
# ! Alternatively, solution generation can be done as post-process job, taking the glue from x86_64, after all builds complete.
|
||||
# - name: Editor .NET (arm64, release)
|
||||
# target: editor
|
||||
# arch: arm64
|
||||
# dotnet: true
|
||||
# should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template .NET (arm64, release)
|
||||
target: template_release
|
||||
arch: arm64
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template .NET (arm64, debug)
|
||||
target: template_debug
|
||||
arch: arm64
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# * .NET arm32
|
||||
|
||||
- name: Template .NET (arm32, release)
|
||||
target: template_release
|
||||
arch: arm32
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template .NET (arm32, debug)
|
||||
target: template_debug
|
||||
arch: arm32
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
exclude:
|
||||
- { opts: { should-build: false } }
|
||||
|
||||
env:
|
||||
BIN: godot.linuxbsd.${{matrix.target}}.${{matrix.arch}}${{ matrix.build-mono == true && '.mono' || '' }}
|
||||
BIN: godot.linuxbsd.${{matrix.opts.target}}.${{matrix.opts.arch}}${{ matrix.opts.dotnet == true && '.mono' || '' }}
|
||||
|
||||
steps:
|
||||
- name: Clone Godot
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: godotengine/godot
|
||||
ref: ${{ inputs.godot-treeish }}
|
||||
ref: ${{ inputs.godot-ref }}
|
||||
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: modules/limboai
|
||||
ref: ${{ inputs.limboai-treeish }}
|
||||
ref: ${{ inputs.limboai-ref }}
|
||||
|
||||
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
|
||||
- uses: ./modules/limboai/.github/actions/init-version
|
||||
|
||||
# About sed see: https://github.com/godotengine/buildroot/issues/6
|
||||
- name: Set up buildroot x86_64
|
||||
if: matrix.arch == 'x86_64'
|
||||
run: |
|
||||
wget https://download.tuxfamily.org/godotengine/toolchains/linux/x86_64-godot-linux-gnu_sdk-buildroot.tar.bz2
|
||||
tar -xjf x86_64-godot-linux-gnu_sdk-buildroot.tar.bz2
|
||||
mv x86_64-godot-linux-gnu_sdk-buildroot buildroot
|
||||
cd buildroot
|
||||
sed -i x86_64-godot-linux-gnu/sysroot/usr/lib/pkgconfig/dbus-1.pc -e "s@/lib@/lib64@g"
|
||||
./relocate-sdk.sh
|
||||
cd ..
|
||||
- name: Set up Linux toolchain
|
||||
uses: ./modules/limboai/.github/actions/setup-linux-toolchain
|
||||
with:
|
||||
arch: ${{matrix.opts.arch}}
|
||||
|
||||
- name: Set up buildroot x86_32
|
||||
if: matrix.arch == 'x86_32'
|
||||
- name: Set up Wayland deps
|
||||
run: |
|
||||
wget https://download.tuxfamily.org/godotengine/toolchains/linux/i686-godot-linux-gnu_sdk-buildroot.tar.bz2
|
||||
tar -xjf i686-godot-linux-gnu_sdk-buildroot.tar.bz2
|
||||
mv i686-godot-linux-gnu_sdk-buildroot buildroot
|
||||
cd buildroot
|
||||
./relocate-sdk.sh
|
||||
cd ..
|
||||
sudo apt-get install libwayland-dev
|
||||
|
||||
- name: Set up scons cache
|
||||
uses: actions/cache@v3
|
||||
if: inputs.test-build # ! Only cache test/PR builds
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{github.workspace}}/.scons_cache/
|
||||
key: ${{matrix.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
key: ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
|
||||
restore-keys: |
|
||||
${{env.BIN}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
${{env.BIN}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}
|
||||
${{env.BIN}}-${{env.GODOT_BASE_BRANCH}}
|
||||
${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
|
||||
${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}
|
||||
${{env.BIN}}-${{inputs.godot-ref}}
|
||||
|
||||
- name: Compilation
|
||||
env:
|
||||
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
|
||||
run: |
|
||||
PATH=${GITHUB_WORKSPACE}/buildroot/bin:$PATH
|
||||
scons platform=linuxbsd target=${{matrix.target}} arch=${{matrix.arch}} module_mono_enabled=${{matrix.build-mono}} ${{env.SCONSFLAGS}}
|
||||
scons platform=linuxbsd target=${{matrix.opts.target}} arch=${{matrix.opts.arch}} module_mono_enabled=${{matrix.opts.dotnet}} ${{env.SCONSFLAGS}}
|
||||
|
||||
- name: Generate C# glue
|
||||
if: matrix.build-mono && matrix.target == 'editor'
|
||||
env:
|
||||
GODOT_VERSION_STATUS: limboai
|
||||
run: |
|
||||
./bin/$BIN --headless --generate-mono-glue ./modules/mono/glue || true
|
||||
|
||||
- name: Build .NET solutions
|
||||
if: matrix.build-mono && matrix.target == 'editor'
|
||||
env:
|
||||
GODOT_VERSION_STATUS: limboai
|
||||
run: |
|
||||
./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=linuxbsd
|
||||
- name: Build .NET assemblies
|
||||
if: matrix.opts.dotnet && matrix.opts.target == 'editor'
|
||||
uses: ./modules/limboai/.github/actions/build-dotnet-assemblies
|
||||
with:
|
||||
platform: linuxbsd
|
||||
bin: ${{env.BIN}}
|
||||
|
||||
- name: Prepare artifact
|
||||
env:
|
||||
OUTDIR: ${{ startsWith(matrix.target, 'template') && 'out/templates' || 'out/' }}
|
||||
OUTDIR: ${{ startsWith(matrix.opts.target, 'template') && 'out/templates' || 'out/' }}
|
||||
run: |
|
||||
strip ./bin/godot.*
|
||||
chmod +x ./bin/godot.*
|
||||
mkdir -p ${{env.OUTDIR}}
|
||||
mv ./bin/godot.* ${{env.OUTDIR}}
|
||||
mv bin/* ${{env.OUTDIR}}
|
||||
ls -R out/
|
||||
|
||||
# Zipping the editor artifact to retain executable bit;
|
||||
# workaround for: https://github.com/actions/upload-artifact/issues/38
|
||||
- name: Zip the editor artifact
|
||||
if: matrix.opts.target == 'editor'
|
||||
shell: bash
|
||||
run: |
|
||||
pushd out/
|
||||
zip -r godot-limboai.editor.linux.zip *
|
||||
rm godot.*
|
||||
rm -rf GodotSharp/
|
||||
echo -e "## Why another ZIP inside?\n\nWorkaround for: https://github.com/actions/upload-artifact/issues/38\n" > README.md
|
||||
popd
|
||||
|
||||
- name: Rename templates
|
||||
if: startsWith(matrix.opts.target, 'template')
|
||||
env:
|
||||
BUILD_TYPE: ${{ endsWith(matrix.opts.target, 'release') && 'release' || 'debug' }}
|
||||
run: |
|
||||
mv out/templates/${BIN} out/templates/linux_${BUILD_TYPE}.${{matrix.opts.arch}}
|
||||
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}${{matrix.opts.dotnet == true && '.mono' || ''}}" > out/templates/version.txt
|
||||
ls -R out/
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
env:
|
||||
NAME_EDITOR: ${{env.NAME_PREFIX}}.${{matrix.target}}.linux.${{matrix.arch}}${{ matrix.build-mono == true && '.mono' || '' }}
|
||||
NAME_TEMPLATES: ${{env.NAME_PREFIX}}.export-templates${{ matrix.build-mono == true && '.mono' || '' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ startsWith(matrix.target, 'template') && env.NAME_TEMPLATES || env.NAME_EDITOR }}
|
||||
name: ${{env.NAME_PREFIX}}${{matrix.opts.dotnet == true && '.dotnet' || ''}}.${{matrix.opts.target}}.linux.${{matrix.opts.arch}}
|
||||
path: out/*
|
||||
|
|
|
@ -2,150 +2,161 @@ name: 🍎 macOS builds
|
|||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
godot-treeish:
|
||||
godot-ref:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
default: master
|
||||
limboai-treeish:
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
test-build:
|
||||
description: Limit to pre-defined test builds
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
godot-treeish:
|
||||
godot-ref:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
default: master
|
||||
limboai-treeish:
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
|
||||
test-build:
|
||||
description: Limit to pre-defined test builds
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
# Global Settings
|
||||
env:
|
||||
SCONS_CACHE_LIMIT: 4096
|
||||
SCONSFLAGS: production=yes tests=no verbose=yes warnings=extra werror=yes
|
||||
SCONSFLAGS: production=yes tests=no verbose=yes warnings=extra
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: true
|
||||
|
||||
jobs:
|
||||
macos-builds:
|
||||
runs-on: "macos-latest"
|
||||
name: ${{ matrix.name }}
|
||||
name: ${{ matrix.opts.name }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
opts:
|
||||
- name: Editor (x86_64, release)
|
||||
target: editor
|
||||
arch: x86_64
|
||||
build-mono: false
|
||||
artifact-name: macos-editor
|
||||
dotnet: false
|
||||
should-build: true
|
||||
|
||||
- name: Template (x86_64, release)
|
||||
target: template_release
|
||||
arch: x86_64
|
||||
build-mono: false
|
||||
artifact-name: macos-templates
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template (x86_64, debug)
|
||||
target: template_debug
|
||||
arch: x86_64
|
||||
build-mono: false
|
||||
artifact-name: macos-templates
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Editor (arm64, release)
|
||||
target: editor
|
||||
arch: arm64
|
||||
build-mono: false
|
||||
artifact-name: macos-editor
|
||||
dotnet: false
|
||||
should-build: true
|
||||
|
||||
- name: Template (arm64, release)
|
||||
target: template_release
|
||||
arch: arm64
|
||||
build-mono: false
|
||||
artifact-name: macos-templates
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template (arm64, debug)
|
||||
target: template_debug
|
||||
arch: arm64
|
||||
build-mono: false
|
||||
artifact-name: macos-templates
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# ! Disabled for now: .NET version fail to build
|
||||
- name: .NET Editor (x86_64, release)
|
||||
target: editor
|
||||
arch: x86_64
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# - name: .NET Editor (x86_64, release)
|
||||
# target: editor
|
||||
# arch: x86_64
|
||||
# build-mono: true
|
||||
# artifact-name: macos-mono-editor
|
||||
# cache-name: macos-editor
|
||||
- name: .NET Template (x86_64, release)
|
||||
target: template_release
|
||||
arch: x86_64
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# - name: .NET Template (x86_64, release)
|
||||
# target: template_release
|
||||
# arch: x86_64
|
||||
# build-mono: true
|
||||
# artifact-name: macos-mono-templates
|
||||
- name: .NET Template (x86_64, debug)
|
||||
target: template_debug
|
||||
arch: x86_64
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# - name: .NET Template (x86_64, debug)
|
||||
# target: template_debug
|
||||
# arch: x86_64
|
||||
# build-mono: true
|
||||
# artifact-name: macos-mono-templates
|
||||
- name: .NET Editor (arm64, release)
|
||||
target: editor
|
||||
arch: arm64
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# - name: .NET Editor (arm64, release)
|
||||
# target: editor
|
||||
# arch: arm64
|
||||
# build-mono: true
|
||||
# artifact-name: macos-mono-editor
|
||||
# cache-name: macos-editor
|
||||
- name: .NET Template (arm64, release)
|
||||
target: template_release
|
||||
arch: arm64
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# - name: .NET Template (arm64, release)
|
||||
# target: template_release
|
||||
# arch: arm64
|
||||
# build-mono: true
|
||||
# artifact-name: macos-mono-templates
|
||||
- name: .NET Template (arm64, debug)
|
||||
target: template_debug
|
||||
arch: arm64
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# - name: .NET Template (arm64, debug)
|
||||
# target: template_debug
|
||||
# arch: arm64
|
||||
# build-mono: true
|
||||
# artifact-name: macos-mono-templates
|
||||
exclude:
|
||||
- { opts: { should-build: false } }
|
||||
|
||||
env:
|
||||
BIN: godot.macos.${{matrix.target}}.${{matrix.arch}}${{ matrix.build-mono == true && '.mono' || '' }}
|
||||
BIN: godot.macos.${{matrix.opts.target}}.${{matrix.opts.arch}}${{ matrix.opts.dotnet == true && '.mono' || '' }}
|
||||
|
||||
steps:
|
||||
|
||||
- name: Clone Godot
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: godotengine/godot
|
||||
ref: ${{ inputs.godot-treeish }}
|
||||
ref: ${{ inputs.godot-ref }}
|
||||
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: modules/limboai
|
||||
ref: ${{ inputs.limboai-treeish }}
|
||||
ref: ${{ inputs.limboai-ref }}
|
||||
|
||||
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
|
||||
- uses: ./modules/limboai/.github/actions/init-version
|
||||
|
||||
- name: Set up Python 3.x
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
architecture: 'x64'
|
||||
python-version: "3.x"
|
||||
architecture: "x64"
|
||||
|
||||
- name: Set up scons
|
||||
run: |
|
||||
python -c "import sys; print(sys.version)"
|
||||
python -m pip install scons==4.4.0
|
||||
|
||||
- name: Set up .NET SDK 6.0
|
||||
if: matrix.opts.dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: "6.0.x"
|
||||
|
||||
- name: Diagnostics
|
||||
run: |
|
||||
python --version
|
||||
|
@ -154,45 +165,49 @@ jobs:
|
|||
|
||||
- name: Set up Vulkan SDK
|
||||
run: |
|
||||
sh misc/scripts/install_vulkan_sdk_macos.sh
|
||||
# ! Note: Vulkan SDK changed packaging, so we need to inline these steps for the time being.
|
||||
#sh misc/scripts/install_vulkan_sdk_macos.sh
|
||||
|
||||
curl -L "https://sdk.lunarg.com/sdk/download/latest/mac/config.json" -o /tmp/vulkan-sdk.json
|
||||
sdk_version=`jq -r '.version' /tmp/vulkan-sdk.json`
|
||||
curl -L "https://sdk.lunarg.com/sdk/download/latest/mac/vulkan-sdk.zip" -o /tmp/vulkan-sdk.zip
|
||||
unzip /tmp/vulkan-sdk.zip -d /tmp
|
||||
/tmp/InstallVulkan-${sdk_version}.app/Contents/MacOS/InstallVulkan-${sdk_version} --accept-licenses --default-answer --confirm-command install
|
||||
rm -Rf /tmp/InstallVulkan-${sdk_version}.app
|
||||
rm -f /tmp/vulkan-sdk.zip
|
||||
|
||||
- name: Set up scons cache
|
||||
uses: actions/cache@v3
|
||||
if: inputs.test-build # ! Only cache test/PR builds
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{github.workspace}}/.scons_cache/
|
||||
key: ${{matrix.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
key: ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
|
||||
restore-keys: |
|
||||
${{env.BIN}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
${{env.BIN}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}
|
||||
${{env.BIN}}-${{env.GODOT_BASE_BRANCH}}
|
||||
${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
|
||||
${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}
|
||||
${{env.BIN}}-${{inputs.godot-ref}}
|
||||
|
||||
- name: Compilation
|
||||
env:
|
||||
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
|
||||
run: |
|
||||
scons -j2 platform=macos target=${{matrix.target}} arch=${{matrix.arch}} module_mono_enabled=${{matrix.build-mono}} ${{env.SCONSFLAGS}}
|
||||
scons -j2 platform=macos target=${{matrix.opts.target}} arch=${{matrix.opts.arch}} module_mono_enabled=${{matrix.opts.dotnet}} ${{env.SCONSFLAGS}}
|
||||
|
||||
# ! Disabled for now: .NET version fail to build
|
||||
|
||||
# - name: Generate C# glue
|
||||
# if: matrix.build-mono && matrix.target == 'editor'
|
||||
# run: |
|
||||
# ./bin/$BIN --headless --generate-mono-glue ./modules/mono/glue || true
|
||||
|
||||
# - name: Build .NET solutions
|
||||
# if: matrix.build-mono && matrix.target == 'editor'
|
||||
# run: |
|
||||
# ./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=macos
|
||||
- name: Build .NET assemblies
|
||||
if: matrix.opts.dotnet && matrix.opts.target == 'editor'
|
||||
uses: ./modules/limboai/.github/actions/build-dotnet-assemblies
|
||||
with:
|
||||
platform: macos
|
||||
bin: ${{env.BIN}}
|
||||
|
||||
- name: Prepare artifact
|
||||
run: |
|
||||
strip bin/godot.*
|
||||
chmod +x bin/godot.*
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact-name }}
|
||||
name: tmp-${{matrix.opts.dotnet == true && 'dotnet-' || ''}}macos-${{matrix.opts.target}}-${{matrix.opts.arch}}
|
||||
path: bin/*
|
||||
|
||||
make-macos-bundle:
|
||||
|
@ -200,81 +215,106 @@ jobs:
|
|||
name: Make macOS Bundles
|
||||
needs: macos-builds
|
||||
|
||||
steps:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
opts:
|
||||
- download-prefix: tmp-macos
|
||||
dotnet: false
|
||||
should-build: true
|
||||
- download-prefix: tmp-dotnet-macos
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
exclude:
|
||||
- { opts: { should-build: false } }
|
||||
|
||||
steps:
|
||||
- name: Clone Godot
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: godotengine/godot
|
||||
ref: ${{ inputs.godot-treeish }}
|
||||
ref: ${{ inputs.godot-ref }}
|
||||
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: modules/limboai
|
||||
ref: ${{ inputs.limboai-treeish }}
|
||||
ref: ${{ inputs.limboai-ref }}
|
||||
|
||||
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
|
||||
- uses: ./modules/limboai/.github/actions/init-version
|
||||
|
||||
- name: Download editor artifact
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: macos-editor
|
||||
pattern: ${{matrix.opts.download-prefix}}-editor-*
|
||||
merge-multiple: true
|
||||
path: bin/
|
||||
|
||||
# Zipping the editor bundle to retain executable bit;
|
||||
# workaround for: https://github.com/actions/upload-artifact/issues/38
|
||||
- name: Make editor bundle
|
||||
env:
|
||||
APP_NAME: Godot${{matrix.opts.dotnet == true && '_mono' || ''}}.app
|
||||
run: |
|
||||
ls bin/
|
||||
lipo -create bin/godot.macos.editor.x86_64 bin/godot.macos.editor.arm64 -output bin/godot.macos.editor.universal
|
||||
strip bin/godot.macos.editor.universal
|
||||
rm bin/godot.macos.editor.{x86_64,arm64}
|
||||
lipo -create bin/godot.macos.editor.x86_64* bin/godot.macos.editor.arm64* -output bin/godot.macos.editor.universal
|
||||
mkdir -p out/editor/
|
||||
cp -r misc/dist/macos_tools.app out/editor/Godot.app
|
||||
mkdir -p out/editor/Godot.app/Contents/MacOS
|
||||
cp bin/godot.macos.editor.universal out/editor/Godot.app/Contents/MacOS/Godot
|
||||
chmod +x out/editor/Godot.app/Contents/MacOS/Godot
|
||||
cp -r misc/dist/macos_tools.app out/editor/${APP_NAME}
|
||||
mkdir -p out/editor/${APP_NAME}/Contents/{MacOS,Resources}
|
||||
cp bin/godot.macos.editor.universal out/editor/${APP_NAME}/Contents/MacOS/Godot
|
||||
chmod +x out/editor/${APP_NAME}/Contents/MacOS/Godot
|
||||
cp -r bin/GodotSharp out/editor/${APP_NAME}/Contents/Resources/GodotSharp || true
|
||||
pushd out/editor
|
||||
zip -q -9 -r ${APP_NAME}.zip ${APP_NAME}
|
||||
rm -rf ${APP_NAME}
|
||||
echo -e "## Why another ZIP inside?\n\nWorkaround for: https://github.com/actions/upload-artifact/issues/38\n" > README.md
|
||||
popd
|
||||
rm -rf bin/*
|
||||
ls out/editor/
|
||||
|
||||
- name: Upload editor bundle
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{env.NAME_PREFIX}}.editor.macos.universal
|
||||
name: ${{env.NAME_PREFIX}}${{matrix.opts.dotnet == true && '.dotnet' || ''}}.editor.macos.universal
|
||||
path: out/editor/*
|
||||
|
||||
- name: Download templates artifact
|
||||
uses: actions/download-artifact@v3
|
||||
if: ${{ !inputs.test-build }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: macos-templates
|
||||
pattern: ${{matrix.opts.download-prefix}}-template_*
|
||||
merge-multiple: true
|
||||
path: bin/
|
||||
|
||||
- name: Make templates bundle
|
||||
if: ${{ !inputs.test-build }}
|
||||
run: |
|
||||
rm -rf out/
|
||||
ls bin/
|
||||
lipo -create bin/godot.macos.template_release.x86_64 bin/godot.macos.template_release.arm64 -output bin/godot.macos.template_release.universal
|
||||
lipo -create bin/godot.macos.template_debug.x86_64 bin/godot.macos.template_debug.arm64 -output bin/godot.macos.template_debug.universal
|
||||
rm bin/godot.macos.template_{debug,release}.{x86_64,arm64}
|
||||
strip bin/godot.*
|
||||
lipo -create bin/godot.macos.template_release.x86_64* bin/godot.macos.template_release.arm64* -output bin/godot.macos.template_release.universal
|
||||
lipo -create bin/godot.macos.template_debug.x86_64* bin/godot.macos.template_debug.arm64* -output bin/godot.macos.template_debug.universal
|
||||
cp -r misc/dist/macos_template.app macos_template.app
|
||||
mkdir -p macos_template.app/Contents/MacOS
|
||||
cp bin/godot.macos.template_debug.universal macos_template.app/Contents/MacOS/godot_macos_debug.universal
|
||||
cp bin/godot.macos.template_release.universal macos_template.app/Contents/MacOS/godot_macos_release.universal
|
||||
chmod +x macos_template.app/Contents/MacOS/godot_macos_{release,debug}.universal
|
||||
zip -r macos.zip macos_template.app
|
||||
rm bin/*
|
||||
zip -q -9 -r macos.zip macos_template.app
|
||||
mkdir -p out/templates/
|
||||
mv macos.zip out/templates/macos.zip
|
||||
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}${{matrix.opts.dotnet == true && '.mono' || ''}}" > out/templates/version.txt
|
||||
rm -rf bin/*
|
||||
ls out/templates/
|
||||
|
||||
- uses: geekyeggo/delete-artifact@v2
|
||||
- uses: geekyeggo/delete-artifact@v5
|
||||
with:
|
||||
name: macos-*
|
||||
useGlob: true
|
||||
failOnError: false
|
||||
name: ${{matrix.opts.download-prefix}}-*
|
||||
useGlob: true
|
||||
failOnError: false
|
||||
|
||||
- name: Upload templates bundle
|
||||
uses: actions/upload-artifact@v3
|
||||
if: ${{ !inputs.test-build }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{env.NAME_PREFIX}}.export-templates
|
||||
name: ${{env.NAME_PREFIX}}${{matrix.opts.dotnet == true && '.dotnet' || ''}}.export-templates.macos
|
||||
path: out/*
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
name: 📦️ Merge templates
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
godot-ref:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
godot-ref:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
merge-templates:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone Godot
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: godotengine/godot
|
||||
ref: ${{ inputs.godot-ref }}
|
||||
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: modules/limboai
|
||||
ref: ${{ inputs.limboai-ref }}
|
||||
|
||||
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
|
||||
- uses: ./modules/limboai/.github/actions/init-version
|
||||
|
||||
- name: Merge classical templates
|
||||
uses: actions/upload-artifact/merge@v4
|
||||
with:
|
||||
name: ${{env.NAME_PREFIX}}.export-templates
|
||||
pattern: ${{env.NAME_PREFIX}}.{export-templates,template_}*
|
||||
delete-merged: true
|
||||
|
||||
- name: Merge .NET templates
|
||||
uses: actions/upload-artifact/merge@v4
|
||||
with:
|
||||
name: ${{env.NAME_PREFIX}}.dotnet.export-templates
|
||||
pattern: ${{env.NAME_PREFIX}}.dotnet.{export-templates,template_}*
|
||||
delete-merged: true
|
|
@ -1,55 +0,0 @@
|
|||
name: 🔗 All Builds
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
godot-treeish:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
default: master
|
||||
limboai-treeish:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
|
||||
jobs:
|
||||
android-build:
|
||||
name: 🤖 Android
|
||||
uses: ./.github/workflows/android.yml
|
||||
with:
|
||||
godot-treeish: ${{ inputs.godot-treeish }}
|
||||
limboai-treeish: ${{ inputs.limboai-treeish }}
|
||||
|
||||
ios-build:
|
||||
name: 🍏 iOS
|
||||
uses: ./.github/workflows/ios.yml
|
||||
with:
|
||||
godot-treeish: ${{ inputs.godot-treeish }}
|
||||
limboai-treeish: ${{ inputs.limboai-treeish }}
|
||||
|
||||
linux-build:
|
||||
name: 🐧 Linux
|
||||
uses: ./.github/workflows/linux.yml
|
||||
with:
|
||||
godot-treeish: ${{ inputs.godot-treeish }}
|
||||
limboai-treeish: ${{ inputs.limboai-treeish }}
|
||||
|
||||
macos-build:
|
||||
name: 🍎 macOS
|
||||
uses: ./.github/workflows/macos.yml
|
||||
with:
|
||||
godot-treeish: ${{ inputs.godot-treeish }}
|
||||
limboai-treeish: ${{ inputs.limboai-treeish }}
|
||||
|
||||
windows-build:
|
||||
name: 🪟 Windows
|
||||
uses: ./.github/workflows/windows.yml
|
||||
with:
|
||||
godot-treeish: ${{ inputs.godot-treeish }}
|
||||
limboai-treeish: ${{ inputs.limboai-treeish }}
|
||||
|
||||
web-build:
|
||||
name: 🌐 Web
|
||||
uses: ./.github/workflows/web.yml
|
||||
with:
|
||||
godot-treeish: ${{ inputs.godot-treeish }}
|
||||
limboai-treeish: ${{ inputs.limboai-treeish }}
|
|
@ -0,0 +1,162 @@
|
|||
name: 🔎 Test builds
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
push:
|
||||
branches: [master]
|
||||
paths-ignore:
|
||||
- "README.md"
|
||||
- "LICENSE.md"
|
||||
- "**/*.png"
|
||||
- "demo/**"
|
||||
- "doc/**"
|
||||
|
||||
pull_request:
|
||||
branches: [master]
|
||||
paths-ignore:
|
||||
- "README.md"
|
||||
- "LICENSE.md"
|
||||
- "**/*.png"
|
||||
- "demo/**"
|
||||
- "doc/**"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
# Global Settings.
|
||||
env:
|
||||
GODOT_REF: "master"
|
||||
GODOT_CPP_REF: "master"
|
||||
|
||||
jobs:
|
||||
unit-tests:
|
||||
name: 🧪 Unit tests
|
||||
runs-on: "ubuntu-20.04"
|
||||
|
||||
# Settings
|
||||
env:
|
||||
SCONSFLAGS: platform=linuxbsd target=editor arch=x86_64 production=false dev_build=true tests=true verbose=yes warnings=extra werror=yes strict_checks=yes
|
||||
SCONS_CACHE_LIMIT: 7168
|
||||
BIN: godot.linuxbsd.editor.dev.x86_64
|
||||
|
||||
steps:
|
||||
- name: Clone Godot
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: godotengine/godot
|
||||
ref: ${{ env.GODOT_REF }}
|
||||
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: modules/limboai
|
||||
|
||||
- name: Set up Linux toolchain
|
||||
uses: ./modules/limboai/.github/actions/setup-linux-toolchain
|
||||
with:
|
||||
arch: x86_64
|
||||
|
||||
- name: Set up scons cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{github.workspace}}/.scons_cache/
|
||||
key: ${{env.BIN}}-${{env.GODOT_REF}}-${{github.ref}}-${{github.sha}}
|
||||
restore-keys: |
|
||||
${{env.BIN}}-${{env.GODOT_REF}}-${{github.ref}}-${{github.sha}}
|
||||
${{env.BIN}}-${{env.GODOT_REF}}-${{github.ref}}
|
||||
${{env.BIN}}-${{env.GODOT_REF}}
|
||||
continue-on-error: true
|
||||
|
||||
- name: Set up Python 3.x
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
architecture: "x64"
|
||||
|
||||
- name: Set up scons
|
||||
run: |
|
||||
python -c "import sys; print(sys.version)"
|
||||
python -m pip install scons==4.4.0
|
||||
python --version
|
||||
scons --version
|
||||
|
||||
- name: Setup GCC problem matcher
|
||||
uses: ammaraskar/gcc-problem-matcher@master
|
||||
|
||||
- name: Compilation
|
||||
env:
|
||||
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
|
||||
run: |
|
||||
PATH=${GITHUB_WORKSPACE}/buildroot/bin:$PATH
|
||||
scons ${{env.SCONSFLAGS}}
|
||||
|
||||
- name: Verify build
|
||||
run: |
|
||||
ls -l bin/
|
||||
bin/${{ env.BIN }} --version
|
||||
bin/${{ env.BIN }} --help
|
||||
|
||||
- name: Unit tests
|
||||
run: |
|
||||
bin/${{ env.BIN }} --test --headless
|
||||
|
||||
static-checks:
|
||||
name: ⚙️ Static checks
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Code style checks
|
||||
uses: pre-commit/action@v3.0.1
|
||||
with:
|
||||
extra_args: --all-files
|
||||
|
||||
cache-env:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
godot-ref: ${{ steps.cache-env.outputs.godot-ref }}
|
||||
godot-cpp-ref: ${{ steps.cache-env.outputs.godot-cpp-ref }}
|
||||
steps:
|
||||
- name: Cache env
|
||||
id: cache-env
|
||||
run: |
|
||||
echo "godot-ref=${GODOT_REF}" >> "$GITHUB_OUTPUT"
|
||||
echo "godot-cpp-ref=${GODOT_CPP_REF}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
linux-test-build:
|
||||
name: 🐧 Linux
|
||||
needs: cache-env
|
||||
uses: ./.github/workflows/linux.yml
|
||||
with:
|
||||
godot-ref: ${{ needs.cache-env.outputs.godot-ref }}
|
||||
limboai-ref: ${{ github.sha }}
|
||||
test-build: true
|
||||
|
||||
windows-test-build:
|
||||
name: 🪟 Windows
|
||||
needs: cache-env
|
||||
uses: ./.github/workflows/windows.yml
|
||||
with:
|
||||
godot-ref: ${{ needs.cache-env.outputs.godot-ref }}
|
||||
limboai-ref: ${{ github.sha }}
|
||||
test-build: true
|
||||
|
||||
macos-test-build:
|
||||
name: 🍎 macOS
|
||||
needs: cache-env
|
||||
uses: ./.github/workflows/macos.yml
|
||||
with:
|
||||
godot-ref: ${{ needs.cache-env.outputs.godot-ref }}
|
||||
limboai-ref: ${{ github.sha }}
|
||||
test-build: true
|
||||
|
||||
gdextension:
|
||||
name: 🔌 GDExtension
|
||||
needs: cache-env
|
||||
uses: ./.github/workflows/gdextension.yml
|
||||
with:
|
||||
godot-cpp-ref: ${{ needs.cache-env.outputs.godot-cpp-ref }}
|
||||
limboai-ref: ${{ github.sha }}
|
||||
test-build: true
|
|
@ -2,22 +2,22 @@ name: 🌐 Web builds
|
|||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
godot-treeish:
|
||||
godot-ref:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
default: master
|
||||
limboai-treeish:
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
godot-treeish:
|
||||
godot-ref:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
default: master
|
||||
limboai-treeish:
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
|
@ -27,7 +27,7 @@ env:
|
|||
SCONS_CACHE_LIMIT: 4096
|
||||
# With `lto=full` VM seems to run out of ram and build fails
|
||||
SCONSFLAGS: use_static_cpp=yes debug_symbols=no lto=thin optimize=size verbose=yes warnings=extra werror=yes tests=no
|
||||
EM_VERSION: 3.1.18
|
||||
EM_VERSION: 3.1.45
|
||||
EM_CACHE_FOLDER: "emsdk-cache"
|
||||
|
||||
jobs:
|
||||
|
@ -40,41 +40,71 @@ jobs:
|
|||
include:
|
||||
- name: Template (release)
|
||||
target: template_release
|
||||
dlink_enabled: no
|
||||
threads: true
|
||||
dlink: false
|
||||
|
||||
- name: Template (release, dlink_enabled=true)
|
||||
- name: Template (release, dlink)
|
||||
target: template_release
|
||||
dlink_enabled: yes
|
||||
threads: true
|
||||
dlink: true
|
||||
|
||||
- name: Template (debug)
|
||||
target: template_debug
|
||||
dlink_enabled: no
|
||||
threads: true
|
||||
dlink: false
|
||||
|
||||
- name: Template (debug, dlink_enabled=true)
|
||||
- name: Template (debug, dlink)
|
||||
target: template_debug
|
||||
dlink_enabled: yes
|
||||
threads: true
|
||||
dlink: true
|
||||
|
||||
- name: Template (release, nothreads)
|
||||
target: template_release
|
||||
threads: false
|
||||
dlink: false
|
||||
|
||||
- name: Template (release, nothreads, dlink)
|
||||
target: template_release
|
||||
threads: false
|
||||
dlink: true
|
||||
|
||||
- name: Template (debug, nothreads)
|
||||
target: template_debug
|
||||
threads: false
|
||||
dlink: false
|
||||
|
||||
- name: Template (debug, nothreads, dlink)
|
||||
target: template_debug
|
||||
threads: false
|
||||
dlink: true
|
||||
|
||||
env:
|
||||
CACHE_NAME: godot.web.${{matrix.target}}${{ matrix.dlink_enabled == true && '.dlink' || '' }}
|
||||
CACHE_NAME: godot.web.${{matrix.target}}${{ matrix.dlink == true && '.dlink' || '' }}
|
||||
|
||||
steps:
|
||||
- name: Clone Godot
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: godotengine/godot
|
||||
ref: ${{ inputs.godot-treeish }}
|
||||
ref: ${{ inputs.godot-ref }}
|
||||
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: modules/limboai
|
||||
ref: ${{ inputs.limboai-treeish }}
|
||||
ref: ${{ inputs.limboai-ref }}
|
||||
|
||||
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
|
||||
- uses: ./modules/limboai/.github/actions/init-version
|
||||
|
||||
- name: Set up Emscripten latest
|
||||
uses: mymindstorm/setup-emsdk@v12
|
||||
- name: Set up Emscripten cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{env.EM_CACHE_FOLDER}}
|
||||
key: ${{env.EM_VERSION}}-${{runner.os}}-libs
|
||||
|
||||
- name: Set up Emscripten
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
with:
|
||||
version: ${{env.EM_VERSION}}
|
||||
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
|
||||
|
@ -90,33 +120,39 @@ jobs:
|
|||
python --version
|
||||
scons --version
|
||||
|
||||
- name: Set up scons cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{github.workspace}}/.scons_cache/
|
||||
key: ${{matrix.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
restore-keys: |
|
||||
${{env.CACHE_NAME}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
${{env.CACHE_NAME}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}
|
||||
${{env.CACHE_NAME}}-${{env.GODOT_BASE_BRANCH}}
|
||||
# ! Note: we stopped using the scons cache in release builds.
|
||||
# - name: Set up scons cache
|
||||
# uses: actions/cache@v4
|
||||
# with:
|
||||
# path: ${{github.workspace}}/.scons_cache/
|
||||
# key: ${{env.CACHE_NAME}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
|
||||
# restore-keys: |
|
||||
# ${{env.CACHE_NAME}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
|
||||
# ${{env.CACHE_NAME}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}
|
||||
# ${{env.CACHE_NAME}}-${{inputs.godot-ref}}
|
||||
|
||||
- name: Compilation
|
||||
env:
|
||||
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
|
||||
run: |
|
||||
scons platform=web target=${{matrix.target}} dlink_enabled=${{matrix.dlink_enabled}} ${{env.SCONSFLAGS}}
|
||||
scons platform=web target=${{matrix.target}} threads=${{matrix.threads}} dlink_enabled=${{matrix.dlink}} ${{env.SCONSFLAGS}}
|
||||
|
||||
- name: Prepare artifacts
|
||||
run: |
|
||||
mkdir -p out/templates/
|
||||
mv bin/godot.web.template_release.wasm32.zip out/templates/web_release.zip || true
|
||||
mv bin/godot.web.template_release.wasm32.dlink.zip out/templates/web_dlink_release.zip || true
|
||||
mv bin/godot.web.template_debug.wasm32.zip out/templates/web_debug.zip || true
|
||||
mv bin/godot.web.template_debug.wasm32.nothreads.zip out/templates/web_nothreads_debug.zip || true
|
||||
mv bin/godot.web.template_debug.wasm32.dlink.zip out/templates/web_dlink_debug.zip || true
|
||||
mv bin/godot.web.template_debug.wasm32.nothreads.dlink.zip out/templates/web_dlink_nothreads_debug.zip || true
|
||||
mv bin/godot.web.template_release.wasm32.zip out/templates/web_release.zip || true
|
||||
mv bin/godot.web.template_release.wasm32.nothreads.zip out/templates/web_nothreads_release.zip || true
|
||||
mv bin/godot.web.template_release.wasm32.dlink.zip out/templates/web_dlink_release.zip || true
|
||||
mv bin/godot.web.template_release.wasm32.nothreads.dlink.zip out/templates/web_dlink_nothreads_release.zip || true
|
||||
rm -rf bin/
|
||||
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}" > out/templates/version.txt
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{env.NAME_PREFIX}}.export-templates
|
||||
name: ${{env.NAME_PREFIX}}.${{matrix.target}}.web${{matrix.threads == false && '.nothreads' || ''}}${{matrix.dlink == true && '.dlink' || ''}}
|
||||
path: out/*
|
||||
|
|
|
@ -2,181 +2,357 @@ name: 🪟 Windows builds
|
|||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
godot-treeish:
|
||||
godot-ref:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
default: master
|
||||
limboai-treeish:
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
test-build:
|
||||
description: Limit to pre-defined test builds
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
godot-treeish:
|
||||
godot-ref:
|
||||
description: A tag, branch or commit hash in the Godot repository.
|
||||
type: string
|
||||
default: master
|
||||
limboai-treeish:
|
||||
limboai-ref:
|
||||
description: A tag, branch or commit hash in the LimboAI repository.
|
||||
type: string
|
||||
default: master
|
||||
test-build:
|
||||
description: Limit to pre-defined test builds
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
# Global Settings
|
||||
env:
|
||||
SCONS_CACHE_MSVC_CONFIG: true
|
||||
BUILD_IMAGE_VERSION: 4.3-f40
|
||||
MESA_VERSION: 23.1.9-1
|
||||
SCONS_CACHE_LIMIT: 4096
|
||||
SCONSFLAGS: production=yes tests=no verbose=yes warnings=extra werror=yes
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: true
|
||||
SCONSFLAGS: production=yes use_mingw=yes verbose=yes warnings=no progress=no d3d12=yes
|
||||
|
||||
jobs:
|
||||
windows-builds:
|
||||
runs-on: "windows-latest"
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: "ubuntu-24.04"
|
||||
name: ${{ matrix.opts.name }}
|
||||
outputs:
|
||||
built-dotnet-editor: ${{ steps.mark-dotnet-editor.outputs.built-dotnet-editor }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
opts:
|
||||
# * Standard x86_64
|
||||
|
||||
- name: Editor (x86_64, release)
|
||||
target: editor
|
||||
arch: x86_64
|
||||
build-mono: false
|
||||
llvm: false
|
||||
dotnet: false
|
||||
should-build: true
|
||||
|
||||
- name: Template (x86_64, release)
|
||||
target: template_release
|
||||
arch: x86_64
|
||||
build-mono: false
|
||||
llvm: false
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template (x86_64, debug)
|
||||
target: template_debug
|
||||
arch: x86_64
|
||||
build-mono: false
|
||||
llvm: false
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# * Standard x86_32
|
||||
|
||||
# - name: Editor (x86_32, release)
|
||||
# target: editor
|
||||
# arch: x86_32
|
||||
# build-mono: false
|
||||
# llvm: false
|
||||
# dotnet: false
|
||||
# should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template (x86_32, release)
|
||||
target: template_release
|
||||
arch: x86_32
|
||||
build-mono: false
|
||||
llvm: false
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template (x86_32, debug)
|
||||
target: template_debug
|
||||
arch: x86_32
|
||||
build-mono: false
|
||||
llvm: false
|
||||
dotnet: false
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# * Standard arm64
|
||||
|
||||
# - name: Editor (arm64, release)
|
||||
# target: editor
|
||||
# arch: arm64
|
||||
# llvm: true
|
||||
# dotnet: false
|
||||
# should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template (arm64, release)
|
||||
target: template_release
|
||||
arch: arm64
|
||||
llvm: true
|
||||
dotnet: false
|
||||
scons-flags: mingw_prefix=/root/llvm-mingw
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template (arm64, debug)
|
||||
target: template_debug
|
||||
arch: arm64
|
||||
llvm: true
|
||||
dotnet: false
|
||||
scons-flags: mingw_prefix=/root/llvm-mingw
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# * .NET x86_64
|
||||
|
||||
- name: Editor .NET (x86_64, release)
|
||||
target: editor
|
||||
arch: x86_64
|
||||
build-mono: true
|
||||
llvm: false
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template .NET (x86_64, release)
|
||||
target: template_release
|
||||
arch: x86_64
|
||||
build-mono: true
|
||||
llvm: false
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template .NET (x86_64, debug)
|
||||
target: template_debug
|
||||
arch: x86_64
|
||||
build-mono: true
|
||||
llvm: false
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# * .NET x86_32
|
||||
|
||||
# - name: Editor .NET (x86_32, release)
|
||||
# target: editor
|
||||
# arch: x86_32
|
||||
# build-mono: true
|
||||
# llvm: false
|
||||
# dotnet: true
|
||||
# should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template .NET (x86_32, release)
|
||||
target: template_release
|
||||
arch: x86_64
|
||||
build-mono: true
|
||||
arch: x86_32
|
||||
llvm: false
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template .NET (x86_32, debug)
|
||||
target: template_debug
|
||||
arch: x86_32
|
||||
build-mono: true
|
||||
llvm: false
|
||||
dotnet: true
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
# * .NET arm64
|
||||
|
||||
# - name: Editor .NET (arm64, release)
|
||||
# target: editor
|
||||
# arch: arm64
|
||||
# llvm: true
|
||||
# dotnet: true
|
||||
# should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template .NET (arm64, release)
|
||||
target: template_release
|
||||
arch: arm64
|
||||
llvm: true
|
||||
dotnet: true
|
||||
scons-flags: mingw_prefix=/root/llvm-mingw
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
- name: Template .NET (arm64, debug)
|
||||
target: template_debug
|
||||
arch: arm64
|
||||
llvm: true
|
||||
dotnet: true
|
||||
scons-flags: mingw_prefix=/root/llvm-mingw
|
||||
should-build: ${{ !inputs.test-build }}
|
||||
|
||||
exclude:
|
||||
- { opts: { should-build: false } }
|
||||
|
||||
env:
|
||||
BIN: godot.windows.${{matrix.target}}.${{matrix.arch}}${{ matrix.build-mono == true && '.mono' || '' }}
|
||||
BIN: godot.windows.${{matrix.opts.target}}.${{matrix.opts.arch}}${{matrix.opts.llvm && '.llvm' || ''}}${{matrix.opts.dotnet == true && '.mono' || ''}}
|
||||
|
||||
steps:
|
||||
- name: Clone Godot
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: godotengine/godot
|
||||
ref: ${{ inputs.godot-treeish }}
|
||||
ref: ${{ inputs.godot-ref }}
|
||||
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: modules/limboai
|
||||
ref: ${{ inputs.limboai-treeish }}
|
||||
ref: ${{ inputs.limboai-ref }}
|
||||
|
||||
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
|
||||
# Inits GODOT_VERSION, LIMBOAI_VERSION, NAME_PREFIX, GODOT_VERSION_STATUS, BUILD_NAME environment variables.
|
||||
- uses: ./modules/limboai/.github/actions/init-version
|
||||
|
||||
- name: Set up Python 3.x
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
architecture: 'x64'
|
||||
|
||||
- name: Set up scons
|
||||
run: |
|
||||
python -c "import sys; print(sys.version)"
|
||||
python -m pip install scons==4.4.0
|
||||
python --version
|
||||
scons --version
|
||||
|
||||
- name: Set up MSVC problem matcher
|
||||
uses: ammaraskar/msvc-problem-matcher@master
|
||||
|
||||
- name: Set up scons cache
|
||||
uses: actions/cache@v3
|
||||
if: inputs.test-build # ! Only cache test/PR builds
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{github.workspace}}/.scons_cache/
|
||||
key: ${{matrix.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
key: ${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
|
||||
restore-keys: |
|
||||
${{env.BIN}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
${{env.BIN}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}
|
||||
${{env.BIN}}-${{env.GODOT_BASE_BRANCH}}
|
||||
${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
|
||||
${{env.BIN}}-${{inputs.godot-ref}}-${{inputs.limboai-ref}}
|
||||
${{env.BIN}}-${{inputs.godot-ref}}
|
||||
|
||||
- name: Compilation
|
||||
env:
|
||||
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
|
||||
- name: Static ANGLE libs
|
||||
run: |
|
||||
scons -j2 platform=windows target=${{matrix.target}} arch=${{matrix.arch}} module_mono_enabled=${{matrix.build-mono}} ${{env.SCONSFLAGS}}
|
||||
mkdir -p deps/angle
|
||||
cd deps/angle
|
||||
url=https://github.com/godotengine/godot-angle-static/releases/download/chromium%2F6601.2/godot-angle-static
|
||||
curl -L -o windows_${{matrix.opts.arch}}.zip $url-${{matrix.opts.arch}}-${{matrix.opts.llvm && 'llvm' || 'gcc'}}-release.zip
|
||||
unzip windows_${{matrix.opts.arch}}.zip
|
||||
rm windows_${{matrix.opts.arch}}.zip
|
||||
|
||||
- name: Generate C# glue
|
||||
if: matrix.build-mono && matrix.target == 'editor'
|
||||
env:
|
||||
GODOT_VERSION_STATUS: limboai
|
||||
- name: Mesa libs
|
||||
run: |
|
||||
./bin/${{ env.BIN }} --headless --generate-mono-glue ./modules/mono/glue || true
|
||||
mkdir -p deps/mesa
|
||||
cd deps/mesa
|
||||
curl -L -o mesa_${{matrix.opts.arch}}.zip https://github.com/godotengine/godot-nir-static/releases/download/${{env.MESA_VERSION}}/godot-nir-static-${{matrix.opts.arch}}-${{matrix.opts.llvm && 'llvm' || 'gcc'}}-release.zip
|
||||
unzip -o mesa_${{matrix.opts.arch}}.zip
|
||||
rm -f mesa_${{matrix.opts.arch}}.zip
|
||||
|
||||
- name: Build .NET solutions
|
||||
if: matrix.build-mono && matrix.target == 'editor'
|
||||
env:
|
||||
GODOT_VERSION_STATUS: limboai
|
||||
- name: Pull build container
|
||||
run: |
|
||||
python ./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=windows
|
||||
podman pull ghcr.io/limbonaut/godot-windows:${{env.BUILD_IMAGE_VERSION}}
|
||||
|
||||
- name: Build using container
|
||||
shell: bash
|
||||
run: |
|
||||
scons_command="scons \
|
||||
platform=windows \
|
||||
target=${{matrix.opts.target}} \
|
||||
arch=${{matrix.opts.arch}} \
|
||||
use_llvm=${{matrix.opts.llvm}} \
|
||||
module_mono_enabled=${{matrix.opts.dotnet}} \
|
||||
${{env.SCONSFLAGS}} \
|
||||
${{matrix.opts.scons-flags}} \
|
||||
angle_libs=/build/deps/angle \
|
||||
mesa_libs=/build/deps/mesa \
|
||||
"
|
||||
podman_run="podman run -it --rm \
|
||||
--env GODOT_VERSION_STATUS=${GODOT_VERSION_STATUS} \
|
||||
--env BUILD_NAME=${BUILD_NAME} \
|
||||
--env NUM_CORES=$(nproc --all) \
|
||||
--env DOTNET_NOLOGO=true \
|
||||
--env DOTNET_CLI_TELEMETRY_OPTOUT=true \
|
||||
--env SCONS_CACHE=/build/.scons_cache/ \
|
||||
--env SCONS_CACHE_LIMIT=${SCONS_CACHE_LIMIT} \
|
||||
-v ${GITHUB_WORKSPACE}/:/build/ \
|
||||
-w /build godot-windows:${{env.BUILD_IMAGE_VERSION}} bash -c \
|
||||
"
|
||||
echo "Running ${podman_run} \"${scons_command}\""
|
||||
${podman_run} "${scons_command}"
|
||||
|
||||
- name: Prepare artifact
|
||||
shell: bash
|
||||
env:
|
||||
OUTDIR: ${{ startsWith(matrix.target, 'template') && 'out/templates' || 'out/' }}
|
||||
OUTDIR: ${{ startsWith(matrix.opts.target, 'template') && 'out/templates' || 'out/' }}
|
||||
run: |
|
||||
rm -f bin/*.{exp,lib,pdb}
|
||||
mkdir -p out/templates/
|
||||
mkdir -p ${{env.OUTDIR}}
|
||||
mv bin/* ${{env.OUTDIR}}
|
||||
ls -R out/
|
||||
|
||||
- name: Rename templates
|
||||
if: startsWith(matrix.opts.target, 'template')
|
||||
shell: bash
|
||||
env:
|
||||
BUILD_TYPE: ${{ endsWith(matrix.opts.target, 'release') && 'release' || 'debug' }}
|
||||
run: |
|
||||
mv out/templates/${BIN}.exe out/templates/windows_${BUILD_TYPE}_${{matrix.opts.arch}}.exe
|
||||
mv out/templates/${BIN}.console.exe out/templates/windows_${BUILD_TYPE}_${{matrix.opts.arch}}_console.exe
|
||||
echo "${GODOT_VERSION}.limboai+${LIMBOAI_VERSION}${{matrix.opts.dotnet == true && '.mono' || ''}}" > out/templates/version.txt
|
||||
ls -R out/
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
env:
|
||||
NAME_EDITOR: ${{env.NAME_PREFIX}}.${{matrix.target}}.windows.${{matrix.arch}}${{ matrix.build-mono == true && '.mono' || '' }}
|
||||
NAME_TEMPLATES: ${{env.NAME_PREFIX}}.export-templates${{ matrix.build-mono == true && '.mono' || '' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ startsWith(matrix.target, 'template') && env.NAME_TEMPLATES || env.NAME_EDITOR }}
|
||||
name: ${{env.NAME_PREFIX}}${{matrix.opts.dotnet == true && '.dotnet' || ''}}.${{matrix.opts.target}}.windows.${{matrix.opts.arch}}
|
||||
path: out/*
|
||||
|
||||
- name: Mark .NET editor as built
|
||||
if: matrix.opts.dotnet && matrix.opts.target == 'editor'
|
||||
id: mark-dotnet-editor
|
||||
run: echo "built-dotnet-editor=true" >> $GITHUB_OUTPUT
|
||||
|
||||
|
||||
dotnet-assemblies:
|
||||
name: .NET assembly for ${{matrix.opts.arch}}
|
||||
needs: windows-builds
|
||||
if: always() && needs.windows-builds.outputs.built-dotnet-editor == 'true'
|
||||
runs-on: "windows-latest"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
opts:
|
||||
- arch: x86_64
|
||||
llvm: false
|
||||
env:
|
||||
BIN: godot.windows.editor.${{matrix.opts.arch}}${{matrix.opts.llvm && '.llvm' || ''}}.mono
|
||||
steps:
|
||||
- name: Clone Godot
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: godotengine/godot
|
||||
ref: ${{ inputs.godot-ref }}
|
||||
|
||||
- name: Clone LimboAI module
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: modules/limboai
|
||||
ref: ${{ inputs.limboai-ref }}
|
||||
|
||||
# Inits GODOT_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
|
||||
- uses: ./modules/limboai/.github/actions/init-version
|
||||
|
||||
- name: Reconstruct artifact name
|
||||
shell: bash
|
||||
run: |
|
||||
echo "ARTIFACT=${{env.NAME_PREFIX}}.dotnet.editor.windows.${{matrix.opts.arch}}" >> $GITHUB_ENV
|
||||
|
||||
- name: Download editor artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{env.ARTIFACT}}
|
||||
path: bin/
|
||||
|
||||
- name: Build .NET assemblies
|
||||
uses: ./modules/limboai/.github/actions/build-dotnet-assemblies
|
||||
with:
|
||||
platform: windows
|
||||
bin: ${{env.BIN}}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{env.ARTIFACT}}
|
||||
overwrite: true
|
||||
path: bin/*
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
# LimboAI-specific
|
||||
demo/addons/
|
||||
demo/script_templates/
|
||||
icons/*.import
|
||||
godot-cpp
|
||||
|
||||
# Godot auto generated files
|
||||
*.gen.*
|
||||
.import/
|
||||
|
@ -181,3 +187,6 @@ godot.creator.*
|
|||
|
||||
# compile commands (https://clang.llvm.org/docs/JSONCompilationDatabase.html)
|
||||
compile_commands.json
|
||||
|
||||
# clang cache
|
||||
.cache
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
repos:
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v17.0.6
|
||||
hooks:
|
||||
- id: clang-format
|
||||
files: \.(c|h|cpp|hpp|cc|cxx|m|mm|inc|java|glsl)$
|
||||
types_or: [text]
|
||||
exclude: |
|
||||
(?x)^(
|
||||
tests/python_build.*|
|
||||
.*thirdparty.*|
|
||||
.*platform/android/java/lib/src/com.*|
|
||||
.*-so_wrap.*
|
||||
)
|
||||
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 24.2.0
|
||||
hooks:
|
||||
- id: black
|
||||
files: (\.py$|SConstruct|SCsub)
|
||||
types_or: [text]
|
||||
exclude: .*thirdparty.*
|
||||
args:
|
||||
- --line-length=120
|
|
@ -1,4 +1,4 @@
|
|||
Copyright 2021-2023 Serhii Snitsaruk
|
||||
Copyright (c) 2023-2025 Serhii Snitsaruk and the LimboAI contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
LimboAI Logo
|
||||
Copyright (c) 2023 Aleksandra Snitsaruk
|
||||
|
||||
This work is licensed under the Creative Commons Attribution 4.0 International
|
||||
license (CC BY 4.0 International): https://creativecommons.org/licenses/by/4.0/
|
153
README.md
153
README.md
|
@ -1,72 +1,139 @@
|
|||
LimboAI - Behavior Trees and State Machines for Godot 4
|
||||
---
|
||||
LimboAI is a C++ module for Godot Engine 4 that provides an implementation of Behavior Trees and State Machines, which can be used together to create complex AI behaviors.
|
||||
<p align="center">
|
||||
<img src="doc/images/logo.svg" width="400" alt="LimboAI logo">
|
||||
</p>
|
||||
|
||||
>**🛈 Supported Godot Engine: 4.1**
|
||||
# LimboAI - Behavior Trees & State Machines for Godot 4
|
||||
|
||||
>**🛈 License**: Use of this source code is governed by an MIT-style license that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
|
||||
[](https://github.com/limbonaut/limboai/actions/workflows/all_builds.yml)
|
||||
[](https://github.com/limbonaut/limboai/actions/workflows/test_builds.yml)
|
||||
[](https://limboai.readthedocs.io/en/latest/?badge=latest)
|
||||
[](https://github.com/limbonaut/limboai/blob/master/LICENSE.md)
|
||||
[](https://discord.gg/N5MGC95GpP)
|
||||
[](https://mastodon.gamedev.place/@limbo)
|
||||
|
||||
A Behavior Tree (BT) is a powerful hierarchical structure used to model and control the behavior of agents in a game. It comprises tasks that represent specific actions or decision-making rules. When executed, the Behavior Tree starts from the root task and traverses down to the leaf tasks, which correspond to the actual actions or behaviors that the agent should perform. For detailed information on how various BT tasks function, please refer to the class documentation. The BTTask class serves as a good starting point.
|
||||
>**🛈 Supported Godot Engine:** **4.3** (v1.2.0+) | **4.2** (v1.1.x releases)
|
||||
|
||||

|
||||
**LimboAI** is an open-source C++ plugin for **Godot Engine 4** providing a combination of
|
||||
**Behavior Trees** and **State Machines**, which can be used together to create complex AI behaviors.
|
||||
It comes with a behavior tree editor, built-in documentation, visual debugger, extensive demo project with a tutorial, and more!
|
||||
While it is implemented in C++, it fully supports GDScript for [creating your own tasks](https://limboai.readthedocs.io/en/stable/behavior-trees/custom-tasks.html) and [states](https://limboai.readthedocs.io/en/stable/hierarchical-state-machines/create-hsm.html).
|
||||
|
||||

|
||||
If you enjoy using LimboAI, please **consider supporting** my efforts with a donation on Ko-fi 😊 Your contribution will help me continue developing and improving it.
|
||||
|
||||
[](https://ko-fi.com/Y8Y2TCNH0)
|
||||
|
||||

|
||||
|
||||
Behavior Trees are powerful hierarchical structures used to model and control the behavior of agents in a game (e.g., characters, enemies). They are designed to make it easier to create rich and highly modular behaviors for your games. To learn more about behavior trees, check out [Introduction to Behavior Trees](https://limboai.readthedocs.io/en/stable/behavior-trees/introduction.html) and our demo project, which includes a tutorial.
|
||||
|
||||
## Demonstration
|
||||
|
||||

|
||||
|
||||
>**🛈 Demo project** lives in the `demo` folder and is available separately in [**Releases**](https://github.com/limbonaut/limboai/releases).
|
||||
> Run `demo/scenes/showcase.tscn` to get started.
|
||||
> It also includes a tutorial that introduces behavior trees through illustrative examples.
|
||||
|
||||
### Videos
|
||||
|
||||
> **🛈** YouTube videos produced by various creators
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=NWaMArUg7mY"><img src="https://img.youtube.com/vi/NWaMArUg7mY/0.jpg" width=410></a>
|
||||
<a href="https://www.youtube.com/watch?v=aP0Aacdxmno"><img src="https://img.youtube.com/vi/aP0Aacdxmno/0.jpg" width=410></a>
|
||||
<a href="https://www.youtube.com/watch?v=vZHzMO90IwQ"><img src="https://img.youtube.com/vi/vZHzMO90IwQ/0.jpg" width=410></a>
|
||||
<a href="https://www.youtube.com/watch?v=gAk3xl5fBsM"><img src="https://img.youtube.com/vi/gAk3xl5fBsM/0.jpg" width=410></a>
|
||||
|
||||
## Features
|
||||
|
||||
- Behavior Trees (BT):
|
||||
- Use the `BTPlayer` node to execute `BehaviorTree` resources.
|
||||
- Easily create, edit, and save `BehaviorTree` resources within the editor.
|
||||
- Combine and nest tasks in a hierarchy to create complex behaviors.
|
||||
- Control the flow of execution using composite, decorator, and condition tasks.
|
||||
- Write your own tasks by extending core classes: `BTAction`, `BTCondition`, `BTDecorator`, and `BTComposite`.
|
||||
- Built-in class documentation. Check out the `BehaviorTree` and `BTTask` class documentation to get started.
|
||||
- Utilize the `Blackboard` for seamless data sharing between tasks.
|
||||
- **Behavior Trees (BT):**
|
||||
- Easily create, edit, and save `BehaviorTree` resources in the editor.
|
||||
- Execute `BehaviorTree` resources using the `BTPlayer` node.
|
||||
- Create complex behaviors by combining and nesting tasks in a hierarchy.
|
||||
- Control execution flow using composite, decorator, and condition tasks.
|
||||
- [Create custom tasks](https://limboai.readthedocs.io/en/stable/behavior-trees/custom-tasks.html) by extending core classes: `BTAction`, `BTCondition`, `BTDecorator`, and `BTComposite`.
|
||||
- Built-in class documentation.
|
||||
- Blackboard system: Share data seamlessly between tasks using the `Blackboard`.
|
||||
- Blackboard plans: Define variables in the BehaviorTree resource and override their values in the BTPlayer node.
|
||||
- Plan editor: Manage variables, their data types and property hints.
|
||||
- Blackboard scopes: Prevent name conflicts and enable advanced techniques like [sharing data between several agents](https://limboai.readthedocs.io/en/stable/behavior-trees/using-blackboard.html#sharing-data-between-several-agents).
|
||||
- Blackboard parameters: [Export a BB parameter](https://limboai.readthedocs.io/en/stable/behavior-trees/using-blackboard.html#task-parameters), for which user can provide a value or bind it to a blackboard variable (can be used in custom tasks).
|
||||
- Inspector support for specifying blackboard variables (custom editor for exported `StringName` properties ending with "_var").
|
||||
- Use the `BTSubtree` task to execute a tree from a different resource file, promoting organization and reusability.
|
||||
- Blackboard scopes separate namespaces of variables from subtrees, and enable advanced techniques like sharing data among agents in a group.
|
||||
- Visual Debugger: Inspect the execution of any BT in a running scene to identify and troubleshoot issues.
|
||||
- Evaluate the performance of your trees with custom performance monitors.
|
||||
- Hierarchical State Machine (HSM)
|
||||
- Extend `LimboState` class to implement state logic.
|
||||
- Visualize BT in-game using `BehaviorTreeView` node (for custom in-game tools).
|
||||
- Monitor tree performance with custom performance monitors.
|
||||
|
||||
- **Hierarchical State Machines (HSM):**
|
||||
- Extend the `LimboState` class to implement state logic.
|
||||
- `LimboHSM` node serves as a state machine that manages `LimboState` instances and transitions.
|
||||
- `LimboHSM` is a state itself and can be nested within other `LimboHSM` instances.
|
||||
- Event-based: Transitions are associated with events, and are triggered by the state machine when the relevant event is dispatched, allowing for better decoupling of transitions from state logic.
|
||||
- [Event-based](https://limboai.readthedocs.io/en/stable/hierarchical-state-machines/create-hsm.html#events-and-transitions): Transitions are associated with events and are triggered by the state machine when the relevant event is dispatched, allowing for better decoupling of transitions from state logic.
|
||||
- Combine state machines with behavior trees using `BTState` for advanced reactive AI.
|
||||
- Delegation: Instead of extending `LimboState`, utilize vanilla `LimboState` and delegate implementation to provided callback functions. Perfect for game jams and quick prototyping.
|
||||
- 🛈 Note: Currently, state machine transition setup and initialization must be done through code as there is no GUI editor for state machines.
|
||||
- Delegation Option: Using the vanilla `LimboState`, [delegate the implementation](https://limboai.readthedocs.io/en/stable/hierarchical-state-machines/create-hsm.html#single-file-state-machine-setup) to your callback functions, making it perfect for rapid prototyping and game jams.
|
||||
- 🛈 Note: State machine setup and initialization require code; there is no GUI editor.
|
||||
|
||||
## How to Get Started
|
||||
- **Tested:** Behavior tree tasks and HSM are covered by unit tests.
|
||||
|
||||
You have two options to start using this module:
|
||||
- **GDExtension:** LimboAI can be [used as extension](https://limboai.readthedocs.io/en/stable/getting-started/getting-limboai.html#get-gdextension-version). Custom engine builds are not necessary.
|
||||
|
||||
1. Download precompiled builds by going to "Actions → All Builds."
|
||||
2. Compile the module on your own (see next section).
|
||||
- **Demo + Tutorial:** Check out our extensive demo project, which includes an introduction to behavior trees using examples.
|
||||
|
||||
## Compiling
|
||||
## First steps
|
||||
|
||||
> 🛈 Precompiled builds are available in "Actions → All Builds"
|
||||
Follow the [Getting started](https://limboai.readthedocs.io/en/stable/getting-started/getting-limboai.html) guide to learn how to get started with LimboAI and the demo project.
|
||||
|
||||
To incorporate this module, you'll need to build Godot Engine from source with LimboAI module included.
|
||||
## Getting LimboAI
|
||||
|
||||
Building From Source:
|
||||
LimboAI can be used as either a C++ module or as a GDExtension shared library. GDExtension version is more convenient to use but somewhat limited in features. Whichever you choose to use, your project will stay compatible with both and you can switch from one to the other any time. See [Using GDExtension](https://limboai.readthedocs.io/en/stable/getting-started/getting-limboai.html#get-gdextension-version).
|
||||
|
||||
### Precompiled builds
|
||||
|
||||
- For the most recent builds, navigate to **Actions** → [**All Builds**](https://github.com/limbonaut/limboai/actions/workflows/all_builds.yml), select a build from the list, and scroll down until you find the **Artifacts** section.
|
||||
- For release builds, check [**Releases**](https://github.com/limbonaut/limboai/releases).
|
||||
|
||||
### Compiling from source
|
||||
|
||||
- Download the Godot Engine source code and put this module source into the `modules/limboai` directory.
|
||||
- Consult the Godot Engine documentation for instructions on [how to build from source code](https://docs.godotengine.org/en/stable/contributing/development/compiling/index.html).
|
||||
- If you plan to export a game utilizing the LimboAI module, you'll need to build export templates as well.
|
||||
- If you plan to export a game utilizing the LimboAI module, you'll also need to build export templates.
|
||||
- To execute unit tests, compile the engine with `tests=yes` and run it with `--test --tc="*[LimboAI]*"`.
|
||||
|
||||
#### For GDExtension
|
||||
|
||||
- You'll need SCons build tool and a C++ compiler. See also [Compiling](https://docs.godotengine.org/en/stable/contributing/development/compiling/index.html).
|
||||
- Run `scons target=editor` to build the plugin library for your current platform.
|
||||
- SCons will automatically clone the godot-cpp/ repository if it doesn't already exist in the `limboai/godot-cpp` directory.
|
||||
- By default, built targets are placed in the demo project: `demo/addons/limboai/bin/`
|
||||
- Check `scons -h` for other options and targets.
|
||||
|
||||
## Using the plugin
|
||||
|
||||
- Online Documentation: [stable](https://limboai.readthedocs.io/en/stable/index.html), [latest](https://limboai.readthedocs.io/en/latest/index.html)
|
||||
- [Getting started](https://limboai.readthedocs.io/en/stable/getting-started/getting-limboai.html)
|
||||
- [Introduction to Behavior Trees](https://limboai.readthedocs.io/en/stable/behavior-trees/introduction.html)
|
||||
- [Creating custom tasks in GDScript](https://limboai.readthedocs.io/en/stable/behavior-trees/custom-tasks.html)
|
||||
- [Sharing data using Blackboard](https://limboai.readthedocs.io/en/stable/behavior-trees/using-blackboard.html)
|
||||
- [Accessing nodes in the scene tree](https://limboai.readthedocs.io/en/stable/behavior-trees/accessing-nodes.html)
|
||||
- [State machines](https://limboai.readthedocs.io/en/stable/hierarchical-state-machines/create-hsm.html)
|
||||
- [Using GDExtension](https://limboai.readthedocs.io/en/stable/getting-started/getting-limboai.html#get-gdextension-version)
|
||||
- [Using LimboAI with C#](https://limboai.readthedocs.io/en/stable/getting-started/c-sharp.html)
|
||||
- [Class reference](https://limboai.readthedocs.io/en/stable/classes/featured-classes.html)
|
||||
|
||||
## Contributing
|
||||
|
||||
All contributions are welcome! Feel free to open issues with bug reports and feature requests, and submit PRs.
|
||||
Contributions are welcome! Please open issues for bug reports, feature requests, or code changes.
|
||||
For detailed guidelines on contributing to code or documentation, check out our [Contributing](https://limboai.readthedocs.io/en/latest/getting-started/contributing.html) page.
|
||||
|
||||
## Roadmap
|
||||
If you have an idea for a behavior tree task or a feature that could be useful in a variety of projects, open an issue to discuss it.
|
||||
|
||||
Features and improvements that may be implemented in the future:
|
||||
## Social
|
||||
|
||||
- Providing precompiled builds for download.
|
||||
- Creating a non-trivial demo project to showcase the capabilities of LimboAI.
|
||||
- Exploring the execution history of Behavior Trees in the Visual Debugger.
|
||||
- Tests and CI.
|
||||
- Expanding the library of tasks that can be optionally included in the build.
|
||||
- Implementing an ignore list for tasks that users may want to hide in the task panel.
|
||||
- GUI editor for state machines.
|
||||
- Supporting GDExtension in the future, once it matures.
|
||||
Need help? We have a Discord server: https://discord.gg/N5MGC95GpP
|
||||
|
||||
I write about LimboAI development on Mastodon: https://mastodon.gamedev.place/@limbo.
|
||||
|
||||
## License
|
||||
|
||||
Use of this source code is governed by an MIT-style license that can be found in the LICENSE file or at https://opensource.org/licenses/MIT
|
||||
|
||||
LimboAI logo and demo project art assets are licensed under the Creative Commons Attribution 4.0 International license that can be found at https://creativecommons.org/licenses/by/4.0/
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
This is SConstruct file for building GDExtension variant using SCons build system.
|
||||
For module variant, see SCsub file.
|
||||
|
||||
Use --project=DIR to customize output path for built targets.
|
||||
- Built targets are placed into "DIR/addons/limboai/bin".
|
||||
- For example: scons --project="../my_project"
|
||||
- built targets will be placed into "../my_project/addons/limboai/bin".
|
||||
- If not specified, built targets are put into the demo/ project.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
from limboai_version import generate_module_version_header, godot_cpp_ref
|
||||
|
||||
sys.path.append("gdextension")
|
||||
from update_icon_entries import update_icon_entries
|
||||
from fix_icon_imports import fix_icon_imports
|
||||
|
||||
# Check if godot-cpp/ exists
|
||||
if not os.path.exists("godot-cpp"):
|
||||
print("Directory godot-cpp/ not found. Cloning repository...")
|
||||
result = subprocess.run(
|
||||
["git", "clone", "-b", godot_cpp_ref, "https://github.com/godotengine/godot-cpp.git"],
|
||||
check=True,
|
||||
# capture_output=True
|
||||
)
|
||||
if result.returncode != 0:
|
||||
print("Error: Cloning godot-cpp repository failed.")
|
||||
Exit(1)
|
||||
print("Finished cloning godot-cpp repository.")
|
||||
|
||||
AddOption(
|
||||
"--project",
|
||||
dest="project",
|
||||
type="string",
|
||||
nargs=1,
|
||||
action="store",
|
||||
metavar="DIR",
|
||||
default="demo",
|
||||
help="Specify project directory",
|
||||
)
|
||||
|
||||
help_text = """
|
||||
Options:
|
||||
--project=DIR Specify project directory (default: "demo");
|
||||
built targets will be placed in DIR/addons/limboai/bin
|
||||
"""
|
||||
Help(help_text)
|
||||
|
||||
project_dir = GetOption("project")
|
||||
if not os.path.isdir(project_dir):
|
||||
print("Project directory not found: " + project_dir)
|
||||
Exit(2)
|
||||
|
||||
# Parse LimboAI-specific variables.
|
||||
vars = Variables()
|
||||
vars.AddVariables(
|
||||
BoolVariable("deploy_manifest", help="Deploy limboai.gdextension into PROJECT/addons/limboai/bin", default=True),
|
||||
BoolVariable("deploy_icons", help="Deploy icons into PROJECT/addons/limboai/icons", default=True),
|
||||
)
|
||||
env = Environment(tools=["default"], PLATFORM="", variables=vars)
|
||||
Help(vars.GenerateHelpText(env))
|
||||
|
||||
# Read LimboAI-specific variables.
|
||||
deploy_manifest = env["deploy_manifest"]
|
||||
deploy_icons = env["deploy_icons"]
|
||||
|
||||
# Remove processed variables from ARGUMENTS to avoid godot-cpp warnings.
|
||||
for o in vars.options:
|
||||
if o.key in ARGUMENTS:
|
||||
del ARGUMENTS[o.key]
|
||||
|
||||
# For reference:
|
||||
# - CCFLAGS are compilation flags shared between C and C++
|
||||
# - CFLAGS are for C-specific compilation flags
|
||||
# - CXXFLAGS are for C++-specific compilation flags
|
||||
# - CPPFLAGS are for pre-processor flags
|
||||
# - CPPDEFINES are for pre-processor defines
|
||||
# - LINKFLAGS are for linking flags
|
||||
|
||||
env = SConscript("godot-cpp/SConstruct")
|
||||
|
||||
# Generate version header.
|
||||
print("Generating LimboAI version header...")
|
||||
generate_module_version_header()
|
||||
|
||||
# Update icon entries in limboai.gdextension file.
|
||||
# Note: This will remove everything after [icons] section, and rebuild it with generated icon entries.
|
||||
print("Updating LimboAI icon entries...")
|
||||
update_icon_entries(silent=True)
|
||||
|
||||
# Fix icon imports in the PROJECT/addons/limboai/icons/.
|
||||
# Enables scaling and color conversion in the editor for imported SVG icons.
|
||||
try:
|
||||
fix_icon_imports(project_dir)
|
||||
except FileNotFoundError as e:
|
||||
print(e)
|
||||
except Exception as e:
|
||||
print("Unknown error: " + str(e))
|
||||
|
||||
# Tweak this if you want to use different folders, or more folders, to store your source code in.
|
||||
env.Append(CPPDEFINES=["LIMBOAI_GDEXTENSION"])
|
||||
sources = Glob("*.cpp")
|
||||
sources += Glob("blackboard/*.cpp")
|
||||
sources += Glob("blackboard/bb_param/*.cpp")
|
||||
sources += Glob("bt/*.cpp")
|
||||
sources += Glob("bt/tasks/*.cpp")
|
||||
sources += Glob("bt/tasks/blackboard/*.cpp")
|
||||
sources += Glob("bt/tasks/composites/*.cpp")
|
||||
sources += Glob("bt/tasks/decorators/*.cpp")
|
||||
sources += Glob("bt/tasks/scene/*.cpp")
|
||||
sources += Glob("bt/tasks/utility/*.cpp")
|
||||
sources += Glob("gdextension/*.cpp")
|
||||
sources += Glob("editor/debugger/*.cpp")
|
||||
sources += Glob("editor/*.cpp")
|
||||
sources += Glob("hsm/*.cpp")
|
||||
sources += Glob("util/*.cpp")
|
||||
|
||||
# Generate documentation header.
|
||||
if env["target"] in ["editor", "template_debug"]:
|
||||
doc_data = env.GodotCPPDocData("gen/doc_data.gen.cpp", source=Glob("doc_classes/*.xml"))
|
||||
sources.append(doc_data)
|
||||
|
||||
# Build library.
|
||||
if env["platform"] == "macos":
|
||||
library = env.SharedLibrary(
|
||||
project_dir
|
||||
+ "/addons/limboai/bin/liblimboai.{}.{}.framework/liblimboai.{}.{}".format(
|
||||
env["platform"], env["target"], env["platform"], env["target"]
|
||||
),
|
||||
source=sources,
|
||||
)
|
||||
else:
|
||||
library = env.SharedLibrary(
|
||||
project_dir + "/addons/limboai/bin/liblimboai{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
|
||||
source=sources,
|
||||
)
|
||||
|
||||
Default(library)
|
||||
|
||||
# Deploy icons into PROJECT/addons/limboai/icons.
|
||||
if deploy_icons:
|
||||
cmd_deploy_icons = env.Command(
|
||||
project_dir + "/addons/limboai/icons/",
|
||||
"icons/",
|
||||
Copy("$TARGET", "$SOURCE"),
|
||||
)
|
||||
Default(cmd_deploy_icons)
|
||||
|
||||
# Deploy limboai.gdextension into PROJECT/addons/limboai/bin.
|
||||
if deploy_manifest:
|
||||
cmd_deploy_manifest = env.Command(
|
||||
project_dir + "/addons/limboai/bin/limboai.gdextension",
|
||||
"gdextension/limboai.gdextension",
|
||||
Copy("$TARGET", "$SOURCE"),
|
||||
)
|
||||
Default(cmd_deploy_manifest)
|
17
SCsub
17
SCsub
|
@ -5,14 +5,23 @@ Import("env_modules")
|
|||
|
||||
module_env = env.Clone()
|
||||
|
||||
module_env.Append(CPPDEFINES=["LIMBOAI_MODULE"])
|
||||
|
||||
import limboai_version
|
||||
|
||||
limboai_version.generate_module_version_header()
|
||||
|
||||
module_env.add_source_files(env.modules_sources, "*.cpp")
|
||||
module_env.add_source_files(env.modules_sources, "blackboard/*.cpp")
|
||||
module_env.add_source_files(env.modules_sources, "blackboard/bb_param/*.cpp")
|
||||
module_env.add_source_files(env.modules_sources, "bt/*.cpp")
|
||||
module_env.add_source_files(env.modules_sources, "bt/composites/*.cpp")
|
||||
module_env.add_source_files(env.modules_sources, "bt/actions/*.cpp")
|
||||
module_env.add_source_files(env.modules_sources, "bt/decorators/*.cpp")
|
||||
module_env.add_source_files(env.modules_sources, "bt/conditions/*.cpp")
|
||||
module_env.add_source_files(env.modules_sources, "bt/tasks/*.cpp")
|
||||
module_env.add_source_files(env.modules_sources, "bt/tasks/blackboard/*.cpp")
|
||||
module_env.add_source_files(env.modules_sources, "bt/tasks/composites/*.cpp")
|
||||
module_env.add_source_files(env.modules_sources, "bt/tasks/decorators/*.cpp")
|
||||
module_env.add_source_files(env.modules_sources, "bt/tasks/misc/*.cpp")
|
||||
module_env.add_source_files(env.modules_sources, "bt/tasks/scene/*.cpp")
|
||||
module_env.add_source_files(env.modules_sources, "bt/tasks/utility/*.cpp")
|
||||
if env.editor_build:
|
||||
module_env.add_source_files(env.modules_sources, "editor/*.cpp")
|
||||
module_env.add_source_files(env.modules_sources, "editor/debugger/*.cpp")
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_aabb.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_AABB_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBAabb : public BBParam {
|
||||
GDCLASS(BBAabb, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::AABB; }
|
||||
};
|
||||
|
||||
#endif // BB_AABB_H
|
||||
#endif // BB_AABB_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_array.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_ARRAY_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBArray : public BBParam {
|
||||
GDCLASS(BBArray, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::ARRAY; }
|
||||
};
|
||||
|
||||
#endif // BB_ARRAY_H
|
||||
#endif // BB_ARRAY_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_basis.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_BASIS_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBBasis : public BBParam {
|
||||
GDCLASS(BBBasis, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::BASIS; }
|
||||
};
|
||||
|
||||
#endif // BB_BASIS_H
|
||||
#endif // BB_BASIS_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_bool.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_BOOL_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBBool : public BBParam {
|
||||
GDCLASS(BBBool, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::BOOL; }
|
||||
};
|
||||
|
||||
#endif // BB_BOOL_H
|
||||
#endif // BB_BOOL_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_byte_array.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_BYTE_ARRAY_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBByteArray : public BBParam {
|
||||
GDCLASS(BBByteArray, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::PACKED_BYTE_ARRAY; }
|
||||
};
|
||||
|
||||
#endif // BB_BYTE_ARRAY_H
|
||||
#endif // BB_BYTE_ARRAY_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_color.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_COLOR_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBColor : public BBParam {
|
||||
GDCLASS(BBColor, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::COLOR; }
|
||||
};
|
||||
|
||||
#endif // BB_COLOR_H
|
||||
#endif // BB_COLOR_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_color_array.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_COLOR_ARRAY_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBColorArray : public BBParam {
|
||||
GDCLASS(BBColorArray, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::PACKED_COLOR_ARRAY; }
|
||||
};
|
||||
|
||||
#endif // BB_COLOR_ARRAY_H
|
||||
#endif // BB_COLOR_ARRAY_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_dictionary.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_DICTIONARY_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBDictionary : public BBParam {
|
||||
GDCLASS(BBDictionary, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::DICTIONARY; }
|
||||
};
|
||||
|
||||
#endif // BB_DICTIONARY_H
|
||||
#endif // BB_DICTIONARY_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_float.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_FLOAT_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBFloat : public BBParam {
|
||||
GDCLASS(BBFloat, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::FLOAT; }
|
||||
};
|
||||
|
||||
#endif // BB_FLOAT_H
|
||||
#endif // BB_FLOAT_H
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* bb_float32_array.h
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BB_FLOAT32_ARRAY_H
|
||||
#define BB_FLOAT32_ARRAY_H
|
||||
|
||||
#include "bb_param.h"
|
||||
|
||||
class BBFloat32Array : public BBParam {
|
||||
GDCLASS(BBFloat32Array, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::PACKED_FLOAT32_ARRAY; }
|
||||
};
|
||||
|
||||
#endif // BB_FLOAT32_ARRAY_H
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_float_array.h
|
||||
* bb_float64_array.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -9,17 +9,18 @@
|
|||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BB_FLOAT_ARRAY_H
|
||||
#define BB_FLOAT_ARRAY_H
|
||||
#ifndef BB_FLOAT64_ARRAY_H
|
||||
#define BB_FLOAT64_ARRAY_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBFloatArray : public BBParam {
|
||||
GDCLASS(BBFloatArray, BBParam);
|
||||
class BBFloat64Array : public BBParam {
|
||||
GDCLASS(BBFloat64Array, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::PACKED_FLOAT64_ARRAY; }
|
||||
};
|
||||
|
||||
#endif // BB_FLOAT_ARRAY_H
|
||||
#endif // BB_FLOAT64_ARRAY_H
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_int.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_INT_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBInt : public BBParam {
|
||||
GDCLASS(BBInt, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::INT; }
|
||||
};
|
||||
|
||||
#endif // BB_INT_H
|
||||
#endif // BB_INT_H
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* bb_int32_array.h
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BB_INT32_ARRAY_H
|
||||
#define BB_INT32_ARRAY_H
|
||||
|
||||
#include "bb_param.h"
|
||||
|
||||
class BBInt32Array : public BBParam {
|
||||
GDCLASS(BBInt32Array, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::PACKED_INT32_ARRAY; }
|
||||
};
|
||||
|
||||
#endif // BB_INT32_ARRAY_H
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_int_array.h
|
||||
* bb_int64_array.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -9,17 +9,18 @@
|
|||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BB_INT_ARRAY_H
|
||||
#define BB_INT_ARRAY_H
|
||||
#ifndef BB_INT64_ARRAY_H
|
||||
#define BB_INT64_ARRAY_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBIntArray : public BBParam {
|
||||
GDCLASS(BBIntArray, BBParam);
|
||||
class BBInt64Array : public BBParam {
|
||||
GDCLASS(BBInt64Array, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::PACKED_INT64_ARRAY; }
|
||||
};
|
||||
|
||||
#endif // BB_INT_ARRAY_H
|
||||
#endif // BB_INT64_ARRAY_H
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_node.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -10,13 +10,10 @@
|
|||
*/
|
||||
|
||||
#include "bb_node.h"
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/variant/variant.h"
|
||||
#include "scene/main/node.h"
|
||||
|
||||
Variant BBNode::get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard, const Variant &p_default) {
|
||||
ERR_FAIL_COND_V(p_agent == nullptr, Variant());
|
||||
ERR_FAIL_COND_V(!p_blackboard.is_valid(), Variant());
|
||||
Variant BBNode::get_value(Node *p_scene_root, const Ref<Blackboard> &p_blackboard, const Variant &p_default) {
|
||||
ERR_FAIL_NULL_V_MSG(p_scene_root, Variant(), "BBNode: get_value() failed - scene_root is null.");
|
||||
ERR_FAIL_COND_V_MSG(p_blackboard.is_null(), Variant(), "BBNode: get_value() failed - blackboard is null.");
|
||||
|
||||
Variant val;
|
||||
if (get_value_source() == SAVED_VALUE) {
|
||||
|
@ -26,16 +23,11 @@ Variant BBNode::get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard,
|
|||
}
|
||||
|
||||
if (val.get_type() == Variant::NODE_PATH) {
|
||||
Node *agent = Object::cast_to<Node>(p_agent);
|
||||
ERR_FAIL_COND_V_MSG(agent == nullptr, Variant(), "BBNode: p_agent must be a Node.");
|
||||
return agent->get_node(val);
|
||||
return p_scene_root->get_node_or_null(val);
|
||||
} else if (val.get_type() == Variant::OBJECT || val.get_type() == Variant::NIL) {
|
||||
return val;
|
||||
} else {
|
||||
Node *node = Object::cast_to<Node>(val);
|
||||
if (unlikely(node == nullptr && val.get_type() != Variant::NIL)) {
|
||||
WARN_PRINT("BBNode: Unexpected variant type of a blackboard variable.");
|
||||
return p_default;
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
WARN_PRINT("BBNode: Unexpected variant type: " + Variant::get_type_name(val.get_type()) + ". Returning default value.");
|
||||
return p_default;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_node.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,16 +13,16 @@
|
|||
#define BB_NODE_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBNode : public BBParam {
|
||||
GDCLASS(BBNode, BBParam);
|
||||
|
||||
protected:
|
||||
virtual Variant::Type get_type() const override { return Variant::NODE_PATH; }
|
||||
static void _bind_methods() {}
|
||||
|
||||
public:
|
||||
virtual Variant get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard, const Variant &p_default = Variant()) override;
|
||||
virtual Variant::Type get_type() const override { return Variant::NODE_PATH; }
|
||||
virtual Variant get_value(Node *p_scene_root, const Ref<Blackboard> &p_blackboard, const Variant &p_default = Variant()) override;
|
||||
};
|
||||
|
||||
#endif // BB_NODE_H
|
||||
#endif // BB_NODE_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_param.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -11,13 +11,14 @@
|
|||
|
||||
#include "bb_param.h"
|
||||
|
||||
#include "modules/limboai/util/limbo_utility.h"
|
||||
#include "../../util/limbo_utility.h"
|
||||
|
||||
#include "core/core_bind.h"
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/object/object.h"
|
||||
#include "core/variant/variant.h"
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#endif // LIMBOAI_MODULE
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
using namespace godot;
|
||||
#endif // LIMBOAI_GDEXTENSION
|
||||
|
||||
VARIANT_ENUM_CAST(BBParam::ValueSource);
|
||||
|
||||
|
@ -29,39 +30,61 @@ void BBParam::set_value_source(ValueSource p_value) {
|
|||
}
|
||||
|
||||
Variant BBParam::get_saved_value() {
|
||||
if (saved_value.get_type() != get_type()) {
|
||||
Callable::CallError err;
|
||||
Variant::construct(get_type(), saved_value, nullptr, 0, err);
|
||||
}
|
||||
return saved_value;
|
||||
}
|
||||
|
||||
void BBParam::set_saved_value(Variant p_value) {
|
||||
saved_value = p_value;
|
||||
if (p_value.get_type() == Variant::NIL) {
|
||||
_assign_default_value();
|
||||
} else {
|
||||
saved_value = p_value;
|
||||
}
|
||||
_update_name();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BBParam::set_variable(const String &p_value) {
|
||||
variable = p_value;
|
||||
void BBParam::set_variable(const StringName &p_variable) {
|
||||
variable = p_variable;
|
||||
_update_name();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
String BBParam::to_string() {
|
||||
#elif LIMBOAI_GDEXTENSION
|
||||
String BBParam::_to_string() {
|
||||
#endif
|
||||
if (value_source == SAVED_VALUE) {
|
||||
return String(saved_value);
|
||||
String s = saved_value.stringify();
|
||||
switch (get_type()) {
|
||||
case Variant::STRING: {
|
||||
s = "\"" + s.c_escape() + "\"";
|
||||
} break;
|
||||
case Variant::STRING_NAME: {
|
||||
s = "&\"" + s.c_escape() + "\"";
|
||||
} break;
|
||||
case Variant::NODE_PATH: {
|
||||
s = "^\"" + s.c_escape() + "\"";
|
||||
} break;
|
||||
default: {
|
||||
} break;
|
||||
}
|
||||
return s;
|
||||
} else {
|
||||
return LimboUtility::get_singleton()->decorate_var(variable);
|
||||
}
|
||||
}
|
||||
|
||||
Variant BBParam::get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard, const Variant &p_default) {
|
||||
Variant BBParam::get_value(Node *p_scene_root, const Ref<Blackboard> &p_blackboard, const Variant &p_default) {
|
||||
ERR_FAIL_COND_V(!p_blackboard.is_valid(), p_default);
|
||||
|
||||
if (value_source == SAVED_VALUE) {
|
||||
if (saved_value == Variant()) {
|
||||
_assign_default_value();
|
||||
}
|
||||
return saved_value;
|
||||
} else {
|
||||
ERR_FAIL_COND_V_MSG(!p_blackboard->has_var(variable), p_default, vformat("BBParam: Blackboard variable \"%s\" doesn't exist.", variable));
|
||||
return p_blackboard->get_var(variable, p_default);
|
||||
}
|
||||
}
|
||||
|
@ -70,22 +93,22 @@ void BBParam::_get_property_list(List<PropertyInfo> *p_list) const {
|
|||
if (value_source == ValueSource::SAVED_VALUE) {
|
||||
p_list->push_back(PropertyInfo(get_type(), "saved_value"));
|
||||
} else {
|
||||
p_list->push_back(PropertyInfo(Variant::STRING, "variable"));
|
||||
p_list->push_back(PropertyInfo(Variant::STRING_NAME, "variable"));
|
||||
}
|
||||
}
|
||||
|
||||
void BBParam::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_value_source", "p_value_source"), &BBParam::set_value_source);
|
||||
ClassDB::bind_method(D_METHOD("set_value_source", "value_source"), &BBParam::set_value_source);
|
||||
ClassDB::bind_method(D_METHOD("get_value_source"), &BBParam::get_value_source);
|
||||
ClassDB::bind_method(D_METHOD("set_saved_value", "p_value"), &BBParam::set_saved_value);
|
||||
ClassDB::bind_method(D_METHOD("set_saved_value", "value"), &BBParam::set_saved_value);
|
||||
ClassDB::bind_method(D_METHOD("get_saved_value"), &BBParam::get_saved_value);
|
||||
ClassDB::bind_method(D_METHOD("set_variable", "p_variable_name"), &BBParam::set_variable);
|
||||
ClassDB::bind_method(D_METHOD("set_variable", "variable_name"), &BBParam::set_variable);
|
||||
ClassDB::bind_method(D_METHOD("get_variable"), &BBParam::get_variable);
|
||||
ClassDB::bind_method(D_METHOD("get_type"), &BBParam::get_type);
|
||||
ClassDB::bind_method(D_METHOD("get_value", "p_agent", "p_blackboard", "p_default"), &BBParam::get_value, Variant());
|
||||
ClassDB::bind_method(D_METHOD("get_value", "scene_root", "blackboard", "default"), &BBParam::get_value, Variant());
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "value_source", PROPERTY_HINT_ENUM, "Saved Value, Blackboard Var"), "set_value_source", "get_value_source");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "variable", PROPERTY_HINT_NONE, "", 0), "set_variable", "get_variable");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "value_source", PROPERTY_HINT_ENUM, "Saved Value,Blackboard Var"), "set_value_source", "get_value_source");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "variable", PROPERTY_HINT_NONE, "", 0), "set_variable", "get_variable");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::NIL, "saved_value", PROPERTY_HINT_NONE, "", 0), "set_saved_value", "get_saved_value");
|
||||
|
||||
BIND_ENUM_CONSTANT(SAVED_VALUE);
|
||||
|
@ -94,6 +117,4 @@ void BBParam::_bind_methods() {
|
|||
|
||||
BBParam::BBParam() {
|
||||
value_source = SAVED_VALUE;
|
||||
variable = "";
|
||||
saved_value = Variant();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_param.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -12,13 +12,16 @@
|
|||
#ifndef BB_PARAM_H
|
||||
#define BB_PARAM_H
|
||||
|
||||
#include "modules/limboai/blackboard/blackboard.h"
|
||||
#include "modules/limboai/util/limbo_utility.h"
|
||||
#include "../../blackboard/blackboard.h"
|
||||
#include "../../util/limbo_utility.h"
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "core/io/resource.h"
|
||||
#include "core/object/object.h"
|
||||
#include "core/typedefs.h"
|
||||
#include "core/variant/variant.h"
|
||||
#endif // LIMBOAI_MODULE
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include <godot_cpp/classes/resource.hpp>
|
||||
#endif // LIMBOAI_GDEXTENSION
|
||||
|
||||
class BBParam : public Resource {
|
||||
GDCLASS(BBParam, Resource);
|
||||
|
@ -32,7 +35,7 @@ public:
|
|||
private:
|
||||
ValueSource value_source;
|
||||
Variant saved_value;
|
||||
String variable;
|
||||
StringName variable;
|
||||
|
||||
_FORCE_INLINE_ void _update_name() {
|
||||
set_name((value_source == SAVED_VALUE) ? String(saved_value) : LimboUtility::get_singleton()->decorate_var(variable));
|
||||
|
@ -41,7 +44,7 @@ private:
|
|||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
virtual Variant::Type get_type() const { return Variant::NIL; }
|
||||
_FORCE_INLINE_ void _assign_default_value() { saved_value = VARIANT_DEFAULT(get_type()); }
|
||||
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
|
||||
|
@ -52,14 +55,20 @@ public:
|
|||
void set_saved_value(Variant p_value);
|
||||
Variant get_saved_value();
|
||||
|
||||
void set_variable(const String &p_value);
|
||||
String get_variable() const { return variable; }
|
||||
void set_variable(const StringName &p_variable);
|
||||
StringName get_variable() const { return variable; }
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
virtual String to_string() override;
|
||||
#elif LIMBOAI_GDEXTENSION
|
||||
virtual String _to_string();
|
||||
#endif
|
||||
|
||||
virtual Variant get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard, const Variant &p_default = Variant());
|
||||
virtual Variant::Type get_type() const { return Variant::NIL; }
|
||||
virtual Variant::Type get_variable_expected_type() const { return get_type(); }
|
||||
virtual Variant get_value(Node *p_scene_root, const Ref<Blackboard> &p_blackboard, const Variant &p_default = Variant());
|
||||
|
||||
BBParam();
|
||||
};
|
||||
|
||||
#endif // BB_PARAM_H
|
||||
#endif // BB_PARAM_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_plane.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_PLANE_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBPlane : public BBParam {
|
||||
GDCLASS(BBPlane, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::PLANE; }
|
||||
};
|
||||
|
||||
#endif // BB_PLANE_H
|
||||
#endif // BB_PLANE_H
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* bb_projection.h
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BB_PROJECTION_H
|
||||
#define BB_PROJECTION_H
|
||||
|
||||
#include "bb_param.h"
|
||||
|
||||
class BBProjection : public BBParam {
|
||||
GDCLASS(BBProjection, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::PROJECTION; }
|
||||
};
|
||||
|
||||
#endif // BB_PROJECTION_H
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_quaternion.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_QUATERNION_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBQuaternion : public BBParam {
|
||||
GDCLASS(BBQuaternion, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::QUATERNION; }
|
||||
};
|
||||
|
||||
#endif // BB_QUATERNION_H
|
||||
#endif // BB_QUATERNION_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_rect2.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_RECT2_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBRect2 : public BBParam {
|
||||
GDCLASS(BBRect2, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::RECT2; }
|
||||
};
|
||||
|
||||
#endif // BB_RECT2_H
|
||||
#endif // BB_RECT2_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_rect2i.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_RECT2I_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBRect2i : public BBParam {
|
||||
GDCLASS(BBRect2i, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::RECT2I; }
|
||||
};
|
||||
|
||||
#endif // BB_RECT2I_H
|
||||
#endif // BB_RECT2I_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_string.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_STRING_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBString : public BBParam {
|
||||
GDCLASS(BBString, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::STRING; }
|
||||
};
|
||||
|
||||
#endif // BB_STRING_H
|
||||
#endif // BB_STRING_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_string_array.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_STRING_ARRAY_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBStringArray : public BBParam {
|
||||
GDCLASS(BBStringArray, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::PACKED_STRING_ARRAY; }
|
||||
};
|
||||
|
||||
#endif // BB_STRING_ARRAY_H
|
||||
#endif // BB_STRING_ARRAY_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_string_name.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_STRING_NAME_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBStringName : public BBParam {
|
||||
GDCLASS(BBStringName, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::STRING_NAME; }
|
||||
};
|
||||
|
||||
#endif // BB_STRING_H
|
||||
#endif // BB_STRING_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_transform2d.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_TRANSFORM2D_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBTransform2D : public BBParam {
|
||||
GDCLASS(BBTransform2D, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::TRANSFORM2D; }
|
||||
};
|
||||
|
||||
#endif // BB_TRANSFORM2D_H
|
||||
#endif // BB_TRANSFORM2D_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_transform3d.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_TRANSFORM3D_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBTransform3D : public BBParam {
|
||||
GDCLASS(BBTransform3D, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::TRANSFORM3D; }
|
||||
};
|
||||
|
||||
#endif // BB_TRANSFORM3D_H
|
||||
#endif // BB_TRANSFORM3D_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_variant.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -10,17 +10,24 @@
|
|||
*/
|
||||
|
||||
#include "bb_variant.h"
|
||||
#include "core/object/object.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
void BBVariant::set_type(Variant::Type p_type) {
|
||||
type = p_type;
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
if (type != p_type) {
|
||||
type = p_type;
|
||||
if (get_saved_value().get_type() != p_type) {
|
||||
_assign_default_value();
|
||||
}
|
||||
emit_changed();
|
||||
notify_property_list_changed();
|
||||
}
|
||||
}
|
||||
|
||||
Variant::Type BBVariant::get_type() const {
|
||||
return type;
|
||||
}
|
||||
|
||||
void BBVariant::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_type", "p_type"), &BBVariant::set_type);
|
||||
ClassDB::bind_method(D_METHOD("set_type", "type"), &BBVariant::set_type);
|
||||
|
||||
String vtypes;
|
||||
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
|
||||
|
@ -32,6 +39,10 @@ void BBVariant::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, vtypes), "set_type", "get_type");
|
||||
}
|
||||
|
||||
BBVariant::BBVariant() {
|
||||
type = Variant::NIL;
|
||||
BBVariant::BBVariant(const Variant &p_value) {
|
||||
set_type(p_value.get_type());
|
||||
set_saved_value(p_value);
|
||||
}
|
||||
|
||||
BBVariant::BBVariant() {
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_variant.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,23 +13,24 @@
|
|||
#define BB_VARIANT_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
class BBVariant : public BBParam {
|
||||
GDCLASS(BBVariant, BBParam);
|
||||
|
||||
private:
|
||||
Variant::Type type;
|
||||
Variant::Type type = Variant::NIL;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
virtual Variant::Type get_type() const override { return type; }
|
||||
public:
|
||||
virtual Variant::Type get_type() const override;
|
||||
void set_type(Variant::Type p_type);
|
||||
|
||||
public:
|
||||
virtual Variant::Type get_variable_expected_type() const override { return Variant::NIL; }
|
||||
|
||||
BBVariant(const Variant &p_value);
|
||||
BBVariant();
|
||||
};
|
||||
|
||||
#endif // BB_VARIANT
|
||||
#endif // BB_VARIANT
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_vector2.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_VECTOR2_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBVector2 : public BBParam {
|
||||
GDCLASS(BBVector2, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::VECTOR2; }
|
||||
};
|
||||
|
||||
#endif // BB_VECTOR2_H
|
||||
#endif // BB_VECTOR2_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_vector2_array.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_VECTOR2_ARRAY_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBVector2Array : public BBParam {
|
||||
GDCLASS(BBVector2Array, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::PACKED_VECTOR2_ARRAY; }
|
||||
};
|
||||
|
||||
#endif // BB_VECTOR2_ARRAY_H
|
||||
#endif // BB_VECTOR2_ARRAY_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_vector2i.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_VECTOR2I_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBVector2i : public BBParam {
|
||||
GDCLASS(BBVector2i, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::VECTOR2I; }
|
||||
};
|
||||
|
||||
#endif // BB_VECTOR2I_H
|
||||
#endif // BB_VECTOR2I_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_vector3.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_VECTOR3_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBVector3 : public BBParam {
|
||||
GDCLASS(BBVector3, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::VECTOR3; }
|
||||
};
|
||||
|
||||
#endif // BB_VECTOR3_H
|
||||
#endif // BB_VECTOR3_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_vector3_array.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_VECTOR3_ARRAY_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBVector3Array : public BBParam {
|
||||
GDCLASS(BBVector3Array, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::PACKED_VECTOR3_ARRAY; }
|
||||
};
|
||||
|
||||
#endif // BB_VECTOR3_ARRAY_H
|
||||
#endif // BB_VECTOR3_ARRAY_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_vector3i.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_VECTOR3I_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBVector3i : public BBParam {
|
||||
GDCLASS(BBVector3i, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::VECTOR3I; }
|
||||
};
|
||||
|
||||
#endif // BB_VECTOR3I_H
|
||||
#endif // BB_VECTOR3I_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_vector4.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_VECTOR4_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBVector4 : public BBParam {
|
||||
GDCLASS(BBVector4, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::VECTOR4; }
|
||||
};
|
||||
|
||||
#endif // BB_VECTOR4_H
|
||||
#endif // BB_VECTOR4_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bb_vector4i.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -13,13 +13,14 @@
|
|||
#define BB_VECTOR4I_H
|
||||
|
||||
#include "bb_param.h"
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BBVector4i : public BBParam {
|
||||
GDCLASS(BBVector4i, BBParam);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
virtual Variant::Type get_type() const override { return Variant::VECTOR4I; }
|
||||
};
|
||||
|
||||
#endif // BB_VECTOR4I_H
|
||||
#endif // BB_VECTOR4I_H
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
/**
|
||||
* bb_variable.cpp
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "bb_variable.h"
|
||||
|
||||
#include "../util/limbo_compat.h"
|
||||
|
||||
void BBVariable::unref() {
|
||||
if (data && data->refcount.unref()) {
|
||||
memdelete(data);
|
||||
}
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
void BBVariable::set_value(const Variant &p_value) {
|
||||
data->value = p_value; // Setting value even when bound as a fallback in case the binding fails.
|
||||
data->value_changed = true;
|
||||
|
||||
if (is_bound()) {
|
||||
Object *obj = OBJECT_DB_GET_INSTANCE(data->bound_object);
|
||||
ERR_FAIL_COND_MSG(!obj, "Blackboard: Failed to get bound object.");
|
||||
#ifdef LIMBOAI_MODULE
|
||||
bool r_valid;
|
||||
obj->set(data->bound_property, p_value, &r_valid);
|
||||
ERR_FAIL_COND_MSG(!r_valid, vformat("Blackboard: Failed to set bound property `%s` on %s", data->bound_property, obj));
|
||||
#elif LIMBOAI_GDEXTENSION
|
||||
obj->set(data->bound_property, p_value);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
Variant BBVariable::get_value() const {
|
||||
if (is_bound()) {
|
||||
Object *obj = OBJECT_DB_GET_INSTANCE(data->bound_object);
|
||||
ERR_FAIL_COND_V_MSG(!obj, data->value, "Blackboard: Failed to get bound object.");
|
||||
#ifdef LIMBOAI_MODULE
|
||||
bool r_valid;
|
||||
Variant ret = obj->get(data->bound_property, &r_valid);
|
||||
ERR_FAIL_COND_V_MSG(!r_valid, data->value, vformat("Blackboard: Failed to get bound property `%s` on %s", data->bound_property, obj));
|
||||
#elif LIMBOAI_GDEXTENSION
|
||||
Variant ret = obj->get(data->bound_property);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
return data->value;
|
||||
}
|
||||
|
||||
void BBVariable::set_type(Variant::Type p_type) {
|
||||
data->type = p_type;
|
||||
data->value = VARIANT_DEFAULT(p_type);
|
||||
}
|
||||
|
||||
Variant::Type BBVariable::get_type() const {
|
||||
return data->type;
|
||||
}
|
||||
|
||||
void BBVariable::set_hint(PropertyHint p_hint) {
|
||||
data->hint = p_hint;
|
||||
}
|
||||
|
||||
PropertyHint BBVariable::get_hint() const {
|
||||
return data->hint;
|
||||
}
|
||||
|
||||
void BBVariable::set_hint_string(const String &p_hint_string) {
|
||||
data->hint_string = p_hint_string;
|
||||
}
|
||||
|
||||
String BBVariable::get_hint_string() const {
|
||||
return data->hint_string;
|
||||
}
|
||||
|
||||
BBVariable BBVariable::duplicate(bool p_deep) const {
|
||||
BBVariable var;
|
||||
var.data->hint = data->hint;
|
||||
var.data->hint_string = data->hint_string;
|
||||
var.data->type = data->type;
|
||||
if (p_deep) {
|
||||
var.data->value = data->value.duplicate(p_deep);
|
||||
} else {
|
||||
var.data->value = data->value;
|
||||
}
|
||||
var.data->binding_path = data->binding_path;
|
||||
var.data->bound_object = data->bound_object;
|
||||
var.data->bound_property = data->bound_property;
|
||||
return var;
|
||||
}
|
||||
|
||||
bool BBVariable::is_same_prop_info(const BBVariable &p_other) const {
|
||||
if (data->type != p_other.data->type) {
|
||||
return false;
|
||||
}
|
||||
if (data->hint != p_other.data->hint) {
|
||||
return false;
|
||||
}
|
||||
if (data->hint_string != p_other.data->hint_string) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BBVariable::copy_prop_info(const BBVariable &p_other) {
|
||||
data->type = p_other.data->type;
|
||||
data->hint = p_other.data->hint;
|
||||
data->hint_string = p_other.data->hint_string;
|
||||
}
|
||||
|
||||
void BBVariable::bind(Object *p_object, const StringName &p_property) {
|
||||
ERR_FAIL_NULL_MSG(p_object, "Blackboard: Binding failed - object is null.");
|
||||
ERR_FAIL_COND_MSG(p_property == StringName(), "Blackboard: Binding failed - property name is empty.");
|
||||
ERR_FAIL_COND_MSG(!OBJECT_HAS_PROPERTY(p_object, p_property), vformat("Blackboard: Binding failed - %s has no property `%s`.", p_object, p_property));
|
||||
data->bound_object = p_object->get_instance_id();
|
||||
data->bound_property = p_property;
|
||||
}
|
||||
|
||||
void BBVariable::unbind() {
|
||||
data->bound_object = 0;
|
||||
data->bound_property = StringName();
|
||||
}
|
||||
|
||||
bool BBVariable::operator==(const BBVariable &p_var) const {
|
||||
if (data == p_var.data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!data || !p_var.data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data->type != p_var.data->type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data->hint != p_var.data->hint) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data->hint_string != p_var.data->hint_string) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (get_value() != p_var.get_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BBVariable::operator!=(const BBVariable &p_var) const {
|
||||
return !(*this == p_var);
|
||||
}
|
||||
|
||||
void BBVariable::operator=(const BBVariable &p_var) {
|
||||
if (this == &p_var) {
|
||||
return;
|
||||
}
|
||||
|
||||
unref();
|
||||
|
||||
if (p_var.data && p_var.data->refcount.ref()) {
|
||||
data = p_var.data;
|
||||
}
|
||||
}
|
||||
|
||||
BBVariable::BBVariable(const BBVariable &p_var) {
|
||||
if (p_var.data && p_var.data->refcount.ref()) {
|
||||
data = p_var.data;
|
||||
}
|
||||
}
|
||||
|
||||
BBVariable::BBVariable(Variant::Type p_type, PropertyHint p_hint, const String &p_hint_string) {
|
||||
data = memnew(Data);
|
||||
data->refcount.init();
|
||||
|
||||
set_type(p_type);
|
||||
data->hint = p_hint;
|
||||
data->hint_string = p_hint_string;
|
||||
}
|
||||
|
||||
BBVariable::~BBVariable() {
|
||||
unref();
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* bb_variable.h
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BB_VARIABLE_H
|
||||
#define BB_VARIABLE_H
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "core/object/object.h"
|
||||
#endif // LIMBOAI_MODULE
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include "godot_cpp/core/object.hpp"
|
||||
using namespace godot;
|
||||
#endif // LIMBOAI_GDEXTENSION
|
||||
|
||||
class BBVariable {
|
||||
private:
|
||||
struct Data {
|
||||
// Is used to decide if the value needs to be synced in a derived plan.
|
||||
bool value_changed = false;
|
||||
|
||||
SafeRefCount refcount;
|
||||
Variant value;
|
||||
Variant::Type type = Variant::NIL;
|
||||
PropertyHint hint = PropertyHint::PROPERTY_HINT_NONE;
|
||||
String hint_string;
|
||||
|
||||
NodePath binding_path;
|
||||
uint64_t bound_object = 0;
|
||||
StringName bound_property;
|
||||
};
|
||||
|
||||
Data *data = nullptr;
|
||||
void unref();
|
||||
|
||||
public:
|
||||
void set_value(const Variant &p_value);
|
||||
Variant get_value() const;
|
||||
|
||||
void set_type(Variant::Type p_type);
|
||||
Variant::Type get_type() const;
|
||||
|
||||
void set_hint(PropertyHint p_hint);
|
||||
PropertyHint get_hint() const;
|
||||
|
||||
void set_hint_string(const String &p_hint_string);
|
||||
String get_hint_string() const;
|
||||
|
||||
BBVariable duplicate(bool p_deep = false) const;
|
||||
|
||||
_FORCE_INLINE_ bool is_value_changed() const { return data->value_changed; }
|
||||
_FORCE_INLINE_ void reset_value_changed() { data->value_changed = false; }
|
||||
|
||||
bool is_same_prop_info(const BBVariable &p_other) const;
|
||||
void copy_prop_info(const BBVariable &p_other);
|
||||
|
||||
// * Editor binding methods
|
||||
NodePath get_binding_path() const { return data->binding_path; }
|
||||
void set_binding_path(const NodePath &p_binding_path) { data->binding_path = p_binding_path; }
|
||||
bool has_binding() { return data->binding_path.is_empty(); }
|
||||
|
||||
// * Runtime binding methods
|
||||
_FORCE_INLINE_ bool is_bound() const { return data->bound_object != 0; }
|
||||
void bind(Object *p_object, const StringName &p_property);
|
||||
void unbind();
|
||||
|
||||
bool operator==(const BBVariable &p_var) const;
|
||||
bool operator!=(const BBVariable &p_var) const;
|
||||
void operator=(const BBVariable &p_var);
|
||||
|
||||
BBVariable(const BBVariable &p_var);
|
||||
BBVariable(Variant::Type p_type = Variant::Type::NIL, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "");
|
||||
~BBVariable();
|
||||
};
|
||||
|
||||
#endif // BB_VARIABLE_H
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* blackboard.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -10,63 +10,158 @@
|
|||
*/
|
||||
|
||||
#include "blackboard.h"
|
||||
#include "../util/limbo_compat.h"
|
||||
|
||||
#include "core/error/error_macros.h"
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "core/variant/variant.h"
|
||||
#include "scene/main/node.h"
|
||||
#endif // LIMBOAI_MODULE
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include <godot_cpp/classes/node.hpp>
|
||||
#include <godot_cpp/classes/ref.hpp>
|
||||
#include <godot_cpp/classes/ref_counted.hpp>
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
using namespace godot;
|
||||
#endif
|
||||
|
||||
Ref<Blackboard> Blackboard::top() const {
|
||||
Ref<Blackboard> bb(this);
|
||||
while (bb->get_parent_scope().is_valid()) {
|
||||
bb = bb->get_parent_scope();
|
||||
while (bb->get_parent().is_valid()) {
|
||||
bb = bb->get_parent();
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
|
||||
Variant Blackboard::get_var(const Variant &p_key, const Variant &p_default) const {
|
||||
if (data.has(p_key)) {
|
||||
return data.get_valid(p_key);
|
||||
Variant Blackboard::get_var(const StringName &p_name, const Variant &p_default, bool p_complain) const {
|
||||
if (data.has(p_name)) {
|
||||
return data.get(p_name).get_value();
|
||||
} else if (parent.is_valid()) {
|
||||
return parent->get_var(p_key, p_default);
|
||||
return parent->get_var(p_name, p_default, p_complain);
|
||||
} else {
|
||||
if (p_complain) {
|
||||
ERR_PRINT(vformat("Blackboard: Variable \"%s\" not found.", p_name));
|
||||
}
|
||||
return p_default;
|
||||
}
|
||||
}
|
||||
|
||||
void Blackboard::set_var(const Variant &p_key, const Variant &p_value) {
|
||||
data[p_key] = p_value;
|
||||
void Blackboard::set_var(const StringName &p_name, const Variant &p_value) {
|
||||
if (data.has(p_name)) {
|
||||
// Not checking type - allowing duck-typing.
|
||||
data[p_name].set_value(p_value);
|
||||
} else {
|
||||
BBVariable var(p_value.get_type());
|
||||
var.set_value(p_value);
|
||||
data.insert(p_name, var);
|
||||
}
|
||||
}
|
||||
|
||||
bool Blackboard::has_var(const Variant &p_key) const {
|
||||
return data.has(p_key) || (parent.is_valid() && parent->has_var(p_key));
|
||||
bool Blackboard::has_var(const StringName &p_name) const {
|
||||
return data.has(p_name) || (parent.is_valid() && parent->has_var(p_name));
|
||||
}
|
||||
|
||||
void Blackboard::erase_var(const Variant &p_key) {
|
||||
data.erase(p_key);
|
||||
void Blackboard::erase_var(const StringName &p_name) {
|
||||
data.erase(p_name);
|
||||
}
|
||||
|
||||
void Blackboard::prefetch_nodepath_vars(Node *p_node) {
|
||||
ERR_FAIL_COND(p_node == nullptr);
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
Variant value = data.get_value_at_index(i);
|
||||
if (value.get_type() == Variant::NODE_PATH) {
|
||||
Node *fetched_node = p_node->get_node_or_null(value);
|
||||
if (fetched_node != nullptr) {
|
||||
data[data.get_key_at_index(i)] = fetched_node;
|
||||
TypedArray<StringName> Blackboard::list_vars() const {
|
||||
TypedArray<StringName> var_names;
|
||||
var_names.resize(data.size());
|
||||
int idx = 0;
|
||||
for (const KeyValue<StringName, BBVariable> &kv : data) {
|
||||
var_names[idx] = kv.key;
|
||||
idx += 1;
|
||||
}
|
||||
return var_names;
|
||||
}
|
||||
|
||||
void Blackboard::print_state() const {
|
||||
Ref<Blackboard> bb{ this };
|
||||
int scope_idx = 0;
|
||||
while (bb.is_valid()) {
|
||||
int i = 0;
|
||||
String line = "Scope " + itos(scope_idx) + ": { ";
|
||||
for (const KeyValue<StringName, BBVariable> &kv : bb->data) {
|
||||
if (i > 0) {
|
||||
line += ", ";
|
||||
}
|
||||
line += String(kv.key) + ": " + String(kv.value.get_value());
|
||||
i++;
|
||||
}
|
||||
line += " }";
|
||||
PRINT_LINE(line);
|
||||
bb = bb->get_parent();
|
||||
scope_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary Blackboard::get_vars_as_dict() const {
|
||||
Dictionary dict;
|
||||
for (const KeyValue<StringName, BBVariable> &kv : data) {
|
||||
dict[kv.key] = kv.value.get_value();
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
void Blackboard::populate_from_dict(const Dictionary &p_dictionary) {
|
||||
Array keys = p_dictionary.keys();
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
if (keys[i].get_type() == Variant::STRING_NAME || keys[i].get_type() == Variant::STRING) {
|
||||
set_var(keys[i], p_dictionary[keys[i]]);
|
||||
} else {
|
||||
ERR_PRINT("Blackboard: Invalid key type in dictionary to populate blackboard. Must be StringName or String.");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void Blackboard::bind_var_to_property(const StringName &p_name, Object *p_object, const StringName &p_property, bool p_create) {
|
||||
if (!data.has(p_name)) {
|
||||
if (p_create) {
|
||||
data.insert(p_name, BBVariable());
|
||||
} else {
|
||||
ERR_FAIL_MSG("Blackboard: Can't bind variable that doesn't exist (var: " + p_name + ").");
|
||||
}
|
||||
}
|
||||
data[p_name].bind(p_object, p_property);
|
||||
}
|
||||
|
||||
void Blackboard::unbind_var(const StringName &p_name) {
|
||||
ERR_FAIL_COND_MSG(!data.has(p_name), "Blackboard: Can't unbind variable that doesn't exist (var: " + p_name + ").");
|
||||
data[p_name].unbind();
|
||||
}
|
||||
|
||||
void Blackboard::assign_var(const StringName &p_name, const BBVariable &p_var) {
|
||||
data.insert(p_name, p_var);
|
||||
}
|
||||
|
||||
void Blackboard::link_var(const StringName &p_name, const Ref<Blackboard> &p_target_blackboard, const StringName &p_target_var, bool p_create) {
|
||||
if (!data.has(p_name)) {
|
||||
if (p_create) {
|
||||
data.insert(p_name, BBVariable());
|
||||
} else {
|
||||
ERR_FAIL_MSG("Blackboard: Can't link variable that doesn't exist (var: " + p_name + ").");
|
||||
}
|
||||
}
|
||||
ERR_FAIL_COND_MSG(p_target_blackboard.is_null(), "Blackboard: Can't link variable to target blackboard that is null (var: " + p_name + ").");
|
||||
ERR_FAIL_COND_MSG(!p_target_blackboard->data.has(p_target_var), "Blackboard: Can't link variable to non-existent target (var: " + p_name + ", target: " + p_target_var + ").");
|
||||
data[p_name] = p_target_blackboard->data[p_target_var];
|
||||
}
|
||||
|
||||
void Blackboard::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_data"), &Blackboard::get_data);
|
||||
ClassDB::bind_method(D_METHOD("set_data", "p_data"), &Blackboard::set_data);
|
||||
ClassDB::bind_method(D_METHOD("get_var", "p_key", "p_default"), &Blackboard::get_var, Variant());
|
||||
ClassDB::bind_method(D_METHOD("set_var", "p_key", "p_value"), &Blackboard::set_var);
|
||||
ClassDB::bind_method(D_METHOD("has_var", "p_key"), &Blackboard::has_var);
|
||||
ClassDB::bind_method(D_METHOD("set_parent_scope", "p_blackboard"), &Blackboard::set_parent_scope);
|
||||
ClassDB::bind_method(D_METHOD("get_parent_scope"), &Blackboard::get_parent_scope);
|
||||
ClassDB::bind_method(D_METHOD("erase_var", "p_key"), &Blackboard::erase_var);
|
||||
ClassDB::bind_method(D_METHOD("prefetch_nodepath_vars", "p_node"), &Blackboard::prefetch_nodepath_vars);
|
||||
ClassDB::bind_method(D_METHOD("get_var", "var_name", "default", "complain"), &Blackboard::get_var, DEFVAL(Variant()), DEFVAL(true));
|
||||
ClassDB::bind_method(D_METHOD("set_var", "var_name", "value"), &Blackboard::set_var);
|
||||
ClassDB::bind_method(D_METHOD("has_var", "var_name"), &Blackboard::has_var);
|
||||
ClassDB::bind_method(D_METHOD("set_parent", "blackboard"), &Blackboard::set_parent);
|
||||
ClassDB::bind_method(D_METHOD("get_parent"), &Blackboard::get_parent);
|
||||
ClassDB::bind_method(D_METHOD("erase_var", "var_name"), &Blackboard::erase_var);
|
||||
ClassDB::bind_method(D_METHOD("clear"), &Blackboard::clear);
|
||||
ClassDB::bind_method(D_METHOD("list_vars"), &Blackboard::list_vars);
|
||||
ClassDB::bind_method(D_METHOD("print_state"), &Blackboard::print_state);
|
||||
ClassDB::bind_method(D_METHOD("get_vars_as_dict"), &Blackboard::get_vars_as_dict);
|
||||
ClassDB::bind_method(D_METHOD("populate_from_dict", "dictionary"), &Blackboard::populate_from_dict);
|
||||
ClassDB::bind_method(D_METHOD("top"), &Blackboard::top);
|
||||
}
|
||||
ClassDB::bind_method(D_METHOD("bind_var_to_property", "var_name", "object", "property", "create"), &Blackboard::bind_var_to_property, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("unbind_var", "var_name"), &Blackboard::unbind_var);
|
||||
ClassDB::bind_method(D_METHOD("link_var", "var_name", "target_blackboard", "target_var", "create"), &Blackboard::link_var, DEFVAL(false));
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* blackboard.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -12,37 +12,62 @@
|
|||
#ifndef BLACKBOARD_H
|
||||
#define BLACKBOARD_H
|
||||
|
||||
#include "bb_variable.h"
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "core/object/object.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "core/variant/dictionary.h"
|
||||
#include "core/variant/variant.h"
|
||||
#include "scene/main/node.h"
|
||||
#endif // LIMBOAI_MODULE
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include <godot_cpp/classes/node.hpp>
|
||||
#include <godot_cpp/classes/ref.hpp>
|
||||
#include <godot_cpp/classes/ref_counted.hpp>
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
#include <godot_cpp/templates/hash_map.hpp>
|
||||
using namespace godot;
|
||||
#endif // LIMBOAI_GDEXTENSION
|
||||
|
||||
class Blackboard : public RefCounted {
|
||||
GDCLASS(Blackboard, RefCounted);
|
||||
|
||||
private:
|
||||
Dictionary data;
|
||||
HashMap<StringName, BBVariable> data;
|
||||
Ref<Blackboard> parent;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_data(const Dictionary &p_value) { data = p_value; }
|
||||
Dictionary get_data() const { return data; }
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
String _to_string() const { return "<" + get_class() + "#" + itos(get_instance_id()) + ">"; }
|
||||
#endif
|
||||
|
||||
void set_parent_scope(const Ref<Blackboard> &p_blackboard) { parent = p_blackboard; }
|
||||
Ref<Blackboard> get_parent_scope() const { return parent; }
|
||||
public:
|
||||
void set_parent(const Ref<Blackboard> &p_blackboard) { parent = p_blackboard; }
|
||||
Ref<Blackboard> get_parent() const { return parent; }
|
||||
|
||||
Ref<Blackboard> top() const;
|
||||
|
||||
Variant get_var(const Variant &p_key, const Variant &p_default) const;
|
||||
void set_var(const Variant &p_key, const Variant &p_value);
|
||||
bool has_var(const Variant &p_key) const;
|
||||
void erase_var(const Variant &p_key);
|
||||
Variant get_var(const StringName &p_name, const Variant &p_default = Variant(), bool p_complain = true) const;
|
||||
void set_var(const StringName &p_name, const Variant &p_value);
|
||||
bool has_var(const StringName &p_name) const;
|
||||
_FORCE_INLINE_ bool has_local_var(const StringName &p_name) const { return data.has(p_name); }
|
||||
void erase_var(const StringName &p_name);
|
||||
void clear() { data.clear(); }
|
||||
TypedArray<StringName> list_vars() const;
|
||||
void print_state() const;
|
||||
|
||||
void prefetch_nodepath_vars(Node *p_node);
|
||||
Dictionary get_vars_as_dict() const;
|
||||
void populate_from_dict(const Dictionary &p_dictionary);
|
||||
|
||||
void bind_var_to_property(const StringName &p_name, Object *p_object, const StringName &p_property, bool p_create = false);
|
||||
void unbind_var(const StringName &p_name);
|
||||
|
||||
void assign_var(const StringName &p_name, const BBVariable &p_var);
|
||||
|
||||
void link_var(const StringName &p_name, const Ref<Blackboard> &p_target_blackboard, const StringName &p_target_var, bool p_create = false);
|
||||
};
|
||||
|
||||
#endif // BLACKBOARD_H
|
||||
#endif // BLACKBOARD_H
|
||||
|
|
|
@ -0,0 +1,578 @@
|
|||
/**
|
||||
* blackboard_plan.cpp
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "blackboard_plan.h"
|
||||
|
||||
#include "../util/limbo_utility.h"
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "editor/editor_inspector.h"
|
||||
#include "editor/editor_interface.h"
|
||||
#elif LIMBOAI_GDEXTENSION
|
||||
#include <godot_cpp/classes/editor_inspector.hpp>
|
||||
#include <godot_cpp/classes/editor_interface.hpp>
|
||||
#include <godot_cpp/classes/engine.hpp>
|
||||
#include <godot_cpp/classes/scene_tree.hpp>
|
||||
#endif
|
||||
|
||||
bool BlackboardPlan::_set(const StringName &p_name, const Variant &p_value) {
|
||||
String name_str = p_name;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
// * Editor
|
||||
if (var_map.has(p_name)) {
|
||||
BBVariable &var = var_map[p_name];
|
||||
var.set_value(p_value);
|
||||
if (base.is_valid() && p_value == base->get_var(p_name).get_value()) {
|
||||
// When user pressed reset property button in inspector...
|
||||
var.reset_value_changed();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
// * Mapping
|
||||
if (name_str.begins_with("mapping/")) {
|
||||
StringName mapped_var_name = name_str.get_slicec('/', 1);
|
||||
StringName value = p_value;
|
||||
bool prop_list_changed = false;
|
||||
if (value == StringName()) {
|
||||
if (parent_scope_mapping.has(mapped_var_name)) {
|
||||
prop_list_changed = true;
|
||||
parent_scope_mapping.erase(mapped_var_name);
|
||||
}
|
||||
} else {
|
||||
if (!parent_scope_mapping.has(mapped_var_name)) {
|
||||
prop_list_changed = true;
|
||||
}
|
||||
parent_scope_mapping[mapped_var_name] = value;
|
||||
}
|
||||
if (prop_list_changed) {
|
||||
notify_property_list_changed();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// * Binding
|
||||
if (name_str.begins_with("binding/")) {
|
||||
StringName bound_var = name_str.get_slicec('/', 1);
|
||||
NodePath value = p_value;
|
||||
bool prop_list_changed = false;
|
||||
if (value.is_empty()) {
|
||||
if (property_bindings.has(bound_var)) {
|
||||
prop_list_changed = true;
|
||||
property_bindings.erase(bound_var);
|
||||
}
|
||||
} else {
|
||||
if (!property_bindings.has(bound_var)) {
|
||||
prop_list_changed = true;
|
||||
}
|
||||
property_bindings[bound_var] = value;
|
||||
}
|
||||
if (prop_list_changed) {
|
||||
notify_property_list_changed();
|
||||
}
|
||||
}
|
||||
|
||||
// * Storage
|
||||
if (name_str.begins_with("var/")) {
|
||||
StringName var_name = name_str.get_slicec('/', 1);
|
||||
String what = name_str.get_slicec('/', 2);
|
||||
if (!var_map.has(var_name) && what == "name") {
|
||||
add_var(var_name, BBVariable());
|
||||
}
|
||||
if (what == "name") {
|
||||
// We don't store variable name with the variable.
|
||||
} else if (what == "type") {
|
||||
var_map[var_name].set_type((Variant::Type)(int)p_value);
|
||||
} else if (what == "value") {
|
||||
var_map[var_name].set_value(p_value);
|
||||
} else if (what == "hint") {
|
||||
var_map[var_name].set_hint((PropertyHint)(int)p_value);
|
||||
} else if (what == "hint_string") {
|
||||
var_map[var_name].set_hint_string(p_value);
|
||||
} else if (what == "property_binding") {
|
||||
property_bindings[var_name] = NodePath(p_value);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BlackboardPlan::_get(const StringName &p_name, Variant &r_ret) const {
|
||||
String name_str = p_name;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
// * Editor
|
||||
if (var_map.has(p_name)) {
|
||||
if (has_mapping(p_name)) {
|
||||
r_ret = "Mapped to " + LimboUtility::get_singleton()->decorate_var(parent_scope_mapping[p_name]);
|
||||
} else if (has_property_binding(p_name)) {
|
||||
const NodePath &binding = property_bindings[p_name];
|
||||
|
||||
Node *edited_node = Object::cast_to<Node>(EditorInterface::get_singleton()->get_inspector()->get_edited_object());
|
||||
if (!edited_node) {
|
||||
edited_node = SCENE_TREE()->get_edited_scene_root();
|
||||
}
|
||||
Node *bound_node = edited_node ? edited_node->get_node_or_null(binding) : nullptr;
|
||||
|
||||
String shortened_path;
|
||||
if (bound_node) {
|
||||
shortened_path = (String)bound_node->get_name() +
|
||||
":" + (String)binding.get_concatenated_subnames();
|
||||
} else {
|
||||
shortened_path = (String)binding.get_name(binding.get_name_count() - 1) +
|
||||
":" + (String)binding.get_concatenated_subnames();
|
||||
}
|
||||
r_ret = String::utf8("🔗 ") + shortened_path;
|
||||
} else {
|
||||
r_ret = var_map[p_name].get_value();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
// * Mapping
|
||||
if (name_str.begins_with("mapping/")) {
|
||||
StringName mapped_var_name = name_str.get_slicec('/', 1);
|
||||
ERR_FAIL_COND_V(mapped_var_name == StringName(), false);
|
||||
if (has_mapping(mapped_var_name)) {
|
||||
r_ret = parent_scope_mapping[mapped_var_name];
|
||||
} else if (has_property_binding(mapped_var_name)) {
|
||||
r_ret = RTR("Already bound to property.");
|
||||
} else {
|
||||
r_ret = StringName();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// * Binding
|
||||
if (name_str.begins_with("binding/")) {
|
||||
StringName bound_var = name_str.get_slicec('/', 1);
|
||||
ERR_FAIL_COND_V(bound_var == StringName(), false);
|
||||
if (has_property_binding(bound_var)) {
|
||||
r_ret = property_bindings[bound_var];
|
||||
} else if (has_mapping(bound_var)) {
|
||||
r_ret = RTR("Already mapped to variable.");
|
||||
} else {
|
||||
r_ret = NodePath();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// * Storage
|
||||
if (!name_str.begins_with("var/")) {
|
||||
return false;
|
||||
}
|
||||
StringName var_name = name_str.get_slicec('/', 1);
|
||||
String what = name_str.get_slicec('/', 2);
|
||||
ERR_FAIL_COND_V(!var_map.has(var_name), false);
|
||||
|
||||
if (what == "name") {
|
||||
r_ret = var_name;
|
||||
} else if (what == "type") {
|
||||
r_ret = var_map[var_name].get_type();
|
||||
} else if (what == "value") {
|
||||
r_ret = var_map[var_name].get_value();
|
||||
} else if (what == "hint") {
|
||||
r_ret = var_map[var_name].get_hint();
|
||||
} else if (what == "hint_string") {
|
||||
r_ret = var_map[var_name].get_hint_string();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BlackboardPlan::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
for (const Pair<StringName, BBVariable> &p : var_list) {
|
||||
String var_name = p.first;
|
||||
BBVariable var = p.second;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
// * Editor
|
||||
if (!_is_var_nil(var) && !_is_var_private(var_name, var)) {
|
||||
if (has_mapping(var_name) || has_property_binding(var_name)) {
|
||||
p_list->push_back(PropertyInfo(Variant::STRING, var_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY));
|
||||
} else {
|
||||
p_list->push_back(PropertyInfo(var.get_type(), var_name, var.get_hint(), var.get_hint_string(), PROPERTY_USAGE_EDITOR));
|
||||
}
|
||||
}
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
// * Storage
|
||||
if (is_derived() && (!var.is_value_changed() || var.get_value() == base->var_map[var_name].get_value())) {
|
||||
// Don't store variable if it's not modified in a derived plan.
|
||||
// Variable is considered modified when it's marked as changed and its value is different from the base plan.
|
||||
continue;
|
||||
}
|
||||
p_list->push_back(PropertyInfo(Variant::STRING, "var/" + var_name + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
|
||||
p_list->push_back(PropertyInfo(Variant::INT, "var/" + var_name + "/type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
|
||||
p_list->push_back(PropertyInfo(var.get_type(), "var/" + var_name + "/value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
|
||||
p_list->push_back(PropertyInfo(Variant::INT, "var/" + var_name + "/hint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
|
||||
p_list->push_back(PropertyInfo(Variant::STRING, "var/" + var_name + "/hint_string", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
|
||||
}
|
||||
|
||||
// * Mapping
|
||||
if (is_mapping_enabled()) {
|
||||
p_list->push_back(PropertyInfo(Variant::NIL, "Mapping", PROPERTY_HINT_NONE, "mapping/", PROPERTY_USAGE_GROUP));
|
||||
for (const Pair<StringName, BBVariable> &p : var_list) {
|
||||
if (_is_var_private(p.first, p.second)) {
|
||||
continue;
|
||||
}
|
||||
if (unlikely(has_property_binding(p.first))) {
|
||||
p_list->push_back(PropertyInfo(Variant::STRING, "mapping/" + p.first, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY));
|
||||
} else {
|
||||
// Serialize only non-empty mappings.
|
||||
PropertyUsageFlags usage = has_mapping(p.first) ? PROPERTY_USAGE_DEFAULT : PROPERTY_USAGE_EDITOR;
|
||||
p_list->push_back(PropertyInfo(Variant::STRING_NAME, "mapping/" + p.first, PROPERTY_HINT_NONE, "", usage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// * Binding
|
||||
p_list->push_back(PropertyInfo(Variant::NIL, "Binding", PROPERTY_HINT_NONE, "binding/", PROPERTY_USAGE_GROUP));
|
||||
for (const Pair<StringName, BBVariable> &p : var_list) {
|
||||
if (_is_var_nil(p.second) || _is_var_private(p.first, p.second)) {
|
||||
continue;
|
||||
}
|
||||
if (unlikely(has_mapping(p.first))) {
|
||||
p_list->push_back(PropertyInfo(Variant::STRING, "binding/" + p.first, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY));
|
||||
} else {
|
||||
PropertyUsageFlags usage = has_property_binding(p.first) ? PROPERTY_USAGE_DEFAULT : PROPERTY_USAGE_EDITOR;
|
||||
// PROPERTY_HINT_LINK is used to signal that NodePath should point to a property.
|
||||
// Our inspector plugin will know how to handle it.
|
||||
p_list->push_back(PropertyInfo(Variant::NODE_PATH, "binding/" + p.first, PROPERTY_HINT_LINK, itos(p.second.get_type()), usage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BlackboardPlan::_property_can_revert(const StringName &p_name) const {
|
||||
if (String(p_name).begins_with("mapping/")) {
|
||||
return true;
|
||||
}
|
||||
return base.is_valid() && base->var_map.has(p_name);
|
||||
}
|
||||
|
||||
bool BlackboardPlan::_property_get_revert(const StringName &p_name, Variant &r_property) const {
|
||||
if (String(p_name).begins_with("mapping/")) {
|
||||
r_property = StringName();
|
||||
return true;
|
||||
}
|
||||
if (base->var_map.has(p_name)) {
|
||||
r_property = base->var_map[p_name].get_value();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BlackboardPlan::set_base_plan(const Ref<BlackboardPlan> &p_base) {
|
||||
if (p_base == this) {
|
||||
WARN_PRINT_ED("BlackboardPlan: Using same resource for derived blackboard plan is not supported.");
|
||||
base.unref();
|
||||
} else {
|
||||
base = p_base;
|
||||
}
|
||||
sync_with_base_plan();
|
||||
notify_property_list_changed();
|
||||
}
|
||||
|
||||
void BlackboardPlan::set_parent_scope_plan_provider(const Callable &p_parent_scope_plan_provider) {
|
||||
parent_scope_plan_provider = p_parent_scope_plan_provider;
|
||||
notify_property_list_changed();
|
||||
}
|
||||
|
||||
bool BlackboardPlan::has_mapping(const StringName &p_name) const {
|
||||
return is_mapping_enabled() && parent_scope_mapping.has(p_name) && parent_scope_mapping[p_name] != StringName();
|
||||
}
|
||||
|
||||
void BlackboardPlan::set_property_binding(const StringName &p_name, const NodePath &p_path) {
|
||||
property_bindings[p_name] = p_path;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BlackboardPlan::set_prefetch_nodepath_vars(bool p_enable) {
|
||||
prefetch_nodepath_vars = p_enable;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
bool BlackboardPlan::is_prefetching_nodepath_vars() const {
|
||||
if (is_derived()) {
|
||||
return base->is_prefetching_nodepath_vars();
|
||||
} else {
|
||||
return prefetch_nodepath_vars;
|
||||
}
|
||||
}
|
||||
|
||||
void BlackboardPlan::add_var(const StringName &p_name, const BBVariable &p_var) {
|
||||
ERR_FAIL_COND(p_name == StringName());
|
||||
ERR_FAIL_COND(var_map.has(p_name));
|
||||
var_map.insert(p_name, p_var);
|
||||
var_list.push_back(Pair<StringName, BBVariable>(p_name, p_var));
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BlackboardPlan::remove_var(const StringName &p_name) {
|
||||
ERR_FAIL_COND(!var_map.has(p_name));
|
||||
var_list.erase(Pair<StringName, BBVariable>(p_name, var_map[p_name]));
|
||||
var_map.erase(p_name);
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
BBVariable BlackboardPlan::get_var(const StringName &p_name) {
|
||||
ERR_FAIL_COND_V(!var_map.has(p_name), BBVariable());
|
||||
return var_map.get(p_name);
|
||||
}
|
||||
|
||||
Pair<StringName, BBVariable> BlackboardPlan::get_var_by_index(int p_index) {
|
||||
Pair<StringName, BBVariable> ret;
|
||||
ERR_FAIL_INDEX_V(p_index, (int)var_map.size(), ret);
|
||||
return var_list.get(p_index);
|
||||
}
|
||||
|
||||
TypedArray<StringName> BlackboardPlan::list_vars() const {
|
||||
TypedArray<StringName> ret;
|
||||
for (const Pair<StringName, BBVariable> &p : var_list) {
|
||||
ret.append(p.first);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
StringName BlackboardPlan::get_var_name(const BBVariable &p_var) const {
|
||||
for (const Pair<StringName, BBVariable> &p : var_list) {
|
||||
if (p.second == p_var) {
|
||||
return p.first;
|
||||
}
|
||||
}
|
||||
return StringName();
|
||||
}
|
||||
|
||||
bool BlackboardPlan::is_valid_var_name(const StringName &p_name) const {
|
||||
String name_str = p_name;
|
||||
if (name_str.begins_with("resource_")) {
|
||||
return false;
|
||||
}
|
||||
return name_str.is_valid_identifier() && !var_map.has(p_name);
|
||||
}
|
||||
|
||||
void BlackboardPlan::rename_var(const StringName &p_name, const StringName &p_new_name) {
|
||||
if (p_name == p_new_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(!is_valid_var_name(p_new_name));
|
||||
ERR_FAIL_COND(!var_map.has(p_name));
|
||||
ERR_FAIL_COND(var_map.has(p_new_name));
|
||||
|
||||
BBVariable var = var_map[p_name];
|
||||
Pair<StringName, BBVariable> new_entry(p_new_name, var);
|
||||
Pair<StringName, BBVariable> old_entry(p_name, var);
|
||||
var_list.find(old_entry)->set(new_entry);
|
||||
|
||||
var_map.erase(p_name);
|
||||
var_map.insert(p_new_name, var);
|
||||
|
||||
if (parent_scope_mapping.has(p_name)) {
|
||||
parent_scope_mapping[p_new_name] = parent_scope_mapping[p_name];
|
||||
parent_scope_mapping.erase(p_name);
|
||||
}
|
||||
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BlackboardPlan::move_var(int p_index, int p_new_index) {
|
||||
ERR_FAIL_INDEX(p_index, (int)var_map.size());
|
||||
ERR_FAIL_INDEX(p_new_index, (int)var_map.size());
|
||||
|
||||
if (p_index == p_new_index) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Pair<StringName, BBVariable>>::Element *E = var_list.front();
|
||||
for (int i = 0; i < p_index; i++) {
|
||||
E = E->next();
|
||||
}
|
||||
List<Pair<StringName, BBVariable>>::Element *E2 = var_list.front();
|
||||
for (int i = 0; i < p_new_index; i++) {
|
||||
E2 = E2->next();
|
||||
}
|
||||
|
||||
var_list.move_before(E, E2);
|
||||
if (p_new_index > p_index) {
|
||||
var_list.move_before(E2, E);
|
||||
}
|
||||
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BlackboardPlan::sync_with_base_plan() {
|
||||
if (base.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
|
||||
// Sync variables with the base plan.
|
||||
for (const Pair<StringName, BBVariable> &p : base->var_list) {
|
||||
const StringName &base_name = p.first;
|
||||
const BBVariable &base_var = p.second;
|
||||
|
||||
if (!var_map.has(base_name)) {
|
||||
add_var(base_name, base_var.duplicate());
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
BBVariable var = var_map[base_name];
|
||||
if (!var.is_same_prop_info(base_var)) {
|
||||
var.copy_prop_info(base_var);
|
||||
changed = true;
|
||||
}
|
||||
if ((!var.is_value_changed() && var.get_value() != base_var.get_value()) ||
|
||||
(var.get_value().get_type() != base_var.get_type())) {
|
||||
// Reset value according to base plan.
|
||||
var.set_value(base_var.get_value());
|
||||
var.reset_value_changed();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Erase variables that do not exist in the base plan.
|
||||
List<StringName> erase_list;
|
||||
for (const Pair<StringName, BBVariable> &p : var_list) {
|
||||
if (!base->has_var(p.first)) {
|
||||
erase_list.push_back(p.first);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
while (erase_list.size()) {
|
||||
remove_var(erase_list.front()->get());
|
||||
erase_list.pop_front();
|
||||
}
|
||||
|
||||
// Sync order of variables.
|
||||
// Glossary: E - element of current plan, B - element of base plan, F - element of current plan (used for forward search).
|
||||
ERR_FAIL_COND(base->var_list.size() != var_list.size());
|
||||
List<Pair<StringName, BBVariable>>::Element *B = base->var_list.front();
|
||||
for (List<Pair<StringName, BBVariable>>::Element *E = var_list.front(); E; E = E->next()) {
|
||||
if (E->get().first != B->get().first) {
|
||||
List<Pair<StringName, BBVariable>>::Element *F = E->next();
|
||||
while (F) {
|
||||
if (F->get().first == B->get().first) {
|
||||
var_list.move_before(F, E);
|
||||
E = F;
|
||||
break;
|
||||
}
|
||||
F = F->next();
|
||||
}
|
||||
}
|
||||
B = B->next();
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
Ref<Blackboard> BlackboardPlan::create_blackboard(Node *p_prefetch_root, const Ref<Blackboard> &p_parent_scope, Node *p_prefetch_root_for_base_plan) {
|
||||
ERR_FAIL_COND_V(p_prefetch_root == nullptr && prefetch_nodepath_vars, memnew(Blackboard));
|
||||
Ref<Blackboard> bb = memnew(Blackboard);
|
||||
bb->set_parent(p_parent_scope);
|
||||
populate_blackboard(bb, true, p_prefetch_root, p_prefetch_root_for_base_plan);
|
||||
return bb;
|
||||
}
|
||||
|
||||
void BlackboardPlan::populate_blackboard(const Ref<Blackboard> &p_blackboard, bool overwrite, Node *p_prefetch_root, Node *p_prefetch_root_for_base_plan) {
|
||||
ERR_FAIL_COND(p_prefetch_root == nullptr && prefetch_nodepath_vars);
|
||||
ERR_FAIL_COND(p_blackboard.is_null());
|
||||
for (const Pair<StringName, BBVariable> &p : var_list) {
|
||||
if (p_blackboard->has_local_var(p.first) && !overwrite) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
Variant::Type existing_type = p_blackboard->get_var(p.first).get_type();
|
||||
Variant::Type planned_type = p.second.get_type();
|
||||
if (existing_type != planned_type && existing_type != Variant::NIL && planned_type != Variant::NIL && !(existing_type == Variant::OBJECT && planned_type == Variant::NODE_PATH)) {
|
||||
WARN_PRINT(vformat("BlackboardPlan: Not overwriting %s as it already exists in the blackboard, but it has a different type than planned (%s vs %s). File: %s",
|
||||
LimboUtility::get_singleton()->decorate_var(p.first), Variant::get_type_name(existing_type), Variant::get_type_name(planned_type), get_path()));
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
bool is_bound = has_property_binding(p.first) || (is_derived() && get_base_plan()->has_property_binding(p.first));
|
||||
bool has_mapping = parent_scope_mapping.has(p.first);
|
||||
bool do_prefetch = !is_bound && !has_mapping && prefetch_nodepath_vars;
|
||||
|
||||
// Add a variable duplicate to the blackboard, optionally with NodePath prefetch.
|
||||
BBVariable var = p.second.duplicate(true);
|
||||
if (unlikely(do_prefetch && p.second.get_type() == Variant::NODE_PATH)) {
|
||||
Node *prefetch_root = !p_prefetch_root_for_base_plan || !is_derived() || is_derived_var_changed(p.first) ? p_prefetch_root : p_prefetch_root_for_base_plan;
|
||||
Node *n = prefetch_root->get_node_or_null(p.second.get_value());
|
||||
if (n != nullptr) {
|
||||
var.set_value(n);
|
||||
} else {
|
||||
ERR_PRINT(vformat("BlackboardPlan: Prefetch failed for variable $%s with value: %s", p.first, p.second.get_value()));
|
||||
var.set_value(Variant());
|
||||
}
|
||||
}
|
||||
p_blackboard->assign_var(p.first, var);
|
||||
|
||||
if (has_mapping) {
|
||||
StringName target_var = parent_scope_mapping[p.first];
|
||||
if (target_var != StringName()) {
|
||||
ERR_CONTINUE_MSG(p_blackboard->get_parent().is_null(), vformat("BlackboardPlan: Cannot link variable %s to parent scope because the parent scope is not set.", LimboUtility::get_singleton()->decorate_var(p.first)));
|
||||
p_blackboard->link_var(p.first, p_blackboard->get_parent(), target_var);
|
||||
}
|
||||
} else if (is_bound) {
|
||||
// Bind variable to a property of a scene node.
|
||||
NodePath binding_path;
|
||||
Node *binding_root;
|
||||
if (has_property_binding(p.first)) {
|
||||
binding_path = property_bindings[p.first];
|
||||
binding_root = p_prefetch_root;
|
||||
} else {
|
||||
binding_path = get_base_plan()->property_bindings[p.first];
|
||||
binding_root = p_prefetch_root_for_base_plan;
|
||||
}
|
||||
ERR_CONTINUE_MSG(binding_path.get_subname_count() != 1, vformat("BlackboardPlan: Can't bind variable %s using property path that contains multiple sub-names: %s", LimboUtility::get_singleton()->decorate_var(p.first), binding_path));
|
||||
NodePath node_path{ binding_path.get_concatenated_names() };
|
||||
StringName prop_name = binding_path.get_subname(0);
|
||||
// TODO: Implement binding for base plan as well.
|
||||
Node *n = binding_root->get_node_or_null(node_path);
|
||||
ERR_CONTINUE_MSG(n == nullptr, vformat("BlackboardPlan: Binding failed for variable %s using property path: %s", LimboUtility::get_singleton()->decorate_var(p.first), binding_path));
|
||||
var.bind(n, prop_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BlackboardPlan::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_prefetch_nodepath_vars", "enable"), &BlackboardPlan::set_prefetch_nodepath_vars);
|
||||
ClassDB::bind_method(D_METHOD("is_prefetching_nodepath_vars"), &BlackboardPlan::is_prefetching_nodepath_vars);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_base_plan", "blackboard_plan"), &BlackboardPlan::set_base_plan);
|
||||
ClassDB::bind_method(D_METHOD("get_base_plan"), &BlackboardPlan::get_base_plan);
|
||||
ClassDB::bind_method(D_METHOD("is_derived"), &BlackboardPlan::is_derived);
|
||||
ClassDB::bind_method(D_METHOD("sync_with_base_plan"), &BlackboardPlan::sync_with_base_plan);
|
||||
ClassDB::bind_method(D_METHOD("set_parent_scope_plan_provider", "callable"), &BlackboardPlan::set_parent_scope_plan_provider);
|
||||
ClassDB::bind_method(D_METHOD("get_parent_scope_plan_provider"), &BlackboardPlan::get_parent_scope_plan_provider);
|
||||
ClassDB::bind_method(D_METHOD("create_blackboard", "prefetch_root", "parent_scope", "prefetch_root_for_base_plan"), &BlackboardPlan::create_blackboard, DEFVAL(Ref<Blackboard>()), DEFVAL(Variant()));
|
||||
ClassDB::bind_method(D_METHOD("populate_blackboard", "blackboard", "overwrite", "prefetch_root", "prefetch_root_for_base_plan"), &BlackboardPlan::populate_blackboard, DEFVAL(Variant()));
|
||||
|
||||
// To avoid cluttering the member namespace, we do not export unnecessary properties in this class.
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefetch_nodepath_vars", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_prefetch_nodepath_vars", "is_prefetching_nodepath_vars");
|
||||
}
|
||||
|
||||
BlackboardPlan::BlackboardPlan() {
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
* blackboard_plan.h
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BLACKBOARD_PLAN_H
|
||||
#define BLACKBOARD_PLAN_H
|
||||
|
||||
#include "bb_variable.h"
|
||||
#include "blackboard.h"
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "core/io/resource.h"
|
||||
#endif // LIMBOAI_MODULE
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include <godot_cpp/classes/resource.hpp>
|
||||
using namespace godot;
|
||||
#endif // LIMBOAI_GDEXTENSION
|
||||
|
||||
class BlackboardPlan : public Resource {
|
||||
GDCLASS(BlackboardPlan, Resource);
|
||||
|
||||
private:
|
||||
List<Pair<StringName, BBVariable>> var_list;
|
||||
HashMap<StringName, BBVariable> var_map;
|
||||
|
||||
// When base is not null, the plan is considered to be derived from the base plan.
|
||||
// A derived plan can only have variables that exist in the base plan,
|
||||
// and only the values can be different in those variables.
|
||||
// The derived plan is synced with the base plan to maintain consistency.
|
||||
Ref<BlackboardPlan> base;
|
||||
|
||||
// Mapping between variables in this plan and their parent scope names.
|
||||
// Used for linking variables to their parent scope counterparts upon Blackboard creation/population.
|
||||
HashMap<StringName, StringName> parent_scope_mapping;
|
||||
// Fetcher function for the parent scope plan. Function should return a Ref<BlackboardPlan>.
|
||||
// Used in the inspector: enables mapping feature when set.
|
||||
Callable parent_scope_plan_provider;
|
||||
|
||||
// Bindings to properties in the scene to which this plan belongs.
|
||||
HashMap<StringName, NodePath> property_bindings;
|
||||
bool property_binding_enabled = false;
|
||||
|
||||
// If true, NodePath variables will be prefetched, so that the vars will contain node pointers instead (upon BB creation/population).
|
||||
bool prefetch_nodepath_vars = true;
|
||||
|
||||
_FORCE_INLINE_ bool _is_var_nil(const BBVariable &p_var) const { return p_var.get_type() == Variant::NIL; }
|
||||
_FORCE_INLINE_ bool _is_var_private(const String &p_name, const BBVariable &p_var) const { return is_derived() && p_name.begins_with("_"); }
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
bool _set(const StringName &p_name, const Variant &p_value);
|
||||
bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
bool _property_can_revert(const StringName &p_name) const;
|
||||
bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
String _to_string() const { return "<" + get_class() + "#" + itos(get_instance_id()) + ">"; }
|
||||
#endif
|
||||
|
||||
public:
|
||||
void set_base_plan(const Ref<BlackboardPlan> &p_base);
|
||||
Ref<BlackboardPlan> get_base_plan() const { return base; }
|
||||
|
||||
void set_parent_scope_plan_provider(const Callable &p_parent_scope_plan_provider);
|
||||
Callable get_parent_scope_plan_provider() const { return parent_scope_plan_provider; }
|
||||
|
||||
bool is_mapping_enabled() const { return parent_scope_plan_provider.is_valid() && (parent_scope_plan_provider.call() != Ref<BlackboardPlan>()); }
|
||||
bool has_mapping(const StringName &p_name) const;
|
||||
|
||||
bool has_property_binding(const StringName &p_name) const { return property_bindings.has(p_name); }
|
||||
void set_property_binding(const StringName &p_name, const NodePath &p_path);
|
||||
NodePath get_property_binding(const StringName &p_name) const { return property_bindings.has(p_name) ? property_bindings[p_name] : NodePath(); }
|
||||
|
||||
void set_prefetch_nodepath_vars(bool p_enable);
|
||||
bool is_prefetching_nodepath_vars() const;
|
||||
|
||||
void add_var(const StringName &p_name, const BBVariable &p_var);
|
||||
void remove_var(const StringName &p_name);
|
||||
BBVariable get_var(const StringName &p_name);
|
||||
Pair<StringName, BBVariable> get_var_by_index(int p_index);
|
||||
_FORCE_INLINE_ bool has_var(const StringName &p_name) { return var_map.has(p_name); }
|
||||
_FORCE_INLINE_ bool is_empty() const { return var_map.is_empty(); }
|
||||
int get_var_count() const { return var_map.size(); }
|
||||
|
||||
TypedArray<StringName> list_vars() const;
|
||||
StringName get_var_name(const BBVariable &p_var) const;
|
||||
bool is_valid_var_name(const StringName &p_name) const;
|
||||
void rename_var(const StringName &p_name, const StringName &p_new_name);
|
||||
void move_var(int p_index, int p_new_index);
|
||||
|
||||
void sync_with_base_plan();
|
||||
_FORCE_INLINE_ bool is_derived() const { return base.is_valid(); }
|
||||
_FORCE_INLINE_ bool is_derived_var_changed(const StringName &p_name) const { return base.is_valid() && var_map.has(p_name) && var_map[p_name].is_value_changed(); }
|
||||
|
||||
Ref<Blackboard> create_blackboard(Node *p_prefetch_root, const Ref<Blackboard> &p_parent_scope = Ref<Blackboard>(), Node *p_prefetch_root_for_base_plan = nullptr);
|
||||
void populate_blackboard(const Ref<Blackboard> &p_blackboard, bool overwrite, Node *p_prefetch_root, Node *p_prefetch_root_for_base_plan = nullptr);
|
||||
|
||||
BlackboardPlan();
|
||||
};
|
||||
|
||||
#endif // BLACKBOARD_PLAN_H
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* behavior_tree.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -11,11 +11,56 @@
|
|||
|
||||
#include "behavior_tree.h"
|
||||
|
||||
#include "../util/limbo_string_names.h"
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/object/object.h"
|
||||
#include "core/templates/list.h"
|
||||
#include "core/variant/variant.h"
|
||||
#endif // ! LIMBOAI_MODULE
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include "godot_cpp/core/error_macros.hpp"
|
||||
#endif // ! LIMBOAI_GDEXTENSION
|
||||
|
||||
void BehaviorTree::set_description(const String &p_value) {
|
||||
description = p_value;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BehaviorTree::set_blackboard_plan(const Ref<BlackboardPlan> &p_plan) {
|
||||
if (blackboard_plan == p_plan) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint() && blackboard_plan.is_valid() &&
|
||||
blackboard_plan->is_connected(LW_NAME(changed), callable_mp(this, &BehaviorTree::_plan_changed))) {
|
||||
blackboard_plan->disconnect(LW_NAME(changed), callable_mp(this, &BehaviorTree::_plan_changed));
|
||||
}
|
||||
|
||||
blackboard_plan = p_plan;
|
||||
if (blackboard_plan.is_null()) {
|
||||
blackboard_plan = Ref<BlackboardPlan>(memnew(BlackboardPlan));
|
||||
}
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
blackboard_plan->connect(LW_NAME(changed), callable_mp(this, &BehaviorTree::_plan_changed));
|
||||
}
|
||||
|
||||
_plan_changed();
|
||||
}
|
||||
|
||||
void BehaviorTree::set_root_task(const Ref<BTTask> &p_value) {
|
||||
#ifdef TOOLS_ENABLED
|
||||
_unset_editor_behavior_tree_hint();
|
||||
#endif // TOOLS_ENABLED
|
||||
root_task = p_value;
|
||||
#ifdef TOOLS_ENABLED
|
||||
_set_editor_behavior_tree_hint();
|
||||
#endif // TOOLS_ENABLED
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
Ref<BehaviorTree> BehaviorTree::clone() const {
|
||||
Ref<BehaviorTree> copy = duplicate(false);
|
||||
|
@ -26,22 +71,69 @@ Ref<BehaviorTree> BehaviorTree::clone() const {
|
|||
return copy;
|
||||
}
|
||||
|
||||
Ref<BTTask> BehaviorTree::instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard) const {
|
||||
ERR_FAIL_COND_V_MSG(root_task == nullptr, memnew(BTTask), "Trying to instance a behavior tree with no valid root task.");
|
||||
Ref<BTTask> inst = root_task->clone();
|
||||
inst->initialize(p_agent, p_blackboard);
|
||||
return inst;
|
||||
void BehaviorTree::copy_other(const Ref<BehaviorTree> &p_other) {
|
||||
ERR_FAIL_COND(p_other.is_null());
|
||||
description = p_other->get_description();
|
||||
root_task = p_other->get_root_task();
|
||||
}
|
||||
|
||||
Ref<BTInstance> BehaviorTree::instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_instance_owner, Node *p_custom_scene_root) const {
|
||||
ERR_FAIL_COND_V_MSG(root_task.is_null(), nullptr, "BehaviorTree: Instantiation failed - BT has no valid root task.");
|
||||
ERR_FAIL_NULL_V_MSG(p_agent, nullptr, "BehaviorTree: Instantiation failed - agent can't be null.");
|
||||
ERR_FAIL_NULL_V_MSG(p_instance_owner, nullptr, "BehaviorTree: Instantiation failed -- instance owner can't be null.");
|
||||
ERR_FAIL_COND_V_MSG(p_blackboard.is_null(), nullptr, "BehaviorTree: Instantiation failed - blackboard can't be null.");
|
||||
Node *scene_root = p_custom_scene_root ? p_custom_scene_root : p_instance_owner->get_owner();
|
||||
ERR_FAIL_NULL_V_MSG(scene_root, nullptr, "BehaviorTree: Instantiation failed - unable to establish scene root. This is likely due to the instance owner not being owned by a scene node and custom_scene_root being null.");
|
||||
Ref<BTTask> root_copy = root_task->clone();
|
||||
root_copy->initialize(p_agent, p_blackboard, scene_root);
|
||||
return BTInstance::create(root_copy, get_path(), p_instance_owner);
|
||||
}
|
||||
|
||||
void BehaviorTree::_plan_changed() {
|
||||
emit_signal(LW_NAME(plan_changed));
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
void BehaviorTree::_set_editor_behavior_tree_hint() {
|
||||
if (root_task.is_valid()) {
|
||||
root_task->data.behavior_tree_id = this->get_instance_id();
|
||||
}
|
||||
}
|
||||
|
||||
void BehaviorTree::_unset_editor_behavior_tree_hint() {
|
||||
if (root_task.is_valid()) {
|
||||
root_task->data.behavior_tree_id = ObjectID();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
void BehaviorTree::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_description", "p_value"), &BehaviorTree::set_description);
|
||||
ClassDB::bind_method(D_METHOD("set_description", "description"), &BehaviorTree::set_description);
|
||||
ClassDB::bind_method(D_METHOD("get_description"), &BehaviorTree::get_description);
|
||||
ClassDB::bind_method(D_METHOD("set_root_task", "p_value"), &BehaviorTree::set_root_task);
|
||||
ClassDB::bind_method(D_METHOD("set_blackboard_plan", "plan"), &BehaviorTree::set_blackboard_plan);
|
||||
ClassDB::bind_method(D_METHOD("get_blackboard_plan"), &BehaviorTree::get_blackboard_plan);
|
||||
ClassDB::bind_method(D_METHOD("set_root_task", "task"), &BehaviorTree::set_root_task);
|
||||
ClassDB::bind_method(D_METHOD("get_root_task"), &BehaviorTree::get_root_task);
|
||||
// ClassDB::bind_method(D_METHOD("init"), &BehaviorTree::init);
|
||||
ClassDB::bind_method(D_METHOD("clone"), &BehaviorTree::clone);
|
||||
ClassDB::bind_method(D_METHOD("instantiate", "p_agent", "p_blackboard"), &BehaviorTree::instantiate);
|
||||
ClassDB::bind_method(D_METHOD("copy_other", "other"), &BehaviorTree::copy_other);
|
||||
ClassDB::bind_method(D_METHOD("instantiate", "agent", "blackboard", "instance_owner", "custom_scene_root"), &BehaviorTree::instantiate, DEFVAL(Variant()));
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "description", PROPERTY_HINT_MULTILINE_TEXT), "set_description", "get_description");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard_plan", PROPERTY_HINT_RESOURCE_TYPE, "BlackboardPlan", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_blackboard_plan", "get_blackboard_plan");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root_task", PROPERTY_HINT_RESOURCE_TYPE, "BTTask", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_root_task", "get_root_task");
|
||||
}
|
||||
|
||||
ADD_SIGNAL(MethodInfo("plan_changed"));
|
||||
}
|
||||
|
||||
BehaviorTree::BehaviorTree() {
|
||||
}
|
||||
|
||||
BehaviorTree::~BehaviorTree() {
|
||||
if (Engine::get_singleton()->is_editor_hint() && blackboard_plan.is_valid() &&
|
||||
blackboard_plan->is_connected(LW_NAME(changed), callable_mp(this, &BehaviorTree::_plan_changed))) {
|
||||
blackboard_plan->disconnect(LW_NAME(changed), callable_mp(this, &BehaviorTree::_plan_changed));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* behavior_tree.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -12,41 +12,61 @@
|
|||
#ifndef BEHAVIOR_TREE_H
|
||||
#define BEHAVIOR_TREE_H
|
||||
|
||||
#include "bt_task.h"
|
||||
|
||||
#include "modules/limboai/blackboard/blackboard.h"
|
||||
#include "../blackboard/blackboard_plan.h"
|
||||
#include "bt_instance.h"
|
||||
#include "tasks/bt_task.h"
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "core/io/resource.h"
|
||||
#include "core/object/object.h"
|
||||
#endif // LIMBOAI_MODULE
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include <godot_cpp/classes/resource.hpp>
|
||||
using namespace godot;
|
||||
#endif // LIMBOAI_GDEXTENSION
|
||||
|
||||
class BehaviorTree : public Resource {
|
||||
GDCLASS(BehaviorTree, Resource);
|
||||
|
||||
private:
|
||||
String description;
|
||||
Ref<BlackboardPlan> blackboard_plan;
|
||||
Ref<BTTask> root_task;
|
||||
|
||||
void _plan_changed();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
void _set_editor_behavior_tree_hint();
|
||||
void _unset_editor_behavior_tree_hint();
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual bool editor_can_reload_from_file() override { return false; }
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
String _to_string() const { return "<" + get_class() + "#" + itos(get_instance_id()) + ">"; }
|
||||
#endif
|
||||
|
||||
void set_description(String p_value) {
|
||||
description = p_value;
|
||||
emit_changed();
|
||||
}
|
||||
public:
|
||||
#ifdef LIMBOAI_MODULE
|
||||
virtual bool editor_can_reload_from_file() override { return false; }
|
||||
#endif
|
||||
|
||||
void set_description(const String &p_value);
|
||||
String get_description() const { return description; }
|
||||
|
||||
void set_root_task(const Ref<BTTask> &p_value) {
|
||||
root_task = p_value;
|
||||
emit_changed();
|
||||
}
|
||||
void set_blackboard_plan(const Ref<BlackboardPlan> &p_plan);
|
||||
Ref<BlackboardPlan> get_blackboard_plan() const { return blackboard_plan; }
|
||||
|
||||
void set_root_task(const Ref<BTTask> &p_value);
|
||||
Ref<BTTask> get_root_task() const { return root_task; }
|
||||
|
||||
// void init();
|
||||
Ref<BehaviorTree> clone() const;
|
||||
Ref<BTTask> instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard) const;
|
||||
void copy_other(const Ref<BehaviorTree> &p_other);
|
||||
Ref<BTInstance> instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_instance_owner, Node *p_custom_scene_root = nullptr) const;
|
||||
|
||||
BehaviorTree();
|
||||
~BehaviorTree();
|
||||
};
|
||||
|
||||
#endif // BEHAVIOR_TREE_H
|
||||
#endif // BEHAVIOR_TREE_H
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
/**
|
||||
* bt_instance.cpp
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "bt_instance.h"
|
||||
|
||||
#include "../editor/debugger/limbo_debugger.h"
|
||||
#include "behavior_tree.h"
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "core/os/time.h"
|
||||
#include "main/performance.h"
|
||||
#endif
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include <godot_cpp/classes/performance.hpp>
|
||||
#include <godot_cpp/classes/time.hpp>
|
||||
#endif
|
||||
|
||||
Ref<BTInstance> BTInstance::create(Ref<BTTask> p_root_task, String p_source_bt_path, Node *p_owner_node) {
|
||||
ERR_FAIL_COND_V(p_root_task.is_null(), nullptr);
|
||||
ERR_FAIL_NULL_V(p_owner_node, nullptr);
|
||||
Ref<BTInstance> inst;
|
||||
inst.instantiate();
|
||||
inst->root_task = p_root_task;
|
||||
inst->owner_node_id = p_owner_node->get_instance_id();
|
||||
inst->source_bt_path = p_source_bt_path;
|
||||
return inst;
|
||||
}
|
||||
|
||||
BT::Status BTInstance::update(double p_delta) {
|
||||
ERR_FAIL_COND_V(!root_task.is_valid(), BT::FRESH);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
double start = Time::get_singleton()->get_ticks_usec();
|
||||
#endif
|
||||
|
||||
const Ref<BTInstance> keep_alive{ this }; // keep instance alive until update is finished
|
||||
last_status = root_task->execute(p_delta);
|
||||
emit_signal(LW_NAME(updated), last_status);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
double end = Time::get_singleton()->get_ticks_usec();
|
||||
update_time_acc += (end - start);
|
||||
update_time_n += 1.0;
|
||||
#endif
|
||||
return last_status;
|
||||
}
|
||||
|
||||
void BTInstance::set_monitor_performance(bool p_monitor) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
monitor_performance = p_monitor;
|
||||
if (monitor_performance) {
|
||||
_add_custom_monitor();
|
||||
} else {
|
||||
_remove_custom_monitor();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool BTInstance::get_monitor_performance() const {
|
||||
#ifdef DEBUG_ENABLED
|
||||
return monitor_performance;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BTInstance::register_with_debugger() {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (LimboDebugger::get_singleton()->is_active()) {
|
||||
LimboDebugger::get_singleton()->register_bt_instance(get_instance_id());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BTInstance::unregister_with_debugger() {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (LimboDebugger::get_singleton() && LimboDebugger::get_singleton()->is_active()) {
|
||||
LimboDebugger::get_singleton()->unregister_bt_instance(get_instance_id());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
||||
double BTInstance::_get_mean_update_time_msec_and_reset() {
|
||||
if (update_time_n) {
|
||||
double mean_time_msec = (update_time_acc * 0.001) / update_time_n;
|
||||
update_time_acc = 0.0;
|
||||
update_time_n = 0.0;
|
||||
return mean_time_msec;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void BTInstance::_add_custom_monitor() {
|
||||
ERR_FAIL_NULL(get_owner_node());
|
||||
ERR_FAIL_COND(root_task.is_null());
|
||||
ERR_FAIL_NULL(root_task->get_agent());
|
||||
|
||||
if (monitor_id == StringName()) {
|
||||
monitor_id = vformat("LimboAI/update_ms|%s_%s_%s", root_task->get_agent()->get_name(), get_owner_node()->get_name(),
|
||||
String(itos(get_instance_id())).md5_text().substr(0, 4));
|
||||
}
|
||||
if (!Performance::get_singleton()->has_custom_monitor(monitor_id)) {
|
||||
PERFORMANCE_ADD_CUSTOM_MONITOR(monitor_id, callable_mp(this, &BTInstance::_get_mean_update_time_msec_and_reset));
|
||||
}
|
||||
}
|
||||
|
||||
void BTInstance::_remove_custom_monitor() {
|
||||
if (monitor_id != StringName() && Performance::get_singleton()->has_custom_monitor(monitor_id)) {
|
||||
Performance::get_singleton()->remove_custom_monitor(monitor_id);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // * DEBUG_ENABLED
|
||||
|
||||
void BTInstance::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_root_task"), &BTInstance::get_root_task);
|
||||
ClassDB::bind_method(D_METHOD("get_owner_node"), &BTInstance::get_owner_node);
|
||||
ClassDB::bind_method(D_METHOD("get_last_status"), &BTInstance::get_last_status);
|
||||
ClassDB::bind_method(D_METHOD("get_source_bt_path"), &BTInstance::get_source_bt_path);
|
||||
ClassDB::bind_method(D_METHOD("get_agent"), &BTInstance::get_agent);
|
||||
ClassDB::bind_method(D_METHOD("get_blackboard"), &BTInstance::get_blackboard);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("is_instance_valid"), &BTInstance::is_instance_valid);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_monitor_performance", "monitor"), &BTInstance::set_monitor_performance);
|
||||
ClassDB::bind_method(D_METHOD("get_monitor_performance"), &BTInstance::get_monitor_performance);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("update", "delta"), &BTInstance::update);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("register_with_debugger"), &BTInstance::register_with_debugger);
|
||||
ClassDB::bind_method(D_METHOD("unregister_with_debugger"), &BTInstance::unregister_with_debugger);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitor_performance"), "set_monitor_performance", "get_monitor_performance");
|
||||
|
||||
ADD_SIGNAL(MethodInfo("updated", PropertyInfo(Variant::INT, "status")));
|
||||
ADD_SIGNAL(MethodInfo("freed"));
|
||||
}
|
||||
|
||||
BTInstance::~BTInstance() {
|
||||
emit_signal(LW_NAME(freed));
|
||||
#ifdef DEBUG_ENABLED
|
||||
_remove_custom_monitor();
|
||||
unregister_with_debugger();
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* bt_instance.h
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
#ifndef BT_INSTANCE_H
|
||||
#define BT_INSTANCE_H
|
||||
|
||||
#include "tasks/bt_task.h"
|
||||
|
||||
class BTInstance : public RefCounted {
|
||||
GDCLASS(BTInstance, RefCounted);
|
||||
|
||||
private:
|
||||
Ref<BTTask> root_task;
|
||||
uint64_t owner_node_id = 0;
|
||||
String source_bt_path;
|
||||
BT::Status last_status = BT::FRESH;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
bool monitor_performance = false;
|
||||
StringName monitor_id;
|
||||
double update_time_acc = 0.0;
|
||||
double update_time_n = 0.0;
|
||||
|
||||
double _get_mean_update_time_msec_and_reset();
|
||||
void _add_custom_monitor();
|
||||
void _remove_custom_monitor();
|
||||
|
||||
#endif // * DEBUG_ENABLED
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
String _to_string() const { return "<" + get_class() + "#" + itos(get_instance_id()) + ">"; }
|
||||
#endif
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ Ref<BTTask> get_root_task() const { return root_task; }
|
||||
_FORCE_INLINE_ Node *get_owner_node() const { return owner_node_id ? Object::cast_to<Node>(OBJECT_DB_GET_INSTANCE(owner_node_id)) : nullptr; }
|
||||
_FORCE_INLINE_ BT::Status get_last_status() const { return last_status; }
|
||||
_FORCE_INLINE_ String get_source_bt_path() const { return source_bt_path; }
|
||||
_FORCE_INLINE_ Node *get_agent() const { return root_task.is_valid() ? root_task->get_agent() : nullptr; }
|
||||
_FORCE_INLINE_ Ref<Blackboard> get_blackboard() const { return root_task.is_valid() ? root_task->get_blackboard() : Ref<Blackboard>(); }
|
||||
|
||||
_FORCE_INLINE_ bool is_instance_valid() const { return root_task.is_valid(); }
|
||||
|
||||
BT::Status update(double p_delta);
|
||||
|
||||
void set_monitor_performance(bool p_monitor);
|
||||
bool get_monitor_performance() const;
|
||||
|
||||
void register_with_debugger();
|
||||
void unregister_with_debugger();
|
||||
|
||||
static Ref<BTInstance> create(Ref<BTTask> p_root_task, String p_source_bt_path, Node *p_owner_node);
|
||||
|
||||
BTInstance() = default;
|
||||
~BTInstance();
|
||||
};
|
||||
|
||||
#endif // BT_INSTANCE_H
|
268
bt/bt_player.cpp
268
bt/bt_player.cpp
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bt_player.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -11,48 +11,135 @@
|
|||
|
||||
#include "bt_player.h"
|
||||
|
||||
#include "bt_task.h"
|
||||
#include "modules/limboai/blackboard/blackboard.h"
|
||||
#include "modules/limboai/editor/debugger/limbo_debugger.h"
|
||||
#include "modules/limboai/util/limbo_string_names.h"
|
||||
#include "../util/limbo_compat.h"
|
||||
#include "../util/limbo_string_names.h"
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "core/config/engine.h"
|
||||
#include "core/debugger/engine_debugger.h"
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/object/object.h"
|
||||
#include "core/os/memory.h"
|
||||
#include "core/string/string_name.h"
|
||||
#include "core/variant/variant.h"
|
||||
#include "main/performance.h"
|
||||
|
||||
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::is_active())
|
||||
#define GET_TICKS_USEC() (OS::get_singleton()->get_ticks_usec())
|
||||
|
||||
#endif // ! LIMBOAI_MODULE
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include <godot_cpp/classes/engine_debugger.hpp>
|
||||
#include <godot_cpp/classes/performance.hpp>
|
||||
#include <godot_cpp/classes/time.hpp>
|
||||
|
||||
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::get_singleton()->is_active())
|
||||
#define GET_TICKS_USEC() (Time::get_singleton()->get_ticks_usec())
|
||||
|
||||
#endif // ! LIMBOAI_GDEXTENSION
|
||||
|
||||
VARIANT_ENUM_CAST(BTPlayer::UpdateMode);
|
||||
|
||||
void BTPlayer::_load_tree() {
|
||||
void BTPlayer::_instantiate_bt() {
|
||||
bt_instance.unref();
|
||||
ERR_FAIL_COND_MSG(!behavior_tree.is_valid(), "BTPlayer: Initialization failed - needs a valid behavior tree.");
|
||||
ERR_FAIL_COND_MSG(!behavior_tree->get_root_task().is_valid(), "BTPlayer: Initialization failed - behavior tree has no valid root task.");
|
||||
Node *agent = GET_NODE(this, agent_node);
|
||||
ERR_FAIL_NULL_MSG(agent, vformat("BTPlayer: Initialization failed - can't get agent with path '%s'.", agent_node));
|
||||
Node *scene_root = _get_scene_root();
|
||||
ERR_FAIL_COND_MSG(scene_root == nullptr,
|
||||
"BTPlayer: Initialization failed - unable to establish scene root. This is likely due to BTPlayer not being owned by a scene node. Check BTPlayer.set_scene_root_hint().");
|
||||
bt_instance = behavior_tree->instantiate(agent, blackboard, this, scene_root);
|
||||
ERR_FAIL_COND_MSG(bt_instance.is_null(), "BTPlayer: Failed to instantiate behavior tree.");
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (tree_instance.is_valid()) {
|
||||
LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path());
|
||||
bt_instance->set_monitor_performance(monitor_performance);
|
||||
bt_instance->register_with_debugger();
|
||||
#endif // DEBUG_ENABLED
|
||||
}
|
||||
|
||||
void BTPlayer::_update_blackboard_plan() {
|
||||
if (blackboard_plan.is_null()) {
|
||||
blackboard_plan = Ref<BlackboardPlan>(memnew(BlackboardPlan));
|
||||
} else if (!RESOURCE_IS_BUILT_IN(blackboard_plan)) {
|
||||
WARN_PRINT_ED("BTPlayer: Using external resource for derived blackboard plan is not supported. Converted to built-in resource.");
|
||||
blackboard_plan = blackboard_plan->duplicate();
|
||||
}
|
||||
#endif
|
||||
tree_instance.unref();
|
||||
ERR_FAIL_COND_MSG(!behavior_tree.is_valid(), "BTPlayer: Needs a valid behavior tree.");
|
||||
ERR_FAIL_COND_MSG(!behavior_tree->get_root_task().is_valid(), "BTPlayer: Behavior tree has no valid root task.");
|
||||
if (prefetch_nodepath_vars == true) {
|
||||
blackboard->prefetch_nodepath_vars(this);
|
||||
|
||||
blackboard_plan->set_base_plan(behavior_tree.is_valid() ? behavior_tree->get_blackboard_plan() : nullptr);
|
||||
}
|
||||
|
||||
void BTPlayer::_initialize() {
|
||||
if (blackboard.is_null()) {
|
||||
blackboard = Ref<Blackboard>(memnew(Blackboard));
|
||||
}
|
||||
tree_instance = behavior_tree->instantiate(get_owner(), blackboard);
|
||||
if (blackboard_plan.is_valid()) {
|
||||
// Don't overwrite existing blackboard values as they may be initialized from code.
|
||||
blackboard_plan->populate_blackboard(blackboard, false, this, _get_scene_root());
|
||||
}
|
||||
if (behavior_tree.is_valid()) {
|
||||
_instantiate_bt();
|
||||
}
|
||||
}
|
||||
|
||||
void BTPlayer::set_bt_instance(const Ref<BTInstance> &p_bt_instance) {
|
||||
ERR_FAIL_COND_MSG(p_bt_instance.is_null(), "BTPlayer: Failed to set behavior tree instance - instance is null.");
|
||||
ERR_FAIL_COND_MSG(!p_bt_instance->is_instance_valid(), "BTPlayer: Failed to set behavior tree instance - instance is not valid.");
|
||||
|
||||
bt_instance = p_bt_instance;
|
||||
blackboard = p_bt_instance->get_blackboard();
|
||||
agent_node = p_bt_instance->get_agent()->get_path();
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
|
||||
#endif
|
||||
bt_instance->set_monitor_performance(monitor_performance);
|
||||
bt_instance->register_with_debugger();
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
blackboard_plan.unref();
|
||||
behavior_tree.unref();
|
||||
}
|
||||
|
||||
void BTPlayer::set_scene_root_hint(Node *p_scene_root) {
|
||||
ERR_FAIL_NULL_MSG(p_scene_root, "BTPlayer: Failed to set scene root hint - scene root is null.");
|
||||
if (bt_instance.is_valid()) {
|
||||
ERR_PRINT("BTPlayer: Scene root hint shouldn't be set after the behavior tree is instantiated. This change will not affect the current behavior tree instance.");
|
||||
}
|
||||
|
||||
scene_root_hint = p_scene_root;
|
||||
}
|
||||
|
||||
void BTPlayer::set_behavior_tree(const Ref<BehaviorTree> &p_tree) {
|
||||
behavior_tree = p_tree;
|
||||
if (Engine::get_singleton()->is_editor_hint() == false && get_owner()) {
|
||||
_load_tree();
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(plan_changed), callable_mp(this, &BTPlayer::_update_blackboard_plan))) {
|
||||
behavior_tree->disconnect(LW_NAME(plan_changed), callable_mp(this, &BTPlayer::_update_blackboard_plan));
|
||||
}
|
||||
if (p_tree.is_valid()) {
|
||||
p_tree->connect(LW_NAME(plan_changed), callable_mp(this, &BTPlayer::_update_blackboard_plan));
|
||||
}
|
||||
behavior_tree = p_tree;
|
||||
_update_blackboard_plan();
|
||||
} else {
|
||||
behavior_tree = p_tree;
|
||||
if (get_owner() && is_inside_tree()) {
|
||||
_update_blackboard_plan();
|
||||
_initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BTPlayer::set_agent_node(const NodePath &p_agent_node) {
|
||||
agent_node = p_agent_node;
|
||||
if (bt_instance.is_valid()) {
|
||||
ERR_PRINT("BTPlayer: Agent node cannot be set after the behavior tree is instantiated. This change will not affect the behavior tree instance.");
|
||||
}
|
||||
}
|
||||
|
||||
void BTPlayer::set_blackboard_plan(const Ref<BlackboardPlan> &p_plan) {
|
||||
blackboard_plan = p_plan;
|
||||
_update_blackboard_plan();
|
||||
}
|
||||
|
||||
void BTPlayer::set_update_mode(UpdateMode p_mode) {
|
||||
update_mode = p_mode;
|
||||
set_active(active);
|
||||
|
@ -67,70 +154,38 @@ void BTPlayer::set_active(bool p_active) {
|
|||
}
|
||||
|
||||
void BTPlayer::update(double p_delta) {
|
||||
if (!tree_instance.is_valid()) {
|
||||
if (!bt_instance.is_valid()) {
|
||||
ERR_PRINT_ONCE(vformat("BTPlayer doesn't have a behavior tree with a valid root task to execute (owner: %s)", get_owner()));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
double start = OS::get_singleton()->get_ticks_usec();
|
||||
#endif
|
||||
|
||||
if (active) {
|
||||
last_status = tree_instance->execute(p_delta);
|
||||
emit_signal(LimboStringNames::get_singleton()->updated, last_status);
|
||||
if (last_status == BTTask::SUCCESS || last_status == BTTask::FAILURE) {
|
||||
emit_signal(LimboStringNames::get_singleton()->behavior_tree_finished, last_status);
|
||||
BT::Status status = bt_instance->update(p_delta);
|
||||
emit_signal(LW_NAME(updated), status);
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
if (status == BTTask::SUCCESS || status == BTTask::FAILURE) {
|
||||
emit_signal(LW_NAME(behavior_tree_finished), status);
|
||||
}
|
||||
#endif // DISABLE_DEPRECATED
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
double end = OS::get_singleton()->get_ticks_usec();
|
||||
update_time_acc += (end - start);
|
||||
update_time_n += 1.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BTPlayer::restart() {
|
||||
tree_instance->cancel();
|
||||
ERR_FAIL_COND_MSG(bt_instance.is_null(), "BTPlayer: Restart failed - no valid tree instance. Make sure the BTPlayer has a valid behavior tree with a valid root task.");
|
||||
bt_instance->get_root_task()->abort();
|
||||
set_active(true);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
||||
void BTPlayer::_set_monitor_performance(bool p_monitor_performance) {
|
||||
void BTPlayer::set_monitor_performance(bool p_monitor_performance) {
|
||||
monitor_performance = p_monitor_performance;
|
||||
|
||||
if (!get_owner()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Performance *perf = Performance::get_singleton();
|
||||
if (monitor_performance) {
|
||||
if (monitor_id == StringName()) {
|
||||
monitor_id = vformat("limboai/update_ms|%s_%s_%s", get_owner()->get_name(), get_name(),
|
||||
String(itos(get_instance_id())).md5_text().substr(0, 4));
|
||||
}
|
||||
if (!perf->has_custom_monitor(monitor_id)) {
|
||||
perf->add_custom_monitor(monitor_id, callable_mp(this, &BTPlayer::_get_mean_update_time_msec), Vector<Variant>());
|
||||
}
|
||||
} else if (monitor_id != StringName() && perf->has_custom_monitor(monitor_id)) {
|
||||
perf->remove_custom_monitor(monitor_id);
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (bt_instance.is_valid()) {
|
||||
bt_instance->set_monitor_performance(monitor_performance);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
double BTPlayer::_get_mean_update_time_msec() {
|
||||
if (update_time_n) {
|
||||
double mean_time_msec = (update_time_acc * 0.001) / update_time_n;
|
||||
update_time_acc = 0.0;
|
||||
update_time_n = 0.0;
|
||||
return mean_time_msec;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
void BTPlayer::_notification(int p_notification) {
|
||||
switch (p_notification) {
|
||||
case NOTIFICATION_PROCESS: {
|
||||
|
@ -143,68 +198,85 @@ void BTPlayer::_notification(int p_notification) {
|
|||
} break;
|
||||
case NOTIFICATION_READY: {
|
||||
if (!Engine::get_singleton()->is_editor_hint()) {
|
||||
if (behavior_tree.is_valid()) {
|
||||
_load_tree();
|
||||
}
|
||||
set_active(active);
|
||||
#ifdef DEBUG_ENABLED
|
||||
_set_monitor_performance(monitor_performance);
|
||||
#endif
|
||||
_initialize();
|
||||
} else {
|
||||
_update_blackboard_plan();
|
||||
}
|
||||
set_active(active);
|
||||
} break;
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (bt_instance.is_valid()) {
|
||||
bt_instance->set_monitor_performance(monitor_performance);
|
||||
bt_instance->register_with_debugger();
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
if (tree_instance.is_valid()) {
|
||||
LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path());
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (bt_instance.is_valid()) {
|
||||
bt_instance->set_monitor_performance(false);
|
||||
bt_instance->unregister_with_debugger();
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(plan_changed), callable_mp(this, &BTPlayer::_update_blackboard_plan))) {
|
||||
behavior_tree->disconnect(LW_NAME(plan_changed), callable_mp(this, &BTPlayer::_update_blackboard_plan));
|
||||
}
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void BTPlayer::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_behavior_tree", "p_path"), &BTPlayer::set_behavior_tree);
|
||||
ClassDB::bind_method(D_METHOD("set_behavior_tree", "behavior_tree"), &BTPlayer::set_behavior_tree);
|
||||
ClassDB::bind_method(D_METHOD("get_behavior_tree"), &BTPlayer::get_behavior_tree);
|
||||
ClassDB::bind_method(D_METHOD("set_update_mode", "p_mode"), &BTPlayer::set_update_mode);
|
||||
ClassDB::bind_method(D_METHOD("set_agent_node", "agent_node"), &BTPlayer::set_agent_node);
|
||||
ClassDB::bind_method(D_METHOD("get_agent_node"), &BTPlayer::get_agent_node);
|
||||
ClassDB::bind_method(D_METHOD("set_update_mode", "update_mode"), &BTPlayer::set_update_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_update_mode"), &BTPlayer::get_update_mode);
|
||||
ClassDB::bind_method(D_METHOD("set_active", "p_active"), &BTPlayer::set_active);
|
||||
ClassDB::bind_method(D_METHOD("set_active", "active"), &BTPlayer::set_active);
|
||||
ClassDB::bind_method(D_METHOD("get_active"), &BTPlayer::get_active);
|
||||
ClassDB::bind_method(D_METHOD("set_blackboard", "p_blackboard"), &BTPlayer::set_blackboard);
|
||||
ClassDB::bind_method(D_METHOD("set_blackboard", "blackboard"), &BTPlayer::set_blackboard);
|
||||
ClassDB::bind_method(D_METHOD("get_blackboard"), &BTPlayer::get_blackboard);
|
||||
ClassDB::bind_method(D_METHOD("set_prefetch_nodepath_vars", "p_value"), &BTPlayer::set_prefetch_nodepath_vars);
|
||||
ClassDB::bind_method(D_METHOD("get_prefetch_nodepath_vars"), &BTPlayer::get_prefetch_nodepath_vars);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_set_blackboard_data", "p_blackboard"), &BTPlayer::_set_blackboard_data);
|
||||
ClassDB::bind_method(D_METHOD("_get_blackboard_data"), &BTPlayer::_get_blackboard_data);
|
||||
ClassDB::bind_method(D_METHOD("set_blackboard_plan", "plan"), &BTPlayer::set_blackboard_plan);
|
||||
ClassDB::bind_method(D_METHOD("get_blackboard_plan"), &BTPlayer::get_blackboard_plan);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("update", "p_delta"), &BTPlayer::update);
|
||||
ClassDB::bind_method(D_METHOD("set_monitor_performance", "enable"), &BTPlayer::set_monitor_performance);
|
||||
ClassDB::bind_method(D_METHOD("get_monitor_performance"), &BTPlayer::get_monitor_performance);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("update", "delta"), &BTPlayer::update);
|
||||
ClassDB::bind_method(D_METHOD("restart"), &BTPlayer::restart);
|
||||
ClassDB::bind_method(D_METHOD("get_last_status"), &BTPlayer::get_last_status);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_bt_instance"), &BTPlayer::get_bt_instance);
|
||||
ClassDB::bind_method(D_METHOD("set_bt_instance", "bt_instance"), &BTPlayer::set_bt_instance);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_scene_root_hint", "scene_root"), &BTPlayer::set_scene_root_hint);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "behavior_tree", PROPERTY_HINT_RESOURCE_TYPE, "BehaviorTree"), "set_behavior_tree", "get_behavior_tree");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "agent_node"), "set_agent_node", "get_agent_node");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Idle,Physics,Manual"), "set_update_mode", "get_update_mode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "get_active");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_NONE, "Blackboard", 0), "", "get_blackboard");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_blackboard_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_blackboard_data", "_get_blackboard_data");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefetch_nodepath_vars"), "set_prefetch_nodepath_vars", "get_prefetch_nodepath_vars");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_NONE, "Blackboard", 0), "set_blackboard", "get_blackboard");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard_plan", PROPERTY_HINT_RESOURCE_TYPE, "BlackboardPlan", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT | PROPERTY_USAGE_ALWAYS_DUPLICATE), "set_blackboard_plan", "get_blackboard_plan");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitor_performance"), "set_monitor_performance", "get_monitor_performance");
|
||||
|
||||
BIND_ENUM_CONSTANT(IDLE);
|
||||
BIND_ENUM_CONSTANT(PHYSICS);
|
||||
BIND_ENUM_CONSTANT(MANUAL);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("behavior_tree_finished", PropertyInfo(Variant::INT, "p_status")));
|
||||
ADD_SIGNAL(MethodInfo("updated", PropertyInfo(Variant::INT, "p_status")));
|
||||
ADD_SIGNAL(MethodInfo("updated", PropertyInfo(Variant::INT, "status")));
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
ClassDB::bind_method(D_METHOD("_set_monitor_performance"), &BTPlayer::_set_monitor_performance);
|
||||
ClassDB::bind_method(D_METHOD("_get_monitor_performance"), &BTPlayer::_get_monitor_performance);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitor_performance"), "_set_monitor_performance", "_get_monitor_performance");
|
||||
ADD_PROPERTY_DEFAULT("monitor_performance", false);
|
||||
#endif // DEBUG_ENABLED
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
ADD_SIGNAL(MethodInfo("behavior_tree_finished", PropertyInfo(Variant::INT, "status")));
|
||||
#endif
|
||||
}
|
||||
|
||||
BTPlayer::BTPlayer() {
|
||||
blackboard = Ref<Blackboard>(memnew(Blackboard));
|
||||
agent_node = LW_NAME(node_pp);
|
||||
}
|
||||
|
||||
BTPlayer::~BTPlayer() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bt_player.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -12,12 +12,19 @@
|
|||
#ifndef BT_PLAYER_H
|
||||
#define BT_PLAYER_H
|
||||
|
||||
#include "../blackboard/blackboard.h"
|
||||
#include "../blackboard/blackboard_plan.h"
|
||||
#include "behavior_tree.h"
|
||||
#include "bt_task.h"
|
||||
#include "modules/limboai/blackboard/blackboard.h"
|
||||
#include "bt_instance.h"
|
||||
#include "tasks/bt_task.h"
|
||||
|
||||
#include "core/object/object.h"
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "scene/main/node.h"
|
||||
#endif
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include <godot_cpp/classes/node.hpp>
|
||||
#endif
|
||||
|
||||
class BTPlayer : public Node {
|
||||
GDCLASS(BTPlayer, Node);
|
||||
|
@ -25,34 +32,46 @@ class BTPlayer : public Node {
|
|||
public:
|
||||
enum UpdateMode : unsigned int {
|
||||
IDLE, // automatically call update() during NOTIFICATION_PROCESS
|
||||
PHYSICS, //# automatically call update() during NOTIFICATION_PHYSICS
|
||||
PHYSICS, // automatically call update() during NOTIFICATION_PHYSICS
|
||||
MANUAL, // manually update state machine, user must call update(delta)
|
||||
};
|
||||
|
||||
private:
|
||||
Ref<BehaviorTree> behavior_tree;
|
||||
NodePath agent_node;
|
||||
Ref<BlackboardPlan> blackboard_plan;
|
||||
UpdateMode update_mode = UpdateMode::PHYSICS;
|
||||
bool active = true;
|
||||
Ref<Blackboard> blackboard;
|
||||
bool prefetch_nodepath_vars = true;
|
||||
int last_status = -1;
|
||||
Node *scene_root_hint = nullptr;
|
||||
bool monitor_performance = false;
|
||||
|
||||
Ref<BTTask> tree_instance;
|
||||
Ref<BTInstance> bt_instance;
|
||||
|
||||
void _load_tree();
|
||||
void _instantiate_bt();
|
||||
void _update_blackboard_plan();
|
||||
void _initialize();
|
||||
_FORCE_INLINE_ Node *_get_scene_root() const { return scene_root_hint ? scene_root_hint : get_owner(); }
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
void _set_blackboard_data(Dictionary p_value) { blackboard->set_data(p_value.duplicate()); }
|
||||
Dictionary _get_blackboard_data() const { return blackboard->get_data(); }
|
||||
|
||||
void _notification(int p_notification);
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
String _to_string() const { return String(get_name()) + ":<" + get_class() + "#" + itos(get_instance_id()) + ">"; }
|
||||
#endif
|
||||
|
||||
public:
|
||||
void set_behavior_tree(const Ref<BehaviorTree> &p_tree);
|
||||
Ref<BehaviorTree> get_behavior_tree() const { return behavior_tree; };
|
||||
|
||||
void set_agent_node(const NodePath &p_agent_node);
|
||||
NodePath get_agent_node() const { return agent_node; }
|
||||
|
||||
void set_blackboard_plan(const Ref<BlackboardPlan> &p_plan);
|
||||
Ref<BlackboardPlan> get_blackboard_plan() const { return blackboard_plan; }
|
||||
|
||||
void set_update_mode(UpdateMode p_mode);
|
||||
UpdateMode get_update_mode() const { return update_mode; }
|
||||
|
||||
|
@ -62,29 +81,19 @@ public:
|
|||
Ref<Blackboard> get_blackboard() const { return blackboard; }
|
||||
void set_blackboard(const Ref<Blackboard> &p_blackboard) { blackboard = p_blackboard; }
|
||||
|
||||
void set_prefetch_nodepath_vars(bool p_value) { prefetch_nodepath_vars = p_value; }
|
||||
bool get_prefetch_nodepath_vars() const { return prefetch_nodepath_vars; }
|
||||
void set_monitor_performance(bool p_monitor_performance);
|
||||
bool get_monitor_performance() const { return monitor_performance; }
|
||||
|
||||
void update(double p_delta);
|
||||
void restart();
|
||||
int get_last_status() const { return last_status; }
|
||||
|
||||
Ref<BTInstance> get_bt_instance() { return bt_instance; }
|
||||
void set_bt_instance(const Ref<BTInstance> &p_bt_instance);
|
||||
|
||||
void set_scene_root_hint(Node *p_scene_root);
|
||||
|
||||
BTPlayer();
|
||||
~BTPlayer();
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
// Performace monitoring.
|
||||
private:
|
||||
bool monitor_performance = false;
|
||||
StringName monitor_id;
|
||||
double update_time_acc = 0.0;
|
||||
double update_time_n = 0.0;
|
||||
|
||||
void _set_monitor_performance(bool p_monitor_performance);
|
||||
bool _get_monitor_performance() const { return monitor_performance; }
|
||||
double _get_mean_update_time_msec();
|
||||
|
||||
#endif // DEBUG_ENABLED
|
||||
};
|
||||
|
||||
#endif // BT_PLAYER_H
|
||||
#endif // BT_PLAYER_H
|
||||
|
|
143
bt/bt_state.cpp
143
bt/bt_state.cpp
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bt_state.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -11,68 +11,155 @@
|
|||
|
||||
#include "bt_state.h"
|
||||
|
||||
#include "modules/limboai/bt/bt_task.h"
|
||||
#include "modules/limboai/editor/debugger/limbo_debugger.h"
|
||||
#include "modules/limboai/hsm/limbo_state.h"
|
||||
#include "modules/limboai/util/limbo_string_names.h"
|
||||
#include "../util/limbo_compat.h"
|
||||
#include "../util/limbo_string_names.h"
|
||||
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/variant/variant.h"
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "core/debugger/engine_debugger.h"
|
||||
#endif // LIMBOAI_MODULE
|
||||
|
||||
void BTState::_setup() {
|
||||
ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned.");
|
||||
tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard());
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include <godot_cpp/classes/engine_debugger.hpp>
|
||||
#endif // LIMBOAI_GDEXTENSION
|
||||
|
||||
void BTState::set_behavior_tree(const Ref<BehaviorTree> &p_tree) {
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan))) {
|
||||
behavior_tree->disconnect(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan));
|
||||
}
|
||||
if (p_tree.is_valid()) {
|
||||
p_tree->connect(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan));
|
||||
}
|
||||
behavior_tree = p_tree;
|
||||
} else {
|
||||
behavior_tree = p_tree;
|
||||
}
|
||||
_update_blackboard_plan();
|
||||
}
|
||||
|
||||
void BTState::set_scene_root_hint(Node *p_scene_root) {
|
||||
ERR_FAIL_NULL_MSG(p_scene_root, "BTState: Failed to set scene root hint - scene root is null.");
|
||||
ERR_FAIL_COND_MSG(bt_instance.is_valid(), "BTState: Scene root hint shouldn't be set after initialization. This change will not affect the current behavior tree instance.");
|
||||
|
||||
scene_root_hint = p_scene_root;
|
||||
}
|
||||
|
||||
void BTState::set_monitor_performance(bool p_monitor) {
|
||||
monitor_performance = p_monitor;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
|
||||
if (bt_instance.is_valid()) {
|
||||
bt_instance->set_monitor_performance(monitor_performance);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BTState::_update_blackboard_plan() {
|
||||
if (get_blackboard_plan().is_null()) {
|
||||
set_blackboard_plan(memnew(BlackboardPlan));
|
||||
} else if (!RESOURCE_IS_BUILT_IN(get_blackboard_plan())) {
|
||||
WARN_PRINT_ED("BTState: Using external resource for derived blackboard plan is not supported. Converted to built-in resource.");
|
||||
set_blackboard_plan(get_blackboard_plan()->duplicate());
|
||||
} else {
|
||||
get_blackboard_plan()->set_base_plan(behavior_tree.is_valid() ? behavior_tree->get_blackboard_plan() : nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
Node *BTState::_get_prefetch_root_for_base_plan() {
|
||||
return _get_scene_root();
|
||||
}
|
||||
|
||||
void BTState::_setup() {
|
||||
LimboState::_setup();
|
||||
ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned.");
|
||||
Node *scene_root = _get_scene_root();
|
||||
ERR_FAIL_NULL_MSG(scene_root, "BTState: Initialization failed - unable to establish scene root. This is likely due to BTState not being owned by a scene node. Check BTState.set_scene_root_hint().");
|
||||
bt_instance = behavior_tree->instantiate(get_agent(), get_blackboard(), this, scene_root);
|
||||
ERR_FAIL_COND_MSG(bt_instance.is_null(), "BTState: Initialization failed - failed to instantiate behavior tree.");
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
bt_instance->register_with_debugger();
|
||||
bt_instance->set_monitor_performance(monitor_performance);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BTState::_exit() {
|
||||
ERR_FAIL_COND(tree_instance == nullptr);
|
||||
tree_instance->cancel();
|
||||
if (bt_instance.is_valid()) {
|
||||
bt_instance->get_root_task()->abort();
|
||||
} else {
|
||||
ERR_PRINT_ONCE("BTState: BehaviorTree is not assigned.");
|
||||
}
|
||||
LimboState::_exit();
|
||||
}
|
||||
|
||||
void BTState::_update(double p_delta) {
|
||||
ERR_FAIL_COND(tree_instance == nullptr);
|
||||
int status = tree_instance->execute(p_delta);
|
||||
emit_signal(LimboStringNames::get_singleton()->updated, p_delta);
|
||||
GDVIRTUAL_CALL(_update, p_delta);
|
||||
if (!is_active()) {
|
||||
// Bail out if a transition happened in the meantime.
|
||||
return;
|
||||
}
|
||||
ERR_FAIL_COND(bt_instance.is_null());
|
||||
BT::Status status = bt_instance->update(p_delta);
|
||||
if (status == BTTask::SUCCESS) {
|
||||
get_root()->dispatch(success_event, Variant());
|
||||
} else if (status == BTTask::FAILURE) {
|
||||
get_root()->dispatch(failure_event, Variant());
|
||||
}
|
||||
emit_signal(LW_NAME(updated), p_delta);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
void BTState::_notification(int p_notification) {
|
||||
switch (p_notification) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
if (bt_instance.is_valid()) {
|
||||
bt_instance->register_with_debugger();
|
||||
bt_instance->set_monitor_performance(monitor_performance);
|
||||
}
|
||||
} break;
|
||||
#endif // DEBUG_ENABLED
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
if (tree_instance.is_valid()) {
|
||||
LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path());
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (bt_instance.is_valid()) {
|
||||
bt_instance->unregister_with_debugger();
|
||||
bt_instance->set_monitor_performance(false);
|
||||
}
|
||||
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan))) {
|
||||
behavior_tree->disconnect(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan));
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
void BTState::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_behavior_tree", "p_value"), &BTState::set_behavior_tree);
|
||||
ClassDB::bind_method(D_METHOD("set_behavior_tree", "behavior_tree"), &BTState::set_behavior_tree);
|
||||
ClassDB::bind_method(D_METHOD("get_behavior_tree"), &BTState::get_behavior_tree);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_success_event", "p_event_name"), &BTState::set_success_event);
|
||||
ClassDB::bind_method(D_METHOD("get_bt_instance"), &BTState::get_bt_instance);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_success_event", "event"), &BTState::set_success_event);
|
||||
ClassDB::bind_method(D_METHOD("get_success_event"), &BTState::get_success_event);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_failure_event", "p_event_name"), &BTState::set_failure_event);
|
||||
ClassDB::bind_method(D_METHOD("set_failure_event", "event"), &BTState::set_failure_event);
|
||||
ClassDB::bind_method(D_METHOD("get_failure_event"), &BTState::get_failure_event);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_monitor_performance", "enable"), &BTState::set_monitor_performance);
|
||||
ClassDB::bind_method(D_METHOD("get_monitor_performance"), &BTState::get_monitor_performance);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_scene_root_hint", "scene_root"), &BTState::set_scene_root_hint);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "behavior_tree", PROPERTY_HINT_RESOURCE_TYPE, "BehaviorTree"), "set_behavior_tree", "get_behavior_tree");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "success_event"), "set_success_event", "get_success_event");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "failure_event"), "set_failure_event", "get_failure_event");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "success_event"), "set_success_event", "get_success_event");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "failure_event"), "set_failure_event", "get_failure_event");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitor_performance"), "set_monitor_performance", "get_monitor_performance");
|
||||
}
|
||||
|
||||
BTState::BTState() {
|
||||
success_event = "success";
|
||||
failure_event = "failure";
|
||||
success_event = LW_NAME(EVENT_SUCCESS);
|
||||
failure_event = LW_NAME(EVENT_FAILURE);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bt_state.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -12,46 +12,55 @@
|
|||
#ifndef BT_STATE_H
|
||||
#define BT_STATE_H
|
||||
|
||||
#include "modules/limboai/bt/behavior_tree.h"
|
||||
#include "modules/limboai/bt/bt_task.h"
|
||||
#include "modules/limboai/hsm/limbo_state.h"
|
||||
#include "../hsm/limbo_state.h"
|
||||
|
||||
#include "core/object/object.h"
|
||||
#include "../bt/behavior_tree.h"
|
||||
#include "../bt/tasks/bt_task.h"
|
||||
|
||||
class BTState : public LimboState {
|
||||
GDCLASS(BTState, LimboState);
|
||||
|
||||
private:
|
||||
Ref<BehaviorTree> behavior_tree;
|
||||
Ref<BTTask> tree_instance;
|
||||
String success_event;
|
||||
String failure_event;
|
||||
Ref<BTInstance> bt_instance;
|
||||
StringName success_event;
|
||||
StringName failure_event;
|
||||
Node *scene_root_hint = nullptr;
|
||||
bool monitor_performance = false;
|
||||
|
||||
_FORCE_INLINE_ Node *_get_scene_root() const { return scene_root_hint ? scene_root_hint : get_owner(); }
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
void _notification(int p_notification);
|
||||
|
||||
virtual bool _should_use_new_scope() const override { return true; }
|
||||
virtual void _update_blackboard_plan() override;
|
||||
virtual Node *_get_prefetch_root_for_base_plan() override;
|
||||
|
||||
virtual void _setup() override;
|
||||
// virtual void _enter() override {}
|
||||
virtual void _exit() override;
|
||||
virtual void _update(double p_delta) override;
|
||||
|
||||
public:
|
||||
void set_behavior_tree(const Ref<BehaviorTree> &p_value) { behavior_tree = p_value; }
|
||||
void set_behavior_tree(const Ref<BehaviorTree> &p_value);
|
||||
Ref<BehaviorTree> get_behavior_tree() const { return behavior_tree; }
|
||||
|
||||
void set_success_event(String p_success_event) { success_event = p_success_event; }
|
||||
String get_success_event() const { return success_event; }
|
||||
Ref<BTInstance> get_bt_instance() const { return bt_instance; }
|
||||
|
||||
void set_failure_event(String p_failure_event) { failure_event = p_failure_event; }
|
||||
String get_failure_event() const { return failure_event; }
|
||||
void set_success_event(const StringName &p_success_event) { success_event = p_success_event; }
|
||||
StringName get_success_event() const { return success_event; }
|
||||
|
||||
void set_failure_event(const StringName &p_failure_event) { failure_event = p_failure_event; }
|
||||
StringName get_failure_event() const { return failure_event; }
|
||||
|
||||
void set_monitor_performance(bool p_monitor);
|
||||
bool get_monitor_performance() const { return monitor_performance; }
|
||||
|
||||
void set_scene_root_hint(Node *p_node);
|
||||
|
||||
BTState();
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
protected:
|
||||
void _notification(int p_notification);
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // BT_STATE_H
|
||||
#endif // BT_STATE_H
|
||||
|
|
342
bt/bt_task.cpp
342
bt/bt_task.cpp
|
@ -1,342 +0,0 @@
|
|||
/**
|
||||
* bt_task.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "bt_task.h"
|
||||
|
||||
#include "modules/limboai/blackboard/blackboard.h"
|
||||
#include "modules/limboai/util/limbo_string_names.h"
|
||||
#include "modules/limboai/util/limbo_utility.h"
|
||||
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/io/resource.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/object/object.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "core/object/script_language.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/hash_map.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
String BTTask::_generate_name() const {
|
||||
if (get_script_instance()) {
|
||||
if (get_script_instance()->has_method(LimboStringNames::get_singleton()->_generate_name)) {
|
||||
ERR_FAIL_COND_V_MSG(!get_script_instance()->get_script()->is_tool(), "ERROR: not a tool script", "Task script should be a \"tool\" script!");
|
||||
return get_script_instance()->call(LimboStringNames::get_singleton()->_generate_name);
|
||||
}
|
||||
String script_path = get_script_instance()->get_script()->get_path();
|
||||
if (!script_path.is_empty()) {
|
||||
// Generate name based on script file
|
||||
return script_path.get_basename().get_file().trim_prefix("BT").to_pascal_case();
|
||||
}
|
||||
}
|
||||
return get_class().trim_prefix("BT");
|
||||
}
|
||||
|
||||
Array BTTask::_get_children() const {
|
||||
Array arr;
|
||||
int num_children = get_child_count();
|
||||
arr.resize(num_children);
|
||||
for (int i = 0; i < num_children; i++) {
|
||||
arr[i] = get_child(i).ptr();
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
void BTTask::_set_children(Array p_children) {
|
||||
data.children.clear();
|
||||
const int num_children = p_children.size();
|
||||
data.children.resize(num_children);
|
||||
for (int i = 0; i < num_children; i++) {
|
||||
Variant task_var = p_children[i];
|
||||
Ref<BTTask> task_ref = task_var;
|
||||
task_ref->data.parent = this;
|
||||
data.children.set(i, task_var);
|
||||
}
|
||||
}
|
||||
|
||||
String BTTask::get_task_name() const {
|
||||
if (data.custom_name.is_empty()) {
|
||||
return _generate_name();
|
||||
}
|
||||
return data.custom_name;
|
||||
}
|
||||
|
||||
Ref<BTTask> BTTask::get_root() const {
|
||||
const BTTask *task = this;
|
||||
while (!task->is_root()) {
|
||||
task = task->data.parent;
|
||||
}
|
||||
return Ref<BTTask>(task);
|
||||
}
|
||||
|
||||
void BTTask::set_custom_name(const String &p_name) {
|
||||
if (data.custom_name != p_name) {
|
||||
data.custom_name = p_name;
|
||||
emit_changed();
|
||||
}
|
||||
};
|
||||
|
||||
void BTTask::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) {
|
||||
ERR_FAIL_COND(p_agent == nullptr);
|
||||
ERR_FAIL_COND(p_blackboard == nullptr);
|
||||
data.agent = p_agent;
|
||||
data.blackboard = p_blackboard;
|
||||
for (int i = 0; i < data.children.size(); i++) {
|
||||
get_child(i)->initialize(p_agent, p_blackboard);
|
||||
}
|
||||
|
||||
if (!GDVIRTUAL_CALL(_setup)) {
|
||||
_setup();
|
||||
}
|
||||
}
|
||||
|
||||
Ref<BTTask> BTTask::clone() const {
|
||||
Ref<BTTask> inst = duplicate(false);
|
||||
inst->data.parent = nullptr;
|
||||
inst->data.agent = nullptr;
|
||||
inst->data.blackboard.unref();
|
||||
for (int i = 0; i < data.children.size(); i++) {
|
||||
Ref<BTTask> c = get_child(i)->clone();
|
||||
c->data.parent = inst.ptr();
|
||||
inst->data.children.set(i, c);
|
||||
}
|
||||
|
||||
// Make BBParam properties unique.
|
||||
List<PropertyInfo> props;
|
||||
inst->get_property_list(&props);
|
||||
HashMap<Ref<Resource>, Ref<Resource>> duplicates;
|
||||
for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
|
||||
if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Variant v = inst->get(E->get().name);
|
||||
|
||||
if (v.is_ref_counted()) {
|
||||
Ref<RefCounted> ref = v;
|
||||
if (ref.is_valid()) {
|
||||
Ref<Resource> res = ref;
|
||||
if (res.is_valid() && res->is_class("BBParam")) {
|
||||
if (!duplicates.has(res)) {
|
||||
duplicates[res] = res->duplicate();
|
||||
}
|
||||
res = duplicates[res];
|
||||
inst->set(E->get().name, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
int BTTask::execute(double p_delta) {
|
||||
if (data.status != RUNNING) {
|
||||
// Reset children status.
|
||||
if (data.status != FRESH) {
|
||||
for (int i = 0; i < get_child_count(); i++) {
|
||||
data.children.get(i)->cancel();
|
||||
}
|
||||
}
|
||||
if (!GDVIRTUAL_CALL(_enter)) {
|
||||
_enter();
|
||||
}
|
||||
} else {
|
||||
data.elapsed += p_delta;
|
||||
}
|
||||
|
||||
if (!GDVIRTUAL_CALL(_tick, p_delta, data.status)) {
|
||||
data.status = _tick(p_delta);
|
||||
}
|
||||
|
||||
if (data.status != RUNNING) {
|
||||
if (!GDVIRTUAL_CALL(_exit)) {
|
||||
_exit();
|
||||
}
|
||||
data.elapsed = 0.0;
|
||||
}
|
||||
return data.status;
|
||||
}
|
||||
|
||||
void BTTask::cancel() {
|
||||
for (int i = 0; i < data.children.size(); i++) {
|
||||
get_child(i)->cancel();
|
||||
}
|
||||
if (data.status == RUNNING) {
|
||||
if (!GDVIRTUAL_CALL(_exit)) {
|
||||
_exit();
|
||||
}
|
||||
}
|
||||
data.status = FRESH;
|
||||
data.elapsed = 0.0;
|
||||
}
|
||||
|
||||
Ref<BTTask> BTTask::get_child(int p_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_idx, data.children.size(), nullptr);
|
||||
return data.children.get(p_idx);
|
||||
}
|
||||
|
||||
int BTTask::get_child_count() const {
|
||||
return data.children.size();
|
||||
}
|
||||
|
||||
void BTTask::add_child(Ref<BTTask> p_child) {
|
||||
ERR_FAIL_COND_MSG(p_child->get_parent().is_valid(), "p_child already has a parent!");
|
||||
p_child->data.parent = this;
|
||||
data.children.push_back(p_child);
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BTTask::add_child_at_index(Ref<BTTask> p_child, int p_idx) {
|
||||
ERR_FAIL_COND_MSG(p_child->get_parent().is_valid(), "p_child already has a parent!");
|
||||
if (p_idx < 0 || p_idx > data.children.size()) {
|
||||
p_idx = data.children.size();
|
||||
}
|
||||
data.children.insert(p_idx, p_child);
|
||||
p_child->data.parent = this;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BTTask::remove_child(Ref<BTTask> p_child) {
|
||||
int idx = data.children.find(p_child);
|
||||
if (idx == -1) {
|
||||
ERR_FAIL_MSG("p_child not found!");
|
||||
} else {
|
||||
data.children.remove_at(idx);
|
||||
p_child->data.parent = nullptr;
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void BTTask::remove_child_at_index(int p_idx) {
|
||||
ERR_FAIL_INDEX(p_idx, get_child_count());
|
||||
data.children.remove_at(p_idx);
|
||||
}
|
||||
|
||||
bool BTTask::has_child(const Ref<BTTask> &p_child) const {
|
||||
return data.children.find(p_child) != -1;
|
||||
}
|
||||
|
||||
bool BTTask::is_descendant_of(const Ref<BTTask> &p_task) const {
|
||||
const BTTask *task = this;
|
||||
while (task != nullptr) {
|
||||
task = task->data.parent;
|
||||
if (task == p_task.ptr()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int BTTask::get_child_index(const Ref<BTTask> &p_child) const {
|
||||
return data.children.find(p_child);
|
||||
}
|
||||
|
||||
Ref<BTTask> BTTask::next_sibling() const {
|
||||
if (data.parent != nullptr) {
|
||||
int idx = data.parent->get_child_index(Ref<BTTask>(this));
|
||||
if (idx != -1 && data.parent->get_child_count() > (idx + 1)) {
|
||||
return data.parent->get_child(idx + 1);
|
||||
}
|
||||
}
|
||||
return Ref<BTTask>();
|
||||
}
|
||||
|
||||
String BTTask::get_configuration_warning() const {
|
||||
String warning = "";
|
||||
|
||||
GDVIRTUAL_CALL(_get_configuration_warning, warning);
|
||||
|
||||
return warning;
|
||||
}
|
||||
|
||||
void BTTask::print_tree(int p_initial_tabs) const {
|
||||
String tabs = "--";
|
||||
for (int i = 0; i < p_initial_tabs; i++) {
|
||||
tabs += "--";
|
||||
}
|
||||
print_line(vformat("%s Name: %s Instance: %s", tabs, get_task_name(), Ref<BTTask>(this)));
|
||||
for (int i = 0; i < get_child_count(); i++) {
|
||||
get_child(i)->print_tree(p_initial_tabs + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void BTTask::_bind_methods() {
|
||||
// Public Methods.
|
||||
ClassDB::bind_method(D_METHOD("is_root"), &BTTask::is_root);
|
||||
ClassDB::bind_method(D_METHOD("get_root"), &BTTask::get_root);
|
||||
ClassDB::bind_method(D_METHOD("initialize", "p_agent", "p_blackboard"), &BTTask::initialize);
|
||||
ClassDB::bind_method(D_METHOD("clone"), &BTTask::clone);
|
||||
ClassDB::bind_method(D_METHOD("execute", "p_delta"), &BTTask::execute);
|
||||
ClassDB::bind_method(D_METHOD("get_child", "p_idx"), &BTTask::get_child);
|
||||
ClassDB::bind_method(D_METHOD("get_child_count"), &BTTask::get_child_count);
|
||||
ClassDB::bind_method(D_METHOD("add_child", "p_child"), &BTTask::add_child);
|
||||
ClassDB::bind_method(D_METHOD("add_child_at_index", "p_child", "p_idx"), &BTTask::add_child_at_index);
|
||||
ClassDB::bind_method(D_METHOD("remove_child", "p_child"), &BTTask::remove_child);
|
||||
ClassDB::bind_method(D_METHOD("remove_child_at_index", "p_idx"), &BTTask::remove_child_at_index);
|
||||
ClassDB::bind_method(D_METHOD("has_child", "p_child"), &BTTask::has_child);
|
||||
ClassDB::bind_method(D_METHOD("is_descendant_of", "p_task"), &BTTask::is_descendant_of);
|
||||
ClassDB::bind_method(D_METHOD("get_child_index", "p_child"), &BTTask::get_child_index);
|
||||
ClassDB::bind_method(D_METHOD("next_sibling"), &BTTask::next_sibling);
|
||||
ClassDB::bind_method(D_METHOD("print_tree", "p_initial_tabs"), &BTTask::print_tree, Variant(0));
|
||||
ClassDB::bind_method(D_METHOD("get_task_name"), &BTTask::get_task_name);
|
||||
ClassDB::bind_method(D_METHOD("get_custom_name"), &BTTask::get_custom_name);
|
||||
ClassDB::bind_method(D_METHOD("set_custom_name", "p_name"), &BTTask::set_custom_name);
|
||||
|
||||
// Properties, setters and getters.
|
||||
ClassDB::bind_method(D_METHOD("get_agent"), &BTTask::get_agent);
|
||||
ClassDB::bind_method(D_METHOD("set_agent", "p_agent"), &BTTask::set_agent);
|
||||
ClassDB::bind_method(D_METHOD("_get_children"), &BTTask::_get_children);
|
||||
ClassDB::bind_method(D_METHOD("_set_children", "p_children"), &BTTask::_set_children);
|
||||
ClassDB::bind_method(D_METHOD("get_blackboard"), &BTTask::get_blackboard);
|
||||
ClassDB::bind_method(D_METHOD("get_parent"), &BTTask::get_parent);
|
||||
ClassDB::bind_method(D_METHOD("get_status"), &BTTask::get_status);
|
||||
ClassDB::bind_method(D_METHOD("get_elapsed_time"), &BTTask::get_elapsed_time);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "custom_name"), "set_custom_name", "get_custom_name");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "agent", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_agent", "get_agent");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_RESOURCE_TYPE, "Blackboard", PROPERTY_USAGE_NONE), "", "get_blackboard");
|
||||
// ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "parent", PROPERTY_HINT_RESOURCE_TYPE, "BTTask", 0), "", "get_parent");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "children", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_children", "_get_children");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "status", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_status");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "elapsed_time", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_elapsed_time");
|
||||
|
||||
GDVIRTUAL_BIND(_setup);
|
||||
GDVIRTUAL_BIND(_enter);
|
||||
GDVIRTUAL_BIND(_exit);
|
||||
GDVIRTUAL_BIND(_tick, "p_delta");
|
||||
GDVIRTUAL_BIND(_generate_name);
|
||||
GDVIRTUAL_BIND(_get_configuration_warning);
|
||||
|
||||
// Enums.
|
||||
ClassDB::bind_integer_constant(get_class_static(), "TaskStatus", "FRESH", FRESH);
|
||||
ClassDB::bind_integer_constant(get_class_static(), "TaskStatus", "RUNNING", RUNNING);
|
||||
ClassDB::bind_integer_constant(get_class_static(), "TaskStatus", "FAILURE", FAILURE);
|
||||
ClassDB::bind_integer_constant(get_class_static(), "TaskStatus", "SUCCESS", SUCCESS);
|
||||
}
|
||||
|
||||
BTTask::BTTask() {
|
||||
data.custom_name = String();
|
||||
data.agent = nullptr;
|
||||
data.parent = nullptr;
|
||||
data.children = Vector<Ref<BTTask>>();
|
||||
data.status = FRESH;
|
||||
data.elapsed = 0.0;
|
||||
}
|
||||
|
||||
BTTask::~BTTask() {
|
||||
for (int i = 0; i < get_child_count(); i++) {
|
||||
ERR_FAIL_COND(!get_child(i).is_valid());
|
||||
get_child(i)->data.parent = nullptr;
|
||||
get_child(i).unref();
|
||||
}
|
||||
}
|
111
bt/bt_task.h
111
bt/bt_task.h
|
@ -1,111 +0,0 @@
|
|||
/**
|
||||
* bt_task.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BTTASK_H
|
||||
#define BTTASK_H
|
||||
|
||||
#include "modules/limboai/blackboard/blackboard.h"
|
||||
|
||||
#include "core/io/resource.h"
|
||||
#include "core/object/object.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/vector.h"
|
||||
#include "core/variant/array.h"
|
||||
#include "core/variant/dictionary.h"
|
||||
#include "scene/resources/texture.h"
|
||||
|
||||
class BTTask : public Resource {
|
||||
GDCLASS(BTTask, Resource);
|
||||
|
||||
public:
|
||||
enum {
|
||||
FRESH,
|
||||
RUNNING,
|
||||
FAILURE,
|
||||
SUCCESS,
|
||||
};
|
||||
|
||||
private:
|
||||
friend class BehaviorTree;
|
||||
|
||||
// Avoid namespace pollution in derived classes.
|
||||
struct Data {
|
||||
String custom_name;
|
||||
Node *agent;
|
||||
Ref<Blackboard> blackboard;
|
||||
BTTask *parent;
|
||||
Vector<Ref<BTTask>> children;
|
||||
int status;
|
||||
double elapsed;
|
||||
} data;
|
||||
|
||||
Array _get_children() const;
|
||||
void _set_children(Array children);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
virtual String _generate_name() const;
|
||||
virtual void _setup() {}
|
||||
virtual void _enter() {}
|
||||
virtual void _exit() {}
|
||||
virtual int _tick(double p_delta) { return FAILURE; }
|
||||
|
||||
GDVIRTUAL0RC(String, _generate_name);
|
||||
GDVIRTUAL0(_setup);
|
||||
GDVIRTUAL0(_enter);
|
||||
GDVIRTUAL0(_exit);
|
||||
GDVIRTUAL1R(int, _tick, double);
|
||||
GDVIRTUAL0RC(String, _get_configuration_warning);
|
||||
|
||||
public:
|
||||
virtual bool editor_can_reload_from_file() override { return false; }
|
||||
|
||||
Node *get_agent() const { return data.agent; }
|
||||
void set_agent(Node *p_agent) { data.agent = p_agent; }
|
||||
|
||||
String get_custom_name() const { return data.custom_name; }
|
||||
void set_custom_name(const String &p_name);
|
||||
String get_task_name() const;
|
||||
|
||||
Ref<Blackboard> get_blackboard() const { return data.blackboard; }
|
||||
Ref<BTTask> get_parent() const { return Ref<BTTask>(data.parent); }
|
||||
Ref<BTTask> get_root() const;
|
||||
bool is_root() const { return data.parent == nullptr; }
|
||||
|
||||
virtual Ref<BTTask> clone() const;
|
||||
virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard);
|
||||
virtual String get_configuration_warning() const;
|
||||
|
||||
int execute(double p_delta);
|
||||
void cancel();
|
||||
int get_status() const { return data.status; }
|
||||
double get_elapsed_time() const { return data.elapsed; };
|
||||
|
||||
Ref<BTTask> get_child(int p_idx) const;
|
||||
int get_child_count() const;
|
||||
void add_child(Ref<BTTask> p_child);
|
||||
void add_child_at_index(Ref<BTTask> p_child, int p_idx);
|
||||
void remove_child(Ref<BTTask> p_child);
|
||||
void remove_child_at_index(int p_idx);
|
||||
bool has_child(const Ref<BTTask> &p_child) const;
|
||||
bool is_descendant_of(const Ref<BTTask> &p_task) const;
|
||||
int get_child_index(const Ref<BTTask> &p_child) const;
|
||||
Ref<BTTask> next_sibling() const;
|
||||
|
||||
void print_tree(int p_initial_tabs = 0) const;
|
||||
|
||||
BTTask();
|
||||
~BTTask();
|
||||
};
|
||||
|
||||
#endif // BTTASK_H
|
|
@ -1,23 +0,0 @@
|
|||
/**
|
||||
* bt_decorator.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "bt_decorator.h"
|
||||
|
||||
String BTDecorator::get_configuration_warning() const {
|
||||
String warning = BTTask::get_configuration_warning();
|
||||
if (!warning.is_empty()) {
|
||||
warning += "\n";
|
||||
}
|
||||
if (get_child_count() != 1) {
|
||||
warning += "Decorator should have a single child task.\n";
|
||||
}
|
||||
return warning;
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/**
|
||||
* bt_for_each.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "bt_for_each.h"
|
||||
|
||||
#include "modules/limboai/blackboard/blackboard.h"
|
||||
#include "modules/limboai/util/limbo_utility.h"
|
||||
|
||||
#include "core/error/error_list.h"
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
String BTForEach::_generate_name() const {
|
||||
return vformat("ForEach %s in %s",
|
||||
LimboUtility::get_singleton()->decorate_var(save_var),
|
||||
LimboUtility::get_singleton()->decorate_var(array_var));
|
||||
}
|
||||
|
||||
void BTForEach::_enter() {
|
||||
current_idx = 0;
|
||||
}
|
||||
|
||||
int BTForEach::_tick(double p_delta) {
|
||||
ERR_FAIL_COND_V_MSG(get_child_count() == 0, FAILURE, "ForEach decorator has no child.");
|
||||
ERR_FAIL_COND_V_MSG(save_var.is_empty(), FAILURE, "ForEach save variable is not set.");
|
||||
ERR_FAIL_COND_V_MSG(array_var.is_empty(), FAILURE, "ForEach array variable is not set.");
|
||||
|
||||
Array arr = get_blackboard()->get_var(array_var, Variant());
|
||||
if (arr.size() == 0) {
|
||||
return SUCCESS;
|
||||
}
|
||||
Variant elem = arr.get(current_idx);
|
||||
get_blackboard()->set_var(save_var, elem);
|
||||
|
||||
int status = get_child(0)->execute(p_delta);
|
||||
if (status == RUNNING) {
|
||||
return RUNNING;
|
||||
} else if (status == FAILURE) {
|
||||
return FAILURE;
|
||||
} else if (current_idx == (arr.size() - 1)) {
|
||||
return SUCCESS;
|
||||
} else {
|
||||
current_idx += 1;
|
||||
return RUNNING;
|
||||
}
|
||||
}
|
||||
|
||||
void BTForEach::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_array_var", "p_variable"), &BTForEach::set_array_var);
|
||||
ClassDB::bind_method(D_METHOD("get_array_var"), &BTForEach::get_array_var);
|
||||
ClassDB::bind_method(D_METHOD("set_save_var", "p_variable"), &BTForEach::set_save_var);
|
||||
ClassDB::bind_method(D_METHOD("get_save_var"), &BTForEach::get_save_var);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "array_var"), "set_array_var", "get_array_var");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "save_var"), "set_save_var", "get_save_var");
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/**
|
||||
* bt_new_scope.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "bt_new_scope.h"
|
||||
|
||||
#include "modules/limboai/blackboard/blackboard.h"
|
||||
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/os/memory.h"
|
||||
#include "core/string/ustring.h"
|
||||
|
||||
void BTNewScope::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) {
|
||||
ERR_FAIL_COND(p_agent == nullptr);
|
||||
ERR_FAIL_COND(p_blackboard == nullptr);
|
||||
|
||||
Ref<Blackboard> bb = memnew(Blackboard);
|
||||
|
||||
bb->set_data(blackboard_data.duplicate());
|
||||
bb->set_parent_scope(p_blackboard);
|
||||
|
||||
BTDecorator::initialize(p_agent, bb);
|
||||
}
|
||||
|
||||
int BTNewScope::_tick(double p_delta) {
|
||||
ERR_FAIL_COND_V_MSG(get_child_count() == 0, FAILURE, "BT decorator has no child.");
|
||||
return get_child(0)->execute(p_delta);
|
||||
}
|
||||
|
||||
void BTNewScope::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("_set_blackboard_data", "p_data"), &BTNewScope::_set_blackboard_data);
|
||||
ClassDB::bind_method(D_METHOD("_get_blackboard_data"), &BTNewScope::_get_blackboard_data);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_blackboard_data"), "_set_blackboard_data", "_get_blackboard_data");
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
/**
|
||||
* bt_new_scope.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BT_NEW_SCOPE_H
|
||||
#define BT_NEW_SCOPE_H
|
||||
|
||||
#include "bt_decorator.h"
|
||||
|
||||
#include "core/object/object.h"
|
||||
|
||||
class BTNewScope : public BTDecorator {
|
||||
GDCLASS(BTNewScope, BTDecorator);
|
||||
|
||||
private:
|
||||
Dictionary blackboard_data;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
void _set_blackboard_data(const Dictionary &p_value) { blackboard_data = p_value; }
|
||||
Dictionary _get_blackboard_data() const { return blackboard_data; }
|
||||
|
||||
virtual int _tick(double p_delta) override;
|
||||
|
||||
public:
|
||||
virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) override;
|
||||
};
|
||||
|
||||
#endif // BT_NEW_SCOPE_H
|
|
@ -1,48 +0,0 @@
|
|||
/**
|
||||
* bt_repeat.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "bt_repeat.h"
|
||||
|
||||
#include "core/object/object.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
String BTRepeat::_generate_name() const {
|
||||
return vformat("Repeat x%s", times);
|
||||
}
|
||||
|
||||
void BTRepeat::_enter() {
|
||||
cur_iteration = 1;
|
||||
}
|
||||
|
||||
int BTRepeat::_tick(double p_delta) {
|
||||
ERR_FAIL_COND_V_MSG(get_child_count() == 0, FAILURE, "BT decorator has no child.");
|
||||
int status = get_child(0)->execute(p_delta);
|
||||
if (status == RUNNING) {
|
||||
return RUNNING;
|
||||
} else if (status == FAILURE && abort_on_failure) {
|
||||
return FAILURE;
|
||||
} else if (cur_iteration >= times) {
|
||||
return SUCCESS;
|
||||
} else {
|
||||
cur_iteration += 1;
|
||||
return RUNNING;
|
||||
}
|
||||
}
|
||||
|
||||
void BTRepeat::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_times", "p_value"), &BTRepeat::set_times);
|
||||
ClassDB::bind_method(D_METHOD("get_times"), &BTRepeat::get_times);
|
||||
ClassDB::bind_method(D_METHOD("set_abort_on_failure", "p_value"), &BTRepeat::set_abort_on_failure);
|
||||
ClassDB::bind_method(D_METHOD("get_abort_on_failure"), &BTRepeat::get_abort_on_failure);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "times", PROPERTY_HINT_RANGE, "1,65535"), "set_times", "get_times");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "abort_on_failure"), "set_abort_on_failure", "get_abort_on_failure");
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/**
|
||||
* bt_run_limit.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "bt_run_limit.h"
|
||||
|
||||
String BTRunLimit::_generate_name() const {
|
||||
return vformat("RunLimit x%d", run_limit);
|
||||
}
|
||||
|
||||
int BTRunLimit::_tick(double p_delta) {
|
||||
ERR_FAIL_COND_V_MSG(get_child_count() == 0, FAILURE, "BT decorator has no child.");
|
||||
if (get_child(0)->get_status() != RUNNING) {
|
||||
if (num_runs >= run_limit) {
|
||||
return FAILURE;
|
||||
}
|
||||
num_runs += 1;
|
||||
}
|
||||
return get_child(0)->execute(p_delta);
|
||||
}
|
||||
|
||||
void BTRunLimit::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_run_limit", "p_value"), &BTRunLimit::set_run_limit);
|
||||
ClassDB::bind_method(D_METHOD("get_run_limit"), &BTRunLimit::get_run_limit);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "run_limit"), "set_run_limit", "get_run_limit");
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/**
|
||||
* bt_subtree.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "bt_subtree.h"
|
||||
|
||||
#include "modules/limboai/blackboard/blackboard.h"
|
||||
#include "modules/limboai/bt/actions/bt_action.h"
|
||||
#include "modules/limboai/bt/actions/bt_fail.h"
|
||||
#include "modules/limboai/bt/bt_task.h"
|
||||
#include "modules/limboai/bt/decorators/bt_decorator.h"
|
||||
#include "modules/limboai/bt/decorators/bt_new_scope.h"
|
||||
|
||||
#include "core/config/engine.h"
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/object/object.h"
|
||||
#include "core/typedefs.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
String BTSubtree::_generate_name() const {
|
||||
String s;
|
||||
if (subtree.is_null()) {
|
||||
s = "(unassigned)";
|
||||
} else if (subtree->get_path().is_empty()) {
|
||||
s = "(unsaved)";
|
||||
} else {
|
||||
s = vformat("\"%s\"", subtree->get_path());
|
||||
}
|
||||
return vformat("Subtree %s", s);
|
||||
}
|
||||
|
||||
void BTSubtree::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) {
|
||||
ERR_FAIL_COND_MSG(!subtree.is_valid(), "Subtree is not assigned.");
|
||||
ERR_FAIL_COND_MSG(!subtree->get_root_task().is_valid(), "Subtree root task is not valid.");
|
||||
ERR_FAIL_COND_MSG(get_child_count() != 0, "Subtree task shouldn't have children during initialization.");
|
||||
|
||||
add_child(subtree->get_root_task()->clone());
|
||||
|
||||
BTNewScope::initialize(p_agent, p_blackboard);
|
||||
}
|
||||
|
||||
int BTSubtree::_tick(double p_delta) {
|
||||
ERR_FAIL_COND_V_MSG(get_child_count() == 0, FAILURE, "BT decorator doesn't have a child.");
|
||||
return get_child(0)->execute(p_delta);
|
||||
}
|
||||
|
||||
String BTSubtree::get_configuration_warning() const {
|
||||
String warning = BTTask::get_configuration_warning(); // BTDecorator skipped intentionally
|
||||
if (!warning.is_empty()) {
|
||||
warning += "\n";
|
||||
}
|
||||
if (subtree.is_null()) {
|
||||
warning += "Subtree needs to be assigned.\n";
|
||||
}
|
||||
return warning;
|
||||
}
|
||||
|
||||
void BTSubtree::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_subtree", "p_value"), &BTSubtree::set_subtree);
|
||||
ClassDB::bind_method(D_METHOD("get_subtree"), &BTSubtree::get_subtree);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "subtree", PROPERTY_HINT_RESOURCE_TYPE, "BehaviorTree"), "set_subtree", "get_subtree");
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* bt_check_trigger.cpp
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "bt_check_trigger.h"
|
||||
|
||||
#include "../../../util/limbo_utility.h"
|
||||
|
||||
void BTCheckTrigger::set_variable(const StringName &p_variable) {
|
||||
variable = p_variable;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
PackedStringArray BTCheckTrigger::get_configuration_warnings() {
|
||||
PackedStringArray warnings = BTCondition::get_configuration_warnings();
|
||||
if (variable == StringName()) {
|
||||
warnings.append("Variable is not set.");
|
||||
}
|
||||
return warnings;
|
||||
}
|
||||
|
||||
String BTCheckTrigger::_generate_name() {
|
||||
if (variable == StringName()) {
|
||||
return "CheckTrigger ???";
|
||||
}
|
||||
return "CheckTrigger " + LimboUtility::get_singleton()->decorate_var(variable);
|
||||
}
|
||||
|
||||
BT::Status BTCheckTrigger::_tick(double p_delta) {
|
||||
ERR_FAIL_COND_V_MSG(variable == StringName(), FAILURE, "BBCheckVar: `variable` is not set.");
|
||||
Variant trigger_value = get_blackboard()->get_var(variable, false);
|
||||
if (trigger_value == Variant(true)) {
|
||||
get_blackboard()->set_var(variable, false);
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
void BTCheckTrigger::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_variable", "variable"), &BTCheckTrigger::set_variable);
|
||||
ClassDB::bind_method(D_METHOD("get_variable"), &BTCheckTrigger::get_variable);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "variable"), "set_variable", "get_variable");
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* bt_check_trigger.h
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BT_CHECK_TRIGGER_H
|
||||
#define BT_CHECK_TRIGGER_H
|
||||
|
||||
#include "../bt_condition.h"
|
||||
|
||||
class BTCheckTrigger : public BTCondition {
|
||||
GDCLASS(BTCheckTrigger, BTCondition);
|
||||
TASK_CATEGORY(Blackboard);
|
||||
|
||||
private:
|
||||
StringName variable;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
virtual String _generate_name() override;
|
||||
virtual Status _tick(double p_delta) override;
|
||||
|
||||
public:
|
||||
void set_variable(const StringName &p_variable);
|
||||
StringName get_variable() const { return variable; }
|
||||
|
||||
virtual PackedStringArray get_configuration_warnings() override;
|
||||
};
|
||||
|
||||
#endif // BT_CHECK_TRIGGER
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* bt_check_var.cpp
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "bt_check_var.h"
|
||||
|
||||
void BTCheckVar::set_variable(const StringName &p_variable) {
|
||||
variable = p_variable;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BTCheckVar::set_check_type(LimboUtility::CheckType p_check_type) {
|
||||
check_type = p_check_type;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BTCheckVar::set_value(const Ref<BBVariant> &p_value) {
|
||||
value = p_value;
|
||||
emit_changed();
|
||||
if (Engine::get_singleton()->is_editor_hint() && value.is_valid() &&
|
||||
!value->is_connected(LW_NAME(changed), callable_mp((Resource *)this, &Resource::emit_changed))) {
|
||||
value->connect(LW_NAME(changed), callable_mp((Resource *)this, &Resource::emit_changed));
|
||||
}
|
||||
}
|
||||
|
||||
PackedStringArray BTCheckVar::get_configuration_warnings() {
|
||||
PackedStringArray warnings = BTCondition::get_configuration_warnings();
|
||||
if (variable == StringName()) {
|
||||
warnings.append("`variable` should be assigned.");
|
||||
}
|
||||
if (!value.is_valid()) {
|
||||
warnings.append("`value` should be assigned.");
|
||||
}
|
||||
return warnings;
|
||||
}
|
||||
|
||||
String BTCheckVar::_generate_name() {
|
||||
if (variable == StringName()) {
|
||||
return "CheckVar ???";
|
||||
}
|
||||
|
||||
return vformat("Check if: %s %s %s", LimboUtility::get_singleton()->decorate_var(variable),
|
||||
LimboUtility::get_singleton()->get_check_operator_string(check_type),
|
||||
value.is_valid() ? Variant(value) : Variant("???"));
|
||||
}
|
||||
|
||||
BT::Status BTCheckVar::_tick(double p_delta) {
|
||||
ERR_FAIL_COND_V_MSG(variable == StringName(), FAILURE, "BTCheckVar: `variable` is not set.");
|
||||
ERR_FAIL_COND_V_MSG(!value.is_valid(), FAILURE, "BTCheckVar: `value` is not set.");
|
||||
|
||||
ERR_FAIL_COND_V_MSG(!get_blackboard()->has_var(variable), FAILURE, vformat("BTCheckVar: Blackboard variable doesn't exist: \"%s\". Returning FAILURE.", variable));
|
||||
|
||||
Variant left_value = get_blackboard()->get_var(variable, Variant());
|
||||
Variant right_value = value->get_value(get_scene_root(), get_blackboard());
|
||||
|
||||
return LimboUtility::get_singleton()->perform_check(check_type, left_value, right_value) ? SUCCESS : FAILURE;
|
||||
}
|
||||
|
||||
void BTCheckVar::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_variable", "variable"), &BTCheckVar::set_variable);
|
||||
ClassDB::bind_method(D_METHOD("get_variable"), &BTCheckVar::get_variable);
|
||||
ClassDB::bind_method(D_METHOD("set_check_type", "check_type"), &BTCheckVar::set_check_type);
|
||||
ClassDB::bind_method(D_METHOD("get_check_type"), &BTCheckVar::get_check_type);
|
||||
ClassDB::bind_method(D_METHOD("set_value", "value"), &BTCheckVar::set_value);
|
||||
ClassDB::bind_method(D_METHOD("get_value"), &BTCheckVar::get_value);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "variable"), "set_variable", "get_variable");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "check_type", PROPERTY_HINT_ENUM, "Equal,Less Than,Less Than Or Equal,Greater Than,Greater Than Or Equal,Not Equal"), "set_check_type", "get_check_type");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "value", PROPERTY_HINT_RESOURCE_TYPE, "BBVariant"), "set_value", "get_value");
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* bt_check_var.h
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BT_CHECK_VAR_H
|
||||
#define BT_CHECK_VAR_H
|
||||
|
||||
#include "../bt_condition.h"
|
||||
|
||||
#include "../../../blackboard/bb_param/bb_variant.h"
|
||||
#include "../../../util/limbo_utility.h"
|
||||
|
||||
class BTCheckVar : public BTCondition {
|
||||
GDCLASS(BTCheckVar, BTCondition);
|
||||
TASK_CATEGORY(Blackboard);
|
||||
|
||||
private:
|
||||
StringName variable;
|
||||
LimboUtility::CheckType check_type = LimboUtility::CheckType::CHECK_EQUAL;
|
||||
Ref<BBVariant> value;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
virtual String _generate_name() override;
|
||||
virtual Status _tick(double p_delta) override;
|
||||
|
||||
public:
|
||||
virtual PackedStringArray get_configuration_warnings() override;
|
||||
|
||||
void set_variable(const StringName &p_variable);
|
||||
StringName get_variable() const { return variable; }
|
||||
|
||||
void set_check_type(LimboUtility::CheckType p_check_type);
|
||||
LimboUtility::CheckType get_check_type() const { return check_type; }
|
||||
|
||||
void set_value(const Ref<BBVariant> &p_value);
|
||||
Ref<BBVariant> get_value() const { return value; }
|
||||
};
|
||||
|
||||
#endif // BT_CHECK_VAR_H
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* bt_set_var.cpp
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "bt_set_var.h"
|
||||
|
||||
String BTSetVar::_generate_name() {
|
||||
if (variable == StringName()) {
|
||||
return "SetVar ???";
|
||||
}
|
||||
return vformat("Set %s %s= %s",
|
||||
LimboUtility::get_singleton()->decorate_var(variable),
|
||||
LimboUtility::get_singleton()->get_operation_string(operation),
|
||||
value.is_valid() ? Variant(value) : Variant("???"));
|
||||
}
|
||||
|
||||
BT::Status BTSetVar::_tick(double p_delta) {
|
||||
ERR_FAIL_COND_V_MSG(variable == StringName(), FAILURE, "BTSetVar: `variable` is not set.");
|
||||
ERR_FAIL_COND_V_MSG(!value.is_valid(), FAILURE, "BTSetVar: `value` is not set.");
|
||||
Variant result;
|
||||
Variant error_result = LW_NAME(error_value);
|
||||
Variant right_value = value->get_value(get_scene_root(), get_blackboard(), error_result);
|
||||
ERR_FAIL_COND_V_MSG(right_value == error_result, FAILURE, "BTSetVar: Failed to get parameter value. Returning FAILURE.");
|
||||
if (operation == LimboUtility::OPERATION_NONE) {
|
||||
result = right_value;
|
||||
} else if (operation != LimboUtility::OPERATION_NONE) {
|
||||
Variant left_value = get_blackboard()->get_var(variable, error_result);
|
||||
ERR_FAIL_COND_V_MSG(left_value == error_result, FAILURE, vformat("BTSetVar: Failed to get \"%s\" blackboard variable. Returning FAILURE.", variable));
|
||||
result = LimboUtility::get_singleton()->perform_operation(operation, left_value, right_value);
|
||||
ERR_FAIL_COND_V_MSG(result == Variant(), FAILURE, "BTSetVar: Operation not valid. Returning FAILURE.");
|
||||
}
|
||||
get_blackboard()->set_var(variable, result);
|
||||
return SUCCESS;
|
||||
};
|
||||
|
||||
void BTSetVar::set_variable(const StringName &p_variable) {
|
||||
variable = p_variable;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BTSetVar::set_value(const Ref<BBVariant> &p_value) {
|
||||
value = p_value;
|
||||
emit_changed();
|
||||
if (Engine::get_singleton()->is_editor_hint() && value.is_valid() &&
|
||||
!value->is_connected(LW_NAME(changed), callable_mp((Resource *)this, &Resource::emit_changed))) {
|
||||
value->connect(LW_NAME(changed), callable_mp((Resource *)this, &Resource::emit_changed));
|
||||
}
|
||||
}
|
||||
|
||||
void BTSetVar::set_operation(LimboUtility::Operation p_operation) {
|
||||
operation = p_operation;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
PackedStringArray BTSetVar::get_configuration_warnings() {
|
||||
PackedStringArray warnings = BTAction::get_configuration_warnings();
|
||||
if (variable == StringName()) {
|
||||
warnings.append("`variable` should be assigned.");
|
||||
}
|
||||
if (!value.is_valid()) {
|
||||
warnings.append("`value` should be assigned.");
|
||||
}
|
||||
return warnings;
|
||||
}
|
||||
|
||||
void BTSetVar::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_variable", "variable"), &BTSetVar::set_variable);
|
||||
ClassDB::bind_method(D_METHOD("get_variable"), &BTSetVar::get_variable);
|
||||
ClassDB::bind_method(D_METHOD("set_value", "value"), &BTSetVar::set_value);
|
||||
ClassDB::bind_method(D_METHOD("get_value"), &BTSetVar::get_value);
|
||||
ClassDB::bind_method(D_METHOD("get_operation"), &BTSetVar::get_operation);
|
||||
ClassDB::bind_method(D_METHOD("set_operation", "operation"), &BTSetVar::set_operation);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "variable"), "set_variable", "get_variable");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "value", PROPERTY_HINT_RESOURCE_TYPE, "BBVariant"), "set_value", "get_value");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "None,Addition,Subtraction,Multiplication,Division,Modulo,Power,Bitwise Shift Left,Bitwise Shift Right,Bitwise AND,Bitwise OR,Bitwise XOR"), "set_operation", "get_operation");
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* bt_set_var.h
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BT_SET_VAR_H
|
||||
#define BT_SET_VAR_H
|
||||
|
||||
#include "../bt_action.h"
|
||||
|
||||
#include "../../../blackboard/bb_param/bb_variant.h"
|
||||
#include "../../../util/limbo_utility.h"
|
||||
|
||||
class BTSetVar : public BTAction {
|
||||
GDCLASS(BTSetVar, BTAction);
|
||||
TASK_CATEGORY(Blackboard);
|
||||
|
||||
private:
|
||||
StringName variable;
|
||||
Ref<BBVariant> value;
|
||||
LimboUtility::Operation operation = LimboUtility::OPERATION_NONE;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
virtual String _generate_name() override;
|
||||
virtual Status _tick(double p_delta) override;
|
||||
|
||||
public:
|
||||
virtual PackedStringArray get_configuration_warnings() override;
|
||||
|
||||
void set_variable(const StringName &p_variable);
|
||||
StringName get_variable() const { return variable; }
|
||||
|
||||
void set_value(const Ref<BBVariant> &p_value);
|
||||
Ref<BBVariant> get_value() const { return value; }
|
||||
|
||||
void set_operation(LimboUtility::Operation p_operation);
|
||||
LimboUtility::Operation get_operation() const { return operation; }
|
||||
};
|
||||
|
||||
#endif // BT_SET_VAR
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bt_action.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -11,13 +11,10 @@
|
|||
|
||||
#include "bt_action.h"
|
||||
|
||||
String BTAction::get_configuration_warning() const {
|
||||
String warning = BTTask::get_configuration_warning();
|
||||
if (!warning.is_empty()) {
|
||||
warning += "\n";
|
||||
PackedStringArray BTAction::get_configuration_warnings() {
|
||||
PackedStringArray warnings = BTTask::get_configuration_warnings();
|
||||
if (get_child_count_excluding_comments() != 0) {
|
||||
warnings.append("Action can't have child tasks.");
|
||||
}
|
||||
if (get_child_count() != 0) {
|
||||
warning += "Action can't have child tasks.\n";
|
||||
}
|
||||
return warning;
|
||||
}
|
||||
return warnings;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bt_action.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -12,15 +12,16 @@
|
|||
#ifndef BT_ACTION_H
|
||||
#define BT_ACTION_H
|
||||
|
||||
#include "../bt_task.h"
|
||||
|
||||
#include "core/object/object.h"
|
||||
#include "bt_task.h"
|
||||
|
||||
class BTAction : public BTTask {
|
||||
GDCLASS(BTAction, BTTask);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
public:
|
||||
virtual String get_configuration_warning() const override;
|
||||
virtual PackedStringArray get_configuration_warnings() override;
|
||||
};
|
||||
|
||||
#endif // BT_ACTION_H
|
||||
#endif // BT_ACTION_H
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* bt_comment.cpp
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "bt_comment.h"
|
||||
|
||||
#include "bt_task.h"
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include <godot_cpp/classes/engine.hpp>
|
||||
using namespace godot;
|
||||
#endif
|
||||
|
||||
Ref<BTTask> BTComment::clone() const {
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
return BTTask::clone();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PackedStringArray BTComment::get_configuration_warnings() {
|
||||
PackedStringArray warnings = BTTask::get_configuration_warnings();
|
||||
if (get_child_count_excluding_comments() > 0) {
|
||||
warnings.append("Can only have other comment tasks as children.");
|
||||
}
|
||||
if (get_parent().is_null()) {
|
||||
warnings.append("Can't be the root task.");
|
||||
}
|
||||
return warnings;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* bt_comment.h
|
||||
* =============================================================================
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BT_COMMENT_H
|
||||
#define BT_COMMENT_H
|
||||
|
||||
#include "bt_task.h"
|
||||
|
||||
class BTComment : public BTTask {
|
||||
GDCLASS(BTComment, BTTask);
|
||||
TASK_CATEGORY(Utility);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
public:
|
||||
virtual Ref<BTTask> clone() const override;
|
||||
virtual PackedStringArray get_configuration_warnings() override;
|
||||
};
|
||||
|
||||
#endif // BT_COMMENT_H
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bt_composite.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -11,13 +11,10 @@
|
|||
|
||||
#include "bt_composite.h"
|
||||
|
||||
String BTComposite::get_configuration_warning() const {
|
||||
String warning = BTTask::get_configuration_warning();
|
||||
if (!warning.is_empty()) {
|
||||
warning += "\n";
|
||||
PackedStringArray BTComposite::get_configuration_warnings() {
|
||||
PackedStringArray warnings = BTTask::get_configuration_warnings();
|
||||
if (get_child_count_excluding_comments() < 1) {
|
||||
warnings.append("Composite should have at least one child task.");
|
||||
}
|
||||
if (get_child_count() < 1) {
|
||||
warning += "Composite should have at least one child task.\n";
|
||||
}
|
||||
return warning;
|
||||
}
|
||||
return warnings;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* bt_composite.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2023 Serhii Snitsaruk
|
||||
* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
|
@ -12,15 +12,16 @@
|
|||
#ifndef BT_COMPOSITE_H
|
||||
#define BT_COMPOSITE_H
|
||||
|
||||
#include "../bt_task.h"
|
||||
|
||||
#include "core/object/object.h"
|
||||
#include "bt_task.h"
|
||||
|
||||
class BTComposite : public BTTask {
|
||||
GDCLASS(BTComposite, BTTask);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
public:
|
||||
virtual String get_configuration_warning() const override;
|
||||
virtual PackedStringArray get_configuration_warnings() override;
|
||||
};
|
||||
|
||||
#endif // BT_COMPOSITE_H
|
||||
#endif // BT_COMPOSITE_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue